From a79f26dfefa1af89e11e791beefa731104c91cdb Mon Sep 17 00:00:00 2001 From: Jos de Jong Date: Tue, 16 Apr 2013 01:41:11 -0700 Subject: [PATCH 01/52] Create gh-pages branch via GitHub --- images/bg_hr.png | Bin 0 -> 943 bytes images/blacktocat.png | Bin 0 -> 1428 bytes images/icon_download.png | Bin 0 -> 1162 bytes images/sprite_download.png | Bin 0 -> 16799 bytes index.html | 57 +++++ javascripts/main.js | 1 + params.json | 1 + stylesheets/pygment_trac.css | 70 ++++++ stylesheets/stylesheet.css | 431 +++++++++++++++++++++++++++++++++++ 9 files changed, 560 insertions(+) create mode 100644 images/bg_hr.png create mode 100644 images/blacktocat.png create mode 100644 images/icon_download.png create mode 100644 images/sprite_download.png create mode 100644 index.html create mode 100644 javascripts/main.js create mode 100644 params.json create mode 100644 stylesheets/pygment_trac.css create mode 100644 stylesheets/stylesheet.css diff --git a/images/bg_hr.png b/images/bg_hr.png new file mode 100644 index 0000000000000000000000000000000000000000..7973bd69888c7e10ccad1111d555ceabb7cd99b6 GIT binary patch literal 943 zcmaJ=O^ee&7!FiK7FWCot{@Ck@nrMW&tx0B-6VAbrk1u~FTzffX&bu9#AIsIdef8t z!QZfdz=K}>3m(LO;6X3qN}Y6@>cJYA%)G<%Jn!ec>9im1@7>wsIBwrMF}iHO!q%;8 zSJ@xEd~(FL18NRvkBsOXMVM>4WQc*~qcQGc17IjxRnj!O_^B1gan0x#EWT48PK->5B2>mI;LIx zC*FSw$Nfc!g)WZCEOJ=mM)}lLsOk|$ltg_(&ax_YCWMlBLPDVT%D_gB7o_$YZ`-OB z#1sV%whRq21>W;qwN$N?OUGtQQe;JvOsQrna;+v+j8dth=*?orHHb6waX>S!yXCgT zo!oR3{E&GzaOAzfZYv@_Sf{LdyJInS>TS60&R9%yCs$y>2x(*gYIJtRrYAja$Ceq} z!N&oc_K1!3-Ft`U>`CM;quEbB4KG%!MovB*9_3!QzFhqHwrbwK|Doo-y>auDJNSP6 T=d)j*_4El@X4^PFK7I8YBT*xD literal 0 HcmV?d00001 diff --git a/images/blacktocat.png b/images/blacktocat.png new file mode 100644 index 0000000000000000000000000000000000000000..6e264fe57a2e35a2855405ac7d4102c3f6ddcdae GIT binary patch literal 1428 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%s|1+P|wiV z#N6CmN5ROz&_Lh7NZ-&%*U;R`*vQJjKmiJrfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8EkR}&8R-I5=oVMzl_XZ^<`pZ$OmImpPAEg{v+u2}(t{7puX=A(aKG z`a!A1`K3k4z=%sz23b{L-^Aq1JP;qO z-q+X4Gq1QLF)umQ)5TT^Xo6m5W{Q=eg`=5?o13Glvx}*rp{t>#shg3DvyriZv5}jZ ztD`wguSMv>2~2MaLa!4}y`ZF!TL84#CABECEH%ZgC_h&L>}9J=EN(GzcCm0X zaRr%YgxxI=y(w7S0@dq`Q?EYIG5Vm0MT%&c5HR(CnDAr^T6f1avxRvmvnsN+?-j}Z~1)Zr#rqzrt`edmo44*B<0=C4>mrxHF6$p zVws~UocMfeI`gB8pYMLYTzA87`NOI2w2B*JM5L`^AkN4AFQu&S+6ULTPjv;vzl4& z-eaK_F|D4~l3hzBSF~icNT@MID=v+_X`vpuvf=8+S(|^vlRdHe0<)v-^wiVR3w=TQ)uFA9F z>vmqc-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%s|1+P|wiV z#N6CmN5ROz&_Lh7NZ-&%*U;R`*vQJjKmiJrfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8EkR}&8R-I5=oVMzl_XZ^<`pZ$OmImpPAEg{v+u2}(t{7puX=A(aKG z`a!A1`K3k4z=%sz23b{L-^Aq1JP;qO z-q+X4Gq1QLF)umQ)5TT^Xo6m5W{Q=$skw`#i#v$3O_v5UEZv#YC% zp@9obuSMv>2~2MaLa!N4y`ZF!TL84#CABECEH%ZgC_h&L>}9J=+-@<(X&zK> z3U0TU;MA)Rbc{YIVv!;mCIn19ASOK70y*%6pPC0u?M1+3t#h8?05D7Z^K@|xskoK& z=l_5E!ww8;ZH!Ed#V+%1n6Rkg{=V8A2QTsNE8^> zvHmCezoM^A29GnE>#ih4F*YzTGbm`! V-6~#faTQcLc)I$ztaD0e0svxP=aVwVK4enmt9g0IKZo#d%7nk4^w@~b(uifvD z``(=MFknn*JH!$I|dc`^>cnF`118Y;wG!- z_Q~1W&C?8M1t(?cY;HxR=xAnRrDFqjVB?XVPEmW7Xl zg^(qUggBL`m+-3rM=LioDlf+`P9R|~F`ECdEBt!??=}Yw)qjY%If&8xr&D?=>QvIs zKr1Rfc1|`6PJT`*elB({9$ot`v%N~NfxMmE%)Ho~K(zmD zLBu>zoJ}(rGZvvZq7h0XXh{f z9Yu9pXE$e%t+NZ2^d~+l6*CJvr+?S~A+Mq$tmp)CGjp=AQj`&+d9}c9XJ;wQ&CM;t zBP+;Tt70}MZ%2E#K>`3(=RTj4U-+kfyU+w*uuI2yk3)lau%kk05?ukdhi;`oX(Qd(Zie|+td0lF!B(ZgdEn&k}~O&w^8 z>?^KhaE^p%K#G;csY3icy5ewJ$krr-^7@+4EHpGa#pDKa+M{G(JcMAk2y@ zAD4bbfGckvCZKO$D4eZfeFQD1|6@RV6@1dY-!HZip7n9y6F|ybPIQY;UY&domoq^$ znnL$MBL=odWST@B_g;kDOd=z~0LQJ9!zQ&qM$$&IgTXny;Z0Zk5gd0m95{LV4p;Lg z8+Ex$iXYRl_%@~x>ANvXi<@~XA@B=8i|)%}?buwZ+!X?a3Y8yVnUE0Qeo6SMC8Aws z%oTAu9Q2kmVDg4^0;oI}|4=6MK~4_-4;-B-+44!cYW9I=iC^WT=PRN#<7uR2G;gX^m~zA)LhEquX)c?AGh2jr8?EN4OcXVV z;~SPr3a2dln~!dJXklj=nG><%dSc7eo7xW;2yhgKuf<^15ZR7 zUEEA3kE=8gb=FL$&gf{@0wF=_TtZ_KqgzL6nv?JpI3FKMS`Li6q^-nGqp!0~jK z&Hlv0L(YyC>gE8|dPLM;-oe__-3N@b41Zvsb@qTCV*MRwZe!@b(0!)+0&c{o0{S%1 zW01+)!2R+C-F1r-pJk9*5|M`f2tOqLoQ4Z)CPSKaQ67mtJB zf~Z+z98vUy`wi2tN08e*72TJeg@}!3N6n#{y$O;{GJyaQd8jpTz`TBE2V)#ocq31~ z!DHeRdw(Lais)#Qn#!mvBe^;hCsL}okh7kvm@s!By?Ue6nbAR#le#~q-&gU@yQ!Pi zv}<+lsMJe!7w*Fk(j+S<-1mdt#8d3U%X}W3q|sxS?#FO{$Wv`+`VYS@0I!j(gykt8 zjVk0ac&Y+o3M9%E3piX?>%J3K(71|O$W&KS^usI8M>t51StG2gAwVis9RKVT#W@=p zzJ=9< z;LTNs0;5@f?4#MJA-0s3Z3|8M^gxY*RS{C2Ich`|AIFCJ%5YKaz#L^PFm_E zo@OVpm!ESz&S%FC3((q#q%aX0S)Gb?CWjz+8Y1Qk+VMd=v|K}y)zfqhVpgiFUYT|u ztHh3AgN83Je|(%tq*5S%yaM0 z{Oq1@nou^|=X^xJi6muVAJQ?)Seg`OiQXXs(8zc>zH(f=gfjHho)iq!#Ob5-xlH=T zXY5(nYBg?p9;7*c?LGENVQX$tnlCE0rs7&8(whLtMvpJ==b0~bqFxvaalqIOJqv^$ zE=|+JotCVREY1M|92FXGuzq5Xot#~}zPuQH{3-4ihzBwMc>a77x%vlk7hp$WEBt`Q zInf=VkVI#DR)MsphZBrTlvNzbJoxTizvNhs;#G&|7v3QW=z#S_?QfR?C)7?>zI$x5*H38H#y94`6XM#84uhuOkiOWQ zDVnfMs~SPqvCfv>jk3u*P%fi|%~$W)P7v(j^rZ{f=OBPz;os`U?KK6=k^MjvMoOHNL|+Nb%; zclDh8@cko=nq5^CZTCpwkDb`;g?vcADHCwl<8TkR{V?Qr=M5Ssq9}=5X=|sKRC0G4ckVGg}HQV?XrymN&Do2h;IK~_{KX&+$s-$N2_}FP>iT+i^4k5D zFQw1VyvSB_LTs)yu6GOHu?EZD$$h(buHxg|vKDxbKb1ygl>P4J7|Y?Y9$ev2#&){G zc3h2Ff2k!uMI;cDnQ5@amRLc7rJ!~97sQKv=f8})fexlU7>l|oZ5uAf1XW%ww0m|634J{>o#6qtVhg@F<0bw6E51KgTaTFqu@IE0_M^Ba zYEwd}WOD{Fz48tS&lJsbWEe362uJf58?onE&1f}B$=@!P^7kIP9S$QKtIMcXd*I=q zFiZ{w=J&`c&IF$CX1Dm3#nck)UgzQ)ZDIM&Y^~hF;`)eHCRyzlpgnGfK9PWmHK{h!zv9q1d@0}x4S*i^C%VWe*H6@e zEE|?ysUR17UXhCnXMfU^mGTmN1;!K<=e$#cjd1=h)j)r2?Pc0#8ya$EYf z;7p+hK4$@C)wX^s|BQ8ga`ZYHspd_i7R}MWz?_9DuScwbf;r4X|NiQT;Hk#p>J~rw z`n+RTH%jGei%y@iJ?QSq#hsVwBW6?ZVzsDmlF*^Pzq8+E-C0J4@34vRcM8v{Ip7#g z<0^@3Lyh_mmDfym-^-|d26f+U<3fDT#ZJer#ufLeAsgJ`9{gLG{XF4SSpt$q7Sp6d z8M9c{vpobO3|}s%OZ=}i>R}-mC;7j_Z^Nt>4j~-YK64mHzv*U2MTa*1rXs-I`b*7r zHlSt4W`)L@t+5-&1VJdf;3Ty|^G@o^n2ALR8YWF^ah<8{p}o{N=DlAT|E3PEf}TG6K(UssQ!AV z+IsY54dHEp#RYlRn97Qk=-@|7d3N~s@#LNp*`5|XKd%4}Hm86i&Sr%}_}#ZVfDaX< z2E5UeMnZk9zj}oTfp~t^Z;3&pCP1We6nh;Jcvdzyg7KUt+=|H-{njmTWvUr_{SARt z-5r2Ld9Ky9bthe0pl)Z0798I1Iq+9yLQp1!Ew*LZNLLfXmz{@{F&zrv%dQt=m-xtq z5gIgU%xBP)xktKf9#2MrTF9@ktDxJeHp97G<#7hP$7sPypSUaDg1ALK$?lJ+Pg(oE zFK0S+-wUrvb7HU~aJ^typ@W7Zjy`mwu+-?%_g{x4S*eD|p;j1Tq)6ZsvJ2j|4_COK zHoxnL^8K)cx?y%9OI*(L7FqE;o;FYJz%PKk%&P;8ze7Qt&nGX|?9v#g+j_YJr$7~n z;gV;?grS0{3I%YxRk<>rx_=Yb{+RE2Waxw@6h%wVHAMdsb52gNF=r6nTBCCwphO~N z@Mh+Zcf>kV+%t1*f;wH5sYpRaMWZ%fU!^9?L*%BPQ5cylYReTsW*$=?Z1}J71ST`J z(VhuMzf_5o7)OxKR95uo%pF?px2Dg&#dMmVW!-BlemiohUTb7cpk%*@%x&3XE3So3 zl9a0~hwsyvnJc%8}Sip)Hp5#)Z@9p@v}@_$Y;&d z3EA=_6+P8$%@!hi;$zq9@L74{gP+p-g<;S4_`rx2Z4yP&#m#5!j1MC#JrN{qp^5qq z-kF(LK0=~g^5!J?M4s=tVsIhS+gU>3r(da6vq|Ea^*ipd(#^`<_W8f`nUi#P0<@|l zi_}Xyh$z2FCI?(>Ox?ls5sjh3GY6=LMcgqT@7`O*&_^m7j-R5#&l;1j`wp-AhYPX1 zMz4=pYg1=bQIIDhtw^5HJ|+8+`l1_pp2?!{mxpht&4_}4o4e(WQ6pT#uZVPh862vs$WG<6TVIe9t@IE(eAyZwx)`XtHzNB7NbYwl2LpGnr#d)Lx;bk-{>=U- zU^!(JY&%(Dbi^r}e)4#--M@eGSr@1(IPoYa@ zQZS%&Ft?SsqUMU1d!xXlMzaO?x2U($vF*_Tf7RQE&Wv{VDYr!4Ldd&&y@f8#Isr`l zBI7zEy?X+s8A_{#dbRuu##U6-IuJ|0-_nRGvr8XZkv0E>Axl_BxIV@GRhzU=3xmgs z7t2l$j_1Xg@2zmvU&sIE?o^5k>4UEDqfk19y_0(>Rkb#F)1Jmo!R~V~c%3_`fRKf( z+*Z!J-^LKc>qLWyK;4{(Tu9(M| zj(>DYad4l8iFxUy5`4{s&9@|ti6?Cf@Axp|D{AiaTuX4bw^{ugD+*7f+svF5Z^0+C|OQkI|aCZ*P0X=FFkmao_pq{_;VPBPE6e zck-Q?JoTm&@NadJ#cvMsWLl1BxE#ECyG@Ca{MwSE5L;#`EK?#83??D&H6xPdLyZ}w z)dyS%BGlp1Xd_f`rwKYu{1$57!lm_1hM{&?PeS*=Y9WcpqNJexcN>|#7>`_k5PJIpc`w||MFXxqmUsl>$$BbJVDG@rqV)ExE z%du4Kr;M29@Ym=ajtM|!XJ_~HhuWu~_a+4>`M}yv4=oor7?vOl7{bzzUp=yxSCXSd z15j+1Q7zXu;+Ckx8O+M6b|ZV-WXe!ZgBvfWP=}FyZMl>xwgTg!r!FHlm$1)Y%N`^5 z0&nZOi6ieTR8D7{pIJrPV3&$Cd0Q8o$3UwvPV{O8(K#;t#1v~RQ+-ME@`ehk*~LiL zA69D(Q;7DJ0uA=JqARQo1PatUjv}`RHYQu^FHSaR`PUdDniOGVKgJqtgx9*Yn8Xc_ z{}!%<<3F@pggPsviG6_GRzLHyLKJz>s$p2L07$be z&(~)r5{`K{^36{C`{EYM;7#mU?_1J43GnIU<8mea)Wk+-PvHH$NUV@!Yu#eaeZKlE zLt0k+%QQ1+AY<^415M5McZeO6D%fP8n>WI&8*M}BWKL_Og92AenwbUUJ5wH$U2#12 zi3|){``@`{bKcLuP^*cdg|r0byEJm3?+zmLilbT4QjjXti4y3bQHLsubE{3r^~(!` zI5dBTPhoDOYb>4E&tO`m9iO8wWa?KpI>&Gr4Z)RoqK*#1T`me(W379?05R`w@L_BG zm)%vcZtI!TD)J($`y%zl+E0t+Wnxl(V9fJqXk0p)g(Z#~+d9fd_+bAnZAfjUio6M3 z9zH(y<}On?01oy$sObo{-)*nF>0RnYz*-YtySuf}LNRfhn9YP!@ORI+obUEvb>Gnv zymotjN&!lr{EFl`9^R~vB`wqG^n|>o0D7bTEqIIw<1>q(VuD^UjDIlczW+6x?pgQI z{zrZ$R|VDi@*55&$E~;F&m=YXzjUs8IovMl09lGibV@s`OuNO5J11moe2c4Z9A9=j z_oTa+B!ntFIAEDv9BqR+g5C!$R^e#S==J=D*$VS_Pidd^_x%}Jl(Owb=w0FNCzOKA zu(V(HD?*x@$u|-dtpha3zBZ>j8lLj4oNgFwGuOUQKW6wgu-0swT!cGMpK1G9ui`efd3=bH2EG z5srbg|eJ)iXLY z;pmT{w`-`?hDl~7Bxag#M`amvO%5D~h5T+_`0oM&zmwGB+qVieS)uuB*Cxz;8XqqH z?p~&UF!eJ;ipju(^?V*Y{BSC;GUju&Tu-{UeKXr>4}UCiv>-O3GKHMS^kD6~@)hU! zaD5-y_`%aSlg+I4{p19`=pNEAnNd|&bKN$k`L8hk1n z6|fvsu3oB_dh3{0sr@~9`n^7%JhY`iGHQpv;Dk`&4K-g#POWc`TLH74wuQCnG^A>E zY#!_Q<8kwsE&`$^_eCG~j(iH0Hjg=B23Qnya>A9F1UO1;;_E4}`2lJC58;Ep6M!ya z*(7)aszaDPyw!Gyd0d4OsfAhTXWMxC%gnQiOs{5y`t8ZLx0Zz5j?<^bNK6~}2F$12 zjp{5E!y@cOW|!0r^iSY7D8!S)uZySZEo;wzURrcD`KGKawPPjKW%2F?j-~QCB={%2 z<#ahZUIGqp=%zr$j&L10Wqd*|+P;~|t-!SNee#W&`o9}BcO_g+qDQVJ1|+=Gu4u_S zkb~QYBuwM96*l7=1jgZ%&w5?AMg`H*?eyAE;)feeR593cCw2H(_yTRXqxPyp8(_`o zukwSVCavjLyd{4|k!4AC;)f_Z9*KtK{=3 zhRuH#@IwI<8EZ-3vsULfuupib_sC5>jPCaAuF6eGK$9ln%te;-y z`q|~jFps&h@#g~K^@!ZDpL1V@klE)B@aDN(_$Fa~Pp36z;rJfA2zMPa;4-Ywa3Mza z$7#&mMr|r$cQ2Lx!k;mnx4U&8&$uD3vXQ;8!CubzdN7-JO;dRy4UronM?9E83qaEd_unf{kx2>BlOqiHY(h^ z%m(a?`Wh3*g`9>#yxTyOvp=e+qFZ+k>;7L`li9Oni>I2!I;|sf0JlUTLD&tZCVhsY={r3@tA+hN4;zd*Pj<~bWba%b4G&(gP= z^}AbVj8cKzOQyAy+@?K!?Ms6UySts&9o+m`YZner(=rx%ny!-MI*o*dvQcdRMg}_{ zt1l9>e$qtgC%&=JqIddgN#b&3B|A5z6t>ayOHn?Pm@dW{>q+^8c9IWT=C8ml>~;(* zu92=2eA{h`sSmQqjcYLtvdKR`=X>~0cZ~oaMBBoUF@SbQ_>iGvTrfB5J)ZZr5sgMz zbl(T7!`G!Gsv3YG?H&o4_*C6cto$aqm)O{4(PZxr@lP`x!pfgwfAgJ& zv7*k#a&_L1ut-jMZ#_;b-%mNsqZ4IG(K0BHW~)@z>NIA=>}vAtg5My-RpMkP{rbbb zo@-44YNm+P2fVG32PTZ)@M&oTh*aOZR5?pCXd`$}TJrOtcs8MX0xAG&ySK*YcDn-Q zZt3_>1ii%CQT5_8{0?fqZ8veE=n;RO7OS@q68pBZ!n0SXQ)uG?S@xaOU3BJ-*wS|5 zSDu(Xd0bYkkW0l259mGw@spX^FuO9Db`HK2$ivXmS?AMQTn-}^Q=z7u3j%vQO= z8r}?ftai&Fv{%NYB(3iW$V`xQP~9$IP8%bocS%{^dA=Rn!i5BHl9dvf?htu2s%dKU zP+}6{MQgBus$1gt@r=%X#1DL)sec>tbKGfXc05 zJek~E6dfV^*fGZz3M&t}ephq9hqbIRSDSULwi&q=jn!GS!|OEkt})lt`b-F;Q+{Yu zs~!z*gd#_D9EBqM{r@`QN$U+rbx}E z@}vrk2G{&yW^GtGJ(S487ESTG>UaFIp3}uz`|iU#w1B(F5|!p$&dqR>CM?}jnb2ii z@1Q~1$oNO=yrqkkF1|`t|M!o62+x$Q<0qYJ`N}^uysb-|MqOs^8hzhJ4(GbB`HWxW>^VkX=;Ec^{sgBJX z0jZ!|gIKTmO##ek2ZH!M=b^QSGXCGl%xX795vUA0iDu|>PMN1-W5v?#KaUg&c4ivo zqWa#@;6KgA8SZ2xE0SZ9Q2Kg8h{y{iHqO@H5Y0w6^S3t&<5cGNW>D}^gzRl6SY!uzs^^4!@B;et-l zgyb9h@ZF4{+vZL(6a)A8*=EU=)cU<~Vy=dHAo~nBMr%=k=jn(Dlc0Mh)p~y&R0w*P zY)R9kCAB9iSDqHJ@MA*M;=qD{CT%^Q zF-UmCzQS*9S>rfC*RR;ffB)38HX}!^eO*>+dhQ<+YHXiqzxZ?8mB6VUPZ2nD!^n?c z@PV7DJ3DH6poSxS;e}DwbZ0~U;|=GZb_F{Dx4fx}gQ~1p>o(lc)0>RT6$>HG`)?cA zLEc&y_X;=qB6&Y9UEje4U+GfY`z_>5=z`;t(KvMjVu?B25?i*A@+c9_Cs1G;Mh|^; zm351x7F6=vn=wJqER^(tq`flikpfy|x4xHL6N`m)qZUPWL0)W2UEuoY#BuzE8ay}l<cM|q&BN@eZbaik9U6Tj z)htHc3>G1O`KA5s9xnG(;}fbho}{>ZZyXXNf+g&N$g9u^U>0=h^(E^$S0(TzDY5LB zaPzW$&?J&Y&1t#eaAv+zw+m&x7CBg=H)S_Rb!a&Ep5V!MHmEIx(wpo10Jo z5IyjtWG@^+UWsmeI|%Iyf`0oT_8?6QF?-+Y*2By#Kv+Ab@1Ew!NF$#6d+=TqBnSI5 z5`RY~7uuLP-zM;KdXV_J`Q2$F1;l6gj_bB!7{5obSlp#Fp!~?N6MHzJ>$}XDS5O5P z=IVX22{CXr33*I{cFGN}%saPo@qY1QcQj1`Wqp0?fp;&`0J#4pS2DFfo6|fly?_v7 zf_&R2n@8<02>o2F+N8EtY#H|9t3?2Z&TxzIW)`{hhl$X3eluZzdW}UEtyl#pz$@3K z7mYC&d^wT^&r~VcyvdUXp~azR>^bXX*G0&7liFrIH$cR?Oyrpmgr z>;FUE6*6L)<(b94j}t1G3@{?pA3S+%d?VEtGI4jZa;H~0Z}0OY&c7D4nj_xNIv?|f zVq<_Y*K7Md#YW0iAcsOX2KCS3rH0^xIn5`)qp}M%#t)?~NsVCZD>9{juzr>Kl|Ypf&rsQChczq0or_<<7k#>o z2J!rr@Cy$PDcv#G^xZN+Y{P0f+U49@{K|k6mH*4dqhKO1>H^u4h!*S)CT7)h5h{~C z*2{mtuno8oXGV$a=R(SgM)#8*SKs=Zb?$$A;MRfp_?Bi+90r56~vWlDd@7ZheJQp50OkmPe#%#T6kPO=Xh~TCZ{0PbcBYe2#&MJBB#FGxah> zF@DkV`r0+bikn;W3gaiKe+2Yl3cECM1@z|J0X|O>(j0wmUt^Da@Aw@wt{6goA!(^I9jZ7a49;=m$i8R(?-| z+NFlllLj*9O!Ya(#EqT{%nN}vi9w*OZTd+R@on1`$7rq`Ar_OlViKWbYuK18F9q&@ zih>h1wPaG>h5f9>$H%AtK!htbE|Ga9^^J#u5)jKR1eJ#9BB%gG*RkJcmf*@E#)aVl zxnbFTR6CrXNj8I!M1sRnI!@|Nn2cm9Kv1}|!nJnK7l7a%;uL$B!o>sA&YS#w8P($f z*Aj`gq1NNbSk9!$lM6Q7-2Np0)UbTOC!vCd;B)#X5(yA^ivsnms#z%WW4NkxU^1!5 z$U7rmF)?4#19oTA4zCM(+j&sFmwd@U6bcYW)T~=eBcwi2Fm#7vc&#;b41q0_B8-Q` z^w6N8Nyt?h8U-Q(tI?!_c*ciDSBjp$6@=u~k=HsqZM1uyZES$A#y1enS0>-~%OD{S zs|dXDxzjJr@mS77gb>G{pG2PpN1U-WuU@iIor;}b^^FxJUs;l|-J{y{!tVF;UZ!QE ziHsw@=o!?mVit`{KE_bFU=6`}V2&Z3f@5)U-$7@@|W~f%(1ljZgIK>=e{NSQ?=DynS5Vd=2X5o4k%Hae+;5mhAW zf##U)s+32fM6q>pxln4Zg+e$40HBzs84`Dv=22<{qaOZ))f-$csrp;NSX?pxNvQ#l z0JT}9)JHo%+uZaJA7c#C3>po|1rC3z3{hHRdFp0N;#wqhf2N7nV*I>jS!@n>i43Lk zT{qj)_e;*~CM9>$w5a`6K|G+Wfq(qi)GZ+l*eJ~`Ke6iUSR=8elJIqyOp&uSJ)wrX z{45kmSWKDnKz~TOjldmgOe(qRfTOgRu&s+1crEEt3+GRSEqEs+Uy!}=k6#^=$Wdsr zG<3w#_!B#=CiBRT;(klzCJy~j&Jn7xn;&Y@%As#UiB|#)(=E|aYEI3}uDlLxmIjO= zIx*{jEo1Tx{vnNK{gllO=M0ss?dO?@Z!|G*dkZx?oV9T(cvO~LoDQ4D zR)d}GBCNlDaAcUXVB_49G{cR3K%i68pTw1J>ia5~2b&E_x+TI3DMM)9>n(^*hCfuB zyL7eUPWXtFcwY_V<8DseJ+c(i1Mh_yi5Y}t5Cm(A+S3?(bvk??%tk|N^nR7YMxAbk##4`Iv9SX_OT zax9m4kRHuoD+){OU%X$T?<~iULWFo`6aj7*qUjHE&p(p6ba z)!EP(lCvb0!-`Gb--u#yFV0%-Wz4ZPHpsV8v|{X1d`&4DNj24OJCTElJAs4!4vcUU znw~SX_8P4Yy*?@RFI-cz=}-diZRO(T+FN>NIoe7>!L7$iZ4q?Dg~GrNN>S`|iLCvp zlW*vyfPc|yMubf)jRua!7<6bTG3{fktOgk_g3+)S*IMqm-gS)H2 z(FSbEm7#VeCQ8a-=Q02+fZ#WPuv?jafkfI|+-oyJSH!)}KlAi+{%t!6;Avpuk_BPl z5*K7eMW~LD_Y=F>x1wiKEO7jlHM59C3>8H**j8oAEMYs?K@;mxK>|bw34viQAj!0~ zSHgC20&5JdP+AnwjPTRkMD}+x=|eb|>D6Q4vy3U+OjvB&=eWi#4PUvq{%-*XkY_ zWP(hU0}j)W`k!jJg%qGvnjM82w#c>mv4JT|xR7{^jn4%n;}`KaT%2T8v^Q+kK5;s8 zGW9Jb?TmC--h>NiAt$!?= z*8YJ-%FR4;6ztlTX6G5 zw75#P6D(4X@aLBi)-~|8=O*2t>N_|Nzh##1Wz#YJJ~I4wEKz!R$JH*tHkdkTu#&qG zcE+nwy8A&vUP9pGhw#)b26t5orbDO@b4iMM&0EsM*Np5H$W#72@b?~04@m@CAF)Uc z&9^U)$@H2bs0BM2#*pe zrq_pjRsg>c+SAlk?3unzj+Ls=F2Td| zAepnMJ8#9XocqogEgC?EP~Y=$mm~Q>{O1 z!uL(uVW;IKt(O0S483t22L*Uw5y*je#bSD|^za-;<|Jqj`z3lLwLtZ{BVtO9I@RIC z@;S0hTI(jqjgS2o>?i0o!H>i`oHC8L3bgYVFG2LUI{L6o_xP8u=RGLnjN%t)4{M0n zqEm=fO+cAFqWW*V%YYmyL7poh-4OalMSme}sPnLxpe}d|WFGe0t9}SujE5&Up*KW_ zQ^8m{O1QN;;G=Hwq!D=J*R^(rk%4%1Lr3dxzv*Zb%L%bNqnoX+tDLjn#~cut`NMtt z##4=N=bxXWe~xSYZde|=Qdo2|U+1VGaI$|jQp{a3`=)mTV)9pOcW@hSozNsCb^t-KR23IP{T$_GE?f(41eZo^e zafKwLx54OcW|a$QJ!;^fX=HC^+M54~-Kw`gr&QwU@JL#-z~yh(V@z;VaPUxtcIBAi z`X$lT^Icch9QH5e+sSUvByzeRK`k_pCGd9i5wfbL@VWO{+i}e{$wkYv&J^w0}Gp>}x~c9oa1Xwv-~uq!=EvW|{zD-!U>Uu|HT4*~JOPoH=lqc^6wE}|Et z0GVw9)B9h#F)Mf_Ujl%Lr~{Nu7fE@K#hm#rpA+&+qDP1cWvXW2wc;KlBRKG=mI>ND zPJZ4QK)|h}T>XfV_oJrIz_$-xB2So5+N+CQ-A!|b7>b|3-!5H6QWmR6paB7tqF<>w38j+4jIcWg^(L26^&kM}?RBsKjPb3K_!-Voy-w*1FOwr2pKSJ(0 zC!6}vG8Z?d_}Avr5gpm6eP?W=sicxB0&k-}0uy0{NLu#5DiTt3`0G z0%p5qXrga|moi6hMb4Y6+&#dff6j}#@qF8?>?AlBsWFdwlE&C2pAaof9`#vRomH8V zm8B(72c{VO7OJ<&qRl26VYtmh1Ifm@5YQr%QO)=4dRTh{v2{L23xaL2Nc>o1sc9)} zA;xQHi01`Quk2lrGhbI9ia5UCv(zDO9<(Z-S1)I*_6ylz&Q339c(b17%+xo4?>Wn6 z($TUrAo#lQQ^k=Hr{;H=l!B!4thaqSymZ!aHIW!M)Qo!@NT^>{muF@R)xC=4keDKj z3~2%FPxLBC)21I!8T@@u7+!GvZFE~~>NDNT%f9$sD+L+Sg-jZi3e88M&APzj+Ai@B zXJ&N1Th2JYlI|#TCQG;T8%r%%$ZZld7iB_4aBKy z7xdrR=^l}HqA zd+mI)Mi456z^)UFpHJ;d}l z_d&aZxxw4fHG*37-_WQ^_snjyoFT2h`Sq7k5I3_dPDhO%r%JRNO?HPBWE1igFbuy- z0;jy^qK_fHhEw$dsE~c_P_HZ)`NEg{P9a+xO{Clz1}jZr;ywdN?M{S2T&?B`TTV`n zqrJT$Av8eoI=T1G!So^1dp2v`^5m6^s;5Yub~tZ{yE{ZtpOZ6bmf>={l4Q9+Z_*M? zlZKY~N+EkDAJmH{Q|y~GwlU*FM(EtxFw_k11_!vC)dm6{%UA9 z5YEby?`;fLl?@v)0<=d_VVLS~_%UxqQ(t;Qu5xsI`ySwNm%s4~XbSOUAVQXY1g6Ab zDjhXbC>LC0eoVh;QyJN2@Qph*oSE8M4d~u(m%OO%D5jt6eCu{evxdZrBFlrLD5Ke^ zR$dgQ^kx`1)WUBqtOz1J3kEZ0=a@B+Sk zFZBTPzY{>HjN;qoBk#UDN8JcKS0RB^j602YS6jPG8On!#&Klowy-C zKb*SA6l$|z(mT{8yslnwzRk_=p^++r-_iC|_yXLtWXQX&2gVgw*H|aC^gZ02bxpJ< z2uER6my>xJKR{k*0CtBnC7#`&NBC_FN4aH&RPL*9^2mHST6;QIj>|2lV;3cNUTi*I zQ?ZN}^o??DCoQjV$==~GAKYt?rr42{Wtul6A9?zjOe-Tl5LcCc|c<9aZ6smsY&k{MaGQs^7oDT zRFRJ2-VNujT~8lBNHMm^pW;VPxvcvQk$Wn1TczA*Z++aZ$Aq0CAHVQ)^O_)^e3bO3 z5v6b5e%iA~F@+nw*wq-2x}aB$srZ#Jm==E5*!ESkR1Vx38_0jvwDGtnuxP&c@$AD+ zZZ~@8zRfs3xDUnPpz48#e>ZliD5@#1N`8H)I)lqs$n0}7$-!#(M2aNQmdNQO7t!Wl zUkOx!-i8wrD~=Sn!JouI7DI zO70F7iGL_iFPoJ5<@G1I_lY2QpNfOYf?d6Y?j)#)@UNsiWf}aRY9H)B(6z|0c2l~3 z@jDKj@z5jy22}hX2{o7>rK>FWbCMe3P%G7-L9Q6MI;4+a2 literal 0 HcmV?d00001 diff --git a/index.html b/index.html new file mode 100644 index 00000000..7d5f0dd5 --- /dev/null +++ b/index.html @@ -0,0 +1,57 @@ + + + + + + + + + + + vis.js + + + + + +
+
+ View on GitHub + +

vis.js

+

Dynamic, browser-based visualization library

+ +
+ Download this project as a .zip file + Download this project as a tar.gz file +
+
+
+ + +
+
+

vis.js

+ +

Vis.js is a dynamic, browser based visualization library. +The library is designed to be easy to use, to handle large amounts +of dynamic data, and to enable manipulation of the data. +The library consists of Timeline, LineChart, LineChart3d, Graph, and Treegrid.

+ +

vis.js Library is part of CHAP, +the Common Hybrid Agent Platform, developed by Almende B.V.

+
+
+ + + + + + + + diff --git a/javascripts/main.js b/javascripts/main.js new file mode 100644 index 00000000..d8135d37 --- /dev/null +++ b/javascripts/main.js @@ -0,0 +1 @@ +console.log('This would be the main JS file.'); diff --git a/params.json b/params.json new file mode 100644 index 00000000..335c757b --- /dev/null +++ b/params.json @@ -0,0 +1 @@ +{"name":"vis.js","tagline":"Dynamic, browser-based visualization library","body":"vis.js\r\n==================\r\n\r\nVis.js is a dynamic, browser based visualization library.\r\nThe library is designed to be easy to use, to handle large amounts\r\nof dynamic data, and to enable manipulation of the data.\r\nThe library consists of Timeline, LineChart, LineChart3d, Graph, and Treegrid.\r\n\r\nvis.js Library is part of [CHAP](http://chap.almende.com),\r\nthe Common Hybrid Agent Platform, developed by [Almende B.V](http://almende.com).\r\n","google":"","note":"Don't delete this file! It's used internally to help with page regeneration."} \ No newline at end of file diff --git a/stylesheets/pygment_trac.css b/stylesheets/pygment_trac.css new file mode 100644 index 00000000..e65cedff --- /dev/null +++ b/stylesheets/pygment_trac.css @@ -0,0 +1,70 @@ +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f0f3f3; } +.highlight .c { color: #0099FF; font-style: italic } /* Comment */ +.highlight .err { color: #AA0000; background-color: #FFAAAA } /* Error */ +.highlight .k { color: #006699; font-weight: bold } /* Keyword */ +.highlight .o { color: #555555 } /* Operator */ +.highlight .cm { color: #0099FF; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #009999 } /* Comment.Preproc */ +.highlight .c1 { color: #0099FF; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #0099FF; font-weight: bold; font-style: italic } /* Comment.Special */ +.highlight .gd { background-color: #FFCCCC; border: 1px solid #CC0000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #003300; font-weight: bold } /* Generic.Heading */ +.highlight .gi { background-color: #CCFFCC; border: 1px solid #00CC00 } /* Generic.Inserted */ +.highlight .go { color: #AAAAAA } /* Generic.Output */ +.highlight .gp { color: #000099; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #003300; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #99CC66 } /* Generic.Traceback */ +.highlight .kc { color: #006699; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #006699; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #006699; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #006699 } /* Keyword.Pseudo */ +.highlight .kr { color: #006699; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #007788; font-weight: bold } /* Keyword.Type */ +.highlight .m { color: #FF6600 } /* Literal.Number */ +.highlight .s { color: #CC3300 } /* Literal.String */ +.highlight .na { color: #330099 } /* Name.Attribute */ +.highlight .nb { color: #336666 } /* Name.Builtin */ +.highlight .nc { color: #00AA88; font-weight: bold } /* Name.Class */ +.highlight .no { color: #336600 } /* Name.Constant */ +.highlight .nd { color: #9999FF } /* Name.Decorator */ +.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #CC0000; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #CC00FF } /* Name.Function */ +.highlight .nl { color: #9999FF } /* Name.Label */ +.highlight .nn { color: #00CCFF; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #330099; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #003333 } /* Name.Variable */ +.highlight .ow { color: #000000; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mf { color: #FF6600 } /* Literal.Number.Float */ +.highlight .mh { color: #FF6600 } /* Literal.Number.Hex */ +.highlight .mi { color: #FF6600 } /* Literal.Number.Integer */ +.highlight .mo { color: #FF6600 } /* Literal.Number.Oct */ +.highlight .sb { color: #CC3300 } /* Literal.String.Backtick */ +.highlight .sc { color: #CC3300 } /* Literal.String.Char */ +.highlight .sd { color: #CC3300; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #CC3300 } /* Literal.String.Double */ +.highlight .se { color: #CC3300; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #CC3300 } /* Literal.String.Heredoc */ +.highlight .si { color: #AA0000 } /* Literal.String.Interpol */ +.highlight .sx { color: #CC3300 } /* Literal.String.Other */ +.highlight .sr { color: #33AAAA } /* Literal.String.Regex */ +.highlight .s1 { color: #CC3300 } /* Literal.String.Single */ +.highlight .ss { color: #FFCC33 } /* Literal.String.Symbol */ +.highlight .bp { color: #336666 } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #003333 } /* Name.Variable.Class */ +.highlight .vg { color: #003333 } /* Name.Variable.Global */ +.highlight .vi { color: #003333 } /* Name.Variable.Instance */ +.highlight .il { color: #FF6600 } /* Literal.Number.Integer.Long */ + +.type-csharp .highlight .k { color: #0000FF } +.type-csharp .highlight .kt { color: #0000FF } +.type-csharp .highlight .nf { color: #000000; font-weight: normal } +.type-csharp .highlight .nc { color: #2B91AF } +.type-csharp .highlight .nn { color: #000000 } +.type-csharp .highlight .s { color: #A31515 } +.type-csharp .highlight .sc { color: #A31515 } diff --git a/stylesheets/stylesheet.css b/stylesheets/stylesheet.css new file mode 100644 index 00000000..2bd468ab --- /dev/null +++ b/stylesheets/stylesheet.css @@ -0,0 +1,431 @@ +/******************************************************************************* +Slate Theme for GitHub Pages +by Jason Costello, @jsncostello +*******************************************************************************/ + +@import url(pygment_trac.css); + +/******************************************************************************* +MeyerWeb Reset +*******************************************************************************/ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font: inherit; + vertical-align: baseline; +} + +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} + +ol, ul { + list-style: none; +} + +blockquote, q { +} + +table { + border-collapse: collapse; + border-spacing: 0; +} + +a:focus { + outline: none; +} + +/******************************************************************************* +Theme Styles +*******************************************************************************/ + +body { + box-sizing: border-box; + color:#373737; + background: #212121; + font-size: 16px; + font-family: 'Myriad Pro', Calibri, Helvetica, Arial, sans-serif; + line-height: 1.5; + -webkit-font-smoothing: antialiased; +} + +h1, h2, h3, h4, h5, h6 { + margin: 10px 0; + font-weight: 700; + color:#222222; + font-family: 'Lucida Grande', 'Calibri', Helvetica, Arial, sans-serif; + letter-spacing: -1px; +} + +h1 { + font-size: 36px; + font-weight: 700; +} + +h2 { + padding-bottom: 10px; + font-size: 32px; + background: url('../images/bg_hr.png') repeat-x bottom; +} + +h3 { + font-size: 24px; +} + +h4 { + font-size: 21px; +} + +h5 { + font-size: 18px; +} + +h6 { + font-size: 16px; +} + +p { + margin: 10px 0 15px 0; +} + +footer p { + color: #f2f2f2; +} + +a { + text-decoration: none; + color: #007edf; + text-shadow: none; + + transition: color 0.5s ease; + transition: text-shadow 0.5s ease; + -webkit-transition: color 0.5s ease; + -webkit-transition: text-shadow 0.5s ease; + -moz-transition: color 0.5s ease; + -moz-transition: text-shadow 0.5s ease; + -o-transition: color 0.5s ease; + -o-transition: text-shadow 0.5s ease; + -ms-transition: color 0.5s ease; + -ms-transition: text-shadow 0.5s ease; +} + +#main_content a:hover { + color: #0069ba; + text-shadow: #0090ff 0px 0px 2px; +} + +footer a:hover { + color: #43adff; + text-shadow: #0090ff 0px 0px 2px; +} + +em { + font-style: italic; +} + +strong { + font-weight: bold; +} + +img { + position: relative; + margin: 0 auto; + max-width: 739px; + padding: 5px; + margin: 10px 0 10px 0; + border: 1px solid #ebebeb; + + box-shadow: 0 0 5px #ebebeb; + -webkit-box-shadow: 0 0 5px #ebebeb; + -moz-box-shadow: 0 0 5px #ebebeb; + -o-box-shadow: 0 0 5px #ebebeb; + -ms-box-shadow: 0 0 5px #ebebeb; +} + +pre, code { + width: 100%; + color: #222; + background-color: #fff; + + font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; + font-size: 14px; + + border-radius: 2px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + + + +} + +pre { + width: 100%; + padding: 10px; + box-shadow: 0 0 10px rgba(0,0,0,.1); + overflow: auto; +} + +code { + padding: 3px; + margin: 0 3px; + box-shadow: 0 0 10px rgba(0,0,0,.1); +} + +pre code { + display: block; + box-shadow: none; +} + +blockquote { + color: #666; + margin-bottom: 20px; + padding: 0 0 0 20px; + border-left: 3px solid #bbb; +} + +ul, ol, dl { + margin-bottom: 15px +} + +ul li { + list-style: inside; + padding-left: 20px; +} + +ol li { + list-style: decimal inside; + padding-left: 20px; +} + +dl dt { + font-weight: bold; +} + +dl dd { + padding-left: 20px; + font-style: italic; +} + +dl p { + padding-left: 20px; + font-style: italic; +} + +hr { + height: 1px; + margin-bottom: 5px; + border: none; + background: url('../images/bg_hr.png') repeat-x center; +} + +table { + border: 1px solid #373737; + margin-bottom: 20px; + text-align: left; + } + +th { + font-family: 'Lucida Grande', 'Helvetica Neue', Helvetica, Arial, sans-serif; + padding: 10px; + background: #373737; + color: #fff; + } + +td { + padding: 10px; + border: 1px solid #373737; + } + +form { + background: #f2f2f2; + padding: 20px; +} + +img { + width: 100%; + max-width: 100%; +} + +/******************************************************************************* +Full-Width Styles +*******************************************************************************/ + +.outer { + width: 100%; +} + +.inner { + position: relative; + max-width: 640px; + padding: 20px 10px; + margin: 0 auto; +} + +#forkme_banner { + display: block; + position: absolute; + top:0; + right: 10px; + z-index: 10; + padding: 10px 50px 10px 10px; + color: #fff; + background: url('../images/blacktocat.png') #0090ff no-repeat 95% 50%; + font-weight: 700; + box-shadow: 0 0 10px rgba(0,0,0,.5); + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; +} + +#header_wrap { + background: #212121; + background: -moz-linear-gradient(top, #373737, #212121); + background: -webkit-linear-gradient(top, #373737, #212121); + background: -ms-linear-gradient(top, #373737, #212121); + background: -o-linear-gradient(top, #373737, #212121); + background: linear-gradient(top, #373737, #212121); +} + +#header_wrap .inner { + padding: 50px 10px 30px 10px; +} + +#project_title { + margin: 0; + color: #fff; + font-size: 42px; + font-weight: 700; + text-shadow: #111 0px 0px 10px; +} + +#project_tagline { + color: #fff; + font-size: 24px; + font-weight: 300; + background: none; + text-shadow: #111 0px 0px 10px; +} + +#downloads { + position: absolute; + width: 210px; + z-index: 10; + bottom: -40px; + right: 0; + height: 70px; + background: url('../images/icon_download.png') no-repeat 0% 90%; +} + +.zip_download_link { + display: block; + float: right; + width: 90px; + height:70px; + text-indent: -5000px; + overflow: hidden; + background: url(../images/sprite_download.png) no-repeat bottom left; +} + +.tar_download_link { + display: block; + float: right; + width: 90px; + height:70px; + text-indent: -5000px; + overflow: hidden; + background: url(../images/sprite_download.png) no-repeat bottom right; + margin-left: 10px; +} + +.zip_download_link:hover { + background: url(../images/sprite_download.png) no-repeat top left; +} + +.tar_download_link:hover { + background: url(../images/sprite_download.png) no-repeat top right; +} + +#main_content_wrap { + background: #f2f2f2; + border-top: 1px solid #111; + border-bottom: 1px solid #111; +} + +#main_content { + padding-top: 40px; +} + +#footer_wrap { + background: #212121; +} + + + +/******************************************************************************* +Small Device Styles +*******************************************************************************/ + +@media screen and (max-width: 480px) { + body { + font-size:14px; + } + + #downloads { + display: none; + } + + .inner { + min-width: 320px; + max-width: 480px; + } + + #project_title { + font-size: 32px; + } + + h1 { + font-size: 28px; + } + + h2 { + font-size: 24px; + } + + h3 { + font-size: 21px; + } + + h4 { + font-size: 18px; + } + + h5 { + font-size: 14px; + } + + h6 { + font-size: 12px; + } + + code, pre { + min-width: 320px; + max-width: 480px; + font-size: 11px; + } + +} From 15e6e3e57cb8c9e67f9c7544aca489ba0387ded0 Mon Sep 17 00:00:00 2001 From: josdejong Date: Tue, 16 Apr 2013 10:59:38 +0200 Subject: [PATCH 02/52] Initial web page --- css/style.css | 208 +++++++++++++ images/bg_hr.png | Bin 943 -> 0 bytes images/blacktocat.png | Bin 1428 -> 0 bytes images/icon_download.png | Bin 1162 -> 0 bytes images/sprite_download.png | Bin 16799 -> 0 bytes img/forkme_right_darkblue_121621.png | Bin 0 -> 7791 bytes index.html | 72 ++--- javascripts/main.js | 1 - params.json | 1 - stylesheets/pygment_trac.css | 70 ----- stylesheets/stylesheet.css | 431 --------------------------- 11 files changed, 239 insertions(+), 544 deletions(-) create mode 100644 css/style.css delete mode 100644 images/bg_hr.png delete mode 100644 images/blacktocat.png delete mode 100644 images/icon_download.png delete mode 100644 images/sprite_download.png create mode 100644 img/forkme_right_darkblue_121621.png delete mode 100644 javascripts/main.js delete mode 100644 params.json delete mode 100644 stylesheets/pygment_trac.css delete mode 100644 stylesheets/stylesheet.css diff --git a/css/style.css b/css/style.css new file mode 100644 index 00000000..8e4e3197 --- /dev/null +++ b/css/style.css @@ -0,0 +1,208 @@ + +html, body { + font-family: arial; + font-size: 11pt; + color: #4D4D4D; + line-height: 1.7em; + + padding: 0px; + margin: 0px; + width: 100%; + height: 100%; +} + +body { + overflow-y: scroll; +} + +#container { + margin: 0 auto; + width: 900px; + width: 600px; + + /* TODO: cleanup + height: 100%; + */ +} + +#menu { + width: 150px; + float: left; + text-align: right; + + /* TODO: cleanup + height: 100%; + position: fixed; + overflow-x: hidden; + overflow-y: auto; + */ +} + +#menu-inner { + padding: 70px 20px 0px 0px; +} + +#contents { + /* TODO: cleanup + margin-left: 150px; + */ + padding: 50px 25px; + + width: 700px; + float: left; +} + +h2 { + padding-top: 20px; + padding-bottom: 10px; + border-bottom: 1px solid #a0c0f0; + color: #2B7CE9; +} + +a { + color: #2B7CE9; + text-decoration: none; +} +a:visited { + color: #2E60A4; +} +a:hover { + color: red; + text-decoration: underline; +} + +/* +ul.nav { + text-decoration: none; + text-transform: uppercase; + + margin-bottom: 30px; + padding-left: 0px; +} +li.nav { + list-style: none; +} + +ul li.nav { + text-decoration: none; + text-transform: uppercase; + font-weight: bold; + font-size: 11pt; + color: #2B7CE9; + + margin-top: 5px; +} + +ul li ul li.nav { + text-decoration: none; + text-transform: none; + font-weight: normal; + font-size: 11pt; + color: #4D4D4D; +} +*/ + +div.nav ul { + text-decoration: none; + text-transform: uppercase; + + margin-bottom: 30px; + padding-left: 0px; +} +li.nav { + +} + +div.nav ul li { + text-decoration: none; + text-transform: uppercase; + font-weight: bold; + font-size: 11pt; + color: #2B7CE9; + + list-style: none; + margin-top: 5px; +} + +div.nav ul li ul li { + text-decoration: none; + text-transform: none; + font-weight: normal; + font-size: 11pt; + color: #4D4D4D; + + list-style: none; +} + +a.nav { + color: #4D4D4D; +} + +a.nav:hover { + color: #2B7CE9; +} + + +table.example { + border-collapse: collapse; +} + +th.example { + font-weight: normal; + border: 1px solid lightgray; + background-color: #E5E5E5; + text-align: left; + vertical-align: top; + padding: 5px; +} +td.example { + border: 1px solid lightgray; + padding: 5px; +} + + +pre { + line-height: 1.5em; + font-size: 10pt; + overflow-x: auto; + background-color: #F5F5F5; + border: 1px solid lightgray; + padding: 5px; +} + +pre.example { + background-color: transparent; + border: none; + padding: 0px; + margin: 0px; +} + + +div.lastupdate { + font-size: 75%; + margin-top: 40px; + + border-top: 1px solid #a0c0f0; + color: #2B7CE9; +} + +img { + border: none; +} + +img.thumb { + border: 1px solid #a0c0f0; + width: 120px; + height: 60px; +} + +img.thumb:hover { + border-color: #2E60A4; +} + +#forkme { + position: fixed; + top: 0; + right: 0; + border: 0; +} \ No newline at end of file diff --git a/images/bg_hr.png b/images/bg_hr.png deleted file mode 100644 index 7973bd69888c7e10ccad1111d555ceabb7cd99b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 943 zcmaJ=O^ee&7!FiK7FWCot{@Ck@nrMW&tx0B-6VAbrk1u~FTzffX&bu9#AIsIdef8t z!QZfdz=K}>3m(LO;6X3qN}Y6@>cJYA%)G<%Jn!ec>9im1@7>wsIBwrMF}iHO!q%;8 zSJ@xEd~(FL18NRvkBsOXMVM>4WQc*~qcQGc17IjxRnj!O_^B1gan0x#EWT48PK->5B2>mI;LIx zC*FSw$Nfc!g)WZCEOJ=mM)}lLsOk|$ltg_(&ax_YCWMlBLPDVT%D_gB7o_$YZ`-OB z#1sV%whRq21>W;qwN$N?OUGtQQe;JvOsQrna;+v+j8dth=*?orHHb6waX>S!yXCgT zo!oR3{E&GzaOAzfZYv@_Sf{LdyJInS>TS60&R9%yCs$y>2x(*gYIJtRrYAja$Ceq} z!N&oc_K1!3-Ft`U>`CM;quEbB4KG%!MovB*9_3!QzFhqHwrbwK|Doo-y>auDJNSP6 T=d)j*_4El@X4^PFK7I8YBT*xD diff --git a/images/blacktocat.png b/images/blacktocat.png deleted file mode 100644 index 6e264fe57a2e35a2855405ac7d4102c3f6ddcdae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1428 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 diff --git a/img/forkme_right_darkblue_121621.png b/img/forkme_right_darkblue_121621.png new file mode 100644 index 0000000000000000000000000000000000000000..146ef8a800602169cf78c686fc5a6d138a76bc0a GIT binary patch literal 7791 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 - + - + - + - vis.js - + vis.js | dynamic, browser-based visualization library + - + - -
-
- View on GitHub +
+

vis.js

-

vis.js

-

Dynamic, browser-based visualization library

+

+ Vis.js is a dynamic, browser based visualization library. + The library is designed to be easy to use, to handle large amounts + of dynamic data, and to enable manipulation of the data. + The library consists of a Timeline, LineChart, LineChart3d, Graph, and Treegrid. +

-
- Download this project as a .zip file - Download this project as a tar.gz file -
-
-
+

+ Vis.js Library is part of CHAP, + the Common Hybrid Agent Platform, developed by Almende B.V. + It is the successor of the CHAP Links Library. +

- -
-
-

vis.js

+

+ The source code of vis.js is available on github: + https://github.com/almende/vis +

-

Vis.js is a dynamic, browser based visualization library. -The library is designed to be easy to use, to handle large amounts -of dynamic data, and to enable manipulation of the data. -The library consists of Timeline, LineChart, LineChart3d, Graph, and Treegrid.

+

+ Coming soon... +

+
-

vis.js Library is part of CHAP, -the Common Hybrid Agent Platform, developed by Almende B.V.

- - + + Fork me on GitHub + - - - - - - + diff --git a/javascripts/main.js b/javascripts/main.js deleted file mode 100644 index d8135d37..00000000 --- a/javascripts/main.js +++ /dev/null @@ -1 +0,0 @@ -console.log('This would be the main JS file.'); diff --git a/params.json b/params.json deleted file mode 100644 index 335c757b..00000000 --- a/params.json +++ /dev/null @@ -1 +0,0 @@ -{"name":"vis.js","tagline":"Dynamic, browser-based visualization library","body":"vis.js\r\n==================\r\n\r\nVis.js is a dynamic, browser based visualization library.\r\nThe library is designed to be easy to use, to handle large amounts\r\nof dynamic data, and to enable manipulation of the data.\r\nThe library consists of Timeline, LineChart, LineChart3d, Graph, and Treegrid.\r\n\r\nvis.js Library is part of [CHAP](http://chap.almende.com),\r\nthe Common Hybrid Agent Platform, developed by [Almende B.V](http://almende.com).\r\n","google":"","note":"Don't delete this file! It's used internally to help with page regeneration."} \ No newline at end of file diff --git a/stylesheets/pygment_trac.css b/stylesheets/pygment_trac.css deleted file mode 100644 index e65cedff..00000000 --- a/stylesheets/pygment_trac.css +++ /dev/null @@ -1,70 +0,0 @@ -.highlight .hll { background-color: #ffffcc } -.highlight { background: #f0f3f3; } -.highlight .c { color: #0099FF; font-style: italic } /* Comment */ -.highlight .err { color: #AA0000; background-color: #FFAAAA } /* Error */ -.highlight .k { color: #006699; font-weight: bold } /* Keyword */ -.highlight .o { color: #555555 } /* Operator */ -.highlight .cm { color: #0099FF; font-style: italic } /* Comment.Multiline */ -.highlight .cp { color: #009999 } /* Comment.Preproc */ -.highlight .c1 { color: #0099FF; font-style: italic } /* Comment.Single */ -.highlight .cs { color: #0099FF; font-weight: bold; font-style: italic } /* Comment.Special */ -.highlight .gd { background-color: #FFCCCC; border: 1px solid #CC0000 } /* Generic.Deleted */ -.highlight .ge { font-style: italic } /* Generic.Emph */ -.highlight .gr { color: #FF0000 } /* Generic.Error */ -.highlight .gh { color: #003300; font-weight: bold } /* Generic.Heading */ -.highlight .gi { background-color: #CCFFCC; border: 1px solid #00CC00 } /* Generic.Inserted */ -.highlight .go { color: #AAAAAA } /* Generic.Output */ -.highlight .gp { color: #000099; font-weight: bold } /* Generic.Prompt */ -.highlight .gs { font-weight: bold } /* Generic.Strong */ -.highlight .gu { color: #003300; font-weight: bold } /* Generic.Subheading */ -.highlight .gt { color: #99CC66 } /* Generic.Traceback */ -.highlight .kc { color: #006699; font-weight: bold } /* Keyword.Constant */ -.highlight .kd { color: #006699; font-weight: bold } /* Keyword.Declaration */ -.highlight .kn { color: #006699; font-weight: bold } /* Keyword.Namespace */ -.highlight .kp { color: #006699 } /* Keyword.Pseudo */ -.highlight .kr { color: #006699; font-weight: bold } /* Keyword.Reserved */ -.highlight .kt { color: #007788; font-weight: bold } /* Keyword.Type */ -.highlight .m { color: #FF6600 } /* Literal.Number */ -.highlight .s { color: #CC3300 } /* Literal.String */ -.highlight .na { color: #330099 } /* Name.Attribute */ -.highlight .nb { color: #336666 } /* Name.Builtin */ -.highlight .nc { color: #00AA88; font-weight: bold } /* Name.Class */ -.highlight .no { color: #336600 } /* Name.Constant */ -.highlight .nd { color: #9999FF } /* Name.Decorator */ -.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */ -.highlight .ne { color: #CC0000; font-weight: bold } /* Name.Exception */ -.highlight .nf { color: #CC00FF } /* Name.Function */ -.highlight .nl { color: #9999FF } /* Name.Label */ -.highlight .nn { color: #00CCFF; font-weight: bold } /* Name.Namespace */ -.highlight .nt { color: #330099; font-weight: bold } /* Name.Tag */ -.highlight .nv { color: #003333 } /* Name.Variable */ -.highlight .ow { color: #000000; font-weight: bold } /* Operator.Word */ -.highlight .w { color: #bbbbbb } /* Text.Whitespace */ -.highlight .mf { color: #FF6600 } /* Literal.Number.Float */ -.highlight .mh { color: #FF6600 } /* Literal.Number.Hex */ -.highlight .mi { color: #FF6600 } /* Literal.Number.Integer */ -.highlight .mo { color: #FF6600 } /* Literal.Number.Oct */ -.highlight .sb { color: #CC3300 } /* Literal.String.Backtick */ -.highlight .sc { color: #CC3300 } /* Literal.String.Char */ -.highlight .sd { color: #CC3300; font-style: italic } /* Literal.String.Doc */ -.highlight .s2 { color: #CC3300 } /* Literal.String.Double */ -.highlight .se { color: #CC3300; font-weight: bold } /* Literal.String.Escape */ -.highlight .sh { color: #CC3300 } /* Literal.String.Heredoc */ -.highlight .si { color: #AA0000 } /* Literal.String.Interpol */ -.highlight .sx { color: #CC3300 } /* Literal.String.Other */ -.highlight .sr { color: #33AAAA } /* Literal.String.Regex */ -.highlight .s1 { color: #CC3300 } /* Literal.String.Single */ -.highlight .ss { color: #FFCC33 } /* Literal.String.Symbol */ -.highlight .bp { color: #336666 } /* Name.Builtin.Pseudo */ -.highlight .vc { color: #003333 } /* Name.Variable.Class */ -.highlight .vg { color: #003333 } /* Name.Variable.Global */ -.highlight .vi { color: #003333 } /* Name.Variable.Instance */ -.highlight .il { color: #FF6600 } /* Literal.Number.Integer.Long */ - -.type-csharp .highlight .k { color: #0000FF } -.type-csharp .highlight .kt { color: #0000FF } -.type-csharp .highlight .nf { color: #000000; font-weight: normal } -.type-csharp .highlight .nc { color: #2B91AF } -.type-csharp .highlight .nn { color: #000000 } -.type-csharp .highlight .s { color: #A31515 } -.type-csharp .highlight .sc { color: #A31515 } diff --git a/stylesheets/stylesheet.css b/stylesheets/stylesheet.css deleted file mode 100644 index 2bd468ab..00000000 --- a/stylesheets/stylesheet.css +++ /dev/null @@ -1,431 +0,0 @@ -/******************************************************************************* -Slate Theme for GitHub Pages -by Jason Costello, @jsncostello -*******************************************************************************/ - -@import url(pygment_trac.css); - -/******************************************************************************* -MeyerWeb Reset -*******************************************************************************/ - -html, body, div, span, applet, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, big, cite, code, -del, dfn, em, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, -b, u, i, center, -dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td, -article, aside, canvas, details, embed, -figure, figcaption, footer, header, hgroup, -menu, nav, output, ruby, section, summary, -time, mark, audio, video { - margin: 0; - padding: 0; - border: 0; - font: inherit; - vertical-align: baseline; -} - -/* HTML5 display-role reset for older browsers */ -article, aside, details, figcaption, figure, -footer, header, hgroup, menu, nav, section { - display: block; -} - -ol, ul { - list-style: none; -} - -blockquote, q { -} - -table { - border-collapse: collapse; - border-spacing: 0; -} - -a:focus { - outline: none; -} - -/******************************************************************************* -Theme Styles -*******************************************************************************/ - -body { - box-sizing: border-box; - color:#373737; - background: #212121; - font-size: 16px; - font-family: 'Myriad Pro', Calibri, Helvetica, Arial, sans-serif; - line-height: 1.5; - -webkit-font-smoothing: antialiased; -} - -h1, h2, h3, h4, h5, h6 { - margin: 10px 0; - font-weight: 700; - color:#222222; - font-family: 'Lucida Grande', 'Calibri', Helvetica, Arial, sans-serif; - letter-spacing: -1px; -} - -h1 { - font-size: 36px; - font-weight: 700; -} - -h2 { - padding-bottom: 10px; - font-size: 32px; - background: url('../images/bg_hr.png') repeat-x bottom; -} - -h3 { - font-size: 24px; -} - -h4 { - font-size: 21px; -} - -h5 { - font-size: 18px; -} - -h6 { - font-size: 16px; -} - -p { - margin: 10px 0 15px 0; -} - -footer p { - color: #f2f2f2; -} - -a { - text-decoration: none; - color: #007edf; - text-shadow: none; - - transition: color 0.5s ease; - transition: text-shadow 0.5s ease; - -webkit-transition: color 0.5s ease; - -webkit-transition: text-shadow 0.5s ease; - -moz-transition: color 0.5s ease; - -moz-transition: text-shadow 0.5s ease; - -o-transition: color 0.5s ease; - -o-transition: text-shadow 0.5s ease; - -ms-transition: color 0.5s ease; - -ms-transition: text-shadow 0.5s ease; -} - -#main_content a:hover { - color: #0069ba; - text-shadow: #0090ff 0px 0px 2px; -} - -footer a:hover { - color: #43adff; - text-shadow: #0090ff 0px 0px 2px; -} - -em { - font-style: italic; -} - -strong { - font-weight: bold; -} - -img { - position: relative; - margin: 0 auto; - max-width: 739px; - padding: 5px; - margin: 10px 0 10px 0; - border: 1px solid #ebebeb; - - box-shadow: 0 0 5px #ebebeb; - -webkit-box-shadow: 0 0 5px #ebebeb; - -moz-box-shadow: 0 0 5px #ebebeb; - -o-box-shadow: 0 0 5px #ebebeb; - -ms-box-shadow: 0 0 5px #ebebeb; -} - -pre, code { - width: 100%; - color: #222; - background-color: #fff; - - font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; - font-size: 14px; - - border-radius: 2px; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - - - -} - -pre { - width: 100%; - padding: 10px; - box-shadow: 0 0 10px rgba(0,0,0,.1); - overflow: auto; -} - -code { - padding: 3px; - margin: 0 3px; - box-shadow: 0 0 10px rgba(0,0,0,.1); -} - -pre code { - display: block; - box-shadow: none; -} - -blockquote { - color: #666; - margin-bottom: 20px; - padding: 0 0 0 20px; - border-left: 3px solid #bbb; -} - -ul, ol, dl { - margin-bottom: 15px -} - -ul li { - list-style: inside; - padding-left: 20px; -} - -ol li { - list-style: decimal inside; - padding-left: 20px; -} - -dl dt { - font-weight: bold; -} - -dl dd { - padding-left: 20px; - font-style: italic; -} - -dl p { - padding-left: 20px; - font-style: italic; -} - -hr { - height: 1px; - margin-bottom: 5px; - border: none; - background: url('../images/bg_hr.png') repeat-x center; -} - -table { - border: 1px solid #373737; - margin-bottom: 20px; - text-align: left; - } - -th { - font-family: 'Lucida Grande', 'Helvetica Neue', Helvetica, Arial, sans-serif; - padding: 10px; - background: #373737; - color: #fff; - } - -td { - padding: 10px; - border: 1px solid #373737; - } - -form { - background: #f2f2f2; - padding: 20px; -} - -img { - width: 100%; - max-width: 100%; -} - -/******************************************************************************* -Full-Width Styles -*******************************************************************************/ - -.outer { - width: 100%; -} - -.inner { - position: relative; - max-width: 640px; - padding: 20px 10px; - margin: 0 auto; -} - -#forkme_banner { - display: block; - position: absolute; - top:0; - right: 10px; - z-index: 10; - padding: 10px 50px 10px 10px; - color: #fff; - background: url('../images/blacktocat.png') #0090ff no-repeat 95% 50%; - font-weight: 700; - box-shadow: 0 0 10px rgba(0,0,0,.5); - border-bottom-left-radius: 2px; - border-bottom-right-radius: 2px; -} - -#header_wrap { - background: #212121; - background: -moz-linear-gradient(top, #373737, #212121); - background: -webkit-linear-gradient(top, #373737, #212121); - background: -ms-linear-gradient(top, #373737, #212121); - background: -o-linear-gradient(top, #373737, #212121); - background: linear-gradient(top, #373737, #212121); -} - -#header_wrap .inner { - padding: 50px 10px 30px 10px; -} - -#project_title { - margin: 0; - color: #fff; - font-size: 42px; - font-weight: 700; - text-shadow: #111 0px 0px 10px; -} - -#project_tagline { - color: #fff; - font-size: 24px; - font-weight: 300; - background: none; - text-shadow: #111 0px 0px 10px; -} - -#downloads { - position: absolute; - width: 210px; - z-index: 10; - bottom: -40px; - right: 0; - height: 70px; - background: url('../images/icon_download.png') no-repeat 0% 90%; -} - -.zip_download_link { - display: block; - float: right; - width: 90px; - height:70px; - text-indent: -5000px; - overflow: hidden; - background: url(../images/sprite_download.png) no-repeat bottom left; -} - -.tar_download_link { - display: block; - float: right; - width: 90px; - height:70px; - text-indent: -5000px; - overflow: hidden; - background: url(../images/sprite_download.png) no-repeat bottom right; - margin-left: 10px; -} - -.zip_download_link:hover { - background: url(../images/sprite_download.png) no-repeat top left; -} - -.tar_download_link:hover { - background: url(../images/sprite_download.png) no-repeat top right; -} - -#main_content_wrap { - background: #f2f2f2; - border-top: 1px solid #111; - border-bottom: 1px solid #111; -} - -#main_content { - padding-top: 40px; -} - -#footer_wrap { - background: #212121; -} - - - -/******************************************************************************* -Small Device Styles -*******************************************************************************/ - -@media screen and (max-width: 480px) { - body { - font-size:14px; - } - - #downloads { - display: none; - } - - .inner { - min-width: 320px; - max-width: 480px; - } - - #project_title { - font-size: 32px; - } - - h1 { - font-size: 28px; - } - - h2 { - font-size: 24px; - } - - h3 { - font-size: 21px; - } - - h4 { - font-size: 18px; - } - - h5 { - font-size: 14px; - } - - h6 { - font-size: 12px; - } - - code, pre { - min-width: 320px; - max-width: 480px; - font-size: 11px; - } - -} From f2d19b9fc5f2e4acbfd32627fb700ca5df9b7a8e Mon Sep 17 00:00:00 2001 From: josdejong Date: Tue, 16 Apr 2013 11:02:42 +0200 Subject: [PATCH 03/52] CNAME file added --- CNAME | 1 + 1 file changed, 1 insertion(+) create mode 100644 CNAME diff --git a/CNAME b/CNAME new file mode 100644 index 00000000..a527df55 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +visjs.org \ No newline at end of file From e97d7d21182563dd6a3ef07931403cebfbd8420a Mon Sep 17 00:00:00 2001 From: josdejong Date: Tue, 16 Apr 2013 11:17:03 +0200 Subject: [PATCH 04/52] Keywords and title updated --- index.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index 4e321c80..e0571ae1 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,10 @@ - + + + + From 757290e77678dd285cef081901141f77430212db Mon Sep 17 00:00:00 2001 From: josdejong Date: Tue, 16 Apr 2013 12:36:49 +0200 Subject: [PATCH 05/52] Logo created --- .gitignore | 2 + css/style.css | 1 - favicon.ico | Bin 0 -> 4286 bytes img/logo/vis-icon.svg | 90 ++++++++++++++++++++++++++++++++ img/logo/vis-icon16.png | Bin 0 -> 437 bytes img/logo/vis-icon32.ico | Bin 0 -> 4286 bytes img/logo/vis-icon32.png | Bin 0 -> 728 bytes img/logo/vis.svg | 110 ++++++++++++++++++++++++++++++++++++++++ img/logo/vis128.png | Bin 0 -> 3528 bytes img/logo/vis256.png | Bin 0 -> 6952 bytes img/logo/vis64.png | Bin 0 -> 1905 bytes index.html | 83 +++++++++++++++++++++--------- 12 files changed, 261 insertions(+), 25 deletions(-) create mode 100644 .gitignore create mode 100644 favicon.ico create mode 100644 img/logo/vis-icon.svg create mode 100644 img/logo/vis-icon16.png create mode 100644 img/logo/vis-icon32.ico create mode 100644 img/logo/vis-icon32.png create mode 100644 img/logo/vis.svg create mode 100644 img/logo/vis128.png create mode 100644 img/logo/vis256.png create mode 100644 img/logo/vis64.png diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..9a4d5fda --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea +_site diff --git a/css/style.css b/css/style.css index 8e4e3197..29d2e08b 100644 --- a/css/style.css +++ b/css/style.css @@ -18,7 +18,6 @@ body { #container { margin: 0 auto; width: 900px; - width: 600px; /* TODO: cleanup height: 100%; diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..2df678e29e5864cc1c4942e9f9d6a772d4e7ae45 GIT binary patch literal 4286 zcmZQzU<5)11qKkwutI==L5zWcK?8_^LJST-3=+o$J{(x^e-w{~0W1x?-_-H{&Ae2a z;SYOf;Z1LEmlXVeS))xe{C?NeA!GlmE+?wT11aJEW_lFfu!5x-YSPH@KWaZ|;s1VH z-~ZSBKL1}en*4t~G2s8ZHMRdg?4M6k9FiOUpnUbJ)e0luzG^oA|7K3||M%PaiE;uo*gp>(=5V`eb^pIz zUh@CV+~ohSnk_Kg^mcJRUi02A%03zyqo@bj4bP9jxCi<7^`xNxFYENc z_`~iQ2ze}ZKZ^gMOk&!zk50`J=Worhq)P>{jXXq{(smr z6GiXarG+SVQ>&~%vA<3qZU=H&1m&xjwK@p7iGC#KGnjwTX=M9Bc^RIrfN}9|WySyZ zo7(@stT%v*zwUPV|6%WJl(0cJlN3I({h%;?Gc5vc7brixYBGiMU$xnQJdU!UN=v_uD5>&EGJ0Vb~8$yYDu%qQo~S{6Xy`m>z1<*z5Irl=Fb1`cTJ;-zhUmhXFp60E$NYNKP|&{)a=36&%`w@Kre9s`JS6+ literal 0 HcmV?d00001 diff --git a/img/logo/vis-icon.svg b/img/logo/vis-icon.svg new file mode 100644 index 00000000..21de7221 --- /dev/null +++ b/img/logo/vis-icon.svg @@ -0,0 +1,90 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/img/logo/vis-icon16.png b/img/logo/vis-icon16.png new file mode 100644 index 0000000000000000000000000000000000000000..4914cd6345b003e865915c25031f0bdce447cfea GIT binary patch literal 437 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ zu)P6cM!8Z8Q=p(^iEBhjaDG}zd16s2LwR|*US?i)adKios$PCk`s{Z$QVa}?MxHK? zAr`%RC!f`J36wZi|9sx>#2B^7H#NkZy%ued^4%2VWhVBIrCwaS?2V3&hIW#nV33%~ z5|hc*Z;CF&a&z^ zyxpu7)cn;_c=b~kX?AvVyL{23s~6wU{?!sF&Tzf`_4JOPbIyHQa?V*Z>Hn$sI!+Re zk2TvaHP!en;w*@<*vI{1JCoRP=}4{6*4!?O1H29l+QDp5Yu)YCE6YWfe^=b5>LFS1 zQRHJp-wll!OR8O%6J{G^a2xGaN-NBCdVV-q<{ldZ&k~l_Kv`!qR|bKPH>+|>Z$0>A zsglj@X7q9I_MJ;+@o;WF{ONiePr$E`H*@~){hGh_ti+5@>``hsf7Rl literal 0 HcmV?d00001 diff --git a/img/logo/vis-icon32.ico b/img/logo/vis-icon32.ico new file mode 100644 index 0000000000000000000000000000000000000000..2df678e29e5864cc1c4942e9f9d6a772d4e7ae45 GIT binary patch literal 4286 zcmZQzU<5)11qKkwutI==L5zWcK?8_^LJST-3=+o$J{(x^e-w{~0W1x?-_-H{&Ae2a z;SYOf;Z1LEmlXVeS))xe{C?NeA!GlmE+?wT11aJEW_lFfu!5x-YSPH@KWaZ|;s1VH z-~ZSBKL1}en*4t~G2s8ZHMRdg?4M6k9FiOUpnUbJ)e0luzG^oA|7K3||M%PaiE;uo*gp>(=5V`eb^pIz zUh@CV+~ohSnk_Kg^mcJRUi02A%03zyqo@bj4bP9jxCi<7^`xNxFYENc z_`~iQ2ze}ZKZ^gMOk&!zk50`J=Worhq)P>{jXXq{(smr z6GiXarG+SVQ>&~%vA<3qZU=H&1m&xjwK@p7iGC#KGnjwTX=M9Bc^RIrfN}9|WySyZ zo7(@stT%v*zwUPV|6%WJl(0cJlN3I({h%;?Gc5vc7brixYBGiMU$xnQJdU!UN=v_uD5>&EGJ0Vb~8$yYDu%qQo~S{6Xy`m>z1<*z5Irl=Fb1`cTJ;-zhUmhXFp60E$NYNKP|&{)a=36&%`w@Kre9s`JS6+ literal 0 HcmV?d00001 diff --git a/img/logo/vis-icon32.png b/img/logo/vis-icon32.png new file mode 100644 index 0000000000000000000000000000000000000000..3c805ba3868edb3c03efe25ff9d32615160d3690 GIT binary patch literal 728 zcmV;}0w?{6P)Aqj8E((1L`K~S-mzBM&zWqbt&ORh@OWDzlXoW)T>&ZvJWc9|I)9o0D_a`5QtuF5 z0oHbP+mTNNzgGgFSP?vWtx?i?gKz}M{}OB;81{HMrgCRNMOCbEwkTNH($S0#3-k)` zDQnu#@sLbxOeP$VxH+pLS%Kiok;#)CtszCO0q9l#Lq3V+m}=XjqcY2}S^@2SHSO-{ zD!?Dzxa47=sbJ^F6)sOJ_V~@d!DhO1E=rmp_04RtxAXy{Y0l!5!o^^F&Z|)mg);0^ z_sPpWok1VWge@>3;NuUI?R|p}RpreJzRZUAa0S%O=0Dq};|t~3R#CUrK`MvL>wpv!5aUf0coy9t$tuQZODn$zHb#7tOb=7K`d-@2Y_hy6LP#Jz;d+OAF}FPIpX zm>pM$jL3G$wv(&3jq`pB;%{`i?gJ+w#}s4=ChMtx>u{a4IOV}xt3qdh!@S@y-@{4M zMhg>4Lv{UsDF_8*u0)h}b6t_DbZJDPfJ7*8vi}10>U#>#0Dc3|c)V12bjRrc0000< KMNUMnLSTXl7f84O literal 0 HcmV?d00001 diff --git a/img/logo/vis.svg b/img/logo/vis.svg new file mode 100644 index 00000000..9737564b --- /dev/null +++ b/img/logo/vis.svg @@ -0,0 +1,110 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + vis + + + + diff --git a/img/logo/vis128.png b/img/logo/vis128.png new file mode 100644 index 0000000000000000000000000000000000000000..c64d5e5341576560c3c21bc43e053a66ee07900d GIT binary patch literal 3528 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 literal 0 HcmV?d00001 diff --git a/img/logo/vis256.png b/img/logo/vis256.png new file mode 100644 index 0000000000000000000000000000000000000000..bf8df16f567ca0d3e38a2b88e230c99320ae458a GIT binary patch literal 6952 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 literal 0 HcmV?d00001 diff --git a/img/logo/vis64.png b/img/logo/vis64.png new file mode 100644 index 0000000000000000000000000000000000000000..ce4c08e97785b4be248646941b5f685eb3842db4 GIT binary patch literal 1905 zcmV-%2afoOP)Xw>3HhnOOJ$LbfW3C}NZ}<9o z=KIck>&%d^eqE>7$Kc!+z-=55;I;s6^`48%A>dA^{$Dl z1gvBzrdNvuB)VR|LGF7OXlerHHVov{#@1=Bx_}cjgW~3hhS@a(0uOwY5OB7eZ^&Ft zX#w{pbj+?5VuPjwcgHo1E$9uItLX@sUNtb1WR;~9_;E~Q0_I+!sR&SX;HOay)W+=% z1Ni<=6$_htOF~l-FgCAaYrCjDApl2;zpFZMYed6pX72)HQxUL~W)&Nb3;67m$h^y{ z6gNjyhNybbR0NbF8sc!Fmq&k$!^J)}18n3eZaz_=X!Xz2lmtjTaJgUDHUHsb0tQWK za5+tJ`-uYGsLv9bl7Np-hzNU$>79V%5mwyUb&4PUu@9O6kX0xizR)qb>>M~0pC7WF+u0!La2`Z^_B z8C)emGR-cFz~`r&MdCSv>jM(Lexx9^RV3j_Qiu4`Lq_KfWEIvVk{c8oIf{_Us(>bQ zfp?=kWYH>QDI@{7F({!$X1{y*LdU}wx0^AnBZ5$Bbwg7J9ts$Vg?GGz#3!zp&kFF3~p-nHT zP_*g~AzHi~qT%B3lmZhA3bTjb7U0p@Qk-X7rFgzvxf>z?;t>(Cuz;YKL(t2?Cvnhp zikwQ3&KcOq>R3tZm|xeC-LCOmK;(hpgqL}zXcW^+)wgOVViHbwdv>2UvId^cE6g{s zuz+*D^6v9mMz2UfPp621xQtexO>4^&1bKp>%pvxY{B+*H?FVVc@oZfnwW%X-x|&kD zn$;lI#@4vAEA{ueCl5=wblPXDyc1T^<@XnCwW0w2TUF85RqP<5t<@9Y_iz>=ldJWe zWJbdR&i8pO@3-;>R?>w9^GXDM4+o!zgI6jnETWBxl>-qi8k!!3-@DYj{q=LiyqBwRfg zz@^i^-D0R5stO}hi`E+6Ja~7z$Yh9g-l)6yv4g5p+@Hwd)`K+un%TCv#SVHpMO+&S zT8c6=sv=-+Rl`=kXnKSIanq%vUX%Gxm>QqGMrPZ<$aEez?{DId@tkeJBMAf_p7O!x zaaOY`0w`eVN-XcKCM<8zRpZ z6eggx1$eXv3&EzZOJs8LY)W-B%|_z+vWh#8wy=?9Nr;4;-Jog$atgInhR34?H%LTT zcNlN5`Im#DQ9PQ;G4DJAflsnmwWeBXe2!J@SVTlLEFkPJrk!-osMvuu8tWNrs`SbB z8KEWu7S=V!yhNVh;z=L#jhm~#gB{l_Mc%CL&(RWqlHID3y;CLjGRKTmeHYT r6sk_aa|9lNAnfOCQ{Gt8c~SlcnFE9+P>ycx00000NkvXXu0mjf&hdVb literal 0 HcmV?d00001 diff --git a/index.html b/index.html index e0571ae1..ee69a9aa 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,6 @@ - @@ -16,30 +15,66 @@ +
-

vis.js

- -

- Vis.js is a dynamic, browser based visualization library. - The library is designed to be easy to use, to handle large amounts - of dynamic data, and to enable manipulation of the data. - The library consists of a Timeline, LineChart, LineChart3d, Graph, and Treegrid. -

- -

- Vis.js Library is part of CHAP, - the Common Hybrid Agent Platform, developed by Almende B.V. - It is the successor of the CHAP Links Library. -

- -

- The source code of vis.js is available on github: - https://github.com/almende/vis -

- -

- Coming soon... -

+ + + +
+

vis.js

+ +

+ Vis.js is a dynamic, browser based visualization library. + The library is designed to be easy to use, to handle large amounts + of dynamic data, and to enable manipulation of the data. + The library consists of a Timeline, LineChart, LineChart3d, Graph, and Treegrid. +

+ +

+ Vis.js Library is part of CHAP, + the Common Hybrid Agent Platform, developed by Almende B.V. + It is the successor of the CHAP Links Library. +

+ +

+ The source code of vis.js is available on github: + https://github.com/almende/vis +

+ +

+ Coming soon... +

+
From 43145262773b07df92e3c69637c8b6ae8d384da6 Mon Sep 17 00:00:00 2001 From: josdejong Date: Tue, 16 Apr 2013 14:08:06 +0200 Subject: [PATCH 06/52] Logo updated --- img/logo/vis-icon.svg | 8 ++++---- img/logo/vis.svg | 12 ++++++------ img/logo/vis128.png | Bin 3528 -> 3528 bytes img/logo/vis256.png | Bin 6952 -> 6839 bytes img/logo/vis64.png | Bin 1905 -> 1895 bytes index.html | 3 ++- 6 files changed, 12 insertions(+), 11 deletions(-) diff --git a/img/logo/vis-icon.svg b/img/logo/vis-icon.svg index 21de7221..1ec49008 100644 --- a/img/logo/vis-icon.svg +++ b/img/logo/vis-icon.svg @@ -15,9 +15,9 @@ version="1.1" inkscape:version="0.48.3.1 r9886" sodipodi:docname="vis-icon.svg" - inkscape:export-filename="/home/jos/projects/vis-pages/img/logo/vis-icon16.png" - inkscape:export-xdpi="45" - inkscape:export-ydpi="45"> + inkscape:export-filename="/home/jos/projects/vis-pages/img/logo/vis-icon32.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90"> image/svg+xml - + diff --git a/img/logo/vis.svg b/img/logo/vis.svg index 9737564b..387fcbcb 100644 --- a/img/logo/vis.svg +++ b/img/logo/vis.svg @@ -27,9 +27,9 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="4" - inkscape:cx="42.110097" - inkscape:cy="66.949941" + inkscape:zoom="1" + inkscape:cx="-113.31153" + inkscape:cy="88.17545" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" @@ -58,7 +58,7 @@ image/svg+xml - + @@ -78,7 +78,7 @@ xml:space="preserve" id="flowRoot3757" style="font-size:92px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans" - transform="translate(25.084525,901.73727)">vis vis dZ|qrKq>!y)6lKe9EHQ|L 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 lkH)n>fue>?N%fw*lk)|0cA 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 diff --git a/img/logo/vis64.png b/img/logo/vis64.png index ce4c08e97785b4be248646941b5f685eb3842db4..25b7de143f3084e1d217ef9055a75516185c1ed6 100644 GIT binary patch delta 1806 zcmV+p2l4pv4(AS#Zhz!SL_t(|ob8)gZyVPchM!qUij=68+GE+W9II6WIc^=dP12x6 z(-uu`T=)m{pXDYOLEHi<3bZH+qYK&wkZa3zyhx6uO0rB@D`jyV&e97;3(0eal1yfp zO79)XGjqQ4p7-0%43&@mlJYpkP=hugXq*ucv;jfmjDVmG2!9%SkdxnCc9>sx_dmb+ zn#P6huXj%ZC15k-v9NVOz*z6sFUV8x0!>Z8^BtF5v9Wbppe`VT?Rwn0XS2NRqHFM@ zF`YMuw1&*plnVIkQ-|g4Qf#mtxIJU@Xw_-RTun#7!j{XuXXT6aJov*SyDVVV3r$6U z<-i{w+IRxDcYj^@?0%8em-Qu~sR($KbVwHtR<9_aDhIz89r(>Xo2^X!0%KDVu(n&i zunn^bNTa(%}+0vmg0Iax8d^e zxx?Isi|fH~yTWLXDYPL_0?dlp!v_3(TyB!4D%_Yf`S^~-M*4t+>1PhcS03^(>5{d| zCGl*>V}B>-5wB1cG?@#0yI&)0R2z91rVcl+n6!n<$4xCdOf5Q9i-%Gn^)M-RgQg;& zE9$@aJ;XwA^NLZEEP$Sv!h2&nlSAUAHf1w(6m&)vel@A{$=xD$MVk;dV7ymjVnCy> z&7Y)iECB!mag`gB2DfKyHZvY09i;#|mQc~uqkpOC8%+Sfxek?IUpKLwQvGmTG*t|E z6`W-8@P9&IkzFfS}P-y}(J) z7JpHRhExn)!ErrumPgKV$rnB8k@+5U08NE=##^Lvn3~J8o3H&)^4;+kbjeNrF`J|C z)yodLs_^c3L^y6I=ko9Qe9gJ~+I24Vn+$d77@GL>#{+hAF3D}1WXk6GmQB$qXGDim zrxY<%5^-@^noQX|Ua@=)>WXQcPl(I9oqw#mzjy#uh2d`T*vL!&b~t1x{P0pldi`N2 zl+@7{F?oH!Y@k!_O-nxaJ`PM>;r%zFM_PO(JP+1) ztI6Fbz|Y9Oc8ywRjDtP|_>p@Ye0MZVXY6Fn(^kg8cB%uyJ^|^x%T`(}KV4Hu#DC=r zGT{^2N@$=}xP8~&}kb22~ zuv0F3$Mtx;VzHfe*v-3y426hU$_)MOIz4R~>o3K&ml3eIVKX@*o@BVoU}{brork;R z#??#y(U9B+A1oEPzgQ6dHcd&PvVW)OWl1ZQaoEX<(_L#sCEg-_YAf^qY{8XE@3@ei z=>bxk_h8wc(EmYD2`;S3)7@)==-U_9F?I3o%&*n&gfo?u6M5}o#8-uWs3Ktgh1_Tn z0q1(;6Z_rkxJYH>yBskUemv2_hgV}<9yFzekqA`;?B-q8CB;a0t41_bet(IG6o9R? z!*-^AXZ-2B%gUDjOF^A6jkhjFxcU87zBd{s7Ovgu2uIAnkh{U*9Z$4rL`;eN>$v-S z_}6T%s+1MM&=kHk6ynCUR^GncB6U%a5U{Xblr|CPx(@=LO#Yq+^FFcUq{tLpZhw&_ zQ#jhol8OSOy#^m#jnUOAPJi!00t!V>Dz`*j-KNv zmG=tgdJI}ZD%nFWBvpV1Jdw1(Z4s5xUU6OiG%1fCje_gJ+zX4(?xgwqldSL9%3{tp zPkgy*VM`oM6I|(eF#Ei*@~?&Y7e!`#Y^YSUF9DYA9V?wJZ4{5>k0(Jatn&UFQ7#Xf zRkcVZL?!zkD%Dx@On>n4ip8b=qqU(=8o2x2ts4CuI{h6wZ(W4#j6*tC`cF~L@^D>` zSXiYkqSD(gUsmPOUQGg08HZ<^HbY(hLpOFEX}eqxROa!Hs78lRz!RZhd#vq9j>P=% wV5#;Y<$spsX|o>amJ~9_!Gpy@RqgOUTsC{WAuy<{00000Ne4wvM6N<$g1w}LZ~y=R delta 1816 zcmV+z2j}?b4)G3iA*@dNtL`qGE0fLc_keW+-uS_uRqbV<|@l0f2Sbymkq?lyfei9L7mf@7{BIdAv+ zdglAieCy1RuYO&p*vH`97Qk&B5a6}|ZsULew*_z;f}4{+o`2ObwQTG@pFPT>x8wD$ ziK_&xWGJRriv%RPUcW)^dlzVG0_HXh>M~< zErje$I1%B{AG59tA;6V>0pC7WF+u0!La2 z`Z^_B8C)emGR-cFz~`r&MdCSv>jM(Lexx9^RV3j_Qiu4`Lq_KfWEIvVk{c8oIf{_U zs(>bQfq!?SJY>--WGN&8xG^Z9MP|Qy_(I3S7rI4xpioGS&fB{|QxVYaFR%O#0v_PT zpjeSC0O$-5TuKNS=(bn2DVw2c(B>!jVnDz*k5y=}MElqczpB>(_o zAr99EMBE+Mu#%yOhYJBT5#hjd)mhUUO#lG&gnv1FIV?fZ3-v>-XsQ@c4_-xi;4LEH zRnb%~@Y^#T_oo}P@p1KxfLO@7-c3b7UZu#ZjTu{asD}5w3+#IWTy=pD`goj=H)glj z48MIZ9t}cAq!0 z2A<9<%r~*HfOEa_?(4^&1bKp>%pvxY{B+*H?FVVc@oZfn zwW%X-x|&kDn$;lI#@4vAEA{ueCl5=wblPXDyc1T^<@XnCwW0w2TUF85RqP<5t<@9Y z_iz>=ldJWeWJbdR&i8pO@3-;>R?>w9^GXDM4+o!zgI6jv1$P!KwE$nwVd)m!T0~3*~VI?yahNCplB3}rd2!AQMq^JIpDB~sCxZB zGXu8#W0`lIJFl9%XUQ!v; z8^ZgR(>9Rf;)N5INfJ>;{AYM@+v@F7C}X z@8UWuM#5)^f{ySLS)bZWJEsW18 zwrQ2;2oi@RTs;@SrPIFMVt=R{stO}hi`E+6Ja~7z$Yh9g-l)6yv4g5p+@Hwd)`K+u zn%TCv#SVHpMO+&ST8c6=sv=-+Rl`=kXnKSIanq%vUX%Gxm>QqGMrPZ<$aEez?{DId z@tkeJBMAf_p7O!xaaOY`0w`eVTkG8OpWl4yHoZX;m z0&)tqREEc+1vf}US$7z3u=$sRqES4W$}#Ue0)bDmSGA^EYJ84W>{vuZG%O(OFQ%Pz z&ZyXdH5%&~YpV3g_J0|nCIS}LHO9O|p5Wq1AM=fytG|OC*DOWe!6j?1rpJ=o%yVfv z)O6ag=zn=IfcJVl2ztwl91RPW?Yzvk!DO*g)LckUE-Dy2Cfi<8oLH#8@v%e5$DyNz zM@I{f!MKc^La~<7p=cDUPQh~o9)Te2=WJ8nSkie>{s)-@gb^iBj&AJ$0000

From 807fe3b0af4e96e9d765c3edbe6eaab3806778cc Mon Sep 17 00:00:00 2001 From: josdejong Date: Fri, 3 May 2013 16:35:58 +0200 Subject: [PATCH 07/52] Updated home page --- _layouts/default.html | 63 +++++++++++++++++ index.html | 86 ----------------------- index.md | 159 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 222 insertions(+), 86 deletions(-) create mode 100644 _layouts/default.html delete mode 100644 index.html create mode 100644 index.md diff --git a/_layouts/default.html b/_layouts/default.html new file mode 100644 index 00000000..bf6cfbca --- /dev/null +++ b/_layouts/default.html @@ -0,0 +1,63 @@ + + + + + + + + + + + + + vis.js | a dynamic, browser-based visualization library + + + + + +

+ + + +
+ {{ content }} +
+
+ + + Fork me on GitHub + + + + diff --git a/index.html b/index.html deleted file mode 100644 index 3c65097e..00000000 --- a/index.html +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - - - - - - - vis.js | dynamic, browser-based visualization library - - - - - -
- - - -
-

vis.js

- -

- Vis.js is a dynamic, browser based visualization library. - The library is designed to be easy to use, to handle large amounts - of dynamic data, and to enable manipulation of the data. - The library consists of the components Timeline, LineChart, - LineChart3d, Graph, and TreeGrid. -

- -

- Vis.js Library is part of CHAP, - the Common Hybrid Agent Platform, developed by Almende B.V. - It is the successor of the CHAP Links Library. -

- -

- The source code of vis.js is available on github: - https://github.com/almende/vis -

- -

- Coming soon... -

-
-
- - - Fork me on GitHub - - - - diff --git a/index.md b/index.md new file mode 100644 index 00000000..0f43b872 --- /dev/null +++ b/index.md @@ -0,0 +1,159 @@ +--- +layout: default +title: vis.js +--- + +# vis.js + + +Vis.js is a dynamic, browser based visualization library. +The library is designed to be easy to use, to handle large amounts +of dynamic data, and to enable manipulation of the data. +The library consists of Timeline, LineChart, LineChart3d, Graph, and Treegrid. + +Vis.js Library is part of [CHAP](http://chap.almende.com), +the Common Hybrid Agent Platform, developed by [Almende B.V](http://almende.com). + + +## Install + +Install via npm: + + npm install vis + +Install via bower: + + bower install vis + +Or download the library from the github project: +[https://github.com/almende/vis.git](https://github.com/almende/vis.git). + + +## Load + + +To use a component, include the javascript file of vis in your webpage: + +```html + + + + + + + + + +``` + +or load vis.js using require.js: + +```js +require.config({ + paths: { + vis: 'path/to/vis', + } +}); +require(['vis'], function (math) { + // ... load a visualization +}); +``` + + +A timeline can be instantiated as: + +```js +var timeline = new Timeline(container, data, options); +``` + +Where `container` is an HTML element, `data` is an Array with data or a DataSet, +and `options` is an optional object with configuration options for the +component. + + +## Example + +A basic example on loading a Timeline is shown below. More examples can be +found in the [examples directory](https://github.com/almende/vis/tree/master/examples) +of the project. + +```html + + + + Timeline basic demo + + + + + +
+ + + + +``` + + +## Build + +To build the library from source, clone the project from github + + git clone git://github.com/almende/vis.git + +The project uses [jake](https://github.com/mde/jake) as build tool. +The build script uses [Browserify](http://browserify.org/) to +bundle the source code into a library, +and uses [UglifyJS](http://lisperator.net/uglifyjs/) to minify the code. +The source code uses the module style of node (require and module.exports) to +organize dependencies. + +To install all dependencies and build the library, run `npm install` in the +root of the project. + + cd vis + npm install + +To be able to run jake from the command line, jake must be installed globally: + + sudo npm install -g jake + +Then, the project can be build by executing jake in the root of the project: + + jake + + +## License + +Copyright (C) 2010-2013 Almende B.V. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + From 1e492accfab7eea15880c8a5e9b043371ea76d93 Mon Sep 17 00:00:00 2001 From: josdejong Date: Fri, 3 May 2013 16:42:30 +0200 Subject: [PATCH 08/52] Fixed code examples on the home page --- _config.yml | 0 index.md | 106 ++++++++++++++++++++++++---------------------------- 2 files changed, 49 insertions(+), 57 deletions(-) create mode 100644 _config.yml diff --git a/_config.yml b/_config.yml new file mode 100644 index 00000000..e69de29b diff --git a/index.md b/index.md index 0f43b872..c5c133ad 100644 --- a/index.md +++ b/index.md @@ -34,39 +34,33 @@ Or download the library from the github project: To use a component, include the javascript file of vis in your webpage: -```html - - - - - - - - - -``` + + + + + + + + + or load vis.js using require.js: -```js -require.config({ - paths: { - vis: 'path/to/vis', - } -}); -require(['vis'], function (math) { - // ... load a visualization -}); -``` + require.config({ + paths: { + vis: 'path/to/vis', + } + }); + require(['vis'], function (math) { + // ... load a visualization + }); A timeline can be instantiated as: -```js -var timeline = new Timeline(container, data, options); -``` + var timeline = new Timeline(container, data, options); Where `container` is an HTML element, `data` is an Array with data or a DataSet, and `options` is an optional object with configuration options for the @@ -79,38 +73,36 @@ A basic example on loading a Timeline is shown below. More examples can be found in the [examples directory](https://github.com/almende/vis/tree/master/examples) of the project. -```html - - - - Timeline basic demo - + + + + Timeline basic demo + + + + + +
- - - -
- - - - -``` + + + ## Build From 49a00ceb5aabeda232672ec796e02d74ec251c7e Mon Sep 17 00:00:00 2001 From: josdejong Date: Fri, 7 Jun 2013 11:48:41 +0200 Subject: [PATCH 09/52] Added docs and examples --- docs/css/prettify.css | 87 + docs/css/style.css | 69 + docs/dataset.html | 23 + docs/graph.html | 1136 +++++++++ docs/img/graph/graph.png | Bin 0 -> 23400 bytes docs/img/graph/graph120x60.png | Bin 0 -> 4678 bytes docs/img/timeline/timeline.png | Bin 0 -> 23229 bytes docs/img/timeline/timeline120x60.png | Bin 0 -> 6671 bytes docs/index.html | 29 + docs/lib/prettify/lang-apollo.js | 2 + docs/lib/prettify/lang-css.js | 2 + docs/lib/prettify/lang-hs.js | 2 + docs/lib/prettify/lang-lisp.js | 2 + docs/lib/prettify/lang-lua.js | 2 + docs/lib/prettify/lang-ml.js | 2 + docs/lib/prettify/lang-proto.js | 1 + docs/lib/prettify/lang-scala.js | 2 + docs/lib/prettify/lang-sql.js | 2 + docs/lib/prettify/lang-vb.js | 2 + docs/lib/prettify/lang-vhdl.js | 3 + docs/lib/prettify/lang-wiki.js | 2 + docs/lib/prettify/lang-yaml.js | 2 + docs/lib/prettify/prettify.css | 1 + docs/lib/prettify/prettify.js | 33 + docs/timeline.html | 492 ++++ examples/graph/01_basic_usage.html | 50 + examples/graph/02_random_nodes.html | 110 + examples/graph/03_images.html | 83 + examples/graph/04_shapes.html | 76 + examples/graph/05_social_network.html | 78 + examples/graph/06_groups.html | 160 ++ examples/graph/07_selections.html | 76 + examples/graph/08_mobile_friendly.html | 108 + examples/graph/09_sizing.html | 80 + examples/graph/10_multiline_text.html | 50 + examples/graph/11_custom_style.html | 131 + examples/graph/12_scalable_images.html | 85 + examples/graph/13_dashed_lines.html | 65 + examples/graph/14_dot_language.html | 18 + .../graph/15_dot_language_playground.html | 209 ++ examples/graph/graphviz/data/fsm.gv.txt | 20 + examples/graph/graphviz/data/hello.gv.txt | 1 + examples/graph/graphviz/data/process.gv.txt | 15 + examples/graph/graphviz/data/siblings.gv.txt | 512 ++++ examples/graph/graphviz/data/softmaint.gv.txt | 377 +++ .../graph/graphviz/data/traffic_lights.gv.txt | 29 + .../graph/graphviz/data/transparency.gv.txt | 105 + examples/graph/graphviz/data/twopi2.gv.txt | 2212 +++++++++++++++++ examples/graph/graphviz/data/unix.gv.txt | 55 + examples/graph/graphviz/data/world.gv.txt | 67 + examples/graph/graphviz/graphviz_gallery.html | 88 + examples/graph/graphviz/screenshots/fsm.png | Bin 0 -> 70809 bytes examples/graph/graphviz/screenshots/hello.png | Bin 0 -> 18000 bytes .../graph/graphviz/screenshots/softmaint.png | Bin 0 -> 267856 bytes .../graphviz/screenshots/traffic_lights.png | Bin 0 -> 59829 bytes .../img/refresh-cl/Hardware-Fax-icon.png | Bin 0 -> 3645 bytes .../img/refresh-cl/Hardware-Laptop-1-icon.png | Bin 0 -> 3781 bytes .../refresh-cl/Hardware-Mobile-Phone-icon.png | Bin 0 -> 3463 bytes .../Hardware-My-Computer-3-icon.png | Bin 0 -> 5402 bytes .../refresh-cl/Hardware-My-PDA-02-icon.png | Bin 0 -> 3531 bytes .../refresh-cl/Hardware-My-PDA-04-icon.png | Bin 0 -> 4153 bytes .../refresh-cl/Hardware-My-PDA-05-icon.png | Bin 0 -> 4131 bytes .../Hardware-My-Phone-Picture-icon.png | Bin 0 -> 3234 bytes .../refresh-cl/Hardware-Printer-Blue-icon.png | Bin 0 -> 3478 bytes .../refresh-cl/Misc-Scanner-default-icon.png | Bin 0 -> 3168 bytes .../img/refresh-cl/Network-Drive-icon.png | Bin 0 -> 3320 bytes .../Network-Internet-Connection-icon.png | Bin 0 -> 4320 bytes .../img/refresh-cl/Network-Pipe-icon.png | Bin 0 -> 1000 bytes .../img/refresh-cl/System-Firewall-2-icon.png | Bin 0 -> 4668 bytes .../img/refresh-cl/System-Globe-icon.png | Bin 0 -> 4595 bytes examples/graph/img/refresh-cl/license.txt | 14 + .../img/soft-scraps-icons/Document-icon24.png | Bin 0 -> 1104 bytes .../img/soft-scraps-icons/Document-icon32.png | Bin 0 -> 2771 bytes .../img/soft-scraps-icons/Document-icon48.png | Bin 0 -> 2771 bytes .../img/soft-scraps-icons/Email-icon24.png | Bin 0 -> 668 bytes .../img/soft-scraps-icons/Email-icon32.png | Bin 0 -> 873 bytes .../img/soft-scraps-icons/Email-icon48.png | Bin 0 -> 1487 bytes .../img/soft-scraps-icons/Folder-icon24.png | Bin 0 -> 691 bytes .../img/soft-scraps-icons/Folder-icon32.png | Bin 0 -> 874 bytes .../img/soft-scraps-icons/Folder-icon48.png | Bin 0 -> 1506 bytes .../img/soft-scraps-icons/Folder-icon64.png | Bin 0 -> 1771 bytes .../soft-scraps-icons/Smiley-Angry-icon.png | Bin 0 -> 3210 bytes .../soft-scraps-icons/Smiley-Grin-icon.png | Bin 0 -> 3917 bytes .../User-Administrator-Blue-icon.png | Bin 0 -> 3901 bytes .../User-Administrator-Green-icon.png | Bin 0 -> 3906 bytes .../soft-scraps-icons/User-Coat-Blue-icon.png | Bin 0 -> 3559 bytes .../User-Coat-Green-icon.png | Bin 0 -> 3571 bytes .../soft-scraps-icons/User-Coat-Red-icon.png | Bin 0 -> 3544 bytes .../User-Executive-Green-icon.png | Bin 0 -> 3805 bytes .../User-Preppy-Blue-icon.png | Bin 0 -> 3802 bytes .../User-Preppy-Red-icon.png | Bin 0 -> 3800 bytes .../graph/img/soft-scraps-icons/license.txt | 12 + examples/timeline/01_basic.html | 31 + examples/timeline/02_dataset.html | 54 + examples/timeline/03_much_data.html | 65 + examples/timeline/04_html_data.html | 69 + examples/timeline/05_groups.html | 64 + .../img/Hardware-Mobile-Phone-icon.png | Bin 0 -> 3463 bytes examples/timeline/img/attachment-icon.png | Bin 0 -> 2774 bytes examples/timeline/img/blog-post-edit-icon.png | Bin 0 -> 4225 bytes examples/timeline/img/comments-icon.png | Bin 0 -> 3173 bytes .../timeline/img/community-users-icon.png | Bin 0 -> 4664 bytes examples/timeline/img/license.txt | 17 + .../timeline/img/license_aesthetica-2.txt | 36 + examples/timeline/img/license_refresh-cl.txt | 26 + examples/timeline/img/mail-icon.png | Bin 0 -> 3298 bytes examples/timeline/img/notes-edit-icon.png | Bin 0 -> 2913 bytes examples/timeline/img/product-icon.png | Bin 0 -> 1594 bytes examples/timeline/img/truck-icon.png | Bin 0 -> 1703 bytes .../timeline/requirejs/requirejs_example.html | 11 + examples/timeline/requirejs/scripts/main.js | 19 + .../timeline/requirejs/scripts/require.js | 35 + 112 files changed, 7209 insertions(+) create mode 100644 docs/css/prettify.css create mode 100644 docs/css/style.css create mode 100644 docs/dataset.html create mode 100644 docs/graph.html create mode 100644 docs/img/graph/graph.png create mode 100644 docs/img/graph/graph120x60.png create mode 100644 docs/img/timeline/timeline.png create mode 100644 docs/img/timeline/timeline120x60.png create mode 100644 docs/index.html create mode 100644 docs/lib/prettify/lang-apollo.js create mode 100644 docs/lib/prettify/lang-css.js create mode 100644 docs/lib/prettify/lang-hs.js create mode 100644 docs/lib/prettify/lang-lisp.js create mode 100644 docs/lib/prettify/lang-lua.js create mode 100644 docs/lib/prettify/lang-ml.js create mode 100644 docs/lib/prettify/lang-proto.js create mode 100644 docs/lib/prettify/lang-scala.js create mode 100644 docs/lib/prettify/lang-sql.js create mode 100644 docs/lib/prettify/lang-vb.js create mode 100644 docs/lib/prettify/lang-vhdl.js create mode 100644 docs/lib/prettify/lang-wiki.js create mode 100644 docs/lib/prettify/lang-yaml.js create mode 100644 docs/lib/prettify/prettify.css create mode 100644 docs/lib/prettify/prettify.js create mode 100644 docs/timeline.html create mode 100644 examples/graph/01_basic_usage.html create mode 100755 examples/graph/02_random_nodes.html create mode 100755 examples/graph/03_images.html create mode 100755 examples/graph/04_shapes.html create mode 100644 examples/graph/05_social_network.html create mode 100644 examples/graph/06_groups.html create mode 100644 examples/graph/07_selections.html create mode 100755 examples/graph/08_mobile_friendly.html create mode 100644 examples/graph/09_sizing.html create mode 100755 examples/graph/10_multiline_text.html create mode 100644 examples/graph/11_custom_style.html create mode 100644 examples/graph/12_scalable_images.html create mode 100644 examples/graph/13_dashed_lines.html create mode 100644 examples/graph/14_dot_language.html create mode 100644 examples/graph/15_dot_language_playground.html create mode 100644 examples/graph/graphviz/data/fsm.gv.txt create mode 100644 examples/graph/graphviz/data/hello.gv.txt create mode 100644 examples/graph/graphviz/data/process.gv.txt create mode 100644 examples/graph/graphviz/data/siblings.gv.txt create mode 100644 examples/graph/graphviz/data/softmaint.gv.txt create mode 100644 examples/graph/graphviz/data/traffic_lights.gv.txt create mode 100644 examples/graph/graphviz/data/transparency.gv.txt create mode 100644 examples/graph/graphviz/data/twopi2.gv.txt create mode 100644 examples/graph/graphviz/data/unix.gv.txt create mode 100644 examples/graph/graphviz/data/world.gv.txt create mode 100644 examples/graph/graphviz/graphviz_gallery.html create mode 100644 examples/graph/graphviz/screenshots/fsm.png create mode 100644 examples/graph/graphviz/screenshots/hello.png create mode 100644 examples/graph/graphviz/screenshots/softmaint.png create mode 100644 examples/graph/graphviz/screenshots/traffic_lights.png create mode 100644 examples/graph/img/refresh-cl/Hardware-Fax-icon.png create mode 100644 examples/graph/img/refresh-cl/Hardware-Laptop-1-icon.png create mode 100644 examples/graph/img/refresh-cl/Hardware-Mobile-Phone-icon.png create mode 100644 examples/graph/img/refresh-cl/Hardware-My-Computer-3-icon.png create mode 100644 examples/graph/img/refresh-cl/Hardware-My-PDA-02-icon.png create mode 100644 examples/graph/img/refresh-cl/Hardware-My-PDA-04-icon.png create mode 100644 examples/graph/img/refresh-cl/Hardware-My-PDA-05-icon.png create mode 100644 examples/graph/img/refresh-cl/Hardware-My-Phone-Picture-icon.png create mode 100644 examples/graph/img/refresh-cl/Hardware-Printer-Blue-icon.png create mode 100644 examples/graph/img/refresh-cl/Misc-Scanner-default-icon.png create mode 100644 examples/graph/img/refresh-cl/Network-Drive-icon.png create mode 100644 examples/graph/img/refresh-cl/Network-Internet-Connection-icon.png create mode 100644 examples/graph/img/refresh-cl/Network-Pipe-icon.png create mode 100644 examples/graph/img/refresh-cl/System-Firewall-2-icon.png create mode 100644 examples/graph/img/refresh-cl/System-Globe-icon.png create mode 100644 examples/graph/img/refresh-cl/license.txt create mode 100644 examples/graph/img/soft-scraps-icons/Document-icon24.png create mode 100644 examples/graph/img/soft-scraps-icons/Document-icon32.png create mode 100644 examples/graph/img/soft-scraps-icons/Document-icon48.png create mode 100644 examples/graph/img/soft-scraps-icons/Email-icon24.png create mode 100644 examples/graph/img/soft-scraps-icons/Email-icon32.png create mode 100644 examples/graph/img/soft-scraps-icons/Email-icon48.png create mode 100644 examples/graph/img/soft-scraps-icons/Folder-icon24.png create mode 100644 examples/graph/img/soft-scraps-icons/Folder-icon32.png create mode 100644 examples/graph/img/soft-scraps-icons/Folder-icon48.png create mode 100644 examples/graph/img/soft-scraps-icons/Folder-icon64.png create mode 100644 examples/graph/img/soft-scraps-icons/Smiley-Angry-icon.png create mode 100644 examples/graph/img/soft-scraps-icons/Smiley-Grin-icon.png create mode 100644 examples/graph/img/soft-scraps-icons/User-Administrator-Blue-icon.png create mode 100644 examples/graph/img/soft-scraps-icons/User-Administrator-Green-icon.png create mode 100644 examples/graph/img/soft-scraps-icons/User-Coat-Blue-icon.png create mode 100644 examples/graph/img/soft-scraps-icons/User-Coat-Green-icon.png create mode 100644 examples/graph/img/soft-scraps-icons/User-Coat-Red-icon.png create mode 100644 examples/graph/img/soft-scraps-icons/User-Executive-Green-icon.png create mode 100644 examples/graph/img/soft-scraps-icons/User-Preppy-Blue-icon.png create mode 100644 examples/graph/img/soft-scraps-icons/User-Preppy-Red-icon.png create mode 100644 examples/graph/img/soft-scraps-icons/license.txt create mode 100644 examples/timeline/01_basic.html create mode 100644 examples/timeline/02_dataset.html create mode 100644 examples/timeline/03_much_data.html create mode 100644 examples/timeline/04_html_data.html create mode 100644 examples/timeline/05_groups.html create mode 100644 examples/timeline/img/Hardware-Mobile-Phone-icon.png create mode 100755 examples/timeline/img/attachment-icon.png create mode 100755 examples/timeline/img/blog-post-edit-icon.png create mode 100755 examples/timeline/img/comments-icon.png create mode 100755 examples/timeline/img/community-users-icon.png create mode 100644 examples/timeline/img/license.txt create mode 100644 examples/timeline/img/license_aesthetica-2.txt create mode 100644 examples/timeline/img/license_refresh-cl.txt create mode 100755 examples/timeline/img/mail-icon.png create mode 100755 examples/timeline/img/notes-edit-icon.png create mode 100644 examples/timeline/img/product-icon.png create mode 100644 examples/timeline/img/truck-icon.png create mode 100644 examples/timeline/requirejs/requirejs_example.html create mode 100644 examples/timeline/requirejs/scripts/main.js create mode 100644 examples/timeline/requirejs/scripts/require.js diff --git a/docs/css/prettify.css b/docs/css/prettify.css new file mode 100644 index 00000000..b4ec4ca0 --- /dev/null +++ b/docs/css/prettify.css @@ -0,0 +1,87 @@ +.com { + color: gray; +} + +.lit { + color: red; +} + +.pun { + color: gray; +} + +.pln { + color: #333333; +} + +pre.prettyprint { + border: 1px solid lightgray; + background-color: #fcfcfc; + padding: 5px; + + font-size: 10pt; + line-height: 1.5em; + font-family: monospace; +} + +ol.linenums { + margin-top:0; + margin-bottom:0; +} + +li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8 { + list-style:none; +} + +li.L1,li.L3,li.L5,li.L7,li.L9 { + background:#eee; +} + +.str,.atv { + color: green; +} + +.kwd,.tag { + color:#2B7CE9; +} + +.typ,.atn,.dec { + color: darkorange; +} + +@media print { + .com { + color:#600; + font-style:italic; + } + + .typ { + color:#404; + font-weight:700; + } + + .lit { + color:#044; + } + + .pun { + color:#440; + } + + .pln { + color:#000; + } + + .atn { + color:#404; + } + + .str,.atv { + color:#060; + } + + .kwd,.tag { + color:#006; + font-weight:700; + } +} \ No newline at end of file diff --git a/docs/css/style.css b/docs/css/style.css new file mode 100644 index 00000000..15554585 --- /dev/null +++ b/docs/css/style.css @@ -0,0 +1,69 @@ +html, body { + width: 100%; + height: 100%; + padding: 0; + margin: 0; +} + +body, td, th { + font-family: arial, sans-serif; + font-size: 11pt; + color: #4D4D4D; + line-height: 1.7em; +} + +#container { + margin: 0 auto; + padding-bottom: 50px; + width: 700px; +} + +h1 { + font-size: 180%; + font-weight: bold; + padding: 0; + margin: 1em 0 1em 0; +} + +h2 { + padding-top: 20px; + padding-bottom: 10px; + border-bottom: 1px solid #a0c0f0; + color: #2B7CE9; +} + +h3 { + font-size: 140%; +} + + +a { + color: #2B7CE9; + text-decoration: none; +} +a:visited { + color: #2E60A4; +} +a:hover { + color: red; + text-decoration: underline; +} + +table { + border-collapse: collapse; +} + +th { + font-weight: bold; + border: 1px solid lightgray; + background-color: #E5E5E5; + text-align: left; + vertical-align: top; + padding: 5px; +} + +td { + border: 1px solid lightgray; + padding: 5px; + vertical-align: top; +} diff --git a/docs/dataset.html b/docs/dataset.html new file mode 100644 index 00000000..201d6e5b --- /dev/null +++ b/docs/dataset.html @@ -0,0 +1,23 @@ + + + + + vis.js | DataSet documentation + + + + + + + + + +
+ +

DataSet documentation

+ +

coming soon...

+ +
+ + \ No newline at end of file diff --git a/docs/graph.html b/docs/graph.html new file mode 100644 index 00000000..39051935 --- /dev/null +++ b/docs/graph.html @@ -0,0 +1,1136 @@ + + + + + vis.js | graph documentation + + + + + + + + +
+ +

Graph documentation

+ + + + + + + + + + + + + + +
AuthorJos de Jong, Almende B.V.
Webpagehttp://visjs.org
License Apache License, Version 2.0
+ + +

Contents

+ + +

Overview

+

+ Graph is a visualization to display graphs and networks consisting of nodes + and edges. The visualization is easy to use and supports custom shapes, + styles, colors, sizes, images, and more. +

+ +

+ The graph visualization works smooth on any modern browser for up to a + few hundred nodes and edges. +

+ +

+ To get started with Graph, install or download the + vis.js library. +

+ +

Example

+

+ Here a basic graph example. More examples can be found in the + examples directory. +

+ +
<!doctype html>
+<html>
+<head>
+    <title>Graph | Basic usage</title>
+
+    <script type="text/javascript" src="../../vis.js"></script>
+</head>
+
+<body>
+
+<div id="mygraph"></div>
+
+<script type="text/javascript">
+    // create an array with nodes
+    var nodes = [
+        {id: 1, label: 'Node 1'},
+        {id: 2, label: 'Node 2'},
+        {id: 3, label: 'Node 3'},
+        {id: 4, label: 'Node 4'},
+        {id: 5, label: 'Node 5'}
+    ];
+
+    // create an array with edges
+    var edges = [
+        {from: 1, to: 2},
+        {from: 1, to: 3},
+        {from: 2, to: 4},
+        {from: 2, to: 5}
+    ];
+
+    // create a graph
+    var container = document.getElementById('mygraph');
+    var data= {
+        nodes: nodes,
+        edges: edges,
+    };
+    var options = {
+        width: '400px',
+        height: '400px'
+    };
+    var graph = new vis.Graph(container, data, options);
+</script>
+
+</body>
+</html>
+
+ + +

Loading

+

+ Install or download the vis.js library. + in a subfolder of your project. Include the library script in the head of your html code: +

+ +
+<script type="text/javascript" src="vis/vis.js"></script>
+
+ + +The constructor of the Graph is vis.Graph. +
var graph = new vis.Graph(container, data, options);
+ +The constructor accepts three parameters: +
    +
  • + container is the DOM element in which to create the graph. +
  • +
  • + data is an Object containing properties nodes and + edges, which both contain an array with objects. + Optionally, data may contain an options object. + The parameter data is optional, data can also be set using + the method setData. Section Data Format + describes the data object. +
  • +
  • + options is an optional Object containing a name-value map + with options. Options can also be set using the method + setOptions. + Section Configuration Options + describes the available options. +
  • +
+ +

Data Format

+

+ The data parameter of the Graph constructor is an object + which can contain different types of data. + The following properties are supported in the data object: +

+ +
    +
  • + A property pair nodes and edges, + both containing an Array with objects. The data formats are described + in the sections Nodes and Edges. + Example: +
    +var data = {
    +    nodes: [...],
    +    edges: [...]
    +};
    +
    +
  • +
  • + A property dot, + containing a string with data in the + DOT language. + DOT support is described in section DOT_language. + + Example: +
    +var data = {
    +    dot: '...'
    +};
    +
    +
  • +
  • + A property options, + containing an object with global options. + Options can be provided as third parameter in the graph constructor + as well. Section Configuration Options + describes the available options. + +
  • +
+ +

Nodes

+ +

+ Nodes typically have an id and label. + A node must contain at least a property id. + Nodes can have extra properties, used to define the shape and style of the + nodes. +

+ +

+ A JavaScript Array with nodes is constructed like: +

+
+var nodes = [
+    {
+        id: 1,
+        label: 'Node 1'
+    },
+    // ... more nodes
+];
+
+ + +

+ Nodes support the following properties: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredDescription
colorString | ObjectnoColor for the node.
color.backgroundStringnoBackground color for the node.
color.borderStringnoBorder color for the node.
color.highlightString | ObjectnoColor of the node when selected.
color.highlight.backgroundStringnoBackground color of the node when selected.
color.highlight.borderStringnoBorder color of the node when selected.
groupNumber | StringnoA group number or name. The type can be number, + string, or an other type. All nodes with the same group get + the same color schema.
fontColorStringnoFont color for label in the node.
fontFaceStringnoFont face for label in the node, for example "verdana" or "arial".
fontSizeNumbernoFont size in pixels for label in the node.
idNumber | StringyesA unique id for this node. + Nodes may not have duplicate id's. + Id's do not need to be consecutive. + An id is normally a number, but may be any type.
imagestringnoUrl of an image. Only applicable when the shape of the node is + image.
radiusnumbernoRadius for the node. Applicable for all shapes except box, + circle, ellipse and database. + The value of radius will override a value in + property value.
shapestringnoDefine the shape for the node. + Choose from + ellipse (default), circle, box, + database, image, label, dot, + star, triangle, triangleDown, and square. +

+ + In case of image, a property with name image must + be provided, containing image urls. +

+ + The shapes dot, star, triangle, + triangleDown, and square, are scalable. + The size is determined by the properties radius or + value. +

+ + When a property label is provided, + this label will be displayed inside the shape in case of shapes + box, circle, ellipse, + and database. + For all other shapes, the label will be displayed right below the shape. + +
labelstringnoText label to be displayed in the node or under the image of the node. + Multiple lines can be separated by a newline character \n .
titlestringnoTitle to be displayed when the user hovers over the node. + The title can contain HTML code.
valuenumbernoA value for the node. + The radius of the nodes will be scaled automatically from minimum to + maximum value. + Only applicable when the shape of the node is dot. + If a radius is provided for the node too, it will override the + radius calculated from the value.
xnumbernoHorizontal position in pixels. + The horizontal position of the node will be fixed. + The vertical position y may remain undefined.
ynumbernoVertical position in pixels. + The vertical position of the node will be fixed. + The horizontal position x may remain undefined.
+ + +

Edges

+ +

+ Edges are connections between nodes. + An edge must at least contain properties from and + to, both referring to the id of a node. + Edges can have extra properties, used to define the type and style. +

+ +

+ A JavaScript Array with edges is constructed as: +

+
+var edges = [
+    {
+        from: 1,
+        to: 3
+    },
+    // ... more edges
+];
+
+ +

+ Edges support the following properties: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredDescription
colorstringnoA HTML color for the edge.
dashObjectno + Object containing properties for dashed lines. + Available properties: length, gap, + altLength. +
dash.altLengthnumbernoLength of the alternated dash in pixels on a dashed line. + Specifying dash.altLength allows for creating + a dashed line with a dash-dot style, for example when + dash.length=10 and dash.altLength=5. + See also the option dahs.length. + Only applicable when the line style is dash-line.
dash.lengthnumbernoLength of a dash in pixels on a dashed line. + Only applicable when the line style is dash-line.
dash.gapnumbernoLength of a gap in pixels on a dashed line. + Only applicable when the line style is dash-line.
fontColorStringnoFont color for the text label of the edge. + Only applicable when property label is defined.
fontFaceStringnoFont face for the text label of the edge, + for example "verdana" or "arial". + Only applicable when property label is defined.
fontSizeNumbernoFont size in pixels for the text label of the edge. + Only applicable when property label is defined.
fromNumber | StringyesThe id of a node where the edge starts. The type must correspond with + the type of the node id's. This is normally a number, but can be any + type.
lengthnumbernoThe length of the edge in pixels.
stylestringnoDefine a line style for the edge. + Choose from line (default), arrow, + arrow-center, or dash-line. +
labelstringnoText label to be displayed halfway the edge.
titlestringnoTitle to be displayed when the user hovers over the edge. + The title can contain HTML code.
toNumber | StringyesThe id of a node where the edge ends. The type must correspond with + the type of the node id's. This is normally a number, but can be any + type.
valuenumbernoA value for the edge. + The width of the edges will be scaled automatically from minimum to + maximum value. + If a width is provided for the edge too, it will override the + width calculated from the value.
widthnumbernoWidth of the line in pixels. The width will + override a specified value, if a value is + specified too.
+ + + +

DOT language

+ +

+ Graph supports data in the + DOT language. + To provide data in the DOT language, the data object must contain + a property dot with a String containing the data. +

+ +

+ Example usage: +

+ +
+// provide data in the DOT language
+var data = {
+    dot: 'digraph {1 -> 1 -> 2; 2 -> 3; 2 -- 4; 2 -> 1 }'
+};
+
+// create a graph
+var graph = new vis.Graph(container, data);
+
+ + + +

Configuration Options

+ +

+ Options can be used to customize the graph. Options are defined as a JSON object. + All options are optional. +

+ +
+var options = {
+    width:  '100%',
+    height: '400px',
+    edges: {
+        color: 'red',
+        width: 2
+    }
+};
+
+ +

+ The following options are available. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
edges.colorString"#2B7CE9"The default color of a edge.
edges.dashObjectObject + Object containing default properties for dashed lines. + Available properties: length, gap, + altLength. +
edges.dash.altLengthnumbernoneDefault length of the alternated dash in pixels on a dashed line. + Specifying dash.altLength allows for creating + a dashed line with a dash-dot style, for example when + dash.length=10 and dash.altLength=5. + See also the option dahs.length. + Only applicable when the line style is dash-line.
edges.dash.lengthnumber10Default length of a dash in pixels on a dashed line. + Only applicable when the line style is dash-line.
edges.dash.gapnumber5Default length of a gap in pixels on a dashed line. + Only applicable when the line style is dash-line.
edges.lengthNumber100The default length of a edge.
edges.styleString"line"The default style of a edge. + Choose from line (default), arrow, + arrow-center, dash-line.
edges.widthNumber1The default width of a edge.
groupsObjectnoneIt is possible to specify custom styles for groups. + Each node assigned a group gets the specified style. + See Groups for an overview of the available styles + and an example. +
heightString"400px"The height of the graph in pixels or as a percentage.
nodes.colorString | ObjectObjectDefault color of the nodes. When color is a string, the color is applied + to both background as well as the border of the node.
nodes.color.backgroundString"#97C2FC"Default background color of the nodes
nodes.color.borderString"#2B7CE9"Default border color of the nodes
nodes.color.highlightString | ObjectObjectDefault color of the node when the node is selected. Applied to + both border and background of the node.
nodes.color.highlight.backgroundString"#D2E5FF"Default background color of the node when selected.
nodes.color.highlight.borderString"#2B7CE9"Default border color of the node when selected.
nodes.fontColorString"black"Default font color for the text label in the nodes.
nodes.fontFaceString"sans"Default font face for the text label in the nodes, for example "verdana" or "arial".
nodes.fontSizeNumber14Default font size in pixels for the text label in the nodes.
nodes.groupStringnoneDefault group for the nodes.
nodes.imageStringnoneDefault image url for the nodes. only applicable with shape image.
nodes.widthMinNumber16The minimum width for a scaled image. Only applicable with shape image.
nodes.widthMaxNumber64The maximum width for a scaled image. Only applicable with shape image.
nodes.shapeString"ellipse"The default shape for all nodes. + Choose from + ellipse (default), circle, box, + database, image, label, dot, + star, triangle, triangleDown, and square. + This shape can be overridden by a group shape, or by a shape of an individual node.
nodes.radiusNumber5The default radius for a node. Only applicable with shape dot.
nodes.radiusMinNumber5The minimum radius for a scaled node. Only applicable with shape dot.
nodes.radiusMaxNumber20The maximum radius for a scaled node. Only applicable with shape dot.
selectableBooleantrueIf true, nodes in the graph can be selected by clicking them, or + by keeping the Shift key down and dragging a selection area around them. + When the Ctrl key is down, the new selection is appended to the + previous selection. If not, the new selection replaces the previous selection.
stabilizeBooleantrueIf true, the graph is stabilized before displaying it. If false, + the nodes move to a stabe position visibly in an animated way.
widthString"400px"The width of the graph in pixels or as a percentage.
+ +
+ +

Groups

+ +

It is possible to specify custom styles for groups of nodes. + Each node having assigned to this group gets the specified style. + The options groups is an object containing one or multiple groups, + identified by a unique string, the groupname. +

+

+ A group can have the following styles: +

+ +
+var options = {
+    // ...
+
+    groups: {
+        mygroup: {
+            shape: 'circle',
+            color: {
+                border: 'black',
+                background: 'white',
+                highlight: {
+                    border: 'yellow',
+                    background: 'orange'
+                }
+            }
+            fontColor: 'red',
+            fontSize: 18
+        }
+        // add more groups here
+    }
+};
+
+var nodes = [
+    {id: 1, label: 'Node 1'},                    // will get the default style
+    {id: 2, label: 'Node 2', group: 'mygroup'},  // will get the style from 'mygroup'
+    // ... more nodes
+];
+
+ + +

The following styles are available for groups:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
colorString | ObjectObjectColor of the node
color.borderString"#2B7CE9"Border color of the node
color.backgroundString"#97C2FC"Background color of the node
color.highlightString"#D2E5FF"Color of the node when selected.
color.highlight.backgroundString"#D2E5FF"Background color of the node when selected.
color.highlight.borderString"#D2E5FF"Border color of the node when selected.
imageStringnoneDefault image for the nodes. Only applicable in combination with + shape image.
fontColorString"black"Font color of the node.
fontFaceString"sans"Font name of the node, for example "verdana" or "arial".
fontSizeNumber14Font size for the node in pixels.
shapeString"ellipse"Choose from + ellipse (default), circle, box, + database, image, label, dot, + star, triangle, triangleDown, and square. + In case of image, a property with name image must be provided, containing + image urls.
radiusNumber5Default radius for the node. Only applicable in combination with + shapes box and dot.
+ + +

Methods

+

+ Graph supports the following methods. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodReturn TypeDescription
setData(data)noneLoads data. Parameter data is an object containing + nodes, edges, and options. Parameters nodes, edges are an Array. + Options is a name-value map and is optional. +
setOptions(options)noneSet options for the graph. The available options are described in + the section Configuration Options. +
getSelection()Array of selection elementsStandard getSelection() implementation. + Returns an array with one or multiple selections. Each selection contains + the property row. The selections are not ordered. +
redraw()noneRedraw the graph. Useful when the layout of the webpage changed.
setSelection(selection)noneStandard setSelection(selection) implementation. + selection is an array with selection elements. The visualization + accepts one or multiple selection elements, which must have the property row. + Example usage: graph.setSelection([{"row": 3}]);. +
setSize(width, height)noneParameters width and height are strings, + containing a new size for the visualization. Size can be provided in pixels + or in percentages.
+ +

Events

+

+ Graph fires events after one or multiple nodes are selected. + The event can be catched by creating a listener. +

+ +

+ Here an example on how to catch a select event. +

+ +
+function onselect() {
+    var sel = graph.getSelection();
+
+    var info = 'selected row(s): ';
+    for (var i = 0; i < sel.length; i++) {
+        info += sel[i].row + ' ';
+    }
+
+    alert(info);
+}
+
+vis.events.addListener(graph, 'select', onselect);
+
+ +

+ The following events are available. +

+ + + + + + + + + + + + + + + + + +
nameDescriptionProperties
selectFired after the user selects or unselects a node by clicking it, + or when selecting a number of nodes by dragging a selection area + around them. Not fired when the method setSelection + is executed. The corresponding rows in the Array are selected. +
+ The selected rows can be retrieved via the method getSelection. +
none
+ + +

Data Policy

+

+ All code and data are processed and rendered in the browser. No data is sent to any server. +

+ +
+ + diff --git a/docs/img/graph/graph.png b/docs/img/graph/graph.png new file mode 100644 index 0000000000000000000000000000000000000000..3acaa13149a5dfbae14be8737f2664a1925be490 GIT binary patch literal 23400 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 IM6N<$g1{XUg#Z8m literal 0 HcmV?d00001 diff --git a/docs/img/timeline/timeline.png b/docs/img/timeline/timeline.png new file mode 100644 index 0000000000000000000000000000000000000000..d77c304ca9c30e0c093d94e8acaaf46157704027 GIT binary patch literal 23229 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 l(*Keh$p!eA05p-;x0bZCDHZ;` literal 0 HcmV?d00001 diff --git a/docs/img/timeline/timeline120x60.png b/docs/img/timeline/timeline120x60.png new file mode 100644 index 0000000000000000000000000000000000000000..f9d0c6a71096dd36d254740021131aa33f339e30 GIT binary patch literal 6671 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 + + + + vis.js | documentation + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/lib/prettify/lang-apollo.js b/docs/lib/prettify/lang-apollo.js new file mode 100644 index 00000000..bfc0014c --- /dev/null +++ b/docs/lib/prettify/lang-apollo.js @@ -0,0 +1,2 @@ +PR.registerLangHandler(PR.createSimpleLexer([["com",/^#[^\r\n]*/,null,"#"],["pln",/^[\t\n\r \xA0]+/,null,"\t\n\r \u00a0"],["str",/^\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)/,null,'"']],[["kwd",/^(?:ADS|AD|AUG|BZF|BZMF|CAE|CAF|CA|CCS|COM|CS|DAS|DCA|DCOM|DCS|DDOUBL|DIM|DOUBLE|DTCB|DTCF|DV|DXCH|EDRUPT|EXTEND|INCR|INDEX|NDX|INHINT|LXCH|MASK|MSK|MP|MSU|NOOP|OVSK|QXCH|RAND|READ|RELINT|RESUME|RETURN|ROR|RXOR|SQUARE|SU|TCR|TCAA|OVSK|TCF|TC|TS|WAND|WOR|WRITE|XCH|XLQ|XXALQ|ZL|ZQ|ADD|ADZ|SUB|SUZ|MPY|MPR|MPZ|DVP|COM|ABS|CLA|CLZ|LDQ|STO|STQ|ALS|LLS|LRS|TRA|TSQ|TMI|TOV|AXT|TIX|DLY|INP|OUT)\s/, +null],["typ",/^(?:-?GENADR|=MINUS|2BCADR|VN|BOF|MM|-?2CADR|-?[1-6]DNADR|ADRES|BBCON|[SE]?BANK\=?|BLOCK|BNKSUM|E?CADR|COUNT\*?|2?DEC\*?|-?DNCHAN|-?DNPTR|EQUALS|ERASE|MEMORY|2?OCT|REMADR|SETLOC|SUBRO|ORG|BSS|BES|SYN|EQU|DEFINE|END)\s/,null],["lit",/^\'(?:-*(?:\w|\\[\x21-\x7e])(?:[\w-]*|\\[\x21-\x7e])[=!?]?)?/],["pln",/^-*(?:[!-z_]|\\[\x21-\x7e])(?:[\w-]*|\\[\x21-\x7e])[=!?]?/i],["pun",/^[^\w\t\n\r \xA0()\"\\\';]+/]]),["apollo","agc","aea"]) \ No newline at end of file diff --git a/docs/lib/prettify/lang-css.js b/docs/lib/prettify/lang-css.js new file mode 100644 index 00000000..61157f38 --- /dev/null +++ b/docs/lib/prettify/lang-css.js @@ -0,0 +1,2 @@ +PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[ \t\r\n\f]+/,null," \t\r\n\u000c"]],[["str",/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],["str",/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],["kwd",/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//], +["com",/^(?: + + setItems(items) + none + Set a data set with items for the Timeline. + items can be an Array with Objects, + a DataSet, or a DataView. + + + + + setOptions(options) + none + Set or update options. It is possible to change any option + of the timeline at any time. You can for example switch orientation + on the fly. + + + + + + +

Styles

+

+ All parts of the Timeline have a class name and a default css style. + The styles can be overwritten, which enables full customization of the layout + of the Timeline. +

+ +

For example, to change the border and background color of all items, include the + following code inside the head of your html code or in a separate stylesheet.

+
<style>
+    .graph .item {
+      border-color: orange;
+      background-color: yellow;
+    }
+</style>
+
+ + +

Data Policy

+

+ All code and data are processed and rendered in the browser. No data is sent to any server. +

+ + + + diff --git a/examples/graph/01_basic_usage.html b/examples/graph/01_basic_usage.html new file mode 100644 index 00000000..3bed9c75 --- /dev/null +++ b/examples/graph/01_basic_usage.html @@ -0,0 +1,50 @@ + + + + Graph | Basic usage + + + + + + + + +
+ + + + + diff --git a/examples/graph/02_random_nodes.html b/examples/graph/02_random_nodes.html new file mode 100755 index 00000000..a3de91a5 --- /dev/null +++ b/examples/graph/02_random_nodes.html @@ -0,0 +1,110 @@ + + + + Graph | Random nodes + + + + + + + + + + +
+ + + +
+
+ +
+ +

+ + diff --git a/examples/graph/03_images.html b/examples/graph/03_images.html new file mode 100755 index 00000000..f0235fb6 --- /dev/null +++ b/examples/graph/03_images.html @@ -0,0 +1,83 @@ + + + + Graph | Images + + + + + + + + + + +
+ + + diff --git a/examples/graph/04_shapes.html b/examples/graph/04_shapes.html new file mode 100755 index 00000000..25b3f3ea --- /dev/null +++ b/examples/graph/04_shapes.html @@ -0,0 +1,76 @@ + + + + Graph | Shapes + + + + + + + + + +
+ +
+ + diff --git a/examples/graph/05_social_network.html b/examples/graph/05_social_network.html new file mode 100644 index 00000000..480eca6b --- /dev/null +++ b/examples/graph/05_social_network.html @@ -0,0 +1,78 @@ + + + + Graph | Social Network + + + + + + + + + +
+

+ Icons: Scrap Icons by Deleket +

+ +
+ + diff --git a/examples/graph/06_groups.html b/examples/graph/06_groups.html new file mode 100644 index 00000000..59adfb51 --- /dev/null +++ b/examples/graph/06_groups.html @@ -0,0 +1,160 @@ + + + + Graph | Groups + + + + + + + + + + +
+ Number of groups: + + Number of nodes per group: + + +
+
+ +
+ + + diff --git a/examples/graph/07_selections.html b/examples/graph/07_selections.html new file mode 100644 index 00000000..25c761e2 --- /dev/null +++ b/examples/graph/07_selections.html @@ -0,0 +1,76 @@ + + + + Graph | Selections + + + + + + + + +
+
+ + + + + diff --git a/examples/graph/08_mobile_friendly.html b/examples/graph/08_mobile_friendly.html new file mode 100755 index 00000000..de44f4a8 --- /dev/null +++ b/examples/graph/08_mobile_friendly.html @@ -0,0 +1,108 @@ + + + + Graph | Mobile friendly + + + + + + + + + + + + +
+ + diff --git a/examples/graph/09_sizing.html b/examples/graph/09_sizing.html new file mode 100644 index 00000000..67a48f8e --- /dev/null +++ b/examples/graph/09_sizing.html @@ -0,0 +1,80 @@ + + + + Graph | Sizing + + + + + + + + + +
+ + diff --git a/examples/graph/10_multiline_text.html b/examples/graph/10_multiline_text.html new file mode 100755 index 00000000..695d5fba --- /dev/null +++ b/examples/graph/10_multiline_text.html @@ -0,0 +1,50 @@ + + + + Graph | Multiline text + + + + + + + + + +
+ + diff --git a/examples/graph/11_custom_style.html b/examples/graph/11_custom_style.html new file mode 100644 index 00000000..20e9dd59 --- /dev/null +++ b/examples/graph/11_custom_style.html @@ -0,0 +1,131 @@ + + + + Graph | Custom style + + + + + + + + + +
+ + diff --git a/examples/graph/12_scalable_images.html b/examples/graph/12_scalable_images.html new file mode 100644 index 00000000..8a3da963 --- /dev/null +++ b/examples/graph/12_scalable_images.html @@ -0,0 +1,85 @@ + + + + Graph | Scalable images + + + + + + + + + +
+ +
+ + diff --git a/examples/graph/13_dashed_lines.html b/examples/graph/13_dashed_lines.html new file mode 100644 index 00000000..6f954672 --- /dev/null +++ b/examples/graph/13_dashed_lines.html @@ -0,0 +1,65 @@ + + + + Graph | Dashed lines + + + + + + + + + +

+ This example shows the different options for dashed lines. +

+ +
+ + diff --git a/examples/graph/14_dot_language.html b/examples/graph/14_dot_language.html new file mode 100644 index 00000000..7d86df95 --- /dev/null +++ b/examples/graph/14_dot_language.html @@ -0,0 +1,18 @@ + + + Graph | DOT Language + + + + +
+ + + + diff --git a/examples/graph/15_dot_language_playground.html b/examples/graph/15_dot_language_playground.html new file mode 100644 index 00000000..a6e96c86 --- /dev/null +++ b/examples/graph/15_dot_language_playground.html @@ -0,0 +1,209 @@ + + + + Graph | DOT language playground + + + + + + + + + + + + + + + + + +
+

DOT language playground

+ +
+
+ + +
+
+ + +
+
+ + + + + + + + + + + + + diff --git a/examples/graph/graphviz/data/fsm.gv.txt b/examples/graph/graphviz/data/fsm.gv.txt new file mode 100644 index 00000000..e59b7c2d --- /dev/null +++ b/examples/graph/graphviz/data/fsm.gv.txt @@ -0,0 +1,20 @@ +digraph finite_state_machine { + rankdir=LR; + size="8,5" + node [shape = doublecircle]; LR_0 LR_3 LR_4 LR_8; + node [shape = circle]; + LR_0 -> LR_2 [ label = "SS(B)" ]; + LR_0 -> LR_1 [ label = "SS(S)" ]; + LR_1 -> LR_3 [ label = "S($end)" ]; + LR_2 -> LR_6 [ label = "SS(b)" ]; + LR_2 -> LR_5 [ label = "SS(a)" ]; + LR_2 -> LR_4 [ label = "S(A)" ]; + LR_5 -> LR_7 [ label = "S(b)" ]; + LR_5 -> LR_5 [ label = "S(a)" ]; + LR_6 -> LR_6 [ label = "S(b)" ]; + LR_6 -> LR_5 [ label = "S(a)" ]; + LR_7 -> LR_8 [ label = "S(b)" ]; + LR_7 -> LR_5 [ label = "S(a)" ]; + LR_8 -> LR_6 [ label = "S(b)" ]; + LR_8 -> LR_5 [ label = "S(a)" ]; +} diff --git a/examples/graph/graphviz/data/hello.gv.txt b/examples/graph/graphviz/data/hello.gv.txt new file mode 100644 index 00000000..7bc71ff4 --- /dev/null +++ b/examples/graph/graphviz/data/hello.gv.txt @@ -0,0 +1 @@ +digraph G {Hello->World} \ No newline at end of file diff --git a/examples/graph/graphviz/data/process.gv.txt b/examples/graph/graphviz/data/process.gv.txt new file mode 100644 index 00000000..34fe9fb5 --- /dev/null +++ b/examples/graph/graphviz/data/process.gv.txt @@ -0,0 +1,15 @@ +graph G { + run -- intr; + intr -- runbl; + runbl -- run; + run -- kernel; + kernel -- zombie; + kernel -- sleep; + kernel -- runmem; + sleep -- swap; + swap -- runswap; + runswap -- new; + runswap -- runmem; + new -- runmem; + sleep -- runmem; +} diff --git a/examples/graph/graphviz/data/siblings.gv.txt b/examples/graph/graphviz/data/siblings.gv.txt new file mode 100644 index 00000000..e6628dfc --- /dev/null +++ b/examples/graph/graphviz/data/siblings.gv.txt @@ -0,0 +1,512 @@ +/* +This is a graphviz-produced layout of the "family tree" of a fraternity and sorority. + +Each member in the graph was assigned a "big brother" from one organization and a "big sister" from the other. Blue icons represent Brothers from the fraternity, Pink represents Sisters from the sorority (Purple members are in both organizations - like honoraries.) + +Charter members (who can have no parent nodes) are outlined. + +... + +dot -Tgif -Goverlap=false -o siblings.gif siblings.dot + + +We're experimenting with different ways of coloring and graphing, but found this the easiest for now. When we have more people in, we might look at different shades depending on generation number -- earlier people would get lighter colors, more recent members darker. Thumbnail images would be an interesting alteration as well. + +from Japheth Cleaver +*/ + + +digraph sdsu { + size="36,36"; + node [color=grey, style=filled]; + node [fontname="Verdana", size="30,30"]; + graph [ fontname = "Arial", + fontsize = 36, + style = "bold", + label = "\nKappa Kappa Psi/Tau Beta Sigma\nSan Diego State University\nEta Mu and Zeta Xi Family Tree\n\nto date: November 30th, 2008\n", + ssize = "30,60" ]; +"Lori Brede" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=10"]; +"Michael Griffith" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=24"]; +"Amie Holston" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=30"]; +"Michael Griffith" -> "Lori Brede" +"Amie Holston" -> "Lori Brede" +"Casey Carter" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=11"]; +"Laura De'Armond" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=14"]; +"Laura De'Armond" -> "Casey Carter" +"Japheth Cleaver" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=12"]; +"Chuk Gawlik" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=22"]; +"Stacy Snyder" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=309"]; +"Chuk Gawlik" -> "Japheth Cleaver" +"Stacy Snyder" -> "Japheth Cleaver" +"Jillian Clifton" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=13"]; +"David Guthrie" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=25"]; +"David Guthrie" -> "Jillian Clifton" +"Japheth Cleaver" -> "Jillian Clifton" +"Tony Sacco" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=55"]; +"Heather Smith" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=59"]; +"Tony Sacco" -> "Laura De'Armond" +"Heather Smith" -> "Laura De'Armond" +"Kevin Decker" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=15"]; +"Alex Hansen" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=26"]; +"Wanda Livelsberger" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=53"]; +"Alex Hansen" -> "Kevin Decker" +"Wanda Livelsberger" -> "Kevin Decker" +"Patrick Doerr" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=16"]; +"Deanna Jagow" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=23"]; +"Alex Hansen" -> "Patrick Doerr" +"Deanna Jagow" -> "Patrick Doerr" +"Lori Asaro" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=178"]; +"Mark Pearson" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=169"]; +"Lori Ball" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=167"]; +"Mark Pearson" -> "Lori Asaro" +"Lori Ball" -> "Lori Asaro" +"Ryan Farris" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=18"]; +"Rob Reiner" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=51"]; +"Cindy Teel" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=62"]; +"Rob Reiner" -> "Ryan Farris" +"Cindy Teel" -> "Ryan Farris" +"Ginger Palmer" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=180"]; +"Mark Newton-John" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=46"]; +"Mark Newton-John" -> "Ginger Palmer" +"Matthew FitzGerald" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=19"]; +"Mervin Maniago" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=41"]; +"Mervin Maniago" -> "Matthew FitzGerald" +"Amie Holston" -> "Matthew FitzGerald" +"Tani Miller" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=195"]; +"Mark Pearson" -> "Tani Miller" +"Vienna McMurtry" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=196"]; +"Robert Walwick" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=153"]; +"Robert Walwick" -> "Vienna McMurtry" +"Ginger Palmer" -> "Vienna McMurtry" +"Chuck Foster" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=20"]; +"Karen Saye" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=56"]; +"Kevin Decker" -> "Chuck Foster" +"Karen Saye" -> "Chuck Foster" +"Gary Frampton" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=201"]; +"Ginger Palmer" -> "Gary Frampton" +"Pat Norris" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=207"]; +"Sean Tipps" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=204"]; +"Teresa Long" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=194"]; +"Sean Tipps" -> "Pat Norris" +"Teresa Long" -> "Pat Norris" +"Marc Martin-ez" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=208"]; +"Mark Pearson" -> "Marc Martin-ez" +"Tani Miller" -> "Marc Martin-ez" +"Kristen Villone" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=209"]; +"Kelly Erickson" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=199"]; +"Anna Pedroza" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=197"]; +"Kelly Erickson" -> "Kristen Villone" +"Anna Pedroza" -> "Kristen Villone" +"Geoff Frank" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=21"]; +"Chris Livelsberger" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=40"]; +"Amy Price" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=57"]; +"Chris Livelsberger" -> "Geoff Frank" +"Amy Price" -> "Geoff Frank" +"Tracy Murray" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=210"]; +"John FitzGibbon" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=92"]; +"Judy Dulcich" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=177"]; +"John FitzGibbon" -> "Tracy Murray" +"Judy Dulcich" -> "Tracy Murray" +"Ian McIntosh" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=215"]; +"Barbara Tollison" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=172"]; +"Robert Walwick" -> "Ian McIntosh" +"Barbara Tollison" -> "Ian McIntosh" +"Jayson Smith" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=58"]; +"Jayson Smith" -> "Chuk Gawlik" +"Heather Smith" -> "Chuk Gawlik" +"Kelly McKinney" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=222"]; +"Mark Nadeau" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=183"]; +"Mark Nadeau" -> "Kelly McKinney" +"Judy Dulcich" -> "Kelly McKinney" +"Chris Livelsberger" -> "Deanna Jagow" +"Amy Price" -> "Deanna Jagow" +"Renee Thompson" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=231"]; +"J. Angeles" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=3"]; +"Kelley Smith" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=223"]; +"J. Angeles" -> "Renee Thompson" +"Kelley Smith" -> "Renee Thompson" +"Steven Smith" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=233"]; +"John FitzGibbon" -> "Steven Smith" +"Charlene Andrews" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=234"]; +"Diane Reoch" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=227"]; +"Diane Reoch" -> "Charlene Andrews" +"Tonya Alexander" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=238"]; +"Gail Vasquez" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=225"]; +"Gail Vasquez" -> "Tonya Alexander" +"Spencer Caldwell" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=239"]; +"Becky Bernal" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=218"]; +"Becky Bernal" -> "Spencer Caldwell" +"Chuk Gawlik" -> "Michael Griffith" +"Wanda Livelsberger" -> "Michael Griffith" +"Russell Grant" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=242"]; +"Steven Smith" -> "Russell Grant" +"Tiffany Worthington" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=66"]; +"Chuck Foster" -> "David Guthrie" +"Tiffany Worthington" -> "David Guthrie" +"Jerry Maya" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=250"]; +"John FitzGibbon" -> "Jerry Maya" +"Melissa Schwartz" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=252"]; +"Russell Grant" -> "Melissa Schwartz" +"Delphy Shaulis" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=255"]; +"Renee Thompson" -> "Delphy Shaulis" +"Martin Naiman" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=45"]; +"Janean Angeles" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=86"]; +"Martin Naiman" -> "Alex Hansen" +"Janean Angeles" -> "Alex Hansen" +"Leslie Harlow" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=265"]; +"Dennis McColl" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=251"]; +"Denise Luna" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=236"]; +"Dennis McColl" -> "Leslie Harlow" +"Denise Luna" -> "Leslie Harlow" +"Jonathan Yudman" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=267"]; +"April Ortiz-cloninger" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=258"]; +"April Ortiz-cloninger" -> "Jonathan Yudman" +"Michael Elgo" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=268"]; +"Carol Kropp" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=254"]; +"Spencer Caldwell" -> "Michael Elgo" +"Carol Kropp" -> "Michael Elgo" +"Denmark Vea" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=269"]; +"Marc Martin-ez" -> "Denmark Vea" +"Kelley Smith" -> "Denmark Vea" +"Kathleen Hansen" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=27"]; +"Martin Naiman" -> "Kathleen Hansen" +"Heather Smith" -> "Kathleen Hansen" +"Laura Stegner" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=274"]; +"April Ortiz-cloninger" -> "Laura Stegner" +"Kathy Jones" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=28"]; +"J. Angeles" -> "Kathy Jones" +"Eric Gates" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=282"]; +"Erick Sugimura" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=280"]; +"Erick Sugimura" -> "Eric Gates" +"Laura Stegner" -> "Eric Gates" +"Jennifer Stoewe" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=288"]; +"Eric Gates" -> "Jennifer Stoewe" +"Karen Helbling" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=29"]; +"Regan Ashker" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=5"]; +"Kevin Decker" -> "Karen Helbling" +"Regan Ashker" -> "Karen Helbling" +"Scott Wood" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=295"]; +"Eric Gates" -> "Scott Wood" +"Greg Flood" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=200"]; +"Greg Flood" -> "J. Angeles" +"Ginger Palmer" -> "J. Angeles" +"Lynn Reeves" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=48"]; +"Chuk Gawlik" -> "Amie Holston" +"Lynn Reeves" -> "Amie Holston" +"Susan Colwell" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=302"]; +"Michael Elgo" -> "Susan Colwell" +"Christopher Jouan" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=306"]; +"Kevin Owens" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=245"]; +"Kevin Owens" -> "Christopher Jouan" +"Kristianna Reynante" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=308"]; +"Michael Elgo" -> "Kristianna Reynante" +"Janean Angeles" -> "Kristianna Reynante" +"Amy Berner" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=300"]; +"Amy Berner" -> "Stacy Snyder" +"Deanna Johnson" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=31"]; +"Alex Hansen" -> "Deanna Johnson" +"Laura De'Armond" -> "Deanna Johnson" +"Johnny Richardson" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=310"]; +"Russell Grant" -> "Johnny Richardson" +"Nathan Fellhauer" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=313"]; +"James Rowland" [color=thistle, URL="http://sdsu.kkytbs.net/members/profile.html?who=52"]; +"James Rowland" -> "Nathan Fellhauer" +"Kristianna Reynante" -> "Nathan Fellhauer" +"Brian Raneses" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=314"]; +"Sean McHenry" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=42"]; +"Sean McHenry" -> "Brian Raneses" +"Penny Lewis" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=315"]; +"Martin Naiman" -> "Penny Lewis" +"Becky Graham" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=316"]; +"Kristen Elgo" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=7"]; +"Kristen Elgo" -> "Becky Graham" +"Steven Gross" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=318"]; +"Rob Reiner" -> "Steven Gross" +"Stacy Snyder" -> "Steven Gross" +"Sedona Reynolds" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=32"]; +"Mark Newton-John" -> "Sedona Reynolds" +"Cindy Teel" -> "Sedona Reynolds" +"Klair Mayerchak" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=320"]; +"Nathan Fellhauer" -> "Klair Mayerchak" +"Becky Graham" -> "Klair Mayerchak" +"Shari VerBerkmoes" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=321"]; +"Sean McHenry" -> "Shari VerBerkmoes" +"Janean Angeles" -> "Shari VerBerkmoes" +"Anson Summers" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=326"]; +"James Rowland" -> "Anson Summers" +"Dusty Jolliff" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=33"]; +"Rob Reiner" -> "Dusty Jolliff" +"Stacy Snyder" -> "Dusty Jolliff" +"Jennifer Garman" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=331"]; +"James Rowland" -> "Jennifer Garman" +"Kelly Greenhill" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=333"]; +"Rob Reiner" -> "Kelly Greenhill" +"Kristen Elgo" -> "Kelly Greenhill" +"Lucinda Farless" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=334"]; +"J. Angeles" -> "Lucinda Farless" +"Susan Colwell" -> "Lucinda Farless" +"Alfredo Cardenas" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=335"]; +"Chuk Gawlik" -> "Alfredo Cardenas" +"Kathleen Hansen" -> "Alfredo Cardenas" +"Jennifer Jouan" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=34"]; +"Andrea Owens" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=276"]; +"Andrea Owens" -> "Jennifer Jouan" +"Tamara Scrivner" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=345"]; +"Joseph Butler" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=69"]; +"Sarah Maltese" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=83"]; +"Joseph Butler" -> "Tamara Scrivner" +"Sarah Maltese" -> "Tamara Scrivner" +"Bradley Stouse" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=346"]; +"Ryan Underwood" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=74"]; +"Ryan Underwood" -> "Bradley Stouse" +"Cindy Teel" -> "Bradley Stouse" +"Casondra Brimmage" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=347"]; +"Kristopher Lininger" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=85"]; +"Ilana Melcher" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=73"]; +"Kristopher Lininger" -> "Casondra Brimmage" +"Ilana Melcher" -> "Casondra Brimmage" +"Cassiopeia Guthrie" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=348"]; +"Jeremy Frazier" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=79"]; +"Christine Mount" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=76"]; +"Jeremy Frazier" -> "Cassiopeia Guthrie" +"Christine Mount" -> "Cassiopeia Guthrie" +"Kathleen Moran" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=349"]; +"Matthew FitzGerald" -> "Kathleen Moran" +"Lori Brede" -> "Kathleen Moran" +"Tiffany Kalland" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=35"]; +"Tony Sacco" -> "Tiffany Kalland" +"Karen Helbling" -> "Tiffany Kalland" +"Kristen Anderson" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=350"]; +"Jennie Bogart" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=78"]; +"David Guthrie" -> "Kristen Anderson" +"Jennie Bogart" -> "Kristen Anderson" +"Laura Simonette" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=351"]; +"Jon Weisel" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=89"]; +"Jon Weisel" -> "Laura Simonette" +"Japheth Cleaver" -> "Laura Simonette" +"Nathan Williams" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=352"]; +"David Guthrie" -> "Nathan Williams" +"Karen Helbling" -> "Nathan Williams" +"Rebecca Hippert" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=353"]; +"Ryan Underwood" -> "Rebecca Hippert" +"Tiffany Kalland" -> "Rebecca Hippert" +"Samuel Wallace" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=354"]; +"Joseph Butler" -> "Samuel Wallace" +"Deanna Jagow" -> "Samuel Wallace" +"Scott Gardner" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=355"]; +"Jeremy Frazier" -> "Scott Gardner" +"Christine Mount" -> "Scott Gardner" +"Alberto Ayon" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=356"]; +"Bradley Stouse" -> "Alberto Ayon" +"Jennie Bogart" -> "Alberto Ayon" +"Susannah Clayton" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=357"]; +"Nathan Williams" -> "Susannah Clayton" +"Karen Helbling" -> "Susannah Clayton" +"Lisa Gochnauer" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=358"]; +"Scott Gardner" -> "Lisa Gochnauer" +"Casondra Brimmage" -> "Lisa Gochnauer" +"Jamie Jackson" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=359"]; +"Samuel Wallace" -> "Jamie Jackson" +"Tamara Scrivner" -> "Jamie Jackson" +"Christina Kelly" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=36"]; +"Matthew FitzGerald" -> "Christina Kelly" +"Lori Brede" -> "Christina Kelly" +"Gara Thornton" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=360"]; +"Mark Newton-John" -> "Gara Thornton" +"Laura Simonette" -> "Gara Thornton" +"Robert Winebarger" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=361"]; +"Robin Ellison" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=90"]; +"Scott Gardner" -> "Robert Winebarger" +"Robin Ellison" -> "Robert Winebarger" +"Jeremy Kirchner" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=37"]; +"Rob Reiner" -> "Jeremy Kirchner" +"Sandy Konar" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=38"]; +"Jennifer Brandon" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=9"]; +"Jennifer Brandon" -> "Sandy Konar" +"Dan Kuhlman" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=39"]; +"Rob Reiner" -> "Dan Kuhlman" +"Dusty Jolliff" -> "Dan Kuhlman" +"Lindsay Arehart" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=4"]; +"Martin Naiman" -> "Lindsay Arehart" +"Jennifer Brandon" -> "Lindsay Arehart" +"J. Angeles" -> "Mervin Maniago" +"Kathy Jones" -> "Mervin Maniago" +"Jarrod Monroe" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=43"]; +"Jamie Fratacci" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=44"]; +"Mark Newton-John" -> "Jarrod Monroe" +"Jamie Fratacci" -> "Jarrod Monroe" +"Chuk Gawlik" -> "Jamie Fratacci" +"Tiffany Worthington" -> "Jamie Fratacci" +"Russell Grant" -> "Martin Naiman" +"Tonya Alexander" -> "Martin Naiman" +"Edward Givens" [color=lightblue, outline=bold, style=bold, URL="http://sdsu.kkytbs.net/members/profile.html?who=106"]; +"Edward Givens" -> "Mark Newton-John" +"Veronica Nickel" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=47"]; +"Regan Ashker" -> "Veronica Nickel" +"Wanda Livelsberger" -> "Lynn Reeves" +"Bryan Ransom" [color=thistle, URL="http://sdsu.kkytbs.net/members/profile.html?who=49"]; +"Jayson Smith" -> "Bryan Ransom" +"Tony Sacco" -> "Regan Ashker" +"Dusty Jolliff" -> "Regan Ashker" +"Jennifer Stout" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=50"]; +"Matthew FitzGerald" -> "Jennifer Stout" +"Deanna Jagow" -> "Jennifer Stout" +"Sean McHenry" -> "James Rowland" +"James Rowland" -> "Wanda Livelsberger" +"Janean Angeles" -> "Wanda Livelsberger" +"Melissa Roy" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=54"]; +"Mervin Maniago" -> "Melissa Roy" +"Christina Kelly" -> "Melissa Roy" +"Dennis McColl" -> "Tony Sacco" +"April Ortiz-cloninger" -> "Tony Sacco" +"Tony Sacco" -> "Karen Saye" +"Tony Sacco" -> "Amy Price" +"Kathleen Hansen" -> "Amy Price" +"James Rowland" -> "Jayson Smith" +"Brian Raneses" -> "Heather Smith" +"Kristen Elgo" -> "Heather Smith" +"Josh Atwood" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=6"]; +"David Guthrie" -> "Josh Atwood" +"Lori Brede" -> "Josh Atwood" +"Katie Browne" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=60"]; +"Patrick Doerr" -> "Katie Browne" +"Jamie Fratacci" -> "Katie Browne" +"Kristin Tang" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=61"]; +"James Rowland" -> "Kristin Tang" +"Heather Smith" -> "Kristin Tang" +"Mervin Maniago" -> "Cindy Teel" +"Veronica Nickel" -> "Cindy Teel" +"Mike Tulumello" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=63"]; +"Matthew FitzGerald" -> "Mike Tulumello" +"Katie Browne" -> "Mike Tulumello" +"Veronica Villanueva" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=64"]; +"Ryan Farris" -> "Veronica Villanueva" +"Sedona Reynolds" -> "Veronica Villanueva" +"Mervin Maniago" -> "Tiffany Worthington" +"Jennifer Jouan" -> "Tiffany Worthington" +"Scott Wright" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=67"]; +"James Rowland" -> "Scott Wright" +"Kristen Elgo" -> "Scott Wright" +"Jeremy Browne" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=68"]; +"Matthew FitzGerald" -> "Jeremy Browne" +"Japheth Cleaver" -> "Jeremy Browne" +"James Fogelman" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=688"]; +"Alberto Ayon" -> "James Fogelman" +"Susannah Clayton" -> "James Fogelman" +"Sandra Chase" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=689"]; +"David Guthrie" -> "Sandra Chase" +"Japheth Cleaver" -> "Sandra Chase" +"Patrick Doerr" -> "Joseph Butler" +"Deanna Jagow" -> "Joseph Butler" +"Laura Fisher" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=690"]; +"Nathan Williams" -> "Laura Fisher" +"Casondra Brimmage" -> "Laura Fisher" +"Katie Kozma" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=691"]; +"Scott Wright" -> "Katie Kozma" +"Robin Ellison" -> "Katie Kozma" +"Rachel Perkins" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=692"]; +"Joseph Butler" -> "Rachel Perkins" +"Cassiopeia Guthrie" -> "Rachel Perkins" +"Sarah Titilah" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=693"]; +"Robert Winebarger" -> "Sarah Titilah" +"Karen Helbling" -> "Sarah Titilah" +"Ashley Rehart" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=694"]; +"Laura Fisher" -> "Ashley Rehart" +"Cara Yancey" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=695"]; +"Katie Kozma" -> "Cara Yancey" +"Ashley Presley" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=698"]; +"Cara Yancey" -> "Ashley Presley" +"Leila Wilhelm" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=699"]; +"Robin Ellison" -> "Leila Wilhelm" +"Sean McHenry" -> "Kristen Elgo" +"Stacy Snyder" -> "Kristen Elgo" +"Greg Moody" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=70"]; +"Ryan Farris" -> "Greg Moody" +"Jennifer Stout" -> "Greg Moody" +"Lisa Fleck" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=700"]; +"Rachel Perkins" -> "Lisa Fleck" +"Christine Coyne" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=701"]; +"Rachel Perkins" -> "Christine Coyne" +"Jennifer Cooley" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=702"]; +"Laura Fisher" -> "Jennifer Cooley" +"Elizabeth Larios" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=703"]; +"Ashley Rehart" -> "Elizabeth Larios" +"Cate Threlkeld" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=707"]; +"Katie Kozma" -> "Cate Threlkeld" +"Erika Tapia" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=71"]; +"Patrick Doerr" -> "Erika Tapia" +"Melissa Roy" -> "Erika Tapia" +"Robbyn Rozelle" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=72"]; +"Jarrod Monroe" -> "Robbyn Rozelle" +"Tiffany Kalland" -> "Robbyn Rozelle" +"Ryan Farris" -> "Ilana Melcher" +"Veronica Villanueva" -> "Ilana Melcher" +"Greg Moody" -> "Ryan Underwood" +"Katie Browne" -> "Ryan Underwood" +"Cameron Brown" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=75"]; +"Joseph Butler" -> "Cameron Brown" +"Tiffany Kalland" -> "Cameron Brown" +"Ryan Underwood" -> "Christine Mount" +"Lori Brede" -> "Christine Mount" +"Janay Rabe" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=77"]; +"Greg Moody" -> "Janay Rabe" +"Cindy Teel" -> "Janay Rabe" +"Jeremy Browne" -> "Jennie Bogart" +"Tiffany Kalland" -> "Jennie Bogart" +"Ryan Farris" -> "Jeremy Frazier" +"Ilana Melcher" -> "Jeremy Frazier" +"Crystal Bozak" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=8"]; +"Patrick Doerr" -> "Crystal Bozak" +"Katie Browne" -> "Crystal Bozak" +"Kameka Smith" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=80"]; +"Matthew FitzGerald" -> "Kameka Smith" +"Ilana Melcher" -> "Kameka Smith" +"Kyra Sacco" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=81"]; +"Joseph Butler" -> "Kyra Sacco" +"Robbyn Rozelle" -> "Kyra Sacco" +"Samuel Behar" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=82"]; +"Ryan Underwood" -> "Samuel Behar" +"Lori Brede" -> "Samuel Behar" +"Patrick Doerr" -> "Sarah Maltese" +"Deanna Jagow" -> "Sarah Maltese" +"David Bronson" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=84"]; +"Kristin Alongi-Hutchins" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=87"]; +"Tony Sacco" -> "David Bronson" +"Kristin Alongi-Hutchins" -> "David Bronson" +"Cameron Brown" -> "Kristopher Lininger" +"Kameka Smith" -> "Kristopher Lininger" +"Rakan Abu-Rahma" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=852"]; +"Christine Coyne" -> "Rakan Abu-Rahma" +"Jennifer Berry" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=270"]; +"Jennifer Berry" -> "Janean Angeles" +"Penny Lewis" -> "Kristin Alongi-Hutchins" +"Melissa Bebak" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=88"]; +"Greg Moody" -> "Melissa Bebak" +"Sarah Maltese" -> "Melissa Bebak" +"Scott Wright" -> "Jennifer Brandon" +"Japheth Cleaver" -> "Jennifer Brandon" +"Samuel Behar" -> "Robin Ellison" +"Kyra Sacco" -> "Robin Ellison" +"Teresa Simms" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=91"]; +"Joseph Butler" -> "Teresa Simms" +"Janay Rabe" -> "Teresa Simms" +"Robert Schmidtke" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=188"]; +"Jean Newman" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=166"]; +"Robert Schmidtke" -> "John FitzGibbon" +"Jean Newman" -> "John FitzGibbon" +"Brittany DePew" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=928"]; +"Elizabeth Larios" -> "Brittany DePew" +"Kathleen Halberg" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=929"]; +"Ashley Rehart" -> "Kathleen Halberg" +"Terrance Hirsch" [color=lightblue, URL="http://sdsu.kkytbs.net/members/profile.html?who=96"]; +"J. Angeles" -> "Terrance Hirsch" +"Susan Colwell" -> "Terrance Hirsch" +"Monique Arellano" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=972"]; +"Ashley Presley" -> "Monique Arellano" +"Anthony Henderson" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=973"]; +"Jennifer Cooley" -> "Anthony Henderson" +"Amethyst Tagle" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=974"]; +"Cate Threlkeld" -> "Amethyst Tagle" +"Mallory Williams" [color=lightpink, URL="http://sdsu.kkytbs.net/members/profile.html?who=975"]; +"Lisa Fleck" -> "Mallory Williams" +} \ No newline at end of file diff --git a/examples/graph/graphviz/data/softmaint.gv.txt b/examples/graph/graphviz/data/softmaint.gv.txt new file mode 100644 index 00000000..04110890 --- /dev/null +++ b/examples/graph/graphviz/data/softmaint.gv.txt @@ -0,0 +1,377 @@ +digraph G { + size="7,10" + page="8.5,11" + center="" + node[width=.25,height=.375,fontsize=9] + fcfpr1_1_2t_17 -> 341411; + fcfpr1_1t_1 -> 341411; + rdlfpr2_0_rdlt_4 -> 341411; + fpfpr1_0_1t_1 -> 341411; + fpfpr1_1_2t_11 -> 341411; + rtafpr1_1_2t_28 -> 341411; + rtafpr1_1_3t_6 -> 341411; + rdlfpr1_1t_1 -> 358866; + rtafpr1_1_3t_6 -> 358866; + tmfpr1_1_3t_5 -> 358930; + fcfpr1_1_3t_9 -> 358930; + pcfpr1_1_3t_7 -> 358930; + fpfpr1_1_3g_1 -> 358930; + fpfpr1_1_3t_1 -> 358930; + aufpr1_1_3t_1 -> 358930; + rtafpr1_0_3g_1 -> 358930; + rtafpr1_1_3t_6 -> 358930; + msgfpr1_1_1g_12 -> 371943; + rtafpr1_1_1g_8 -> 371943; + rtafpr1_1_1t_35 -> 371943; + rtafpr1_1_1t_45 -> 371943; + rtafpr1_1_3t_6 -> 371943; + tlfpr2_0_rdlg_2 -> 374300; + fcfpr1_1_3t_8 -> 374300; + fcfpr1_1_3t_9 -> 374300; + rtafpr1_1_3t_6 -> 374300; + fcfpr1_0_5g_1 -> 371942; + fcfpr1_1_1t_19 -> 371942; + fcfpr1_1_3t_9 -> 371942; + fcfpr1_1_3t_9 -> 374700; + tymsgfpr1_1_3t_3 -> 374700; + fpfpr1_1_3t_1 -> 374700; + rtafpr1_1_3t_7 -> 374700; + fcfpr1_1_3g_2 -> 374741; + fcfpr1_1_3t_9 -> 374741; + fpfpr1_1_3t_1 -> 374741; + rtafpr1_1_3t_7 -> 374741; + fcfpr1_1_1t_18 -> 374886; + fcfpr1_1_3t_9 -> 374886; + fpfpr1_1_3t_1 -> 374886; + rtafpr1_1_3t_7 -> 374886; + fcfpr1_1_3t_9 -> 375039; + fpfpr1_1_3t_1 -> 375039; + fcfpr1_1_3t_42 -> 375507; + fcfpr1_1_3t_9 -> 375507; + rdlfpr2_0_rdlt_158 -> 375507; + rtafpr1_1_3t_7 -> 375507; + rtafpr1_1_3t_71 -> 375507; + dbfpr1_1_3t_2 -> 375507; + fcfpr1_1_3t_9 -> 375508; + rdlfpr1_1g_13 -> 375508; + rtafpr1_1_3t_7 -> 375508; + rtafpr2_1_rdlg_1 -> 375508; + dbfpr1_1_3t_2 -> 375508; + fcfpr1_1_3t_9 -> 375519; + fpfpr1_1_3g_1 -> 375519; + fpfpr1_1_3t_1 -> 375519; + fcfpr1_1_3t_9 -> 377380; + rdlfpr1_1g_16 -> 377380; + rdlfpr1_1t_100 -> 377380; + fcfpr1_0_2g_1 -> 377719; + fcfpr1_1_3t_10 -> 377719; + fcfpr1_1_3t_7 -> 377719; + fcfpr1_1_3t_9 -> 377719; + rdlfpr2_0_rdlg_12 -> 377719; + rdlfpr2_0_rdlt_108 -> 377719; + rdlfpr2_0_rdlt_27 -> 377719; + rdlfpr2_0_rdlt_30 -> 377719; + fcfpr1_1_3t_9 -> 377763; + fcfpr1_1_3t_9 -> 379848; + fpfpr1_1_3t_1 -> 379848; + fcfpr1_1_3t_9 -> 380571; + fcfpr1_1_3t_9 -> 380604; + fpfpr1_1_3t_1 -> 380604; + fcfpr1_1_3t_9 -> 381211; + fpfpr1_1_3t_1 -> 381211; + fcfpr1_1_3t_9 -> 381835; + fcfpr1_1_3t_9 -> 381897; + fcfpr1_1_3t_9 -> 381901; + fpfpr1_1_3t_1 -> 381901; + fcfpr1_1_3t_9 -> 382103; + rtafpr1_1_3t_7 -> 382103; + fcfpr1_1_3t_9 -> 382161; + fcfpr1_1_3t_9 -> 383174; + fpfpr1_1_3t_1 -> 383174; + rtafpr1_1_3t_7 -> 383174; + fpfpr1_1_3g_1 -> 352010; + fpfpr1_1_3t_1 -> 352010; + fpfpr1_1_3t_1 -> 382409; + fpfpr1_1_3t_1 -> 382827; + fpfpr1_1_3t_1 -> 382928; + rtafpr1_1_3t_7 -> 382928; + tlfpr1_1_1t_5 -> 358224; + tymsgfpr1_1_1t_23 -> 358224; + tymsgfpr1_1_3t_3 -> 358224; + rcfpr0_0_1t_9 -> 358224; + rcfpr1_1_1t_5 -> 358224; + odfpr0_0_1t_8 -> 358224; + odfpr1_1_1t_6 -> 358224; + ecdsgfpr1_1_1t_4 -> 358224; + tymsgfpr1_1_1t_18 -> 358900; + tymsgfpr1_1_3t_3 -> 358900; + rcfpr1_1_1t_100 -> 358900; + rcfpr1_1_1t_22 -> 358900; + rcfpr1_1_1t_37 -> 358900; + odfpr1_1_1t_21 -> 358900; + tymsgfpr1_1_3t_3 -> 372568; + rcfpr1_1_1t_30 -> 372568; + odfpr1_1_1t_31 -> 372568; + tlfpr1_1_1t_20 -> 375557; + tymsgfpr1_1_1t_24 -> 375557; + tymsgfpr1_1_3t_3 -> 375557; + rcfpr1_1_1t_11 -> 375557; + odfpr1_1_1t_9 -> 375557; + ecdsgfpr1_1_1t_19 -> 375557; + rtafpr1_1_1g_14 -> 376956; + rtafpr1_1_1t_64 -> 376956; + rtafpr1_1_2t_18 -> 376956; + rtafpr1_1_3t_30 -> 376956; + rtafpr1_1_3t_7 -> 376956; + rtafpr1_1_3t_7 -> 379339; + rtafpr1_1_1t_14 -> 379422; + rtafpr1_1_1t_20 -> 379422; + rtafpr1_1_3t_7 -> 379422; + rtafpr1_1_3t_7 -> 383039; + fcfpr1_1_1t_18 -> 359471; + fcfpr2_0_1t_1 -> 359471; + fcfpr2_0_1t_2 -> 359471; + ccsfpr2_0_1t_99 -> 359471; + fcfpr1_1_3t_42 -> 384096; + rtafpr1_1_3t_71 -> 384096; + tlfpr1_0_4g_4 -> 354290; + rcfpr0_0_1t_9 -> 354290; + odfpr0_0_1t_8 -> 354290; + pagfpr1_1_1t_23 -> 354290; + rcfpr1_1_1t_5 -> 379864; + rcfpr1_1_1t_100 -> 382574; + rcfpr1_1_1t_22 -> 382574; + rcfpr1_1_1t_37 -> 382574; + rcfpr1_1_1t_30 -> 370706; + rcfpr1_1_1t_30 -> 377908; + rcfpr1_1_1t_30 -> 377924; + rcfpr1_1_1t_30 -> 377971; + rcfpr1_1_1t_30 -> 377980; + odfpr1_1_1t_31 -> 377980; + rcfpr1_1_1t_30 -> 378362; + rcfpr1_1_1t_30 -> 378656; + rcfpr1_1_1t_30 -> 378666; + rcfpr1_1_1t_30 -> 379169; + odfpr1_1_1t_31 -> 379169; + rcfpr1_1_1t_110 -> 379341; + rcfpr1_1_1t_30 -> 379341; + rcfpr1_1_1t_62 -> 379341; + odfpr1_1_1t_31 -> 379341; + rcfpr1_1_1t_30 -> 379972; + rcfpr1_1_1t_30 -> 380298; + rcfpr1_1_1t_30 -> 380448; + rcfpr1_1_1t_30 -> 380475; + odfpr1_1_1t_31 -> 380475; + rcfpr1_1_1t_30 -> 380526; + odfpr1_1_1t_31 -> 357430; + rcfpr1_1_1t_11 -> 379968; + odfpr1_1_1t_9 -> 379968; + ccsfpr2_0_1t_99 -> 359100; + ccsfpr2_0_1t_99 -> 376529; + ccsfpr2_0_1t_99 -> 377801; + ccsfpr2_0_1t_99 -> 379126; + ccsfpr2_0_1t_99 -> 379212; + ccsfpr2_0_1t_99 -> 380285; + ccsfpr2_0_1t_99 -> 380963; + ccsfpr2_0_1t_99 -> 384909; + tlfpr1_0_4g_4 -> 358471; + odfpr0_0_1t_7 -> 358471; + odfpr1_0_1t_36 -> 358471; + odfpr1_0_3t_18 -> 358471; + odfpr1_0_3t_21 -> 358471; + tlfpr1_0_4g_4 -> 375024; + tlfpr1_0_4g_4 -> 375027; + rcfpr1_1_1t_110 -> 381710; + rcfpr1_1_1t_62 -> 381710; + rcfpr1_1_1t_110 -> 381775; + rcfpr1_1_1t_62 -> 381775; + rcfpr1_1_1t_110 -> 382436; + fcfpr1_1_3t_34 -> 382528; + rcfpr1_1_1t_110 -> 382528; + rtafpr1_1_3t_48 -> 382528; + rcfpr1_1_1t_110 -> 382566; + rcfpr1_1_1t_110 -> 382572; + odfpr0_0_1t_7 -> 353506; + rcfpr1_0_1t_35 -> 370509; + odfpr0_0_1t_7 -> 370509; + odfpr0_0_1t_7 -> 370510; + odfpr1_0_1t_38 -> 370510; + tlfpr1_0_4g_5 -> 354546; + rcfpr1_1_1t_61 -> 354546; + odfpr1_0_3t_18 -> 354546; + odfpr1_0_3t_20 -> 354546; + odfpr1_0_3t_18 -> 354757; + odfpr1_0_3t_20 -> 354757; + odfpr1_0_3t_18 -> 354766; + odfpr1_0_3t_20 -> 354766; + odfpr1_0_3t_18 -> 354771; + odfpr1_0_3t_20 -> 354771; + odfpr1_0_3t_18 -> 354785; + odfpr1_0_3t_23 -> 354785; + odfpr1_0_3t_24 -> 354785; + odfpr1_0_3t_18 -> 354878; + odfpr1_0_3t_23 -> 354878; + odfpr1_0_3t_24 -> 354878; + odfpr1_0_3t_18 -> 355080; + odfpr1_0_3t_23 -> 355080; + odfpr1_0_3t_24 -> 355080; + odfpr1_0_3t_18 -> 355288; + odfpr1_0_3t_23 -> 355288; + odfpr1_0_3t_24 -> 355288; + odfpr2_0_03t_13 -> 355288; + odfpr1_0_3t_18 -> 355800; + odfpr1_0_3t_21 -> 355800; + odfpr1_0_3t_18 -> 356116; + odfpr1_0_3t_21 -> 356116; + odfpr1_0_3t_18 -> 356741; + odfpr1_0_3t_21 -> 356741; + odfpr1_0_3t_18 -> 357340; + odfpr1_0_3t_21 -> 357340; + odfpr1_0_3t_18 -> 357538; + odfpr1_0_3t_21 -> 357538; + odfpr1_0_3t_18 -> 357769; + odfpr1_0_3t_21 -> 357769; + odfpr1_0_3t_18 -> 357793; + odfpr1_0_3t_21 -> 357793; + odfpr1_0_3t_18 -> 358155; + odfpr1_0_3t_21 -> 358155; + odfpr1_0_3t_18 -> 358157; + odfpr1_0_3t_21 -> 358157; + odfpr1_0_3t_18 -> 358159; + odfpr1_0_3t_21 -> 358159; + odfpr1_0_3t_18 -> 358584; + odfpr1_0_3t_21 -> 358584; + odfpr1_0_3t_18 -> 360104; + odfpr1_0_3t_21 -> 360104; + odfpr1_0_3t_18 -> 360144; + odfpr1_0_3t_21 -> 360144; + odfpr1_0_3t_18 -> 360672; + odfpr1_0_3t_21 -> 360672; + odfpr1_0_3t_5 -> 360672; + odfpr1_0_3t_18 -> 360839; + odfpr1_0_3t_21 -> 360839; + odfpr1_0_3t_18 -> 371187; + tlfpr1_0_3g_5 -> 373300; + odfpr1_0_3t_12 -> 373300; + odfpr1_0_3t_18 -> 373300; + odfpr1_0_3t_18 -> 375134; + odfpr1_0_5t_18 -> 375134; + rcfpr0_0_1t_10 -> 375319; + odfpr1_0_3t_18 -> 375319; + odfpr1_0_3t_36 -> 375319; + odfpr1_0_5t_17 -> 375319; + odfpr1_0_5t_19 -> 375319; + odfpr1_0_3t_18 -> 375499; + odfpr1_0_3t_18 -> 377220; + odfpr1_0_5t_21 -> 377220; + tlfpr1_0_3g_7 -> 377562; + tlfpr1_1_1t_3 -> 377562; + odfpr1_0_3t_18 -> 377562; + odfpr1_0_3t_36 -> 377562; + odfpr1_0_5t_20 -> 377562; + odfpr1_0_3t_18 -> 378108; + odfpr1_0_3t_6 -> 378108; + odfpr1_0_5t_20 -> 354221; + + odfpr0_0_1t_7 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + tlfpr1_0_3g_5 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + odfpr0_0_1t_8 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rcfpr1_1_1t_61 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + fcfpr1_1t_1 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + odfpr1_0_3t_18 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + tlfpr1_0_3g_7 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rcfpr1_1_1t_62 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + ccsfpr2_0_1t_99 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + tymsgfpr1_1_3t_3 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rcfpr0_0_1t_9 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rtafpr1_1_1t_14 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rtafpr1_1_3t_30 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rcfpr1_1_1t_110 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + dbfpr1_1_3t_2 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rtafpr1_1_1g_8 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rcfpr1_1_1t_30 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + tlfpr1_1_1t_20 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rtafpr1_1_1t_64 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + tlfpr2_0_rdlg_2 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rtafpr1_1_2t_28 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + tlfpr1_1_1t_3 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + odfpr1_1_1t_6 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + fpfpr1_1_3t_1 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + aufpr1_1_3t_1 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + fcfpr1_1_3t_34 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rcfpr1_1_1t_5 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + fcfpr1_1_1t_18 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + odfpr1_0_3t_36 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + tlfpr1_1_1t_5 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + fcfpr1_1_1t_19 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + odfpr1_1_1t_9 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + fcfpr1_1_3t_7 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rcfpr1_1_1t_37 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + fcfpr1_1_3t_8 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + odfpr1_1_1t_21 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + fcfpr1_1_3t_9 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rdlfpr2_0_rdlt_27 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + fcfpr1_1_3g_2 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rtafpr1_1_1t_35 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + odfpr1_0_5t_20 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + fpfpr1_1_3g_1 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + odfpr1_0_5t_21 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + fpfpr1_1_2t_11 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + ecdsgfpr1_1_1t_19 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + odfpr1_0_1t_36 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rtafpr1_1_1g_14 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + tymsgfpr1_1_1t_23 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + tymsgfpr1_1_1t_24 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + odfpr1_0_1t_38 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + fcfpr1_0_2g_1 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rdlfpr1_1t_1 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rcfpr0_0_1t_10 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rcfpr1_1_1t_100 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rdlfpr2_0_rdlt_108 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + pcfpr1_1_3t_7 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + odfpr1_0_3t_20 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + ecdsgfpr1_1_1t_4 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + tmfpr1_1_3t_5 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + odfpr1_0_3t_21 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + fpfpr1_0_1t_1 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + odfpr1_0_3t_23 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rcfpr1_1_1t_22 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + pagfpr1_1_1t_23 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rtafpr1_1_3t_71 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rtafpr1_1_2t_18 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rdlfpr2_0_rdlt_158 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rtafpr1_1_3t_6 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + odfpr1_0_3t_24 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rtafpr1_1_3t_7 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rtafpr1_0_3g_1 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rtafpr1_1_1t_20 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rdlfpr1_1g_13 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rcfpr1_0_1t_35 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + fcfpr1_1_2t_17 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rtafpr2_1_rdlg_1 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rdlfpr2_0_rdlt_4 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rdlfpr1_1g_16 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + fcfpr2_0_1t_1 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + fcfpr2_0_1t_2 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rdlfpr1_1t_100 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + msgfpr1_1_1g_12 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rdlfpr2_0_rdlt_30 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + odfpr1_0_3t_5 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + tlfpr1_0_4g_4 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + fcfpr1_1_3t_42 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + odfpr1_0_3t_6 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + tlfpr1_0_4g_5 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rtafpr1_1_3t_48 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + odfpr1_0_5t_17 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + odfpr1_0_5t_18 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + tymsgfpr1_1_1t_18 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + odfpr1_0_5t_19 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + fcfpr1_1_3t_10 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + fcfpr1_0_5g_1 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + odfpr1_0_3t_12 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + odfpr2_0_03t_13 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rcfpr1_1_1t_11 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + odfpr1_1_1t_31 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rdlfpr2_0_rdlg_12 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; + rtafpr1_1_1t_45 [label="",shape=circle,height=0.12,width=0.12,fontsize=1]; +} diff --git a/examples/graph/graphviz/data/traffic_lights.gv.txt b/examples/graph/graphviz/data/traffic_lights.gv.txt new file mode 100644 index 00000000..2cc3c482 --- /dev/null +++ b/examples/graph/graphviz/data/traffic_lights.gv.txt @@ -0,0 +1,29 @@ +##"I played some days with making an interface between our ConceptBase system (essentially a database system to store models) and graphviz. One example graph is attached. It is a so-called petri net for Dutch traffic lights. The example is actually taken from a book by Wil van der Aalst." Contributed by Manfred Jeusfeld. + +##Command to produce the output: "neato -Tpng thisfile > thisfile.png" + +digraph TrafficLights { +node [shape=box]; gy2; yr2; rg2; gy1; yr1; rg1; +node [shape=circle,fixedsize=true,width=0.9]; green2; yellow2; red2; safe2; safe1; green1; yellow1; red1; +gy2->yellow2; +rg2->green2; +yr2->safe1; +yr2->red2; +safe2->rg2; +green2->gy2; +yellow2->yr2; +red2->rg2; +gy1->yellow1; +rg1->green1; +yr1->safe2; +yr1->red1; +safe1->rg1; +green1->gy1; +yellow1->yr1; +red1->rg1; + +overlap=false +label="PetriNet Model TrafficLights\nExtracted from ConceptBase and layed out by Graphviz" +fontsize=12; +} + diff --git a/examples/graph/graphviz/data/transparency.gv.txt b/examples/graph/graphviz/data/transparency.gv.txt new file mode 100644 index 00000000..cfb82319 --- /dev/null +++ b/examples/graph/graphviz/data/transparency.gv.txt @@ -0,0 +1,105 @@ +graph G { +// graph [splines=true overlap=false] +// graph [truecolor bgcolor="#ff00005f"] + node [style=filled fillcolor="#00ff005f"] + 1 -- 30 [f=1]; + 1 -- 40 [f=14]; + 8 -- 46 [f=1]; + 8 -- 16 [f=18]; + 10 -- 25 [f=1]; + 10 -- 19 [f=5]; + 10 -- 33 [f=1]; + 12 -- 8 [f=1]; + 12 -- 36 [f=5]; + 12 -- 17 [f=16]; + 13 -- 38 [f=1]; + 13 -- 24 [f=19]; + 24 -- 49 [f=1]; + 24 -- 13 [f=1]; + 24 -- 47 [f=12]; + 24 -- 12 [f=19]; + 25 -- 27 [f=1]; + 25 -- 12 [f=1]; + 27 -- 12 [f=1]; + 27 -- 14 [f=8]; + 29 -- 10 [f=1]; + 29 -- 8 [f=17]; + 30 -- 24 [f=1]; + 30 -- 44 [f=15]; + 38 -- 29 [f=1]; + 38 -- 35 [f=15]; + 2 -- 42 [f=2]; + 2 -- 35 [f=3]; + 2 -- 11 [f=19]; + 14 -- 18 [f=2]; + 14 -- 24 [f=15]; + 14 -- 38 [f=18]; + 18 -- 49 [f=2]; + 18 -- 47 [f=20]; + 26 -- 41 [f=2]; + 26 -- 42 [f=15]; + 31 -- 39 [f=2]; + 31 -- 47 [f=17]; + 31 -- 25 [f=14]; + 37 -- 26 [f=2]; + 37 -- 16 [f=14]; + 39 -- 50 [f=2]; + 39 -- 14 [f=2]; + 39 -- 18 [f=17]; + 39 -- 47 [f=10]; + 41 -- 31 [f=2]; + 41 -- 8 [f=16]; + 42 -- 44 [f=2]; + 42 -- 29 [f=12]; + 44 -- 37 [f=2]; + 44 -- 32 [f=15]; + 3 -- 20 [f=2]; + 3 -- 28 [f=19]; + 6 -- 45 [f=2]; + 6 -- 28 [f=10]; + 9 -- 6 [f=2]; + 9 -- 16 [f=1]; + 15 -- 16 [f=2]; + 15 -- 48 [f=2]; + 16 -- 50 [f=2]; + 16 -- 32 [f=14]; + 16 -- 39 [f=8]; + 20 -- 33 [f=2]; + 33 -- 9 [f=2]; + 33 -- 46 [f=3]; + 33 -- 48 [f=17]; + 45 -- 15 [f=2]; + 4 -- 17 [f=4]; + 4 -- 15 [f=6]; + 4 -- 12 [f=16]; + 17 -- 21 [f=4]; + 19 -- 35 [f=4]; + 19 -- 15 [f=9]; + 19 -- 43 [f=4]; + 21 -- 19 [f=4]; + 21 -- 50 [f=4]; + 23 -- 36 [f=4]; + 34 -- 23 [f=4]; + 34 -- 24 [f=11]; + 35 -- 34 [f=4]; + 35 -- 16 [f=6]; + 35 -- 18 [f=16]; + 36 -- 46 [f=4]; + 5 -- 7 [f=1]; + 5 -- 36 [f=6]; + 7 -- 32 [f=1]; + 7 -- 11 [f=2]; + 7 -- 14 [f=17]; + 11 -- 40 [f=1]; + 11 -- 50 [f=1]; + 22 -- 46 [f=1]; + 28 -- 43 [f=1]; + 28 -- 8 [f=18]; + 32 -- 28 [f=1]; + 32 -- 39 [f=13]; + 32 -- 42 [f=15]; + 40 -- 22 [f=1]; + 40 -- 47 [f=1]; + 43 -- 11 [f=1]; + 43 -- 17 [f=19]; +} diff --git a/examples/graph/graphviz/data/twopi2.gv.txt b/examples/graph/graphviz/data/twopi2.gv.txt new file mode 100644 index 00000000..72b28fa7 --- /dev/null +++ b/examples/graph/graphviz/data/twopi2.gv.txt @@ -0,0 +1,2212 @@ +digraph G { + ranksep=3; + ratio=auto; +"1" [ label="02f5daf56e299b8a8ecea892",shape="hexagon",style="filled",color="green" ]; +"189E" [ label="ca5af2",shape="box",style="filled",color="grey" ]; +"790E" [ label="b4dfef6",shape="box",style="filled",color="grey" ]; +"2" [ label="171192dc1f8e6ea551548a910c00",shape="hexagon",style="filled",color="green" ]; +"191E" [ label="629e42",shape="box",style="filled",color="grey" ]; +"3" [ label="6bce02baf91781a831e1b95",shape="hexagon",style="filled",color="green" ]; +"193E" [ label="1c08373",shape="box",style="filled",color="grey" ]; +"4" [ label="6236a67933a619a6a3d48",shape="hexagon",style="filled",color="green" ]; +"195E" [ label="be8f4199f",shape="box",style="filled",color="grey" ]; +"5" [ label="50962c93b4cb293f5beb59eb",shape="hexagon",style="filled",color="green" ]; +"197E" [ label="be8f4199f",shape="box",style="filled",color="grey" ]; +"6" [ label="05d4b1ed6a6135eec3abd3f2",shape="hexagon",style="filled",color="green" ]; +"199E" [ label="",shape="box",style="filled",color="grey" ]; +"7" [ label="08769f73d31c1a99be2d9363f",shape="hexagon",style="filled",color="green" ]; +"201E" [ label="629e42",shape="box",style="filled",color="grey" ]; +"8" [ label="a6a196a504c3a7657d1fa41",shape="hexagon",style="filled",color="green" ]; +"203E" [ label="cd856f",shape="box",style="filled",color="grey" ]; +"9" [ label="837ebf4bde22e1f1535cb662",shape="hexagon",style="filled",color="green" ]; +"725E" [ label="d0eb84",shape="box",style="filled",color="grey" ]; +"785E" [ label="dd2ba36",shape="box",style="filled",color="grey" ]; +"10" [ label="5f865c374cb3fe976dd376b8",shape="hexagon",style="filled",color="green" ]; +"205E" [ label="23ad1",shape="box",style="filled",color="grey" ]; +"11" [ label="8be752bc95d436a90493bec9",shape="hexagon",style="filled",color="green" ]; +"207E" [ label="ee91c97828",shape="box",style="filled",color="grey" ]; +"12" [ label="969a58db14386cb9d2f51ec",shape="hexagon",style="filled",color="green" ]; +"209E" [ label="7c7c",shape="box",style="filled",color="grey" ]; +"13" [ label="da24f74aad2ff519009d1f38c",shape="hexagon",style="filled",color="green" ]; +"211E" [ label="460aed10cc9",shape="box",style="filled",color="grey" ]; +"14" [ label="3124d3a6ed3381a6341c6",shape="hexagon",style="filled",color="green" ]; +"213E" [ label="bbe0a8f93dc1",shape="box",style="filled",color="grey" ]; +"15" [ label="71512ec7d43f958f2b6da",shape="hexagon",style="filled",color="green" ]; +"215E" [ label="3f0a2b4eb62f",shape="box",style="filled",color="grey" ]; +"16" [ label="3828a2c682419423cf",shape="hexagon",style="filled",color="green" ]; +"727E" [ label="2",shape="box",style="filled",color="grey" ]; +"784E" [ label="",shape="box",style="filled",color="grey" ]; +"17" [ label="aa868f65c34cdb64f1fad19a",shape="hexagon",style="filled",color="green" ]; +"217E" [ label="3089106e3b",shape="box",style="filled",color="grey" ]; +"787E" [ label="1aaaab063",shape="box",style="filled",color="grey" ]; +"18" [ label="dca32af03698c988b22",shape="hexagon",style="filled",color="green" ]; +"219E" [ label="eb8",shape="box",style="filled",color="grey" ]; +"19" [ label="d8f4a9e463a1e89217f",shape="hexagon",style="filled",color="green" ]; +"221E" [ label="4c6c8c",shape="box",style="filled",color="grey" ]; +"20" [ label="c96782ef56711c5d6a3f69",shape="hexagon",style="filled",color="green" ]; +"223E" [ label="6a8f5bafb1",shape="box",style="filled",color="grey" ]; +"21" [ label="4f04c39708f",shape="hexagon",style="filled",color="green" ]; +"225E" [ label="a49284e9",shape="box",style="filled",color="grey" ]; +"22" [ label="97284d4c3a5d499853f0e",shape="hexagon",style="filled",color="green" ]; +"227E" [ label="53069e384a2",shape="box",style="filled",color="grey" ]; +"792E" [ label="79b69c612",shape="box",style="filled",color="grey" ]; +"23" [ label="c4d32527b670afb370d643",shape="hexagon",style="filled",color="green" ]; +"231E" [ label="e851f5ddd920",shape="box",style="filled",color="grey" ]; +"24" [ label="5e9156098c064",shape="hexagon",style="filled",color="green" ]; +"233E" [ label="",shape="box",style="filled",color="grey" ]; +"25" [ label="3d475ea3aeca51b60212dd",shape="hexagon",style="filled",color="green" ]; +"235E" [ label="4280833ef80172",shape="box",style="filled",color="grey" ]; +"26" [ label="966d271c22e75c7538",shape="hexagon",style="filled",color="green" ]; +"237E" [ label="cab04b7c14a",shape="box",style="filled",color="grey" ]; +"27" [ label="b630e1af6ae1997f0e8ba750",shape="hexagon",style="filled",color="green" ]; +"239E" [ label="bb828f1a326",shape="box",style="filled",color="grey" ]; +"783E" [ label="499f6985db294c",shape="box",style="filled",color="grey" ]; +"28" [ label="ebd8ffc2ac3a90efb8af9",shape="hexagon",style="filled",color="green" ]; +"241E" [ label="1ebeec",shape="box",style="filled",color="grey" ]; +"791E" [ label="c0b727",shape="box",style="filled",color="grey" ]; +"29" [ label="69fdd1a1f4768c5efe7",shape="hexagon",style="filled",color="green" ]; +"243E" [ label="35b8742610",shape="box",style="filled",color="grey" ]; +"30" [ label="d93a80739fc1edb41a11b7294",shape="hexagon",style="filled",color="green" ]; +"245E" [ label="e03b8bc0435a",shape="box",style="filled",color="grey" ]; +"31" [ label="bf65cfddeb00ff847feae0c",shape="hexagon",style="filled",color="green" ]; +"247E" [ label="8df",shape="box",style="filled",color="grey" ]; +"32" [ label="916c686a1e82dba72524a",shape="hexagon",style="filled",color="green" ]; +"249E" [ label="a849f9d352e",shape="box",style="filled",color="grey" ]; +"33" [ label="f496bcf0889b301d77819c",shape="hexagon",style="filled",color="green" ]; +"251E" [ label="f29dfb9",shape="box",style="filled",color="grey" ]; +"34" [ label="76889f7d35e",shape="hexagon",style="filled",color="green" ]; +"253E" [ label="e7ef998",shape="box",style="filled",color="grey" ]; +"35" [ label="668d636002",shape="hexagon",style="filled",color="green" ]; +"255E" [ label="4379b5ed",shape="box",style="filled",color="grey" ]; +"36" [ label="e1e4c23db39d8bd633c3a",shape="hexagon",style="filled",color="green" ]; +"257E" [ label="1ed5d7f63b8c6",shape="box",style="filled",color="grey" ]; +"37" [ label="842bc5775657c1e0d67",shape="hexagon",style="filled",color="green" ]; +"259E" [ label="a387210a27b",shape="box",style="filled",color="grey" ]; +"38" [ label="e4e2f4e6d",shape="hexagon",style="filled",color="green" ]; +"261E" [ label="1f4f0fdf",shape="box",style="filled",color="grey" ]; +"39" [ label="04390dec6f1779353c07f5",shape="hexagon",style="filled",color="green" ]; +"263E" [ label="bac77c3f414a",shape="box",style="filled",color="grey" ]; +"40" [ label="69f2611acc42c36ed7cc",shape="hexagon",style="filled",color="green" ]; +"265E" [ label="cab04b7c14a",shape="box",style="filled",color="grey" ]; +"41" [ label="1562abef0d8241",shape="hexagon",style="filled",color="green" ]; +"267E" [ label="6a8f5bafb1",shape="box",style="filled",color="grey" ]; +"42" [ label="e49aaa5cc4e44355d6a0",shape="hexagon",style="filled",color="green" ]; +"269E" [ label="cc3f63d",shape="box",style="filled",color="grey" ]; +"43" [ label="e8ebe1bf5f421c1223",shape="hexagon",style="filled",color="green" ]; +"271E" [ label="96325ea",shape="box",style="filled",color="grey" ]; +"44" [ label="2759e82e30d6d",shape="hexagon",style="filled",color="green" ]; +"273E" [ label="ca5af2",shape="box",style="filled",color="grey" ]; +"45" [ label="23c1ec53358d237c1",shape="hexagon",style="filled",color="green" ]; +"275E" [ label="cab04b7c14a",shape="box",style="filled",color="grey" ]; +"46" [ label="5838586c293d455",shape="hexagon",style="filled",color="green" ]; +"277E" [ label="83c397b8bf7f",shape="box",style="filled",color="grey" ]; +"47" [ label="f841118350a27b7ea29a9c9d",shape="hexagon",style="filled",color="green" ]; +"279E" [ label="69f4ecb77d",shape="box",style="filled",color="grey" ]; +"48" [ label="658d208447d8ec5d6de8",shape="hexagon",style="filled",color="green" ]; +"281E" [ label="f7b22b9640",shape="box",style="filled",color="grey" ]; +"49" [ label="11180ae7706510211bc4",shape="hexagon",style="filled",color="green" ]; +"283E" [ label="052bb6e3",shape="box",style="filled",color="grey" ]; +"50" [ label="5807acd8d58e006f43",shape="hexagon",style="filled",color="green" ]; +"285E" [ label="",shape="box",style="filled",color="grey" ]; +"51" [ label="fe4e848cb5291ee59a2",shape="hexagon",style="filled",color="green" ]; +"287E" [ label="e3aefac763",shape="box",style="filled",color="grey" ]; +"52" [ label="c4f31ea3844e12da27ad47c6",shape="hexagon",style="filled",color="green" ]; +"289E" [ label="fb16636aae",shape="box",style="filled",color="grey" ]; +"53" [ label="00cbeb87c182ca0785f",shape="hexagon",style="filled",color="green" ]; +"291E" [ label="3089106e3b",shape="box",style="filled",color="grey" ]; +"54" [ label="11f088bfd8",shape="hexagon",style="filled",color="green" ]; +"293E" [ label="6a80cbe",shape="box",style="filled",color="grey" ]; +"55" [ label="64a9ec24428099ad8ed82ba6",shape="hexagon",style="filled",color="green" ]; +"745E" [ label="68d8993e61d8c82cd29e8d0182b0",shape="box",style="filled",color="grey" ]; +"56" [ label="3c2a62e0e5e9f7",shape="hexagon",style="filled",color="green" ]; +"295E" [ label="ae32701",shape="box",style="filled",color="grey" ]; +"57" [ label="dd84fe6a65cfac7bca03ebd",shape="hexagon",style="filled",color="green" ]; +"297E" [ label="",shape="box",style="filled",color="grey" ]; +"58" [ label="b06bbfa920aa95dd",shape="hexagon",style="filled",color="green" ]; +"299E" [ label="07",shape="box",style="filled",color="grey" ]; +"59" [ label="6b5aaa4bdf44b2c898854",shape="hexagon",style="filled",color="green" ]; +"301E" [ label="4c6c8c",shape="box",style="filled",color="grey" ]; +"789E" [ label="3a0ff0",shape="box",style="filled",color="grey" ]; +"60" [ label="855d26296eda4eb7",shape="hexagon",style="filled",color="green" ]; +"303E" [ label="53069e384a2",shape="box",style="filled",color="grey" ]; +"61" [ label="e82f47b8d4949ba4af69b38cbc19",shape="hexagon",style="filled",color="green" ]; +"305E" [ label="b62cd1d0a0",shape="box",style="filled",color="grey" ]; +"62" [ label="86569bffb49adf6b3d0ebac",shape="hexagon",style="filled",color="green" ]; +"307E" [ label="660ffeb76fc59",shape="box",style="filled",color="grey" ]; +"63" [ label="a96e47ff37983425a3e452095",shape="hexagon",style="filled",color="green" ]; +"309E" [ label="cab04b7c14a",shape="box",style="filled",color="grey" ]; +"64" [ label="71a48d11b2e7e56b1df128bd",shape="hexagon",style="filled",color="green" ]; +"311E" [ label="be8f4199f",shape="box",style="filled",color="grey" ]; +"65" [ label="a0befe6dd1ca7b165786835",shape="hexagon",style="filled",color="green" ]; +"313E" [ label="3cfae",shape="box",style="filled",color="grey" ]; +"66" [ label="f33ec11db496f7bfcb024f",shape="hexagon",style="filled",color="green" ]; +"315E" [ label="71e6b",shape="box",style="filled",color="grey" ]; +"67" [ label="fe6be3206549f5b5564acde84783",shape="hexagon",style="filled",color="green" ]; +"317E" [ label="",shape="box",style="filled",color="grey" ]; +"68" [ label="e4dba079d5fcb1f165920a3bf",shape="hexagon",style="filled",color="green" ]; +"319E" [ label="",shape="box",style="filled",color="grey" ]; +"69" [ label="35dfbee3123dc389cba0b15",shape="hexagon",style="filled",color="green" ]; +"746E" [ label="4c865eec228e41e7f4e5fc68a9a6",shape="box",style="filled",color="grey" ]; +"70" [ label="16c508ab98483d430bbe",shape="hexagon",style="filled",color="green" ]; +"321E" [ label="cab04b7c14a",shape="box",style="filled",color="grey" ]; +"71" [ label="9c9e2e0f2da8758e436c",shape="hexagon",style="filled",color="green" ]; +"327E" [ label="cd0d985a366cad7e",shape="box",style="filled",color="grey" ]; +"72" [ label="fb039d7a2a9fe73b5f468eba9",shape="hexagon",style="filled",color="green" ]; +"329E" [ label="81dabfaba8",shape="box",style="filled",color="grey" ]; +"73" [ label="2ef949c4a39b",shape="hexagon",style="filled",color="green" ]; +"331E" [ label="617809d979f",shape="box",style="filled",color="grey" ]; +"74" [ label="a9497e0757b0969bde707ed5",shape="hexagon",style="filled",color="green" ]; +"333E" [ label="541ab86a2e",shape="box",style="filled",color="grey" ]; +"75" [ label="230cc6bbc66b24eae94fa03d",shape="hexagon",style="filled",color="green" ]; +"335E" [ label="",shape="box",style="filled",color="grey" ]; +"76" [ label="1d163eac141def176461c",shape="hexagon",style="filled",color="green" ]; +"337E" [ label="0acc5bb8ca4",shape="box",style="filled",color="grey" ]; +"77" [ label="32979f8cf86",shape="hexagon",style="filled",color="green" ]; +"339E" [ label="a7e89580",shape="box",style="filled",color="grey" ]; +"78" [ label="37d80ae421dba4a70730338860",shape="hexagon",style="filled",color="green" ]; +"341E" [ label="",shape="box",style="filled",color="grey" ]; +"79" [ label="fbba7215e7c13173a60206",shape="hexagon",style="filled",color="green" ]; +"343E" [ label="617809d979f",shape="box",style="filled",color="grey" ]; +"80" [ label="2dd8cc4d693415f93c0f8fc",shape="hexagon",style="filled",color="green" ]; +"345E" [ label="94da691e20e3",shape="box",style="filled",color="grey" ]; +"81" [ label="00880e6f50c765ebc1f85d3e9",shape="hexagon",style="filled",color="green" ]; +"347E" [ label="e7ef998",shape="box",style="filled",color="grey" ]; +"82" [ label="ef13d45b1277ac9a0444adb",shape="hexagon",style="filled",color="green" ]; +"349E" [ label="a7fe7",shape="box",style="filled",color="grey" ]; +"83" [ label="2573e1bf51f1b307f4640",shape="hexagon",style="filled",color="green" ]; +"351E" [ label="84e4ede82074",shape="box",style="filled",color="grey" ]; +"84" [ label="162d8039483d8",shape="hexagon",style="filled",color="green" ]; +"353E" [ label="a8e9",shape="box",style="filled",color="grey" ]; +"85" [ label="f490de272a7f6e4af346d40",shape="hexagon",style="filled",color="green" ]; +"355E" [ label="460aed10cc9",shape="box",style="filled",color="grey" ]; +"788E" [ label="391256c872",shape="box",style="filled",color="grey" ]; +"86" [ label="678bf739c344b9ad41da1",shape="hexagon",style="filled",color="green" ]; +"357E" [ label="396b16a892fe",shape="box",style="filled",color="grey" ]; +"87" [ label="876d120b38b0e88817",shape="hexagon",style="filled",color="green" ]; +"359E" [ label="e5",shape="box",style="filled",color="grey" ]; +"88" [ label="503737b64d432c60d6ac557e0e6",shape="hexagon",style="filled",color="green" ]; +"361E" [ label="9937ccba1469",shape="box",style="filled",color="grey" ]; +"89" [ label="b36e0be6f67fc25286127456",shape="hexagon",style="filled",color="green" ]; +"363E" [ label="87a7e69a72412",shape="box",style="filled",color="grey" ]; +"90" [ label="4cc20a0b7651e486",shape="hexagon",style="filled",color="green" ]; +"365E" [ label="e079d2c",shape="box",style="filled",color="grey" ]; +"91" [ label="08dade990b2282",shape="hexagon",style="filled",color="green" ]; +"367E" [ label="45827dbdd8",shape="box",style="filled",color="grey" ]; +"92" [ label="f8128d574c356631b8a9",shape="hexagon",style="filled",color="green" ]; +"369E" [ label="",shape="box",style="filled",color="grey" ]; +"93" [ label="88a4f0337c2189c3fc7b31",shape="hexagon",style="filled",color="green" ]; +"729E" [ label="da0d7bbcf30",shape="box",style="filled",color="grey" ]; +"94" [ label="1b13908a9f0763c0ae54af9062080",shape="hexagon",style="filled",color="green" ]; +"371E" [ label="8b06a67a",shape="box",style="filled",color="grey" ]; +"95" [ label="e2a5d11499b7e",shape="hexagon",style="filled",color="green" ]; +"373E" [ label="66abc181ac4",shape="box",style="filled",color="grey" ]; +"96" [ label="90cc275011c2013c61eb11",shape="hexagon",style="filled",color="green" ]; +"375E" [ label="",shape="box",style="filled",color="grey" ]; +"97" [ label="1e003bfe8fc840df0163f4c",shape="hexagon",style="filled",color="green" ]; +"747E" [ label="8983ffbc30deb364dd92c3ad85c9",shape="box",style="filled",color="grey" ]; +"98" [ label="1927c743a0d440a5a0",shape="hexagon",style="filled",color="green" ]; +"377E" [ label="b12441ecff15fa12c",shape="box",style="filled",color="grey" ]; +"99" [ label="155d892827c33ed3cae3",shape="hexagon",style="filled",color="green" ]; +"379E" [ label="71e6b",shape="box",style="filled",color="grey" ]; +"100" [ label="9f24ba80192c339a64c0",shape="hexagon",style="filled",color="green" ]; +"381E" [ label="",shape="box",style="filled",color="grey" ]; +"101" [ label="3e814305b42beb41b8c706",shape="hexagon",style="filled",color="green" ]; +"383E" [ label="1c08373",shape="box",style="filled",color="grey" ]; +"102" [ label="eccfe5ff0af70fe9fbec8b2360f90",shape="hexagon",style="filled",color="green" ]; +"385E" [ label="be8f4199f",shape="box",style="filled",color="grey" ]; +"103" [ label="8fa622d9f842c5572a545ed72982",shape="hexagon",style="filled",color="green" ]; +"387E" [ label="4dccb",shape="box",style="filled",color="grey" ]; +"104" [ label="ad9142a65f5eab78b4ca5e",shape="hexagon",style="filled",color="green" ]; +"389E" [ label="f36cce089",shape="box",style="filled",color="grey" ]; +"105" [ label="20f234fdcd0e1fc50261ce8",shape="hexagon",style="filled",color="green" ]; +"391E" [ label="67219ef689f0146b544",shape="box",style="filled",color="grey" ]; +"106" [ label="e06cc38155ff6781cf944d745",shape="hexagon",style="filled",color="green" ]; +"393E" [ label="87a7e69a72412",shape="box",style="filled",color="grey" ]; +"107" [ label="cfdf1932665dcb4cd3c",shape="hexagon",style="filled",color="green" ]; +"395E" [ label="964b86fc1bba0e",shape="box",style="filled",color="grey" ]; +"108" [ label="6d4a4a5a5af91b895272c30",shape="hexagon",style="filled",color="green" ]; +"397E" [ label="b5e86c73d1198f",shape="box",style="filled",color="grey" ]; +"109" [ label="e0ad365c2fb444358201",shape="hexagon",style="filled",color="green" ]; +"399E" [ label="bb5e89c8963",shape="box",style="filled",color="grey" ]; +"110" [ label="b07bbdc8cca5985d4c4",shape="hexagon",style="filled",color="green" ]; +"401E" [ label="50023f6f88",shape="box",style="filled",color="grey" ]; +"111" [ label="df5dba74c75b228de48c",shape="hexagon",style="filled",color="green" ]; +"403E" [ label="7e493ee44b28",shape="box",style="filled",color="grey" ]; +"112" [ label="0b8694c9ef9b27b9c3d8",shape="hexagon",style="filled",color="green" ]; +"405E" [ label="2342b759c03",shape="box",style="filled",color="grey" ]; +"113" [ label="81e20155999fa64e0ae6fd",shape="hexagon",style="filled",color="green" ]; +"407E" [ label="4280833ef80172",shape="box",style="filled",color="grey" ]; +"114" [ label="3ef07ae75d29a707",shape="hexagon",style="filled",color="green" ]; +"409E" [ label="4280833ef80172",shape="box",style="filled",color="grey" ]; +"115" [ label="4a36db80f1ab1e97",shape="hexagon",style="filled",color="green" ]; +"411E" [ label="460aed10cc9",shape="box",style="filled",color="grey" ]; +"116" [ label="16da5f1301b36df4df0f",shape="hexagon",style="filled",color="green" ]; +"413E" [ label="460aed10cc9",shape="box",style="filled",color="grey" ]; +"117" [ label="6b3f3fa236bb90592d23a",shape="hexagon",style="filled",color="green" ]; +"415E" [ label="83c397b8bf7f",shape="box",style="filled",color="grey" ]; +"118" [ label="f2a57e4d4f0cec516891e3",shape="hexagon",style="filled",color="green" ]; +"417E" [ label="bd2484",shape="box",style="filled",color="grey" ]; +"119" [ label="deb3089920548bf1ecb23f0d",shape="hexagon",style="filled",color="green" ]; +"419E" [ label="87a7e69a72412",shape="box",style="filled",color="grey" ]; +"120" [ label="bf01c8a262",shape="hexagon",style="filled",color="green" ]; +"421E" [ label="01",shape="box",style="filled",color="grey" ]; +"121" [ label="23dc3a52fed9c119610b5e8",shape="hexagon",style="filled",color="green" ]; +"423E" [ label="71e6b",shape="box",style="filled",color="grey" ]; +"122" [ label="aff7fc220edc93572bb2",shape="hexagon",style="filled",color="green" ]; +"748E" [ label="68d8993e61d8c82cd29e8d0182b0",shape="box",style="filled",color="grey" ]; +"123" [ label="78cc16f965adc5f712ea2372c6",shape="hexagon",style="filled",color="green" ]; +"425E" [ label="23ad1",shape="box",style="filled",color="grey" ]; +"124" [ label="5be631dff7b97697be7dc0a2f07f2",shape="hexagon",style="filled",color="green" ]; +"427E" [ label="",shape="box",style="filled",color="grey" ]; +"786E" [ label="421",shape="box",style="filled",color="grey" ]; +"125" [ label="48398d080dfcccced48da1980",shape="hexagon",style="filled",color="green" ]; +"431E" [ label="866808df",shape="box",style="filled",color="grey" ]; +"126" [ label="03716a2c341e5edaa31",shape="hexagon",style="filled",color="green" ]; +"433E" [ label="21407f8a6d7",shape="box",style="filled",color="grey" ]; +"127" [ label="ddfeabe456a9de5f5784",shape="hexagon",style="filled",color="green" ]; +"435E" [ label="aac615ae78",shape="box",style="filled",color="grey" ]; +"128" [ label="d550a7f392c787661aadd48",shape="hexagon",style="filled",color="green" ]; +"437E" [ label="e3aefac763",shape="box",style="filled",color="grey" ]; +"129" [ label="4c82921f4ad3f07066540",shape="hexagon",style="filled",color="green" ]; +"439E" [ label="a7fe7",shape="box",style="filled",color="grey" ]; +"130" [ label="0bc7f8f513e0e74b270",shape="hexagon",style="filled",color="green" ]; +"441E" [ label="a849f9d352e",shape="box",style="filled",color="grey" ]; +"131" [ label="3b1563a23eb9",shape="hexagon",style="filled",color="green" ]; +"443E" [ label="a8e9",shape="box",style="filled",color="grey" ]; +"132" [ label="be233fafa38d931d894",shape="hexagon",style="filled",color="green" ]; +"445E" [ label="a849f9d352e",shape="box",style="filled",color="grey" ]; +"133" [ label="f906dc5244ee6a371f8",shape="hexagon",style="filled",color="green" ]; +"749E" [ label="4c865eec228e41e7f4e5fc68a9a6",shape="box",style="filled",color="grey" ]; +"134" [ label="e7a887d88c2318beba51",shape="hexagon",style="filled",color="green" ]; +"447E" [ label="9d8988c0945d6",shape="box",style="filled",color="grey" ]; +"135" [ label="be6b73bd46a7a5183e8c91a",shape="hexagon",style="filled",color="green" ]; +"449E" [ label="ee91c97828",shape="box",style="filled",color="grey" ]; +"769E" [ label="444189d179b5db71fe",shape="box",style="filled",color="grey" ]; +"770E" [ label="1e1fbbe14ac24e0518",shape="box",style="filled",color="grey" ]; +"136" [ label="644f112bb0aa452ee7040a",shape="hexagon",style="filled",color="green" ]; +"451E" [ label="52f247fc3b",shape="box",style="filled",color="grey" ]; +"137" [ label="010957669f3770aac",shape="hexagon",style="filled",color="green" ]; +"453E" [ label="78",shape="box",style="filled",color="grey" ]; +"138" [ label="0a185946ee443342b07d8e1",shape="hexagon",style="filled",color="green" ]; +"455E" [ label="87a7e69a72412",shape="box",style="filled",color="grey" ]; +"139" [ label="f66fe4df3d189e69ce10c9c",shape="hexagon",style="filled",color="green" ]; +"457E" [ label="21407f8a6d7",shape="box",style="filled",color="grey" ]; +"140" [ label="247e407f45b353f8",shape="hexagon",style="filled",color="green" ]; +"459E" [ label="",shape="box",style="filled",color="grey" ]; +"141" [ label="84907547f36d0ff7",shape="hexagon",style="filled",color="green" ]; +"461E" [ label="e920b915087",shape="box",style="filled",color="grey" ]; +"142" [ label="805004328dad9d315d",shape="hexagon",style="filled",color="green" ]; +"463E" [ label="4280833ef80172",shape="box",style="filled",color="grey" ]; +"143" [ label="4f0cbd3fbf0cb1e8c",shape="hexagon",style="filled",color="green" ]; +"465E" [ label="403126",shape="box",style="filled",color="grey" ]; +"144" [ label="4869e993f2bb10f",shape="hexagon",style="filled",color="green" ]; +"467E" [ label="ff",shape="box",style="filled",color="grey" ]; +"145" [ label="665b76844ff78fc2cf66ca2",shape="hexagon",style="filled",color="green" ]; +"469E" [ label="af0268dddd",shape="box",style="filled",color="grey" ]; +"146" [ label="3f16509139c7dad5163b91799",shape="hexagon",style="filled",color="green" ]; +"471E" [ label="3089106e3b",shape="box",style="filled",color="grey" ]; +"147" [ label="01db23a60422ba93a68611cc0",shape="hexagon",style="filled",color="green" ]; +"473E" [ label="",shape="box",style="filled",color="grey" ]; +"148" [ label="46125fcc583c0f494a3a1d3",shape="hexagon",style="filled",color="green" ]; +"475E" [ label="db6c4213a717bc",shape="box",style="filled",color="grey" ]; +"149" [ label="731857fe189fb398e80a0594",shape="hexagon",style="filled",color="green" ]; +"477E" [ label="3089106e3b",shape="box",style="filled",color="grey" ]; +"150" [ label="6fb7a84e370ef70feac5cb",shape="hexagon",style="filled",color="green" ]; +"479E" [ label="396b16a892fe",shape="box",style="filled",color="grey" ]; +"151" [ label="e343cea291b79a2ed4e",shape="hexagon",style="filled",color="green" ]; +"481E" [ label="88d8b220746882d",shape="box",style="filled",color="grey" ]; +"152" [ label="5f2592b20f13356b7fc8b42",shape="hexagon",style="filled",color="green" ]; +"483E" [ label="",shape="box",style="filled",color="grey" ]; +"153" [ label="275a0407e33e9b8aa9cdd051",shape="hexagon",style="filled",color="green" ]; +"731E" [ label="",shape="box",style="filled",color="grey" ]; +"154" [ label="011d119375cf494ca2fa8d59",shape="hexagon",style="filled",color="green" ]; +"750E" [ label="8983ffbc30deb364dd92c3ad85c9",shape="box",style="filled",color="grey" ]; +"155" [ label="173fd00917644f0f1f3e3",shape="hexagon",style="filled",color="green" ]; +"485E" [ label="0acc5bb8ca4",shape="box",style="filled",color="grey" ]; +"156" [ label="c72df69b40156a3254",shape="hexagon",style="filled",color="green" ]; +"487E" [ label="fff03efcd",shape="box",style="filled",color="grey" ]; +"157" [ label="6c632ad9c42228bb337",shape="hexagon",style="filled",color="green" ]; +"489E" [ label="eb8",shape="box",style="filled",color="grey" ]; +"158" [ label="bbb13dc62adf2de2a42b6",shape="hexagon",style="filled",color="green" ]; +"491E" [ label="69ce90c9b2",shape="box",style="filled",color="grey" ]; +"159" [ label="6282bc21f6",shape="hexagon",style="filled",color="green" ]; +"495E" [ label="de34214b4c258c9333ec3",shape="box",style="filled",color="grey" ]; +"160" [ label="71cf45dd4e91bcca945137b40e",shape="hexagon",style="filled",color="green" ]; +"499E" [ label="65fd8495",shape="box",style="filled",color="grey" ]; +"161" [ label="a3b6df27179b175c88fa4c9cf9f",shape="hexagon",style="filled",color="green" ]; +"501E" [ label="6577",shape="box",style="filled",color="grey" ]; +"162" [ label="284f14a259991806654e74",shape="hexagon",style="filled",color="green" ]; +"503E" [ label="4280833ef80172",shape="box",style="filled",color="grey" ]; +"163" [ label="a7c99ccf6ddf6f5ebbe",shape="hexagon",style="filled",color="green" ]; +"505E" [ label="c4fd8",shape="box",style="filled",color="grey" ]; +"164" [ label="c32d2697e8",shape="hexagon",style="filled",color="green" ]; +"507E" [ label="52f247fc3b",shape="box",style="filled",color="grey" ]; +"165" [ label="d12bd75c24b110ef90cdd35d3",shape="hexagon",style="filled",color="green" ]; +"509E" [ label="0668",shape="box",style="filled",color="grey" ]; +"166" [ label="1c07453d584f3d14b1876fdb",shape="hexagon",style="filled",color="green" ]; +"511E" [ label="460aed10cc9",shape="box",style="filled",color="grey" ]; +"167" [ label="f713a8b311ffa05ce3683ad10",shape="hexagon",style="filled",color="green" ]; +"513E" [ label="30d6138b63eb",shape="box",style="filled",color="grey" ]; +"168" [ label="3cdc90c57243373efaba65a",shape="hexagon",style="filled",color="green" ]; +"515E" [ label="fa2afbd869",shape="box",style="filled",color="grey" ]; +"169" [ label="e3bdbca0e2256fffa8a59018",shape="hexagon",style="filled",color="green" ]; +"517E" [ label="81dabfaba8",shape="box",style="filled",color="grey" ]; +"170" [ label="75ba8d840070942eb4e737849",shape="hexagon",style="filled",color="green" ]; +"519E" [ label="81dabfaba8",shape="box",style="filled",color="grey" ]; +"171" [ label="fbdc3ca37406f66635c8b226e",shape="hexagon",style="filled",color="green" ]; +"521E" [ label="8cbcf5cb5",shape="box",style="filled",color="grey" ]; +"172" [ label="40b49a5a9bb256c7a3286e56",shape="hexagon",style="filled",color="green" ]; +"523E" [ label="f72564578be",shape="box",style="filled",color="grey" ]; +"173" [ label="3b2f08d52e4bca3f9ca7bbbd6",shape="hexagon",style="filled",color="green" ]; +"525E" [ label="81dabfaba8",shape="box",style="filled",color="grey" ]; +"174" [ label="4a38abc630c82b0c48dfbf5271",shape="hexagon",style="filled",color="green" ]; +"527E" [ label="f0bd1521",shape="box",style="filled",color="grey" ]; +"175" [ label="2d7b7fb6c9ad6821752651f7",shape="hexagon",style="filled",color="green" ]; +"529E" [ label="47b2da3d",shape="box",style="filled",color="grey" ]; +"176" [ label="910b00285f11bb90d0a15641",shape="hexagon",style="filled",color="green" ]; +"531E" [ label="81dabfaba8",shape="box",style="filled",color="grey" ]; +"177" [ label="24431c3eb075102f07cc2c1be",shape="hexagon",style="filled",color="green" ]; +"533E" [ label="",shape="box",style="filled",color="grey" ]; +"178" [ label="07f8a9e55a16beddb3c9153b0",shape="hexagon",style="filled",color="green" ]; +"535E" [ label="81dabfaba8",shape="box",style="filled",color="grey" ]; +"179" [ label="c1c30f30d40c4f1f84924622f",shape="hexagon",style="filled",color="green" ]; +"537E" [ label="c5d5be3942",shape="box",style="filled",color="grey" ]; +"180" [ label="86276bb1e23f2c7ffcbe82a0",shape="hexagon",style="filled",color="green" ]; +"539E" [ label="0f940646",shape="box",style="filled",color="grey" ]; +"181" [ label="f78e145a127014eb43345a0c",shape="hexagon",style="filled",color="green" ]; +"541E" [ label="d370c12dbc",shape="box",style="filled",color="grey" ]; +"182" [ label="a27037332d9fa5c43bcfe94c0",shape="hexagon",style="filled",color="green" ]; +"543E" [ label="80874aa8",shape="box",style="filled",color="grey" ]; +"183" [ label="c29ce10bb8d19b498355aa04",shape="hexagon",style="filled",color="green" ]; +"545E" [ label="1c08373",shape="box",style="filled",color="grey" ]; +"184" [ label="4f8c642b53c349c687534bda35db",shape="hexagon",style="filled",color="green" ]; +"547E" [ label="46969c4",shape="box",style="filled",color="grey" ]; +"185" [ label="30cc206b1878485",shape="hexagon",style="filled",color="green" ]; +"549E" [ label="23ad1",shape="box",style="filled",color="grey" ]; +"186" [ label="5d69639a5e3bdd3d",shape="hexagon",style="filled",color="green" ]; +"551E" [ label="6139fa6adc88d",shape="box",style="filled",color="grey" ]; +"187" [ label="b656f0ed2202b8e46eb",shape="hexagon",style="filled",color="green" ]; +"553E" [ label="f6e6236b48bc3",shape="box",style="filled",color="grey" ]; +"188" [ label="3b566eaa70ed401479d43a9",shape="hexagon",style="filled",color="green" ]; +"555E" [ label="4c6c8c",shape="box",style="filled",color="grey" ]; +"189" [ label="d6125ef42bd9958",shape="hexagon",style="filled",color="green" ]; +"557E" [ label="4c6c8c",shape="box",style="filled",color="grey" ]; +"190" [ label="dd12f26f8d9bb55",shape="hexagon",style="filled",color="green" ]; +"559E" [ label="83c397b8bf7f",shape="box",style="filled",color="grey" ]; +"191" [ label="ea890ccca2f7c2107351",shape="hexagon",style="filled",color="green" ]; +"561E" [ label="eb8",shape="box",style="filled",color="grey" ]; +"192" [ label="84e4f1c582427a98d7b",shape="hexagon",style="filled",color="green" ]; +"563E" [ label="eb8",shape="box",style="filled",color="grey" ]; +"193" [ label="d378760b814eaecb6efe636e0efc4",shape="hexagon",style="filled",color="green" ]; +"565E" [ label="81bcc35f82891",shape="box",style="filled",color="grey" ]; +"194" [ label="f722890f70a32dce3baff371a",shape="hexagon",style="filled",color="green" ]; +"567E" [ label="84e4ede82074",shape="box",style="filled",color="grey" ]; +"195" [ label="666f11bb45c3a8dcf26e1ed79",shape="hexagon",style="filled",color="green" ]; +"569E" [ label="c90f755c8b6612d",shape="box",style="filled",color="grey" ]; +"196" [ label="91ecbe29a71f00ed5a3",shape="hexagon",style="filled",color="green" ]; +"571E" [ label="0a963fef9",shape="box",style="filled",color="grey" ]; +"197" [ label="30c3f3bf8463d3843dc57d8e98",shape="hexagon",style="filled",color="green" ]; +"573E" [ label="3089106e3b",shape="box",style="filled",color="grey" ]; +"198" [ label="8ea965ab6ee8dedb6c3333e9",shape="hexagon",style="filled",color="green" ]; +"575E" [ label="84e4ede82074",shape="box",style="filled",color="grey" ]; +"199" [ label="3eecb304bab2136a76deda",shape="hexagon",style="filled",color="green" ]; +"577E" [ label="8df",shape="box",style="filled",color="grey" ]; +"200" [ label="d886e4b76537a99bc71b8a9331c94",shape="hexagon",style="filled",color="green" ]; +"579E" [ label="1172dca23",shape="box",style="filled",color="grey" ]; +"201" [ label="dcc5d5e9d6c4e",shape="hexagon",style="filled",color="green" ]; +"581E" [ label="a8e9",shape="box",style="filled",color="grey" ]; +"202" [ label="8292af691429f8d9ed481ff71ffd",shape="hexagon",style="filled",color="green" ]; +"583E" [ label="212af4",shape="box",style="filled",color="grey" ]; +"203" [ label="12fcb26b3de00ef98719c2ca",shape="hexagon",style="filled",color="green" ]; +"585E" [ label="",shape="box",style="filled",color="grey" ]; +"204" [ label="a141a557a60912051f3c135",shape="hexagon",style="filled",color="green" ]; +"587E" [ label="",shape="box",style="filled",color="grey" ]; +"205" [ label="64eeeddfc34489ff396",shape="hexagon",style="filled",color="green" ]; +"751E" [ label="8983ffbc30deb364dd92c3ad85c9",shape="box",style="filled",color="grey" ]; +"206" [ label="f5d636e14a6cd716362158d",shape="hexagon",style="filled",color="green" ]; +"589E" [ label="32c958c9997",shape="box",style="filled",color="grey" ]; +"207" [ label="84e4978afc069d5a1aecbf2b",shape="hexagon",style="filled",color="green" ]; +"593E" [ label="56caa96d171a9ac2da7c",shape="box",style="filled",color="grey" ]; +"208" [ label="52a6c2063bccd83110c32",shape="hexagon",style="filled",color="green" ]; +"597E" [ label="",shape="box",style="filled",color="grey" ]; +"209" [ label="46f754ea06f070dbc023e571a876",shape="hexagon",style="filled",color="green" ]; +"599E" [ label="ffccaa9e3",shape="box",style="filled",color="grey" ]; +"210" [ label="c10cb9baf4dcb43e24",shape="hexagon",style="filled",color="green" ]; +"601E" [ label="ac6e99186",shape="box",style="filled",color="grey" ]; +"211" [ label="3dafe1619016463f521f",shape="hexagon",style="filled",color="green" ]; +"603E" [ label="b9",shape="box",style="filled",color="grey" ]; +"212" [ label="0f5db6ce12751ddcc64e",shape="hexagon",style="filled",color="green" ]; +"605E" [ label="bb828f1a326",shape="box",style="filled",color="grey" ]; +"213" [ label="34c8c8dc0f6e41c7e7b2",shape="hexagon",style="filled",color="green" ]; +"607E" [ label="2832ed5cea6",shape="box",style="filled",color="grey" ]; +"214" [ label="0a49c95f107c0aa57c9b5748",shape="hexagon",style="filled",color="green" ]; +"609E" [ label="",shape="box",style="filled",color="grey" ]; +"215" [ label="3b4fdad8e0429d112",shape="hexagon",style="filled",color="green" ]; +"611E" [ label="cab04b7c14a",shape="box",style="filled",color="grey" ]; +"216" [ label="17dafa5ebaafd48440e3",shape="hexagon",style="filled",color="green" ]; +"613E" [ label="b5f038f79a3",shape="box",style="filled",color="grey" ]; +"217" [ label="f4c69e5e212f89348122e8",shape="hexagon",style="filled",color="green" ]; +"615E" [ label="396b16a892fe",shape="box",style="filled",color="grey" ]; +"218" [ label="4f2e020854dfacce46a12",shape="hexagon",style="filled",color="green" ]; +"617E" [ label="e079d2c",shape="box",style="filled",color="grey" ]; +"219" [ label="6448451ac2ceade90715378b",shape="hexagon",style="filled",color="green" ]; +"619E" [ label="",shape="box",style="filled",color="grey" ]; +"220" [ label="7d7b14baa649330",shape="hexagon",style="filled",color="green" ]; +"621E" [ label="77d145b32328880440c7a",shape="box",style="filled",color="grey" ]; +"221" [ label="d7c27cc6f7b02a31eb64d",shape="hexagon",style="filled",color="green" ]; +"623E" [ label="87a7e69a72412",shape="box",style="filled",color="grey" ]; +"222" [ label="8f5a69ece1",shape="hexagon",style="filled",color="green" ]; +"752E" [ label="eb9cf6456613d4cd06f7c0894bd6",shape="box",style="filled",color="grey" ]; +"223" [ label="eccf7c722ddf",shape="hexagon",style="filled",color="green" ]; +"625E" [ label="df61d5f5fc",shape="box",style="filled",color="grey" ]; +"224" [ label="86633c26be93ada8b",shape="hexagon",style="filled",color="green" ]; +"627E" [ label="08500a6044",shape="box",style="filled",color="grey" ]; +"225" [ label="3f9ddf1ffbc0d38b",shape="hexagon",style="filled",color="green" ]; +"629E" [ label="07",shape="box",style="filled",color="grey" ]; +"226" [ label="e33792703",shape="hexagon",style="filled",color="green" ]; +"631E" [ label="6a8f5bafb1",shape="box",style="filled",color="grey" ]; +"227" [ label="293a225dc56dd1e0564e6bb",shape="hexagon",style="filled",color="green" ]; +"633E" [ label="e3aefac763",shape="box",style="filled",color="grey" ]; +"228" [ label="57c77c341f94afddef07e6",shape="hexagon",style="filled",color="green" ]; +"635E" [ label="5e80f85274",shape="box",style="filled",color="grey" ]; +"229" [ label="3bbfc7bfdbbb1ba1bfad7517",shape="hexagon",style="filled",color="green" ]; +"637E" [ label="",shape="box",style="filled",color="grey" ]; +"230" [ label="a7167d5eb5408b3839903",shape="hexagon",style="filled",color="green" ]; +"639E" [ label="8c8b5bde6",shape="box",style="filled",color="grey" ]; +"231" [ label="34d7bb6af4fcd8d630de72500c8",shape="hexagon",style="filled",color="green" ]; +"641E" [ label="32fe7eee5283",shape="box",style="filled",color="grey" ]; +"232" [ label="8e69341faa4489",shape="hexagon",style="filled",color="green" ]; +"643E" [ label="cab04b7c14a",shape="box",style="filled",color="grey" ]; +"233" [ label="459236f07c73814faf5",shape="hexagon",style="filled",color="green" ]; +"645E" [ label="18083a711d",shape="box",style="filled",color="grey" ]; +"234" [ label="c71aa521578164debd0c5",shape="hexagon",style="filled",color="green" ]; +"647E" [ label="78",shape="box",style="filled",color="grey" ]; +"235" [ label="a5520019b8a73bc141b5fd416a",shape="hexagon",style="filled",color="green" ]; +"649E" [ label="3219b6b71443",shape="box",style="filled",color="grey" ]; +"236" [ label="6c89dc59ee7aaebbbd6bb64",shape="hexagon",style="filled",color="green" ]; +"651E" [ label="8c8b5bde6",shape="box",style="filled",color="grey" ]; +"237" [ label="a9a36ef02f",shape="hexagon",style="filled",color="green" ]; +"653E" [ label="6a80cbe",shape="box",style="filled",color="grey" ]; +"238" [ label="3db761b596844f133c",shape="hexagon",style="filled",color="green" ]; +"655E" [ label="e920b915087",shape="box",style="filled",color="grey" ]; +"239" [ label="383db224d7508ef072bea21d0",shape="hexagon",style="filled",color="green" ]; +"657E" [ label="975fedfb64df",shape="box",style="filled",color="grey" ]; +"240" [ label="8e307415fb435445ced7",shape="hexagon",style="filled",color="green" ]; +"659E" [ label="21dff35936370ae5f",shape="box",style="filled",color="grey" ]; +"241" [ label="aff6d7896e0e142bbc3e78",shape="hexagon",style="filled",color="green" ]; +"661E" [ label="d2498",shape="box",style="filled",color="grey" ]; +"242" [ label="e153c6e676c7369b285b4e9033a",shape="hexagon",style="filled",color="green" ]; +"663E" [ label="",shape="box",style="filled",color="grey" ]; +"243" [ label="f3c4311de0e931f08c232b",shape="hexagon",style="filled",color="green" ]; +"665E" [ label="a849f9d352e",shape="box",style="filled",color="grey" ]; +"244" [ label="0c72a426929600000f5",shape="hexagon",style="filled",color="green" ]; +"667E" [ label="45827dbdd8",shape="box",style="filled",color="grey" ]; +"245" [ label="38fa61352f5086d2cb51",shape="hexagon",style="filled",color="green" ]; +"669E" [ label="af0268dddd",shape="box",style="filled",color="grey" ]; +"246" [ label="ad1dd724f1c3e",shape="hexagon",style="filled",color="green" ]; +"671E" [ label="cab04b7c14a",shape="box",style="filled",color="grey" ]; +"247" [ label="11bb8ed3ae227d3acefc",shape="hexagon",style="filled",color="green" ]; +"673E" [ label="eb8",shape="box",style="filled",color="grey" ]; +"248" [ label="f2c7b3bb4d44f977d0ab8a42351",shape="hexagon",style="filled",color="green" ]; +"675E" [ label="",shape="box",style="filled",color="grey" ]; +"249" [ label="51e045ca826077ae765",shape="hexagon",style="filled",color="green" ]; +"679E" [ label="e842",shape="box",style="filled",color="grey" ]; +"250" [ label="aa0adc8978020629574",shape="hexagon",style="filled",color="green" ]; +"753E" [ label="68d8993e61d8c82cd29e8d0182b0",shape="box",style="filled",color="grey" ]; +"251" [ label="3b6b2c549de670d7bf5fc0ee",shape="hexagon",style="filled",color="green" ]; +"681E" [ label="",shape="box",style="filled",color="grey" ]; +"252" [ label="5eea496cc301b2a9721",shape="hexagon",style="filled",color="green" ]; +"683E" [ label="",shape="box",style="filled",color="grey" ]; +"253" [ label="bfc6564cbdeeffac00a141",shape="hexagon",style="filled",color="green" ]; +"685E" [ label="3b0a8a1c2e5050bd",shape="box",style="filled",color="grey" ]; +"254" [ label="c360aaeb167487c9578a8f",shape="hexagon",style="filled",color="green" ]; +"687E" [ label="d",shape="box",style="filled",color="grey" ]; +"255" [ label="39d025b265f9790490781cb201",shape="hexagon",style="filled",color="green" ]; +"689E" [ label="5e80f85274",shape="box",style="filled",color="grey" ]; +"256" [ label="b4ce21e0a3df1d097277d6",shape="hexagon",style="filled",color="green" ]; +"691E" [ label="a849f9d352e",shape="box",style="filled",color="grey" ]; +"257" [ label="8bdb6a91c6dee925b557c705b3",shape="hexagon",style="filled",color="green" ]; +"693E" [ label="53069e384a2",shape="box",style="filled",color="grey" ]; +"258" [ label="ac487676a04e4",shape="hexagon",style="filled",color="green" ]; +"695E" [ label="a8e9",shape="box",style="filled",color="grey" ]; +"259" [ label="18115fa32ff1cb99",shape="hexagon",style="filled",color="green" ]; +"697E" [ label="45827dbdd8",shape="box",style="filled",color="grey" ]; +"260" [ label="b7b899dc8bc6a32b28cb098fa16",shape="hexagon",style="filled",color="green" ]; +"699E" [ label="32fe7eee5283",shape="box",style="filled",color="grey" ]; +"261" [ label="b69e426d974e1907e88",shape="hexagon",style="filled",color="green" ]; +"703E" [ label="e842",shape="box",style="filled",color="grey" ]; +"262" [ label="60d0128bdb61ae40e98638bd1391",shape="hexagon",style="filled",color="green" ]; +"705E" [ label="23ad1",shape="box",style="filled",color="grey" ]; +"264" [ label="8fb60d769e4c387",shape="hexagon",style="filled",color="green" ]; +"709E" [ label="6a8f5bafb1",shape="box",style="filled",color="grey" ]; +"265" [ label="e1fa7f549e5a0893bb42da5",shape="hexagon",style="filled",color="green" ]; +"711E" [ label="6a3c6921b0aeceda3",shape="box",style="filled",color="grey" ]; +"266" [ label="a77622f2ff77ffeeb2",shape="hexagon",style="filled",color="green" ]; +"713E" [ label="21dff35936370ae5f",shape="box",style="filled",color="grey" ]; +"267" [ label="30d9d350943c0e3ff7594b50",shape="hexagon",style="filled",color="green" ]; +"715E" [ label="b5e86c73d1198f",shape="box",style="filled",color="grey" ]; +"268" [ label="89ced1a7906d58d687d5a04",shape="hexagon",style="filled",color="green" ]; +"717E" [ label="c0174bbe7ae8",shape="box",style="filled",color="grey" ]; +"269" [ label="1de26f6b12b0d292f94184",shape="hexagon",style="filled",color="green" ]; +"719E" [ label="65fd8495",shape="box",style="filled",color="grey" ]; +"270" [ label="26fa7360ab81be9d4434a",shape="hexagon",style="filled",color="green" ]; +"721E" [ label="af0268dddd",shape="box",style="filled",color="grey" ]; +"272" [ label="4a9d79c960b8d33e39251e5f66",shape="hexagon" ]; +"34E" [ label="330342f283ef2",shape="box",style="filled",color="grey" ]; +"252E" [ label="3dafb9a29c00",shape="box",style="filled",color="grey" ]; +"436E" [ label="8d5137b16a",shape="box",style="filled",color="grey" ]; +"274" [ label="10a7d61c201c67a5e78542807cd",shape="hexagon" ]; +"59E" [ label="ef6361295eba07",shape="box",style="filled",color="grey" ]; +"500E" [ label="a8f0fe2eb7bc1471",shape="box",style="filled",color="grey" ]; +"720E" [ label="cfff3acd8e9d",shape="box",style="filled",color="grey" ]; +"275" [ label="f8ff39eab120851f143bf19",shape="hexagon" ]; +"98E" [ label="4e3cfd27a",shape="box",style="filled",color="grey" ]; +"278" [ label="4995c71223c9f6067324d387a2",shape="hexagon" ]; +"35E" [ label="57948adb5dead",shape="box",style="filled",color="grey" ]; +"488E" [ label="a738ba39",shape="box",style="filled",color="grey" ]; +"598E" [ label="be7d637c50c",shape="box",style="filled",color="grey" ]; +"604E" [ label="8d52f183ec",shape="box",style="filled",color="grey" ]; +"628E" [ label="cef12b6",shape="box",style="filled",color="grey" ]; +"279" [ label="b9ae94e6935503603341ecf4",shape="hexagon" ]; +"99E" [ label="14a3c17f3d",shape="box",style="filled",color="grey" ]; +"280" [ label="fd28c194a46fde909b019c52f",shape="hexagon" ]; +"242E" [ label="9fe65061641",shape="box",style="filled",color="grey" ]; +"270E" [ label="34d06d1ed6",shape="box",style="filled",color="grey" ]; +"272E" [ label="713db1c1",shape="box",style="filled",color="grey" ]; +"284E" [ label="90dccb18c0",shape="box",style="filled",color="grey" ]; +"286E" [ label="e17fea65",shape="box",style="filled",color="grey" ]; +"288E" [ label="aebb7b91b",shape="box",style="filled",color="grey" ]; +"586E" [ label="4348f3abcb7716",shape="box",style="filled",color="grey" ]; +"763E" [ label="b082f7a5ff",shape="box",style="filled",color="grey" ]; +"281" [ label="7c0ab977f5a3c4ab6d625f5033",shape="hexagon" ]; +"45E" [ label="20949455f573f",shape="box",style="filled",color="grey" ]; +"470E" [ label="c338481d79773",shape="box",style="filled",color="grey" ]; +"670E" [ label="e1d01ef89f",shape="box",style="filled",color="grey" ]; +"722E" [ label="c4507c22d19",shape="box",style="filled",color="grey" ]; +"282" [ label="7e0b91491c8c8566892cd9a0889",shape="hexagon" ]; +"103E" [ label="de9efa12873949",shape="box",style="filled",color="grey" ]; +"283" [ label="d58478d9c273ad4f4b2e091324",shape="hexagon" ]; +"165E" [ label="1a220eb692c",shape="box",style="filled",color="grey" ]; +"284" [ label="8be0efdd94a6383e87fbfded4f",shape="hexagon" ]; +"39E" [ label="c8a6c26d4fd9f",shape="box",style="filled",color="grey" ]; +"224E" [ label="8cbae42a3900",shape="box",style="filled",color="grey" ]; +"268E" [ label="fc73",shape="box",style="filled",color="grey" ]; +"632E" [ label="",shape="box",style="filled",color="grey" ]; +"710E" [ label="102f1",shape="box",style="filled",color="grey" ]; +"285" [ label="3aeb78ea51020a44f2d2615436dae",shape="hexagon" ]; +"53E" [ label="96deede0c6b44119",shape="box",style="filled",color="grey" ]; +"286" [ label="6bbd5b422edb8e358dcc20eecf9",shape="hexagon" ]; +"38E" [ label="4f2de229621272",shape="box",style="filled",color="grey" ]; +"166E" [ label="d495de0b35f6",shape="box",style="filled",color="grey" ]; +"288" [ label="4856000a6802ddfc121ef40432297",shape="hexagon",style="filled",color="#ff0000" ]; +"40E" [ label="04904a458422a5b9",shape="box",style="filled",color="grey" ]; +"218E" [ label="8cd4d",shape="box",style="filled",color="grey" ]; +"244E" [ label="",shape="box",style="filled",color="grey" ]; +"246E" [ label="9be88247",shape="box",style="filled",color="grey" ]; +"258E" [ label="4f05b",shape="box",style="filled",color="grey" ]; +"290E" [ label="8b092",shape="box",style="filled",color="grey" ]; +"292E" [ label="c3bbf4",shape="box",style="filled",color="grey" ]; +"308E" [ label="6331b3f",shape="box",style="filled",color="grey" ]; +"318E" [ label="",shape="box",style="filled",color="grey" ]; +"388E" [ label="3711",shape="box",style="filled",color="grey" ]; +"472E" [ label="c5255d",shape="box",style="filled",color="grey" ]; +"478E" [ label="5c6a2",shape="box",style="filled",color="grey" ]; +"566E" [ label="51ec95518d1b3",shape="box",style="filled",color="grey" ]; +"570E" [ label="82a65ed4b69",shape="box",style="filled",color="grey" ]; +"574E" [ label="05fed5e",shape="box",style="filled",color="grey" ]; +"608E" [ label="bf",shape="box",style="filled",color="grey" ]; +"614E" [ label="ce",shape="box",style="filled",color="grey" ]; +"658E" [ label="1a830d9f",shape="box",style="filled",color="grey" ]; +"664E" [ label="",shape="box",style="filled",color="grey" ]; +"682E" [ label="",shape="box",style="filled",color="grey" ]; +"289" [ label="2e31175cbd52fcd08360fe86d20",shape="hexagon" ]; +"41E" [ label="4ad5d68f07981a",shape="box",style="filled",color="grey" ]; +"636E" [ label="51192117f9b4",shape="box",style="filled",color="grey" ]; +"642E" [ label="6bf214d9e7fa5f2df",shape="box",style="filled",color="grey" ]; +"690E" [ label="558d8534f92fddfe",shape="box",style="filled",color="grey" ]; +"700E" [ label="6819fd5a6cdd280dd",shape="box",style="filled",color="grey" ]; +"290" [ label="3aa0ce5efcf79bc3ecced1886e89",shape="hexagon" ]; +"56E" [ label="ff9d64ddf49a20f",shape="box",style="filled",color="grey" ]; +"264E" [ label="6c93f24516f01d",shape="box",style="filled",color="grey" ]; +"510E" [ label="32b98f11f3d01d6",shape="box",style="filled",color="grey" ]; +"718E" [ label="8f7c875500073",shape="box",style="filled",color="grey" ]; +"291" [ label="7c1767485953d9c2",shape="hexagon" ]; +"66E" [ label="086",shape="box",style="filled",color="grey" ]; +"76E" [ label="",shape="box",style="filled",color="grey" ]; +"610E" [ label="450d3a2d49cbfd",shape="box",style="filled",color="grey" ]; +"292" [ label="9c1305d59c37e9be9f13d7d049c",shape="hexagon" ]; +"73E" [ label="817",shape="box",style="filled",color="grey" ]; +"293" [ label="efe092824916a5637ee35d439589",shape="hexagon" ]; +"49E" [ label="",shape="box",style="filled",color="grey" ]; +"214E" [ label="",shape="box",style="filled",color="grey" ]; +"216E" [ label="",shape="box",style="filled",color="grey" ]; +"236E" [ label="",shape="box",style="filled",color="grey" ]; +"278E" [ label="",shape="box",style="filled",color="grey" ]; +"358E" [ label="",shape="box",style="filled",color="grey" ]; +"398E" [ label="",shape="box",style="filled",color="grey" ]; +"400E" [ label="",shape="box",style="filled",color="grey" ]; +"402E" [ label="",shape="box",style="filled",color="grey" ]; +"404E" [ label="",shape="box",style="filled",color="grey" ]; +"406E" [ label="",shape="box",style="filled",color="grey" ]; +"408E" [ label="",shape="box",style="filled",color="grey" ]; +"412E" [ label="",shape="box",style="filled",color="grey" ]; +"438E" [ label="",shape="box",style="filled",color="grey" ]; +"448E" [ label="",shape="box",style="filled",color="grey" ]; +"476E" [ label="",shape="box",style="filled",color="grey" ]; +"504E" [ label="",shape="box",style="filled",color="grey" ]; +"552E" [ label="",shape="box",style="filled",color="grey" ]; +"634E" [ label="",shape="box",style="filled",color="grey" ]; +"768E" [ label="",shape="box",style="filled",color="grey" ]; +"295" [ label="70815f0352b43dc1562133ab6eb",shape="hexagon",style="filled",color="#A52A2A" ]; +"44E" [ label="ef2d4636934472",shape="box",style="filled",color="grey" ]; +"92E" [ label="22bd92e302816",shape="box",style="filled",color="grey" ]; +"250E" [ label="74e86",shape="box",style="filled",color="grey" ]; +"316E" [ label="",shape="box",style="filled",color="grey" ]; +"380E" [ label="",shape="box",style="filled",color="grey" ]; +"424E" [ label="c",shape="box",style="filled",color="grey" ]; +"442E" [ label="a5a",shape="box",style="filled",color="grey" ]; +"446E" [ label="bce",shape="box",style="filled",color="grey" ]; +"454E" [ label="",shape="box",style="filled",color="grey" ]; +"460E" [ label="",shape="box",style="filled",color="grey" ]; +"462E" [ label="",shape="box",style="filled",color="grey" ]; +"648E" [ label="",shape="box",style="filled",color="grey" ]; +"656E" [ label="e9",shape="box",style="filled",color="grey" ]; +"666E" [ label="b701e7",shape="box",style="filled",color="grey" ]; +"692E" [ label="f2e7cc",shape="box",style="filled",color="grey" ]; +"712E" [ label="8a9eb2806b0aa",shape="box",style="filled",color="grey" ]; +"296" [ label="e287d497450664a4c0f4efc338",shape="hexagon",style="filled",color="#ff0000" ]; +"47E" [ label="06eff1db45cdf",shape="box",style="filled",color="grey" ]; +"330E" [ label="c0f34a600",shape="box",style="filled",color="grey" ]; +"514E" [ label="bd7aca295ca",shape="box",style="filled",color="grey" ]; +"516E" [ label="0da9135",shape="box",style="filled",color="grey" ]; +"518E" [ label="fe821bce",shape="box",style="filled",color="grey" ]; +"520E" [ label="e64f22a31",shape="box",style="filled",color="grey" ]; +"522E" [ label="46e412a3",shape="box",style="filled",color="grey" ]; +"526E" [ label="99da1f8a5",shape="box",style="filled",color="grey" ]; +"528E" [ label="0f167280",shape="box",style="filled",color="grey" ]; +"530E" [ label="82d201",shape="box",style="filled",color="grey" ]; +"532E" [ label="1d529eb4",shape="box",style="filled",color="grey" ]; +"534E" [ label="",shape="box",style="filled",color="grey" ]; +"536E" [ label="bf141dbce",shape="box",style="filled",color="grey" ]; +"538E" [ label="e3fd0c7b3",shape="box",style="filled",color="grey" ]; +"540E" [ label="c96cb3",shape="box",style="filled",color="grey" ]; +"542E" [ label="0fabab47",shape="box",style="filled",color="grey" ]; +"544E" [ label="1b82200",shape="box",style="filled",color="grey" ]; +"297" [ label="2ced414a91575a48f2dd29a",shape="hexagon" ]; +"46E" [ label="85221d5e9e",shape="box",style="filled",color="grey" ]; +"93E" [ label="97a7eea3f",shape="box",style="filled",color="grey" ]; +"206E" [ label="4d22e1",shape="box",style="filled",color="grey" ]; +"426E" [ label="e65185ca",shape="box",style="filled",color="grey" ]; +"550E" [ label="",shape="box",style="filled",color="grey" ]; +"706E" [ label="a9012b7bb5",shape="box",style="filled",color="grey" ]; +"298" [ label="38f162cf917ce7298663a1f1c607",shape="hexagon" ]; +"36E" [ label="a031c9192ae8e75",shape="box",style="filled",color="grey" ]; +"95E" [ label="062fc905b9eb35",shape="box",style="filled",color="grey" ]; +"364E" [ label="c8fc17180bea86",shape="box",style="filled",color="grey" ]; +"394E" [ label="09e64744536c5e1",shape="box",style="filled",color="grey" ]; +"420E" [ label="af4a1fac3e2076",shape="box",style="filled",color="grey" ]; +"456E" [ label="238805e2194c3",shape="box",style="filled",color="grey" ]; +"624E" [ label="73e6ed83012",shape="box",style="filled",color="grey" ]; +"299" [ label="549fa15d68f0b3bee6192f888cd8",shape="hexagon" ]; +"48E" [ label="d17f8f4eeb8e63d",shape="box",style="filled",color="grey" ]; +"168E" [ label="cca7040e47789",shape="box",style="filled",color="grey" ]; +"260E" [ label="47ebc3f17",shape="box",style="filled",color="grey" ]; +"282E" [ label="cf5a6049ad",shape="box",style="filled",color="grey" ]; +"554E" [ label="2a47a6a27",shape="box",style="filled",color="grey" ]; +"590E" [ label="eff3468631dd4",shape="box",style="filled",color="grey" ]; +"767E" [ label="efb52b499303115c33fd",shape="box",style="filled",color="grey" ]; +"300" [ label="8593dcf973b110d00cecdc1e756",shape="hexagon",style="filled",color="#ff7f00" ]; +"62E" [ label="472a156cf2b55f",shape="box",style="filled",color="grey" ]; +"190E" [ label="647",shape="box",style="filled",color="grey" ]; +"226E" [ label="",shape="box",style="filled",color="grey" ]; +"238E" [ label="8a",shape="box",style="filled",color="grey" ]; +"254E" [ label="",shape="box",style="filled",color="grey" ]; +"256E" [ label="",shape="box",style="filled",color="grey" ]; +"262E" [ label="",shape="box",style="filled",color="grey" ]; +"266E" [ label="e8b",shape="box",style="filled",color="grey" ]; +"274E" [ label="",shape="box",style="filled",color="grey" ]; +"276E" [ label="f",shape="box",style="filled",color="grey" ]; +"294E" [ label="",shape="box",style="filled",color="grey" ]; +"296E" [ label="",shape="box",style="filled",color="grey" ]; +"310E" [ label="1b34fb150",shape="box",style="filled",color="grey" ]; +"320E" [ label="",shape="box",style="filled",color="grey" ]; +"322E" [ label="a7d2",shape="box",style="filled",color="grey" ]; +"332E" [ label="",shape="box",style="filled",color="grey" ]; +"340E" [ label="",shape="box",style="filled",color="grey" ]; +"344E" [ label="f55670",shape="box",style="filled",color="grey" ]; +"346E" [ label="1ed67841",shape="box",style="filled",color="grey" ]; +"348E" [ label="07283",shape="box",style="filled",color="grey" ]; +"374E" [ label="73ba1714ee",shape="box",style="filled",color="grey" ]; +"378E" [ label="27709106",shape="box",style="filled",color="grey" ]; +"452E" [ label="93ea0",shape="box",style="filled",color="grey" ]; +"508E" [ label="",shape="box",style="filled",color="grey" ]; +"524E" [ label="1d792d81",shape="box",style="filled",color="grey" ]; +"612E" [ label="a",shape="box",style="filled",color="grey" ]; +"626E" [ label="",shape="box",style="filled",color="grey" ]; +"638E" [ label="",shape="box",style="filled",color="grey" ]; +"644E" [ label="",shape="box",style="filled",color="grey" ]; +"654E" [ label="",shape="box",style="filled",color="grey" ]; +"672E" [ label="",shape="box",style="filled",color="grey" ]; +"302" [ label="23f94655294d3ff537f2915fa",shape="hexagon" ]; +"797E" [ label="",shape="box",style="filled",color="grey" ]; +"798E" [ label="a2eab7c9fa641e5f",shape="box",style="filled",color="grey" ]; +"303" [ label="a9058241db5b6b6c25569acdf5",shape="hexagon" ]; +"52E" [ label="b2babf3244213",shape="box",style="filled",color="grey" ]; +"650E" [ label="b354cd9e9dbb0bfa",shape="box",style="filled",color="grey" ]; +"304" [ label="bdbdb31bd777fb65dd6dd2d0e7",shape="hexagon" ]; +"50E" [ label="3bec1c012b498",shape="box",style="filled",color="grey" ]; +"640E" [ label="c54f0fc1e05",shape="box",style="filled",color="grey" ]; +"646E" [ label="9ab6c66dc",shape="box",style="filled",color="grey" ]; +"652E" [ label="699e3db878047",shape="box",style="filled",color="grey" ]; +"306" [ label="1d4ea80c7194689d69f9592186",shape="hexagon" ]; +"55E" [ label="8066f87a88f4e",shape="box",style="filled",color="grey" ]; +"220E" [ label="3a8173d6c",shape="box",style="filled",color="grey" ]; +"338E" [ label="24dfe1a997a",shape="box",style="filled",color="grey" ]; +"368E" [ label="65a1",shape="box",style="filled",color="grey" ]; +"486E" [ label="59a8b435ccd",shape="box",style="filled",color="grey" ]; +"490E" [ label="86e9b0428",shape="box",style="filled",color="grey" ]; +"562E" [ label="5a7a610a8a",shape="box",style="filled",color="grey" ]; +"564E" [ label="8f143077e",shape="box",style="filled",color="grey" ]; +"600E" [ label="6472c2861e0e0dd681",shape="box",style="filled",color="grey" ]; +"668E" [ label="f0f45e707",shape="box",style="filled",color="grey" ]; +"674E" [ label="95e93c4a13",shape="box",style="filled",color="grey" ]; +"698E" [ label="33e1de",shape="box",style="filled",color="grey" ]; +"307" [ label="7204950f6233bf9c9e1f00d4a870",shape="hexagon" ]; +"107E" [ label="ccceeef40edda78",shape="box",style="filled",color="grey" ]; +"308" [ label="a2c4b1d72e2da483a86ae0c62e5",shape="hexagon" ]; +"108E" [ label="eedc819a68add6",shape="box",style="filled",color="grey" ]; +"309" [ label="f603819d560c5603259aa05dca",shape="hexagon" ]; +"109E" [ label="acacfc83af504",shape="box",style="filled",color="grey" ]; +"310" [ label="2f43cba12702078b4e0d3bfdae2bc",shape="hexagon" ]; +"110E" [ label="3c1edc8de4795936",shape="box",style="filled",color="grey" ]; +"311" [ label="8f9cdc26798117dd3e9ee4a8770",shape="hexagon" ]; +"58E" [ label="881d373",shape="box",style="filled",color="grey" ]; +"234E" [ label="",shape="box",style="filled",color="grey" ]; +"300E" [ label="",shape="box",style="filled",color="grey" ]; +"306E" [ label="8c7cd9b93b1cbe48e1",shape="box",style="filled",color="grey" ]; +"314E" [ label="616d8a7b",shape="box",style="filled",color="grey" ]; +"342E" [ label="",shape="box",style="filled",color="grey" ]; +"354E" [ label="",shape="box",style="filled",color="grey" ]; +"370E" [ label="",shape="box",style="filled",color="grey" ]; +"382E" [ label="",shape="box",style="filled",color="grey" ]; +"422E" [ label="",shape="box",style="filled",color="grey" ]; +"444E" [ label="",shape="box",style="filled",color="grey" ]; +"582E" [ label="",shape="box",style="filled",color="grey" ]; +"620E" [ label="",shape="box",style="filled",color="grey" ]; +"630E" [ label="",shape="box",style="filled",color="grey" ]; +"684E" [ label="",shape="box",style="filled",color="grey" ]; +"696E" [ label="",shape="box",style="filled",color="grey" ]; +"801E" [ label="",shape="box",style="filled",color="grey" ]; +"312" [ label="97c9d726e27304311901a52ce",shape="hexagon",style="filled",color="#ff0000" ]; +"42E" [ label="1112164c2f7a",shape="box",style="filled",color="grey" ]; +"192E" [ label="5c609b12c",shape="box",style="filled",color="grey" ]; +"194E" [ label="00265",shape="box",style="filled",color="grey" ]; +"196E" [ label="04767",shape="box",style="filled",color="grey" ]; +"198E" [ label="f0d99f16",shape="box",style="filled",color="grey" ]; +"200E" [ label="",shape="box",style="filled",color="grey" ]; +"202E" [ label="6e186b",shape="box",style="filled",color="grey" ]; +"204E" [ label="d382",shape="box",style="filled",color="grey" ]; +"312E" [ label="c6b5321a",shape="box",style="filled",color="grey" ]; +"336E" [ label="",shape="box",style="filled",color="grey" ]; +"376E" [ label="",shape="box",style="filled",color="grey" ]; +"384E" [ label="aeb8",shape="box",style="filled",color="grey" ]; +"386E" [ label="2e53009d4a375",shape="box",style="filled",color="grey" ]; +"428E" [ label="",shape="box",style="filled",color="grey" ]; +"474E" [ label="",shape="box",style="filled",color="grey" ]; +"484E" [ label="",shape="box",style="filled",color="grey" ]; +"546E" [ label="dea1d1",shape="box",style="filled",color="grey" ]; +"548E" [ label="5a0b4b906a",shape="box",style="filled",color="grey" ]; +"314" [ label="1727041c622518c9dd24f7c211",shape="hexagon" ]; +"113E" [ label="49704867bee95",shape="box",style="filled",color="grey" ]; +"315" [ label="31f2f9aef958979f9f3532b9b",shape="hexagon",style="filled",color="#ff0000" ]; +"43E" [ label="47cd70f",shape="box",style="filled",color="grey" ]; +"240E" [ label="248df40dae",shape="box",style="filled",color="grey" ]; +"298E" [ label="",shape="box",style="filled",color="grey" ]; +"334E" [ label="9dd5bf47f",shape="box",style="filled",color="grey" ]; +"360E" [ label="",shape="box",style="filled",color="grey" ]; +"390E" [ label="28533c",shape="box",style="filled",color="grey" ]; +"418E" [ label="",shape="box",style="filled",color="grey" ]; +"492E" [ label="a4c7d0",shape="box",style="filled",color="grey" ]; +"502E" [ label="4f6f7f",shape="box",style="filled",color="grey" ]; +"584E" [ label="7ab64a969",shape="box",style="filled",color="grey" ]; +"588E" [ label="",shape="box",style="filled",color="grey" ]; +"602E" [ label="69",shape="box",style="filled",color="grey" ]; +"606E" [ label="67513d",shape="box",style="filled",color="grey" ]; +"662E" [ label="cf",shape="box",style="filled",color="grey" ]; +"316" [ label="a54092a3033f7d5e41e0a76c1",shape="hexagon" ]; +"51E" [ label="1467f017b74e",shape="box",style="filled",color="grey" ]; +"317" [ label="2043b477ac0393676a4309514d0",shape="hexagon" ]; +"116E" [ label="bdec8c86db51b9",shape="box",style="filled",color="grey" ]; +"318" [ label="ab48d1f65812bc0f8ab6941c3b5",shape="hexagon" ]; +"74E" [ label="81",shape="box",style="filled",color="grey" ]; +"319" [ label="ca3d67754cf62fdafbf0a1e0",shape="hexagon" ]; +"57E" [ label="75b14f1719d",shape="box",style="filled",color="grey" ]; +"94E" [ label="62f36ea98a",shape="box",style="filled",color="grey" ]; +"350E" [ label="e3a76d31ca59a",shape="box",style="filled",color="grey" ]; +"440E" [ label="b3cadc253f7",shape="box",style="filled",color="grey" ]; +"466E" [ label="fb58e11",shape="box",style="filled",color="grey" ]; +"676E" [ label="8606837526d81cdec",shape="box",style="filled",color="grey" ]; +"320" [ label="a7a7f3681dad1250b01cf80bc17",shape="hexagon" ]; +"60E" [ label="2c514b0cd8f7d3",shape="box",style="filled",color="grey" ]; +"366E" [ label="7e494b",shape="box",style="filled",color="grey" ]; +"434E" [ label="15d44ab97",shape="box",style="filled",color="grey" ]; +"458E" [ label="78b2d75d00166",shape="box",style="filled",color="grey" ]; +"618E" [ label="761e0f72f95",shape="box",style="filled",color="grey" ]; +"321" [ label="275afb2b215b966d9fac51b96b9",shape="hexagon" ]; +"72E" [ label="ac284d73563",shape="box",style="filled",color="grey" ]; +"362E" [ label="7e74e1587f3a4d208",shape="box",style="filled",color="grey" ]; +"372E" [ label="ffd1b1af3b6864078f3",shape="box",style="filled",color="grey" ]; +"572E" [ label="b38049e00",shape="box",style="filled",color="grey" ]; +"322" [ label="c3c93c700edc0cb4f95f03c04",shape="hexagon" ]; +"54E" [ label="99237fce1358",shape="box",style="filled",color="grey" ]; +"222E" [ label="3dcf8f454",shape="box",style="filled",color="grey" ]; +"302E" [ label="c5acd20cad2",shape="box",style="filled",color="grey" ]; +"556E" [ label="6c998bf2a5edd",shape="box",style="filled",color="grey" ]; +"558E" [ label="4b683",shape="box",style="filled",color="grey" ]; +"323" [ label="63a3d4fb9d38a0182be6e39e76",shape="hexagon" ]; +"37E" [ label="bba6e6e194ccf",shape="box",style="filled",color="grey" ]; +"208E" [ label="01938827",shape="box",style="filled",color="grey" ]; +"210E" [ label="9",shape="box",style="filled",color="grey" ]; +"352E" [ label="64ef1d545",shape="box",style="filled",color="grey" ]; +"450E" [ label="b473716",shape="box",style="filled",color="grey" ]; +"568E" [ label="7c13bf753da",shape="box",style="filled",color="grey" ]; +"576E" [ label="4e4a79111d",shape="box",style="filled",color="grey" ]; +"686E" [ label="af4abb0d6a99",shape="box",style="filled",color="grey" ]; +"324" [ label="4399cf78123dedd0dfe9776104",shape="hexagon" ]; +"228E" [ label="af9c489df53",shape="box",style="filled",color="grey" ]; +"248E" [ label="3703059dbc5a8",shape="box",style="filled",color="grey" ]; +"304E" [ label="8a46e6",shape="box",style="filled",color="grey" ]; +"468E" [ label="f9d09",shape="box",style="filled",color="grey" ]; +"578E" [ label="cd1e9af3dec2",shape="box",style="filled",color="grey" ]; +"660E" [ label="9e650e89bb",shape="box",style="filled",color="grey" ]; +"688E" [ label="f62b136b2171",shape="box",style="filled",color="grey" ]; +"694E" [ label="4727c415d06bcbef",shape="box",style="filled",color="grey" ]; +"714E" [ label="38b3b0d9",shape="box",style="filled",color="grey" ]; +"766E" [ label="a153512d982",shape="box",style="filled",color="grey" ]; +"325" [ label="40f253cd228f7ac2d0aee",shape="hexagon" ]; +"97E" [ label="a3ff993",shape="box",style="filled",color="grey" ]; +"506E" [ label="7528dd86b",shape="box",style="filled",color="grey" ]; +"326" [ label="89a2505da6179a80202d4a6c3",shape="hexagon" ]; +"61E" [ label="75eea05672a5",shape="box",style="filled",color="grey" ]; +"175E" [ label="3b0c08dd2ca",shape="box",style="filled",color="grey" ]; +"482E" [ label="a3781072b",shape="box",style="filled",color="grey" ]; +"328" [ label="2601085bde1b2450d64509f36",shape="hexagon" ]; +"75E" [ label="0efbd",shape="box",style="filled",color="grey" ]; +"580E" [ label="bb92d1da1f38d52f8ff",shape="box",style="filled",color="grey" ]; +"329" [ label="5c81103c751345d0ee0f4bd",shape="hexagon" ]; +"96E" [ label="b23526044",shape="box",style="filled",color="grey" ]; +"330" [ label="fcbd9ad14139718bc6fcc8b4",shape="hexagon" ]; +"100E" [ label="73ca543bf1",shape="box",style="filled",color="grey" ]; +"170E" [ label="c2f32e2cf9",shape="box",style="filled",color="grey" ]; +"333" [ label="44cbb41a9cfc15497eacd294",color="yellow",style="filled",shape="doubleoctagon" ]; +"63E" [ label="6a91",shape="box",style="filled",color="grey" ]; +"67E" [ label="b074e",shape="box",style="filled",color="grey" ]; +"68E" [ label="06209",shape="box",style="filled",color="grey" ]; +"69E" [ label="58e3dcc618",shape="box",style="filled",color="grey" ]; +"70E" [ label="eee44624da",shape="box",style="filled",color="grey" ]; +"71E" [ label="6a91",shape="box",style="filled",color="grey" ]; +"802E" [ label="e1e8c",shape="box",style="filled",color="grey" ]; +"793E" [ label="",shape="box",style="filled",color="grey" ]; +"334" [ label="b46b0756dba915943839e90a55",color="yellow",style="filled",shape="doubleoctagon" ]; +"64E" [ label="5fdf",shape="box",style="filled",color="grey" ]; +"81E" [ label="3eca1f94dc181",shape="box",style="filled",color="grey" ]; +"82E" [ label="6b1bb9b0e",shape="box",style="filled",color="grey" ]; +"83E" [ label="a54d477232",shape="box",style="filled",color="grey" ]; +"84E" [ label="a164d9f60fbbdd",shape="box",style="filled",color="grey" ]; +"85E" [ label="78c8463ea",shape="box",style="filled",color="grey" ]; +"86E" [ label="c110ba7",shape="box",style="filled",color="grey" ]; +"87E" [ label="3b63cdc0f",shape="box",style="filled",color="grey" ]; +"88E" [ label="6f578c5128",shape="box",style="filled",color="grey" ]; +"89E" [ label="3e048573fd",shape="box",style="filled",color="grey" ]; +"336" [ URL="tes hi",area="test",label="825c7994d5da13afe519861818",color="#ff0000",style="filled",shape="tripleoctagon" ]; +"1E" [ label="f4bef37b6a94bfd00",shape="box",style="filled",color="grey" ]; +"2E" [ label="d2647f8b6d8661d08",shape="box",style="filled",color="grey" ]; +"3E" [ label="964cb56d8f69ff058",shape="box",style="filled",color="grey" ]; +"4E" [ label="4f35e206816c3bd22",shape="box",style="filled",color="grey" ]; +"5E" [ label="affb2d716803a2d3e",shape="box",style="filled",color="grey" ]; +"6E" [ label="e4ae306d9bd669c70",shape="box",style="filled",color="grey" ]; +"7E" [ label="4dbf4395236fb03ed",shape="box",style="filled",color="grey" ]; +"8E" [ label="15b3ad672cd2f713a",shape="box",style="filled",color="grey" ]; +"9E" [ label="8d6e6e0cd9b842a47",shape="box",style="filled",color="grey" ]; +"10E" [ label="00d0dd018fe879f96",shape="box",style="filled",color="grey" ]; +"11E" [ label="f28b78d4803c",shape="box",style="filled",color="grey" ]; +"12E" [ label="2d886da042b5384b4",shape="box",style="filled",color="grey" ]; +"13E" [ label="548c0081a62132b44",shape="box",style="filled",color="grey" ]; +"14E" [ label="52126553e52385d16",shape="box",style="filled",color="grey" ]; +"15E" [ label="9fe716e738eaea34e",shape="box",style="filled",color="grey" ]; +"16E" [ label="5782807b5f575e0a8",shape="box",style="filled",color="grey" ]; +"17E" [ label="792fd6f9df1fa1e33",shape="box",style="filled",color="grey" ]; +"18E" [ label="c471b6fdbfb852661",shape="box",style="filled",color="grey" ]; +"19E" [ label="a84844dfd0052b3b5",shape="box",style="filled",color="grey" ]; +"20E" [ label="724dabdce9744d061",shape="box",style="filled",color="grey" ]; +"21E" [ label="57f7fd2eecec93c8b",shape="box",style="filled",color="grey" ]; +"22E" [ label="baba65f670ee34a88",shape="box",style="filled",color="grey" ]; +"23E" [ label="ac34ec0f0488b17ec",shape="box",style="filled",color="grey" ]; +"24E" [ label="51e74bec5513083bb",shape="box",style="filled",color="grey" ]; +"25E" [ label="8e2d970b2f820ee35",shape="box",style="filled",color="grey" ]; +"26E" [ label="19398d3cd6b9c674f",shape="box",style="filled",color="grey" ]; +"27E" [ label="6505e29f4a11d9530",shape="box",style="filled",color="grey" ]; +"28E" [ label="bc4824f07a9d2bba6",shape="box",style="filled",color="grey" ]; +"29E" [ label="3acbf8a1537e4e1a1",shape="box",style="filled",color="grey" ]; +"30E" [ label="536264e787cf70469",shape="box",style="filled",color="grey" ]; +"31E" [ label="d",shape="box",style="filled",color="grey" ]; +"65E" [ label="d4b2",shape="box",style="filled",color="grey" ]; +"119E" [ label="2a9caef7",shape="box",style="filled",color="grey" ]; +"150E" [ label="73d12",shape="box",style="filled",color="grey" ]; +"176E" [ label="8896166adc0",shape="box",style="filled",color="grey" ]; +"743E" [ label="9f",shape="box",style="filled",color="grey" ]; +"744E" [ label="2e1313c",shape="box",style="filled",color="grey" ]; +"764E" [ label="cd6",shape="box",style="filled",color="grey" ]; +"337" [ label="8304a439f91fc90b3fe8dd35be8",color="yellow",style="filled",shape="doubleoctagon" ]; +"120E" [ label="345d26b3f821fe",shape="box",style="filled",color="grey" ]; +"121E" [ label="357679fea1e2f",shape="box",style="filled",color="grey" ]; +"122E" [ label="c71043819b6a79",shape="box",style="filled",color="grey" ]; +"123E" [ label="f9df653b86fb8df",shape="box",style="filled",color="grey" ]; +"124E" [ label="020df871874cd",shape="box",style="filled",color="grey" ]; +"125E" [ label="4c52fdd8e396692",shape="box",style="filled",color="grey" ]; +"126E" [ label="8b98c3ddbe0b336",shape="box",style="filled",color="grey" ]; +"127E" [ label="d9f4abac731a9e",shape="box",style="filled",color="grey" ]; +"128E" [ label="50f4d9b97aefe",shape="box",style="filled",color="grey" ]; +"129E" [ label="ea920d9f5b295119",shape="box",style="filled",color="grey" ]; +"130E" [ label="ff5c9b242337c",shape="box",style="filled",color="grey" ]; +"131E" [ label="4e12f7ff0918",shape="box",style="filled",color="grey" ]; +"132E" [ label="ee3b6be71d59b",shape="box",style="filled",color="grey" ]; +"133E" [ label="615cd6b5e3d21c",shape="box",style="filled",color="grey" ]; +"134E" [ label="6d52dd1b198bb",shape="box",style="filled",color="grey" ]; +"135E" [ label="8c932e1e502dca",shape="box",style="filled",color="grey" ]; +"136E" [ label="e84330eef281284a",shape="box",style="filled",color="grey" ]; +"137E" [ label="85fc23f1c88b4",shape="box",style="filled",color="grey" ]; +"138E" [ label="5997cb0c083422",shape="box",style="filled",color="grey" ]; +"339" [ label="b1ffbabb24d71f67d1e0ce23c51",color="yellow",style="filled",shape="doubleoctagon" ]; +"151E" [ label="",shape="box",style="filled",color="grey" ]; +"153E" [ label="41a8b095c7fd3",shape="box",style="filled",color="grey" ]; +"154E" [ label="151bcc2a8de7ea634",shape="box",style="filled",color="grey" ]; +"155E" [ label="6c541cad8de1b15",shape="box",style="filled",color="grey" ]; +"156E" [ label="c935c7f4d1090ac",shape="box",style="filled",color="grey" ]; +"157E" [ label="5ce1fcfb042b",shape="box",style="filled",color="grey" ]; +"158E" [ label="531806429433",shape="box",style="filled",color="grey" ]; +"159E" [ label="d285240b89cb",shape="box",style="filled",color="grey" ]; +"160E" [ label="f22c27c0f0a54e",shape="box",style="filled",color="grey" ]; +"161E" [ label="8d0d8314d211d80",shape="box",style="filled",color="grey" ]; +"162E" [ label="",shape="box",style="filled",color="grey" ]; +"347" [ label="9652ab8b55fdb2a36d1f3fe020",shape="hexagon" ]; +"139E" [ label="ef8b68bb5772f3",shape="box",style="filled",color="grey" ]; +"795E" [ label="16c3ae29c0bc713",shape="box",style="filled",color="grey" ]; +"348" [ label="676bbe7d1c1fb71742df534ce8",shape="hexagon" ]; +"799E" [ label="a78eb40ae56aaa9",shape="box",style="filled",color="grey" ]; +"800E" [ label="6aae8d25951",shape="box",style="filled",color="grey" ]; +"349" [ label="66c0220688a999aaf7f1702d1",shape="hexagon" ]; +"141E" [ label="67b6a4dca3a6d",shape="box",style="filled",color="grey" ]; +"350" [ label="1322fb0818783e6f9a4f173d47c52",shape="hexagon" ]; +"142E" [ label="9696c0950295d8cb5",shape="box",style="filled",color="grey" ]; +"678E" [ label="b5c747cc9",shape="box",style="filled",color="grey" ]; +"351" [ label="ff07977fca5513098d220d1eb3a",shape="hexagon" ]; +"143E" [ label="89a36b13f8c344b",shape="box",style="filled",color="grey" ]; +"232E" [ label="56292d076643",shape="box",style="filled",color="grey" ]; +"680E" [ label="b5c747cc9",shape="box",style="filled",color="grey" ]; +"704E" [ label="431430c49",shape="box",style="filled",color="grey" ]; +"352" [ label="a97ef281eafc34b1630d450a1df",shape="hexagon" ]; +"144E" [ label="4ff4e275c710c3b",shape="box",style="filled",color="grey" ]; +"432E" [ label="d13da6273c9b4da",shape="box",style="filled",color="grey" ]; +"353" [ label="72cbb37db85ed3c6eda5dcf8",shape="hexagon" ]; +"145E" [ label="33ff9e43d5ab",shape="box",style="filled",color="grey" ]; +"354" [ label="0f6784e49852c0be0da23b16",shape="hexagon" ]; +"146E" [ label="d4f958b03a98",shape="box",style="filled",color="grey" ]; +"396E" [ label="8e24e9b4e",shape="box",style="filled",color="grey" ]; +"355" [ label="383f5c65cc6c25aa0a0e6dbb",shape="hexagon" ]; +"147E" [ label="1ff8ff951ee9",shape="box",style="filled",color="grey" ]; +"356" [ label="f52a45620969f0df4e6ae1dcd7",shape="hexagon" ]; +"148E" [ label="5256925081c812",shape="box",style="filled",color="grey" ]; +"357" [ label="1f5df34ad75a55a76ef4afa0a47",shape="hexagon" ]; +"149E" [ label="26a185dde9a93dd",shape="box",style="filled",color="grey" ]; +"358" [ label="45ba4d4c61c9601a26d59e47e0260",shape="hexagon" ]; +"167E" [ label="99bd3e7feeb710",shape="box",style="filled",color="grey" ]; +"359" [ label="f95344b0ae31693f3a2746597d4",shape="hexagon" ]; +"169E" [ label="4e8259973f1f",shape="box",style="filled",color="grey" ]; +"360" [ label="b79798b186d6b82288e8be4017d",shape="hexagon" ]; +"171E" [ label="63b079bd5847",shape="box",style="filled",color="grey" ]; +"361" [ label="47e0067f4d853afd2012f04daa8",shape="hexagon" ]; +"172E" [ label="92fb5d4a0805",shape="box",style="filled",color="grey" ]; +"362" [ label="f2b6201774de40a29b504b1f716",shape="hexagon" ]; +"173E" [ label="d7203571944b",shape="box",style="filled",color="grey" ]; +"363" [ label="800422ab81d804eef3e7b91dfba91",shape="hexagon" ]; +"174E" [ label="952316a1a5a785",shape="box",style="filled",color="grey" ]; +"364" [ label="35b941379e1af658078cffb83a2",shape="hexagon" ]; +"101E" [ label="331675c046693f",shape="box",style="filled",color="grey" ]; +"365" [ label="d4f7b7fba7afcf7a72397353ec",shape="hexagon" ]; +"102E" [ label="32c4684b55361",shape="box",style="filled",color="grey" ]; +"367" [ label="e4b45b7a2f884d3734bfd5985656",shape="hexagon" ]; +"104E" [ label="1333074979f2d0b",shape="box",style="filled",color="grey" ]; +"368" [ label="02c2ba83680ab57f236a33d702",shape="hexagon" ]; +"105E" [ label="084d4bfa5853e",shape="box",style="filled",color="grey" ]; +"369" [ label="9ccd974150a18260b207b6584caa",shape="hexagon" ]; +"106E" [ label="28f7bfc40c88e6a",shape="box",style="filled",color="grey" ]; +"374" [ label="653ae44d45dcadeb481b53027d",shape="hexagon" ]; +"111E" [ label="8f95518f48528",shape="box",style="filled",color="grey" ]; +"375" [ label="d66f542ef1ce4d02c59bec65e",shape="hexagon" ]; +"112E" [ label="2ef209509e2a",shape="box",style="filled",color="grey" ]; +"377" [ label="a2984b7a11e49440420058c1d80",shape="hexagon" ]; +"114E" [ label="ef42184297591d",shape="box",style="filled",color="grey" ]; +"378" [ label="31055116421c96b37f72a262bb",shape="hexagon" ]; +"115E" [ label="be9c5958196ed",shape="box",style="filled",color="grey" ]; +"380" [ label="8462bb2eec1a62d19a15865e57c92",shape="hexagon" ]; +"117E" [ label="16a795a1d63f30df",shape="box",style="filled",color="grey" ]; +"392E" [ label="85a34bc9616ff",shape="box",style="filled",color="grey" ]; +"381" [ label="c21eb96fe100a1efaa128181b7",shape="hexagon" ]; +"118E" [ label="f1b0d754353a6",shape="box",style="filled",color="grey" ]; +"382" [ label="e3e284d0cc803d98d674f9c3f6d",color="yellow",style="filled",shape="doubleoctagon" ]; +"177E" [ label="30417faf916",shape="box",style="filled",color="grey" ]; +"178E" [ label="e618df70814a",shape="box",style="filled",color="grey" ]; +"179E" [ label="fa90ddf10bd574",shape="box",style="filled",color="grey" ]; +"180E" [ label="815cc0b83d733",shape="box",style="filled",color="grey" ]; +"181E" [ label="f787d827958c",shape="box",style="filled",color="grey" ]; +"182E" [ label="f20f7f513e",shape="box",style="filled",color="grey" ]; +"183E" [ label="290907417e13",shape="box",style="filled",color="grey" ]; +"184E" [ label="e8386a8e1c8a",shape="box",style="filled",color="grey" ]; +"185E" [ label="319bc900218b",shape="box",style="filled",color="grey" ]; +"186E" [ label="3ba7afb0e48ae1",shape="box",style="filled",color="grey" ]; +"187E" [ label="6ba0776fc8e",shape="box",style="filled",color="grey" ]; +"188E" [ label="09847696ae",shape="box",style="filled",color="grey" ]; +"383" [ label="908f9ad506eae9ab6ada185e3",color="yellow",style="filled",shape="doubleoctagon" ]; +"730E" [ label="65694ca6d575",shape="box",style="filled",color="grey" ]; +"732E" [ label="37f57e81ebed95",shape="box",style="filled",color="grey" ]; +"741E" [ label="9b6c",shape="box",style="filled",color="grey" ]; +"765E" [ label="88ebe2e8782c",shape="box",style="filled",color="grey" ]; +"796E" [ label="901b2105a902ee7791",shape="box",style="filled",color="grey" ]; +"384" [ label="593caebf2037317648bb451aa79",color="yellow",style="filled",shape="doubleoctagon" ]; +"726E" [ label="351dd0aefe480c",shape="box",style="filled",color="grey" ]; +"728E" [ label="56e1a896",shape="box",style="filled",color="grey" ]; +"742E" [ label="5ba4693031",shape="box",style="filled",color="grey" ]; +"385" [ label="717c254aeffbb527dabfc",shape="hexagon" ]; +"328E" [ label="123cc6d1ac",shape="box",style="filled",color="grey" ]; +"496E" [ label="",shape="box",style="filled",color="grey" ]; +"594E" [ label="7f8c557bcf3889",shape="box",style="filled",color="grey" ]; +"622E" [ label="da3d5",shape="box",style="filled",color="grey" ]; +"754E" [ label="68d8993e61d8c82cd29e8d0182b0",shape="box",style="filled",color="grey" ]; +"755E" [ label="4c865eec228e41e7f4e5fc68a9a6",shape="box",style="filled",color="grey" ]; +"756E" [ label="8983ffbc30deb364dd92c3ad85c9",shape="box",style="filled",color="grey" ]; +"757E" [ label="68d8993e61d8c82cd29e8d0182b0",shape="box",style="filled",color="grey" ]; +"758E" [ label="4c865eec228e41e7f4e5fc68a9a6",shape="box",style="filled",color="grey" ]; +"759E" [ label="8983ffbc30deb364dd92c3ad85c9",shape="box",style="filled",color="grey" ]; +"760E" [ label="8983ffbc30deb364dd92c3ad85c9",shape="box",style="filled",color="grey" ]; +"761E" [ label="eb9cf6456613d4cd06f7c0894bd6",shape="box",style="filled",color="grey" ]; +"762E" [ label="1e2298c4bb",shape="box",style="filled",color="grey" ]; +"1" -> "189E" [ label=" ",color="blue",arrowhead="dot" ]; +"1" -> "790E" [ label=" ",color="blue",arrowhead="dot" ]; +"2" -> "191E" [ label=" ",color="blue",arrowhead="dot" ]; +"3" -> "193E" [ label=" ",color="blue",arrowhead="dot" ]; +"4" -> "195E" [ label=" ",color="blue",arrowhead="dot" ]; +"5" -> "197E" [ label=" ",color="blue",arrowhead="dot" ]; +"6" -> "199E" [ label=" ",color="blue",arrowhead="dot" ]; +"7" -> "201E" [ label=" ",color="blue",arrowhead="dot" ]; +"8" -> "203E" [ label=" ",color="blue",arrowhead="dot" ]; +"9" -> "725E" [ label=" ",color="blue",arrowhead="dot" ]; +"9" -> "785E" [ label=" ",color="blue",arrowhead="dot" ]; +"10" -> "205E" [ label=" ",color="blue",arrowhead="dot" ]; +"11" -> "207E" [ label=" ",color="blue",arrowhead="dot" ]; +"12" -> "209E" [ label=" ",color="blue",arrowhead="dot" ]; +"13" -> "211E" [ label=" ",color="blue",arrowhead="dot" ]; +"14" -> "213E" [ label=" ",color="blue",arrowhead="dot" ]; +"15" -> "215E" [ label=" ",color="blue",arrowhead="dot" ]; +"16" -> "727E" [ label=" ",color="blue",arrowhead="dot" ]; +"16" -> "784E" [ label=" ",color="blue",arrowhead="dot" ]; +"17" -> "217E" [ label=" ",color="blue",arrowhead="dot" ]; +"17" -> "787E" [ label=" ",color="blue",arrowhead="dot" ]; +"18" -> "219E" [ label=" ",color="blue",arrowhead="dot" ]; +"19" -> "221E" [ label=" ",color="blue",arrowhead="dot" ]; +"20" -> "223E" [ label=" ",color="blue",arrowhead="dot" ]; +"21" -> "225E" [ label=" ",color="blue",arrowhead="dot" ]; +"22" -> "227E" [ label=" ",color="blue",arrowhead="dot" ]; +"22" -> "792E" [ label=" ",color="blue",arrowhead="dot" ]; +"23" -> "231E" [ label=" ",color="blue",arrowhead="dot" ]; +"24" -> "233E" [ label=" ",color="blue",arrowhead="dot" ]; +"25" -> "235E" [ label=" ",color="blue",arrowhead="dot" ]; +"26" -> "237E" [ label=" ",color="blue",arrowhead="dot" ]; +"27" -> "239E" [ label=" ",color="blue",arrowhead="dot" ]; +"27" -> "783E" [ label=" ",color="blue",arrowhead="dot" ]; +"28" -> "241E" [ label=" ",color="blue",arrowhead="dot" ]; +"28" -> "791E" [ label=" ",color="blue",arrowhead="dot" ]; +"29" -> "243E" [ label=" ",color="blue",arrowhead="dot" ]; +"30" -> "245E" [ label=" ",color="blue",arrowhead="dot" ]; +"31" -> "247E" [ label=" ",color="blue",arrowhead="dot" ]; +"32" -> "249E" [ label=" ",color="blue",arrowhead="dot" ]; +"33" -> "251E" [ label=" ",color="blue",arrowhead="dot" ]; +"34" -> "253E" [ label=" ",color="blue",arrowhead="dot" ]; +"35" -> "255E" [ label=" ",color="blue",arrowhead="dot" ]; +"36" -> "257E" [ label=" ",color="blue",arrowhead="dot" ]; +"37" -> "259E" [ label=" ",color="blue",arrowhead="dot" ]; +"38" -> "261E" [ label=" ",color="blue",arrowhead="dot" ]; +"39" -> "263E" [ label=" ",color="blue",arrowhead="dot" ]; +"40" -> "265E" [ label=" ",color="blue",arrowhead="dot" ]; +"41" -> "267E" [ label=" ",color="blue",arrowhead="dot" ]; +"42" -> "269E" [ label=" ",color="blue",arrowhead="dot" ]; +"43" -> "271E" [ label=" ",color="blue",arrowhead="dot" ]; +"44" -> "273E" [ label=" ",color="blue",arrowhead="dot" ]; +"45" -> "275E" [ label=" ",color="blue",arrowhead="dot" ]; +"46" -> "277E" [ label=" ",color="blue",arrowhead="dot" ]; +"47" -> "279E" [ label=" ",color="blue",arrowhead="dot" ]; +"48" -> "281E" [ label=" ",color="blue",arrowhead="dot" ]; +"49" -> "283E" [ label=" ",color="blue",arrowhead="dot" ]; +"50" -> "285E" [ label=" ",color="blue",arrowhead="dot" ]; +"51" -> "287E" [ label=" ",color="blue",arrowhead="dot" ]; +"52" -> "289E" [ label=" ",color="blue",arrowhead="dot" ]; +"53" -> "291E" [ label=" ",color="blue",arrowhead="dot" ]; +"54" -> "293E" [ label=" ",color="blue",arrowhead="dot" ]; +"55" -> "745E" [ label=" ",color="blue",arrowhead="dot" ]; +"56" -> "295E" [ label=" ",color="blue",arrowhead="dot" ]; +"57" -> "297E" [ label=" ",color="blue",arrowhead="dot" ]; +"58" -> "299E" [ label=" ",color="blue",arrowhead="dot" ]; +"59" -> "301E" [ label=" ",color="blue",arrowhead="dot" ]; +"59" -> "789E" [ label=" ",color="blue",arrowhead="dot" ]; +"60" -> "303E" [ label=" ",color="blue",arrowhead="dot" ]; +"61" -> "305E" [ label=" ",color="blue",arrowhead="dot" ]; +"62" -> "307E" [ label=" ",color="blue",arrowhead="dot" ]; +"63" -> "309E" [ label=" ",color="blue",arrowhead="dot" ]; +"64" -> "311E" [ label=" ",color="blue",arrowhead="dot" ]; +"65" -> "313E" [ label=" ",color="blue",arrowhead="dot" ]; +"66" -> "315E" [ label=" ",color="blue",arrowhead="dot" ]; +"67" -> "317E" [ label=" ",color="blue",arrowhead="dot" ]; +"68" -> "319E" [ label=" ",color="blue",arrowhead="dot" ]; +"69" -> "746E" [ label=" ",color="blue",arrowhead="dot" ]; +"70" -> "321E" [ label=" ",color="blue",arrowhead="dot" ]; +"71" -> "327E" [ label=" ",color="blue",arrowhead="dot" ]; +"72" -> "329E" [ label=" ",color="blue",arrowhead="dot" ]; +"73" -> "331E" [ label=" ",color="blue",arrowhead="dot" ]; +"74" -> "333E" [ label=" ",color="blue",arrowhead="dot" ]; +"75" -> "335E" [ label=" ",color="blue",arrowhead="dot" ]; +"76" -> "337E" [ label=" ",color="blue",arrowhead="dot" ]; +"77" -> "339E" [ label=" ",color="blue",arrowhead="dot" ]; +"78" -> "341E" [ label=" ",color="blue",arrowhead="dot" ]; +"79" -> "343E" [ label=" ",color="blue",arrowhead="dot" ]; +"80" -> "345E" [ label=" ",color="blue",arrowhead="dot" ]; +"81" -> "347E" [ label=" ",color="blue",arrowhead="dot" ]; +"82" -> "349E" [ label=" ",color="blue",arrowhead="dot" ]; +"83" -> "351E" [ label=" ",color="blue",arrowhead="dot" ]; +"84" -> "353E" [ label=" ",color="blue",arrowhead="dot" ]; +"85" -> "355E" [ label=" ",color="blue",arrowhead="dot" ]; +"85" -> "788E" [ label=" ",color="blue",arrowhead="dot" ]; +"86" -> "357E" [ label=" ",color="blue",arrowhead="dot" ]; +"87" -> "359E" [ label=" ",color="blue",arrowhead="dot" ]; +"88" -> "361E" [ label=" ",color="blue",arrowhead="dot" ]; +"89" -> "363E" [ label=" ",color="blue",arrowhead="dot" ]; +"90" -> "365E" [ label=" ",color="blue",arrowhead="dot" ]; +"91" -> "367E" [ label=" ",color="blue",arrowhead="dot" ]; +"92" -> "369E" [ label=" ",color="blue",arrowhead="dot" ]; +"93" -> "729E" [ label=" ",color="blue",arrowhead="dot" ]; +"94" -> "371E" [ label=" ",color="blue",arrowhead="dot" ]; +"95" -> "373E" [ label=" ",color="blue",arrowhead="dot" ]; +"96" -> "375E" [ label=" ",color="blue",arrowhead="dot" ]; +"97" -> "747E" [ label=" ",color="blue",arrowhead="dot" ]; +"98" -> "377E" [ label=" ",color="blue",arrowhead="dot" ]; +"99" -> "379E" [ label=" ",color="blue",arrowhead="dot" ]; +"100" -> "381E" [ label=" ",color="blue",arrowhead="dot" ]; +"101" -> "383E" [ label=" ",color="blue",arrowhead="dot" ]; +"102" -> "385E" [ label=" ",color="blue",arrowhead="dot" ]; +"103" -> "387E" [ label=" ",color="blue",arrowhead="dot" ]; +"104" -> "389E" [ label=" ",color="blue",arrowhead="dot" ]; +"105" -> "391E" [ label=" ",color="blue",arrowhead="dot" ]; +"106" -> "393E" [ label=" ",color="blue",arrowhead="dot" ]; +"107" -> "395E" [ label=" ",color="blue",arrowhead="dot" ]; +"108" -> "397E" [ label=" ",color="blue",arrowhead="dot" ]; +"109" -> "399E" [ label=" ",color="blue",arrowhead="dot" ]; +"110" -> "401E" [ label=" ",color="blue",arrowhead="dot" ]; +"111" -> "403E" [ label=" ",color="blue",arrowhead="dot" ]; +"112" -> "405E" [ label=" ",color="blue",arrowhead="dot" ]; +"113" -> "407E" [ label=" ",color="blue",arrowhead="dot" ]; +"114" -> "409E" [ label=" ",color="blue",arrowhead="dot" ]; +"115" -> "411E" [ label=" ",color="blue",arrowhead="dot" ]; +"116" -> "413E" [ label=" ",color="blue",arrowhead="dot" ]; +"117" -> "415E" [ label=" ",color="blue",arrowhead="dot" ]; +"118" -> "417E" [ label=" ",color="blue",arrowhead="dot" ]; +"119" -> "419E" [ label=" ",color="blue",arrowhead="dot" ]; +"120" -> "421E" [ label=" ",color="blue",arrowhead="dot" ]; +"121" -> "423E" [ label=" ",color="blue",arrowhead="dot" ]; +"122" -> "748E" [ label=" ",color="blue",arrowhead="dot" ]; +"123" -> "425E" [ label=" ",color="blue",arrowhead="dot" ]; +"124" -> "427E" [ label=" ",color="blue",arrowhead="dot" ]; +"124" -> "786E" [ label=" ",color="blue",arrowhead="dot" ]; +"125" -> "431E" [ label=" ",color="blue",arrowhead="dot" ]; +"126" -> "433E" [ label=" ",color="blue",arrowhead="dot" ]; +"127" -> "435E" [ label=" ",color="blue",arrowhead="dot" ]; +"128" -> "437E" [ label=" ",color="blue",arrowhead="dot" ]; +"129" -> "439E" [ label=" ",color="blue",arrowhead="dot" ]; +"130" -> "441E" [ label=" ",color="blue",arrowhead="dot" ]; +"131" -> "443E" [ label=" ",color="blue",arrowhead="dot" ]; +"132" -> "445E" [ label=" ",color="blue",arrowhead="dot" ]; +"133" -> "749E" [ label=" ",color="blue",arrowhead="dot" ]; +"134" -> "447E" [ label=" ",color="blue",arrowhead="dot" ]; +"135" -> "449E" [ label=" ",color="blue",arrowhead="dot" ]; +"135" -> "769E" [ label=" ",color="blue",arrowhead="dot" ]; +"135" -> "770E" [ label=" ",color="blue",arrowhead="dot" ]; +"136" -> "451E" [ label=" ",color="blue",arrowhead="dot" ]; +"137" -> "453E" [ label=" ",color="blue",arrowhead="dot" ]; +"138" -> "455E" [ label=" ",color="blue",arrowhead="dot" ]; +"139" -> "457E" [ label=" ",color="blue",arrowhead="dot" ]; +"140" -> "459E" [ label=" ",color="blue",arrowhead="dot" ]; +"141" -> "461E" [ label=" ",color="blue",arrowhead="dot" ]; +"142" -> "463E" [ label=" ",color="blue",arrowhead="dot" ]; +"143" -> "465E" [ label=" ",color="blue",arrowhead="dot" ]; +"144" -> "467E" [ label=" ",color="blue",arrowhead="dot" ]; +"145" -> "469E" [ label=" ",color="blue",arrowhead="dot" ]; +"146" -> "471E" [ label=" ",color="blue",arrowhead="dot" ]; +"147" -> "473E" [ label=" ",color="blue",arrowhead="dot" ]; +"148" -> "475E" [ label=" ",color="blue",arrowhead="dot" ]; +"149" -> "477E" [ label=" ",color="blue",arrowhead="dot" ]; +"150" -> "479E" [ label=" ",color="blue",arrowhead="dot" ]; +"151" -> "481E" [ label=" ",color="blue",arrowhead="dot" ]; +"152" -> "483E" [ label=" ",color="blue",arrowhead="dot" ]; +"153" -> "731E" [ label=" ",color="blue",arrowhead="dot" ]; +"154" -> "750E" [ label=" ",color="blue",arrowhead="dot" ]; +"155" -> "485E" [ label=" ",color="blue",arrowhead="dot" ]; +"156" -> "487E" [ label=" ",color="blue",arrowhead="dot" ]; +"157" -> "489E" [ label=" ",color="blue",arrowhead="dot" ]; +"158" -> "491E" [ label=" ",color="blue",arrowhead="dot" ]; +"159" -> "495E" [ label=" ",color="blue",arrowhead="dot" ]; +"160" -> "499E" [ label=" ",color="blue",arrowhead="dot" ]; +"161" -> "501E" [ label=" ",color="blue",arrowhead="dot" ]; +"162" -> "503E" [ label=" ",color="blue",arrowhead="dot" ]; +"163" -> "505E" [ label=" ",color="blue",arrowhead="dot" ]; +"164" -> "507E" [ label=" ",color="blue",arrowhead="dot" ]; +"165" -> "509E" [ label=" ",color="blue",arrowhead="dot" ]; +"166" -> "511E" [ label=" ",color="blue",arrowhead="dot" ]; +"167" -> "513E" [ label=" ",color="blue",arrowhead="dot" ]; +"168" -> "515E" [ label=" ",color="blue",arrowhead="dot" ]; +"169" -> "517E" [ label=" ",color="blue",arrowhead="dot" ]; +"170" -> "519E" [ label=" ",color="blue",arrowhead="dot" ]; +"171" -> "521E" [ label=" ",color="blue",arrowhead="dot" ]; +"172" -> "523E" [ label=" ",color="blue",arrowhead="dot" ]; +"173" -> "525E" [ label=" ",color="blue",arrowhead="dot" ]; +"174" -> "527E" [ label=" ",color="blue",arrowhead="dot" ]; +"175" -> "529E" [ label=" ",color="blue",arrowhead="dot" ]; +"176" -> "531E" [ label=" ",color="blue",arrowhead="dot" ]; +"177" -> "533E" [ label=" ",color="blue",arrowhead="dot" ]; +"178" -> "535E" [ label=" ",color="blue",arrowhead="dot" ]; +"179" -> "537E" [ label=" ",color="blue",arrowhead="dot" ]; +"180" -> "539E" [ label=" ",color="blue",arrowhead="dot" ]; +"181" -> "541E" [ label=" ",color="blue",arrowhead="dot" ]; +"182" -> "543E" [ label=" ",color="blue",arrowhead="dot" ]; +"183" -> "545E" [ label=" ",color="blue",arrowhead="dot" ]; +"184" -> "547E" [ label=" ",color="blue",arrowhead="dot" ]; +"185" -> "549E" [ label=" ",color="blue",arrowhead="dot" ]; +"186" -> "551E" [ label=" ",color="blue",arrowhead="dot" ]; +"187" -> "553E" [ label=" ",color="blue",arrowhead="dot" ]; +"188" -> "555E" [ label=" ",color="blue",arrowhead="dot" ]; +"189" -> "557E" [ label=" ",color="blue",arrowhead="dot" ]; +"190" -> "559E" [ label=" ",color="blue",arrowhead="dot" ]; +"191" -> "561E" [ label=" ",color="blue",arrowhead="dot" ]; +"192" -> "563E" [ label=" ",color="blue",arrowhead="dot" ]; +"193" -> "565E" [ label=" ",color="blue",arrowhead="dot" ]; +"194" -> "567E" [ label=" ",color="blue",arrowhead="dot" ]; +"195" -> "569E" [ label=" ",color="blue",arrowhead="dot" ]; +"196" -> "571E" [ label=" ",color="blue",arrowhead="dot" ]; +"197" -> "573E" [ label=" ",color="blue",arrowhead="dot" ]; +"198" -> "575E" [ label=" ",color="blue",arrowhead="dot" ]; +"199" -> "577E" [ label=" ",color="blue",arrowhead="dot" ]; +"200" -> "579E" [ label=" ",color="blue",arrowhead="dot" ]; +"201" -> "581E" [ label=" ",color="blue",arrowhead="dot" ]; +"202" -> "583E" [ label=" ",color="blue",arrowhead="dot" ]; +"203" -> "585E" [ label=" ",color="blue",arrowhead="dot" ]; +"204" -> "587E" [ label=" ",color="blue",arrowhead="dot" ]; +"205" -> "751E" [ label=" ",color="blue",arrowhead="dot" ]; +"206" -> "589E" [ label=" ",color="blue",arrowhead="dot" ]; +"207" -> "593E" [ label=" ",color="blue",arrowhead="dot" ]; +"208" -> "597E" [ label=" ",color="blue",arrowhead="dot" ]; +"209" -> "599E" [ label=" ",color="blue",arrowhead="dot" ]; +"210" -> "601E" [ label=" ",color="blue",arrowhead="dot" ]; +"211" -> "603E" [ label=" ",color="blue",arrowhead="dot" ]; +"212" -> "605E" [ label=" ",color="blue",arrowhead="dot" ]; +"213" -> "607E" [ label=" ",color="blue",arrowhead="dot" ]; +"214" -> "609E" [ label=" ",color="blue",arrowhead="dot" ]; +"215" -> "611E" [ label=" ",color="blue",arrowhead="dot" ]; +"216" -> "613E" [ label=" ",color="blue",arrowhead="dot" ]; +"217" -> "615E" [ label=" ",color="blue",arrowhead="dot" ]; +"218" -> "617E" [ label=" ",color="blue",arrowhead="dot" ]; +"219" -> "619E" [ label=" ",color="blue",arrowhead="dot" ]; +"220" -> "621E" [ label=" ",color="blue",arrowhead="dot" ]; +"221" -> "623E" [ label=" ",color="blue",arrowhead="dot" ]; +"222" -> "752E" [ label=" ",color="blue",arrowhead="dot" ]; +"223" -> "625E" [ label=" ",color="blue",arrowhead="dot" ]; +"224" -> "627E" [ label=" ",color="blue",arrowhead="dot" ]; +"225" -> "629E" [ label=" ",color="blue",arrowhead="dot" ]; +"226" -> "631E" [ label=" ",color="blue",arrowhead="dot" ]; +"227" -> "633E" [ label=" ",color="blue",arrowhead="dot" ]; +"228" -> "635E" [ label=" ",color="blue",arrowhead="dot" ]; +"229" -> "637E" [ label=" ",color="blue",arrowhead="dot" ]; +"230" -> "639E" [ label=" ",color="blue",arrowhead="dot" ]; +"231" -> "641E" [ label=" ",color="blue",arrowhead="dot" ]; +"232" -> "643E" [ label=" ",color="blue",arrowhead="dot" ]; +"233" -> "645E" [ label=" ",color="blue",arrowhead="dot" ]; +"234" -> "647E" [ label=" ",color="blue",arrowhead="dot" ]; +"235" -> "649E" [ label=" ",color="blue",arrowhead="dot" ]; +"236" -> "651E" [ label=" ",color="blue",arrowhead="dot" ]; +"237" -> "653E" [ label=" ",color="blue",arrowhead="dot" ]; +"238" -> "655E" [ label=" ",color="blue",arrowhead="dot" ]; +"239" -> "657E" [ label=" ",color="blue",arrowhead="dot" ]; +"240" -> "659E" [ label=" ",color="blue",arrowhead="dot" ]; +"241" -> "661E" [ label=" ",color="blue",arrowhead="dot" ]; +"242" -> "663E" [ label=" ",color="blue",arrowhead="dot" ]; +"243" -> "665E" [ label=" ",color="blue",arrowhead="dot" ]; +"244" -> "667E" [ label=" ",color="blue",arrowhead="dot" ]; +"245" -> "669E" [ label=" ",color="blue",arrowhead="dot" ]; +"246" -> "671E" [ label=" ",color="blue",arrowhead="dot" ]; +"247" -> "673E" [ label=" ",color="blue",arrowhead="dot" ]; +"248" -> "675E" [ label=" ",color="blue",arrowhead="dot" ]; +"249" -> "679E" [ label=" ",color="blue",arrowhead="dot" ]; +"250" -> "753E" [ label=" ",color="blue",arrowhead="dot" ]; +"251" -> "681E" [ label=" ",color="blue",arrowhead="dot" ]; +"252" -> "683E" [ label=" ",color="blue",arrowhead="dot" ]; +"253" -> "685E" [ label=" ",color="blue",arrowhead="dot" ]; +"254" -> "687E" [ label=" ",color="blue",arrowhead="dot" ]; +"255" -> "689E" [ label=" ",color="blue",arrowhead="dot" ]; +"256" -> "691E" [ label=" ",color="blue",arrowhead="dot" ]; +"257" -> "693E" [ label=" ",color="blue",arrowhead="dot" ]; +"258" -> "695E" [ label=" ",color="blue",arrowhead="dot" ]; +"259" -> "697E" [ label=" ",color="blue",arrowhead="dot" ]; +"260" -> "699E" [ label=" ",color="blue",arrowhead="dot" ]; +"261" -> "703E" [ label=" ",color="blue",arrowhead="dot" ]; +"262" -> "705E" [ label=" ",color="blue",arrowhead="dot" ]; +"264" -> "709E" [ label=" ",color="blue",arrowhead="dot" ]; +"265" -> "711E" [ label=" ",color="blue",arrowhead="dot" ]; +"266" -> "713E" [ label=" ",color="blue",arrowhead="dot" ]; +"267" -> "715E" [ label=" ",color="blue",arrowhead="dot" ]; +"268" -> "717E" [ label=" ",color="blue",arrowhead="dot" ]; +"269" -> "719E" [ label=" ",color="blue",arrowhead="dot" ]; +"270" -> "721E" [ label=" ",color="blue",arrowhead="dot" ]; +"272" -> "34E" [ label=" ",color="blue",arrowhead="dot" ]; +"272" -> "252E" [ label=" ",color="blue",arrowhead="dot" ]; +"272" -> "436E" [ label=" ",color="blue",arrowhead="dot" ]; +"274" -> "59E" [ label=" ",color="blue",arrowhead="dot" ]; +"274" -> "500E" [ label=" ",color="blue",arrowhead="dot" ]; +"274" -> "720E" [ label=" ",color="blue",arrowhead="dot" ]; +"275" -> "98E" [ label=" ",color="blue",arrowhead="dot" ]; +"278" -> "35E" [ label=" ",color="blue",arrowhead="dot" ]; +"278" -> "488E" [ label=" ",color="blue",arrowhead="dot" ]; +"278" -> "598E" [ label=" ",color="blue",arrowhead="dot" ]; +"278" -> "604E" [ label=" ",color="blue",arrowhead="dot" ]; +"278" -> "628E" [ label=" ",color="blue",arrowhead="dot" ]; +"279" -> "99E" [ label=" ",color="blue",arrowhead="dot" ]; +"280" -> "242E" [ label=" ",color="blue",arrowhead="dot" ]; +"280" -> "270E" [ label=" ",color="blue",arrowhead="dot" ]; +"280" -> "272E" [ label=" ",color="blue",arrowhead="dot" ]; +"280" -> "284E" [ label=" ",color="blue",arrowhead="dot" ]; +"280" -> "286E" [ label=" ",color="blue",arrowhead="dot" ]; +"280" -> "288E" [ label=" ",color="blue",arrowhead="dot" ]; +"280" -> "586E" [ label=" ",color="blue",arrowhead="dot" ]; +"280" -> "763E" [ label=" ",color="blue",arrowhead="dot" ]; +"281" -> "45E" [ label=" ",color="blue",arrowhead="dot" ]; +"281" -> "470E" [ label=" ",color="blue",arrowhead="dot" ]; +"281" -> "670E" [ label=" ",color="blue",arrowhead="dot" ]; +"281" -> "722E" [ label=" ",color="blue",arrowhead="dot" ]; +"282" -> "103E" [ label=" ",color="blue",arrowhead="dot" ]; +"283" -> "165E" [ label=" ",color="blue",arrowhead="dot" ]; +"284" -> "39E" [ label=" ",color="blue",arrowhead="dot" ]; +"284" -> "224E" [ label=" ",color="blue",arrowhead="dot" ]; +"284" -> "268E" [ label=" ",color="blue",arrowhead="dot" ]; +"284" -> "632E" [ label=" ",color="blue",arrowhead="dot" ]; +"284" -> "710E" [ label=" ",color="blue",arrowhead="dot" ]; +"285" -> "53E" [ label=" ",color="blue",arrowhead="dot" ]; +"286" -> "38E" [ label=" ",color="blue",arrowhead="dot" ]; +"286" -> "166E" [ label=" ",color="blue",arrowhead="dot" ]; +"288" -> "40E" [ label=" ",color="blue",arrowhead="dot" ]; +"288" -> "218E" [ label=" ",color="blue",arrowhead="dot" ]; +"288" -> "244E" [ label=" ",color="blue",arrowhead="dot" ]; +"288" -> "246E" [ label=" ",color="blue",arrowhead="dot" ]; +"288" -> "258E" [ label=" ",color="blue",arrowhead="dot" ]; +"288" -> "290E" [ label=" ",color="blue",arrowhead="dot" ]; +"288" -> "292E" [ label=" ",color="blue",arrowhead="dot" ]; +"288" -> "308E" [ label=" ",color="blue",arrowhead="dot" ]; +"288" -> "318E" [ label=" ",color="blue",arrowhead="dot" ]; +"288" -> "388E" [ label=" ",color="blue",arrowhead="dot" ]; +"288" -> "472E" [ label=" ",color="blue",arrowhead="dot" ]; +"288" -> "478E" [ label=" ",color="blue",arrowhead="dot" ]; +"288" -> "566E" [ label=" ",color="blue",arrowhead="dot" ]; +"288" -> "570E" [ label=" ",color="blue",arrowhead="dot" ]; +"288" -> "574E" [ label=" ",color="blue",arrowhead="dot" ]; +"288" -> "608E" [ label=" ",color="blue",arrowhead="dot" ]; +"288" -> "614E" [ label=" ",color="blue",arrowhead="dot" ]; +"288" -> "658E" [ label=" ",color="blue",arrowhead="dot" ]; +"288" -> "664E" [ label=" ",color="blue",arrowhead="dot" ]; +"288" -> "682E" [ label=" ",color="blue",arrowhead="dot" ]; +"289" -> "41E" [ label=" ",color="blue",arrowhead="dot" ]; +"289" -> "636E" [ label=" ",color="blue",arrowhead="dot" ]; +"289" -> "642E" [ label=" ",color="blue",arrowhead="dot" ]; +"289" -> "690E" [ label=" ",color="blue",arrowhead="dot" ]; +"289" -> "700E" [ label=" ",color="blue",arrowhead="dot" ]; +"290" -> "56E" [ label=" ",color="blue",arrowhead="dot" ]; +"290" -> "264E" [ label=" ",color="blue",arrowhead="dot" ]; +"290" -> "510E" [ label=" ",color="blue",arrowhead="dot" ]; +"290" -> "718E" [ label=" ",color="blue",arrowhead="dot" ]; +"291" -> "66E" [ label=" ",color="blue",arrowhead="dot" ]; +"291" -> "76E" [ label=" ",color="blue",arrowhead="dot" ]; +"291" -> "610E" [ label=" ",color="blue",arrowhead="dot" ]; +"292" -> "73E" [ label=" ",color="blue",arrowhead="dot" ]; +"293" -> "49E" [ label=" ",color="blue",arrowhead="dot" ]; +"293" -> "214E" [ label=" ",color="blue",arrowhead="dot" ]; +"293" -> "216E" [ label=" ",color="blue",arrowhead="dot" ]; +"293" -> "236E" [ label=" ",color="blue",arrowhead="dot" ]; +"293" -> "278E" [ label=" ",color="blue",arrowhead="dot" ]; +"293" -> "358E" [ label=" ",color="blue",arrowhead="dot" ]; +"293" -> "398E" [ label=" ",color="blue",arrowhead="dot" ]; +"293" -> "400E" [ label=" ",color="blue",arrowhead="dot" ]; +"293" -> "402E" [ label=" ",color="blue",arrowhead="dot" ]; +"293" -> "404E" [ label=" ",color="blue",arrowhead="dot" ]; +"293" -> "406E" [ label=" ",color="blue",arrowhead="dot" ]; +"293" -> "408E" [ label=" ",color="blue",arrowhead="dot" ]; +"293" -> "412E" [ label=" ",color="blue",arrowhead="dot" ]; +"293" -> "438E" [ label=" ",color="blue",arrowhead="dot" ]; +"293" -> "448E" [ label=" ",color="blue",arrowhead="dot" ]; +"293" -> "476E" [ label=" ",color="blue",arrowhead="dot" ]; +"293" -> "504E" [ label=" ",color="blue",arrowhead="dot" ]; +"293" -> "552E" [ label=" ",color="blue",arrowhead="dot" ]; +"293" -> "634E" [ label=" ",color="blue",arrowhead="dot" ]; +"293" -> "768E" [ label=" ",color="blue",arrowhead="dot" ]; +"295" -> "44E" [ label=" ",color="blue",arrowhead="dot" ]; +"295" -> "92E" [ label=" ",color="blue",arrowhead="dot" ]; +"295" -> "250E" [ label=" ",color="blue",arrowhead="dot" ]; +"295" -> "316E" [ label=" ",color="blue",arrowhead="dot" ]; +"295" -> "380E" [ label=" ",color="blue",arrowhead="dot" ]; +"295" -> "424E" [ label=" ",color="blue",arrowhead="dot" ]; +"295" -> "442E" [ label=" ",color="blue",arrowhead="dot" ]; +"295" -> "446E" [ label=" ",color="blue",arrowhead="dot" ]; +"295" -> "454E" [ label=" ",color="blue",arrowhead="dot" ]; +"295" -> "460E" [ label=" ",color="blue",arrowhead="dot" ]; +"295" -> "462E" [ label=" ",color="blue",arrowhead="dot" ]; +"295" -> "648E" [ label=" ",color="blue",arrowhead="dot" ]; +"295" -> "656E" [ label=" ",color="blue",arrowhead="dot" ]; +"295" -> "666E" [ label=" ",color="blue",arrowhead="dot" ]; +"295" -> "692E" [ label=" ",color="blue",arrowhead="dot" ]; +"295" -> "712E" [ label=" ",color="blue",arrowhead="dot" ]; +"296" -> "47E" [ label=" ",color="blue",arrowhead="dot" ]; +"296" -> "330E" [ label=" ",color="blue",arrowhead="dot" ]; +"296" -> "514E" [ label=" ",color="blue",arrowhead="dot" ]; +"296" -> "516E" [ label=" ",color="blue",arrowhead="dot" ]; +"296" -> "518E" [ label=" ",color="blue",arrowhead="dot" ]; +"296" -> "520E" [ label=" ",color="blue",arrowhead="dot" ]; +"296" -> "522E" [ label=" ",color="blue",arrowhead="dot" ]; +"296" -> "526E" [ label=" ",color="blue",arrowhead="dot" ]; +"296" -> "528E" [ label=" ",color="blue",arrowhead="dot" ]; +"296" -> "530E" [ label=" ",color="blue",arrowhead="dot" ]; +"296" -> "532E" [ label=" ",color="blue",arrowhead="dot" ]; +"296" -> "534E" [ label=" ",color="blue",arrowhead="dot" ]; +"296" -> "536E" [ label=" ",color="blue",arrowhead="dot" ]; +"296" -> "538E" [ label=" ",color="blue",arrowhead="dot" ]; +"296" -> "540E" [ label=" ",color="blue",arrowhead="dot" ]; +"296" -> "542E" [ label=" ",color="blue",arrowhead="dot" ]; +"296" -> "544E" [ label=" ",color="blue",arrowhead="dot" ]; +"297" -> "46E" [ label=" ",color="blue",arrowhead="dot" ]; +"297" -> "93E" [ label=" ",color="blue",arrowhead="dot" ]; +"297" -> "206E" [ label=" ",color="blue",arrowhead="dot" ]; +"297" -> "426E" [ label=" ",color="blue",arrowhead="dot" ]; +"297" -> "550E" [ label=" ",color="blue",arrowhead="dot" ]; +"297" -> "706E" [ label=" ",color="blue",arrowhead="dot" ]; +"298" -> "36E" [ label=" ",color="blue",arrowhead="dot" ]; +"298" -> "95E" [ label=" ",color="blue",arrowhead="dot" ]; +"298" -> "364E" [ label=" ",color="blue",arrowhead="dot" ]; +"298" -> "394E" [ label=" ",color="blue",arrowhead="dot" ]; +"298" -> "420E" [ label=" ",color="blue",arrowhead="dot" ]; +"298" -> "456E" [ label=" ",color="blue",arrowhead="dot" ]; +"298" -> "624E" [ label=" ",color="blue",arrowhead="dot" ]; +"299" -> "48E" [ label=" ",color="blue",arrowhead="dot" ]; +"299" -> "168E" [ label=" ",color="blue",arrowhead="dot" ]; +"299" -> "260E" [ label=" ",color="blue",arrowhead="dot" ]; +"299" -> "282E" [ label=" ",color="blue",arrowhead="dot" ]; +"299" -> "554E" [ label=" ",color="blue",arrowhead="dot" ]; +"299" -> "590E" [ label=" ",color="blue",arrowhead="dot" ]; +"299" -> "767E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "62E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "190E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "226E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "238E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "254E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "256E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "262E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "266E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "274E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "276E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "294E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "296E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "310E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "320E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "322E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "332E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "340E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "344E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "346E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "348E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "374E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "378E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "452E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "508E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "524E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "612E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "626E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "638E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "644E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "654E" [ label=" ",color="blue",arrowhead="dot" ]; +"300" -> "672E" [ label=" ",color="blue",arrowhead="dot" ]; +"302" -> "797E" [ label=" ",color="blue",arrowhead="dot" ]; +"302" -> "798E" [ label=" ",color="blue",arrowhead="dot" ]; +"303" -> "52E" [ label=" ",color="blue",arrowhead="dot" ]; +"303" -> "650E" [ label=" ",color="blue",arrowhead="dot" ]; +"304" -> "50E" [ label=" ",color="blue",arrowhead="dot" ]; +"304" -> "640E" [ label=" ",color="blue",arrowhead="dot" ]; +"304" -> "646E" [ label=" ",color="blue",arrowhead="dot" ]; +"304" -> "652E" [ label=" ",color="blue",arrowhead="dot" ]; +"306" -> "55E" [ label=" ",color="blue",arrowhead="dot" ]; +"306" -> "220E" [ label=" ",color="blue",arrowhead="dot" ]; +"306" -> "338E" [ label=" ",color="blue",arrowhead="dot" ]; +"306" -> "368E" [ label=" ",color="blue",arrowhead="dot" ]; +"306" -> "486E" [ label=" ",color="blue",arrowhead="dot" ]; +"306" -> "490E" [ label=" ",color="blue",arrowhead="dot" ]; +"306" -> "562E" [ label=" ",color="blue",arrowhead="dot" ]; +"306" -> "564E" [ label=" ",color="blue",arrowhead="dot" ]; +"306" -> "600E" [ label=" ",color="blue",arrowhead="dot" ]; +"306" -> "668E" [ label=" ",color="blue",arrowhead="dot" ]; +"306" -> "674E" [ label=" ",color="blue",arrowhead="dot" ]; +"306" -> "698E" [ label=" ",color="blue",arrowhead="dot" ]; +"307" -> "107E" [ label=" ",color="blue",arrowhead="dot" ]; +"308" -> "108E" [ label=" ",color="blue",arrowhead="dot" ]; +"309" -> "109E" [ label=" ",color="blue",arrowhead="dot" ]; +"310" -> "110E" [ label=" ",color="blue",arrowhead="dot" ]; +"311" -> "58E" [ label=" ",color="blue",arrowhead="dot" ]; +"311" -> "234E" [ label=" ",color="blue",arrowhead="dot" ]; +"311" -> "300E" [ label=" ",color="blue",arrowhead="dot" ]; +"311" -> "306E" [ label=" ",color="blue",arrowhead="dot" ]; +"311" -> "314E" [ label=" ",color="blue",arrowhead="dot" ]; +"311" -> "342E" [ label=" ",color="blue",arrowhead="dot" ]; +"311" -> "354E" [ label=" ",color="blue",arrowhead="dot" ]; +"311" -> "370E" [ label=" ",color="blue",arrowhead="dot" ]; +"311" -> "382E" [ label=" ",color="blue",arrowhead="dot" ]; +"311" -> "422E" [ label=" ",color="blue",arrowhead="dot" ]; +"311" -> "444E" [ label=" ",color="blue",arrowhead="dot" ]; +"311" -> "582E" [ label=" ",color="blue",arrowhead="dot" ]; +"311" -> "620E" [ label=" ",color="blue",arrowhead="dot" ]; +"311" -> "630E" [ label=" ",color="blue",arrowhead="dot" ]; +"311" -> "684E" [ label=" ",color="blue",arrowhead="dot" ]; +"311" -> "696E" [ label=" ",color="blue",arrowhead="dot" ]; +"311" -> "801E" [ label=" ",color="blue",arrowhead="dot" ]; +"312" -> "42E" [ label=" ",color="blue",arrowhead="dot" ]; +"312" -> "192E" [ label=" ",color="blue",arrowhead="dot" ]; +"312" -> "194E" [ label=" ",color="blue",arrowhead="dot" ]; +"312" -> "196E" [ label=" ",color="blue",arrowhead="dot" ]; +"312" -> "198E" [ label=" ",color="blue",arrowhead="dot" ]; +"312" -> "200E" [ label=" ",color="blue",arrowhead="dot" ]; +"312" -> "202E" [ label=" ",color="blue",arrowhead="dot" ]; +"312" -> "204E" [ label=" ",color="blue",arrowhead="dot" ]; +"312" -> "312E" [ label=" ",color="blue",arrowhead="dot" ]; +"312" -> "336E" [ label=" ",color="blue",arrowhead="dot" ]; +"312" -> "376E" [ label=" ",color="blue",arrowhead="dot" ]; +"312" -> "384E" [ label=" ",color="blue",arrowhead="dot" ]; +"312" -> "386E" [ label=" ",color="blue",arrowhead="dot" ]; +"312" -> "428E" [ label=" ",color="blue",arrowhead="dot" ]; +"312" -> "474E" [ label=" ",color="blue",arrowhead="dot" ]; +"312" -> "484E" [ label=" ",color="blue",arrowhead="dot" ]; +"312" -> "546E" [ label=" ",color="blue",arrowhead="dot" ]; +"312" -> "548E" [ label=" ",color="blue",arrowhead="dot" ]; +"314" -> "113E" [ label=" ",color="blue",arrowhead="dot" ]; +"315" -> "43E" [ label=" ",color="blue",arrowhead="dot" ]; +"315" -> "240E" [ label=" ",color="blue",arrowhead="dot" ]; +"315" -> "298E" [ label=" ",color="blue",arrowhead="dot" ]; +"315" -> "334E" [ label=" ",color="blue",arrowhead="dot" ]; +"315" -> "360E" [ label=" ",color="blue",arrowhead="dot" ]; +"315" -> "390E" [ label=" ",color="blue",arrowhead="dot" ]; +"315" -> "418E" [ label=" ",color="blue",arrowhead="dot" ]; +"315" -> "492E" [ label=" ",color="blue",arrowhead="dot" ]; +"315" -> "502E" [ label=" ",color="blue",arrowhead="dot" ]; +"315" -> "584E" [ label=" ",color="blue",arrowhead="dot" ]; +"315" -> "588E" [ label=" ",color="blue",arrowhead="dot" ]; +"315" -> "602E" [ label=" ",color="blue",arrowhead="dot" ]; +"315" -> "606E" [ label=" ",color="blue",arrowhead="dot" ]; +"315" -> "662E" [ label=" ",color="blue",arrowhead="dot" ]; +"316" -> "51E" [ label=" ",color="blue",arrowhead="dot" ]; +"317" -> "116E" [ label=" ",color="blue",arrowhead="dot" ]; +"318" -> "74E" [ label=" ",color="blue",arrowhead="dot" ]; +"319" -> "57E" [ label=" ",color="blue",arrowhead="dot" ]; +"319" -> "94E" [ label=" ",color="blue",arrowhead="dot" ]; +"319" -> "350E" [ label=" ",color="blue",arrowhead="dot" ]; +"319" -> "440E" [ label=" ",color="blue",arrowhead="dot" ]; +"319" -> "466E" [ label=" ",color="blue",arrowhead="dot" ]; +"319" -> "676E" [ label=" ",color="blue",arrowhead="dot" ]; +"320" -> "60E" [ label=" ",color="blue",arrowhead="dot" ]; +"320" -> "366E" [ label=" ",color="blue",arrowhead="dot" ]; +"320" -> "434E" [ label=" ",color="blue",arrowhead="dot" ]; +"320" -> "458E" [ label=" ",color="blue",arrowhead="dot" ]; +"320" -> "618E" [ label=" ",color="blue",arrowhead="dot" ]; +"321" -> "72E" [ label=" ",color="blue",arrowhead="dot" ]; +"321" -> "362E" [ label=" ",color="blue",arrowhead="dot" ]; +"321" -> "372E" [ label=" ",color="blue",arrowhead="dot" ]; +"321" -> "572E" [ label=" ",color="blue",arrowhead="dot" ]; +"322" -> "54E" [ label=" ",color="blue",arrowhead="dot" ]; +"322" -> "222E" [ label=" ",color="blue",arrowhead="dot" ]; +"322" -> "302E" [ label=" ",color="blue",arrowhead="dot" ]; +"322" -> "556E" [ label=" ",color="blue",arrowhead="dot" ]; +"322" -> "558E" [ label=" ",color="blue",arrowhead="dot" ]; +"323" -> "37E" [ label=" ",color="blue",arrowhead="dot" ]; +"323" -> "208E" [ label=" ",color="blue",arrowhead="dot" ]; +"323" -> "210E" [ label=" ",color="blue",arrowhead="dot" ]; +"323" -> "352E" [ label=" ",color="blue",arrowhead="dot" ]; +"323" -> "450E" [ label=" ",color="blue",arrowhead="dot" ]; +"323" -> "568E" [ label=" ",color="blue",arrowhead="dot" ]; +"323" -> "576E" [ label=" ",color="blue",arrowhead="dot" ]; +"323" -> "686E" [ label=" ",color="blue",arrowhead="dot" ]; +"324" -> "228E" [ label=" ",color="blue",arrowhead="dot" ]; +"324" -> "248E" [ label=" ",color="blue",arrowhead="dot" ]; +"324" -> "304E" [ label=" ",color="blue",arrowhead="dot" ]; +"324" -> "468E" [ label=" ",color="blue",arrowhead="dot" ]; +"324" -> "578E" [ label=" ",color="blue",arrowhead="dot" ]; +"324" -> "660E" [ label=" ",color="blue",arrowhead="dot" ]; +"324" -> "688E" [ label=" ",color="blue",arrowhead="dot" ]; +"324" -> "694E" [ label=" ",color="blue",arrowhead="dot" ]; +"324" -> "714E" [ label=" ",color="blue",arrowhead="dot" ]; +"324" -> "766E" [ label=" ",color="blue",arrowhead="dot" ]; +"325" -> "97E" [ label=" ",color="blue",arrowhead="dot" ]; +"325" -> "506E" [ label=" ",color="blue",arrowhead="dot" ]; +"326" -> "61E" [ label=" ",color="blue",arrowhead="dot" ]; +"326" -> "175E" [ label=" ",color="blue",arrowhead="dot" ]; +"326" -> "482E" [ label=" ",color="blue",arrowhead="dot" ]; +"328" -> "75E" [ label=" ",color="blue",arrowhead="dot" ]; +"328" -> "580E" [ label=" ",color="blue",arrowhead="dot" ]; +"329" -> "96E" [ label=" ",color="blue",arrowhead="dot" ]; +"330" -> "100E" [ label=" ",color="blue",arrowhead="dot" ]; +"330" -> "170E" [ label=" ",color="blue",arrowhead="dot" ]; +"333" -> "63E" [ label=" ",color="blue",arrowhead="dot" ]; +"333" -> "67E" [ label=" ",color="blue",arrowhead="dot" ]; +"333" -> "68E" [ label=" ",color="blue",arrowhead="dot" ]; +"333" -> "69E" [ label=" ",color="blue",arrowhead="dot" ]; +"333" -> "70E" [ label=" ",color="blue",arrowhead="dot" ]; +"333" -> "71E" [ label=" ",color="blue",arrowhead="dot" ]; +"333" -> "802E" [ label=" ",color="blue",arrowhead="dot" ]; +"333" -> "793E" [ label=" ",color="blue",arrowhead="dot" ]; +"334" -> "64E" [ label=" ",color="blue",arrowhead="dot" ]; +"334" -> "81E" [ label=" ",color="blue",arrowhead="dot" ]; +"334" -> "82E" [ label=" ",color="blue",arrowhead="dot" ]; +"334" -> "83E" [ label=" ",color="blue",arrowhead="dot" ]; +"334" -> "84E" [ label=" ",color="blue",arrowhead="dot" ]; +"334" -> "85E" [ label=" ",color="blue",arrowhead="dot" ]; +"334" -> "86E" [ label=" ",color="blue",arrowhead="dot" ]; +"334" -> "87E" [ label=" ",color="blue",arrowhead="dot" ]; +"334" -> "88E" [ label=" ",color="blue",arrowhead="dot" ]; +"334" -> "89E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "1E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "2E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "3E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "4E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "5E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "6E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "7E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "8E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "9E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "10E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "11E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "12E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "13E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "14E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "15E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "16E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "17E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "18E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "19E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "20E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "21E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "22E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "23E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "24E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "25E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "26E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "27E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "28E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "29E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "30E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "31E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "65E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "119E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "150E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "176E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "743E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "744E" [ label=" ",color="blue",arrowhead="dot" ]; +"336" -> "764E" [ label=" ",color="blue",arrowhead="dot" ]; +"337" -> "120E" [ label=" ",color="blue",arrowhead="dot" ]; +"337" -> "121E" [ label=" ",color="blue",arrowhead="dot" ]; +"337" -> "122E" [ label=" ",color="blue",arrowhead="dot" ]; +"337" -> "123E" [ label=" ",color="blue",arrowhead="dot" ]; +"337" -> "124E" [ label=" ",color="blue",arrowhead="dot" ]; +"337" -> "125E" [ label=" ",color="blue",arrowhead="dot" ]; +"337" -> "126E" [ label=" ",color="blue",arrowhead="dot" ]; +"337" -> "127E" [ label=" ",color="blue",arrowhead="dot" ]; +"337" -> "128E" [ label=" ",color="blue",arrowhead="dot" ]; +"337" -> "129E" [ label=" ",color="blue",arrowhead="dot" ]; +"337" -> "130E" [ label=" ",color="blue",arrowhead="dot" ]; +"337" -> "131E" [ label=" ",color="blue",arrowhead="dot" ]; +"337" -> "132E" [ label=" ",color="blue",arrowhead="dot" ]; +"337" -> "133E" [ label=" ",color="blue",arrowhead="dot" ]; +"337" -> "134E" [ label=" ",color="blue",arrowhead="dot" ]; +"337" -> "135E" [ label=" ",color="blue",arrowhead="dot" ]; +"337" -> "136E" [ label=" ",color="blue",arrowhead="dot" ]; +"337" -> "137E" [ label=" ",color="blue",arrowhead="dot" ]; +"337" -> "138E" [ label=" ",color="blue",arrowhead="dot" ]; +"339" -> "151E" [ label=" ",color="blue",arrowhead="dot" ]; +"339" -> "153E" [ label=" ",color="blue",arrowhead="dot" ]; +"339" -> "154E" [ label=" ",color="blue",arrowhead="dot" ]; +"339" -> "155E" [ label=" ",color="blue",arrowhead="dot" ]; +"339" -> "156E" [ label=" ",color="blue",arrowhead="dot" ]; +"339" -> "157E" [ label=" ",color="blue",arrowhead="dot" ]; +"339" -> "158E" [ label=" ",color="blue",arrowhead="dot" ]; +"339" -> "159E" [ label=" ",color="blue",arrowhead="dot" ]; +"339" -> "160E" [ label=" ",color="blue",arrowhead="dot" ]; +"339" -> "161E" [ label=" ",color="blue",arrowhead="dot" ]; +"339" -> "162E" [ label=" ",color="blue",arrowhead="dot" ]; +"347" -> "139E" [ label=" ",color="blue",arrowhead="dot" ]; +"347" -> "795E" [ label=" ",color="blue",arrowhead="dot" ]; +"348" -> "799E" [ label=" ",color="blue",arrowhead="dot" ]; +"348" -> "800E" [ label=" ",color="blue",arrowhead="dot" ]; +"349" -> "141E" [ label=" ",color="blue",arrowhead="dot" ]; +"350" -> "142E" [ label=" ",color="blue",arrowhead="dot" ]; +"350" -> "678E" [ label=" ",color="blue",arrowhead="dot" ]; +"351" -> "143E" [ label=" ",color="blue",arrowhead="dot" ]; +"351" -> "232E" [ label=" ",color="blue",arrowhead="dot" ]; +"351" -> "680E" [ label=" ",color="blue",arrowhead="dot" ]; +"351" -> "704E" [ label=" ",color="blue",arrowhead="dot" ]; +"352" -> "144E" [ label=" ",color="blue",arrowhead="dot" ]; +"352" -> "432E" [ label=" ",color="blue",arrowhead="dot" ]; +"353" -> "145E" [ label=" ",color="blue",arrowhead="dot" ]; +"354" -> "146E" [ label=" ",color="blue",arrowhead="dot" ]; +"354" -> "396E" [ label=" ",color="blue",arrowhead="dot" ]; +"355" -> "147E" [ label=" ",color="blue",arrowhead="dot" ]; +"356" -> "148E" [ label=" ",color="blue",arrowhead="dot" ]; +"357" -> "149E" [ label=" ",color="blue",arrowhead="dot" ]; +"358" -> "167E" [ label=" ",color="blue",arrowhead="dot" ]; +"359" -> "169E" [ label=" ",color="blue",arrowhead="dot" ]; +"360" -> "171E" [ label=" ",color="blue",arrowhead="dot" ]; +"361" -> "172E" [ label=" ",color="blue",arrowhead="dot" ]; +"362" -> "173E" [ label=" ",color="blue",arrowhead="dot" ]; +"363" -> "174E" [ label=" ",color="blue",arrowhead="dot" ]; +"364" -> "101E" [ label=" ",color="blue",arrowhead="dot" ]; +"365" -> "102E" [ label=" ",color="blue",arrowhead="dot" ]; +"367" -> "104E" [ label=" ",color="blue",arrowhead="dot" ]; +"368" -> "105E" [ label=" ",color="blue",arrowhead="dot" ]; +"369" -> "106E" [ label=" ",color="blue",arrowhead="dot" ]; +"374" -> "111E" [ label=" ",color="blue",arrowhead="dot" ]; +"375" -> "112E" [ label=" ",color="blue",arrowhead="dot" ]; +"377" -> "114E" [ label=" ",color="blue",arrowhead="dot" ]; +"378" -> "115E" [ label=" ",color="blue",arrowhead="dot" ]; +"380" -> "117E" [ label=" ",color="blue",arrowhead="dot" ]; +"380" -> "392E" [ label=" ",color="blue",arrowhead="dot" ]; +"381" -> "118E" [ label=" ",color="blue",arrowhead="dot" ]; +"382" -> "177E" [ label=" ",color="blue",arrowhead="dot" ]; +"382" -> "178E" [ label=" ",color="blue",arrowhead="dot" ]; +"382" -> "179E" [ label=" ",color="blue",arrowhead="dot" ]; +"382" -> "180E" [ label=" ",color="blue",arrowhead="dot" ]; +"382" -> "181E" [ label=" ",color="blue",arrowhead="dot" ]; +"382" -> "182E" [ label=" ",color="blue",arrowhead="dot" ]; +"382" -> "183E" [ label=" ",color="blue",arrowhead="dot" ]; +"382" -> "184E" [ label=" ",color="blue",arrowhead="dot" ]; +"382" -> "185E" [ label=" ",color="blue",arrowhead="dot" ]; +"382" -> "186E" [ label=" ",color="blue",arrowhead="dot" ]; +"382" -> "187E" [ label=" ",color="blue",arrowhead="dot" ]; +"382" -> "188E" [ label=" ",color="blue",arrowhead="dot" ]; +"383" -> "730E" [ label=" ",color="blue",arrowhead="dot" ]; +"383" -> "732E" [ label=" ",color="blue",arrowhead="dot" ]; +"383" -> "741E" [ label=" ",color="blue",arrowhead="dot" ]; +"383" -> "765E" [ label=" ",color="blue",arrowhead="dot" ]; +"383" -> "796E" [ label=" ",color="blue",arrowhead="dot" ]; +"384" -> "726E" [ label=" ",color="blue",arrowhead="dot" ]; +"384" -> "728E" [ label=" ",color="blue",arrowhead="dot" ]; +"384" -> "742E" [ label=" ",color="blue",arrowhead="dot" ]; +"385" -> "328E" [ label=" ",color="blue",arrowhead="dot" ]; +"385" -> "496E" [ label=" ",color="blue",arrowhead="dot" ]; +"385" -> "594E" [ label=" ",color="blue",arrowhead="dot" ]; +"385" -> "622E" [ label=" ",color="blue",arrowhead="dot" ]; +"385" -> "754E" [ label=" ",color="blue",arrowhead="dot" ]; +"385" -> "755E" [ label=" ",color="blue",arrowhead="dot" ]; +"385" -> "756E" [ label=" ",color="blue",arrowhead="dot" ]; +"385" -> "757E" [ label=" ",color="blue",arrowhead="dot" ]; +"385" -> "758E" [ label=" ",color="blue",arrowhead="dot" ]; +"385" -> "759E" [ label=" ",color="blue",arrowhead="dot" ]; +"385" -> "760E" [ label=" ",color="blue",arrowhead="dot" ]; +"385" -> "761E" [ label=" ",color="blue",arrowhead="dot" ]; +"385" -> "762E" [ label=" ",color="blue",arrowhead="dot" ]; +"1E" -> "34E" [ color="purple",arrowhead="none" ]; +"2E" -> "35E" [ color="purple",arrowhead="none" ]; +"3E" -> "36E" [ color="purple",arrowhead="none" ]; +"4E" -> "37E" [ color="purple",arrowhead="none" ]; +"5E" -> "38E" [ color="purple",arrowhead="none" ]; +"6E" -> "39E" [ color="purple",arrowhead="none" ]; +"7E" -> "40E" [ color="purple",arrowhead="none" ]; +"9E" -> "41E" [ color="purple",arrowhead="none" ]; +"10E" -> "42E" [ color="purple",arrowhead="none" ]; +"11E" -> "43E" [ color="purple",arrowhead="none" ]; +"12E" -> "44E" [ color="purple",arrowhead="none" ]; +"13E" -> "45E" [ color="purple",arrowhead="none" ]; +"14E" -> "46E" [ color="purple",arrowhead="none" ]; +"15E" -> "47E" [ color="purple",arrowhead="none" ]; +"16E" -> "48E" [ color="purple",arrowhead="none" ]; +"49E" -> "17E" [ color="purple",arrowhead="none" ]; +"18E" -> "50E" [ color="purple",arrowhead="none" ]; +"19E" -> "51E" [ color="purple",arrowhead="none" ]; +"20E" -> "52E" [ color="purple",arrowhead="none" ]; +"21E" -> "53E" [ color="purple",arrowhead="none" ]; +"22E" -> "54E" [ color="purple",arrowhead="none" ]; +"23E" -> "55E" [ color="purple",arrowhead="none" ]; +"24E" -> "56E" [ color="purple",arrowhead="none" ]; +"25E" -> "57E" [ color="purple",arrowhead="none" ]; +"26E" -> "58E" [ color="purple",arrowhead="none" ]; +"27E" -> "59E" [ color="purple",arrowhead="none" ]; +"28E" -> "60E" [ color="purple",arrowhead="none" ]; +"29E" -> "61E" [ color="purple",arrowhead="none" ]; +"30E" -> "62E" [ color="purple",arrowhead="none" ]; +"31E" -> "63E" [ color="purple",arrowhead="none" ]; +"64E" -> "65E" [ color="purple",arrowhead="none" ]; +"66E" -> "8E" [ color="purple",arrowhead="none" ]; +"71E" -> "76E" [ color="purple",arrowhead="none" ]; +"67E" -> "72E" [ color="purple",arrowhead="none" ]; +"68E" -> "73E" [ color="purple",arrowhead="none" ]; +"69E" -> "74E" [ color="purple",arrowhead="none" ]; +"70E" -> "75E" [ color="purple",arrowhead="none" ]; +"81E" -> "92E" [ color="purple",arrowhead="none" ]; +"82E" -> "93E" [ color="purple",arrowhead="none" ]; +"83E" -> "94E" [ color="purple",arrowhead="none" ]; +"84E" -> "95E" [ color="purple",arrowhead="none" ]; +"85E" -> "96E" [ color="purple",arrowhead="none" ]; +"86E" -> "97E" [ color="purple",arrowhead="none" ]; +"87E" -> "98E" [ color="purple",arrowhead="none" ]; +"88E" -> "99E" [ color="purple",arrowhead="none" ]; +"89E" -> "100E" [ color="purple",arrowhead="none" ]; +"101E" -> "120E" [ color="purple",arrowhead="none" ]; +"102E" -> "121E" [ color="purple",arrowhead="none" ]; +"103E" -> "122E" [ color="purple",arrowhead="none" ]; +"104E" -> "123E" [ color="purple",arrowhead="none" ]; +"105E" -> "124E" [ color="purple",arrowhead="none" ]; +"106E" -> "125E" [ color="purple",arrowhead="none" ]; +"107E" -> "126E" [ color="purple",arrowhead="none" ]; +"108E" -> "127E" [ color="purple",arrowhead="none" ]; +"109E" -> "128E" [ color="purple",arrowhead="none" ]; +"110E" -> "129E" [ color="purple",arrowhead="none" ]; +"111E" -> "130E" [ color="purple",arrowhead="none" ]; +"112E" -> "131E" [ color="purple",arrowhead="none" ]; +"113E" -> "132E" [ color="purple",arrowhead="none" ]; +"114E" -> "133E" [ color="purple",arrowhead="none" ]; +"115E" -> "134E" [ color="purple",arrowhead="none" ]; +"116E" -> "135E" [ color="purple",arrowhead="none" ]; +"117E" -> "136E" [ color="purple",arrowhead="none" ]; +"118E" -> "137E" [ color="purple",arrowhead="none" ]; +"119E" -> "138E" [ color="purple",arrowhead="none" ]; +"139E" -> "151E" [ color="purple",arrowhead="none" ]; +"141E" -> "153E" [ color="purple",arrowhead="none" ]; +"142E" -> "154E" [ color="purple",arrowhead="none" ]; +"143E" -> "155E" [ color="purple",arrowhead="none" ]; +"144E" -> "156E" [ color="purple",arrowhead="none" ]; +"145E" -> "157E" [ color="purple",arrowhead="none" ]; +"146E" -> "158E" [ color="purple",arrowhead="none" ]; +"147E" -> "159E" [ color="purple",arrowhead="none" ]; +"148E" -> "160E" [ color="purple",arrowhead="none" ]; +"149E" -> "161E" [ color="purple",arrowhead="none" ]; +"150E" -> "162E" [ color="purple",arrowhead="none" ]; +"165E" -> "177E" [ color="purple",arrowhead="none" ]; +"166E" -> "178E" [ color="purple",arrowhead="none" ]; +"167E" -> "179E" [ color="purple",arrowhead="none" ]; +"168E" -> "180E" [ color="purple",arrowhead="none" ]; +"169E" -> "181E" [ color="purple",arrowhead="none" ]; +"170E" -> "182E" [ color="purple",arrowhead="none" ]; +"171E" -> "183E" [ color="purple",arrowhead="none" ]; +"172E" -> "184E" [ color="purple",arrowhead="none" ]; +"173E" -> "185E" [ color="purple",arrowhead="none" ]; +"174E" -> "186E" [ color="purple",arrowhead="none" ]; +"175E" -> "187E" [ color="purple",arrowhead="none" ]; +"176E" -> "188E" [ color="purple",arrowhead="none" ]; +"189E" -> "190E" [ color="purple",arrowhead="none" ]; +"191E" -> "192E" [ color="purple",arrowhead="none" ]; +"193E" -> "194E" [ color="purple",arrowhead="none" ]; +"195E" -> "196E" [ color="purple",arrowhead="none" ]; +"197E" -> "198E" [ color="purple",arrowhead="none" ]; +"199E" -> "200E" [ color="purple",arrowhead="none" ]; +"201E" -> "202E" [ color="purple",arrowhead="none" ]; +"203E" -> "204E" [ color="purple",arrowhead="none" ]; +"205E" -> "206E" [ color="purple",arrowhead="none" ]; +"207E" -> "208E" [ color="purple",arrowhead="none" ]; +"209E" -> "210E" [ color="purple",arrowhead="none" ]; +"412E" -> "211E" [ color="purple",arrowhead="none" ]; +"214E" -> "213E" [ color="purple",arrowhead="none" ]; +"216E" -> "215E" [ color="purple",arrowhead="none" ]; +"217E" -> "218E" [ color="purple",arrowhead="none" ]; +"219E" -> "220E" [ color="purple",arrowhead="none" ]; +"221E" -> "222E" [ color="purple",arrowhead="none" ]; +"223E" -> "224E" [ color="purple",arrowhead="none" ]; +"225E" -> "226E" [ color="purple",arrowhead="none" ]; +"227E" -> "228E" [ color="purple",arrowhead="none" ]; +"231E" -> "232E" [ color="purple",arrowhead="none" ]; +"233E" -> "234E" [ color="purple",arrowhead="none" ]; +"236E" -> "235E" [ color="purple",arrowhead="none" ]; +"237E" -> "238E" [ color="purple",arrowhead="none" ]; +"239E" -> "240E" [ color="purple",arrowhead="none" ]; +"241E" -> "242E" [ color="purple",arrowhead="none" ]; +"243E" -> "244E" [ color="purple",arrowhead="none" ]; +"245E" -> "246E" [ color="purple",arrowhead="none" ]; +"247E" -> "248E" [ color="purple",arrowhead="none" ]; +"249E" -> "250E" [ color="purple",arrowhead="none" ]; +"251E" -> "252E" [ color="purple",arrowhead="none" ]; +"253E" -> "254E" [ color="purple",arrowhead="none" ]; +"255E" -> "256E" [ color="purple",arrowhead="none" ]; +"257E" -> "258E" [ color="purple",arrowhead="none" ]; +"259E" -> "260E" [ color="purple",arrowhead="none" ]; +"261E" -> "262E" [ color="purple",arrowhead="none" ]; +"263E" -> "264E" [ color="purple",arrowhead="none" ]; +"265E" -> "266E" [ color="purple",arrowhead="none" ]; +"267E" -> "268E" [ color="purple",arrowhead="none" ]; +"269E" -> "270E" [ color="purple",arrowhead="none" ]; +"271E" -> "272E" [ color="purple",arrowhead="none" ]; +"273E" -> "274E" [ color="purple",arrowhead="none" ]; +"275E" -> "276E" [ color="purple",arrowhead="none" ]; +"278E" -> "277E" [ color="purple",arrowhead="none" ]; +"279E" -> "767E" [ color="purple",arrowhead="none" ]; +"281E" -> "282E" [ color="purple",arrowhead="none" ]; +"283E" -> "284E" [ color="purple",arrowhead="none" ]; +"285E" -> "286E" [ color="purple",arrowhead="none" ]; +"768E" -> "287E" [ color="purple",arrowhead="none" ]; +"289E" -> "290E" [ color="purple",arrowhead="none" ]; +"291E" -> "292E" [ color="purple",arrowhead="none" ]; +"293E" -> "294E" [ color="purple",arrowhead="none" ]; +"295E" -> "296E" [ color="purple",arrowhead="none" ]; +"297E" -> "298E" [ color="purple",arrowhead="none" ]; +"299E" -> "300E" [ color="purple",arrowhead="none" ]; +"301E" -> "302E" [ color="purple",arrowhead="none" ]; +"303E" -> "304E" [ color="purple",arrowhead="none" ]; +"305E" -> "306E" [ color="purple",arrowhead="none" ]; +"307E" -> "308E" [ color="purple",arrowhead="none" ]; +"309E" -> "310E" [ color="purple",arrowhead="none" ]; +"311E" -> "312E" [ color="purple",arrowhead="none" ]; +"313E" -> "314E" [ color="purple",arrowhead="none" ]; +"315E" -> "316E" [ color="purple",arrowhead="none" ]; +"317E" -> "318E" [ color="purple",arrowhead="none" ]; +"319E" -> "320E" [ color="purple",arrowhead="none" ]; +"321E" -> "322E" [ color="purple",arrowhead="none" ]; +"327E" -> "800E" [ color="purple",arrowhead="none" ]; +"329E" -> "330E" [ color="purple",arrowhead="none" ]; +"331E" -> "332E" [ color="purple",arrowhead="none" ]; +"333E" -> "334E" [ color="purple",arrowhead="none" ]; +"335E" -> "336E" [ color="purple",arrowhead="none" ]; +"337E" -> "338E" [ color="purple",arrowhead="none" ]; +"339E" -> "340E" [ color="purple",arrowhead="none" ]; +"341E" -> "342E" [ color="purple",arrowhead="none" ]; +"343E" -> "344E" [ color="purple",arrowhead="none" ]; +"345E" -> "346E" [ color="purple",arrowhead="none" ]; +"347E" -> "348E" [ color="purple",arrowhead="none" ]; +"349E" -> "350E" [ color="purple",arrowhead="none" ]; +"351E" -> "352E" [ color="purple",arrowhead="none" ]; +"353E" -> "354E" [ color="purple",arrowhead="none" ]; +"412E" -> "355E" [ color="purple",arrowhead="none" ]; +"357E" -> "358E" [ color="purple",arrowhead="none" ]; +"359E" -> "360E" [ color="purple",arrowhead="none" ]; +"361E" -> "362E" [ color="purple",arrowhead="none" ]; +"363E" -> "364E" [ color="purple",arrowhead="none" ]; +"365E" -> "366E" [ color="purple",arrowhead="none" ]; +"367E" -> "368E" [ color="purple",arrowhead="none" ]; +"369E" -> "370E" [ color="purple",arrowhead="none" ]; +"371E" -> "372E" [ color="purple",arrowhead="none" ]; +"373E" -> "374E" [ color="purple",arrowhead="none" ]; +"375E" -> "376E" [ color="purple",arrowhead="none" ]; +"377E" -> "378E" [ color="purple",arrowhead="none" ]; +"379E" -> "380E" [ color="purple",arrowhead="none" ]; +"381E" -> "382E" [ color="purple",arrowhead="none" ]; +"383E" -> "384E" [ color="purple",arrowhead="none" ]; +"385E" -> "386E" [ color="purple",arrowhead="none" ]; +"387E" -> "388E" [ color="purple",arrowhead="none" ]; +"389E" -> "390E" [ color="purple",arrowhead="none" ]; +"391E" -> "392E" [ color="purple",arrowhead="none" ]; +"393E" -> "394E" [ color="purple",arrowhead="none" ]; +"395E" -> "396E" [ color="purple",arrowhead="none" ]; +"397E" -> "398E" [ color="purple",arrowhead="none" ]; +"399E" -> "400E" [ color="purple",arrowhead="none" ]; +"402E" -> "401E" [ color="purple",arrowhead="none" ]; +"404E" -> "403E" [ color="purple",arrowhead="none" ]; +"406E" -> "405E" [ color="purple",arrowhead="none" ]; +"408E" -> "407E" [ color="purple",arrowhead="none" ]; +"236E" -> "409E" [ color="purple",arrowhead="none" ]; +"412E" -> "411E" [ color="purple",arrowhead="none" ]; +"412E" -> "413E" [ color="purple",arrowhead="none" ]; +"278E" -> "415E" [ color="purple",arrowhead="none" ]; +"417E" -> "418E" [ color="purple",arrowhead="none" ]; +"419E" -> "420E" [ color="purple",arrowhead="none" ]; +"421E" -> "422E" [ color="purple",arrowhead="none" ]; +"423E" -> "424E" [ color="purple",arrowhead="none" ]; +"425E" -> "426E" [ color="purple",arrowhead="none" ]; +"427E" -> "428E" [ color="purple",arrowhead="none" ]; +"431E" -> "432E" [ color="purple",arrowhead="none" ]; +"433E" -> "434E" [ color="purple",arrowhead="none" ]; +"435E" -> "436E" [ color="purple",arrowhead="none" ]; +"438E" -> "437E" [ color="purple",arrowhead="none" ]; +"439E" -> "440E" [ color="purple",arrowhead="none" ]; +"441E" -> "442E" [ color="purple",arrowhead="none" ]; +"443E" -> "444E" [ color="purple",arrowhead="none" ]; +"445E" -> "446E" [ color="purple",arrowhead="none" ]; +"448E" -> "447E" [ color="purple",arrowhead="none" ]; +"449E" -> "450E" [ color="purple",arrowhead="none" ]; +"451E" -> "452E" [ color="purple",arrowhead="none" ]; +"453E" -> "454E" [ color="purple",arrowhead="none" ]; +"455E" -> "456E" [ color="purple",arrowhead="none" ]; +"457E" -> "458E" [ color="purple",arrowhead="none" ]; +"459E" -> "460E" [ color="purple",arrowhead="none" ]; +"461E" -> "462E" [ color="purple",arrowhead="none" ]; +"236E" -> "463E" [ color="purple",arrowhead="none" ]; +"465E" -> "466E" [ color="purple",arrowhead="none" ]; +"467E" -> "468E" [ color="purple",arrowhead="none" ]; +"469E" -> "470E" [ color="purple",arrowhead="none" ]; +"471E" -> "472E" [ color="purple",arrowhead="none" ]; +"473E" -> "474E" [ color="purple",arrowhead="none" ]; +"476E" -> "475E" [ color="purple",arrowhead="none" ]; +"477E" -> "478E" [ color="purple",arrowhead="none" ]; +"479E" -> "358E" [ color="purple",arrowhead="none" ]; +"481E" -> "482E" [ color="purple",arrowhead="none" ]; +"483E" -> "484E" [ color="purple",arrowhead="none" ]; +"485E" -> "486E" [ color="purple",arrowhead="none" ]; +"487E" -> "488E" [ color="purple",arrowhead="none" ]; +"489E" -> "490E" [ color="purple",arrowhead="none" ]; +"491E" -> "492E" [ color="purple",arrowhead="none" ]; +"495E" -> "795E" [ color="purple",arrowhead="none" ]; +"499E" -> "500E" [ color="purple",arrowhead="none" ]; +"501E" -> "502E" [ color="purple",arrowhead="none" ]; +"504E" -> "503E" [ color="purple",arrowhead="none" ]; +"505E" -> "506E" [ color="purple",arrowhead="none" ]; +"507E" -> "508E" [ color="purple",arrowhead="none" ]; +"509E" -> "510E" [ color="purple",arrowhead="none" ]; +"412E" -> "511E" [ color="purple",arrowhead="none" ]; +"513E" -> "514E" [ color="purple",arrowhead="none" ]; +"515E" -> "516E" [ color="purple",arrowhead="none" ]; +"517E" -> "518E" [ color="purple",arrowhead="none" ]; +"519E" -> "520E" [ color="purple",arrowhead="none" ]; +"521E" -> "522E" [ color="purple",arrowhead="none" ]; +"523E" -> "524E" [ color="purple",arrowhead="none" ]; +"525E" -> "526E" [ color="purple",arrowhead="none" ]; +"527E" -> "528E" [ color="purple",arrowhead="none" ]; +"529E" -> "530E" [ color="purple",arrowhead="none" ]; +"531E" -> "532E" [ color="purple",arrowhead="none" ]; +"533E" -> "534E" [ color="purple",arrowhead="none" ]; +"535E" -> "536E" [ color="purple",arrowhead="none" ]; +"537E" -> "538E" [ color="purple",arrowhead="none" ]; +"539E" -> "540E" [ color="purple",arrowhead="none" ]; +"541E" -> "542E" [ color="purple",arrowhead="none" ]; +"543E" -> "544E" [ color="purple",arrowhead="none" ]; +"545E" -> "546E" [ color="purple",arrowhead="none" ]; +"547E" -> "548E" [ color="purple",arrowhead="none" ]; +"549E" -> "550E" [ color="purple",arrowhead="none" ]; +"551E" -> "552E" [ color="purple",arrowhead="none" ]; +"553E" -> "554E" [ color="purple",arrowhead="none" ]; +"555E" -> "556E" [ color="purple",arrowhead="none" ]; +"557E" -> "558E" [ color="purple",arrowhead="none" ]; +"278E" -> "559E" [ color="purple",arrowhead="none" ]; +"561E" -> "562E" [ color="purple",arrowhead="none" ]; +"563E" -> "564E" [ color="purple",arrowhead="none" ]; +"565E" -> "566E" [ color="purple",arrowhead="none" ]; +"567E" -> "568E" [ color="purple",arrowhead="none" ]; +"569E" -> "570E" [ color="purple",arrowhead="none" ]; +"571E" -> "572E" [ color="purple",arrowhead="none" ]; +"573E" -> "574E" [ color="purple",arrowhead="none" ]; +"575E" -> "576E" [ color="purple",arrowhead="none" ]; +"577E" -> "578E" [ color="purple",arrowhead="none" ]; +"579E" -> "580E" [ color="purple",arrowhead="none" ]; +"581E" -> "582E" [ color="purple",arrowhead="none" ]; +"583E" -> "584E" [ color="purple",arrowhead="none" ]; +"585E" -> "586E" [ color="purple",arrowhead="none" ]; +"587E" -> "588E" [ color="purple",arrowhead="none" ]; +"589E" -> "590E" [ color="purple",arrowhead="none" ]; +"593E" -> "594E" [ color="purple",arrowhead="none" ]; +"597E" -> "598E" [ color="purple",arrowhead="none" ]; +"599E" -> "600E" [ color="purple",arrowhead="none" ]; +"601E" -> "602E" [ color="purple",arrowhead="none" ]; +"603E" -> "604E" [ color="purple",arrowhead="none" ]; +"605E" -> "606E" [ color="purple",arrowhead="none" ]; +"607E" -> "608E" [ color="purple",arrowhead="none" ]; +"609E" -> "610E" [ color="purple",arrowhead="none" ]; +"611E" -> "612E" [ color="purple",arrowhead="none" ]; +"613E" -> "614E" [ color="purple",arrowhead="none" ]; +"615E" -> "358E" [ color="purple",arrowhead="none" ]; +"617E" -> "618E" [ color="purple",arrowhead="none" ]; +"619E" -> "620E" [ color="purple",arrowhead="none" ]; +"621E" -> "622E" [ color="purple",arrowhead="none" ]; +"623E" -> "624E" [ color="purple",arrowhead="none" ]; +"625E" -> "626E" [ color="purple",arrowhead="none" ]; +"627E" -> "628E" [ color="purple",arrowhead="none" ]; +"629E" -> "630E" [ color="purple",arrowhead="none" ]; +"631E" -> "632E" [ color="purple",arrowhead="none" ]; +"634E" -> "633E" [ color="purple",arrowhead="none" ]; +"635E" -> "636E" [ color="purple",arrowhead="none" ]; +"637E" -> "638E" [ color="purple",arrowhead="none" ]; +"639E" -> "640E" [ color="purple",arrowhead="none" ]; +"641E" -> "642E" [ color="purple",arrowhead="none" ]; +"643E" -> "644E" [ color="purple",arrowhead="none" ]; +"645E" -> "646E" [ color="purple",arrowhead="none" ]; +"647E" -> "648E" [ color="purple",arrowhead="none" ]; +"649E" -> "650E" [ color="purple",arrowhead="none" ]; +"651E" -> "652E" [ color="purple",arrowhead="none" ]; +"653E" -> "654E" [ color="purple",arrowhead="none" ]; +"655E" -> "656E" [ color="purple",arrowhead="none" ]; +"657E" -> "658E" [ color="purple",arrowhead="none" ]; +"659E" -> "660E" [ color="purple",arrowhead="none" ]; +"661E" -> "662E" [ color="purple",arrowhead="none" ]; +"663E" -> "664E" [ color="purple",arrowhead="none" ]; +"665E" -> "666E" [ color="purple",arrowhead="none" ]; +"667E" -> "668E" [ color="purple",arrowhead="none" ]; +"669E" -> "670E" [ color="purple",arrowhead="none" ]; +"671E" -> "672E" [ color="purple",arrowhead="none" ]; +"673E" -> "674E" [ color="purple",arrowhead="none" ]; +"675E" -> "676E" [ color="purple",arrowhead="none" ]; +"679E" -> "680E" [ color="purple",arrowhead="none" ]; +"681E" -> "682E" [ color="purple",arrowhead="none" ]; +"683E" -> "684E" [ color="purple",arrowhead="none" ]; +"685E" -> "686E" [ color="purple",arrowhead="none" ]; +"687E" -> "688E" [ color="purple",arrowhead="none" ]; +"689E" -> "690E" [ color="purple",arrowhead="none" ]; +"691E" -> "692E" [ color="purple",arrowhead="none" ]; +"693E" -> "694E" [ color="purple",arrowhead="none" ]; +"695E" -> "696E" [ color="purple",arrowhead="none" ]; +"697E" -> "698E" [ color="purple",arrowhead="none" ]; +"699E" -> "700E" [ color="purple",arrowhead="none" ]; +"703E" -> "704E" [ color="purple",arrowhead="none" ]; +"705E" -> "706E" [ color="purple",arrowhead="none" ]; +"709E" -> "710E" [ color="purple",arrowhead="none" ]; +"711E" -> "712E" [ color="purple",arrowhead="none" ]; +"713E" -> "714E" [ color="purple",arrowhead="none" ]; +"715E" -> "398E" [ color="purple",arrowhead="none" ]; +"717E" -> "718E" [ color="purple",arrowhead="none" ]; +"719E" -> "720E" [ color="purple",arrowhead="none" ]; +"721E" -> "722E" [ color="purple",arrowhead="none" ]; +"725E" -> "726E" [ color="purple",arrowhead="none" ]; +"727E" -> "728E" [ color="purple",arrowhead="none" ]; +"729E" -> "730E" [ color="purple",arrowhead="none" ]; +"731E" -> "732E" [ color="purple",arrowhead="none" ]; +"741E" -> "743E" [ color="purple",arrowhead="none" ]; +"742E" -> "744E" [ color="purple",arrowhead="none" ]; +"745E" -> "754E" [ color="purple",arrowhead="none" ]; +"746E" -> "755E" [ color="purple",arrowhead="none" ]; +"747E" -> "756E" [ color="purple",arrowhead="none" ]; +"748E" -> "757E" [ color="purple",arrowhead="none" ]; +"749E" -> "758E" [ color="purple",arrowhead="none" ]; +"750E" -> "759E" [ color="purple",arrowhead="none" ]; +"751E" -> "760E" [ color="purple",arrowhead="none" ]; +"752E" -> "761E" [ color="purple",arrowhead="none" ]; +"753E" -> "762E" [ color="purple",arrowhead="none" ]; +"763E" -> "764E" [ color="purple",arrowhead="none" ]; +"765E" -> "766E" [ color="purple",arrowhead="none" ]; +"770E" -> "783E" [ color="purple",arrowhead="none" ]; +"770E" -> "784E" [ color="purple",arrowhead="none" ]; +"769E" -> "785E" [ color="purple",arrowhead="none" ]; +"769E" -> "786E" [ color="purple",arrowhead="none" ]; +"769E" -> "787E" [ color="purple",arrowhead="none" ]; +"770E" -> "788E" [ color="purple",arrowhead="none" ]; +"770E" -> "789E" [ color="purple",arrowhead="none" ]; +"769E" -> "790E" [ color="purple",arrowhead="none" ]; +"770E" -> "791E" [ color="purple",arrowhead="none" ]; +"769E" -> "792E" [ color="purple",arrowhead="none" ]; +"793E" -> "769E" [ color="purple",arrowhead="none" ]; +"769E" -> "784E" [ color="purple",arrowhead="none" ]; +"770E" -> "785E" [ color="purple",arrowhead="none" ]; +"788E" -> "787E" [ color="purple",arrowhead="none" ]; +"770E" -> "792E" [ color="purple",arrowhead="none" ]; +"798E" -> "799E" [ color="purple",arrowhead="none" ]; +"796E" -> "797E" [ color="purple",arrowhead="none" ]; +"793E" -> "789E" [ color="purple",arrowhead="none" ]; +"783E" -> "787E" [ color="purple",arrowhead="none" ]; +"784E" -> "792E" [ color="purple",arrowhead="none" ]; +"787E" -> "789E" [ color="purple",arrowhead="none" ]; +"769E" -> "791E" [ color="purple",arrowhead="none" ]; +"802E" -> "801E" [ color="purple",arrowhead="none" ]; +} diff --git a/examples/graph/graphviz/data/unix.gv.txt b/examples/graph/graphviz/data/unix.gv.txt new file mode 100644 index 00000000..431ab655 --- /dev/null +++ b/examples/graph/graphviz/data/unix.gv.txt @@ -0,0 +1,55 @@ +/* courtesy Ian Darwin and Geoff Collyer, Softquad Inc. */ +digraph unix { + size="6,6"; + node [color=lightblue, style=filled]; + "5th Edition" -> "6th Edition"; + "5th Edition" -> "PWB 1.0"; + "6th Edition" -> "LSX"; + "6th Edition" -> "1 BSD"; + "6th Edition" -> "Mini Unix"; + "6th Edition" -> "Wollongong"; + "6th Edition" -> "Interdata"; + "Interdata" -> "Unix/TS 3.0"; + "Interdata" -> "PWB 2.0"; + "Interdata" -> "7th Edition"; + "7th Edition" -> "8th Edition"; + "7th Edition" -> "32V"; + "7th Edition" -> "V7M"; + "7th Edition" -> "Ultrix-11"; + "7th Edition" -> "Xenix"; + "7th Edition" -> "UniPlus+"; + "V7M" -> "Ultrix-11"; + "8th Edition" -> "9th Edition"; + "1 BSD" -> "2 BSD"; + "2 BSD" -> "2.8 BSD"; + "2.8 BSD" -> "Ultrix-11"; + "2.8 BSD" -> "2.9 BSD"; + "32V" -> "3 BSD"; + "3 BSD" -> "4 BSD"; + "4 BSD" -> "4.1 BSD"; + "4.1 BSD" -> "4.2 BSD"; + "4.1 BSD" -> "2.8 BSD"; + "4.1 BSD" -> "8th Edition"; + "4.2 BSD" -> "4.3 BSD"; + "4.2 BSD" -> "Ultrix-32"; + "PWB 1.0" -> "PWB 1.2"; + "PWB 1.0" -> "USG 1.0"; + "PWB 1.2" -> "PWB 2.0"; + "USG 1.0" -> "CB Unix 1"; + "USG 1.0" -> "USG 2.0"; + "CB Unix 1" -> "CB Unix 2"; + "CB Unix 2" -> "CB Unix 3"; + "CB Unix 3" -> "Unix/TS++"; + "CB Unix 3" -> "PDP-11 Sys V"; + "USG 2.0" -> "USG 3.0"; + "USG 3.0" -> "Unix/TS 3.0"; + "PWB 2.0" -> "Unix/TS 3.0"; + "Unix/TS 1.0" -> "Unix/TS 3.0"; + "Unix/TS 3.0" -> "TS 4.0"; + "Unix/TS++" -> "TS 4.0"; + "CB Unix 3" -> "TS 4.0"; + "TS 4.0" -> "System V.0"; + "System V.0" -> "System V.2"; + "System V.2" -> "System V.3"; +} + diff --git a/examples/graph/graphviz/data/world.gv.txt b/examples/graph/graphviz/data/world.gv.txt new file mode 100644 index 00000000..3e6e4e37 --- /dev/null +++ b/examples/graph/graphviz/data/world.gv.txt @@ -0,0 +1,67 @@ +digraph world { +size="7,7"; + {rank=same; S8 S24 S1 S35 S30;} + {rank=same; T8 T24 T1 T35 T30;} + {rank=same; 43 37 36 10 2;} + {rank=same; 25 9 38 40 13 17 12 18;} + {rank=same; 26 42 11 3 33 19 39 14 16;} + {rank=same; 4 31 34 21 41 28 20;} + {rank=same; 27 5 22 32 29 15;} + {rank=same; 6 23;} + {rank=same; 7;} + + S8 -> 9; + S24 -> 25; + S24 -> 27; + S1 -> 2; + S1 -> 10; + S35 -> 43; + S35 -> 36; + S30 -> 31; + S30 -> 33; + 9 -> 42; + 9 -> T1; + 25 -> T1; + 25 -> 26; + 27 -> T24; + 2 -> {3 ; 16 ; 17 ; T1 ; 18} + 10 -> { 11 ; 14 ; T1 ; 13; 12;} + 31 -> T1; + 31 -> 32; + 33 -> T30; + 33 -> 34; + 42 -> 4; + 26 -> 4; + 3 -> 4; + 16 -> 15; + 17 -> 19; + 18 -> 29; + 11 -> 4; + 14 -> 15; + 37 -> {39 ; 41 ; 38 ; 40;} + 13 -> 19; + 12 -> 29; + 43 -> 38; + 43 -> 40; + 36 -> 19; + 32 -> 23; + 34 -> 29; + 39 -> 15; + 41 -> 29; + 38 -> 4; + 40 -> 19; + 4 -> 5; + 19 -> {21 ; 20 ; 28;} + 5 -> {6 ; T35 ; 23;} + 21 -> 22; + 20 -> 15; + 28 -> 29; + 6 -> 7; + 15 -> T1; + 22 -> T35; + 22 -> 23; + 29 -> T30; + 7 -> T8; + 23 -> T24; + 23 -> T1; +} diff --git a/examples/graph/graphviz/graphviz_gallery.html b/examples/graph/graphviz/graphviz_gallery.html new file mode 100644 index 00000000..c5d96ed2 --- /dev/null +++ b/examples/graph/graphviz/graphviz_gallery.html @@ -0,0 +1,88 @@ + + + Graph | Graphviz Gallery + + + + + + + + + + +

+ The following examples are unmodified copies from the + Graphviz Gallery. +

+

+ Note that some style attributes of Graphviz are not supported by vis.js, + and that vis.js offers options not supported by Graphviz (which could make + some examples look much nicer). +

+ +

+ + +

+ +
+ + + diff --git a/examples/graph/graphviz/screenshots/fsm.png b/examples/graph/graphviz/screenshots/fsm.png new file mode 100644 index 0000000000000000000000000000000000000000..544b8ed68b6d36cdd3d40283f219f23533b27d40 GIT binary patch literal 70809 zcmcG$Wmr~g*ETw71SFMi6%a`gK~h4nNGa)*1_5bl5RjIIh$11<4bt5prP3f>N_WQ| zx31@X_IK>>&--I@EDv0_Fy}R|Ys5Lmd5#&ZC@*^vj~Wj_kc$uQODiJ?h9`ocE8$|p zC)A%!q~P0y=l7pFAP7Dg>JJ+7KAsXj#Ch>R?jFuKHV!TW1&?b{CVWKo;-1C}DO+o6 z6Pp)^l)Z_;3ln2TXY&_kjIs~p6xDqQDG-Dac_1yJ;xf82?y3=OS}V38Oe}dH7mv9p zBZxpN^K$Z!hYHuZJ}N1FcXA8=RB9pnWp&shMqXi=P5I;RPY27-a=*xG<$lW)o_d_k ze3M+3q+bokH>Er(iP?;l@$P+3ug?$e-S%NbTkCb)RgQLkkg$KTyL$kgg;*wmE1S&8P{++31EqS$kLd*6@{{LjkQX+8!81vNwj z1qpqSOuj24gZ<;j4{Cn_XJ=>sfB+^A4uXV)gatfZt&9N+6?OHd?(VRQa?;ZM_!kJU z{d~IbO7}Z%ZEZ!y$Nx+!qM)M-%gA7Z-z&K@M*?5tA(zFOKXJWDNC=nva62yBJvlk~ z-7Ry{PoF+f?!j$Q_stOQ?Cg|MR(|7Z|Mu4}v#xi%7-(o{ROs*h)dJ7X> zBBbs9!-tJ|I#mS@i}D1NJO~o`_U)_YW@$`pY{TWj-2GFxo&?d53Wvp+FoB7BhhEV( znpgiW%Dv<3*TyW>?4<8zQ;Um%sgGirIXH42>4xa$x4q}LEU=xdmFbOn`}Wh9FPGxt z;)YADX$JH4B0Nuz_+8_F{?z{b`7NC*Y@E8TqC7onAvLe={d?$7P)8giZ%bL@@kdLEkm+I6cw zKRd3rgU8|sLLG+uCq*`528M`FpO_C04-MwO#^{KJ=jY`Sj+NQsAk{lR9=#KGw((m$ z-dzp^i}8Q;%5Zb0g^hzl`q?v<)-akO{VJU*r|GTvPK_^SB($`&9D7GU$H#fie_UOe zsG+%Y=MLOzDh%Ar7%k_3gv1fOLOVQ;&-7D92JZLo-w$BrxrSTh0g^snzdl6j*FE>E zo|U=J1hW#;(h}4Ur*2Pdl)G*}!wryp9Cx#2Cf{!Ki#g&wH)lL?AFfH>_?m%4iPgV0 z0G~oK<-2~%>&x#%T#E*(ORKUSD7ba4>GB)hpE2cA+4cQej~-EO&uMX9Ui{Ez9>&AHtqccTPq)R2x$>- zwJL*&3I`mAg{}s$Kt|GF9G^6v4CZa!gp*#r+%DJ%v z7nNj>F`R7;Q=>R~td^&JA@1=jSaptW4K;k&9?w zso$7x(h`YK&h*#JZEa)l3I#)&9L9AtgmmvJ-gn z9~Zl6U-6UnNbLM%o9kmqF@J4s?R`197F(}lt>Mv8$@D%Zad8Gc&%8qd5jkqA%0eVIO&H&B%`cM>MzOE^HF%ns$hF}mp@S< zRe2Np%3qf*5($t*3y`#%OtzhF3_!dcmj|D=T;ZJkjva^(S3M zhcATa?CtG0ma_9_R?8-3JUnV#>)yN}MZD9~S^XQ|1_l#>XDf*As-(1uii&m{Z2bD3 zBDW?CyS+WL`7rg3z*PuDeheg0^Vee@cE#TzyMFz8E_QPjt9{|ZL%knquuW7PHnxMH4GyhQYDLv=;TS#E+}0)qcG~ggnwoIhy6*1o?zi7BL8= zFx`f^j_9bEn1QJZ*t%qJtf;6ch!U&h>x)EQ2N?8TC!1-Q z(x0%=3a$+d40MZ`;=SqS{QcZ{s<^CdF%0|)we)^hOms8?Yz+1rH%J&5Z1c`cOiY;g z`7gu6-oJnU*X{Lmuk$m+TPl#Sq;hp!RRWR_a<|U&6hX>tCv65NyQsKWYuxMXOeTyv;CqVfEO^U( zd3hOmc|t=&LmsPPo}JY(ikO%f2z1TPlOBP5racHk&Z&t>Lo>U60RtVKkvt@Mz(Pq; z(OZ_@^>fR1&EdiajVh;H*R(!-3NHPTB9m{+yFsC$($Akik3K%#=~F-u28KlPDnHV{ z_NSE2quSAvC?2uB*jrY4`sUiBoTc4-@M_D!oQAX0W4pDV6)f5I-gZ{w%lUQTg+^^> zN8%TgiKnNh+k1LifA^(p5qL5&F_qiT<2~zskHx^iFg!dw)fj+}ctfDh(J1^h;-T9!U4gIIEv);s*{2Zid{yippsPCY|J{G<$Y-_T0(oRc&|w$IW)iE!qXnW-nsI@u02I=0B$2U=ArDm+yDucp5h3p9~>m# zUg*X^Rz`~3X4)oe+y#)?A7uY=zmjQNIA>gZ{N=)RyP4)-%3Ef{;MLZ;(fRzALwPL+ zo3oouMB=xqx(Bk=?dIA^`~w4xnuAEH<6zVNL}2cX3z+DT^_aQ1@?`7OlNEz5-%z`o zs%!vv-7isq$Za!T8IWIllr>^4b~r~CB+XpCJE&Ei{GSW(?L4?jnxj)ys$RVq8A<$a z#3}bYb;}-ecXMODd6V?sy?c?J^I-|%4hsY~`S=Q5HVs1}X#REbPlSPD(W=>MyX|%! z-L4R6H)bQm4ePzp_DeieR4yT?UHtCQ6i6g%V`CG|7yKXdiY3Fvd?)5nd1qL$k3}JY zAXDY_71{6t-hbCsiSvX)L0nv%L#Ohei}nnFz>-whKdh`hfUQGeTs5jAx4v?*M_A%W z&JkEFFXZm0UcdOBmRMXC5fvR_+wb_&bx&89p2iQZ2)M1i(oS3NxZU_Bzz9eXiD44| zhQN<&^g}~^L(9t?|GkjMuju<%H7e{)@--`cP+;>9@>72bVGBd<`R|P-6RWC(hn9J4nNq;R9xD06__@UliSqjjtLS8I3UhYdigYxR~hW6&2uO zK4At1;o;#3QlZ_`3Kw58MxpXuHTGPzEoC|+N%1L8$)Lt~CuiP0S697$vAsOrBuwm? zaSUviJL>2N`glO(o#DIBxbG(6c!id#-@S`K2ul8LHca{NX1{%s(a*H6%(*vb*`1tk zezV?{5}Eqx2>)3}Yq{=~G~8z(X~iCyRbn8CZ$`g;^WXCjHH*XIZ|BTwN=E0rRJOa& zreh*`P#%mR@`g0+v{qpe!XuI#R+Lj;RfNpEI)blVc0>?4RZ*^=IV}@UG*?7T2woZa zuJHb7BQ!#9*|2|Rd-V2QrOW%umtaFmizJkf`6$3+d1wgLXOvAy@ zIFdD(dS@t=Tjt-4A;kJh{m(zkifLyhuLa>++3C9mh*c{9lgPxx2*AF#vEg#8MlBIR zZt*qgUk+|P!Dz7-l`gG+Zp&L8zsj={yOfYxA#`E$bM$6gX4b=q5CKcYmnno5Esh5| z%2b9jL7Q7&ML#`MXBNJ?>~ApEB6@coDPl6E1ztv6>7=X*VLt+7=4dVaxj9l6rpN#Dk;GTW8PZq=S64R;&p72I7~N|Z_QsjCyWHDqS~gyW4N zACxgR`n;U9(>Yr)n@`^`h@ekK=&8=HsxhNlLYK4a6fSqhn2M9I9qMxKJ_x8)*R86q z7D4{Uge~4bw5%ViQW=hXdV#g@Vgl7jdLN5T;jKbNZ}Tf3iRTQ6Tr&xKJ>BpF9_r** zy|O5wMi`?zT%^eUIx;_@2VA%wjG+9h|G|1tt(wlfWzVodI3>*ru3Q*e-K1i;=;5fY zBc0skx`G0piGDCtBBbqrM5#_VTxWO1Mo#VN>OPaR2({*5a4Q~9R`R?CtzdG)Odu1HqXx%D4AIFcGJ-DhoYzJ0Lr+$3Us zufrzcUr!3-m^4|zrkXR*CQoK1#m5RFjFK?MuddP?PhoutH5@u3vfKZpx+3^*cn@V_ zgH6`$aS}~)H+9hd=uau|7#lXgp*F|+q2;fr_3iekE6<&sWx;1{pZ|>(ORM0fg{vC; z+9r~ZDZdM+oiZ%3GQ&S_qMST%Ms*B&>4Og;Nhh00gxeP{Mu7AB* zQX=1VooRw_!SQTjEPqXDos*OEBEkbT)5P502k9THsXV=n=+6X+joW{$4W}0FBFVeS zw3qN>?_G!PB|I#MAS2xq&r;HUP;Z#0VKZy#f6o7`UKSADj4eUGr}%Tw`8X@_Z^@4;;9R$iCw~3Am=D(7 znZ8@$^i6^Hr>;&%WU%^vUbseIxh>6|v-fW-LgP_8E?rQ8%_i6%NjcZc-$KR-!j-QIuqiBbIq(;Hp>5K~KVV5TB|HK{720d8Ji5+pJ*vOWaT5DJ9W zJbe&AKNhYk#ZuY;j$sv96%>H(f8MIGI~F-o!{Rnl>miJ?7^vsKOm!dsdqUlWmnm7f zFRag#Ro-HSh`^kTxGOj&K0s~Uo9Jk!n1_Wgek^KQ$+sVa5uh~LGS3;r73nYdzN1E0|H_+gz%K~P3}`D zbWrP|qwBt)13!y`5Z*s$G>r=E$O?Hir+ypeyn3eTy7B1IBPlmGp_7x7;gML`*lF0(uSaoz830=?Ob z3bWkYVtB~G_S?P<+M^ARk5XEx4R1C*w0^d#nc)O?QLXu5@G>t^Nw;$N=YHD~XI3y> zm)M)=wJZ5`>5D4+j^l1)QwodW$;$b?M9;O{HSsTXqTye&pJyatKat8cjdF)#|G%X< zfyZBalCHZcr(*cN{B!Y0aC1RniS>?)PA>VC)-tnQ`2%=8J&>lbj{M3S^$jRe%b<^bZZUj-2$Ma5~jt7RQP!forYZ^aUlN=FU z0UZ?-X5oKu^(BvJ?;@*bhyls>FnR$>f^xf65kk)@dfEMJv*O~XWaq22tDe zk97j!M$ezG_=#WrJe9mLiH>}|)N)^UQ@mXHpNRbPBj$;N6|?NNA_}~mg-WQ132(j~KelpZi*aTZ`T_%Zfeg=C9VdQt5QnP5O zv?h45dsQdjOEDnjZbwrAWnrrIGY;pzTR-a7kIUI}lOK(7Kv>w^+=L?i-+NrHv&s1^ zN!0SuZH|2C)8|k0ug7-TRF;x#7GouPYj1DZm)=XNq7(UOP5jFs5OHQgp@rLy6CN+e zC{J?C4Py(w_f9Xy6J*@5x$96x5bmKP{G$4#NmwyESMpnXI>{}2?b+T01)gW;*QuQL z2qT4dEl-P=33V-s{GMtGR*HH*ijrF&P&t*^v(M!kC%^xqcMzlPMW1o%f#MbYo) z%qX^m0^C%=iv)uBFYe-iXsqcGE`!&IJC71?&sG@c^tFE z9}`KN^%n=lS8mj@z9~GPH%iaQz@gV~;l6ea>%(npUzrq%7cXwT< zD%jPyEOI=m@8pjO_$&ugxhkUs+aad1vr*SWH0#Ft)aW6fU}PovVy`g8DAkmx17)}V5->G$IPM{P~fgzPTLy~pFm!lLn$s`Jqg zQ)zplI)rdbSGfNVx!$6Rgsw&W^Lu|Hc~g4bDYrq+GK84vrK{3G0!af@p)vK#C2Wd= zQ#Gg5)n$5qyb^ow_#ghbW)z+=3(exl_wVt%yu1#MkFPK?BG4`n&HGe5-Th9jtgx`8 zrFn6(l`ML}@!;jI5Z#hR*uYlq`Y9T^&&7o^*BkV%hNL^YyMm{^q6cd!*UD9%qwAfT zaOrwF=MQ{|f!t(ofAdFQ9~uG;4roH?$Na4vMrjVjy8GW%*&pptFaiFO8kbf(bZe1B zdsP|C(=X=_>58pZH-u09OFKt~#50MDGDpMHso%p1yvH9y2{o9j6$r^1JHp+?<(;3t zh6W|%zvuq{Z-H;1wt5wIihc z>{0N$xAlU_>vIoUF(T1tsy@Br<8&7;T!7MZ7AN3O))1mT@D%~Ht^Ol(Tu}H5CiY*j z2xzsvMls;$40wh*58}jkGmfCJun@WtHXG&8zEjR@j=Cb-6>&#M=)GSOKuB0zRW~LB z{&^7%k+>Kdk~B1wvSW|7=T$yVy68$F!%j&Dv5$99PmARKLN+A2o?{=5fD?w8mdUDnqvwpZesYFa3N z-|*2Gu8EbS{KedSmx47TYe(>fyb+-{@0I3*K544hfM3`wa_{@u4*2h-d}rk5CV~?G zBE0~X1XzI!RJgZpeHk#iGm4+|V^F+c-^|DeLo0bxHj&exa*o0mE8AIrdx_%tOrR}n z;dxl>89Y|Rd;PfWk9{mJVV`4(ir#Rvz znqko8kxEufg614*cPe))tE!BCe13ppKVnV)6s#$G>?%tedt5QDOGkx7os};e-}c=8 zb}#66%F)!$yhZ$h!e!ktPaLS&3XiB*)y{J?;K**?yvaz6OPymnqzheyu-1!v%R@wY zd3m@OF9x*k-9dED@zJ6*d?_Z5NExb6u4dgT+Z@naH0U@NHj6Sk7TKYMWlP&N1V1aQ z@VrNe{92!PpKQ~q^AtVm*R>)plC$=-Wwd>0X2#ao*tpUEM1gnZ58hLfUF{f}89%i! zvmg*n(=ye9(o5gW%bivz9pzu1=f62$UK)$FL^Q8Iq3DKlkr!@*zWej#LC*Gh`{D2% zv?EcUn=w6xmP(~Vkx9=(4^J%x53EUFZxu%td*L&)^!(niW1!m?Zy(*gj%QEwX|Az% zV~cKZ>hL`NkTvhpyc8p`e)E&wFK#0DDhegt&gLeWGWxzyZ#-5VEGQ_zp5+68573xn z4q}v*s2WxjCl9amvl2c>r`u2VduJ)KqTG}50Oi+zATxPK&A#?_eG#Z5NNa7GPtq0D z)Ua!GiA+sRMRvYPQ3^Y8BzPW~<6?3K9)JFPb!D^!U)XuA*&7W5p^Q}lU?#1v&sb_R z?lzgf2yH0fOSmRnW-p5D|8$`9^a6@Xqx^Yt%h>7~`%JwL#^#Sl+|$(?7hXD*lWOXW zg{S5!r#$qiI&>Hru9sNqUlew$!`N~jBX>ZoSxOjjAlo<@)Ba>U=pUR1N8}r6F+uRk|VL>?gl>-GJ7>KHgik+|f2S zzYaV{R9sxJ^;oIF>Cx`5p?tmQwvO)Zdk-JtL0!?6oPUMh^T6QoJ03I!&jTiU_Z40O z`k#e`<^~1^lp-!XdD<0*-|J0zD50!-U0yEe(DM6)+ep{a@#r?)wqI1ls*3uyxU}6T)KE9Z+K9tV@ToegxeM<;MN5;xe+vfg$pnQ50aH;*~KD}4J zN#V-6qj9|*FtobSMhAhsx5&}jQ`9in=)-=9`=Tv*U7%Hfq_n(FPin zWF(ahpFuqqTQ%puzm}pcB#v0Kw&SX zN7Iy;Ikq?^tcv?Gm7zL5*FmT0FQMq4o^Dz^*4p-`@r{8)Xtm)2JSeIK+}?g4ID@j5 zZB-Q&ePHGU?dNb+*e{ESi10k?qU=f#rIDAHQ_v*6bP3be);3<$og51b3l|R$9qIZg zOkr49E*I^2OF+u_5pXWdSFVuI(2S*RJ~N`fiCu>;uuOTP3CK(FWidJ0nq>BA{2zzb zi%?TeZi7{}jtB>KQXY*`p0!?#HaIuu*B$qy5!SOS{5te|Vc}I$662*yml&bA&ad9W z1JV`;I4ZNTsi`TJ2s@yW5i`Xw%da1Woq0@qXxT2|xwyFKe@l{J34`k2Kl(=*aH7w85lEESR|wq!u%*7cyjV` z+i(%=7I+P4&I6eSzA2YXgkTfVheEOuIbJDV*z|)Rm#dZO zJ5*s;EgqNDvKJp0;Uqbr*7jl$rsc|!cyNy{{_5amD;YT#v=o-=Z}a)HhEF*~j)ob( z`H5FTD$KCfc)!F5O$+cgrXs9XLI-2N7v36d^}~T-F}3qm>l&-eFa9rd>o}L=|BY@X zoqcZ)G7w@st+N?1{rW#WwJ`eqot;~O4Jon_z`!L*_;tn9mpTpIQpz6S#ICJz-)ClG zYA}Q+YsIFzk;=-YCXvmzfngT`xmf9mDJ(=|6=x^G5$8d{9U#mWu=NNEPKyM#%bLzdtVvX>cY> zdqY3@VXB3?aL2s;cEz)v_}~Z8ERLE}Rbwl-7hoOJUGwbFiQA67UMJ}AG(?kbV+HoxT}M!GMLFxOSSm5PBTc?)9me7Z|_ne1tZP zx5^lG2bwI5GSZ@c?e78#E^F@DXMfF~J+_@_>utNKXm^U|@3gnE<$+1^-GSGl5noPT z#9kcgaA-$J+1SxNWZ$u-Umj8!So5Ud6yS8$KiXcqcHwLzP<*N@j?ZOxK%LipZ{=CU zHDcU?=hKoa<5d(TB_$|c6Z991q*QHQrTt+)K37&&jx0X5yij_}srS;s%IeqZ;19x_P)k$)v>19@6En>c9)&P2G|c26renzFUW1nLJ%lvboQuM zqz#9MM{m1T=c(a4wp@gc$ka)k)f~e_@X(+aQSwIrqs_hkh;xocpZ-+BRV=-KHfC%Va7!WMweD_H)seztBtKKbi~Eo9fK!) zH# zl2+e)hpK&|_&amM`q2QhHapL&h>`Q-fIB;AciW?RDfh+mXBo84Uo-ICE)zaL^M)SM zYumw3&}OR_oW2jG55fpiFQwhQ;xKA{JP2>C(@lX<@$sSY@w6z-#&Chbudy<2&`Bt1 zXaud-9uu1O#G@g=Ubk!S65!%`YjC_$%f2Tefky8-7e(H?zwp700_kM3yrWhNWGe4i-+4=RS?ws`Zp=0~*SUdk%0Ix0>K z!1E-2dKB1oK0Quq=bBA2;(>_{H6F#kW zA@f7r&c8%-xg;-5=G?Qf<4k*n{lZ1U{*gwF8~Oi-PTlRd5<$aFp}7t+)SzF9)Z%VfwkEDr&RuGR5mG_#;z z@Kv_(ODcX!0_Rhm$?4f$2LUIBerRvZH7bN92#7A+tgn(VE*MCYzqwmIT~j|8?!%s8APvk>JDCI#vvvL#5M2LPDF;Y?DXOkeZsG z4*=HhpMU-VNkklQ-&6o_Zl5267Rp>pU(k~_H8mBNh{%g^Tu*qcUy=8r&CqOdQ_OI5 zcH@qchucZ-Ti-X-bGke|GZlyTOi_sODf$gh(a73b`j{;H_H9C=rbL!mhXu0koB$$4O{1j7sWJ%=u0I@&P+FDgWd@SQq0oB9={W?rAPF8 z6GX|y&(_AP&?sXQeqGn4x^nMv5T%I)9bv-2&adN?$Ei)?^VEW)_#0pb@qefej#roK zoOtAJGZ*=`qzY71^|@7+{ZCu)=}L78{{ZnLW8x9vyIQHQpb5L}KpMxlLid^cPQ-mS z?-?hLh)ORO`S>7Cty2B{wefd+rt%>nC1oxDr+`B=tNZK{r<6e^VZdwZ@~>7TGvnKX z`+Z9U!;V{o7LN5e=d1pAiOyV5$-C2_C112*J(kgMb@mwhFs%MyN9xE!6Z~*E?m4J-%FHJY_;J z?qQ&9#JEf@p^K646;=l(R8$kUoEjJ!JTb}5<~-@NdHE)@g*8s|<%l& zeVxD?_YUcfC3C(vq$u=O$w^5{@;EF!21U)((e5&x*aXNkBcbAlicx@CU^u#Q@-4;3 z>F;gWtY=RG{7m^p4I5)a1S|@d=jbxBcU{cCT}JW_l<#JFU^Zlxkz^Uo#_}}Wt8>v9z2bszH!!g2hzgxeL~+_-N5ekE}6sK z8|1=HEn(RRvftp-Z8N(@hl!M{x@C?p{+8?8?>luM#V^>tOtJ0Ht!Emmb#J#O7p!~A z%-}NZYFJDcL}^`ZI4i@A;@c5~g;H^&Zgp0#n@OuT24f-m-iukdU3-*0&*Bs%xQB)O ztVp$TqS;;jfFOlmPAwy2GDD57%N_-}G$~y{wION9XqB=toD!@3eBZpc*{m!P!cdMF zmq`AEee?99NX`MiRX>HR#GmF?FZI(t!MX*43wUksChM>fwy(XCJ!hQccWm^BHIVuU zs&ky0+Rf%0V84PNqR|jsT)OeIsq{R{Z-dhNZeo(YL`KK;J!;-ki?@b7lmjg12M^== zmk0#y3P&}PRhEg#m|Gt;^~^qAQ$iK5KtWa~{lSi=){j*)EH690Jyh06m5DiWDn3_L z&l+|7`CwbEv1ObFDX?s!S$L=|8=82^0x;`R;xR?-QKz=q+RvNf>1<+w5wUX8uqz@j zeMxQ~)s1;1ywR(zFP@R*q@pp7_?W-blp?jFsH__(%DS!(wXBNjARmnt>;UZkY_nGu zW6|ZQunXZD+c{)u_n^81O*5z}jX-e+()j8OSfjBWx?e-RkIHJ&4{GAV1r`)h&oGd# z(^l?wcI#|wCS|`QH@Xw4E=!+_jm!YPvvut)cU=`l6Z0pnpZma%ZM%70Y3r`9zN{sD za;9+Zz>VtmmW;CFu1bU9NIK5b{S&MEszLwmxldigr;_9ElMZIbz6Cwr+&4Q(AT9K$ zYr8ak_qd~^9e6R0I=((RGH> zv_iH8x({UDfc=5uxC{IQHybK+6Ws7zox4iT2+Y~dlAbJfd^xH=-6Seg_b$He8S##o*HdHRwR-D) z8h+^Mw-?Z<896z|yQpp(NBHGB!r|!rmaTDA=`q`Z$T!(M$ZT6ndYs#|pI`Mp zwwKYO*L3Gk+t~AzSD;@GQ-Ol%Rpn^Y1H(A?<(V)|wy%!m&x^5_mh`+xE`b4d8qsQ1 z2ZAgFWZ6b}2XUTPi;qwv8w8$ebH7VW%2hMlwxhUo20!McSE%JRB}6-;%oeipFk`vs%GKd$y|AD7s<>MP+CzmsFEXbv?TJ2@T28*hvSch;ulCkbRQ7wbB@{~d#q?JS zA#Xqp72mU4ENikE!5VYDkXRsEfs)89)G-#b|jP40jf)u8ic=`OM z)5^Nu^m1M8aGuAI$v+az%VXE`A7%4Rjm6_p64dvoAK6(kIJSeN8)S#jULN6;RF;%P z2Rh^Z>RQJV16Lbq_Sr> zItGCk7Iaa&2<_I=>R&G>`zFcwSw%(Z?(S#p#eFfUsjbTPLia&{dp7*zhEVAK14*fi zdfpo_w!6J5fmg17tq$vYk{V8q>)-_+dRqI3bg^&VphFjslR`A&^=n@hc58e4*tZZ$ z)y~0+gBsQ)+#Nm<06=#*n0;5*3LC>8SPSbKtvRFmJ`OA|48riZZq3Lo%uwr<8 z@p7?JJM-gWL#H;I1eRzPIg9;T=iZa2Dk}b9sf^dI1qgt85Y;G7gSgXebhZ~??boNC z~jZQN(=jqVpZlB?CPU# z>v$-}qlj_O!!Vir=-f_@2O-BECR#X@I1IAkRNql*rSau>n5$+4s`uxh9LS#@`UpLp zuJ`=eEmO|6jtb0C`Y>YwJr0>NtyW)HyAZ<-Pokjc;o*|a<#?3J@Rs_y3}K9Z(xcvL z0)V@;=L*;QH8G(5r{7)d0S49f!H0wE#tnSxur#fR)v6DfRi+Rdqo>!`+MpyQdHhjm zK;$|B%9Wo8wyvYO12#aV;a_*%|M_RgptnO9u+(@8`Ag7KNG%l#gE3;140^+{7H&tJ zQXXaWeNIb5|3x(}BKKY^d}czP8YXX6-ab+X(DmJ~B`-nem$V(-ZDWh)D79>TXG@-z zI)Z^yJyhW)}iMaK5K%6l?0GKS-oj-qQG<64`1r|vKwu(7dG z58!lqeLcdq_VASessQE>(GjguERUdT)O*pI>`QIco!Qv&$dT=O9ZCx1qsxrx_L_-Y zb03o}i(S;S@>5FyjV4M#G4+9tY1(&X=kB|=H&9~|O6xcN3Kays&Z_UM#GUPIZ#Vr& zeT0UfrsqIwU+K8q6#+N=GrxAj{!=+2sM?;F7qp%XD+-XHLc9_XxFQ}f{?;y5CjnD^>ApR7mF5|SNc;M%wWt!G;aona)>1~IM|%{L@h_-yBRYD^qaBp z$?q}}PkpehohBvx>#O6y`U@&)kFjCC_f5*~B9|xC0_-jE%(icO7p+r8DC3LUKjuqH zX+NgZG=~^}jnnPP90ft;!o_d$^%7gmL*r-9Bw3c@I{lklTW6pFhJ2e5Z2j`()>Rgk z#>q(rU=UUcS3wjmz1k$9p~m%13Z(!_h={zK%FkFC8cJ~W+BMW{TlIrK(Jf!to|LBTd)UPy0r66oc~%#*Im-SA)gWz^ z$Q^)AUaeAOl}k!#ixEyaJ`))})L`TZJ*BM{x_Vk_JM9+MleOctE^b9I+X%-<4>FHj z?4N)MP%~}6fBy#VeSQ=*VQSo(moPp&q~{d|l?x?o0OW6t;<1lxd6qY&od$D0fS9VI zqvM^pmsr&YmLc;xN&2-mepE`?Go5$05Fu$L+g&N2Y*spZ?%^fxE9;F zx!J~mfn;T6Y5u(Zvn}tt*T;%}NuV>7m6Z!D2H17kmM+0k5O0X0JFoZ0-o^>RG*nb% zBm!#2=4NS_-kjk1d+v0Z0~XL2Z$7aNmNrz)=jP%fgt1H%eFg21W_+2Cq$e;I8p~zI z#0K3TI*=KhV4;Eq#AJ1NbePU#$*G848!fS%URw)?$vlu_Y<`Mr`J9?6k*UJW&i+~_ zSgQc^mM|DF4RYF=Pr@93etnk>W(;MasRWr2^6NmYJdC!LSPr2hDEVT5WJ8E7IrPQQ z>NTFGz4bUdTm(q00n!A}H`4f{l2k+`2AJ~h@=!`uR~s1&te{3SK!PGBmS7Z?(eyw0 z;Oo7w>wb?}`0|h2dQnnvKL$q(*m`_&4g>*_e|Fy9xb@atM^JdUjFJ)w441kvWx@oi zGD102nsQ7=PX6j}dr=CW1ulG1@{d$%&>Kie!jXaN}n=6cr$*A1ZiM{6lf_a-I=3yx!WSmU;gu()5^g;>a6 z!;J9r1fIrnf5&JEeC~cTv(j^>S_U^J=L_T4EPu|_My>QA6=JTwK<^%k={j1@-)yC^ zoq{vS$j&xO0Yl+Eh~igdyQES1;yQ9Se@K9OXh^5^Fb-yM4InCfGrI+%1SW2taRJyt z5Z1xml)Z8+Aambof`I0-e^q@)y8 zfquWAy6-a=?HCG^H%|?v^J~2l$aW7 znm-2!^t>qws&a5wSC_6wM7)qA9=L*_ zP;TpAtw?M;ne5N-fe2oYJS>tetC56-4&tPaW+&ZAe`OjFe z=l^Fc7-pn1qA!eK4oc;!UE$>|luOPR{vhId6965^-(JJG4(g1nFJ$JW zKwg7J%$M-pWu>r<$7Mr*Vgq*jV~~z$ZaZWqMHQ9)8w`o;?`HYQ?>w9~NK=x5nbP;Cr3LwiN^^dq~{I5NF%P1&F2@|OIU_cNC zdqeMqkWY_qeJcYx=C2mOc@hh`L{84k$Jb|g`~fAgiRIR71$ttmPh5UhyYj(gDj1C6=Dwiy=q&`LF|>69CQ`nc*Hh;) zoUfP|y{f8eO;*Ta4M55QXzM{rgIGWh5q-{>o4^y|QjOb%z^ZJ^KO@J#-~M;xn0$-@ zfsrmd5I%v6eS$G@&f1Cp?a=Wd^m~NRZg}c&K&W|`TBHsWVI9$|SA>M9AsWL_`%L%u z5D+8(4Yyh9=jip_-QBeQq-11;Kqfk1t?Pn(!UZHM)3dWig{NpR3ypzzgL9MXE&ogV zqqZFS>3-N38=;e02qS^0G!6l!d(Bd45BSsi4~eLlo4<(C+{5$%)zMnf-=NMUD*7>` zYTqz3GZQIyVnA|$u?JVaeEBkpSAf(N2x#MvB*ODV@QbE(`l{alo2;L4g#-?2M6t62 zBXA9(NzY?WrAe6)=+}U=+(vo<^ zT<v1AZAV~38WPe1?`OyYjis$>N5dd$NX5U;j(b@h8PStv+J1`<&DmX!&BHI5o{ zOMY?wDCB4enHR-vc!M_)Q&6-4neaeCffZl_jKmkcJluL_o|u@Jf7+F$0KsF2%i+a~ zIXFhfD_5iz?J+PgAjm^EV$=f|mm}4Sv${p9=1B zwpGEw4{F-XpFK-+j?2uve)r?{1%9gg_;`48pYY+fqz5GoP+4N?|17ry?F>rjmXcx= zHc_{S3W%U80P*D2kq|Ryat@7pKtLBRUd(k64UkNx6Vuhy{5szm`ysU^DoQB~Dd2Km zpBSimOm=^e-&uidgNlZxGk`)8m+9(;rI*j-7xO;vEZ3V=POFWbo%nEp)l>KWry3f6 z2-mJITmpitoSbqt;kQx5I^^PTKz~yU3$0K*LII@@vkKDp?(zScARr(xhKXNoxKM4x zA~1dgG`B-->rVHggnFUy!pI^`=udacPpGJHE&j6pBNZPhvl-7SI|Yop!}Ul`4r{7| zHL<^<`txUh)aZRqZtgr9+22(%fT;z;8!EnkFI4jl0g|xDdhGVcjvIm9bsJP|cb$?<>+zTi4uKRm?K9|UZl z4dv;qE>uIre&g?t38U{Q1XTR2`^|@WG$6G5CTvlPF&K5uF06)ueo%N#EiHY8=YkH% zH4vl+ld%qJKvMI7;;#rsYON(B7W9pbn!r$jnPlbS3WtpmCtdUa<*3zgfe*x9V9s-j z)h}i(wB~9Q`d%PoxuxYU7gh%#7*JLxh-!D}7ePH#{_^l9>SY-X4QSxxT-xP`H@u$) zX5+t)?SXM45ncQ!iyLMBy=iF#>8PYh#C>;3b^U0S^8l5ho;`bp!c19{4?o3F} z>(tQ?-PrCtYrjXQ+NH2(du@5S6XJNuy+(d$ZKB)(tTqK+kKi_zDC+)pW8*ngEbx+_ zl%gWi8#iuX6HuaFlmObq{*fNw!`oI z=?PV05@6?;{4qUOC81~pNPm%jVI-mZJwHAa{15iFymNJ`$no*>sSCUatU1yy``_-3@g2<2G-@1^h{J_=qPH=GWO9*qQ z>%lt{iUCr|e-u*9wg&kvfIFxi5?p33d>o4i3&YZfHyFS`#U~Z^l1^9)Dvl_sGT&8i zRqW=q*h{~T$F&xboXiAHlAM&}4blhXTZyH5g4dbr+41Cgk;~=`OU%0f{<##q(ab3 zL+5+?^)7z?obB}SOk3WQ%{iP+2vmKqRjNrm;r_+v_Gr+h`j|U2Q8J%JrFBtUd{jd| zT7f9yqKv=AF-^JuQz$3|!g9g`J|`AqoxI<_f4>P^2D~kzYyuH^%zE_g&P7yv1LeXb zR8&;pAkaKQg~)fOIFi_%CnxQHq5lL!^2A3WiBRGp9-Y6+VsvBTAP+x3X%s>|$@hG# ztA?RyRW4q&pKE=YaskF0Gjs5!;F1;^%ak^t` zJ^ncXk&T!AUMbqG7@vo&1?;tSF~dXMMF64b)`>5S*Ti#@;~LZx_<#NAH5MF&@QQT7 zsB%~t%Nd)tlL6pFm_30AI2+-N&4XT}p!pf>O zZwyDRea8W-Jg2q%`Gycj57Lj7m89T)BF>GR$-^oWIleO%2*=LVg!h_CQ1&cl`;OJuID~J%!t0BKAfaw?P4J;X0F{xE zImN-j%*YtqHV+N>Z|rCi`-Sn?%*-1Fe^3cK%r;%--7MP zmK*pqBFVuGs}K3^$&)8gQYf0x!HA0a`0>Zcsu`voTo0qvrY!5ee-A@04ACmGtCHG> z{i+uH6igV zN_tUqZpJznZ>-w`Pa}dan8+#V;qaNcw>YUo6y%N3;-O=UwRLrQ)?>7=yLk&=BY2IK&`?S`x~l-U&TD4&>IATa-5-CxhK!aTLE7gkl$qtPgfQu+Uqw= z*oj7173C(5k|7SRMY(!#oO?SeU}U=Lo&UU$SG7|n5+SA$TsadIt?qit9Bs*-@Bngg zaj|{)u+>%=wITX=Z&ZKnG_zRk0N}dQ?Ir84LDfBLH){kD<5H#Qx)^-^daO~HeCz76 z9RDs5ZrS?82_{{rfVZUKJs9*l+1j2{P_nz2DFU;a!}Rn!cklLN$RVl`WrI`kQFBHk z(NcX2?l>zy|NN0bl|$&=mq!w1!p`mE=FU(X9SP~(b`QCVMAGL-vW=*E&fV64J!kp( zD^Y!*Jw*sTXZ?p7E%gv0fPVRto#(rJjtGa;*2;i_2Rt-jcf9!ByX>Otizvnq_v1)+ zwu6ws#Kh#VHrGx~gOUCpFI3aQcC#QtN>0r4lr3WOdW475pOEx=m%a+gK4_w69Tx9_ z(|_hr6gdQHw+M6)@*!{*n==gM;kWeb6OjRuFSyxdzrm(^tDHCxIBBnudv6oeB4)`DD&nMo$-0$^(tvO>u1S#3nBM%^Qcq=E1S<%^r*`K+p(mG7VNopkX#3DGQ*$O3uby^1#7^(Kk-dG1Z`r{CCM? z>?%ScC@4r6a1oZ22>NzD*D^{TKi-^YR6^>|94}u9of~30c8F@Rg8<*K=D=KU+am)^WQD{&m zTfN}+aHJXGgwOO_DV=#?8ECC=W@P5%e3ht@idshw0!$Q(sOA2aL;=9_FTldwJ&sYT>k)WkkXczR$V zCnpmx@tHz-Mp%IL z{ru?)p_;W;RI$J#T9i@8PM(ZuJNxm7upQtGWnHHb5mdLAVimIrq9dL@eTo!k;zx;` zoo+E8T@=gDGg=oWkRjnSicXQ3Yz)@YAo`;h|5RP=A-eWk9%@Aw(T$~sQwKcG=j@}V z{sK41Zv{3SIK;UVLk>NK4+}9+Sw$QSBn?f7utn@~aCDrSn;U=^Tfl#wDTN55aHka5 zcb+I#q1Vx}ALG@s?cY{33PhZWT?1x%TTy9g6g$vBPKw?#v+TJDK|W@1UQOpSqCxYI zgj9hp7c~{!;CiD<|H3{wp`(5Q0g|9G<7E@ZZbL&V<{VlusX}MV#+R82^aQDxC|g?9 z0zyNtB1U1?<0$(9tbNI@nLqqp&cQ(lVF4%MyG>*K!}|EYcnLMGf;ZqS=0) zbzXPiGw-Pd?Cz78$f~TYe4+K;*JaR^6%-XWKg!CoD#+zSw!eklglO_}e7qir-U#`! zT!hg3WTg&8VZr}<9Oc2DUN+Pxz%Fj8s{_~zGZ4%sPM4}`)yhN(2ZaqU+U`#PdT|P% zY-IeWB6?XWpUIEdKzdX_AQ&RJStUBCkxaX?$w|=onlW8QZyaTuq780ivNe%WdoG|* z4DS*_toFWeEfA%N$wpGg(A!!B7c@P{)Py--Lqn>VOBmDpt5?ZqFsW_czJ~xwaBeC; ze}0PYraAWNAq@=;0A=HxXo%Psc$ohKoe>xsO;M4J<0SD(!bKHGE15ncb z+LUSlL26KN@D!|JeFFlR{__ybZza8NuP#mz40~?#9-;D&9|fG(h0ulqcd-D5OElF` zqLN$#n`RDAxtElPR5 z0T>rhdje0HcXuD0%_&)vwHNgi#l+jly^upAH?6+Eg9rt=&Rmu9nF3f_LsU)>#5_ZN z4^tki6hl+fT91RQVBME9@MlIJL;1nX#}@zupX*lXBU&?L4o@n!AK38&AoBxgokT0E zsHP^38RO^ApK;dRkr(f+%$ucXm!!};sdb~?B%#KcK4DJ}SQ5vV@z^mjx>;U>+(FkX zBZ@^f<52k8QPz?yE-zcm49Y^hoKBkxC(9W)rS=aFN}?OF%0@ss0|6c=1g%#Nb3^V1 z6H4lH_o8~%&I=0anwvL3@^VE=s;r|!^~iKDISm&f@FW~y=jK}He-HrinrGvG>!+<}F)**UEU;z9LQynjkAC_NIaVj?RiMfEt6E zff9%#9``p=E{+{A0vN^Ix3IVkzyuwrJN`Ns;)dL2Xc(VWeZlvwbJdo;?c@ zC;+&_5sve!7<3Xt!z}Gzyq|j#uP3$wC82$Ujz;K%STAfOrLJ5lZEekJ5@X18P(1W5 zVd34*802}B1da0~JvG?tKy7~X^(p+E1EsBv=977M{y{uBq>i5;giX)N`iy7`R3Fx` zoYx_B?!dobg*qo9G zlgF;EP$WALLmKQSiYkFH60&r-(i&h4W>;em;?^W$*p}fxSyyFbKpfc$>H)BhV2FyP zWA{HoV418JoG==Ct32_rxEyQy<2kWI6If^g&h ze=C(9!Y$dDt$lV;4mGd5yu4W>=`BOU$~O|8B+ybdE~zT4QS+{tm|HQ>UA+FCz7L`v zW&s!<;czB1=cQ)_Ymuyn6X*tqUB#2zzhe-!9g8(vbGBo`-3rafo#Xoj#ISLTJ0vYKGPF=EPNysM=SbgPMB|pHnztKU8G7jEo@xn4@ULZm*Q)EYXFdb{d4v=9rLB7PcBQ^37Dkzi<~5ss)1` zN&jkt+x>^<}sz?MMjhmuTYsIbgk43!rwXp?yT+1c2k34ns){)eIMaHFdjJ|Yrx`XJ8KV#i z(Mek#Br$G-z*i5Y5dzQ*fFR0)2cH7`t*c9JisayG$>?wB#Za1Ias9ewwNxETAQAX} zygE^(nb4%SLqY%92*Rx zmR)=0BZQty$J*U0as<=lC=1K;b}jqldYL@Tdw`n5EWl|E8u?H}=P{d6VahUCSNR(@7Z`m$9t-7lm8YxWsQ+p=&^bodg$* zn;6ToYZuoNjS9Y`EdaERbX|9AEd?vzV`&5U$$l8uqen-mBsy1bcEiRtqj5$wBIq8` zHKU+ z)ID9#cGg#rIhOBGXQjDt0)cmPiMt1rcpsw3Ij7ZJKJi=F+pRlSiZ0}05Q5Svp((qV z%q9P^jBF$6Bpd-KQScLx2bdmkS0iH((HH`LPJoEAXOD%n=idJbt?Iw3Vzag~_i#wJ zla&FY0p`bKKogvW^7_ErT2B=bV zzzqO^ZA-e((e_Z0<^aRo)0#zKm~NVZuU|Jsi<6p#qMtRBkAgV1evLuIAy+c$T?2?g zSLuD8^E{OF2gff>aW9B||{vwK}FVHU^h56oPbWVw^)ymeKRjVwKj?^Cq8l6kjo zoA(Oyrr6gK1zxjVUx@hAN!4z-ioaiogO8 zA9n27!vq>4a#@7k2+Mh!aT#n;l+gq#j52If8b*y|WC_JVf&v0Mw{KsB2RLvoTRVWMj78!0a$=}2NQw}c%#7is=-Zgans+? z0!y999(~l;gslcxRKpr6ReRqlzCS76w?&~S_W>p(3^%{}l1flE{@FjBN_O@3ps$`EjJ8f9vSB9jpJ3MYNq=Dq(#- z*RXbQIkIGA#%w}KA!#sU`1rcx$R35(4E{p-%XT*W#!b2zJiNDFI$qx1VH1<9AzP89 z=#+oY{TcV?!yC?wwT_+s0&is)Ne*E2$@In6-#+t!+XZsXow__Sva&7-N47fRVO_5m ze>u~czelf{4%DqTCe%LUCGrJo(T?MLKRqz*yfhpcAx*|;1 zI)>j&TXAx6fovQJqit9sNMYsDKYX|dvC5r0&rv_XN5l}c4piW8l~+*lY#vVX764c( zvhs(UFcfid*@ST%Tx2HyWHfxhEg`V+O9*dBWSLJHUHx}?{AEk)l_I;jasblmy{XGZ z*RdeYloB$X{*@*2-DTyU9_?fwwDlfo`61R@Btv%aTo>)ko6v)l8nrBJDl>Ox87i5G zVv+CnRAO8#_f}<_g>lWI8XgxtP4RMK6$UV7h7AN*5~c0!Ibu~z7=GYD7~tXy3e$RZ z%jT^Q#>dAG3)w16%tTdDs}+&oXr*Xr)GK-L;DPC@U*PYu+hvTk>HqigSvgse{@>Me zSG$V&I0!$WS#UWlP8!t6b@bebG%o;-0i&*S5sKv_McdvBA_c7X&# zm1xmMG}vi2tGlDw!S_b}h46cGC?7~4-rJT;X*MoLF^%hwMZl98D-?F@%C)JF5()V+ zY4-fTjey0>fX05q$PhG#cQ)M^dPj}8Gd4XSx_(e$V17?*$g4KpahV!*X(Dm8jurWJ zTODbc+;&OM{{HgaFp0*<{NjAFbi~Fi(+Z{M!0mqyXlj-$CQKJXk16y9es@DGx%8pgSvfs{A{Hj}N+uHPRR9iTj-ap1$4^mP67#&SqD=3cmK$@KLNJhJnRLL@l zr|6q^M@13#Gll|Yp=Uff|7&7ApW7Y_H2WWLMr1Lneh!W_7ZDx_fPJ#BY?_4k<4n$6 z$)KrFO!<|a+-_F4FGaoxqR#FXcz_3}I3GOK9vyyGvAnB)8-B#slVGZBE@_LY+PmX_ znKrdK1-HLGmR4982293of$$vwst~ufg7Sd4ZUHDN#zepAvzhREd<=>sgM(?1mw8hn zD@SU4FdFs@=x;<7rJUn_BzQb844U-SM_KDWS zLvWr$12tSo%0qbJ1MadNP0sn%pC`ZVvvEY1ogd=CgRHZ9wKI>eEtH!w&J#smu%Dg7uthd_d0Vqw{d5J${8 zhHLlkxCd0_`~o+w`2fH{%$YW3L^oWK|Ir5$3jafg4x#>go0E(VQxnJcYyBvg)H>b* z;b3n40<50JrSInEmfbnU$6FH@8rtRf+Tfkj9{f)8;7|_vfAHgK3^GPEoiQjQ?wT0U zi17En1l3MW09zujxdM-zv7A7I<22o!yn%BIJcFqp&vZTDh!oLeBVQUld(|}g{N8ZI z@VAyrj}uoVWF~-(TDc-?ds0S$pizO7+wGd!NIxzvqA?nwuMeKKQBR3 z4UeRJb6>3Ys`f8G%K~2=N15PB|0Qvn**ihhrx&}o zmR}#7{V-lSrFZaZaq;J#&zdnkXr-P}F$z1?$-KYu6*RD@ewxj6;#eFu^#AA1pWjbK zC5Z|!yzH9Eo&{5*sO?I^55(Qb@+L^WwzevnQw+a7uvo?*{N~Nlfdh%EMX7zS$d-A+ z%)DvZD*eN{Ue~T1*JjWEXH0yA3D4uOv9=Ht62f;*{Fb&FFsh3l~tN*ck~b*pHIe2cu9#MW`PpJm2+ zDngd*;Hp&+qolO$Mw-V@7DkH`_|TW7sceD|r%#@KEiJg3$Vsz#^aLW%WiVdQ;#Pn$ z0j8hXbihcNmiT6ox_b>M;tBUR1{Y8^>JIBx!sfwKGZJCxlk?i_XCqjogV2e*grXkJ_uJjp_t_R(zNxe?9Q}= zUgqTFWrxCLF7vq9*x!c-RoAkB^9u3k(}i3|wU9M*<$I*JdxFz}V9q4UfVi=V$oP~1 zH?J|n7YUc@y83el-2UM^XsgH446?ZNz9lj*F`gM5Z0kEB;^;zE3jSV~OruJBVetqQ z0uPGK>y|K>G7l7Eh@x*xP<;POCyxS2DQjD2fm(L2v^caz-_)$|^1LFss()4d>(9TX z8SKz1Srr*Uulo(Wbq0q?F_28%sCe49O5wH)bO#{9sq+pugTQ7!?I2WVjb`-7(g*T6 zpt=6F5evVYDV1DikRHd@HH_-Z44HpbZvCg7%&ID-xP=14g6oJ*UF%AF=SSg#yS5>8 z%8rMph{$9XkvfJjY$vJu({V}tt>>3wrK$_|e%1n?X0&`%>3)1~4qEi$nrEh}At#W$ z%_Z3w?`@}}3$+gX_NK_Gs(p4H!AX;D2XEX$YL=V5GQ~GsWYrPH7h?K4WI@F-Xc&Zm zF4+#Z{40+G<5*8A&rIYBQnSS7q@J(KTfAYnhCh0xuig4EKvzjV`6dxBI{p_pg1}*E z!@IeKh1Xn|x7_(tDB@VDRb=YA)$xbZn&9}Jg#El*BF~zss0xkh-Z6e;DX;s%TuC~W zKw`iE*@e|~BIZ>X8KJ>#8}2CqT1IM@)OwYjM_;SA$Z|`pjrw;ES@XzP2tvkWe?9sB z^Nu06mw(z+8rdzOkr`S_IG9%fr2#Jq1^QPC!$rlf4XUFr8)TWU3y>j%f{ zsfp`0r)^$W)N zjlar&E41ob9FKj1!$u$p0f|F3I+3bM+L^36J%^UEs3Go7QGNy@nItsf%b zM7T5g<|*@p4sWO^TG?BV9%UA%a6cj$^UFVNqgJ!$4~uvr2;O)FBQB9-GY4q#s5)Sd zA}Z~}^@GD4t4@GYB}tv$3k-bHKHb_ToLJwMFtR)IRrE#m-F06-k$Aq4Cc%j0)KZbu zd|d*q4^8vaLI$Lnv@G1|3t1pV#kuM~_C(wlR~y!MjsT2;K7c9zqq-D+i|xh8)k z_(fm{F-rs!S~x@}0__r4?e!J~?TN^^_S9&7`duEae}t^u*Phz|E_m-)l=$@6njOtl zkdpg$$A?bvZ9eaKzU`*~!;~?HXH^s!I6QQZ;TinPRnB z&M5!<-h4$)lAb8vA8;db`zNhRnOVG_ZhIl5&F|fI~R+W z(@)PtzuJE|pQfpxVBa2LuMjJ(7Tq>Cq5sh{s`A%VDb;K zm38vfG333{KVQ*IrrAQKe_(lTT$y)besQ8`5{rE4`V}8-N_|5^6ZeOFjJ(B0&JX6+ zHzBht-n{uP`MHfy>=SSIUBp7O84EWS&wV%&LVcQgRIlPf!HZAYx#H4tJ7+fJMLr%r zpJwc_ZOyK_@>$%ym9>*2cjP}zvr5&lRYt3?6}7223D<~j*qkDncoG(?GO(JK zXjO)@w)Ev0xw*R^zqUL|p>hkm^14(W57G?A3}w|>`KALnGtjzxEwC{k8^x6BZ|;8- zTX5IUF>(J;M1`&Q2cqmYJKkCp`+gH;1lLfixS)L` zjE;7(JAuUZmXzjs>fl@7o08g`jjb4;F10W5vIKOi2TY~vJI56!Wp>PmIxO#?8!Xsg z;7nICpw}4dE*v+gtRWnE>DLRAp1C9SbtZvynaOttm3D^2B)OuviSvyd2^~gF`UrRWr_*J&IAqJiv0e)=b2k{WxpM zW2NhCX*_o#v%cZFJW#k^(-pYv@?>QgUN78I-2c95JWER@u~nmFnYFTb=_Nz)?!i@# zjsBJJ2~M+~kd+?8vN{uoaehDF0tvFiqg97{$AWCecU>@0+q_Zfyr(^Nz50+-#?;y$ z(Yd<~-!o57ni#Fg5`eGP*PrcMf!m|ct2rxwzZWg#&5iriQ_2KRvQZS6dOehUd7PYN zNJLjwWw$usEA9!;RqLf#9yYe*5l_tUzc-S{{LcF7&v1tgc-{mAux!VOHzuhG{XN*Z>J#(%syF5qKO6d2f8LKXdJ-V`PM(iK z;9ULEd&aafdud;!E6ZBXdx=Oy>t1B<^5)xD=$ZOw9w z375Ze<=w8sC)2OG>JO=`I!$DT>n3O!NF*0;M89ib>$#+5y}g^k{zH%B=>u~c+fDRN zl{Ei_n97`VmK=lPaRVja?zelrv+T4t0l7*)%USC9^7EFf7EQirfUofHW~^K{KW6TJ zh$Pdq5BIEG+gu`P*I1=Fa$Qwb>U$YI$%EfZTd9=0C+tIg=4eWF9k&l_I?Xxkf7o$o zQ<~-BmcB8O;iXpy4M*swDQ};U8WXu+f~BRr9~Xpuxa#~?P;|doq~yf7WG!{u&J&D< zHt!~1G0Y>uUa_;wKWY7Nhm!IQg&X($GM`X7&~*9MVk(Y>ibVw+lsYL*1J%dy^#^O95uf46)Dx%N zpqY|YQUsVnWe2Z|(Jw>sVW7~Mjnqi1(E`InV&RcOBbVyvxcd>!$0ILl!)03$&~?LP zmX3|>nJNBaSh=Al>{}MeG-(g5*01g6Pqe~c#|&h9N3aT3mgRbd)qbhsX#ALB?m33IlnBcGN@IY(eULXO2wzknG-|k=uB6-HD?3^p`rB{>H#j0lI?7RXUZ2 zaa|=iTnUkNT8SLg}O*_ed7b&a33ES?RpZzBXyE z80aKCu%Pz0?mUH(ImFoH!M-UPePr6(Nq(vY_8ZRh2G5^9-xL{s>PNiShs%SG+elT& z+x-|G)0zi~EB*E@eC(kt{Gub(+0DC%`}M(rKQ|XP^QUUwop;nIv5TP4q7j#zcIM=r zsQs}(!L{1JJ-~#Aohq%8cPEd*2WG8Y(nW1F{ZEzoaM&Y*{}844wsF@pJ60yl_>P>` zn@DV>-Qb+cNdOhQM)`R0q{3%~!hbYfDiSDOcagyy+*3xP9Vag7F zZQ-}`pN@#}GrS~0=PViblw9Ibiw$pIIAt(t`VOrIkOU^i_$O=6Kbz$j_X6C2{`wbY zv)~pJg2&gd4>~V5M}jx8*?D~?GONfD3ODb&>e|~YG5tenT?tXc@20nvjzxhWVR3>$ zLip3KuP>D37~P6ra@N$))coC%!F;fUl;f!ltJ+#*G;^5y%%7R70`sy*e?Mn_E_k4P z_&rDWg7wv_;~(Z^<)_UxK35bo)T~>1$!VH~6c+jRTK3O=@Fh|%P7<3WSo+=FnsRPN zX(*hI*DD{qV=h0lJWI6L{$cw?grkjHOF2NsFkE^H>tljo2Mw5ti7Hr3f2r4yUtGd! z08r}eDR#^52Em^2QP#|V(Dcw0QyW~#2w8$9hk99l$@Q}p)g0Wu{Q-}O!~Was%f}EcP=ww`4e_XU zV4ru!)V*UQx+}p|RU~I*$*BP|DjF!g2~>%6OdDdv01d<=kTB!8Cs&|7SsE{xfGi)k zK>9(?tYczwRYKw^-@Pu}TM5D&30P!NO=i~>6^RRD!OLdczMVJzCgwxwxBwM0JG^_j zjG_rJpYDTHK^V^iXY-@20XPa~5tw;mbO-n^-%>#pXRj>Z8eUO1wQ{TJTYip7x2yL` z2Cd@@FTs%htUo729Gm^#JPvhOY1%cIx@6=-#y9v%jV;9kgr8nkaJ~s z|I?;8m{3JB_0?2WZHfZop4A4Pwk|pblEUd~*4j}1)QV{^)Ib2g2wPOpj!6khxVQ1> z|0*s!4}Ov9MDJhH6m)U~{gPmwutSo%1Fi&}C4%SA-`3F)1MF|IT9UWBWnuKrv%K`j zo)2SXj7}^JUVqz7vsz15|LM<(^_!r_Be zG5QB{uJpyDfmvTR0YHJlQkL)g;gO<*o{!d3KP1A-qH*uc>DM0Eeq5Nq5HzXnIjxhR zLjox7%%%nVU=ezS2WIi_GQx2y`~3WTn4rxI zP-4Qu!(9>t9wiTSh$?M!I&{~+m1c40m)y+*^DyT4>kFWqKpsG7i{pIHJIxW_KmA3# zKS^V1po3KN=T8bQ;uI%tFpd}`juQFt-o3NHB+->dD=N+9_R!6Cd>gJ$_(tf`&K~$j zm-Zz45XCL*L!`XE;o&b}n-RBrKq5(QtRC*^dDT0cmXNBwYofDB#eF3|puLP1cPAM1 zuspq~s*0wY92aQ2A?y<(>@Ka0v3Kv@@!e-IGG5Zx;CSu+=E$KLX-&}~74x+kpF#!tq z;`d)|&Ylze73&}QOq8}QCOd+|y!1=%!@)a)2mP-r#u-c>rCjPmawX!zb|(^8ocQ@2 zqm7BWDXVr@01w$|)m^-7w7=(4y#M52OGN`)^HvA&%z3p^Qzf-DrKDl)Bo0$M#BRdd z0g@`epr9*|Jdl9UM_kN~jYD|kzsm+TPYmh}yWl89Y|+!Ng{D4Hp7)XUd!+wY7T0#u z;4kZma1^il@&%{ugYsW#97g+(Vq^6adr8re-aDT4Bx#lFj4V#w!}{0*Zx$R{VzS3) z+IZCa0)4N~iGR&-_T9G?&ou6HF&R93o?$+C%0nO`aIfzXUgJ?fbq@s#A92dXk$spr z#T>JTwBZ2Jub*JezirZ*)^o&hleTy=?ogqi@Ud$z!0y2Tfs9`%v?wDVVSnG=y-{OU z1vz8?gHYbqF%ND_AubOltXIr?MT#nKfZPa)U|d`l<#tTdrptG8kW5BytX?*pxQ(0E zAxOBCtek;4B?JU&Ye&9Rr~cw_dH7Aurq5iQZ6La_zh>jtb=w@@+}7?RSEw|wBYoK6 zi~bXA@_%^wl-_TGd)o^_SI=ul_H=uH$-P!R<$rtdMT+3c9k}r!!{MNOZx`Ve7v`0y zPEJZPuFKg%$nJ=N0-@mS?hYp?J^v@=-KZ%bUOnRG;ZkTUModE^BPkTjm1Y0$m3SFh z9cnaZXP@s`b$IWU$X~-q^Ho^!gY>CF_2)xJDR(aa?eY}$g5r%l0F|7PAsY!#eK63T zu{z`IzIjsai>lq+-J8~*e+ZrqkRR6=IxqckPmtP8of%uv?LMI{p+gt_-Rc(J;hG#} zne>zlx!~wmoD2-C2}4(%TfY|r9x8It#wuXIJV!-k{tmSiW*S*AK`}o99_r?V!A>|Q zk&%<*W|Vd&OI$9#r4-mT=x!N0AGgC1_8Wx4sKh|%Z8fq_g$}5-BRef^L}(;*%e!wXRB@m#%ceD(U4d^PInnb;3h6pK7~%KKJU+Y$y>5Ephl zf)eqizyBwKxd*l6b1yG~W(|5pyHTpbDPleW?U8>#fCUtlpo1rwCDPn|@0pSfQ4hp1 zcSLPwm*8tkT*k2poIKr@ch?|6p(7}i2R1v zd@uWTkHw>y+S}4K{mzvk(&m40TQv{hpR&tkQMty?!e8~fR>=+1Pm;@fTc^(Dt0fOE zw`vQ_*SW7wYMvc(UZUuoaPYZb!OXA$}MbVx*ijX9qe{<|YUub27yuQ~Co32AmHJ^6~SxXA2`1gu6thWRsv4 z-PDI4Io|~e>E8YOHUO>MU_CK1Dv7^JPEPJ>$;cR1wLD%=HPifA zaR1`9)~-PRhot)YJD(bs46H?Z2A#YAX8tlkntP+U-KmL%F=kNNF}S)q_2`Q7HU*_i z1!=hkJ+#bp;%5Yv9gnrPy!>$X+N7zdA8i%mKPR9iEMY}~`$>8h9B=Ht&FRmNM&1|X z2;HEwdHHRvD}-aRK;htGhrpilPc5s(*{!W#UwYBSK6$cH+GA#pt{|LBm;m6yX0*^lo_Xo&&nrUXS*$E<;Rk)cMxV`#_+=m6NWz^-$y1LX2`w|n`9u*Y{ zEAY0bLW{SD-nd8fFQeX3dzAu#`-DQvz`uMJI+VYu(M(p`a*GIF`}BLa4NX(LBeSFj z5RtDI_neOh7Ktf|ZRGSi?Y@9Ig5WqqC_@HTH3kajYy8n*?4>a43w*6z)etBx5TW=c zIWW!>-D0*fZ?BfxID>fgkHmv7dTg&e1=;B%y%$(H1jz?-?+sCVLpZw>ZEP@~J-dbb zBNO`tb|a76m`7^HAs1CsVl)fbe_Kh(6y33ROdJjPt~{omlQbI=pq2HREzs$G)T=`! z=N~K3M)e1rIrgEJ>?0W&cZq04@Fi>NTa67fQbl}$;wp#K2vG!q+)SkUgF5TnlUH9*HX6_86y%Y&G+MS0&B5!OXRlB4fOm#xO1G5F(p>SP8Lk8nASU-@1_(Vb|3(pA(5_N#& zi^GK2l<-Nz6IlWVDelnrjBX9={L9X(T^JEqWbo{}YSZqZ&~X1>rR z=?kq&w1*k$U4VWE740!LLcoM!r7Ofbd-v`=`o?v$%Y~yx;pH4`T~{)w%nP3#&|`lY?b;^sVl@!3KL+x`75kLCE!hADov^fDDm5kF>i{DTU$MEsl= z*(;B^gOAU@Qc}1}=l-I+?skWM1H|kdBb&seWDF#Rt_y>FNI@AcdV-l zPu^WStbFWd>!_6u#0-4>IS@dgl6F;2)Q4*Pz@bBgc#ZI#fH*ACl;gED!Mi<89h<6_ zM!$i4rg@1EnMagdINNexNppi_ChT><~iu+YqwAUu~JFP5H+l6oM-4i}6 z`sdm>gD8bcPJVK;V!paZv(c;pdJ|TOj^^g(!~?EMJB#x@$}lx1Y!sZ<=2XzmxofZ! zlFF>)-;S$Ol}pgH;Htb|ghgGeF)aMn*VoDD&-;Vz_Z21fF2{VRw{Cy-*q*hGn%jU3 z9X`g+u%)k+o**m-pk7JGts?LThTYX0SOmah0%TMke2F|<6oVg!rAIUPbo1QUo47B+*u&KkIhEk} zY3ykvXK39y0l}G`H~s!}8#2N5HTk7^F>eodt(dQ`*NZrGcDD|%wMvl1#mD2YYjAMp zLd*%zm){`QLsg{plvj~ZGM@|^krwZILCyIXZl5*-PVKKq+aZctJgGrz4mpRvCeHb zO<51q%Lh|3$juC<`=nCZD|>$J9?0gmmapS^X`w2Ak8~%4Txw6e<7mD*^JY5QqC7>h=zur63kr6<3p*Bsxm@Sz?Y|}W&eOZnOnvK}Qn2NA z8n@^gO;MzwkkPnsp}nWD9E;D&GO6vp;h)kP2`(iL4&BP-+D9iB zESTiG9Deq{cOL)o_M9-o=if_{_c&AUo|D+<_t~s)Z|t<@#qFI+vzxZMd-tVYUC((u zTo63I=GH7cyNRTJwRa(FKE6$LS3QqJ%q;3EP^-hCCw&zeDUW^;<`<_4hXEiXP^1+| zHqQ=99)Crcj6$Oa$x)_y34`P8KGfBO7Cd>xZsa$IPU|IkY43ZBrkr+fm$C~Cf4%qq zBc!yo)V;ar_iycj+$@h0sK|FWF~fZS@p2unn#GWDQEq%FqQ+9;R_YDsU;S=-NER_oiQGV=piq`rug|GG+;( zSeGJ;=F7%(d*{K_!k1HOJaVgXGyE3{<;L&ZspA7#~km2x8H71s~Aam9w9`lyphm^awI#m zp~6G-*fPS{g&ieKCy)}7$hRSiU0jX5G;bEpSRlSRHd84-?Ya`N%VYHEo(KP8k$k;n zFMPf%y=%!v0NI6G?ZsL1f$`~=t~iTYKAEHG zIQYgQXO~doJLu0Yy=}U2`g$+q07q>5Hi4AfpSDj}>|>C?Cs*tyt*&UM`6MduvQJSd zQFF|S*vFfXtCT;JTcuu!c$&on(jH?;ih4F{VS?}$ytPFu})?9#R-)kct3#-7r#RGv-pW z=BA&V?pxQ){k5Tysta)RBS_gOW*}TO4}F##Wqe#bW^4Ui|L=_h7SsIn#+m{P3;sDF zGW&{}Y8R?#xn^q4v;jTh1i|BkJ22xv`}Dimx!}dYFpO}&|83&a^pv?opZ@#e0N)|@{9)C*UoOF( zE3V{&@^0VW2IiTDJSzF@L+$IA-0P3EYRA;q=hm>j(kqgy$?&;ZUBuyFLgDD{m8^B+ z^?{6O^M#j@mNa?s95vZt62H5%uSL#P=bh|{5T!=G@89RcJ-6iZiq(;1k!^r^y~u%9 zqCJCVwvoqR<7bW9ir}kjk57wNvMy+UOq?Zd2561YHK~qMa@ajC(_+V+!GGXogsv&C z$;Z?|I)MN!nTU!nUm_H5AIWf*7)HkbU@=f_*IR&zLIo~Q_{57#^R`}G?C`1GOzGq3 zK%ZPz`*uqqWIGymr;a zR=0R_`<|X~Rr7w*$*bi~p}oDOr14yazXv6q>z`~1{kGh*x!PMlH^0iLmxa1WPF$;P z8;M=-%GsvG;?J^b_NRN;Ux(B_=Bh7jk|R?VE3!3n4-u}iBeC0lg{Gx-i#&y)`+3Q% z`b&RO)wpKZSnA}-tcPB6$}*=V{YYh}D1fU(EjazSf)SP#lbDfkBbRfg;jH%Y#i=?m zw%T!f=1{%i4SN13IXAh^mVtiwx#D0g^JR~Y@R&m6)2tXL-A4)45jD`g2AOsenZ4BhzsV&yG^>B;FLp{4j__ylo9VN zhox@+lzL&-v)miviR`}=8Kzq#trI-%`SCbS6-Q0+D76s3jtVz4cdPAikxiiQDbdP}&h~#@GtMJ%`I@_C~uAPm)$qXB!j3IIOCkqh@jG%a*XJ z@_io7!ucvdm*w2v;jxR4e0GzR(VxuGFM7dr$jO|(F>SzhCvt<#VcQ{@arR#U7DrWG z5s1nTt*UkR3E&nrbX-3Pox#9>4p;Ex)KoN#IKYdXZWO0zrIk?6Fd)Y@+IrANdC#8^ zghv#}pM&7P5{95wcLT%1YS9-E*4AU$Z4IXvkp|T6XnOIk{jrua%sx~Vc=cRBipf0z zdzU_Ckr%86mXG%&mwAP59iO&BRnDKEX=%c>?_FDP?n}d?ti4~Jepf6#zDOl;O6`G$ z`e$vWg(5twlI<;hMtEL8_4n`|RqB!|SkSr4= zCnu-FLbna?-9u1p!>B+$luzk$Hq^<`F`R@)4nD49;2TsX(#YBHR*1bG?@{~!L17gY z-ar2!?SmuJn_ha$`vs+t>W}=V#lzO^h^o>sf}fCr1CZMOKuTkayF(9je}a#}v_U z-FwElhQmk6z@Ytm4omSB&8u;jX0bysb_$f%yGx;brau4R6j!kAg%hX|LJ@M}*yOU1xvzo zr!_m^+(GB9PD9go{OsA6us6VeaLWD(R}RV4cEU=hc=5;XuyEEr%kU$>mhq5$tAkc9 zx1g)ioRyi`oj~8Is45`h)w5s2jqk+3_3J$9M4)E*4}O+d!Z_XN_Cl?J@(1cynScxXu876D~U`?P`Iqgkuj& zaYwZUA5N*hH6MH9NAX&km|11LmN9?7%@oB|X^l(I4qyp)%-%N`+)H7wXX-*SKjlK= zrq<7jUoE_1hE`d&CbNWC>0CIZvbjj}*)XGilxzGdd=Em)3Y1m}Zt*i*`FT%$XR*)E zOud64cfT)a?lc~fZqHUMs4rU;Vk9ewHUw-HyiH%@3mcgE zzrUszyp4&Ed3e%apgDCWd~M4KzjIBgo}>w6^r4gw>h{l}Hq(QPDId25iL>*DS{K}8 zuW4wIl|uihQ4|Cu1JIA<{2x_Z(Y&o+MOnE5&O5KJoJ7zs8;>-@hzbtdo*3kHJ<&!3 z11qWbQiFN~is?O*Sk%llh;lZxai{fhy}aRF_I9J~N2N}<(Pg)1JKse; z#CPL-Coa;ye<8!@$4&KFk&Mzy2GOzm&DE@f&DJXGJXh_Pb9yA!b397$I-ZrGl2;RE z<_MUY-{j3!-kzG_<_?}Oy z)5RC*bRRAG**2#nfe`bRd(Kp@amwhOysJ0wNMrZc#U z**7w>LDQyNsecYbA^33A!=M3E%#>_L$asj|1FyS_Q$hCQdG4^9Xaur(y6fqaCykgJ z!?sQwRvyQW9m{e`8IdVV{vP(V1BEb*s%S)=99&D>UBswn=KWdi+$o)2JW@0K0a@#6 zQJA{s-NGmiK-p8;QRbDG4@gdabBL=6z#NDz7;wrDcWf*-Rtf-PL%YT(f&1-;qpF*s(I z!^aZtF1Ny;Xj|p;A_QH{gtD ztHhQB&uy2URzC~=b?*No>@A?OT)S@J2T4I%DJ7(ll9Db76+}WBky1cXx=W->Bt%*e zX%OjdDFIPBq(o4<8~$~>-+lh?JLencjNu;de)rzu9oKzbYt1>=oJCm9l6tm2wz=qdIO{{ekR6ihNhncl8v zTi-6eKPdw#y1=l26Ke7J?sc&LLNXcB$Ak63xd2$~7O;kf3Ht~{(mrQ=FZ<|pe;RRz zYaT0oU~3=nuNJ@z+zIr{TZ&VjWWiOOi762wI{S$t-7Xe?n0zvTGG$c!%cp-uLu{i zA^ifbY zIA8Isz%%&O7Ji+^)Bb%zY>)feDzlmdnzx9Vo7CnOMV1id3sb}o9A^DPNbN`kbPiw` zb~I1ecI;D@0$$qZic0YB9<8vx3O~$g%S#}s7u?zqCIRqsMA`(VH8KHb$2-4U0e?mA zsS2Vb*vC*8Fj(t6%iyd;a=*_j;&6!#RzDvHhQYQ zIS3<)b}WO6;M*O!h?c+FWO$`PGjFEQHeh;0@HU*y(!Uas(w^h z=3+#Km5;`0&ud2eoF7jkgY3Z2Y znn2#NPDW)p`#qUV3X(3=ns34%4Nhc%Fk6U#e!ywLG-vtkfs#K~zR)6?Al;81Ha}oF zYlM5|L+x9Em_3^h?*@zKKkZw@tP_)O4sWI@{EKHnEk!b@SzwkIl3t;v#SBP;h65k!SOA-9Zbd!igJ~aV4Ob!qVa6 zkAGW{la@;4^P774*;~)*mtqmoIcJ~9lpTmB-v$R8JcTDP&q^i*29h67Q^4>ycid6q zpAAWFdbxJ6s=6uRtb4-vQ2TCrY=r_jG>)#vzGO}z)jAwM67L`6a_M?jU+`*wU&Oq& z6*u$CI3#lT@*&uK8-pM9E{Uh$1j*!y3+N95R$)R6AQA8p2q0#V{|eKTs8r9bd*B+T zUFXUJHs?8ZlFH({m%)SY9oV=6Hx5Mii=?E5mI50k>L&1W=xRLMDbz~>+1ObB~0U58e z(*r;aAZA~E63Mxub|s>GEPrJs({B|)k=3{-^rR?VPr%;z4$75aop>8>w?RtIbi}aP8a%* zruEJ>Z^R*6cKS-XsN%<)bq`BxyWs z@%M^@@7&ay71{&AiH22s&BB3(n)hyJ-V$$p`XE|R@)i^6*K*}4=4cVlehD=Ps^GA; zD}-5u)FQi#j%|#AcfaOUnCy=TMNi^)@Zo4}>U{(+Y{&}Eel{Poe;S?`}2n}cow1~Xj>l?an z^GKeblrD&2VGijIe2;c@D|lUYjp3ON)=4Z^q5C^~{b13|^1@}(RIeBDvIXn;sh_nE z_$$2hIeZHcQSCU`1Se}ZcnZT=R=DY)yRSq3&(o}Hc&Owa8BOHFcHOViXU`Ch)=Aox z<`PG0fEz#B6)BeuMuu50|6ogY$?CE(nmYLxQ@-`aa|tYeKY#)>s+GK~;TVzL-W*1Y=*6xp z*SW`5p_D3 zG_PDN;C2c*LQG2`Q3{cDBB44!;UYHFkd+3fCx~tl(+=nzHKe5oUTV23X<^Pf}+k=6qj330ioeNvc`)gLKgCl<* zp9LBQ^1bQ}5^y}rfSi^`HI5-*!}<|$8blL;U^7B?##wv2raEfo9uClq&ZE*t2GQALIhk4;~Oe z(t}0$&>k8>nEo;(U=-c+B1kv)UYQJJCw= zX%^P42A&vu6H12jPYJc_)r}8U3z+vc2QI}sz5#{>iV`=7N<`W{A*lSIDh8c-EF>E6 z!q^9#(vRN>DQH-t<+EQZg>sZxd>uZ&itKt|OQWZb!J?^ff!=LrVAv}qSY`fl^-NxVFGc4?O#obU)5#TQ3R!mDKav z%;6-rWnU~oatbQ?#`%8e4*n}dGG;KAHS+LH_r^n!$Uy$L_Ze5F%@2(>*I&Szk6FpS z$sI;}wtWjl`m5e=uzn4FB#|shL*++~$w&E%*-A;KVI+VGjgT=R4F$X0#UznGEHPcK zvjOBNSJ*#Rhu7hdMY+Piv`xYj2TDJ}!HZ(-p#l&^S{-;@53lO=ZW?rQK3&YE=XdAB zlkX03yZ_z=_ZlADjyqCX50XjkHe2}r{QX;}i;+e*8@VG9;14L=x=M~U8QFKwCB znQH?;AZL2K>O;?k(j?uOij6m>H@LIkR|V%UJ`^fD74OS#L%-?%IbW%wzjb27kd^Io zzhtlnZQ|qN3Wfcv8ojtZNh=2h%2jv5DO6{jJl+otel|GUB5yce6ZM8L15jN}r0>2E zL~Q867Z~yNvlS&Zg+2W|ajhLndW5ou8fs^Ku30?g34sTn`ttqcy7bb*MLm(nY#diH z2)Y2R1wT-k6x`s+XZ*u0*}0s)HgFPGeY4d9gTBV|Gf^Z=4q7TKLm(A2iUh3+p~`Ar z4c4{2_sr3uM79Ql3{bG-FJA#a>2JZ2i;+FmeVVs8u9aai^?9s4fQQe(WT{G6$^H^k zyTw`UxdVzOdFxT!9!aEvgOYE<$(Ca6?(V2b)F%8jHB5fOZW6n*GSdxLpM0Wp=g$zy zTD{(bepH7}REA*U;bCZMtfI&zdC*4uGWcHK?k?dcW6Zf?Un|b>i6x>08ph*s4qqEn zNRTS`j)#TJYxZEM@vv|R>n>dtwVOvH7SMaA&Gh3g?5*zI!mkQuclG70lIIy-8dy87 z&?u}Q)66#9G5y+L@;z(s#AO<5r`_W64{J(Z(+Y~*3$+{O3E{zy)d1uiO*UjZvZt5n z_-N=B=5fYkz&88SRz$%Tr$LSwmw16xh<})0S#>n)-{m53Jx&4i&6zODBL*gA5ajZy zdsVmg@4|UEoHX_q9Qy#krQL0tcR;=X{sGMuLuu2K{Tze*%ihYT4&+{IrIU3^AMEY9 zvh8QWG#ES9Kg^74)V#c8r8a>5d}~G%g(Z7-MJqSq1a~DU`%8!%u{{mGlbLmLJaCBw zjFvb%PFV&lI;FT$z!7Insy%qJ^ffj?+!CD&gjCcP@HD7E7FzX9jq4?VdF`7R&xN4xI zoTrbTfnR@^vrP8Sz8LIs`pYZb(Q}P(I(JRx>u9w7bZXGw(6+v)JWb>sC71);YtL=x zXnK~MNGVz~W18)sL5n98U)$rpobbYhA1uu{!T;Rt;Y}YNYc#e7wb)i1iF1k?xLkM= zqzz=S@ocskx)3zXbO2LJ%Cw8!%#6m_` zeA~Tm(-D<%*fr|rEe9Up>Baq78rO7}VSF=IZ(EC83ZgyHJ&{%NnI$cH&l2q*92a5x zWu`ph-a*Csll@ah+6i=D<=RNcRq-lSFSe(B#xLj%INE#nAtfwi1@ES z@c;>f`pG!hW?;5vHC`5?U+c^RJ9Lt;rx*Ajnod^P0mg(>K8Ou5Fk}7T77GsdX8(wl zLSs0I%5LTwuwUNfI=7~j}={#luA_HH6t`46j+pw-GD9hVrljY=)SjkOk|rLq9e z&0p72Pp4a*r~40|D7JrnsH!6m}Pu*D~SJYVK_hLyX>6tR#sLSpFb_((o zsZpUaEJl)x5R!vLpaE63wcmJN-|U5nfw3`WmIfB&onUb*3`1$ArEg(t1M*JRNy{%C z^Ip%b@kenrw)4ExNMYJONx*E*g#_I<{d=A0bd_k`1!$~2> zLsF(j!c_Gj@W@=nN_uM>(x!KA**@JfMn<{vn_HUA;X`&~Tah5SUpiCC2RGc=5s{_o zMoE}FGXtChvKZe2ASsyF2-U=6@58@`J2^&*6rGmCE0{VTJ5^ zm6ObIGc9~dtunxmWI3TqEXo;q_VpQVzSnfu7(C9?Q|HgUI`ZG5L_7Pdzx0)J54dz{ z$NsQhwQm_b^igr;B=zkRZ?7Si?wMzE$Sbe;)fM&>1hZ|4YR%LvC$czBG6v0qE zWag~;dAAO#`K)o#$=sM>7k^ne)?@P zX42cFE;0w02g71#-jZowBo_%#Gqg#sFD{K|N7md1m51v{RmA_RQ9%nMnEOcI*tZ9X(gC;fP5|%!WgaT`60!)|+*%Ynt0HhbzTx*ZT_gH}6g@ z+;{sWGu%KTS0a*TE8!U_tSC6K@N(hYu6?i4_P7t9{MC{DNqt))oAfpvea{Qg2mml) z4CKs4pzXQi+bck^F0Nc zCf>qFkA+oD40Qc->=0KeR&!pEQDYoc-3oI_%TFp$h+6%mCZ71>5kF>ivT_K^?@ogF zx^r}rkq;raKct2(Kqr$gZCzXL#2_#srCTvzGm@q69&#yqvu|G)7=99xC5l|*|L7@_ z&+J(8S|_U3qbYZ&`11x%EpYA8Ub(Sus<^|JC{|9a6cQ3_XoP+pI0vO>IH_fg$fYqs zUx-AQ0?7Up#0Q|+MdrO=R1o=?=;)f>MGA5aN$EyDjZoGYI-O*EP?7PtQeNdRhgz^X z92=WCe9lIs7{NSYA7e?ypcC*k?ueG+XLl2wV2>m*_2p5&7{Sj8Y1xXUE4Dwnil0wiUcPeUj@qEpsHS`%pkHXc#$FoMlS{C(V zHXTp0^HTdj;U1%-a*Vw^S}&Q_HZpxA{p($hOYM?igAIxF*sJ-*x8auY&9noG1=-N= zT<|afntwn-S_6!2k%2pC<$$oDhQEvLYZ=uZsvcwFLP-Dmk)Pyl%yl{UvAo^I~cq2OIkjY3AR%Ka$8*AMu)s)$A z0H5ccz zA+WYpnaDZhsk%3{YJUx=Xu+4CT-E+wYBL~ZXvkBSM08ysAQ}UT1>_)4K{bSI0uV7a z#%ZlxC|J5s70G>`Uz%kfc%XQZAhx`UT2l!$eH+`c&us-=ihfGMrhnHHdZTlB)cApm^zZL|5+e#yL}4Q*Qk}k?^7{*Jtpd$A5~&pqblSqN z-uZS3R3Zm%BE$F`$7(n1roCZa*~E;yJZYo$IYTcWudLX0QV_|0nE96~x}GBl*?DBY z;hL#ooV!wQ8rFrI15&VtC*fUM`6UhfiD~Y0b7hWa?{Kl4x9Jx4Nz{t}01x>ER4T-1 zR+tdVR|4n)q`OLkU?XW2O-Iv@NndsN#a5I0;|KTbh_(8&pPL_hz`liTxD&3mT0wZu zRll+Rt%u7?hv9theoXoD@2E@B_Kdw!pUZiHBL0^`&*(@OOawLH4!CrEw1=eupDO1H z{Wmepi0j}<4(uu^HTBezMH)htANA3H!c{8N-OvzVqbB31#A)hrSEm#~l>I#z)X@9~ zaK1#3T1CRG05%?bj7LbA4HAf#K_Dac*k{gtZmFL={OHJVm0h*mW`1R^CE;x`kK<&r z=&$3-<*}$GCONyNkl3D@iMbD^w(x^dAiW`CkpX7*{8eBwAm7&Bsrl z0b++<>sEGfB<=xv1Uq=epjge}b$oAn6;W}M$#?1qsc~UNqa)ofC=UXTO^uB+lr90) z0Ohasi;uZ&hKd6v9<2529xsn+-bx=wMxN?jcXG0yR9A*p3yEom6Y-X|-S z$i@4oEx3yB+ok@XZ$X{Fvn2HA!PMnPwF+-u`4Mm*p)Nf&JsKZS{Js{I0-}(n>7KVB zez8co_efvxqx>h}S%$0i`=Ui`ATzFxIne{W4TjQ%pH zQR}56}O)U~a}Kf@&;(Ll>0RR_CC#v1&JosbT(7X$abpnmmgu)>oJgz#p{fmZ zZHjk>z|-Y$EmigG_tkfT=(Xz$w+RS+ur98Hriad)7wQH-hTw)f*u74C!T)Lj+(YM_ z1!otZ3A5B{#5-UJ#U6C=P`6;JT&W{AH46a&i$ih~M9LIqn|YD?NNL;>>xR;_^S$=gW~*G)eal@Nw;* z!sR37ysZ4ieP@Tpc^hXCV}j-$RY#xU1rqeH@3rx2ab{V}FAk6o4o7r0;9ft|2;B);ou4;f5JAdT#b3I7HBmHEm6Dg`J+WZ%2ok~;B9QRxJZ7UQ6*tdlnZWQY|u zQ@BkpF!2(^J)8sfA-PiqIu_8x&%+I0hlmakO3{FoXKh&}VmXdvIDA)@jHs=xor)w( z2Lb?byM*>R`qitZSJ!2%))9K{1X|AWWnmCtfD{NR8bHg)t|P9EPB&7vK)^?HOhBo) zgdQVwI{!dDsM2nlfp1B`Jht_kK|b4>{WAG!Hw6>S1e9*86Y~Wf|JW1kAf;q_|5PW> z^|Kf=84t|-NIx{;WHv0MV%6`e;aZ!l!8Hs(r>LdXInI^a`MEe!-!<)fFLHM<4iAR3!fojLv=^gt?2d0vptJ4#EZi$< zP$OL9jAY||Z#95aSa1MFL_;gXG!OzF34JLPtRcngmhMjuo|Veszl5WL256rqVj5L938T^aMEux_NAWcmF)R|5BZJh zO0xF6h$Qx)K)_~Tmd}!&x!XHqCXbh9k-vq?4Y&_M%ea1UgFvcXiGvw*V-pilBf-`=R)7z%67W#Q-LY&C zB|ciT`rl+<{9T(x0Lul{--%^S zuYku8K10z|7Q1Jep*U|{aOUHfiBo;p75{r!NDcZoY1ceZ{FEM`7Hc)c) zu052K-P0_~d*qg{Y>@i-E=b&wIVXX?NACpyuU~_FS>63LC(&rk)IE3j;!j0-s2Gp_ zcU;J38$Tu9jCQlg?kaf*JBBL-20_6FWOE_Z7NoocgJ(g%#IaS}ajxz0iwj}VZc0~ft~wzFC~WybYj!Wa36@-PpoYVi^_9iuTsB+3~KkvH#%lp`^fI8GkC0mCJe z9t{RZrQNu)$d#nI79Y;t6Zz!Nw0`c}HYAbj2oFTUb+;mdr`*h6Afv}TpfcrlQHFd-zE?Y;B<(m4$;U$5+0~;`- zL7uK|VbR7>?-g;&t(j86fBG9Tjlf7KsO=o8L*SS*SGdnX!Djo~S1oLj38wfyny6j{ ztqCJ%PgB4nbpN%zbRU)u_U**%TU+0Ssox$xMb+`^UjH%%WxEtzRWGz>Ab1D_^-YH5 z@vp*@&<2^$n(k9pw_^ThS-|+y#_5w~VR$BVA1w{Y>Z-$To$239>IG7;)8~grX#M%) z&r@FO*>{%E@&8QsKYXF~EBudf?rOPSrql4b>C>k}HC%Bl<9)f~lbd|VGde5xR<36wB zH?zbkuwQJfao-q=c`G9}nw-u6&@Iewx4VyB{YMdQ5%|TN-fNZ!@7o10j#L*QXMviw zPMF8d|hCGxR~me~)xfQvsTAm^-4ExqujyfeC+w z`Bd-i;u2(r42oc6&;Z2l2qb*tU{DA29iE^#ieHzw`3ighYRlH4_Au00hB1UdNR!f! zS~s-~OZe=VMDHk;Y34FNC$mIC-kMdhno#$`Qx48+gouxWaUx_WVh^nJ@77WUr;A^oLulQ8|hJb zx`a|>EMv1971d6U;^T>O<24D!rtP@m0H_okML_($FM5Dc?ljM3poNU6Ir1dHNDrRd z(?4j_kVK#l50QTV&mq=&M@^q%rl3GiwJxN7!!+A@TD?b9 z*rzYY*k^CIo30VbV#+^syz*5+&gh|*;&ag%G{PZMg(Tg#HSx<83#MZx3VPzJYur5+ zP7n{db+3t3Jn-c0Pf zM5NG;y}U-{^TSF(c2M*DXrvLboB)9FORD%)uwRhmr@}AL%xB+O9W6lzr5EDr`Bws* z_6T&Ch}9dC@&q7ilK2mppn;c*9wCqZP9-?a`{*LXQ~MA>l)z7kFmmqCVDpEhP|m|! zUksDqUAp9Kej>iD%$zh7T9at;NFpi1w!szKtn@n?ijb*pC4O&LV+4iDqp44vl>a@l z{kdYnT0}ElA)J)Fm-?HnTJB{esWLN4BJ?lT(G^n#sxweCfp7_cLxinBVroIkYcnkg zNo*jxfpCN-aJZS>+e5pvyFbcvr+x2T5Y1NS{(7j;mDH0e672q^n+|0LwUK|eWyit5 z{((9=ip1=&{CKnOgUgUTnlZzZqG#UQ3YeDWkmr&n5YJLAVNE9F%p zV{BK8jl2mF%DrKRJ7(24;MV+i~p7{*xKIsi8#BPgryK6n6`oq>0}MIP)lhaTwJ zFkB8H+HX?`PvV{C?BJ)Qmifx~>BISyFfHHPKjV%ZIxHNE0)U=ex_Yaib-xijC(;MZ zpKtxV2i`$~?mmz8`qu#fs{#ue5ME6=`@F9Wzz!>+e-NPcx_tCaR{Q$rBbTJ|(@SKc zYNbv$b*`~vI<{S-e|$B+)xRBwkZj~?;9D&Vzu_5*3GeOLrU!{M^e+!Y1CO4+AfwON z(^6A=k(fw@YCy*#y7abcr% zdxD811PN~h2N5i=l|uN|i71E*zSLAA_L3!uhV71B+!b1HJ^$GIoHSSGM>v0=KQr55 z9nm3@y#2$dr`0Lf-NJRFUpc5bGB{^@>QPGV^Vti~2`5hO_4}Oh-MDe%E0_izk$05w zKWg-*hKdgHiAWUx0p7nsp`p0J?Z)BMqGS-dOBI0yjUBwX7Dy6HniQm`zX0pB0|pLW zK{V5nyS8k~?=ivGc8lVX*FA0}UC|1)k3RaX`y?wneQW&brQl$D%O!Nw+bEJiUFt8) zGBFbg5s?aM>V4%Adi1cIlLT$$VH^!)YhCi>2DY4wMEgri=5RWEn?E+b7k+^$PIIN3 zcV>oCoOx=j{Ee%Sa{~c+_kA2Z5(YcX4kfGBq|xBuoGCD}o4Atx*yq#MQwtN4@d4X6HB&Y!^2q&WmuM# z?&9snJfO41gt8Ybk*dpAVb7t3ZyQojKaK2kD8^_Ymt5QyT#!-2bzHMZc2!?d&`Nh^ zx};I&z%n*Cc>Fuq`hiRiF<~yyuO)-esRgEEHUVFog>`+CBC&{3yHNA5cyvCs{+GI@ z<{V5mpsuC87Zq*bk&)xEpy6){0e$>Mv zCk#s^Le)wSA91*X1L%Hjs_*x%Qo-mMq%QL~{JLMfj9321w^y)b`rS40$e%;bZ%2fe z)u`1<9bW}w+)d6ZatWjIrzIwKq68uZlCJ1spg#%{i;w`HB9BA3SFp+2m~`kjf@zPB zx;`{(8ZfAef?mK+d-6oi9{PEd@93!Z-K^aafBOedy^-zgihzDK5=3c9eE98~TElZk zh6CXr9;uIZuM!bQBm|{lqb?^O3G%85)@Dt0dYAzSnohSYS!K`G*gXH6?c8x^ActaS zY3S(BH-VJ-X)o=M3ARFK9<9GH&yXbum;YMX-00(I{gE)W*gQ^&!dr$>5iK^u4F>uQ zuAcsWLPCiHy2oC-8lVYh5D>UhT(^ZAc**YmT{|#n0}8aS+zSj(Q4rZHFk$2EEdlC5 zJ?@`VD}LBC&pBt-l7ANsgk`8KB^oxnS!Lv?bYNc$&{DE_)~}K;Q&^PORa}!etdW%c z#Rnfv`V*|~SrzTDK5x72^Wh-$60ot|u*7ijk76DYIWF zQCFdrFY!6|Mn!fT!lR%%#l^uvq13gs<^d2=s#v__$@?~(o36S|zB4_)bk;t=OpAJr zN|cge-Dz?n&h5FVx7d$8N{cIhP<0=P=G&VDA z7`gYzWKL?0&7G#|l(w$+8~n;_`stQ`)9uHN%E}b4E}l}`77EO1^TC|o(e^J7!amxY z2}Gvl%MG{dhEvRh)vmvi;UaVW;`S?!B04oYsOti3g$0RuEjxFsJCbSt-h&O)0$3=} zMK=S`Ygj3G##T6G(*b@57%0F}i`Y7k_gyB7)pc|(mR4^XIrkZ*0#Q_ehk}AHyY<_nvc4u&X47#<4&tSz&;+8Ix{md3AmmBC4@qO+Zh-)Z)3i9C;5DE0Tp?9@FU;k z&*y$7HD~QS3J|0c&%_g{QVtg_;!h1_>*nuSg-5J>P6tF^@t!g>rhTOsP{h_x!QW)~ zDYS8$F20Rb%-DR9+b)NNn7BM2rX%U$BZdSyc*-z2@E~)d>j^K1LBlohpqDgw-)0PI zG{~N(hWUgl=-ZZ8kzRPz>Q?6yUa^fP^h&We08hh3W5L|UXr(PJ*njA*KW_N9f9WBQ zq)LEVtNXV|a+P_@0&bYreO^1BeIee)!wik%&)oN4s{i_4#Xu1=&!GxlCQJ)=~(pC50I*OcD;x8ZRWwWps0cw;P?bx{cv zT&*}Jan+Er)U4sv#ldR;^IyuZ%ez9)XHdXe<2Lb3?m$I>qB0Y(kNA_*o7{D?-PkkUczYng5F znF5_0{0!%z46)SGoEJ2VcXr>m;{sLJAY_1faGwg2hM zVCoyKJJAx4`K}f={TRe22j@tdCW~@opn?(4Aq9odrOo)+!C-{{oh`MmW zxHconJ^{W1*UA|<$(4N1)nT7gNA9<_(^o2sf|!a+<|~PgoKuyGX$yRTffDwj@Mx67 zciTw?E;#uiU-k` ziHY4bHm(X-To&~g<2?yD2-}!k)DVizyknO|*?3XQ^+d#HwcW6UVKtlvHq#=HBcZyO z9EXy>f7mP#qZDGUH$`8FX*%X$h`!m8gc45~X@7DgW(PlrmOVTH<* zenD0Ms&iQJGb<@S?H;6xjae77oE!we0#0>EVDYDQ3%g=>qfNH61Wu|?Ttl-RuSM?T zXwi$kx8&MOb;>1xBcbI9TFZ;JyUDqxaZzH4wQn$uq3ENxM_*(qOCAlVyN6u<`Bzds zUW*c@OfuMx?N&TFy~R5#doY^nNEjkhiUW%Ju(Iy^V$OS&Fv>TRrv)QtNX`P(fOx*7 zwXgP7doZ<0GMnHdKcG{Jg3_g!&=dl&KPc-|7({iAV+=Q-l3qH^WPxK?I=FiDk`U2evL-n9ez^>1=n#v zY|jy?dV9YA8AGQiIGXzUr{ChAI+XYPGmdt1!I8S+$sj!xz3@n`t1x|Tl2E&J zDc1Eq4#$Y@D=p)eLrZxrCvIq!en(5(rC9F4r6ooR`e={m^2&em(4IpJs%U%}!AZK= z&>MRBG9H;VZ#wvP-@%D!#PC9A#8D3w;lPQvuCRlH0HRlHVV~xN9@kFkp43y689NLW(r^ z4fRmK-`<#{b8&)G3i38PA1*nHATIL8(uZZv93B|iEb4q z*yi_sq~lSyM^m@I-s0c>_3w`M5)MGoISMq}veLCW`41M*A zu;+*Ixswn_*ZLc{P|LL-JIO!)rC6LT`vZTy9FuGAjwPgtqQJs!9nC{`<$*2x-DO+L_`gLjCu3X0x%fN~x$2 zfnG<{KR9^OULUPy9Xs@Ihx+d9bloTO{rmT0)(Q#==_AX+Ut<3AW9n2P6bA-30kQea z95f{)8MhFg3a1wG`+f!_e>b-s{fGt%>UMA#O1k7-*9aFj$s{S+_`~U+r$8;7Jy0>R znvu_hUaVrE=P^FA!y?>9PRrJWt%RpB*6r4s~Cc=b>i3e6mMpvChYyEU} zUVrZLI20@yme0}A(UGVUc%vg<`wggIn}Wf>&jd{L8G4D3%nc?IV0$sfnI`$SVx0xd zamT%$eQE020kjYB3v7cBIfdXvU)tFYi!(E9Tk&8h1Kx4Y6N~*GNUhQeL*&&hKYDEl ze3kI;+MRjAd{^=b>`Q;2fSCTn**=|JODhmGqYMlT#J0citw_Q5{`ZZk_bKR`%&s{@ zf>sb|4H5Bx_41mc@J-krRkJO+PK^634B(~ZdqGD)Kjp=Sjr^uRmkV){BMcDYd2ov}3xfN|7k=Zg)K_`wpPQpB&%=;=IAmZr4HWLI(;r zy?y@#TTFNX9DT|LDH>qIj0kp1P2fMXhQ%ESG6Lsg@4uCdNN+FRZ?LLHbbNZ;Mexo4 zEg1CUrRaQ%i@E>)@yOYeQS|Fq``F@_x2+f9Q_i`!UbjsExoPJg8FWMT|E_}V&CO=S zC?=AQKEoYg)rRvk55%$v6qhoPPzKU8M8yQ&hC$SW7eGzCZB7a=<;Ae!owF-p%jZr` zw|-9ToZqMhkmz;VxdF3OOBv6>QfAa2jdQqek7NliDqwWmVUAt(@neFdUMwFUA236| z3=PD=s;!TnE!N`a6WAZ1uOxx_sNcAbU<^lkwv#RS4j9emJ>aB}2l}foWqI?|;q1gs zY;V*Aq{EYn!^@mDVG;mDR6SfT#_j^(ch zVMH_>@~*Eau8UurCMAwG`!r^C_x}AhfFhEnxBz!OKj@JBisW(^v%P(bn1ZCb{h~xn z;ZUf|f#B)WH5a6czIzvkj6>U3S>g}_EG`4btmJ_)Lm9%12iWs%ch6v>@-+)@Lu3K$ z1c9P!Rhjzz{#xpQAH)wEc7)s}<;Ck2dTgGjHQ=Du74Y>yl#A^;+H3cyU9}LpE21`R z+#_#|>YllH6<*Qx$49;LX%9bPCwsp@r60xq^nxs5EWMa^c*1i^e>&o5?8A}9vw*2u z7tmB2g0i#f{OtJMfVpA0uH8cS6)10w02l`+fp(ap-2iur+pGnW?ZIPKpMiV~@b&d| zAF72`CcUbP0vzfOcD^ga&^)0hj8r2tQh*E4k%S-yFjk`KoETJ{zEMi~Mqg)FA~>T^U|(k~HHQ5wH%TfoKJ3d0u+Xwrpe z_|ZIrWZ)f1Lpog3%&$L)Lmj|6-+os3z_+fds_F-J*~7?LS!K?qaB@4%opi!N$#CmBJ2FI$EpA%`hok; zJS~z^fH)?>e+^wT@|t3lB|>0lm5+J@G$yBB#SHvbDJLfZtVs=LWC+Dy0%Je|V#Q{l0|LR1rbuoPxmu(v%FDyO;D-W2hCUhx)W`_31lPF zxBt@8l3psppn-?jOLT04GQExY0;qMSzHqa9-l!%T@b@Ghzk^$?JrmcT`^Zw-IU21x zEAo1tk+gB$CmB!*qHcblhe(<#)1 z@al{YAFx35-BIkln~yaC(I5)ocrqo>o z*3K*#;ob(w3$(-C$QNMkz&a8fCtCjX>guad-_2PCS@W7cMmFGCdHY9dE*PrkU|54XE>{Y>H`=xaxfZvF=SD=pPBA2bB)!WU9LwM~XW>Z^g=Z8Tk2PD`FX69#qj299amMOP4ymaT zfsGIiG!<4vCue(=jYeRRwOjlyh`a8bmpG-6Z>u@f_1HDFl3H{nW`sW{6 zZ946m{m*c~ZZFz1}cfOVb@>l`_?U}YkR3dHC1I&r798%xW}W5L*+@c-A> zcR*wLhkxHFd&}OmY|2P7GEzuL2zd%AG${rz6w>-u~?*L8t@G2cvFSX7i42?z*~WZgl)w_pQ7@+YX; zNq6K(0Cc~Dvf!@)fCTpEEZCjio7{Jr;!fSx@b8$Wd14?$2>AZnYTPY>V} zzOX@fpk@NM%n#C znn3a(Bplt~^KNsln*z%GK%Q=9CjDl&A*M9i_x=!bZHr=efsD)I4D8q4hEyg zqJ5KK1P-t4W>fEN9M}%x0XZpyW4p(u2OZm|S6gr5Th}W&+kY1t+m%W`6>S!drF6sVm^=y3eJ* z14-~RuyWK;P3|%loX-`gmSPS$_2MtJ(1LalD434UO^r-g<{5_kvgW%W6(R?FVe>V%xRz zZ}iBJZ1HK1<@yGSf#fD+uPest*!oMIrdi- z0p9@iLrMR=&yX5r-xu0>H=uJSHuiHL7aEujp4ynikB@nGpSdHhn> zJN$9Yin?kSF;pcb8Zi>HuM48OYmP;`i?z_s!^NSDJ-^DdFekC4lZcSSJh=&_nK1-nM(s z4b4h$tPEll6*QMR(O6sn^fp)auezwA-<4iZ$4Dv2KtQ# zIBImv%tE1z*1~W#H){HUFeX8a${q*=D68+1Qc(DtiUz~xhqBK8n@O%?WJnD}t*g*M zvpbV5Iy!m`RU?2V5Y#zKm0LsZzm6Y0ssslU+`o{)`!wbZw2CA|87i6G=o#1i@{GwC z)M^X>O{{?d(;motKHj`&WE<8||GXz3F(XT<-(K53KzOr#-omks9-4S zFnU%}W|zM6eZqXIA9@sGd>87&f~iuqvB|Lg8rcA(z(49BIGo*f_szR^{6az$V82}| zy-?=~Uf?*m5Vat`4g#+>H9MOcI<&CD!^lJU4ZV~q;2;mbIJdtCZA=@$vOZ(Rc+w5~ z?8~F&ul%M(a0f02K$vn{~&SZqL$ur1VRsj;Xc9J6gIzUwy%P zsC$s-wr+*WpHzY<{h)vqknezNgJcsGmK-46P`%3k_xRWtf&fGCtf=~KCm#^J)Z>j| z!QD22uu=^&vt%spUe!E?V)5XtyF#I1G#ngxm*lOit4jw0rPU_>u$vH#fp2r)1cQo3 zAoH}o!1`OVzMun&I@A zAhk;^i;U=G``JtK@rgx4SJaxkWH}VopTLDO$EBR^rK1yG>{@r-`6=em)7wntjV&I~ zb>0@H_THx9=&Pig_CE7;e{kpc+s`K5qSF!aZnVKJrS?Td9SV9pB)zzP-xCcxAXZSF zc(dW&I1>xGN6y3t%kr$XjG%6c*MA^b0gv8mhpIM#S>eIqx{b)N{z)U8l<_^cdFzY+ zIg%b)x?ZOv%7kLWdyEtX#M!QYL9Z^dH4PDj0+EW7>TPJNEc zgHQeH8hEBUZ)5GsV>AvSKzOYl-2OQ)*#qp&M$h35|GD&uSNrn=Rv&mRk}M>KUeyvM zuPrYY71=(B!tX8y!t`Inw^s8UDJxbaj0(MZL(h6L9x%DGL)uHqsuP!Mb6V(B3AI5FE&)$x9|X|Q6Up6|9J+pH!iD>5vzY+Z_hsyDqgHeQ<#%$<^#|U z3Z?57|3893yGHrnNtTveKZZnA&OHiAn+K=gS2^XT`T^|bF)QPGG-z<0XUR>R0A}04 zq`V9?U7N-Ai_)I}>n)>(qw#=yK&Pj${sWZLY4_kFM0)QTmDZ1X7bbGO^y6t96+-*rne^m z-(LS#ip;2V_6Xt5kIpIQD{mJO#I#BF@v$wb%AiqpiVL8$z2ZR}R=sjQGZa_)Q7@i*f{M;f|o^j^UQp0^jqC zywNRjyN>k3z1l~k3wDgk&NkkA#VfDs`3=Z12`JyDecz0`@35-sklMJIvUMRV&^nHJ zHE^p+s*>hh-drTryK>~(zu8&S<0Yh*nxzZ3H|E6RygZv#S??JLneCn=f*HB{Eia+= z>^Y;4G92JElA*4n+sjx|bzJ63MzhEws|_x#`DG zCehAFR^%8{vCz8iNZ#%FmDGG?{y!og;hM|gyv zo>ux}3vNs9DIfYprt8{v$iIH6bJ`tD0gKzR7NRs&yNF-K6ND`fulIbGA(Tc}503NT zp;7|!s$75B%I80!#N&jlwiaYu4=HHbZy%Cy#N2+e zc&@kVE!!7R85ZiO@`*{xebB;N)(yAW(zv z0u9X>=U1a&I8nMVDaS$o*M*&26AdA&ZhLO?H;@-*dsESN7j zSbDFkWo|yh#FD1J|4n!u;(Cx`JUK3yygEJo`Y&+Hr389EwFL5zavJ%&$QCml=|8W!xYf&g1oqoPG;1I38tbL zt4)K74cmKCO>J)l7j#5autm-b$I3MXQxq}Kxs^a*0HsT50m}{4erFMkZhIWJO(_Cu z1yCIUam-a+lyst5Fhj-c5glL_??c89AppmU3JX($yAHh>rBElWJJXOK=$raQU`$Y$ z88V*crM((c00_CEbT5F?_DS}G7e%uodsQjVp;#Wh1&%Czc86=+C|>L5Yc0d1xc&_pA?D4!GW%>cfn zx1^S8ms-WkjJofsI8yybtb16x9qP%Mlt{8%H$TOX{@b!A=^~2Jnh1NVVLl^MEc~>) zo|WvNT!ch4anMqN+m&$6jUGzbb`}A0@fg5rY^Qz2SC|%FkTL+toF~-k3+myqpv>gW z$+W%r+cz@mA}Wl76kxigpnnLl-|`e~Y+@qh5sess`W-{ii7f^om*>=}{DA-kUlg9l z$)aKqkZw699>#cL9<^Fz7ib~~!-q?%=k*yARt}d)cucc`a8fqf?&b`*W7?1iPZezg zXhgQyosJI>vWHLami0mVtg>s>sA^YrV9%M3hQ@B-A`pE>>HUL^+4)DkUC-)oH*=qL~av)62R9hnxDJU$$_Rw69 znOmvfiuxmv4o%b~EHOaw08;O)(f5dUymZ#UPu3GI;Af2iH~Z>W1vxBKUPhwM>b3e1 zInT1a_3XmYjxhHlhOy`?08u%p!m4;-d-=k``q zp?;Nb%(hGm3Z*A*NR$yK=>bJzggN^3=VYZPEc#wRxmTbnz_7uJ6P5ws89?M8wC?@6 z8ab#i*9m<%#3aZ4CFS9wsU;sNqrzzE*knKYTXI$J4THU2(|8Ih8Nv}#Pl|@qEAWb$ zvtEwe208!|M^I;o?+AFA=i|779iMfubH)TJMX`*s2@n&zYm-)htmRVRVa4dK+6NYH zAAxWN6`A802=cLa;f;gVzeS|j$zT`!R)9OpZetD<869|v2+$kGP&)tj`>yIA?N&p? zIf~F^CV(b(b~I_}c`hXD{kU~Lx8&nnR(9{QG!A#*q$C}S%7EG1Mc-=Yg@MNrpv3Y zKoleBR~2F2<)akr6#(vYG>(1Ax_BT(=j8oiuPxj!@39hAKySeBG`<{oc3S)kC~k4{ zmu?);mq5MEOBKH24t6^Qn;wQPGxU)}`)jx>I<;dU8hwO1%k=1h3d61ZZHD*Nw_3NR zQM(R9*O0>dfE(5+#*`oE7$N*Dvs@vnIXr;61~Aextrrv&sn;!0Z3OVDq7B!7LZzhG zb8e?j;BNi>&uq3`Kxdu92uwL4qP(lxfp=MsWBzxyhhTPr6tiTC3pcbm@9>6k+fW#5t0;Vt z@>wg2_lKWC7v{lLgy4Jaou2(k>d8CbL_rpw9HS8cdNmu& z7R{F~P#k6#kHobFV1q1GDXS24_21#fZKu4VsQx;T)B1+7`qEI&q7IGKc|q$ z4Lg!jX*t8rvsB1(LTe~I^5XSY6ko&<2d`{v!^D6%&YPQiKLsIqA+C5TV_TyF6 zT*_N)Ztn~>jprN#4{z5KPeh*$`Y&jM77{|f3K8-Ao#)cFRprxWmol=M@c>S{TjG|T z(XTj%F%d(u6KAKdsVMzh3vG{u>|BqPvb_wP5@o<+8Ie@wV{poR5&BO0Z+%GjITkR@ z({wA@7pRPj)#Al5J!=#zS&%7TQi zeI}m(23yv){^bv%EPkD{Rq1_V`eyGjp1+Getsa6lSF8!6M#epW&S~Ye`rZWLhMe)0 z={w9{RYGuKTS~6E)7Rww-M1Qqp{pQ81Fj*2ZQ==rW^H!U%W=Vz6Q~Ad0R|q2Xtq4M zQ|NgEV@+G&9VNh*6aaQSh#@EP(CibC0bh7@WPkQ%J|Va+67pZ2qP_mEy4Os>RRA>J za3_rU4qD>y$m@#^qyP32b{5vbx?;NJjO{JF$CiU)7|Z5?#sS_`8+wQ|hY8)v?*;6M zW$!<80%@_84#?uGrVd zE1&+dNWp-DltAfndAgNZa4SkZVMjanEO=f0$v@_&W10k2tNsUq~-J)A~z zj~;NZ2*;Khl#hY&N(D&CN$p0;S9x`j3*pisoNoj44}tqMU%;F6?{(EgKQ*3t=1j>w zLQyDYp<pN$WcVR}l8RFuh5@DeRoEP7ED zy6>*maWM_Js4wX{NfnE3L3nYVQ(k>~o%n>5KekoLD^>g*gIGj!P} zX5iiQ^U4u!;WtKn}sK99;9w6QBrfa&G8-f>uI^%-eedUj^3?$++|cNvM> zLmASXS1?|j+&SJHRu-JEkGD09i+LiYIpogeocr3wVVujNDlO_hwaMiT<{gO^CSDxC zBloEhgCV44=bg{pvqVL)FtFs_7cQ!;^w#$uCM4L|V1Fnp<~c(iG%LVeSUQ-BvA^)F zh|sS#<)YE5Sd-Va?D5M9KS?OLxoP0e_{*h>X3xM@;ANEEDdj&9;=!XJ5Zl6}ZRlxM zjCrbG_B@0nXA1jQWmH_Y+ZOcT@q8fMpyf?ZZ(XPHgHz=KA=08LRN4W{2Td6iZOk(k#=CqaITKMtWd7)g z1dW)TQ+)d#Zqr5mKw$&Zf*@t=Dm2#=_`Xnj7zoYTWH@Z!ldjqx<4kDNCPB_cuH+Ad z{q#}4>fqX==pe9vBqJy0W6mA%sj3o!-&o4+dlYx}=gxGYQa3m|KhPL_8g^t)xfoD# z!od7TReSb^3#ZF~8eh)*m4Eg|@P8yQE;>FPR@gkDg~1bV zbWh?(o3IQ0E9B00u7?#F6B=N}{Ieik24AWop2{t|ks>!gTz7!%k@Tc&H3N5Y!JHcn zz9DJO6kf>4aJd-5lkB4SL&k}W(4WNox8_xcxnVgJWuw!5QIVl2TS{@TF1s!Ad(Zyn z0Fq4ATmpWM>ap%narp(>Rx5A(c1q4E3!=(VczjyDdMS6k)akQI2W1&M67DgU-1AfH z?@>a4yjJFXQiS<-U4D~ex?+X*;f{KZRpHHVafkFxD<`6z=Qp}b^zV~P^*=sdJUh5$ zi1^N}J(uQe?W=CzJ5XPO1)xry9gQvc&(wCc*D12aYxP%*Vvx>J<*X|5q`hu=hVqJ4 z{Uduj`jVmC_=;vb!B$ZsWY?Xzc-9Dgtup_75Yv@)W-#r^ruM5d>m2_h~{sx@Z3Jl%eo1KR)~8r-dNF z4q84nj*K!GbMF)|&CK27Jo}kp1l0z>c<>@kN5J_u>;1hrR=>HT`oMj&b5(tf-2`4M z1{w~T{n6VeS90oV-}al+OWO!ki#ihG1earP1oIF`B#1F`i~4 zn|XDDt9|dm=D!t$V*}ALBp0A5IS};7eWDVLeEBCo=Q(v^+qXw5@~HGAB+U=JNiL{o ztFNHE3xd(cq~-b_<4wC$PYf2>tHtT`US27GHT*7EC?)g5t^KtcZ8GnK?mv5!4FVf9 zy$4PEt=pDj;eNX^vo2B@`=lV}d!fy6^SVKy?TQ@a$CjOCXS%HaKx2mJ@3g%>ewWJm z^RE(ma71Gj`f0p~jAU%mTN#=DOGvu_V)b|?yow0(gBCZGFGGh-B;bW(T2e<&5$Ju$ zfS@Jss&NhI-=#9y0HnD(X#FR72%aa7kxRG%GX~75Z`VBlpQu?X20LP&rw29@zE4cK z;Cg@BK=a?>dL3d|Kx{}R&r;}}Dx~x&X5DGQF@5G7_n(be(^fq3*RGVkL51vL;iq>C zc{b|9!Y$MiTKL;hb^{$)%`suAIt+y}W=y!SF@gOcy#aO~)Ac{Oau@5Bevr0rlAWKU!joUizAM4)X7J7@U!?rpsA61{nj z@0fNOYd0*3u!V zVF?wK%-V3BEo>aUpBHiI^83w^U#tV{OJ!c`raqg29_?9`p=Lhkp8L>Sf4XEn>tGPY zdS_%geuW4@kQKv%{yXlQUwfVu79CBGEG`h2^5muV>9Y$*ji~vSva5t8}OFQ+O z$>xQGNWs&gOJB}DI#UpM@QC3dq@LA-vm$~wZ% zGJCqWYlgd!{`^tBL7Fc&3_r7$$y;Medii(Zwh_uBIjreBZ!)_VLo*6z0aMY8xOvmk_?2R7zJbUryJ7-unsuDAd=UeQPn(fsyzPIP#6iLQ* z18_^_j-8S5(i3m53NnjCWmDgH-1O&bM(9uB$Q5(w@V+;wnBfZ#5{2^QQ3hv065J0$oZ3GNWw-C^LK z&-dQ#xJfJYTIQ>VJm>C=1n-n&gK${YXoC1_bqe z6EJSH1u-l2pM|V)8686pw7Ll{i67+_mohR=cGx@Y*pm&vJX|K z|5MtxAQ3N5-%SO~yqV?k6+{_-fm~$6=|t6p`vy<%-e>69Ji<9ReF^8>@J5OH@ZH`! z_^*-=?q00ELH!#mUWpl%2R_ZkMuEz#6GRb_&LOf*AW(NyWgyaTuf)ZDzQvtk-~XP# zhVjKfvJ@4G1VU_vTYV+7bVVQA;=vKZ=4sK&og|M__)1D26ma>H5ud}|3)}&WKxHBn zH*rXn881pDFIo~BQnw%LxvzBWmDskj`ERv+k~m`fzkciUg|7@QK%htL>MQ!D+DV(k zOGn33#|ok?3^!}1pXlg+i6J~4Q#@_R$td}$#>t$y^4a1TOv8leR60Y!^4~sP=D2zL z8aDQ<(IT$J%O_he9KO+FrKzu0pE7>9-#a86`Yw-9yN#W1!Ck+Dr?`4?n_>v9D^J~mFAxsenzq zdCLQJTjl&!Kc4sDOCHB9n{z2b=e|2;Bg1R$w(7Q3o8zlg@Ag`cd1mwPL|j|t+f0sG zC?LA9+Q~MnCa&67x=K~ej4B2{M+V1V6-wnCe0B0dKq*yzKF|lgHNa7L2X|J^8mhBu z`aEfG30?)i#2m(^lm2F=RK=%M_1Mi#rBlV76rnSc#6F|&;T;Ny!~G@C3iEfL!V+qh z4MjgKny{>wZ=i?AH~rJTL8_5pcxSicNGrv)u05)JTFoK3oK;|w&aL|9i?B`}g4WKyqJ#p|)K5m6I(&GH8=BjUSaoZ-SDZdZm)#v{!z71vBs;@Y+4BI6)Q-LPP^ED(q1M?%Q4-c zwn{c#q>fMbY0_sFLI$t-q88&QT}ZA(3A5!?w_W@6b9U{{%9YYce`IWi%_He$npmEp z5zRmZItbJgm9^p~cvS1!YlabjrAqdIngF;m+;Vs)DdMb?2HwAOXNN*YMy{rA`}3V& zzZAbcYCfB)>f+RKlwUl14pW=26Y+n;v8%ILR(`0_atwqjR6~J#3FbELrRE<6d(WBM zphP~JTw}m&6@g`J(=?Y?JjcI<<=RUxE)(0-IZZhy&iiW>SqmK$H)B@)ebV|%Nyt`( zeRjwdZ!*PA}qG=Ofv@@C;Ame&|0+Vf!T+Ypn>$!s@;p+WX_%rh2)Y3g=(;k+dY-%_*<(7 zwxyTq5>3+&<_f)OrVA2()03HPF)=`;Rb!iwwmxF>S+>jeg79uw@?XnXp>|HP26wA? zbDMNS{B}!R!B2#5veMMRzxyXk^NtE06gI>P&Qhi?UN>o(n{A?j)Z<%bZ@M3f^G9Sq zMJP%BeQ?5{2~|H6)?u7%VF}xT@OXJt7_o9Ev8aAdig+6<76eg5Y|YaJg9bP;HALrdV|LN6^U9)%6Qv= ziO{G34klyoAw&C1XtzN8_nZe_wLH;fUo3o>g0mITvgK^>s=cMg=6e1Yl>Ci+AHH!` z^m{x|Kpl`c8uaZ_;YdzaJZ<}WNAcE26E#O0rqBif1aIdOS)(=Oa&7zT!XRxXLLpy6 zy!~~gfS{S9dQoFR0xPxw=>^3CU0Lv7AgC>tbLxz1P{WG~1QK_44jz83y!}G~cTf}f zs^$O!Wxn!_nT;|_%QXlj9pb3y_Nu?CeEBJN(n9%7HSDl8>$*YzK5gJHMTUruTLGS) zWa;hRfpbkK5~#-hbC3(*m~$c|N>#V-Dv>LRdi$(zrVmf>^`$cCDe51GU^iWsxNQuq zt)C~AWMVxO@{?P7k!E;7ASjp2W}%y^CWv;*eFCx9`BVdc(A+D;uhu+k<_*J#@Tdn? zNYUwX3S+y7PF~QsDI`X>e8w8KL<(S4gU&Fq#%boHgybQ=$z}BZa^7~Qa0dp`_ew)& z>^F}=oe1cds@c(;t9D(J=;3?B>2w)U^4twRD1kv8lltY7&gy84o{ zJm%7RFXUcPXhWiIUaPK)%83{>_o}c8v|P*aDbMxKx%0IwmgT&x;3V50X66VrYHUka z{f?6(EDe!1pCa2)d7>36&>KPEZio}eZ)kU}0CB%w0oDSrgt=z7POYwG%Pi)jamUbC znmAAJ6j(Ip*6~wSO2`f>N6sO=5TI+kfPpG9x*VZ-IEqNLO3@c6F4>o4&VMkh_fXEj zA4l@d|Iht70q8CJEF(6?0x+Lz= zvWgeT#L{||2~?~m5#|t7h*%~XXe{F6B)0xF=z(esqg=}xTe^BBGh?EzN1X}&Ztz#h zEzCTih4;-m7!)Nm7;1P(en15B2tN8Fcg2^%3E??B*H1S%BjQSK78h&(RW;pUo&C5{ zDBsQx;)oE}u7+v@M!7+6rnSAZl^>X&8ibh!f$a%6_MM0i#*n)iU(D}YL3DwNwGd5l zxuI2^8m^c11kc{JxE?gJ>;AzJ_0;!x={7&@RWA(U$fJ%V`VzSDi>nj^#!!18P}J97MJJL zxYc~qpQ2Ima?=&+Tjd_0m#6aX6}Y_n3;UZbzKrVEf1R$kjM}+C0o2&-v30x#nF`$B znMf>KGX4vIUG`+%!pI3GA>w`Q2~^8wzXef1@j|EBMB>DrV)U=TX;9Ke4`PVB6tKc` zs!#Iqj0*ZBCONcq&ar~znXp^PSC;nX=GJ;MP(X?|Ts%@@aUoMgrE_afHx+}h@HQJ? zD(+RdYLys;aFkW1p|-dRqe0uW#qrg@QKSG9hr=4KgH?hrf&NbJKs_RlqvrepE}|nS zhP(9Dxz7c@bz9P-YdnNqAF)QuQ~b=c!X+G4vz&n?)H`o6*q4>TXykB}*z4)RAa4l3l#$WC8 z65#N+jx6vhAcb9qBr%LJLX)FY*6PsYXbCZ)+JE$i3*`}lpeTxMuN|+3`n)$lZ(grx z*H2D^?#Iwh4zBZf^WP@gB%3VKBvxE!rQhi?;utuS!d{Q%O@OFJ?Q9*@FFJrFf_?Qh zHz0>?!a`j^YbHYom@Zm4UeNx1!Vgph%b$wGb03-vs)mTrsqPLMkt(b}aoPVn4v!FH z0Z;tQf^#WUGthYLQnwz%0=bT+aJN3R_*839NU;7J^-wsOxr7$K-T$ovw%A**HN>Q5 z+TjEiksjk3Z<=h4v%9tClGD0+y#PYfEl{1l_nkp^l~3{y<~L=$-}V(L0e`aEYFP-p z|AX!SsTK#DL@d2NXe2@quZj;I4sNp#%ktXnkPUlBXOfd^ARb*KbV}K3fi&@>Wp*HQ zP`u$7B*fEXpiDH@*)rMFAdhlg2fk3w9U}UCguI5FCMz~7Qh#~Jr~ilt%8!9S>c8mG z4}YPl1ZU+Iw7NBGTXp+EeLJBmVj+5SI04dL(Meu(Kxv1>#$JaG$}cRMm)0VAGfXtM ziail6Pm@WgcRlaC1TVFxfYw#C%r=$&m0M;~RmIPQQP?48fz_bhI_zZK;_3Jze@&6C@3d zv7>v&ZD}lt-E$+b5#@Q(KIbVKBy=?m;XmBi-45GEs~LilRZbmx5e?YXSs!Mv=cjfz z2Vn=c77*8Ai858D;HlH$qGh~xR*=t?kDb3`F_2KY7tlZ>4ZbD9QWI?d1s}b9mRs3x zfv8!q?kyX>TYpyH&S+facGhkk;>g0n!uP_)-g6%$6*oa~;iy~@lJfmF8HNVB?pY0y zE}w&fn5BPdushBN3%zXk*;Dk%brjiwDS23{T-*1=d)51Vh+&d-%4~#yIsr)XgDQt4y4FfMS4*O$8Tn=VPBMb(stGhUAT2(GrjSMFT{T;~Q$AZ+Zcx`w{k|Jmwly>c6F@bJ}L zUy&h(0!JjFbeQ$;IO!elMYs`drA@-FRobJy7feCO!Z_w=Ar2R#o_Q>?Unm3<)hN@6S)!W^gSz+Z=9~rwuNAwxXt=-hs)c-+{RrKI@ z0tsX~^h*~uZjRmU;)%Z)Mf<zz7fKvVnUk*P~O#GbO3m9ur%9q4OCNU2Z9H8+YG6^Ksjwdh%oZH;LyZ++_qk zaSlFQE#(Eb9E9WFx$@UcpCYXH_+11|#3Wuwpw87@la6#cmnR(=il7t;S#ZlGF2)+_Ag*P>H_WZa) zpzn()-;RW(cYdLqqJ^KQE7JY3*<}r$V1cV6bPIJOu+&Fq`quN`n!hxkd-eUkp*%+A;~|X>QmMel$Y*(eAC^4qWu1Q!BdnK47-7 zJ_%^y!V~OlHz`E(J12@PRh`A?@W@EiO|kmNsj5X%PSxz{*IVVfi@Pk|nXNUtD#iW2 z;Wu!~l31uVKDXcT72Ub+@y!GN$z6m%Nsb{a!OzHuonN*zy({YmLt`-RQAUn{q^^Kc z&Y%U9L0GrGliO&KYe}VD5xsNG63+)Xj#muT(E%reV;SK9UiQAwtBGsN;H6%Jm_Y4M zbkQM&b~(#43eVe&9J2URUl^>JU+2`>b}(%Y;iJ8XODA!ZrPYb$L|Lnb)LBG7(kzK7YbksCi$9nM}%|fUym}d+GMYe^~}Ile7=E7sZ@r?v%uN2jMBmLuDGdFEY)Qsn6PuzmzeA-0kdc@mREJy%(at6 z{*E%6|7B))e2dxaI3Z;vE*tULCW*5YGP8fFk$k0DizX&-0wq;N!2`9woCDcTslXdl z;SIJ-G6Pq+}iB{caM;sE19f=a|oBI-E6zjtf){%ty&tdLuhG(NS zR?8Pe4NnJ25s_%ff%e+mS6S%$qTvT4hTAifxr@FpU%x3JwH{6^93L2-IkvT!#{{fD zH44kkF-jUij*YfYLqeCVJoA)2BlEb2q`t4~6hDdIZf#cnWzb_XJR%)Tuxu*;=NW)l zbc3Oz1mP$QVIOG-F-vA@VxqIN3XG~W^{9%6yLUk9nrhjpUT=V%53sOua;{6r0?w$X zoEvirAKUNVVJ=IOI}Cvh!5O8@f5&Np6}b&0Ea&f4d^`E%pYge1wtG|9Un0N;oL28e zKf%dyzjB2SaaKY*C5_S5h^O6_c3`2YA<}6d{mF!mq!|%d1jd+fb_e~7m z*A=T!@HQP|isWUr$fg27+7Q#95{04{{-w{Z9^UXKr!SCCwG}I>(UI?$RS_`O0SJJ* z=wmDZ24sON4-)>9B*+)9zF9jS*K_xuSvj{$X=!+NZCd1yqe&R#(%QgMm@1s4A8-D8 z-(Cor-%#I`=6_KEtXq+GOYec)B8`Dq99@-fOUkuU^y9;%I=bqb0&Wv`*hPkpXqLuF z^4X>?_upX^mdZ?&;{i>O>nx8I(*tAt;Dx4DKmAH=cD?$q^DuM0O83{}<6Ck=3lJ@I zkFb#?&ZFmrlbeBNQgIgqgI|~ENBiufnCWq&iEo=?r#kpk{swuxz0TX6_6jL2$pWd} zz11J=Fb*3DzaQxzNbZMD>I6UHrV5hsL8ujt0ZPj zRZVOb%9YJVq`$z6pYu}jyT1`VnLD@kHzv7yzxwm{hO@4>aw?ur-RBDy(syT3Xsc~L zSH6S{I*yOh6oON?dx9!FKAk-WMYAW4f=Bkn2-l`UyVaN@s>d7-$&ZNdENmUeyjwel zgFV=DO9z;(0qAE=Xq{NLARZ2m?&InY#JSJ~PmOo49Ie%1Rj_@ObI~4|7Zt(-v2Ul} z-|PBiwoGWtLb(mpAI2>ux}FmYd6%f*X=z!o^NPb)Sv1!v(BM!Louk!Nzx9|k+Ai;J zIzPj07oV?I{hou?Iv9XNbd&kj;n8d(bm!Qp{(KCsvrIcaOxY*870_UL&?@6@?>D`& zD&xC%SvodZEP&7B)3|jN=2lnke|k}j9qCr;>;lvxck*gYN4EW3H@NitaQYJ}F87JP ztFM%K7k56~&z|>P{(M^-SFs<0z>_~`Cr{@?W$Zt+UllKsBZ^z@^6np6jrA`QfooH~ zuU=hSlhK@*rP<}dzA9+f0fp~hAbNMP~JjH_30 z4ZfD&H_^Avn7>CnZ5!sipc-OlCKENC`17n>)vQa0mlkHf@az^fie9Iyt>40@+R=>& z{fRL7J=xX%aiVld`C;IIYO&4bg7JyM!`AQWMl@6X;-)xN9EzvVX8q(DX}TENrAo1H zK#yw}l{W0%J`B?gM2dVcC=N!l88<#Qx*oUmKXSetxC-*?@_*=hx*k;7(NlbAxz5Am z@q79cJN~?#&r8@WMb_o{{4awUf6Dh)R!V+S*iu8OsXQo~G#R&>?~Qe7u`1EPJ%m## zZ-|IQ16}`f#?!Q4P2fKI->|Wpgkdgt(RjXk{@LQf91NVV%hQOAGDG$qN&f`?M@uZ27}DwsJX`S?!U~bVg?B zr0B!T(hZfRmXa2cGk8P!#wno(o4{KYqG#Pjt%qY^c1C8rInT)c>}iZIyJ#&l9Ppn< zlzev}oB04T+R*GeWDM0)aFBIVg?@LzKIG8ZwvM#BCvk~p-CjWR>VLWY*2r|@XJ37+ zz#D~HFv;8R9?y>#D^)SOt6VPsJAXVPWuJb5${Jnr|-O z7F!;mY)ZVhSp9j^z%3d-$jQQ{H`ddYHNB@ZgnEmE!j8rRvibUT?e>J!L8+3zej+QV zO>Lif5A3}@*YnhQT#@;>D=K?sjKw9jFx)o+ZrdwFm+-f~1uwSlu$1YzWwz2adj;0v z_T=`nn+^4l7&LlmKDlQYdHsBvZ2IkIwZ55_99hluM^Sy7`0~chLw~{D|4F35^AtM! zM6f|83U$EC%}*N25l(0aN2Y!F;AJqzPIsxx}H*K7Pc-uj^S{3WFbz#05O}vAOcM0P_pbs zSJ0@^-|^vh9&8VYu$sme2c215#0Eqi`UQ6WvNv|&et0gNlf6S+Ty+CzO%y<|qI7Uz z65?Gz0oCcc&mp74d_)BvDLI&T&7nD0_D0 zy|VNI+!t|OZQRE@bhlY*)(ycWEyg)Gy^X)tbn^jy9pl+49 z1TRk1*!>}UHCg-?8f+)xT31$@NOilNZwdo{ei>wnjl(xVFlW~x`D}Y zLsDQ5%E*c9o%(wtgofnm%|c30Tl$o*v4im<~I%+%i?O~Y|EkxB#+sSrf9 zhe4C`hzO6=SxVRVX}Tpn?SGHwGHj>q{xtsl=maj`P2R=r@@l*u?`lrcqdhHgnjNdG zHul_7`auGcBb);r-kxnR-9N-$2{e3`;VqAd$oPGnO5n>~^(V?3Gt2xyw5s*GiZM&% z2%W6NU4DRZf6G&{=27(7@oxWN_ew?Y(@a0Pex9K$YZqZ7omT~gdwF3FFpJ0Qk0o3AK1yHocupr z0C(T>YeL(OlGxcWQqz{FV-hoCJUv6stAQ@;i{MrupZ%UOtYy5zjt9|^4p;{C5m}=U z_NlLvSSUYR^B$jjE!A2=q_vez4i-4X)BYNJmz-g%Y!<>6uKks+ZnFgo6CgC*TcIY~ zzmi9&1zSbF?a1x_kSc2a*QsO1bVrC4GP{iUUUb<0y0wVz5@sN0IEP-2>BtQ4l%inz zlVt3*yzG=!Af{mi*xTOsv(jk~@RCjIU6gWu)3yhl6ck|@B|$*KRdsUmvB^@*a@qS{ zZa@Fj^NdDy$p5#~V+XpMZ!6d7mE&_=XzBk%j4rBY-OyT6f|2qj%D~@WG{-2$TrB=o zm!-JcJfGW8=@_k~jF7$ML(hwCye1?DK|CPrlzb$&0*g32_Wm+kKFjaVr3DI=)9j=B z`G33x!o7^pXd{#Ep3t=jGC$rT|7!cl@OgaSzWs-OBH{th7qwDeN8{O#7wqhE$qJ=n zOjs*Ij6(@Y=Cx6eHHzq+{7#3|7hZ6JKH-$zb)qJ}%Nf1ZwfUPR`-A1@(XgSMht(Q8 zl#8{k@?)hn&6MiSlk(AO)drcXoC-@`_;$He5gYG~sA1Os{521Q7)8`928l-h;W9NO zYiZ(|FRoC;!)y=HUPzjLAMc4sjI+8+ozEjv$uRq2Bg4C0 zC0Y6)m4J6v$#P+Gt7&;6tV$*YiR~vuG`BsytfS_ZAF_2poU*__JzE#h zfBtju;pmzE7Vw0hJO*o?k_5stu~-{T+#{knoE|>yJ1uK4t!8HaBy&?;bTX0r7)1ep z@zclQW{z1xQ)NL48+5aWXIm$R)|C?E9;JyYwzy7Kfj&1c|cHv zk(CBX)0RB2F=u_E;Qza_?$nk5;av1{-TX?4}J{Ik6|lTB#2t-Wo}SLyAcnvsLQNXVq|C0QxMqhv2~EvVnYX4}A- z;wtNm817s{BU_=s=MK0h{}IprS};s%q4bQ9-hAt|D%ndE8wha*jr6Sd`J0RU9AnM& zQ%vlS=1~mN4o!vJX%E=08TzHP$blw6e#OkGsnKOmwrnM*DZh44Thx904Ur^C={O%| zsh%+m9_KpMRZ1_Fv{5y(PPV z@@vKSo+SUa`qB-OkY?_!GQlpN=B@loi!hiVSCvoMP`+|*cGhltY}LtWs~2)FcPoSv z+i^Le@aRdCmX`J(4p#s5Zx%Pxg`f>fc_ZRtevKBGz!CE#O?3#5B;8DZO=R+l<51Vr z$qfzUdQq=crFX|>kxYH==P*mu%IHu-D79dOm=?+^vr75JmBBQ+8eqN0Ulaicq3RP<~gepubEZ4%%+FB~J!x z$aPILrRg|ZlD-S4mfsx{5eYUI=l31{h7U#l^Ij_IL^kG=+e5F1O;!A=+_j6C9l93? zUrWYj3AulL>>ZMn0o!>WO-&)fSv~?QjTC_th`HraFb`vC>t+Ni^`LcqV_?X9d7*htKo43sI z?a#p=3!FSiadP8E`KIk&>)yE6J^xJ_O8Y>8C=POn0uY0<2gzdvuipu}%51N(8tTg4 zHim%d-8{#y*T8TvG)utX3VHS|a=hmVLv%A~*N7~vLLx0laQrmKs8OPo5PR%}aadHj zui~%5f#fML{C20{Jf2N~4a#v{LtHbzubR)Co{8g=8aU92;OT?5j*N^LG}_K@#EL!v z;}gDJ3o;F=5D+Y&IBazGl3-{+N?qN-j%lR(Yc|idI#l8#+#{bKmcm9jpJ#xYnf!ZI)fXX6j1V~`J<@mgSg!nsv_i#` z_JuLB1>_5jGKrCIQP%3lMW2P<`;E_en_|+WFGY<_cK$@y91j*cZd7U=F2kP{e&ti( zwmO#kUI*dl4{X0_9Hg(CT^efH-gYZ?RC-I)*?#S^Rhz#&bh7@4`umez6W3Xaq8(0; z($vS@`S%PN2zT-N2_S)?d#N++X zqvm<9OO-dUBFEGC-g}}C1A)=Dg8`s4P&qi{YG+1weiu*wh^jbZ+|M6(tKg2K+v4xC z3k!*|p!5I1`3(Y1Ck_hX4`NFCHWCC=Byvfcd!3M+rDB|jD3MV-z?M#UsaJ@ zY~K_ON2VjRj5H^VtP!`<82njRI3PK^m5E^aQ3!+WUFf}S#HHY0FgUq+K#|-*_n7q0 z_q=JI7&VeODzX<)^>_-=c_pFu`}G@~9P@9h1i^P=W#^whbP8(Fz}3U67P;x_(Ot>V)elCsBV)(W@~CCi7ab*j2UE&w~FXZuR1oF{vsWo zT}JcDxP+aB&B=+N-_)Di6AqWUH-ep?21YuM(8ntbocQWj#OR=k*&iOA7up>#Qn5ZJ zrgm|;*uiu^n=#uaiM?;#bcjuE2QarwgB7FqcjwdQBi}D$W{Q&h)OHk8B`D4w5CeEe z%D2J9lbzz#VRtjNSIDJrgZ^hqqWjGD4i7gqf}^L77sw4xEOU$eUrNM$oJF&*(fnp( zS}Wr57<{X21Rzo`&qK){*x-$!_G$WnF+YZ0ReG)xa75=2SR|i)4tq-|s4sIsdAv%c zdopiYX$&PWYsj~`#z}j}l2hw}t@SI%`D5ZQ+xc00MITC6Z-vwl)^UChEPeJr#P@X8 zjLB<>I6i$|fjuQMb2Q9p)CzAWlK=euy_Y_3c4TX<#ylA)ATfBBKZ+=B3yM{VuImmU zc&EXrP;5xxv-wp4g{F6Ac6!>0@75CxAf|r^IJQWV%`IZ{>kfOQh%K(0GbOW*Gy5_H ze(m@{elapi&Dz$;?HI~ZSS>bj{cFwZXXg5+3kR&i@Cbx|`T@DU6N0Dz-e@$ov|8ZNl+sPz^R3n|Baw@M@6E7E7=vU zmcGcL>BeE-GT$xwMmq}VJVLbFM?Kw1HDgqs-v#elXdT_{2i0}eSmliGP4ox<8G~?a}12wSKc@ut` zA;NdN2Y=Ndqq|f@@0qX8_#04yR~UBWs^l?pfG8F80>z!ZOw+atG`qm2Nh1I}NO;6L z_34HA&ZvrQVHw~rA)LH)a7sIo1p|_EY)!Tp-%@r;UetI^wod5Xw*UQDqEpr;fRZR- zUTxE-6~-cF;zq#$oll?^ZP%mVT=91T)!${B4u;il`<6~wmVXYGPgB}{x8J20q&$*n z3Aj}iWwJrbo-dDzj;MgwgochcJ|Dc_H_=uW-^#PmZS(RjDJQ{pMskS0ayPaGqM$&- z59TyG!M*Ks`M&uMPfPAN) z4wZg0^!BhVg1Sx*B$|I)B9QVQ8hL>j9q?PQ`_Om3VT^d#0+yBY^R~%8)_lHat#VmH zt?EhqA(m*_(9RR$U0Q#sLRl4p|Khey<@tM=QN-qIwTR|_7~Md1>z#iH>EVcCnSrYk z|7SgYf8*Ii4=oBzih3;gMB_=gAjws>&?gG^RF1s_s;AJ(uGiC+iSLPO&grn?Q1d&N zNs8Yc5?IgGRAxK?rzRr-dd^yDf_@U2g=sWu-1RCcttcd4hc6=K{}M>){AB9d^%gC} zyLL;z3ID zfE9ELfQi}1jjG1O1mOyFhUz1i*2ypl-mKp<#}VYu50f0`#6aOWa4SE z*a!e%-C|ePZwkBf3YWFn8z{N-D|3H@JoG(WBJym7^14Z1l|DAgtoR>xZR6{D?-u9y z3Q~62^#sdtjb->37Cj1St$5Z-&G@$tOf)vNJS9Ry?MzdahILY&Zau1N1qUuN!!_(5 zPu$o=PN}B)_Q)=09ucMNJe?eN$L1QiDcdnQsmWYp_6G+CoMc^<^B2=yhB2od;-ZgR zb%|zk4i-^-9ex@l4B0^0U=ob>Le40j+LSrXq*nQDdwSp=YVl%`(|*EZ9_KcmF48@J zO4RA&{k%d6nt4!Ha40n~r}T_cm;c33TbU4>j4Z8LQwL%*i>k_d%5li8uNA_7CvBgS zf3sQpAI!2-j$h(1#`NdXEv@AaIU^=C=>i}o*;ek*%0D5@+`~O*U#gTXu_rh@2FrN} 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 z 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 literal 0 HcmV?d00001 diff --git a/examples/graph/graphviz/screenshots/traffic_lights.png b/examples/graph/graphviz/screenshots/traffic_lights.png new file mode 100644 index 0000000000000000000000000000000000000000..237016a63250dbde44ca17d680b12e5c4fd2d610 GIT binary patch literal 59829 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 bb%b=e-j$^MRt2aiLLeF{y2|B>4^aOD$R^W| literal 0 HcmV?d00001 diff --git a/examples/graph/img/refresh-cl/Hardware-Fax-icon.png b/examples/graph/img/refresh-cl/Hardware-Fax-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..eab07c7e2b492d183e796d5bbc4c14f398f8eac0 GIT binary patch literal 3645 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 literal 0 HcmV?d00001 diff --git a/examples/graph/img/refresh-cl/Hardware-My-Computer-3-icon.png b/examples/graph/img/refresh-cl/Hardware-My-Computer-3-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..26ac6260791799717be9893fcffaa4d4edf3cbdb GIT binary patch literal 5402 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 Ef_{oenE(I) literal 0 HcmV?d00001 diff --git a/examples/graph/img/refresh-cl/Hardware-My-PDA-02-icon.png b/examples/graph/img/refresh-cl/Hardware-My-PDA-02-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a761307d25ed268636a98d310b74555559f436a9 GIT binary patch literal 3531 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 literal 0 HcmV?d00001 diff --git a/examples/graph/img/refresh-cl/Hardware-My-Phone-Picture-icon.png b/examples/graph/img/refresh-cl/Hardware-My-Phone-Picture-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..5e9ea6c56f7ee92297ac2953e22d0f9988c7f0b1 GIT binary patch literal 3234 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 O0000>P)i`S}gIuRu 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 literal 0 HcmV?d00001 diff --git a/examples/graph/img/refresh-cl/license.txt b/examples/graph/img/refresh-cl/license.txt new file mode 100644 index 00000000..7b8b9d43 --- /dev/null +++ b/examples/graph/img/refresh-cl/license.txt @@ -0,0 +1,14 @@ +Refresh Cl icon set + +http://www.iconarchive.com/show/refresh-cl-icons-by-tpdkdesign.net.html +http://www.iconarchive.com/artist/tpdkdesign.net.html + +Artist: TpdkDesign.net +License: Free for non-commercial use. + +Name: TpdkDesign.net +URL: http://www.tpdkdesign.net +Available for custom work: No +Default License: Free for non-commercial use. +Commercial usage: Not allowed + diff --git a/examples/graph/img/soft-scraps-icons/Document-icon24.png b/examples/graph/img/soft-scraps-icons/Document-icon24.png new file mode 100644 index 0000000000000000000000000000000000000000..c420b202ed4b113b4ed87575181c8034b95b29dc GIT binary patch literal 1104 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 Z{tXy76{%(M^g;jt002ovPDHLkV1kG0M@j$y literal 0 HcmV?d00001 diff --git a/examples/graph/img/soft-scraps-icons/Document-icon48.png b/examples/graph/img/soft-scraps-icons/Document-icon48.png new file mode 100644 index 0000000000000000000000000000000000000000..5938c512fbe77d44642dda1cab861ba8c3d851a2 GIT binary patch literal 2771 zcmV;^3M}=BP)82YR@7M#f0Wa9b#B%HmPCR4T?@^>|nrNOQ-6td`s0ut9O?l zp?;2f6xF?s@taX{s1H%UK>gcV1N9nxb*O(r{S4KCYRcoyTl38Zuh;4?qJD|`Yt*D& z0DndOaZ5{!x_I%TK7anasjI8|AOModq`G?bs=jdHf*BtlXZt18pV$HLGt|EvJa|yu zx^+u!-MUp3i^UZyf1ibmayT67&6_vs%$YOl$&)8+{yFN`>jiKF^^rE&#G8F zq30K3rf7@?3R5+E`M%ccRoWa5ts)H}9SR1__3PKwxpU{Z&YP&8t_Oe@bp}!oO-)V7 zgD0nFS5voA@7V^Lw{MZ_UAuN^Xd{NpZK#=d0SKeM-oJmp@9ER0DxJxyx#+@XFvE6f zYHUzGuSXp?a6mnK_AHI29jJ@z0q_a{{NSF+=5i{!xKxqW+}y0m<^UawbYvl*kc zgPhfFx7#c&Eh(qdsnKWhnCroqR4QpuFvh7vp?Vl;O69Uy?ZWtUI<4_66AFb?Fc_41 z*4i4w^~U3NE7+n2fE3zx+6KVIF2>^(0Apig#^rP=E+`NT=-Js>L+a8)d3|01fP0NT z6N|-EQ&W?U&PU00g?RuFGSP*ofJ~>-#_e(ITrOu^E|+R)Y1J;5vjQL-3>vrFRTF>; zg{Xn0#Ig&{WpgT%%_vA)IUspz!s&7?XF{FgrWG_?)N;+!OC@UZf;I!1WBt`Q&S2W6Z&o2woSo)lqHNqhYrb@>f-Zx6*aIS z3X$XKZ0FnX$FB0)h@;^Kv}*{t$-JaEBT1Fh-y_V!f)c-*d<0aPed001t;Dl;?FLIIb{ zE%YfC3*uQ|kf1;aHK^k8xMFPJT0)_)qR|#WE6dx!?bGLr*J4{Z+@Mw~;+4?9Aqr7+ zxqP824vZSV-!B8fa}5`2QmK^q{zgdM>-B9Kh1_^H?PEh4AcgXUVx{x->sM+4sYMWy z=E4bPadDABO0rhE%grh-r$qRTYXCI*PK+4zsaXTd0B}{qyM5a*S{6(0QzKHF zI%omB*U*O9i9j|wI;vs)hOQAWMp_Xx)Dm2$UWi7yF;XeyKn|@9oPma`mR!h(K!(MZ zQ)|XW0KjF<6yipL>lPGcVbS|Y8}IQ~G(|}%tdh&;MD5a6mM5jiaZZO*eo41d{Ltbg ztdxY#0N$*!G{(xZ25O_w9EWo-(7Q2P7(B|7fhxs&;j zhVe=+kCa(MD+W?kkg~=;z%bWgJGI7k?hTL|ndatZMC*Bp#C$v{M4;@CL?T92y^}Yc zwNhws@UbZyQUyTynNqL-@e~BWZb;uy8`e14D#eWtpt`uPgaOF$<+u*v@+zEVIyth6eFAOdGau->wD*1{BYkUc7jr zT3cJ?mj=yL1MlPJeZ@kGWm$EW+_8NM4GavL(vAtzppI5mIgs7FaYHs43{1#M#f?rO&j*bpAT>hjHXL-+pVvD2Il02eMGulz1b$QQAOtAVaVe0G)>q>mj=o>gd?-8yFmrK*CLhRj6*Z zSsRhkX+tUalsPZIR_4h<&s54_OJ1sao;B9` zE@#=Gj2;{u6feY$It?_LOo|bM?>ZKX$zB1ewHPL^ckI~lABI_dy;_@fozE8xBli(% zU}(rDg#h5;qelV&d3oh!poih&`5tac=sK|(r{n|-`|vB?iAGIewF1CCL;xH;a>Odf)872Z5C-4w}hK_M^;KidC)t&9;P-he0Q&m+ z3PeFs&f(t$d#vpv_QA*0BnYB%v|cFT72mcp_JYn^7W(B1MG;c!^A zC5ORpl^9ZP9_gGqc|wiY)j(TYyT7;Zj-1aogn|_f(C=FmqVMO?IHM=IPN|mx$bpx2 ze#-0BB>b*8un>#O_lcfUC-umPJq^6t*Vg9$dvBldVpqlQRo2U{T)84fjGSK~-_etk zlNKNiO&Ay_?Zl!7Z9*v0-Q8^)0Kdy+vN`p`o>O{sWW*kY_U&u)-TX(d@_`;(BFiUd z)?u#Jt4-b9GCRMZ(y*ydPWPzM(UEmiNIvpGlA(Y0-!~rYRhzeOwKg5A#(|Ao|F?eL zPENlu*-Tb_|M)TPk3~MSe(~j3=Hs3o6{-(v(1@oD9|Qn5GN6x+Eyc|@y}j!5 z&wgR+Gb@XH=-#`pP5t?+uaPE1Bqv%v=%||g9?s=>=ENK*3NQ7mU;b2$jgGR{)`xBu z`B#HoyPDN+e)~K9gO7WR7ZFx{00=zwxcyD9{^K8hkIm8~+im}=0n7jWKYLi^fBN5T Z{tXy76{%(M^g;jt002ovPDHLkV1kG0M@j$y literal 0 HcmV?d00001 diff --git a/examples/graph/img/soft-scraps-icons/Email-icon24.png b/examples/graph/img/soft-scraps-icons/Email-icon24.png new file mode 100644 index 0000000000000000000000000000000000000000..c01c9040ecb5f5567275dd9da81d3c18db7bb40f GIT binary patch literal 668 zcmV;N0%QG&P)z34j@%(E-J`BtZH8 z4QP=NL=U4NyLWx8f2Rwqe85i|p!61+-hxnEC-x9@gx$Li@{u-Mw3i0X&A0%KZ^&+c z1;!&T{(p*Y#euF4Brc+21DHjYC=5|5f^s8Hq9b8B`W;yF-jA5f=U24(?TEDB*Y zLFG+gLO&Tm-Qb`aL?{AkT5L~y0Bgv`+&Ze)fa(r|@nX&EAa4MgOFw)ys2yAX-E%ixIzu!t<*VuZK?6y>naoi?zx$`LX) zI3mA+>$li9eAu_kAe{z3*;b#rXHZ{&rZP2!f?I`@%c$9#A~o#vqM%m6tjT1lQ*#c3 z@5Tbgld<3r`t3#b8MU|<&EbdKTzdH&51-BUcd`C9=2_Ag^H`PulPt~a**x;Y>glxW znh9Fnz?ZJTJ#SO?(P?=ur$oTyS>U;UHvY*29e)6g0VL7EWag3p0000jt+nzW0hPEBe_rsJs7KhD|NG~O>`kQ?^EoW0imzrEJl>l`mk@$i}k zmezkk%~#B78g}ZqopljKKCh1)!u5QdS!9 zy#~+)POf+t6}_W@i#LJn-v9-Wwq*dV7NE0%5FwKzZtVe75r8@vkgpM7p8z;XfOMx( z(?=S$19L(rR=l%|KS6*d-1%R=PJjaf;5Y#`^c%l@4TLfk;S&@IE5&V`LHhn@@(ltU z5&%aDu-?_Fnnf}{h9Cjs7jHKMVbQM7kNx-_eP8+JG<5fO+w(DV6)WTuy)!0$@J@ zQr(Rh1eo3cjm<#vMpmzCI9Uapj&%=tYW9`b*n#`Ke3t;H1VBCkR=FEBGy&Qu=J5w$ ztR_SjPh%fiyq7!HRsfOAxym1~d;sR^1^~E60D}O?Bfv^m0}D?b!aM7ybVmyd$@B?W zwwWgy1j5eUOw6rb3k1({KC`k8+CK9jVSfSKCqSV9*h_#F{fpn)0Dn68sa>7w>i{!z zo4CmxqEEbx)y_0&BVE_5^yz2;X8dujjeqD@&jRy-e>$vz_hb`xMZE7!_C%?70Q9y-rPR(I1^ zhB|=|+@YCJI(E3Yr9=DKc&mEYWi`Ck@*@JA6#zRSZAoTWdDVP|5f{VUNQinTfSw`O z>PF_*O$a-i)8)qmIHv%d&xN#=DexYl_;`n-zg%Dnb`&`QYKw9Zlat~ZaWRSskXwv8 z2f)?Ui;-ED@3{{|#|2tr04l0b>d;)oS(%xLplsHG|0rATXh#S0U&8#CJ_p+ylEk4| z&ma?s0QH!6AK74601?2LJ53r500000NkvXXu0mjf-=}-n literal 0 HcmV?d00001 diff --git a/examples/graph/img/soft-scraps-icons/Email-icon48.png b/examples/graph/img/soft-scraps-icons/Email-icon48.png new file mode 100644 index 0000000000000000000000000000000000000000..799ebb70bfe43285841801bb4b70ea7899e4fce7 GIT binary patch literal 1487 zcmV;=1u*)FP)leV_qYTI?LcFJhGx>3u7DXSfbf`}BIhz#Z!RQ#uZL{a=D{t>4l zg2-^x3o3R9Zrwz-sk^AV)Xudqtz(^?y(CSVq_^bwd|#U8%a^1{)=OH*3x~cvIp;g? z^F7b^zV8uO<0euaKpH@*14si%bpUAq9Q!%SQXR-`+K>X^0!O_DkX*pm&Ly%w*=Hu} zUkU-^qvOlihwMw(pP~=1K=fq zTn0Yw0<4>L60-LIg#{2Z(~y@>0*%!W!nZmYfB|A+5;Ct2$jF3nj6+(t=p4GrdMfn>8^A0BgH0UMt8v*2pD6KU(g2-P7xv7G4a+w(r zkWL3MI|5JqU`{izl_^sfazIY>4d0cl`UKk zOiV-Ex(d0mHUS16*GuTD*Z`D&um8f+2oJU*cRI$ z%4$Quk9!~;|L{ZJpvgkf06d|W(3i0#^zTiUbG{*qF;Y^$vU_#%@6NsKxe{zS{A8?` zvdQE64O=56<775+^UU({1tj#OUP7O%03zPjD0`x;;=r4a)=K!9pHCfS@Z}IKPlq>u zQ5ndfY$#XUg1Bb~*NfAfM@^CwcS=)^&656Ae(4i0mlMF`Y z@_uYg?n0x~h!d>VnJkDk5Avh0o}0f8d6SnU>4s=-<9jJc?n2|8WC!78XPT>F;90$d zJ_!Jro`RgsWPUeA_C>n>D56JEeAhT|?j#SPelz%V4q>3~ZPapo3q+nJ_A?jqJ)i?S(JJ;RJzFJRrP zlhDYA)H@l-GRE&)Vo7MZ?!;PuhH`R|f#Ur-2@QY5a&Afduv7t1{1M)XOZJ5ToaNYd z;~=o!wl)9^jzLy*s3DwJ0KCs};9Y*z9j%Mg=t|kaZs3JOs{4TgfW;hVtR`f3zXY+h zdUZ4K`v64iTab1Sn3K>PY(w7Qc*T?r@eB*mc3$8O@p{@7HXp-3%MSQ3Z)~1v70jC) zuLi?Z{=UfZI!C@{PU?K^T&y+8`pNENkAT-W-a&xDFe~OzE^9T2f3H|+Qvi?y@bZfh p?HgRvmIjb&O9M!?r2(Yc{s$l2wJRpk{*eFx002ovPDHLkV1gzKz-Ryf literal 0 HcmV?d00001 diff --git a/examples/graph/img/soft-scraps-icons/Folder-icon24.png b/examples/graph/img/soft-scraps-icons/Folder-icon24.png new file mode 100644 index 0000000000000000000000000000000000000000..16d050846ffe218089d2306d6064ce8bdf2e6718 GIT binary patch literal 691 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 literal 0 HcmV?d00001 diff --git a/examples/graph/img/soft-scraps-icons/Folder-icon64.png b/examples/graph/img/soft-scraps-icons/Folder-icon64.png new file mode 100644 index 0000000000000000000000000000000000000000..6c5d457aa6d13f68f28253ec4180b051899f6e67 GIT binary patch literal 1771 zcmV;P)>{9t5Old5y2RZR3ro>h!=`cV>}26m|!$2cp%D6 zjDXRYpaBgPu}U~pVuC0djP26xwQV`vw7c^)}Vk6#z`4 zwo-j8uJ<@KgZfP-fSahjR1c9UDWOMq0=@FhsmxmgZ2uTIawJ|1?nZCGO?0MeHccqQA?;5B2!?tA`*w^qw-i~$fqAENq-%xF#zGdU>@DbRXNTFifz$^at51HTOe zavUfrk^q1DOU?jSBp6|XZ@ zyqQOmLUTQ+-^Zb_9BaxHRQ_N?|9m?N^K8g*D#+&MD2rQzOuK>%a&ZcACT12ko1$-B zm8k4CC^m5+A;sQ4ugSr`6F0HxQ~IbCH8^q72*8_6jbRVSEHD><7zT%*L&#Z)FMd++ z%T61z6$QDRZZrrE9YTg93c;qupvMyfpamN()agWjD;gN>dhA-XToE_nwTY|hP<`46 zz)Ge@avWs1%mpAU*u>)qiK|}tx!W#LakoCXP8wLNA;f# z**H>`gN0ig;cGSmz!eI^xcv3#WetFiruxmfZ@>rCmI0yT*zd{3^cPyu*wPU|-zb2g zk8#lD$pK)haow-nh8EQW_X9vfb7CKm0I-@V_dEjVDcf6ftgQ<0eu_blbI+sibUOfe zkEwy&4mxvXyPAFz^Gow_&N=09Kf=!7GXn5FQ~mGanj>$Yp5CC@&HZfZ)=Itg!y&EM zy)YGkwM-RG=29W&l$M^LBV1w`T^m;wzc(Iqvbh%+0Vs$9aE-qN0YvnDMS!jCuQ3ez z902u30C*TeZ=Qv1nX)6gFbna78Du1Z`hN|&9f0|%0Ekr25$pk76oBa7Y72vI)D;PK z>NaAbGX}7UshsQB1Jd*iAYG=m0cTIL#ZR%NI~R020CQ6T5Kl|9uO+y13e! z_LfcwV0J11A2H>0nfEv>9yE7lVZSbMBDC1tvr+-r#*`!98~|F-L4D?y5Og~LrA7ey z5x{l8+?xu( zXNc|rI`O_vw6HjQbkU&O0k}IAfE}XD5r3w3{(vLUT3ZV^B0Hvw12Dq~09U^X@oH3b z|C9hC(O6@_Uz+BgP5?DV0CtKpqu?*yU=0CGO9kLd*{)dxV2Tld{si!qY}YITFqr_V zjR2I%cFiIH6H@`$Bil8L08B6fP(%QGWxHk(fD!`m8UZMm?V3dZZc72+ukXY=L2KXD zTW=}`-`ZpVU;qK^(ym|L#`YaNl|7)!06@h-+1^=W?y+$ITLgd)s0A+ee&12qu32M! zuLl~MwB%X=U=gC9t{&h{aO_Cg?wM-`4+G<-#IsKb0Neqff^rtKYkbWkaYh$=DxNM2 z1c5tv6yB!~b@2ew9Xt7mk7J$`iAg1#6jlR8{bakFUK5|j&U+Nty*FO8idq~4AYKK1 zLyZ#|@frL0VnRsgx8gE`=fUUOeQff?L+1n3?UX?_`hiwSX-Y==!Y@$CB{szqds z4*z4Q2ch?d%jH`c@lR8t)x}4lhmtSI{--JF)(t?m1G23ffNTe3+dmSwJ_Hi#dGG)L N002ovPDHLkV1fXtCQ1MR literal 0 HcmV?d00001 diff --git a/examples/graph/img/soft-scraps-icons/Smiley-Angry-icon.png b/examples/graph/img/soft-scraps-icons/Smiley-Angry-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..f40bc381b951af8fc418a9816b33dce90fbba030 GIT binary patch literal 3210 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 literal 0 HcmV?d00001 diff --git a/examples/graph/img/soft-scraps-icons/User-Administrator-Blue-icon.png b/examples/graph/img/soft-scraps-icons/User-Administrator-Blue-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ba2ffac73718abfc5a1d4e0d3dfcaa4201fea7b6 GIT binary patch literal 3901 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 LNkvXXu0mjf!el#T literal 0 HcmV?d00001 diff --git a/examples/graph/img/soft-scraps-icons/User-Administrator-Green-icon.png b/examples/graph/img/soft-scraps-icons/User-Administrator-Green-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a3d3167785d95927c0699b5e9f3c58ac43c77aaf GIT binary patch literal 3906 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 literal 0 HcmV?d00001 diff --git a/examples/graph/img/soft-scraps-icons/User-Coat-Green-icon.png b/examples/graph/img/soft-scraps-icons/User-Coat-Green-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..4a4326b749ed16552a3db1fff820d53a29594c84 GIT binary patch literal 3571 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 Sw%*AA0000)oZU}yJ~@ZOWNC8 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 TfngXZ00000NkvXXu0mjf7*j=+ literal 0 HcmV?d00001 diff --git a/examples/graph/img/soft-scraps-icons/User-Preppy-Blue-icon.png b/examples/graph/img/soft-scraps-icons/User-Preppy-Blue-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b3c774083ec033c622e17a995397c318d94eb750 GIT binary patch literal 3802 zcmV<04khu4P)u)XOFk)nuO{)aJN zCv?RL2#4Ivs5DuukUP2q{B`ekBN$ zF%GfjOsPf`Yy(l z zAtfu9P@8rd@cfW0Ff7vvs~?+++!+#XSd;*77r!5m(2k^ZOs@7heT-lF5}Oa zOF%@OI~=YwG+S%~Up6EH98vN9nctzM^Cm-@Lqbwyf=CEXHMHaGWm~DO+n?~cP|%NF zcb8~yVSN8`2xK!F*ikLc)O5JiLz0XzqoNd^edsnQ9i7F);>lEGMp#262&c}r!oAD4 z!s(`-gnf9rJJ}qH@aW-;wo4`OkBs*vlZE4b5|XHGL|qeOf!N=u&))FdbhziX@p%8N z3K}y!TfaxBA|h%Ewm?|507imHkpQ`S-1y9|cGGXG>L9{S9NS;e-^bBOjY#(~etW3| zRx=iw%oZ?6Qhdbde;6@8%SB~H1u&s(3|5wpqj6V{;1Fv@LIZJap%LIPDJ+1BtPxO{ zfE;21ehxc+q>!JEo@#_On~&lj51gfLZ%FN4;Y=OYLh2gO3dSK5$OFxB#)_CPT=#{! zrEqmYCYWt@a5|GAJ1Y$e@^ir9-~v>#a;md1IH?&J$VD6v9-k2 z|JE!rC#4{n90VpV{mphBCre9W=Vk(Ev>+MH#OC60OS%P6w}37oVhKfb3kV6x0nGy8 zJ`yA_v zpB@dw_Wrkyj>)>Qx_wkhRqlLX*xW=U^+Ipwo}2KD`5Q- zH{zViVnTB=l9?@_5{OzLiNMGfkk|qS6A1}%vO_hPix;SEt$<^q9n81debvSqBC)Bw4NyyF4#N}`8pk=?_A-dTLTCq2XKn~;FsN7`3iFY3Y3kI>f z@fhVkybo$#yA?|dhv@{IB;+GzA58-!WY8tV!zR7zjBk^c2iOWI2h=DOFQF&_4;-&Q zhvT29qUK*sg4BX>7$gggo%c4JY3>!tZ5X3vAc5N%e_HsxB6xEVFKdHc{GI^hF4zSp zR(}`L(m9r!lQsGDONe1&2^nJ~B;<3kazk}y`GOP6Q74W{NWh~?sH?Lb#{T3ZXkI&& zjmrI7(%{D|t2KX87jEBUd^nK6-NJdFn^R27=az5~G4aeH-MVxaY%Lnf(z|_3y3f(Box#vAjeoB>?H`g!Rzk8*)JWYKfgFte=bbVudjuF+i((fXZ~Oy zfyu(d@0pN88=fcwv}YsPGHCg`2Vv2)R7}mtBDCmHNF|VTfq*d@h1dsBE3^9(QY-=C z18N=!$44PKHVO#>J<#3RhO4UF^!&VXKz|34ua$nV;s|_jum$x zA4@2mFezJ$LMCnSDB0Ko)(aL;qmZzGF+mlW~}vV=O( z;bgh`JHX?Q;2p0VqrE4@ZVbGjk27Hy6^r(d7!wO~toYQO!|3K>7i6S3FfBck(2<8^ zNv5a+qhw{-2m+Q15{f0D#-NK3h=lYgq!VCgRtW@qnZS8=;tuTS@zI`>Zut4;b6DRJ z5Hj4)xD8?!{fWYb*qjoz#}A_?ZYp%af&ZAoev!#b`&=#ZNKr)PW7Z|4C$d4MgrY^D zXhqsDqo5XvqS46L0@T+A6aIM*9IEe)9oO#}3qjiygD)cxJ#J+D17i-~G;G%kH_?=` z;YhC01eRnq`)U@jXcjPV0cVf~TR^Qwl^6?%C?x9^2yr6Q@`3OL4E7@Rd`^3gHp0|p zheaR|%Qmr@@ZWHe9lW8e57qEGu{ecxzc>kvjx2(dtJK-ovacXuiXmW3K!64lP{KL^ zQC0^v33Z=F+1p09EUkw9bv<$6@?ytO2(T7lA7jEVel!*yomIpl8wrp+QcGNF{iD}F z{qoVH&>#uLM53sSL|r8QyU(il<<>g*>2FSor^F_(2<^((B_NJc#vzM@_MI%H38m}@ zsl|XPqb}4x22p_;bqg5OBp4rs_$P=w5Fz0U(X|0De39H=5OmeSf#c0s`7ehlD3jRK z5=GnbuNv4;2=Mf(&LhH?E6Zh}9m^-dHN%quQwxzY#_2v_)Ch=0j36LNpg0MUUd$=_ z>P%LpgB{0^x=+zx8$2+5*?w$u2Sv0I-n$I6U=sQ|1g>YS1+h28GixfF2~x>4nC|R^ zH>aM5JW~fpC9aWjZUAuP>ybxCbdjk_NdMC>BZjw$(d9cHi0dj2> zgpX{~N^fmXXaVEXOC=!AKgxJTSYXDC894r-rL_924aG7k_4Gb?mwumQ1kYS zxPAL}(k<{bP1nk7L4Y$Z1Uk8<=~N>ROAUHcuE(~tTPbYLz|YRM z(oc3YfoVjs+JEH;C#;_}0@toxOG}n40iVw&&Wo*g@f{)ZWdy|UHyDfZ^73%grcE?{ z{CM!o3SR%-Y4U^=^#zL04dVl!!}~w|K8C_F$-Hhg$X>K|9U)84aR_$Qp%m^Sn^92- z^hFFLo6^9NQG~&iQVOJ&fnsu?BuQj8NqFBc{zx^}tH5A)sr@_62Ke;;F=&$vR8vy} zvuDr7^XJct*58DCr4t@_XE(HF6@e|us$TQ=1t6=f4&Hn478sF}4hA7DgZAouwGD9J##*qB zDv9fV%dBBgl4eoc_4V~IZQ3+wYH9-A3a=(2Aij0&b2^=-ojZ3zS=rz9Z=r1cn-8Bl z*crF267luI=uii4{?TL-d!FK2eRCJh|J`9|Pboly-5IyrruaON+0%&Y?!A!;bJNuG z!El7`{LNnc!kj@ydoslK|MT*6ykoe%zmFqF{z8?NmEiGs#HQ~g#wW1^#K)|IBI>MJ zvj!e~@S(Wb_;sBZR@Hjq&T%+|h{p|&j4{LFTZ-XiOApN7_!)FLvbZ?4CyWe{fDh8V zZLsd|uYuy+RCsOoNmzY41V(k!*bsN`q7o-OT;zy5_s%Nn5{bpA9bliAm4O{0t9Vtl-pGJLuk-1vY&7 z#*{&0souXIXU?2Kx`fKb1@XDGwzPDdVb{kWYq@j4@mO^?e0)9#-{vtT&jN2$qz*bS zR;N>^Oo8LakBJ(oB$}|^Sn}jkuz2y3gr;A#w+E|RLYK9@K7@9{>lHa>Ts1i*;d8I8 ze3e$dxabX?ffp_0q4-+O-#O)48+mG+-#e*t=0TLR**T}DKC%#_J1YVz%JZLPU zec(Vf&AVT?0Q{FAAXfL2w(r;lS=reM&G~e-7pj}X-@I;Oj*46pyi(yvc&)9q6=qDI zDw_KQfg?tv@!Aa=w?I;oJ)t>Y{@(!ZZ;Lajky(k3VDgjX+8r70K(Q`!Mu&M}^fLJUSeIq*f=8wAn10;Bl*fAq0 Q&j0`b07*qoM6N<$f?a(FSpWb4 literal 0 HcmV?d00001 diff --git a/examples/graph/img/soft-scraps-icons/User-Preppy-Red-icon.png b/examples/graph/img/soft-scraps-icons/User-Preppy-Red-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..f569776ea011a9bbd1488f51c350e6aec7dc2071 GIT binary patch literal 3800 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 Visit artist homepage for details). + diff --git a/examples/timeline/01_basic.html b/examples/timeline/01_basic.html new file mode 100644 index 00000000..d8a5f50e --- /dev/null +++ b/examples/timeline/01_basic.html @@ -0,0 +1,31 @@ + + + + Timeline | Basic demo + + + + + + +

+ + + + \ No newline at end of file diff --git a/examples/timeline/02_dataset.html b/examples/timeline/02_dataset.html new file mode 100644 index 00000000..81c1d0dd --- /dev/null +++ b/examples/timeline/02_dataset.html @@ -0,0 +1,54 @@ + + + + Timeline | Dataset example + + + + + + +
+ + + + \ No newline at end of file diff --git a/examples/timeline/03_much_data.html b/examples/timeline/03_much_data.html new file mode 100644 index 00000000..36221ad7 --- /dev/null +++ b/examples/timeline/03_much_data.html @@ -0,0 +1,65 @@ + + + + Timeline | a lot of data + + + + + + +

+ Test with a lot of data +

+

+ + + +

+
+ + + + \ No newline at end of file diff --git a/examples/timeline/04_html_data.html b/examples/timeline/04_html_data.html new file mode 100644 index 00000000..c01dbfcc --- /dev/null +++ b/examples/timeline/04_html_data.html @@ -0,0 +1,69 @@ + + + + Timeline | HTML data + + + + + + +

+ Load HTML contents in the Timeline +

+
+ + + + \ No newline at end of file diff --git a/examples/timeline/05_groups.html b/examples/timeline/05_groups.html new file mode 100644 index 00000000..42ae2d1c --- /dev/null +++ b/examples/timeline/05_groups.html @@ -0,0 +1,64 @@ + + + + Timeline | Group example + + + + + + +
+ + + + \ No newline at end of file diff --git a/examples/timeline/img/Hardware-Mobile-Phone-icon.png b/examples/timeline/img/Hardware-Mobile-Phone-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..66a6d35fc329c86b12d57185fb82879b471c5546 GIT binary patch literal 3463 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 literal 0 HcmV?d00001 diff --git a/examples/timeline/img/attachment-icon.png b/examples/timeline/img/attachment-icon.png new file mode 100755 index 0000000000000000000000000000000000000000..fc82517762e5c83e8030e4947fd0b5ed62e73b4d GIT binary patch literal 2774 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 literal 0 HcmV?d00001 diff --git a/examples/timeline/img/blog-post-edit-icon.png b/examples/timeline/img/blog-post-edit-icon.png new file mode 100755 index 0000000000000000000000000000000000000000..12ab23c64717a0b361a739661f5bdabf16df85a6 GIT binary patch literal 4225 zcmV-{5Pt88P)rNTd||mjSweJP^3RV9SyvkrLnJkTab3`*ly(-uJPsoxS$jYoANCQz$03cM4aAW6_jSitvx{Kaul_=e`e3TAQ!(4+n+}wT$2W z+}O$$XO5&knVv}gjNYS%VgS`z<4P(yns&LAGC?SwmW**>EdzVX*74x`+I+~^FwC)G zPFfp=p-f;}7t0k@ELGOhspQk+qa)YeBLJmDt=_mYIX;@UCVx*qXsPUtJTd6&7@Nt z;Wyfy?kC4a64`qLP%I_t_2!kyiLvy46Z-!G;NQJ707GqM^E8}@>fv}yA@Y|!9?$28 zf`Q7t0cbQO0`{AYdY!Iay-Lw|j82?*pK~%#B$vxkEEXfb-+v(8tceSq`qmhfrGVc@ z<6|RoPPtlpIT-Li8}R#$y8=)smO-JWodeD){?}_iQjtiMTCJAOWH#0G^bDOobA~Se z>nnPActmYwGWzJzqw2n6$0#v8yl*sk)vbJxF%nrs0{pkmAu3fW-wOr;Uj~rwdj_D< zXeh7OOZ|Rdd)#j2a=QuPrcS4$d)=;5E|<);QYlk1IsQxY!HR$Ys8nk*K9U-D!iVF2 zxl(%`Dfp*}ShRl^02+HJBtP2k%Y^rP@aIekKF3xXh=B8%8-Ohk^6YfF1khBi)v4R< z5u|kQ?-@p~RIYvlN&TIBjzG8D)$=!RDxL(Qpc9FNT3cI1=v@?zMs+M6R}1s=8lS1z z*;!g%Ue?L+aaAdog&w@p$z+nYx3?t%Znujnm8!n~#QRjYZ!idr1(VCM@VQ-X?eVx( z579=Q_!9EtZ|@0!%>+5YDr%q(`FuX16rU&5@_6Jc447-6%UpHc>-Cfs4f|Z?y2dK2 zPPa?hd{Os%eJS*P0P6L78n4QO?*xN^y5H~n;_OuVpYEDMm=OKqjh|B>5R_xAy1X&~ z=Dgn@kTIXfiiJcM%YjJYI{_*di`46Ng;p#COd&qE-R>Zn4NJjXG&M5=>M+F&0m9D; zC{`+$i-}n5*B`il_Q!V}0UkG-O`ed9OQj-KXNWoP)B#XTG~SMq9lGrHwgRR0L=uye zaT}3zBIC%bf#@LF`%OUXM@v{C>5xxJX`~PeXdu@W|*L z0pR)oP@Fq^=HyrIib9r&BeSTQs=|_LzsH~3sv|xJPo`El9Kl3Aqz8V3KeHda;4pGQDixYcA0eOLcVGm5 z_=jKhc{kSnz}xGFyV2NRKK1<{6n<$AFl~6{k*uOB9D#0^C+iZ$;R~?}@i_)4M`m6~ zj c?g`in@ijP7ZnsCb@SApGut)0k`b;NTFuP)NkrM!g;@r72rv$*OfA{y^?zJm_ z-uQ{A!N`@PjW0^n+U{hfDIFc_pGQ&Xr3Hxw&RDwSdiXm+hT zJ3FWcF%=4h3EbDC$bo9LiYS#Z9#g2~T+C!4SnH#)xW%K~(`JG112VXcboRYJVuo49OB5Zit#xCECkCYD^RP|#P4{lu1!vss%`V1 zb4GF?yL~C3I$zI}8ZYL1zTZ9jz%j~Yw)E2Tf7Y)3;%9-8@rjk#`NvQ0>xHhq{kEE% zoTO5zq{ESjg4rTglbzg-j>cllUyaGB;Lwm%>tdmxI6)`VY2Ad6l4N%&?eqGC>#U-q zV`Eb6Ov-4<6T@2dcSoR@-T13+dAl2)IsM#rspfW}TF1jdwYIuulwSIFabkA%kDvOB z7yf47B;MTEP~mWxYV|r~)35x@RZ}hGIGfGtXfz@`j)cRy(QHT;4Z4VQHtG#7Sb8WF zV!9zWypsG#a>?fy zTUhv$XTJGO&yYZtNiIh1R!ey>d90YwjBN$z zrIF0avJcwl^9!}OXDF9S%I)z2P(zO;$CcJkxOia8qBml31A!$$`b&w-q=m{AMuYum%hWwE&Y6Du}{h z^3-7f;gDjR4E53VT1{bs96622E7TIIRI54`iz}!U1@T=_%G|k-D45#czkZp*nV)L+ z=!|m3CrCG|+9<3kqp(gT|HO;c*!^FB_&1*G42lgGjKLfr%U!}EFVPUZ4=WF^X1mj- zSTsi9zL+sq4yG4B5D|wC+-{aiWzeZB3KM{m@wt2s(}+JC3Wvnx*#O{7sdw!a3UB|9 z&_>1JqncGR@@v#DZWv8({L;*C&wcfdl{l9#2!(iG$O?c&03bxmK@;)+ER)Q8E>v9D z2JJMDSw(t?0Ay8)S`~Q%`ILla`k4jFP^h|cJ{lY;aO|luc^%sNxpI$A@#L{uHD%=2 zG5Pg=+Y_C02Zp{e`Gs%avE5YJor3HOp^1=f6(uUv*K4b*s%!Gzu?a9^h(c7CQIOVF zS9B^hDYD1~iz&d7GZ)oRmS2Jj4XHXTG8eum7J>^Oq63=MrD00s-=b*d^ke(2 z-o%TpQ2c90KKreGdu6qq%R2yU3NZ-gDpQ4@E)=0M%o_WBE?R8Hm@bf7p#@Kht1uTV zexDVHT_#Jc6e&qogIdj&6tW1Y$O-Sh{T~z^q)i)C%&$_vut6o?_~l>u(hHwB(9CUR zcO(arBZ;)KBEaggvb?NPC}i;VnlXhjNtg7rRTMBUk~9f(mQ^)O9Fak9;DWVo17KUD zZ%|Mpu^p(!%8w!l$<+b8kAf%mTP^&%Itte9O_TfWPaHmqHVCRUzJp*e1n zy8W6STK$pojLncMo&s$epv}56ifdF#Jg7SlKC9|G>vNAj@#Mh(Hn(#EV01WzE`~7}TbX?j?M5EPiiPhlB+Q!%mFT{v(o^D^gtRk78fHqSa z39B?up4FzXrYj?-RrjIKAoQjnRLiBg#~*#Txh&hD}4Y^)IA!A8l06ZZ{ zIwT~wiCoCov~k{tyaj7Nm@I30@Q3jN!rEk^;caf*8H|AOgvyicEnV1=scF5rxh~YQHJ{tW{Elg>$HtPhxw#=0 zn$LHETJ2U-3ST%J)#=Wnif;V3Nt;AU@#L}U8fv4e!>6cw`m`jZLJiTT#0^+ORQm7ask8k7!=XKHl$|D1f@=aRjNV-# z@j%wKcq5dfU|I>T(r~YoxvIi9UncL!5tBB(j!B#RnkvOkKq^0v%y7wu069&deN)7w z5M+Dq!;c*T!0nX{>4_sD20)I7dHbz5r6c14gwn5?jXGOprj8y>CebarG(3%Lg>dy{ zz$38Vs1y2F>zeWr!1#Td`Z%YsCIE_&xv^^9Ugg4MZ;=n)iLtg4cQ>xId5e|n0XO*lT7f1S*GWaksa?(zt-UFn zFNKd$?~&hfzB70;&>35=yvczL&jlTBf-_f7>_yzUFkDsTe8q$rSlxq9pd;?r|0DAs`c7xOqdYH1C|TJq{rs?5%ZMMv)8hzICIX=C8d)KYaNg z>Eg$prU%YEVs>-1dzZ#inLSVA4m9E?1mV)f$Il)N;KuD`0RWmfGRnRMCQk6!d!U>T z+|)2#$n-$ki-z5*5kd*h1Kz*U)@@e)$Hvx{$9?YR?~Q;X^ zTUeAFK!T>t1W=apIH&CU_a654yESnKpWa2aOPxJ`07Cy)jRs$NkEqwX^wA5C9sh5Aj_o`0yHOcjX?q|MAiXDX9m?#2bRuB?NdhY4+*5}EaP{Wx zM5$7}0`8_P$_#w!#N&<(+Pm@tt3D73=g)DR$&$0NYo5D1mQM_;ER%lesSiJPAb|e` X4%%syG(5Yu00000NkvXXu0mjfMVmS1 literal 0 HcmV?d00001 diff --git a/examples/timeline/img/comments-icon.png b/examples/timeline/img/comments-icon.png new file mode 100755 index 0000000000000000000000000000000000000000..736789edd6ffce59fd55e89948bd5ead588a8106 GIT binary patch literal 3173 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 LNkvXXu0mjfA!Y1$ literal 0 HcmV?d00001 diff --git a/examples/timeline/img/community-users-icon.png b/examples/timeline/img/community-users-icon.png new file mode 100755 index 0000000000000000000000000000000000000000..a77e239a3cb3df9cb8367d0beedbf1ab545fcaf0 GIT binary patch literal 4664 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 LNkvXXu0mjfwykOf literal 0 HcmV?d00001 diff --git a/examples/timeline/img/product-icon.png b/examples/timeline/img/product-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..fb12da43b3d7979fc6377f30398dbd12bcedded2 GIT binary patch literal 1594 zcmV-A2F3Y_P)3`Oy;0h7DOD~)MWi595e+d4w7XP@7D~Alfl#X$B8s5K5aT~F(O(*Y)F2@- zCQX%qs6e@xD0EAyn5IymQd)Ym+Z&~&H(Iys?#y`RTxMss3qLSXe|VacbLLFb_c`zP zeREDF{L4-HAK*U)Q1{aZ+wHDV?>ghBOp_#;yw$q|Iw!w6G}w!Q?l#D>4K~sxnXGFX zR8@hZsz^*qA&(mQUD7p`z9VnhNS*`zEsaXx_O3@?_#|%_K<$b5b~<7wd}wpUBRJ4b z#U)7>vC|Qx_uOnjYuy#t?GDoIkZm^l#}y@nP%wy;1zA)GnnFg>RW^c-Dx7f>KmZUJ zy!lb`(oc690M`rO8B2uPo$(L3LVtDw`tBqmEL#D(JDSmQ{Sp@^U6yox=0GTfIcclz z0T80kj**E7+-|$0siBFm;-Ec6Cp1X6+5>ZI~O3Gt&OO!EF;S@WSS!q zGyy!v`yEo^7NXU+s2Gm|YPpd$p)gc^U zVOY34mphPR=&o| zjze&Oa3XRD?!e5fFBm}ekv9y0u&@A;c^=4UYpO?8c?r#a_HBUSfZi8pZ)W0@N*9Y( z5hj2YdpW?5uSapfS^;_(S{rLoSypVsUwlObz>Dj*(5eWBf#t#79C&QyJ`V81W|D-$ zfrtc@!VWYyT*u|#in#q8K%)pyiSY7`Tlwxyd0-Y7a{;hwKLfb-{U)A-ChH^OuRGwY zuffIAGe{gi3EiC?R5&I!p27_F_hIF$+e{&d%mdZ*J)mozS*yQd09A)y3Fm;xb~cwG z&V{Dh8gzHv#MATBQE}djhU!XqmSrPu)EJyTdH_q;ZK6;bKL@NKP|X!U9hkM|YYuQI z$4!L1!@quE`*nccTU{8P@Blpn0z*T%cBve5pG~ECaHG|S@slQtvS1KUt%+!HLG{dD zo6i8Q9^Akk(5)5_R&n#`s0UyFVM!>l-Lk#&xoWsz{w!N7LiMD)^bG^}{lHo`5%os5 zpMQv`AU~eLAPfL1Yy~h}Fn^k@$>>R0e~Wk_s_gR5FD?h=#>O1IU*GUWN7Dj0rDtDZS87Ycw3HyJ2E%#?I=*yf?9 zr-xoVDlV2|*6bAc{eDbOo`L$hT8tZ)NX4&JT}Aeq73eSfSj50`B{Lk*T~Vz7WWh5h z_f!M`X)%vv;X=zOG&TJJhr@{zg-5Y4)s4QsUZg+21SMy^NP2iG6)QUZGxGNCM_=jt zMk0g(B0~@c;IPpFMoi5_dGl!ad^&&wCyy6m!NN2Ouqb^o&Xp900nYq_J$YZ^_OCl4 z$}l>BaEUhyKpGi}^|>=C0~ead5P&8MaO&i7%wLd-{=PoA7p0^0TnUnrlIUOX7M;Q8 zd-5=Neg_vv_(m+;7%nWDn*f}p0GIPKCXh)Bnc5`RI0VOMAf(9j+SPTd6Jy6F&@0!- z*f3#!4MvCV97t zbbU;eG-Zq({x~v^0V{ZYblj(AkaRy-Jp3WV3}}+Am(06JuO|IF9Y7Z$HxM{Y-Nn29 sE|#y|Pb2?mV2}gc;XNRFPEJnnFH4UWN> zrU6p1wW6qjsz{?D6*MGZ0?M{{sq4bR-fwf+o!PnU%$e&sGjn{;Fq?=j1&odV@Fj0% z<~x_?_rCA*ecv$nfd_LH;3~lP^`fVD?`10OwvHB0V`srIv~)J>OJ{PvoUZ$G`FwQq z-5ZPFJHYREzS!ur+1ANCdz+`euG48%>a129!*MJ)j)Nr0&~(knYWZ|K6Ubt*pvqZ^0|)*IgRY$~xeS2>6>5oSR)7G_ zFg+j$;-y>g$5#*B)8MYzHow-@Lat$W%2Y8kqB5ExnV*z-cshdav;BxAGZ^SS4Tf4I zlc1TkAW9`qm~G(7{Vx^^=DacJ^<5m`cROE_6`Om)D=e%@lCbDdV7KsaFhw-*27Xj6 zLyu1(98KWtWDf2M0g0Iq{G$WZYoXNh**2H}CWt`uR4xK@z?MJ%?VKzri-QFjzM_nAUBE~R z(8Wr+%Hqhac071=8VoPtm&~VVZEZm$rD1HKueA1AD);D20z>f>Qq;CKmlK?S7<_sL zr~dPA+<4O(V=x%5`s~<|nYm54{qKFW=G)A@JeSKrpf$hvnr1}e35-XwST^5@`%b2D zbDaY}Q@qgiJW_d}yZdttMq=onj>6@1qRFnnolhe^9VGMVxZ%b%c>nNwx&ATl{n4qw zdwMQwo(1`D0o=RkzCJ^0Y-?TMDJ?aR$Ah+}MX*^ESSZ8ZfngjzGmT|6EYj)Z`JGX+ zV%PrtCC9J-@p5!DHsIqA4N2OdH;rDBoWg{9I2y5jYyq=P0LnnKr!Xrs$!0ySs;XbuZB}D^eBz;0JoXVunFiF%g>eDE%3nRw zR_k{6wl>spHIh&|(I&h;h%PrcGGrjG;xX}G=&JcOqM;yO-L-?XvTE3XyuzJ<1O&iw!VJT(USIg7I*!1{~aE;g$K^{azTH`@@3cJn${)Q z_vXH#zSBMTmwTEl3nwVDvqt-0gPG$uK|rFADU@=^R7OQqtW^bFV_enlH$C<9?CtIC zIDGWz_ORdga#>g{gA^_$d@+D;UgIcu3gPQOJXOeQx38vuIN@k;@(t?mtZ?y?idO(I x*S+l5fXv_IW=1y;=_?ifE&%_RaTVYyz*l!zp+91aH)j9<002ovPDHLkV1m_RMTh_Z literal 0 HcmV?d00001 diff --git a/examples/timeline/requirejs/requirejs_example.html b/examples/timeline/requirejs/requirejs_example.html new file mode 100644 index 00000000..764a75ba --- /dev/null +++ b/examples/timeline/requirejs/requirejs_example.html @@ -0,0 +1,11 @@ + + + + Timeline requirejs demo + + + + +
+ + diff --git a/examples/timeline/requirejs/scripts/main.js b/examples/timeline/requirejs/scripts/main.js new file mode 100644 index 00000000..15e1d872 --- /dev/null +++ b/examples/timeline/requirejs/scripts/main.js @@ -0,0 +1,19 @@ +require.config({ + paths: { + vis: '../../../../vis' + } +}); + +require(['vis'], function (vis) { + var container = document.getElementById('visualization'); + var data = [ + {id: 1, content: 'item 1', start: '2013-04-20'}, + {id: 2, content: 'item 2', start: '2013-04-14'}, + {id: 3, content: 'item 3', start: '2013-04-18'}, + {id: 4, content: 'item 4', start: '2013-04-16', end: '2013-04-19'}, + {id: 5, content: 'item 5', start: '2013-04-25'}, + {id: 6, content: 'item 6', start: '2013-04-27'} + ]; + var options = {}; + var timeline = new vis.Timeline(container, data, options); +}); diff --git a/examples/timeline/requirejs/scripts/require.js b/examples/timeline/requirejs/scripts/require.js new file mode 100644 index 00000000..8de013dc --- /dev/null +++ b/examples/timeline/requirejs/scripts/require.js @@ -0,0 +1,35 @@ +/* + RequireJS 2.1.2 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + Available via the MIT or new BSD license. + see: http://github.com/jrburke/requirejs for details +*/ +var requirejs,require,define; +(function(Y){function H(b){return"[object Function]"===L.call(b)}function I(b){return"[object Array]"===L.call(b)}function x(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(H(n)){if(this.events.error)try{e=j.execCb(c,n,b,e)}catch(d){a=d}else e=j.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",C(this.error=a)}else e=n;this.exports=e;if(this.map.isDefine&& +!this.ignore&&(p[c]=e,l.onResourceLoad))l.onResourceLoad(j,this.map,this.depMaps);delete k[c];this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=h(a.prefix);this.depMaps.push(d);s(d,"defined",t(this,function(e){var n,d;d=this.map.name;var v=this.map.parentMap?this.map.parentMap.name:null,f=j.makeRequire(a.parentMap,{enableBuildCallback:!0, +skipMap:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,v,!0)})||""),e=h(a.prefix+"!"+d,this.map.parentMap),s(e,"defined",t(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=i(k,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",t(this,function(a){this.emit("error",a)}));d.enable()}}else n=t(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=t(this,function(a){this.inited=!0;this.error= +a;a.requireModules=[b];E(k,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&delete k[a.map.id]});C(a)}),n.fromText=t(this,function(e,c){var d=a.name,u=h(d),v=O;c&&(e=c);v&&(O=!1);q(u);r(m.config,b)&&(m.config[d]=m.config[b]);try{l.exec(e)}catch(k){throw Error("fromText eval for "+d+" failed: "+k);}v&&(O=!0);this.depMaps.push(u);j.completeLoad(d);f([d],n)}),e.load(a.name,f,n,m)}));j.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){this.enabling=this.enabled=!0;x(this.depMaps,t(this,function(a, +b){var c,e;if("string"===typeof a){a=h(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=i(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;s(a,"defined",t(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&s(a,"error",this.errback)}c=a.id;e=k[c];!r(N,c)&&(e&&!e.enabled)&&j.enable(a,this)}));E(this.pluginMaps,t(this,function(a){var b=i(k,a.id);b&&!b.enabled&&j.enable(a,this)}));this.enabling=!1;this.check()},on:function(a,b){var c= +this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){x(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};j={config:m,contextName:b,registry:k,defined:p,urlFetched:S,defQueue:F,Module:W,makeModuleMap:h,nextTick:l.nextTick,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=m.pkgs,c=m.shim,e={paths:!0,config:!0,map:!0};E(a,function(a,b){e[b]?"map"===b?Q(m[b],a,!0,!0):Q(m[b],a,!0):m[b]=a});a.shim&&(E(a.shim,function(a, +b){I(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=j.makeShimExports(a);c[b]=a}),m.shim=c);a.packages&&(x(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ga,"").replace(aa,"")}}),m.pkgs=b);E(k,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=h(b))});if(a.deps||a.callback)j.require(a.deps||[],a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(Y,arguments)); +return b||a.exports&&Z(a.exports)}},makeRequire:function(a,d){function f(e,c,u){var i,m;d.enableBuildCallback&&(c&&H(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(H(c))return C(J("requireargs","Invalid require call"),u);if(a&&r(N,e))return N[e](k[a.id]);if(l.get)return l.get(j,e,a);i=h(e,a,!1,!0);i=i.id;return!r(p,i)?C(J("notloaded",'Module name "'+i+'" has not been loaded yet for context: '+b+(a?"":". Use require([])"))):p[i]}K();j.nextTick(function(){K();m=q(h(null,a));m.skipMap=d.skipMap; +m.init(e,c,u,{enabled:!0});B()});return f}d=d||{};Q(f,{isBrowser:z,toUrl:function(b){var d=b.lastIndexOf("."),g=null;-1!==d&&(g=b.substring(d,b.length),b=b.substring(0,d));return j.nameToUrl(c(b,a&&a.id,!0),g)},defined:function(b){return r(p,h(b,a,!1,!0).id)},specified:function(b){b=h(b,a,!1,!0).id;return r(p,b)||r(k,b)}});a||(f.undef=function(b){w();var c=h(b,a,!0),d=i(k,b);delete p[b];delete S[c.url];delete X[b];d&&(d.events.defined&&(X[b]=d.events),delete k[b])});return f},enable:function(a){i(k, +a.id)&&q(a).enable()},completeLoad:function(a){var b,c,d=i(m.shim,a)||{},h=d.exports;for(w();F.length;){c=F.shift();if(null===c[0]){c[0]=a;if(b)break;b=!0}else c[0]===a&&(b=!0);D(c)}c=i(k,a);if(!b&&!r(p,a)&&c&&!c.inited){if(m.enforceDefine&&(!h||!Z(h)))return y(a)?void 0:C(J("nodefine","No define call for "+a,null,[a]));D([a,d.deps||[],d.exportsFn])}B()},nameToUrl:function(a,b){var c,d,h,f,j,k;if(l.jsExtRegExp.test(a))f=a+(b||"");else{c=m.paths;d=m.pkgs;f=a.split("/");for(j=f.length;0f.attachEvent.toString().indexOf("[native code"))&&!V?(O=!0,f.attachEvent("onreadystatechange", +b.onScriptLoad)):(f.addEventListener("load",b.onScriptLoad,!1),f.addEventListener("error",b.onScriptError,!1)),f.src=d,K=f,D?A.insertBefore(f,D):A.appendChild(f),K=null,f;$&&(importScripts(d),b.completeLoad(c))};z&&M(document.getElementsByTagName("script"),function(b){A||(A=b.parentNode);if(s=b.getAttribute("data-main"))return q.baseUrl||(G=s.split("/"),ba=G.pop(),ca=G.length?G.join("/")+"/":"./",q.baseUrl=ca,s=ba),s=s.replace(aa,""),q.deps=q.deps?q.deps.concat(s):[s],!0});define=function(b,c,d){var i, +f;"string"!==typeof b&&(d=c,c=b,b=null);I(c)||(d=c,c=[]);!c.length&&H(d)&&d.length&&(d.toString().replace(ia,"").replace(ja,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(i=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),function(b){if("interactive"===b.readyState)return P=b}),i=P;i&&(b||(b=i.getAttribute("data-requiremodule")),f=B[i.getAttribute("data-requirecontext")])}(f?f.defQueue:R).push([b,c,d])};define.amd= +{jQuery:!0};l.exec=function(b){return eval(b)};l(q)}})(this); From db7cf5f85b7d5a40dda574a2e32f34819634a162 Mon Sep 17 00:00:00 2001 From: josdejong Date: Fri, 7 Jun 2013 14:36:46 +0200 Subject: [PATCH 10/52] Created gallery --- .gitignore | 1 - _config.yml | 0 _layouts/default.html | 63 - css/style.css | 178 +- css/style.css.bak | 207 + docs/css/prettify.css | 4 + docs/css/style.css | 6 +- img/gallery/graph/01_basic_usage.png | Bin 0 -> 21769 bytes img/gallery/graph/02_random_nodes.png | Bin 0 -> 59579 bytes img/gallery/graph/03_images.png | Bin 0 -> 90604 bytes img/gallery/graph/04_shapes.png | Bin 0 -> 50756 bytes img/gallery/graph/05_social_network.png | Bin 0 -> 78216 bytes img/gallery/graph/06_groups.png | Bin 0 -> 40966 bytes img/gallery/graph/07_selections.png | Bin 0 -> 14025 bytes img/gallery/graph/08_mobile_friendly.png | Bin 0 -> 45752 bytes img/gallery/graph/09_sizing.png | Bin 0 -> 27283 bytes img/gallery/graph/10_multiline_text.png | Bin 0 -> 40747 bytes img/gallery/graph/11_custom_style.png | Bin 0 -> 60523 bytes img/gallery/graph/12_scalable_images.png | Bin 0 -> 106967 bytes img/gallery/graph/13_dashed_lines.png | Bin 0 -> 26811 bytes img/gallery/graph/14_dot_language.png | Bin 0 -> 13090 bytes .../graph/15_dot_language_playground.png | Bin 0 -> 31298 bytes img/gallery/graph/graphviz_gallery.png | Bin 0 -> 267856 bytes img/gallery/timeline/01_basic.png | Bin 0 -> 9239 bytes img/gallery/timeline/02_dataset.png | Bin 0 -> 9239 bytes img/gallery/timeline/03_much_data.png | Bin 0 -> 13951 bytes img/gallery/timeline/04_html_data.png | Bin 0 -> 15839 bytes img/gallery/timeline/05_groups.png | Bin 0 -> 24442 bytes index.html | 294 + index.md | 151 - vis.js | 12379 ++++++++++++++++ vis.min.js | 29 + 32 files changed, 12942 insertions(+), 370 deletions(-) delete mode 100644 _config.yml delete mode 100644 _layouts/default.html create mode 100644 css/style.css.bak create mode 100644 img/gallery/graph/01_basic_usage.png create mode 100644 img/gallery/graph/02_random_nodes.png create mode 100644 img/gallery/graph/03_images.png create mode 100644 img/gallery/graph/04_shapes.png create mode 100644 img/gallery/graph/05_social_network.png create mode 100644 img/gallery/graph/06_groups.png create mode 100644 img/gallery/graph/07_selections.png create mode 100644 img/gallery/graph/08_mobile_friendly.png create mode 100644 img/gallery/graph/09_sizing.png create mode 100644 img/gallery/graph/10_multiline_text.png create mode 100644 img/gallery/graph/11_custom_style.png create mode 100644 img/gallery/graph/12_scalable_images.png create mode 100644 img/gallery/graph/13_dashed_lines.png create mode 100644 img/gallery/graph/14_dot_language.png create mode 100644 img/gallery/graph/15_dot_language_playground.png create mode 100644 img/gallery/graph/graphviz_gallery.png create mode 100644 img/gallery/timeline/01_basic.png create mode 100644 img/gallery/timeline/02_dataset.png create mode 100644 img/gallery/timeline/03_much_data.png create mode 100644 img/gallery/timeline/04_html_data.png create mode 100644 img/gallery/timeline/05_groups.png create mode 100644 index.html delete mode 100644 index.md create mode 100644 vis.js create mode 100644 vis.min.js diff --git a/.gitignore b/.gitignore index 9a4d5fda..485dee64 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ .idea -_site diff --git a/_config.yml b/_config.yml deleted file mode 100644 index e69de29b..00000000 diff --git a/_layouts/default.html b/_layouts/default.html deleted file mode 100644 index bf6cfbca..00000000 --- a/_layouts/default.html +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - - - vis.js | a dynamic, browser-based visualization library - - - - - -
- - - Fork me on GitHub - - - - diff --git a/css/style.css b/css/style.css index 29d2e08b..5852141a 100644 --- a/css/style.css +++ b/css/style.css @@ -1,105 +1,20 @@ -html, body { - font-family: arial; - font-size: 11pt; - color: #4D4D4D; - line-height: 1.7em; - - padding: 0px; - margin: 0px; - width: 100%; - height: 100%; -} - -body { - overflow-y: scroll; -} - -#container { - margin: 0 auto; - width: 900px; - - /* TODO: cleanup - height: 100%; - */ -} - #menu { - width: 150px; - float: left; - text-align: right; - - /* TODO: cleanup - height: 100%; - position: fixed; - overflow-x: hidden; - overflow-y: auto; - */ -} - -#menu-inner { - padding: 70px 20px 0px 0px; -} - -#contents { - /* TODO: cleanup - margin-left: 150px; - */ - padding: 50px 25px; - - width: 700px; - float: left; -} - -h2 { - padding-top: 20px; - padding-bottom: 10px; - border-bottom: 1px solid #a0c0f0; - color: #2B7CE9; -} - -a { - color: #2B7CE9; - text-decoration: none; -} -a:visited { - color: #2E60A4; -} -a:hover { - color: red; - text-decoration: underline; -} - -/* -ul.nav { - text-decoration: none; - text-transform: uppercase; - - margin-bottom: 30px; - padding-left: 0px; -} -li.nav { - list-style: none; + position: absolute; + left: -150px; + top: 35px; } -ul li.nav { - text-decoration: none; - text-transform: uppercase; - font-weight: bold; - font-size: 11pt; - color: #2B7CE9; - - margin-top: 5px; +#forkme { + position: fixed; + top: 0; + right: 0; + border: 0; } -ul li ul li.nav { - text-decoration: none; - text-transform: none; - font-weight: normal; - font-size: 11pt; - color: #4D4D4D; +div.nav { + text-align: right; } -*/ div.nav ul { text-decoration: none; @@ -115,7 +30,7 @@ li.nav { div.nav ul li { text-decoration: none; text-transform: uppercase; - font-weight: bold; + font-weight: normal; font-size: 11pt; color: #2B7CE9; @@ -141,67 +56,24 @@ a.nav:hover { color: #2B7CE9; } - -table.example { - border-collapse: collapse; -} - -th.example { - font-weight: normal; - border: 1px solid lightgray; - background-color: #E5E5E5; - text-align: left; - vertical-align: top; - padding: 5px; -} -td.example { - border: 1px solid lightgray; - padding: 5px; +.gallery .thumb { + display: inline-block; + text-align: center; + margin-right: 10px; + margin-bottom: 20px; } - -pre { - line-height: 1.5em; - font-size: 10pt; - overflow-x: auto; - background-color: #F5F5F5; - border: 1px solid lightgray; - padding: 5px; +.gallery .thumb img { + border: 1px solid white; + border-radius: 5px; + height: 90px; + margin: 0; } -pre.example { - background-color: transparent; - border: none; - padding: 0px; - margin: 0px; +.gallery .thumb a:hover img { + border-color: lightgray; } - -div.lastupdate { - font-size: 75%; - margin-top: 40px; - - border-top: 1px solid #a0c0f0; - color: #2B7CE9; -} - -img { - border: none; -} - -img.thumb { - border: 1px solid #a0c0f0; - width: 120px; - height: 60px; -} - -img.thumb:hover { - border-color: #2E60A4; -} - -#forkme { - position: fixed; - top: 0; - right: 0; - border: 0; +.gallery .thumb div { + margin: 0; } \ No newline at end of file diff --git a/css/style.css.bak b/css/style.css.bak new file mode 100644 index 00000000..29d2e08b --- /dev/null +++ b/css/style.css.bak @@ -0,0 +1,207 @@ + +html, body { + font-family: arial; + font-size: 11pt; + color: #4D4D4D; + line-height: 1.7em; + + padding: 0px; + margin: 0px; + width: 100%; + height: 100%; +} + +body { + overflow-y: scroll; +} + +#container { + margin: 0 auto; + width: 900px; + + /* TODO: cleanup + height: 100%; + */ +} + +#menu { + width: 150px; + float: left; + text-align: right; + + /* TODO: cleanup + height: 100%; + position: fixed; + overflow-x: hidden; + overflow-y: auto; + */ +} + +#menu-inner { + padding: 70px 20px 0px 0px; +} + +#contents { + /* TODO: cleanup + margin-left: 150px; + */ + padding: 50px 25px; + + width: 700px; + float: left; +} + +h2 { + padding-top: 20px; + padding-bottom: 10px; + border-bottom: 1px solid #a0c0f0; + color: #2B7CE9; +} + +a { + color: #2B7CE9; + text-decoration: none; +} +a:visited { + color: #2E60A4; +} +a:hover { + color: red; + text-decoration: underline; +} + +/* +ul.nav { + text-decoration: none; + text-transform: uppercase; + + margin-bottom: 30px; + padding-left: 0px; +} +li.nav { + list-style: none; +} + +ul li.nav { + text-decoration: none; + text-transform: uppercase; + font-weight: bold; + font-size: 11pt; + color: #2B7CE9; + + margin-top: 5px; +} + +ul li ul li.nav { + text-decoration: none; + text-transform: none; + font-weight: normal; + font-size: 11pt; + color: #4D4D4D; +} +*/ + +div.nav ul { + text-decoration: none; + text-transform: uppercase; + + margin-bottom: 30px; + padding-left: 0px; +} +li.nav { + +} + +div.nav ul li { + text-decoration: none; + text-transform: uppercase; + font-weight: bold; + font-size: 11pt; + color: #2B7CE9; + + list-style: none; + margin-top: 5px; +} + +div.nav ul li ul li { + text-decoration: none; + text-transform: none; + font-weight: normal; + font-size: 11pt; + color: #4D4D4D; + + list-style: none; +} + +a.nav { + color: #4D4D4D; +} + +a.nav:hover { + color: #2B7CE9; +} + + +table.example { + border-collapse: collapse; +} + +th.example { + font-weight: normal; + border: 1px solid lightgray; + background-color: #E5E5E5; + text-align: left; + vertical-align: top; + padding: 5px; +} +td.example { + border: 1px solid lightgray; + padding: 5px; +} + + +pre { + line-height: 1.5em; + font-size: 10pt; + overflow-x: auto; + background-color: #F5F5F5; + border: 1px solid lightgray; + padding: 5px; +} + +pre.example { + background-color: transparent; + border: none; + padding: 0px; + margin: 0px; +} + + +div.lastupdate { + font-size: 75%; + margin-top: 40px; + + border-top: 1px solid #a0c0f0; + color: #2B7CE9; +} + +img { + border: none; +} + +img.thumb { + border: 1px solid #a0c0f0; + width: 120px; + height: 60px; +} + +img.thumb:hover { + border-color: #2E60A4; +} + +#forkme { + position: fixed; + top: 0; + right: 0; + border: 0; +} \ No newline at end of file diff --git a/docs/css/prettify.css b/docs/css/prettify.css index b4ec4ca0..07d25d3f 100644 --- a/docs/css/prettify.css +++ b/docs/css/prettify.css @@ -16,12 +16,16 @@ pre.prettyprint { border: 1px solid lightgray; + box-sizing: border-box; + -moz-box-sizing: border-box; background-color: #fcfcfc; padding: 5px; font-size: 10pt; line-height: 1.5em; font-family: monospace; + overflow-x: auto; + width: 100%; } ol.linenums { diff --git a/docs/css/style.css b/docs/css/style.css index 15554585..5addab9c 100644 --- a/docs/css/style.css +++ b/docs/css/style.css @@ -13,9 +13,12 @@ body, td, th { } #container { + position: relative; margin: 0 auto; - padding-bottom: 50px; + padding: 10px 10px 50px 10px; width: 700px; + max-width: 100%; + box-sizing: border-box; } h1 { @@ -36,7 +39,6 @@ h3 { font-size: 140%; } - a { color: #2B7CE9; text-decoration: none; diff --git a/img/gallery/graph/01_basic_usage.png b/img/gallery/graph/01_basic_usage.png new file mode 100644 index 0000000000000000000000000000000000000000..5fea7b0fa8319a864cab8be44ab7ea5cd47cf98f GIT binary patch literal 21769 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

=pBqryqkC;$W>REY<2 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 literal 0 HcmV?d00001 diff --git a/img/gallery/graph/04_shapes.png b/img/gallery/graph/04_shapes.png new file mode 100644 index 0000000000000000000000000000000000000000..b556c59934c13c565ebb30b04578a61760e85493 GIT binary patch literal 50756 zcmeFZ`8(9%|35lNLZ~F!i$P^A`(9BLegq_P8YA^5dzmf)z6q!m2H@rc^TPUa4#~N{#0x;V&<_PEYIwF(H2E}ZM`ut zO#%naIWHg=zd#C5CUj^CAo>WL2?_*>C6S=8|Nryy){aIumrOaOJ&ubla`(=0>;3pM8HN=+PyX0{dgS?cHwt5rR7U#s z*2z&_y^BR&jr=jW8O->fM-1t>c*&o^!i)d;Q;zX<_kTOlD1W?sj{H!ZZSKI;e-HIO z$Ws0H{ge-PL;pP_DfIt+p*U%@dy7mc4Gp~UR#N3|OxAomPjDIUv)9Sbs)J7l@4da% z{-L#SQ>GOhQ+0d}3w|dyGtm4g6eCs5|DSCR3iu~jKE6v;4dddxa4i0wYo~WLj zQlQf|3*~YoqFZl4u%KF8#9g!a7>zEF z(*GxyIB7n~7h1OBLWheJL%b}h&f&U(UPHrl`o3;CyzjXJ>}-A{G{MZR9CQ97J^0-h zo1>jsg|6=Hi;KwLGdI&&r8q=yVA*=kCeqL(=x*+tJmdI}H0^iq8pnMa7;s(8n@p*; zs$a>YV`jflEZlpoc?R$3to@&>$}ym~x%cjYE}gne|BGbCRotY|!{xWGlCrXj-|>zv zBL97A#3WVkrRs|pHEugS3F|q|O^t1*%B!89NnCRa!R&pMdi0;u7}^{B7`@tBSo9$^ z)knj?3=WP0R8L*9w!!khf?7@D9J-#w0xR9>diPhC9UEFT*S4LWwYG_eVPn+t|8vYD z9dJwqE%o4Rn3rKU?whiWZ?IGrD=K8G=@G3_1 zuf9c(|H{^o|NZ$|A2a8iHhlEg`VScwzzsMlP2!R9pa19Zv^Js56SDlJ@+BO_h2pJi zo7l!CnehK;s7Y>`(XZ=EoeOw3s!kb6uWlb+k{TLqon{5%X^YM?l5ckh8DojW*UdocqvPHl9&>^X{ty4AC;emLw zWb@w#;TX(ygV(B6%GGmS-_{zOlb)6;B%LSmpb2`s|12)fPy{_DgP%(Dy+6+-n-}Pb z>J%fwducyLU@+GV?vBqHq~`J4E_uvXvIs~*w{`z-UxXhz92B^i@OP#GH$Cr3 zaG6bNbf{pf7jC=-WIqQpkAG6#a8hmdhHZ|}xbbn6P2N^r`O&j*=Gui3zA70h*D2EO8U06ThRLj(TpPQU8tbpw;?`5`kXX&4B6}V6 z>HjVfP)g`nYMeqK?`WFX+-bpJ@V+^9ae?=%4}Vu|Pd3ZuYG%#9HuAl3PNCqnr2ePhG$lY|5RuRAx{0ZM})O2GIhEDsCRm zi=r3;vo3l~^Q0Q%q18UhD9m$? zv#herDP!+y`?NHcOR6<;(@Q93#_c0!?{g&|>9Xd0MW(k|42WqFNtbVTyuN_#;&3G4 z4hxr8Jh6LVN>VZ6`NP;A7GmgKtyhr^(&9s{4HD;&IY6eYd!axiS_sS%16Cx|8F zbc-8gsTQWf-O@~v6y2oydYUp~6?(qw@src+!# zryl@7LGQch3m`FZ28fM5&?JfE`_-`$a5?E!rt1 zp8NRf*Q4%__Alj1l7AnXmh%aRM^vAO;^N{GK8jD%MX_Uo4_P~^+ z-HfRur@U_qql5~TYb2t05dwq6o>FkX4B>%XrkQ;LS%EZBZVCr6L(bA{$^{8R7!p~| zpJ!TNm1!Wf_pszAzeZJb{o?=9;cJF|lE{2Ju~e&mBkg!xv+{U4{orxTyQ$l&XVLig z{?)dwe~Sly(QZ~)!G_;wT>kP@Lfr2aW)J!*o%X<9HE+j`C&+K9d5Q8G%|Mj3*!D)c z5rd}8vYth8J-#@5z;$_<`r!HlI}E;BLRby*k@3&aJPh)u;Xr?d+u;J?w8h?sMK>_Kr9I zEyPu|5PFq;@EtkUy=O5l-TL}Y2^JE~z})Q>QdTLWPQ^&MX+D;Ig0@syStc}iG6m^U zK;s*ta*|&jpU<R>D*TbeBdLo8wjAu} zh)WKfPgDnc(#A0Eo4aPAt65eb@lRFm8Z0lRkHhyF5l=QG!1z zrzoU}rM3tv;G(}G)rS$`<$YWYt}Z$MWHD$tO-e3m25-3<7@G9@xw-g~f%|q{Kxy1z zSWYdD)ygi?ECD8m9C>ljIjlhC$&&CFwpXV-9_UCDn*TN=L`bIJX}qPBL?kCPGgY>( z)_&~V4fkCenCe5!!6v`j?>g%IY`WA7_7UgF; zu5yde%X^z&J1qLgKMT31Q6L}ts9^ea+@q130k8t#MCQ*vd%f`bIkqlUMcy*gvm%3| zM{4QNeD7Vu@8QXYrqdLM0f7nS3$|>X?+>42^^F>Q{zNAW-A@6|A1=p#or**GUBzkO zqmFU~L$g!uDjv<&WVgN5Iirp_`)+D&x3c;IbxEd^DfLI0pzxA6-(HMaTHbrm-zrpG zvvLV>L=sFcCW_}j{k(h@`H56s@}{GxWGU2dwLy7Y&QNr%MVy6rVALAmp!aN97IOPs z3lgG3>3S=O1p=e`lN$&8RP0plb%}oeFLp&*3(~{RC)*d}%~6IKCr>JA->vtCm#BQh zyU7L-EScahq@k?6%^rnvSH5&RLpm0z{X$va=NM${4Q63kFCGLKcR#E9=%A_VbpRO= z%z8jcXOn4e*H?&rsNcFel zCqMy{at}DsnE2yybe}&L`%u8x+AP@O*Npxl8MSW%zsM2@lKw>)hs_zSmD#(z&~TzIex$@-NfZgwC|oDbm>X z^_>@a<`VmfpPQy^{p-(RSmYrV?{_lJF7GY*tc-ntVeIA#sZ7Wm~dCU#+k29vk zp1=b6ABXN+zrUL-USqr@21|S3=D0Sqf3%~1o18>W2*1ez4vhwLgdE5?V&E+0H`Wcz zbCk5R@2Z8Fo6zIw>Q((kzPj`*&M=HAA)Z%@#oYgRuF6soGpHOX8Yq#+T`MIWpIO^sm;Nl3 zytz*^#%#z}BKV6N$BFMR*<*gOJYlUOLU4KfhN>My6RM`nU=vzh)E)E0sits>d`;5* zVJT&DIxRH{4$@c_DUSRnNeqbzsg-hZ+ZMLg$QK%arw2a%%a@v7F9%kIH|!-uI@cd2=Ttd=rKfW-#g8vN7;$ zz`3n7x)ym7pZwX^&GqWq#{m)Ib6fQLMAz9bxRBbthL}~32&oGCm;PDv7WvWi>6cP- z*yEXy)aiT_3#}RAlPtvhR(Ok0)ZH-!aT?3eL~wb(U)cQEZ>r`TD6g^F&Yi=QwV9ui zXkToN{22}Mby{1sCMMh9_N@8pfQvoRigmUY)`MSrma{&WUZd=^FJ|1{gHFz$>#E@; zRlH6EZik+aa+Br#Uuo?2N=XfM^izeCMb&Jd@Af+lO+PL@dA9tymczAoq+oSYyGCqn zK>XY8F^66yC+s!dkB^-{luCSby)|RTsVzN#!aQ6r<;F z-2;Rt6AAuW?^`GE)avF ztth5K>r^{5#@fHmyybE`rbF_)!lyYlun`YGL`T&~hd28(a3MwBJ$mv)GHk)CG`h^j zxLQUveVwwC!|c^O9E~TpU8J)!H@V_iHI9xO5`7I}!&U!SzxvgcsQhhLJ6n!i4 zu#rHV2(X(PGHdD=(mW`~U?%Q9$1<9)9M)$2Qx*n~9lMiA`Ht6;_XU_b%Gum7_gkN;gWld+>e)XaadIoVb;jy+0!xTIuLLSNh#kIA$RFGo9+`O#PT)QVUm!g4apVk+z#ZxZvrx978u% zD2T3t@l*aKY&R<=b)X)RjT?+yw~v6w1Qp06gwDZq9x`V69Wr)$)~G~PJCcd0AKlyr z3l{1mHOt6iBJaaeC8vE#SQ%xh-2gXn<#r>oFIF*bK@=mi8$TaN3s1B$-Z9Hs zXZw#Pu%yw(aY#P=_EA~Oqps^bghu-J_XEE5R32n#bhoLBWql8S;mr!*9MqgtU$36Oap+gPDn!tt( zuGS8duJ{|b7n-PD2>Q~=l}5VoC3J0NAnOfvMFdIWaWkT1@9l}X6=BZ6L*&dOgx*_| zxE@5Wws?X~IxCv~MS;fg6pMVol7|uqWd{WlKVX%gYt6p}@Que?Cl8ToMt2|g)>2O#>jcY;zPc!$Fm+KYAm)CJSCdKM7&CM8hm z8qRLhXil`_h4bgfd64imgNR~?FeLQH&Nryo%c!l5^~0xG*~zCUUqzRaB%yfvFTet(otV|w+7$ zwVRXuRI-#Kp+-?bjnCZI{9RgM&sjvskE~ykcW>$7g(|p`*1D1 z=htM#osEJLujOSb+GCjMr8lp|2#*Y}QZ2+>5xx zb-QfPBj#2k`NFINN2bQ`*Pg6DP-JZR@>w}Qn`TXkJ>WFbC0rjOOtVS3*4YK}gJvcq z%ARRV;R&n4lEOJ+)7fswSqfJxItvhEY`aVYB%E9`^&hdw4_Xpxj)d2g1VX6(a<(uJ z+(I9GGgkUMMY1I=hhVP``e_h(Nks+vM^OTj@3N*vPK~H%E8(f$zCWO?)70Ii_Gu1(Am|t1U&Y>*Id)B%uxhLFOJ@ zA|s;k&7+W9qzzwa-YH1rO--ozOX`@I1Yu*;)TY8@ z6*c`OP8~Nd;mF!ct+F10M&YCC3 zm72X!S=N>mylr2j$8nLB_8ucmDvauuPRP+In?^(-MX_fgLfHP4ozHJB9sJCuf||*F zJ-uIg(Cp&boBjBd23zCNvzR0A?|5I3o&L_n{eUq9M;k+=Kkb7m=aH1(*Q|k;=hx;8 zXlh|6*MlrFmHqw7oqLegb{!kGe>}Vnsax1SPXr0$)F2cP8krS`$*ZU#hr)9LC~=J$ z+^Th;5r|hm!F$xU`7i@FbPZW9f}=4?$q*f`xjzhPeEC##E&AliSbO^OtWO~PFc7~Q zYMFINlw?-rL@DjoG;nh<-Xsm-QWack|N1R05h!G7iKjz^EC{S0(|;}{Cx-_diq>& z<6{HWEUFTtPy1s&Crglo7DnbTko|l?lINmss*6T~?O9pBGeOOxvY8=gq%L$G>(B^% zveD$%i|c`s8VlN$dcnDFZ&P5D{+45Q0Vq*n+h~b?uy`zhI3MI?rGjW8`Aw2$&3@mB zf``}`@5%0Mod@dng$Z8D=tbSx1j7uYG(4}=j(RZZ?9~YXUpp$yOs<+$_9Eohjp|NkeE14e88#ehP1mVwmcDVaQ#QaQ*dZdi2TAZ)>P>A1)dZMBf=@$y)vzCcMQM}QP2 zlKIBjCx*n|zG;^EQMe06*XpOV7S z>5f_~#S;&X+8c_$G@7KJUuWq#<3eu>KjHz$1Ycj+I|v<^F@G-883)4*nFt$~L6a8* z@|h70KwOfSIz{`2dY^83w}Hh{ZH!s#i}w&{ynX*`Ro*}og(^RFP+b|PoL?c3UH#x| z4U@jmEhBOq$(Je-#y?!j@CV+V_u$>aQxwv)y|8b)E)S=+?SrZ8+pWtW-f%bl`)wfB zbrCnNS8n;7)He`YB5il^yuEH3Z61#TPgewap(~^sM6)f@EJ8y+)^B)sJ#gh{4;%Oq zBPB(HQcBOS{XuJT1Wu=POI#E5`Dr*rg|Pb4Dh^$^``Z5ik87sO9`Jv=%UF9TK7DW7 z8jaVqj<_TuA7stnIZb~_SauMYR?6#z*1j7$rL$X(Xh#P|Xnt++Rwj@MjEw9I4(hkD z*zA1Db84C?K+PNWylE7#%y$BLNNl%!&$D%G=ke!i}xp6g0^mF*NT z?34nte4RYET}jo=v{k1AZ0ZhFU0%p|ee>W*wV_z>SM1v2**gc(3wMCqENj*v3b1*4 z^bz*z^1QFEc$r~tkvC^(>$JkrMQ7yPgdnt>cf|JzV__*Q$3>XRcVQazRwMGqCt05B zMIj4ZeT_a{coVhXpc92ROW#QkXg)cGcAPN(kpx8vnH3nOFL`LM>s?dW?%Chz_8Ml9 z?ZT<|;*9l}yBLi^PQyF@)WOJGENqHC;RH7V)j6k6bARGu{+nYaqs_k`D+A|d_YQOs zX8qME`J>x+-&9A^aq&ba^nOur{Wh_$)$K)7-tK}lD+fj`-d(nx9-fPh<6QPo3J+Sa z$fqjz0Hx>`aL^07_wL>6h@HZ%ey(0!{HS?6;UUtz1+?!6xweh=E8SXsr^G-VT}IN= zmlkt)pnKNn?P<6Y20w96Ehjk6^tYcyGuN3@^1fy<7!6U^jgAYza_kusY_s%!N^UI-24zBb{5&^TFaoz`r7yzMvUO{CpS7w1L<~hw8x`S zHcT35YRCIFESyy_)*k$ObbJ$Rb&!+t)$NY4b9eI_og+23>x%vFZJT1G3Z0@b11V&i z$5E+PsH$)V=L1cA_a)?cagY z0eC!Oj{Bp9u}6jgS&Z~&;#3jNLh6wA03OH;x;x}ML(#-f%@$5bj^KSwQjmT%SVI41 z9d{hA%6seg6O?()>kb5PzfYwSPW%D>0^|xnJZaM>P32$yqwN`7QlPQlHSltdxv>eP z!S98U&-iki?BNYh2FBVK+1PUCbZ##9RX+e2wx^M!@C z(~B3fCeqa_ulPo#O<_%f?^%w~cMkmOM0p2`p(qxm}6T`L<;(=_Qvbv1Ca6*>PBx?9V1+<{=7{n)hmue;RXhI9csH8~pnZf)p7 zEkmWYj6srx?cdbh_R)N#zyH4#b=;H(sw+ZuYHW-#@|Xh|pqg8hof4*8K32w~-e||K z^qu`ClddII7V9nBs$}P&Jv9I4eY?_^hAS5sY~NM}g#w*a+csW$bHs*rw0DM@!*z8% z)f`l}b&F@uL&v}4Qyf5#s@+s7A%3`eUIYpRg!QmXaEbAny_U)&l}dT28vpuB} zAE~K9V%OFcSHz)Wz{GH67Ok)O(ku-oH9U7gqKuAR({U>=&_6+dorN!))T|=OAuVFy zqeybr8VCc%TR>4B-e~^lr*7|=GgA0bfS32>0=wsvQA0sTRN9K^d_2e_eoJ+iiF$af zdL0}cgHUrl#9C0k+gG8e1z2AMAT^{j#CLhg82#Iy4dRo4yI;*MN$>7!0OAGyHR+~6 z_(C_lR$ph^%FgMpF<20FMnjpfIu=+;);zQ$B?OgUziOgh_6GP^nyfp|`bCs(KGu^) zvr&Z(N$V7k0S^`kxA@~F#5*_>yQWpvwvv-^-cco zJs9THn$*$)1-MeCggu!rfJ^WrO8>WtPeZYxuR{%Q()lKU+_M6(Vf~xmsH00{lyh9teBV z(~p6}ncLhx#yUi&gUg*iTkcyVqCEp0e`Wo1r6rPVV`{$-Q%~}Rybl%5opJy3mAkvF z*mY#P)X1YkFh)1Pp=WhXL_r!mN8ug-8lm;crvr3u7Hn9r(P+%f`E4dv5f^PVkNavbbpxxt@WIB|tNyOK4cV!Q zn6)?V%^)v#nw7FtY7p&L*e7n--78T`hh@a z6KuY_&kfixG{CQ_qg)ht9+EwO9&hsfTXzR9vaoQGOVseLmG=Q;+jChFd{Zo@aJI9# zdZBibcj@FLT^n@4nqN*&@=U1n8Kp27B_J=6!50hLFoYHqlDJU~0n?F7!s?~RD~Y*f9rHnL+%fTWL{!N0K4 zHQR1;Y@M517b#V9R)x=dumBXDF`09y6OX*c%gcR5PEeZXcPkCg+M0(FNTwwE#x_@g zS`4zw&L3KF4HZF=)dM~>^?mh4l}vaiO(@bN!9%H&HC^o8DjoY(RD?)(*U|Qx7}FWs zkmhN3{cc@ubU_gpSNLfO-fACzm3wO6sQO|f#;RjfKw9R1XWIgWRlrVFb()Pb8?=^H zWH%PyNx@}>a&N~SPK@aJ*YWphxn<$g;BIdQy-i9iTH~NDe55)@?uYPoEz}0}#X||ij{8fhdnXOW zxk{b%e;NDzZ!O+L<74x74vwreHePy|iaGV|{DO_jFUw=!;uOst7Zn*&)VEc3-=3Xs zP|pAS`Nbo62SB%SU9Jf=z<11MXrfZ!({Hy40O7<||7m17A9w1`pqp|})0Jc#c;B6E z2D=v{HZaU!#sbab{3Ytg)lq@xLAt=Jt-dW&tm9Pfd};M<+E}f$7|4igYx_o0E?c3< z#b;k^wHTh3tzM%Elx6NHe-8PLl%68p&@w)S2kQ5EX)z(8*;#kyrpdkk%5O@Sz>CZO z1++|g9#?Wcdleev+4Lo<>PPLhBICKTKTLG*{OjGQzSw~bS8|%1+Ft3bERJ61>-7*d z6mf)W95>YV4YA7#(QH&!z(v*-P-3wS8%+lr_+Ml597)lwcjjKJx#Y6N9ryZV-cy6V z`Ze>=A#n(FO)~bMCP-mO7RT9`$_hcbSAC7!5kpO>hkZdx0O$nXDDFrVSv&Gn&@0Bq zIJnm}S`sxk<^v9SeM?#W6JIhopmCv{{j>ZJ@n?Z!x+(Pw2KxB7P!VZN%`uvJ-e$UH zX_git3qTct7=^W)e12mYBl?~Oq;!hu6r^3g-FEDv#vZy5U#vs;>a8MI0rFw|U-OQg zvG7Q1BUEC^d96u#OY6IiY!f$ldCRa4g--FY3Vy(=Tk808Xgc)nU3yX@eAM`b#}<%e zOc6N5G_TyNC&5jI(boO!*rpTRw3w4f{FutSrBdc7(B8G;ORVBgX8o6}RRgags1cph zh#Fx8w&@ywq;bsjZ0fTgpmgVwT- zAY9w|3Mqshw!)GQAVtKRT3j(&SBmuAo~1qEw$S-X3aGi8N32SC$L0f+Ol>sDP;vF) zDJYG?P8YlB#AsPzt%nF4n8x5n+}d3?mUVu60Jo@~uEzV#&h8N}u<8pvPy~@*cRRD~D%dKv7p7EavYd3-S6WY>kbBaK z--jxLs^m`Ztn9MP9l7-WUR!<@mYQiaA+;ZZ$ja=HSHsx9k zl-k8Ab@J3k?<9I-CODt^+fSDHzP?YrZtz9a^0^2c$r}`p_c?NfV5we&*ZLk&tU+8& z>C-^--$cQVs&wqMVYQDjeWxZI?o`7{mypYqUM^X5h0r-%N~XFvJp@z$FcCt7`ZrqUn z(Jl{rv2NAQe5a330|;Y36(G5|KX!~`0W;m9&i0?p0B*6oW{~a3z$Md=Sy^ziLv}AW zeO?PdgQ9q=*3xUZGhH|hyZ+V=X-(!)ocVM-@C!xeHd$li4zqWz9;UE%D-FU<0`euK8<1L=%_3c9DQiot zWe4-6qjHFoTVudmd_ywic)o$iA5;r5Y-PMHrK-*Y5tDDOr)p`3)O}lA1$Ef^6(8~R zTnCZvl;5qSd^xVyb|(8%aAQEtsxJAqHz#+3;gd&v|7lChDHD*?DA@e1n#_`;KV6i| zj1gc<%8{a~en`hSzOVVh)!NSW(HPWXlBnkA~C6r0LH z0eyr(x{qUW*jJEIs;8$d&IEC!W0{^42I3fJg&_TuvJ@?@kW4CX%G;sd*fYQq7s*&5 zDM(asyqdpXd)rKK({u{81ZQ%C-OC3^DOGUyppeV)-?ufvQT0YKHxm!%!`1;$Y*$Vf z>Zr>S!>SB;`3U|*&We(5F8utyBFXMgv1=coWDQEAFW#y*g zcg;T$2lUQ-q-?obj8$T2@zNm^f=9@eQH8lfD}w0N$EG5$4uI@h2Al;Y~<_q>7nVyc?w%)B1dT}q>LZVD2>dL#D>22Wtl}&g$ z0O)}{#b!RC%KsN=DU3@eRuzf3ubqlr-%n2|_%CG!avb&5^6_|)M z3$dh#Dab(xlTMGkh3p0WTm#h_hpH^?W@{kk^0Zo((p)IoISXOZN8+{*->J0Ard-y0 z^!uPAx!)sVhO`?dKpl;r;i#zpC@YduFS*W+MyoreN=SRr+JscYn}!aql%jQ&?y9!4 z6wurYsYi!evv<-$PZFb^lD)Q8@>8uz>ClP09gL8Tt5yKbWx9QexOrV=t)&El3}xKg zuG<*cvKrgbm?{_;VUf3O=YIF$AAbhV3A~oI3slStRB^Fu)09gQB8|zIsU?U0OQ10t zG!%ExxnPb%b8sv>teOZ^S4lfAUPBxUHQoRcHD5aYxbnF+B`rf_q>z%-1)`#wWLA+% zwV%;7zTb8ugH>ANVYzV4jOo6N$R7zkje{hFYL?ZdpeSI7t2du8WP5w)0!cQbG%Gb5R zMjXE2y*;#{DlH@uV8gs_d^JZ0K~qei0p_rJr%a}^Wam|&rbLEd)gK&HuSYcTHE6uX zRd~G%s7%nA(m}bPgv*45s!L>#zBtZs)YzGa7)F_m%E`;e4qm9|>Q+9(K&NZw<%?(F zI+4Yv%Yz)k$4$s&qN;Y9qJI8_X-w$x2&?=c#UZT$LMY?3>&>8RYahO{(*ZWig^`ZF z0~MN*Q=Um0-)FRN+zhj5slNQhe&Dh|H^L0>_cw9c3+w+9i)zWCvQ_75+FaJPFF^zjtgtWX+FYwo8r!uGaAy5)!Dh=NEV( zlnI~p+Evo^&dfMPuerA1=~a2dfGd@oJxh%5hO0T9;VR9$L(JNi;VuSRuxiP|>seMi zJu*F1*fuh=HDI^d8bpL)*iAB|xMZcW;+|mFu~P%5?W9Ps(S9j_ zasFy^rppbbr2%szH12UvjLlz4$Wf6erCWJn>h^vVs5^<7CN%k*a3Os!itZTTPCY)5 zS@P&^(#)ANz&qD;|IuD`vDKaaedrWLGHbp#BsKrtB-7I=>521$P&MwIeeNz8%A%iY z{0y?@$>kQM0Zs<6C(#6(={0v(3}$bg)Z}XT_^W#eq;mQGTaeG1qm1JHdXg2NO}?E_ z0ok&FK7k{gk@UUEwU-~^a`O8kqON@JzVnscHNZTp2J9ljK?>5>bbIyuBqAZN=iOeV z*3bx>Jnlov(oWwks>kauiDry_5<>z3mZJt7u*%Mc_(0Plq%fz{KGt^n@UyW>b z$>kw7@#TT;H19UC9u+%-VQxhn{8r}FpHkzSV*9Gg-hY2uBU)yc$det`SeExWDn^ge zV54aw&12Pf6u6N6Y__}d^EHVfL-x{8^N5ZulL90V=OeqAS6Gy(p4QJXwQbEM`;H** zGzq~0`-Q)DjD^w_s}o){8=}{AB5;X0X1nbKrRWW6{*^$b`SCZOyaEhZ9_9J_y}mBI z<$pfL1ggAB$CZnjvS7r&hv%7Z7yATGOyYi>9~Y4GDI^`GFOJ~col?qw6(*IA3TKjk zwkmymzrD<}T9qyTJ6e?IMC7pDzuKAC0qIr@I8w)@I|euwZ)7}Y>^qYrwls1wY&E~e zg8M)l-*cXeQO0OQqTwIQfAz`VCrkZ#ez7(ihrVj%m4JeCxsTSJePy?j4iGflg*)MW z;ssj=NJSJ{HhmTUThH9F)OD`S87Q1O(rZ!Ik(TY5=5g>s5mX}8Y9s?N0maaM1t)!= z5|KbGY9MB`l!QQn9H?9e-5qNT7{7Ae%YLp#kqV#^IR> z6FK%k5<+5Zj)SO{CG@Fbegg)Z&A@3_-4EJt^Zhw%>cd+xilo3~db{ zdr}eql31SW?iDJpZhz$K^h)d7c1iK&H1fV4Zs#8!1Ol@nie97XJ3Gg=+#S5Z1kygz zw9HzwG5yG!Jm&GORM#sScKkyR%X0Cc3e>DZFV>Lir)Gt&>6{$ZAU$uHMU#Sk0-e{6p7l0w zM@wj$38Z%99by^~@deX|$s`9It{r)Yih%{khhAqTRqE^u$Ri+Y9Kq4VPEbwBaxEz( z*epsfUWTf?h#o0vxLp>HC8$I#D56fT)HdG#Ii|S{M*&t@SKxA1s2^-Jm1k2awqEl4 z#Y+dr$~S@p)*Dd=)?ISs8naeQpD4L|`GR?6Xmkl_?N;~0PXF)1F-K0L*q#MZu7^Kr zbbIB!mXoTx4qs}By`d@=kHH%I{~Ug&C7ARlCkuD{tj(akpt!yxO~O0RXTP{H)TpSz z>C?)H&)v$or$S=&E$-Uv4gre(gscDN!XAqSM_0iYGJh2nOFOpy`Q&r2ym#tTazXK7 zdssXEU^-7}1(m&iLUWQ_qq6nE2=@T;rBiB-2rk0W-}oA#fDp zW-$kENI41NOXRVZefRj)4NfHkW!9}_4;h8jJU5S4|D?JxsFVLaTY6k&S0wr1?y;QhqZB2kZ2hGy z-0v-y6oVa8guL_L9^nnM$ux$`e@Ny#-$9^ISl7knWk=sy38JV=q3D>lI)2>oZL^HD zXgjj2B9+KF+U^cHD^I+cfA+v2U2E+Is9H4|FUn6uhg0NS6y9l+o(q1HJ*3R$;IPph zdkx-~!inh4Z|@lw^NhI!{_Hi1&~S-9xKpOm$)TZq$IVLQsuh1{sHRRG=+`niMzfnd zWe>VSyy>p-TO+5JVy}`sLHM5+yhi;wX`KDgUd8V)_PNOH&t7{qtLP3($Nat~@v0Ah zr@H28;DzxT%AgaqK;~Ys#UOk?QU#5dc(F)B5~yUEh#PG@pH?T=#}~;51G=PA_2-2*>w+k8U zSNZO48>6a03-xMm=~Z(|S!Uu;_`{`sWeBM+(2)_nN`3G}!wz#`2e>(&*TRFNk7l5c zf2;nVBVLt>mA4vHIq+Zd2zv3Les$eS`*?8po)mh8+&+G|?T(7jIG!928{oQiL$e9k zoiIvJ<{-o`eC`V5B$(?`Q^-+HcJq!293fvvmBcu!2RZSa+2aqoIF@B47&IY}8$m;M z!8yGS;R844#^3NU2WGyse1@%@(DHfpemwDH=d&T3eDN`+H1FfLy@B7~BlIp?{?0 zz6KGmS$vSVU&z+5n*v7a7GX4Dc_Gmj#8DM*elrl4#C2?J-GZY3X`@rIef|Ub+;fC>rS1Bt$7n+W1JY5 zc8*>YdQka&b}&bfD>MCtPUZ~Olo*g^RKM@{S?-HWq!{5cVnwLEmqC})@$~L%&D2;M zXLB>;a*adh@>q!92|p>;#@H@yZFSdQ`}Y41D1d_NGJ}GKAMNZ*NC#EYT0;W;tOZ2h zk_l}>eT9XNi#DG;HT0e>8jOY#8^teF^+u%(Y|SmF+?mUQVO7tc*L)+Xm?xxh1`P?vYqtf=ht zlmjxM;Tf;?6CIG8OK34ltfVtaGS3vyNq8L+ErzbIpF?cffvC2_t*|PGnr>{0DY{Jq zk)UvT#dSrRvWC_`YkFqx@Q|k@^ED{ax)+rhW}iPP^2{BG3wmw5SpFasjA;;bg2aC% z0f2ur1Jlh~1-f2DNxLL|a9yykWH zv*OvZw+lxg`RAe+?W^9)2E|+Kr%#`w#E=GKaH(ibq+k zmBC2=hWFodL)RBA5Wn)lkwHsEb*qMnw6%FHaD|$~2^Q0t zk4jAZ8c5g!#Wz~l0Z*xQQPaz{R2XlIN_>{!k$@%esBU|ExqcCH@7eF3!vzhC;)b!A zPR;@IP{iDO(LB}ttGGiZx39e`N#&=`u898+7r?Kgc4uBsM`6TNnSUDUA@}W}w?aqH z(Y6|5^_ONIqV*Tmq0e_5F){1u)o;9W*7$lem!sVEp+JR-zy0G*G6+N&^Z3g z{{F(B5kbELV%L1PCpAs5_NU4Zs$D&S>P6zZrnNm!Rmu!eoEy7J%m8B<%}`ZWj8(jL z$y6gc5?rT@yjE@9o9-QOa{?Kyiz((81H4H1jZzR&DBAFTV>6_Ut zi~anPY8MOY1W-#!lRS8Mo##U-K}G4o9$H*V{qgWnj)(F$)4%4Jb6;&5wU^#g^^Tv| zTPXirjk6t;S~;Cwm(tKYs%&YNr3$(^q4MVUYfg$z2xRA%>RQ-TY;|g{y6S+?d~zEV zSgbdx(_OZ4b=*EMMhpyk#NG|v)8JMsLj(E)Fb9Ba7o9f^SoHg;0y^?g6`+fb0m^-* z$G#_xgcCv4-mp8G#DTBbjJMeIPbX=?c;HNLzVf?I9pP>x9wtH&%j<$E$&PF1Zh7b| zk&|hA+Ve4#qhZu7nPZ=iY>0bah^Jncp&mEo(2?T` z?taQWk(^1^kAIw%ltCBzZoix_bbpi4*!wL}_olwNMRT|6TxtxMuumg7JC3f0iI6m$3vu7ek$_ zZ1`t?9rftshMA9RPLOYb)d%hkgujQv6DaqcJ?^?4$lOt33^JtLh>gIP&p37$N-LI+d>XNNGX*rN<#;6K?f5T<#QT&<)RjJjF$WqIyHM;GvpEO0bFYO5gjQAZrItv$ToO*eE`)9H9O^h{1DhZ-+RuOWA z?juc*Go%ZmxY6J#vgSH4Ht>teGl|3&WR->x0i^IC=>Osxlo~XfEJ1b@X%Gw9pneKP z3WZn=W-!&(=m=8DNpL* zk&Qs=aO1CL1-L;d6Zl6CQONT6g%}Ob?K)td<1#c9f5q1NPB0~z?%zDC8);hdKeOMU zh9p}4Uu3;`JQUvd2RxEgijb6ji%N*G?=eEMWy>-o46=nmvS&@!v5uXrgOPnFN>XFb zz9suuCMNs#Tz!7u=lSFLORrZmcRBZ*_j#Xl&$%=6zb@QDhWzdS5nOw~th0uX8J|P0 zOtq>x%se9N<7^don849-%1}`s4j{@H9JbWFCtNaAR>6}M*WdA=j#YehKj<9ObOlNm zS}EiNN8LmvNoo2{?ym5ml*Nu50Yl%S@6HEABk#5^+dn+A;5mWo42t>RW))R&%JistBu}%;xe>pE%36i_bnMkREd>R z*~PBnW~@34#$bJa?G?2#RWrq!#wqANHT<&Z@#X%bZLQ7IwJA?;TDJr8Kje4%&YjC) zn*NrfH6TSxxp_y6TKdnkP4^BuGU-3^WOswD2VCCeWM%ESddN^;em!#sWDbh4yAAhp z<_l@$JeL=(jcQ>U3P=4Uyoe4`JVwU}o211H(d$MZ96K<4FJTGnwqsMgoxw6QG!By?%k8dWZim0a z3*v4F5(S2Xm2N{@{XGw}tBooV>edKTX7{$HP_!}zTPhM1bx)&Uuni{{n%>C-AL%T@ zUWGtjj>O_@UlF^mocDwwdG&g)i^PPfuDhB10%EFrU(|3(;MBUn)It9-M?e_={(HY z?pAT*yzfJuE;VYMP(d>b8$>xc;3H*JMXR1e+do6mje^8D^Ccn#Dp%#Q@EF-a2C*S+ zCl6O-d{KJ&KF(wjDcSoJu6d_ebC;K${^pF5Q6xmfSu%YScVs+Dw)Or;l0dXJ+&Ce| zZ#NiiP>e0ePWD7?lfDZ&u5HV25QRX*g)TBX#A8>N%Ij|$=3!SyFxUc7oVRQ$aofPH z{*61hp*YqXA=9FTj|dBmTTE9XED6ao=u zQcz~JJf<-gxowq*e}k{|-ru?@x`Z#oyXa-D9xyMvkj1te{c&PpZTgj&i5Ad>8><_+ zF0%>s)?!y{gO9{!ckhM?QeFYH_uPG>szL#SvZF%-D!oS=v-)<& zVXVSx3hn7L+CeD8G0FP!y?8*x#TXeBVwYYC5+5K=xYs5RllN(cs!1S_D&yhjxZV`Ix zyVYWzzClf2?`)CPk3_e!Q}A*ZB&+M$l$>crON5_sm5uhyL2bB+eiAPaG|8wlz85!$ zuD3WgCS{T+7?ems%b3$Q@ER%Bw$@yi#4I<+hM=d+Gdl%v(k5;WV5s#AP=T73psNLg zx5_|`TRScgy}uswK0?4bmZV#KWIHvv{{B1x8-XssV2iWIUo5k67&X1#>=!}06+d6} z#OV8xLm)O{;0%Tjwx)VH2&zK)>(eansQmHk>J!zi0>kjc#?!u*=YP zRXh%dV>hP{&6G&jXv8;UZNG3$%ylrQ|F~+rD!;IE4QNwEWu;WPM1r%@o^>s#yZE3t z0`}F1H}pv@=0};@MIWQx;F&m_1Unq74|R1Ka(lSij-wB88!EC~^enY)Sb4R68>tJ_ zpAs?6a6@{s0SlC$5dx7f?!dv5_Z3&)Z+kiB>CB0eAvW4@R3XUvEqsHog*puOSoInUX>tt9T;ajzT^02U^q=YtkU(TF9&u>Xon9<0K5@0M& z+8;f0=`iBG8@%9n#aQ<2 zDom;A8QKk1i{$OFNQU_mWIf2CNkKl-ga<^(&^8zc#syTgy`iz6|3U~5Oq9i9v?9N# ztS#@9b=D?0_JCr8I(h{Eh?`Fez9EGaD#uDAi8X*nKL&{T6*m(?MkU}|2gbSh8OIZH zBzc&Ne`7?uI?}U>mJrMRG30{SC~6S3xiwscp$dj057IQ2BrtY%{N{6dSZ#RpOI`!) z+IQTKynd*N}VWu3s_y7`vB|$@OBX&;wn!`tiW`0swxDphS$E{;xS%Ud zD%4mH{>t7Q_i~Wi@V!b%+0-8)=&lyr*i~`4kU5pN*E;kV9uFl>?$k|F18Wc@&aody zlLJF3y%tM}lMXI6a22q2EsYlS6C5{vKs=A&zgS;bVu@&Oe!~3;=M=(p7>rqc2OGZ0 z>i2AKFSm4t3~Wa{47&;~5oi-a$SS(YIK&QZBlJ|{2uz3;1vmIB%jA7iQR~;m4KY`Q zhzpq2m#W#>iX+<;x+Anj$(~xH>6+zlzqw)Tz(6+cIPVs>e%+$ggKA)%tH~0n(N;PM;u?sY0$3d)~>;bT{CnaE5RW17D_n*#D7i~Mtj~fD6=&AihD0uslNIN*9j%I+AZH3)O2&W_kcLTo^6o>4wV$a(u135 zKM67Uf9)#H2tc11Hp6fscxT{L8U+A*`6j}Yc3|Oq2QH}yOYyQ3#{eZDQ>7y@$Yk#oX3vxr0m;BFuk+@ zjjq`l4P*9ynf>VL*~o3+7MI3(Bc9d1H>j+r(6GfHe`CONkNwTF&*r$x21>p7R5(s^ zXbd$S4b`f5BF*YutPBt*YR_sDnF?^+>KWOP`uK75S zL>;g4vhnL)pp?UjC#DyeIt*xEJC4n#UcUrHiY9R~``0|5L-n7OXDEglHzEv;DscSncK4w*`Se%*7a zkcvT%&&f#MWbycpOHQrWRS&W5ff2p>; zC)*Mv5dVwqxFq9Ne}Z+%X5XSA9J^t)=&yj?Qs}_OX@(x#lVmW(Ps?}bH|NDM{SQU51ZM8Sf+ur-Eq6_wq z`VJnr(iguU0?1Ut|4iG>VT47YbHom%NZR@I38#xTf)g_FW<3b0FM#^Tkbj zjbh&6Un}%yaA>l(`tm9>xyng-GFJ`#CF(BiK-CQ|bnbmF`p+y*Rf9_G7{VP4E zR)QJVNHp6!?$v#$%J9hz8lx8~j;+y_HmoQX85No`_I+tf^Y$$!R6VWgn`@WcxNk`$ z%pb}hR}Wp6Z1K969fl6A{cGK)AMCED16MO%iW1A1^zk)UeIFF{H>*x3BFn2Vpogfnr209 z#hXLQOI*g@T;!Kk6Ejo?mRx8EBs6z9(5{lIr|(s!k5VjGTUGNrQA}P5``+-geLNn1 zRHnBtQ6+MbnXi-1iD^9?dRfLp^fYU0lJ_#N3rz%-E-MI*U=T!0AAVfxKmQ#t%+AZZ z8vk)DwZ&o)`VL&ce@*2QoKj&q73d;iFS^gYKTnEE`;G5=uxW*Qyt>^gtwQ6*&~^G< z<(`YGJ|Fi!|FdIXIRWk!Cbf#{$?+D_uJ~w7rochO{GJVJ$yN1;5chZE;nw$Q{8C^h z>M!B(mWkuk*=jABWl9gAHfliEhI^i!I!IVEbV~+fcU!XR<|1>_p2;DQq!1fInufLa z5JUq$LJt7Mh!sSD&lep4_s$T>SQlx`@6$Gvck#;^@>vl^6%#l;ty6Ca?KG;OKB#P* z<{xY~o+=FNTcXO;aDLc7vG%Xy=XV%Y282-`!h%9#j&uAWk zm*HutC!43u@|~H7LfJg3W!F&?P?Zed;Q4eUs_!FS=q-v^FnMv^Qc7b^9ZT2J6qij2cKr^W!SK(JxX9s*`p$t88A1K6_-cNo zG01XG66HJ9Ep?I((;*y>*L9OsEY5Edg#+F#;y`!)W)#a7gL2T53}R5gA}l1 zPR8`jf+UJpCA8(&EPRgQeJU4dVF;J%y4Vo9kePQ-2V4<5e8lM@n!%$4ti(Ywt%D@G zs(ShN+l$QVm$Mc5%DN{$Gdo>>?I^ePaKVe8_r3?uo|&G{lYcviu5J$jF+X7beeUc? zc?&jVVXcKtTYQ@K$tP;{Sg9Xr9J^x1Cta9mK+dn5FSg;DdJmqOVH#L$Cay_l34$0v zWqD5>SVC+J@>K_;+~U-=Lg}@;E`t#q9%*uF+vNZoIY8e%p0OgT-R>+Kr#o`qAvL_O zKj&)p2UWvWGQHp^0^p^l>tWl`NFD~I7II39@X1>w&Ky<# zMSP_{CoC02X>%ng>f3CTnCY~uZB~hPwuPyd%cGkC%!N;|IC*lb<`=M4gc zEFbx0|F81PVIb*2kZEJKzV1n|eZBncjBh18_vQ;CLy$nmZzD1+eBRMZr1!vp*EtO6 zBZ+Lo8G#Kx1shENu{h!pO(bU&e(kNH1$bhtU7@)FTN)L@adK%S74frxnY2|&fLZ_VW$l&z)%{%=YuRo`XHJ{u?dT8Fe?|S>dObZSW z_|7ko|9IdUDA)*ZMR%G!}BCRH}yVW5v67EU$^V4=-)YTcO|u= zj<#-fRkd*mF2${tRwrHD%V#7Be*i2ZSdjRV z_tk5(=f^V%+J*ON$EsDl6zuY7!*}|cJ{gcmw6ybd1D#T)+r-xUx8I$?pAf29Anwaw zHcub3ZDMMf;&K?Q^<{<`G5^9BpNB0?K3$2KdLyJmF686~4RaCxOISRxLoC1augCZI z3eM62XS1&B|GEQ`L!7!Jq+a(NEl|3>nWMuQ` z5={3IY?Dvx$8(N*JUQ%A7LkYU>2p+P>^zcC(Mcz7cf}002_{RRoKYLW=aMumsb1qM&Z(K-)0_MvT-glttpkX z;_#@Q#-nM|a?}pk&m2rR0GH)_mAY9Ou~(Nxh9`sgFTN=KZTC!P4gq*T)?=MB_oPxN z*HyqiRV>?-5md6FvmG4eQ-(sWYE*O?93ROQ#32C=+}VK5y>F5;@R)Meyg%9s9j?=K zgI|Wx#=gf>GV`tM_C17EL5KYUfctdsxOKvm+N$|)34cF!O40U*!u~R%I{_}0UWKyu z;w1EIG5`5^2u4_Gd34(VRj9#r%UI>|PVA9|NS8cEwvK8GU#T2Y_XcXxSx9x}y^8E! zz(oAqLsKYGn*Jj2BMYz}VapKe zW>pwZf7?{?BkF!@_KD-TunUI0>GlqCsbSLWy_wf5X2dxT2HtE~b3EqBS+~3p6sSN> zo&MTtmv&bPUB<_gbIJ*|zcvJtZDBnX(=&);BI~y+950xEFxVYpVO5b~8|9`W0b#Nn zIi;|l9dFj2a<~|a40+f?Ag^+h>lvYb2(lvwjlF$T6yT)xv%DadreB)&4;gq z2TlJ|EY>shmoA2d-kF6u{ULeu%Cg#G@X2K%fqCT^&;FAeX!aaY0X1CxdS$*atV?GsxN}*6x*bZ&~U6^oU*jCq-=XYUMsW>ece(H{A)#)?-7Nih= z&JNuB(og0Oh+4off1b}K#m89?cb&%~p3abp+?V!nm7jd~wH9M%Z!QuXb(!PwMNjp; zHN8%n{&dTegHu+_2KP`fj)LeSM0lZ#)PVT_1S8UapI#Oh;od zd0JE1AMUZGDZ?nq%7V?6`!V$N2DkyOHc=Es53H1UO;(LpU_cDfTK4= z+ALp8Hx>Kae#9=+85?xLA9Q6g2{pdxpzU8_Ul(3&1||4&U00Y3sQWoEGRQPlL@h?M z>xx9`yX8k5DKDAl94w>ER(_rd)Mh5RXij1*y-agrbiL7;F-MKxr#AC6Me{=9)ZW;N z(85eX*AQ#^(>I$^KF4#Su%wK}qKPGoibf60bYiEGxnlDEjf74TE!H5)!f2`fQ`PBs z#YTO-YWUo-5;mL6qYzt3rl*cRSTF;V~ z(rA#bx%hl1fW2%e>`p4Kk+wQG>JG<&6nc&i(|{!FYEsm(G8y%nQ9^thRb2c<6c_qD zGy+4GZ8HQ>Lj1=gyzb&lsv-qjP4>R_2N<`ip~&6SI9ITOA~k3K7;KG7dRMl6IoDxr zXFEajN^1<7qU2NgGeFjUk^>#un#ejbX{Y6Nm%jvvl zYA{t@zva4EoYZ-XZ%uzPA1*QnV<-p*{J3at*TsTuc7nl#{MLt(&Q>-Kax}%wlgEo$ zggY2YX3cB;!7wB>wK{taRmm=s^?Iuq^#V=*grz$pqw->12jNJT?Y>>1g|GD8btR7-Teyq#)AP9h(m3|W3>JUGJ)$7)mVQuJ z_&XaBbawvZD`*c1(KrbT1M=0=C8N$KSEWTE{yVoFbpAG7D%-izGcJkg5BPwY+Maub z{#d>gu(|qX8guX(!f+0V`uAhun)#EW9jsofNBLtSxyKdgO9mc@^2Tc+>tOuNtK>@-_wwws37k8pEJeZG zdi6VDfdTQv5y|*+a*g5Tq>Byjv+_gx*4CC!+EX3h&G1noh@XE=H?qle7>q|iNWZTz z@NnBR62knAi5#VjFyILcyV2JMRU?7O=c-NIY+l4iYut6ffF1IC`N{VuZ};EAL{nw) zFPje4tTDYj>UV&i+YmnufLla9R~+BCbkZ(EdvuawG+lLYW^0qYq*m3#2V{%o^vilYVH;Un)b(X?5jp|q0Wa-0(EDV9BqToZnrp8K+>o+(w)*Ho0uesT)-1@PG-Omy8scE#DvN0v1E(A)u~zP}11HouZ<=>|nQ6JFFHkkmM3lLAu1l$I@1FzV zzzthQ3m0n#<}v&1xv0}|tE2plnIc&Y|8XXb<-+@H^>Y3A9VA27&~9u~Wn}Ktmz2y4 z6RO;Qxl}Dt&-3<21*nE6x5L9ML9T{Cn*G7~KiW+p`~8;f`R3h!`EEj@e;sXPPP+3~ z1@^XvM<4)lkA%-ud-p_Drt%?izGTfC z;guN6FL6w6EL}TW_;o)J7|e>J3|e`{8borB6@K%Uda+()j^yEDHW8ik^?0it?_rVk z)b^JO)%Ok6V5<#r3#XpGx30RGz)kuiL?luhBH%OI@~&i2$dQ}q;|W6{pq#NFi*zRT zsL5TG4I>ql(^Pc~q$^@hg~lKzJ|raSn5%3`UZFFt>6Yk?55M?O8_cRKGt>jkcsVYE zC){HdWg9-aY)B^2-D`@j9rSC{BIO^yh#5Tez<8ZQLEA4j&>p3FT;-E~w7n1R5^bn0 zDjO4VC+j5$3g+D-=`#te>HDNXswGMUnNwAx*5$XBtW|0V-20-b^M5tC#C*K}q(?av zt29t|RjG5e9zFFDvzXvVg)5+>G`LsrY=*mJT{XR`jt8Wwe@h8umr%q0UQMjQ1%=ThP*>WR_Ih>n=Ou zj+PI&*ML0EMR?R7{RV|tVg}2}dq$e4qe(eET4#cMxa{u`m{$xw-kxrG-P6&bVMD*( zfPTZH^HxBb`H7t#D<@dR)1tAT7N9-|RQ9Gy5y{mDM8CX77kxN0!K(`7y3U<9Cey*` ziFWyK9=`n@E^^N!%~V_$pg&0929=NXulRZU$$tcnK*{OvrCcn*I}krdT1avB)ec5G z7Xg9E8C?&_NzSW&QQdM6|L=R+W7p$q*twm6b4^gE6F)iHk2wZb=-Upb3`1UImbb*t zfkexW$bvmsF&SmuZ;A{99}pBks5wO%U7wDBUCwFrW%8Ye>K}_Kffe7hP0b-MlI8b5 z_-2&CeVYGbVK%FNT$8IJibcmKgA)#>mhN=CF1oEZRMlgRb#P8~~UvF=9uf5wy^yh^JO>(_lhlsljwM7%B=}GE7x+7G5&nlue z;zx>99&@tY5!Neai|y9sVqA6}S`r&rxY8Z%!6V{5e6Kg1WV6R{&knx%RkrQ&JeWy@ zu@dY00?4>vK=kVxGjP$La%&H+o1C;c2PZkP{Ayk9{tyYO$tW@!1rfbumqGQM}YqLWfe=tcTEZpyYk&o>NhpDqSI^M;-={75=HD^y`J?o zNYh@^5DJ%uGPqlFf%9o_@C^lu2grwI<-29SsLsaGuL$L6=G3YEgP+@QteVeV$?C*_ z-wf1Oon{$GQi7UbDfU^_6#+GBqMo-?y(1kKRwc=Q47=TxO>;=ibzn=f99*qP?9ua) zHKs6lTi)EFMAE!VZZ#rt0<37SY!zwI*JFP24*UA^sH>rQy_4xwwncAVFx`gu96K;X zaLLq#pzS{mD|96_WmJbry<0w5ynm4mB}iPwc?aVqv&>yy92e9BY;Sn0IL$}m4AO}k zbw^gHd)j&v8z0HY>u8QL7bAq;P8+%*%Nu0aHqM_qCj1+Cg@IAhB&d&M{W{dca?u;H zQP6P1=4MiNa;4V`bJfTIc9}bkJamcma}mu_Avbb|tC~T+b1Xsv+zH-sdYn}OUQI$p zJn!i{+Pfhu4eU59K>=n)9eb^R1ol^$nMv|Q9>!|an?&8uz=3}V(}w+x+^)OU|Mf;G z1KT=|2~|cy!@OZt0bw*@%kDy?Fz`bz{|j~<&w}06?ewrh9_spc z%iJ$V)2aPMgV6-@MR2L;A2OEkkpMGDYyFbMBKqv;;1h{QllFYgzLOp9(9>a>W#hGl zgGM;@l}z6eC?^~CyoHx5GX=0OJD0oEWMPykJ3F3$+b7X#$Ale(NXz{fv<7YHQLBbE zTxOn8cVk{BfwqQkGL?qfCHpOI5Ra5vXQq;ADetlF$T$oR1B%yZECJ@w^u?4L=7YaSKa^Wo4Fr%w5IvID!*f>qD6q^9@WN5)RF zc4fg;=a+UGgA&2UyDvd9$EG_C#FBNQ^W{pqUd!Tf*CaWf?)M*?VZ<9w?aoFo*<_N# zU`ZLcJziy%fs0g-u6ew{O7R1}88Qn}h}t?EicfFf>(s9s1sYs`ME0(f0naH%RCHqFT3pH%S6r0mJ^^WW3`c)(yD87ksWU`O&oo`uibfr;;Qs- zGpB4&Q$zpNwTcDgPEuWZ{v^#uh`!x8KR2_%-ZGbJXSOl=wsLCIm#{%`Sq<)dQjs>e zo6%=-ct)eHMsW}|I#ywpoKWetf^Vg(I=}|LTo5I#AV*Hgx^Qyg2oTK{*(E!FVz$nuQ0=^6?*gO9 zZ1^4dVd~P?3G6dP6Ge&*@yT5P;x@b&X!{E+dyKZB)K>j%aI6MTPISrA`?GM#Jny^A zu&Z%cA-mapU&ME>U9arlN2=ua_#3J!ay;aoSWG@q`09E^3r_KqQ2TJd+2r$)96%vu zQZd_#U`@E_+>Mb3r^d<$vOt^=K5U6HtFdS8w3+T-e5!GOv6-nJFQMPsuOq!O_r>t> z)9DYrCw)uz-fVaC5rz*}w>Fw-^+smK&(ix5OExl-ir$^4(qBAukIRnWaZv^n;9C6e zg=sk010?KzhoFzfJ;D^BIGk34uQXXw{oY2C^1Y3;+jK;?$|;c_-fN4uo;nX?4Qx#x zxA4B(@CnB^Oq_#{5G)sYbVo>(b2+KI**OAnjnxz1(jGO{1ZygvJ9^SBJs^OZ6uw_0DygXw08plCOSPy3o z)aVcJh!BX;Bcuw*pg&7Keu0X1d_W1U!;}NuIZfK$VlR|IffL*Bkf!ZCdG{oIzhNv7 zAJv%mqJ@8f=QR6cj&fN!X4OvZ%xsFWq*2eDI6zy<$3GNk4@rzZRhjLR&T<%%hgwDv zcAAav5^IRLC3){#+5#|mNS4Dr!q{&4mh;kjS>12^_wZ?-_uwS?Fm-F;-?xbTh4%?l zr?x}e)wgldap=r56@8}xi+{9O;_V63Rb5Pv{?jKI6LtjqONV}sF;!T6;+LKMAuTMV z+GOQy*?c8A26CGFMFmMo+Z(I=gkh=rlFokTh2}#C0U0+Ht1iJ#I*JR`qPGyfx8@|q zgEnEpNjSk_{-Qys-iG;9&-RPQ#>TbxFq2LRddhPTb>d8}8Vsu1d6X1^LxN zS~;~pHf)0@#~Z*u3-#3FArCUJ%=L#b0j+Ihec84C1YMa4It74qkSd4DcW<<1ig^Sw zq?|56TX{K{UwU2rsX4MOmFyXbmjoXH+G5mP%wuhB?eSt!6AAarTKN9bE7_A4YWAVw zY`Y-${_0CH4;8a-&mHj0Jp$z;WWGKBh!!MG*FL}g_X(Tg6wB>-uchAB=hMtf>lRO^Cc>cma_Z<@3et8Gh!X%DXK#c@;vD28MFe}}(c z%ma0$N1UXgt!pN;t7O6IR{!_4dsYZU#&;YGVpw;C<{i*;mb0oUzJIfp-hi5Y#Z4sr zyVBx|{kno2Pu@2ea{Kq6Rc~-dH=)+WSk3`pa~b;ZvqJ&3z_l(5-?6wOI_M0hAyK6r zw6&&2RIqhcx9Hawp8C;^Wsz5b$ntzLsVTew)pX9 z*_kK}eX-=pe=BiTU87E{%d?(7FlwtOCFj*GkT zT7S%KhHCRx#(?F{jRM)avR^p~WG8kRTS=NeqHMKgSHG{@1-k4WaG>{}#!j|~-hrB4 z{2t#*r?27LekbLRN`T1OvG@0*#k=@x3c8R+jcc?aSoY;XC@TBJkJ ztyYW1x+6I#k&HRb?N%Ca-L%yq_tC?q-PTZ0z>1%jkipG8CPb|*dN{TeC8p%way<1bc+gyk2-4@*e!P^n!T7VD~8v1Nb z>bKrVPI$F!XBTD_2v^*M)KeLGG8Q6P3z41>+PEl8C7cZ|ba?issPmQ%Y{_yHf1CF8vBq>tbZL!E~U!}NeM zjOwI)n!bO?H((vpTo3gME5AA6mdl^Eu0 zO{i$n53r}euC-%PcPv4CXo(tf-D2@B?uZoX0jj86D;0(*|Ji{sY~UP0A#~9A`ih4b z{-vKUw^l~or^?>MSyf#hSrU0cgl`o3G^ZhI5h$MUe=BB-^`QbMC{}kA=(5l@t1=ATt-`~HGW%#^X@zT`t@gi2?w2cDc_)a~Zudjc(gLzTY2?W_ykA)5mgM|zod5UmLGh!Bw$ z@XnWD71nxZfT+bd;XTv6B-kyx9#j4Y@s9@;CUu=XiYQat;uCZs9~V zw8RLxZq$HW(Z)6DjcoJkjSR$>JP=VjlS64LQsv2vS9>41cR{E1-r8p&7Y9WNkF3bk z5hXXP(oCcZBHC`c__ngQxtZ~@7M*bWL@@8=b9ECWka?tJ9D3{rE)a~To9roehLXZj zK$-1VGUT`g{+!%a+C5>&oV}}waO(ea-)weS$&2Cvcq{Ya_emS#uEoMKW4Ms@kQ@id@OQy%IZWEd6N+Gy~u)}GAj+dQFn znO05DTUriwnK1LE@%`=OvU3-n+gWE|HKrVSkr_5HOSSuB$|=4J@6j5gM*Bu(_osTr z+K1zctuEs{k0h9cQ&%mjeuEe7?v{fL&tMa4H8mxitX_S>s;AQKt!dca>^Y^E=>Z9Y z;L^Hr(M8xf72v6$XJ_zJK$cTLHdyAgO3J5grI(zFX@h|}+E16gQuO){3AJ51?sAVL zhm2j9q0SpCsIfy_slWwBq%W)I>xwU5p2V*>>4$z&Hc(HlhaJlb5>zc=ggW9JNyyL=6s_YKh7->fTaT$P#+oxTZ17}e2_ zTzYEozgmD*cZmPL7Kda{DX3X~Ln3DzP5`vEd^q#}97DgPYTVQ<3E`GI*JpNK{P{F@ zb+5W1o9}pt=2o+f6I*ceseEnm_?R2vuu@dma#HEtGBo58^-!NiVpT!lRVwEG6qDK_ zNv;y#1p%Q4`17|8b>;P2kIN%inXKGPB{%JzO`4xN`gI8uGk!b`If6&{+-YTVY*{i< zDqw_gT!q@<*1B*wY4Ceip+6XU1y#;$Blb>)Odx7(caDsA>wSuyV1phjAt^QEsxB9R z_OCs}jIx7d&e(Jxr^)ITcAc@ri<<8fC_A4dtn?n;IeMXDd{}({@M8{j_GfVoL?MK zvt0R1VYSxH+Vz>$_|S(yD{+_{8_)6Mes7iL}H5p_vcFQw(~nv#Rp6<8skUPBJ?G9{)o*p zVSRULZw+R0y)2gQ3f zi0L+5obJfLO#qvzXH4yys{I;sTGgl3Rwtbw7ospVYsW6-tJ67O_A^%XGT*CEOO1G# z{644IWx*;^;x+KyZS}S~qoszSTC?RRL$u2-Bf_BQLTHo*Dc8!tkNG+qns7Dmh zpV9$K)54_%ZZbh2Lu*Y1#x!2FXWH){4laQzrupM?$)NCy{E#>A#GKk>Mhkh39 znSC{hu^pdF$#)nQ?smwmw>o9EV-&r1s4{`M8vR368v(Ih>Gl1a(@YYvPU0^qNNmO( z^@`XHBlY2GKFOXBpp9n^Vroq`3o;oYLo`6c-GtxpEOR% zPCM3SGKmR@4aKfd$nNYe-s)q$ls(rH*@5~pz5c9~41%|eB)pD8Cjs&yi<3@3XBq&; zE1wHoLPP~PiSZlzI{l#H{Mr+fU)}amb3?)oIr+9ZwnpfDTe6gVAM@G?11Y8`VYq^ui@AX4~Px<*`uphppD5AIZly6MB+cS=0i8jO{bS4n3NqH z#ts)y;xjsF$t}A%x<`;)cNoK(t!TFzY%C0qb8G=z<2bkVCv$|74J>)>}~zI*p6 zT_SgRnIZop5%t3l`L@9#=c7}Mv<9pE^KI!;^6BhS7J)Epx9cVtyf%|R&(;mizKUQJ zd8u3JO`f82%PU;Slvn#?Ojz%5?&SwAbo1%g2t7!jO#@c$6E4%z+FE(iPag2%(@!{w zGj|zw{cgjq*;Qk2?81a%YIh^E;>IrX(3Q~X{>xXcUSiI%O%Z2`I@bU5x_kCj8uZQI z<;B8cjkE9rgbD9iUgx=yM|aAN3nXEM9s`ig4Dup2)c*B6?=Sj^VP=yb3Oa7p#6dM{ z`x&>?d2ujJ3&2H<#pxHa;ct?9e!uSc1IFxkMH7iuZ_31V!o;$Nod=h}{M z&3+DL9So{wO5D5BTlj@+`fX9~g?qYwvY~@4<0kw?R2x^hD|g{igq8dQ?{o6JUvbAJ zj!!`1gXTL!uXE);pY(9DsYyz}c<9fqVucY`o4*1R?5hgGh(<%k@D8k(oWoikav~tH20qfvABVFoOezhkoA78G>VKK58RmPIEuc-t1$_Y@2-y7?*;O zSF4(rjoGUeudBxEQZ(aJV;u=yYj-tXu+plMpYh~zNWq{dC6r)V_iEM|V^{RzDzfuT z7916oyM$d!G3oOqzDpGKZ@vrF6RSh`c80HK&-GLBa>;(ydD*J;lF2_kCZ*%MTxp zNT_E8@^Lc3hs`#icDdJ&BEHN%;I120tyPO2_Y!|E6<4{3mq~-Bj?V@pE3)5BCJcw=RDOLztteK<<=4OCj$OVgWXjDhM*95}c0lFZ?t-<^s}G(m zyb|9MQ71|;MQH*d>bN)hB<9;L0ZV@f(s<=XWs}<#HCqRr?X8xu;x#^jLybb(-hDP(NNSs&M;`@d7iGRmM5|ZG_%!c{=n5fe{PpX z%+1BeU-!~!ZM~;B>fwDPt@%jk&;?M0a|UvH&m?yfXl#2fk+Mvi@Ow1raxKZFm?b}$ z(MicUlnqN=s=uFb`!Tp{_ID3L4<<`kpEd8(4gY$vIHE4Dv@b&b4xYseq z8EtY`Q2PV;wLi>PhwJa5J~a`or(T}(F@62&G^~>&Sq@2|K~c&q8TSPRX{`=Yhv?g) zu_^atq@ok=ma&Xat%B$kg_~{_-j?VSUN=-9d?dDg_=sl0#Odjzbnn~iJ4XWSpN)NY zP|aV5H0ctj>ai+&kxy;y4N8Up+sh*){2(oh|5mjWC}eBpEAM)6?h>)N?fTRq!lYs8 z4dc>ZZJ$X)+&6+tnZK8<$kQa!~fY8Sh#g2 zeAg%AON&Sil5o|Txbx)&_dQ71&EdVMXz*@^8X*;3@LZZ)p2+CZN+`74X^F4jfbB3aql#6j7`K@_q# z6^>2j$vi4@>>Y;?vRAUQE7^x*CY!{u$+72sAK%~aj(_fd_rKd8dOXhgocHHFUVA*> z{%LrCkUcs2qnltN{o9EXx;?lPgi)_A) zxXm}2@g}bcsJ6GK6dW*C+^*VBBeV)gxj$|Lq{k|pihIX^TA$Zp^Bub^VdSGFQoekJ z$-{ZsH>1{PXp@9XWjNBahPTf910m~w+Sdwo`f5J1+$v6D9Ea2zwi1it(;SQh0d?bj*lh<;((gU{IWH{l`l&f!_Ub%C#^OhF3A`v zq}^(!c}E_pf6G;N3P$n<$y{TAkUb2;qV7F!c5(;J(2x@mA(ez6v@M9z8LU<{cXx?6JkpJ3qJ9K zP=fY$jg3l{QbZ`7@be#c>>WdmfmPEx^TN_Tc_%2x)+;%OGq`bb<^{*d>P`nmaC6KZ zm!*)ubd#Z=p~qWLzp+BE^>!+UCS2b1AJr9)(ymy6ZI99dpRo-dH~kW0A=^)A@pV&qUVY#GQsNn^yu9LcQmw%rW+zF6VotwdyHC0jK-@2T9>C`Ki1V`#i;HyO zojb4f{Sx=lF8k%NE~k?omLqC6n3ps-IQS-q(c>PYEwCFAL7`M?1OEM@t4zRp{WP{( z4h)9`pk{ucq3lbk0(UTe5*X)v!>$ZrfuIJ(vPB|JtLqpPsn* zFNl+pk{-XMWR~r8s%A!hJk&Ti-C2{8E)Y4qu*b>~f9>J%Be|t_Qz-U;={K>}^=SBrhM+ zqV; z=dt6jLAcO%^tI&6^+f~RxhK2y_6wgz93FVqHE4i!B!IIJZfqmI&^t%Y&%SzWmoM84 zJkX(KqedZN!pf+x2IQW;0tFLzNwAh({Df1JF;9zXeqw@FaJ<&3rYg;tL)ChM);h2c z$CiJO8w!a3g;#%}Zg{cnb27Yovw;nd4S*|WNv}g7Poao35JVJqGZ1LRBNrDJ6Ni5u zp1Z%#OV0F4#%g1$?xVG_oBd!(mVW2=iEP?07~`t;q`*mV2`hJA;TGoTJ;%CBS8KCk z?8(Aq(vRmv7PEavUVee6c{v7cUAgkE>(-%?xDLB}I51&fY)pS^h}X)B*BSt3%64NL z2|4{>Px;{htH!UV8hbazUT#dASs^3sihhq^#2mB4b`A1vq<8c(eq>8FGPm?|_=EI9 zo-(#R5>x%N-)H-WH$}jKrtJa?)s+UN67&5sj$%_jQl^Kmm7U{gNFH(6@A`;HzveK= z?p(1xUJEwtWnGN19$(<%w>-NFa-E~~9K1pV-o^4g`lw8}wkXD?_u42TcFf;cXD!ICGxE7+ zi21T=zRz_ks*;MaRX+!DlIY-T6o*g^B<~#KU)6{ZyW?l;qqsOXiRhfOH9(jwe^URvH z$NZ2gfJ#!FD6i2`vB5b6g6rA3c)zeHEqr+~kfTC)`E#ma2cvz7fno?Xoz#>)jlcIZ zs`Z6BvXI!aE(*oIZ^1gJ;q84yU~5mwo@fB_J!fk9rxn&DTje?7PHHQrhgcJ}R2;oY z>fjN9oiz0H)_p(z-jtt#vd+@0m7I$4CRbd)_D5sF3zhbJ-aTxtfsv!vJJPGs7RO(8 z?bUBc6a0_WDr?v0q>&~CYiP@c(jkzQg3yz)+AUt8sOw>3Y*jMASI$NJrZ7$0fAQ<# z@mTw>V;Y&<%)iHTeLg3`FBXQy{8Eu$|L6|xn07Pr&6q`(7@w)OlcEu)~vTGOU#q5w0`GKx7e)` zWAR(AoeFV+R7-ar-8lN@>;F><@sKpNLRpVVej(3Zv!iFkCExqoiar5V61J!ZL|(_& ztJeO~%g&>Fxlaq5guuyCt^J&7j`)N=zq{qrlA5`Hnk1ndzGHeN^o^8y)xr3=z4B0b zWj~6*$Xd|*fY1J$e3A>mFaO8@v0*tRzxU85*Pz7AO+-#`Xa@aQ+P`>c3ZPriLs{+C zu7vIN`5l`63=T;SKSYEgi7@gC(nvwN4%xI~ABvdW<;P@6CxpTjLTfY>dJcBAU z$`2UN@9_mj=I}fl-zqLcHl1iaE@)J;Juu6bkbB&_RT`gz$`n0*!niD?#JNOZk7H_f zD8G2u?jj_h7VmVuvHhk*&aX{~i>$?W4&m>T#Z~_uPnpL9qqRhv(p~lKEWPa?)O)V? zr6QMch62O?#`gl-PPW$)<;43dzPuJ8- zS7t-#L`waVu=RIIGcHU^n^yIXh~I9}d~X1vu+ z78B>He~C7*NRHT+A4rRO0)x`ds(geo?JKKlerZt&sO+28KM`vP<+PrM*9g~RE>^5^ zJ3=M-^#>*EtyOGt`SoAsGDmna5h6BvrWi7q^i{{In2Jlt3%Gdy+C=@LKHjPqxFk1h zJ#BED#;Pytm&qd7@=8!y23UNHs`=;BdtEv~_Z9@=ulsD_p&18B+g9RLBc=bpW{Zl7eAxbMNviHd$w4==|&xo=EIEoUfe_=DzR2=%^$ zuX#QT85>y7uvGc8<`tE{lv;6 z;)zV3M%n^%+d(yZnxxD8WVcrn){otM$xeEswuZ@`aXF|gKT;QnSGU3@l*Qc_(_bg8 z&Ifa6t13m%)7YG0vB7m*7Vg0;KDd*uu#q`?-H*hkusf5lvORck{HMEZuSkrk+J8^hsRp@TqZr68;?rcJ~h1Frv{$@*qwv}Gne82Ff_&!ff zXi3}bU3Pbayf0P@oNL6Tgd5JKACBdO^_9%px=Yhvdl!(`(qsQzi;>SUnLwV9^v@pX?E+L=Xdo*)Z}s8B4Kp$csw#)m4)A0}fZe9FFP zi3;Bkir!s+&p9PDf8|DOIb)rvN)#ePWOj$^M?$7b50fU<&&>4t_WHde* zQ3%7Y9IHBP?JIj*J~`-@ zG-anBAclzF)D-;IDDBOFTy7=ZhmO zRx35;T`XHk^p3935$Z@qc+`Xc)4}?k``X#@szo2V0RI8AzFBV=^u^qV(*#B8?El>< z6FKelQQVcSvUxks-2eD_iMPR~pMvt{>}K7sDtX6Qt3wNG5>kBeakg4{NvuSZyZyw# zZbXdj1*P`JHsOZObUH^V>KbO$=gp~wS6;s<*03C`pitM)Xfhe7a7oUY$g(x!g~{Qt>$h&gCN)L9O)zAt@2(?%s48DctSe37RK6k2 z#yoZJ$$=PIjL(|U%D|!lzq#6qz&C0^Sgs6L+WktY*x>C|2G z#$;jLHBv5HkH3|&Oi(~af3B==lI;G;m(xFBh`42aGb2^pkVr=#<41GiU3G6r0uM*M za2W_=B{mqW+{)YgfYa92mR(G(E)GKrbGrcpWqv3THwqZ72tglvbPMK;K&TB=V3Ko8 zkF}#@?Z?^M-ql&HWt3gu_?%Ef!Tw22zsBviLx;+a;egBOd9OxeFMIKad57e#qKa|# zUU$1*%g*$_eTX(vIX$uX)6iDnqWvI{;t`$W_vaCx)PvS)C=*d@>nQ?CHa{@mf3Er% z5N8_~9sMFmt22-P#mm-Qy8d=YJPAO*xEF>2RTC!c z27w{10A7SIJ4_CXwNKg?K%A6YmwgJuoOWSRmh%GG`qvmdj6jXh!;a6%F9UprE7A|( z>8HZ?bZSPCUc;9cpEv|oAQ@IAZ+sa;ju?%9Hk}f|>BB{PUrU|~Km*q*JS?o7FFS`X z`@L$ue6|iLRIHqc?3ky39S_1J}zU#e8jPvi3E;iY=2Fz0gxDL$4G+HxWXs>l zSHA7hti_Jv#-Fv89)o{eh0DMvB>cdxVkF*TxWFshVA+c_IO<$y=~v&sVVQk$HgV=C=W8y z1RSFC3ZszZ1+qEUMb%Qi<$E#DZP;`ep$>agpJSV!=7`_| zIE@I3vIC#N+wAw;b28pi8{A^)u{M#Iu|~eQY3xVg8tB~h-&z2MS3B@O9GTTbqKCW_=N27t@V6Ox0RaDg=qAPw|Cn zd)Jlf(A`5fh3LLzz(CQL|=$|#(pOOz1e=1*{oE{ z7PPmbH$%9;%ykq#6>__O0BLBg-hPYfdJSTg;IM`?_LbFE`I%%?MAE~>DE zCQEG(rC1{O~9Zwi?a46%by&2Ak5Ybzsg`R z*OTbN7CTwt-QgQO<~Ox-kDq&?^E$o|ZULT)B+~?r+cWlPb$rRxmoa=9Cwz+sqn%$b z83XQHVF5*_T~}{Oe@WC@N+KTK-X->WLVAQfUt?XFux|xlu21>|*0&+YmQt9&i#QR0 zp}t~I2@Xt$a=3I<7q(CuSC@t%5j6b#hYk9zDgfUxbX$7#a>TuXr?18FscVxxf*c#ZR>*kAoemvB_OQbnz2Ax%~Y2^pYv!bBbiR)0NrISHMSys zZ^UivWN2D674|GgO!pp6fS1!`LJD!Z>;vzx>May(p&T&j_}&q+jwooKlL&2c6l-P{ zydo7F^hW@_z{lqO2Hly;Mhfvz;Msl!0!3#>Ms7P+^#)4s(t7;$sK3{xZQ?iZgfu_R zs=b*r)OI_*R4*HVk+Ym1vnv^(<^^c;aJlRDv44T3Ew1CX5$n1W{BXD=GqT?1C2&+k7}$d|badczm->+*Gs zR+GyT2s1;5^-GXmYVPb?I;zL5#N66ZY@OP|J@!oFM(EG{-k~Z5RN?X~g0`_KMQQe< zL?vR>V^0bcj*zS7>nCXK8iDtSI)tK7#)PHJ$hSdU?5i`0{F! zZjYM+dO;N9*6i0d6|%5YD@0QOln9VdgGTF&LFN|HTj`@NMM@{|=-r#UQ8G~|{^#Lv?U040 zwB&*Vr|IT_xjkjm$#ZEKbL;tvT5l92;B610+}5*B23+$A`Cx0WJb!8Xs)*FZhJ1I^ z9~ar^Rjo@G(JTac6cdJa^G$ob4JsH*wv(1NjCwpj5zLNWfU$XZ5xg?sTh~Dae5QfO zg*VY7jyw#KuRH4ZrXIjS$$S#JktI{WvI@;d#$+n9E)|1KNjQ!|@5I*l&+)QJuI1-T zfa-rl?`0N(+4&my78%s^k5}n%h>e?ABSSn;oP{C+&>T-?|3aA z5V5R0J80vPMcv8XnYwFZcir7tGZo>3t@u4Qk>>l?63mjKb|o64Ri#Mo#?n!L_ltD? zu&K~?kFAqElR_59qy%qCljJ31T9xq_U!dE!e0#A}*m6>F|2aTON2|xueWhxz_t|v8 z;j4EB#mnfY$bDbdGNun&B{qj)fYDb{d%_3__$LoD;Uq`L%*?F0t$hx%r0$i`tOggB z#qren=qj^$qp_&t(`eOPl}Z-E_i>i;uonq=?j2GwpU0teLpGv^sw6 z@f;JWj@QD*KY^t1ia@k1r<){3pG!oc4ZuRgn~2o05JDD^K%Ah{ZfBmPS)>;Ho%pH% zPaaZEY_=cBQG0+r%FeO<1$xiE25T*eWDi1#;*ML${U%)WD_){8Ba0S8JHvcklOFSm z^-T{sQ{&k3fmu>1hZ|FfGbE4OouAE(S5Fjbx&%A$nk@X>E1ZVy?TbSHEAcS{1t$*? z?IX(Y-D`b*Y3q9|m}UKB{n@%#%6^^_^+{gRFcipgg-o4?d~F7rp*Y^VnJ5qHjpx;O zk7^2f|6assNBQRJH^^sehZoe|X$rx9n6A6DX2gr~9)gR|mhWzQm9S+xh}2yNUdVkm z?{w_;jY%HUeM?W9`qp@__27=HbaF8@d(xrU7u!fSZ!Cc^Fw!n>T`*V(F$si0-1cz| z1ahLvv&{eu(`ce_tzapC^!FcVi{?@7gpSsehZLII)t&1c4RD9Gy`MoRAZC;ph% z=;7o~!rm0RU45SXY7?tlACe{EZDa&oGz4A3nF+e3WNFxGVzgl+zzHI#hEfip#AwF1iNdcOCOAlQXr>%86Md zS9;$+t=dAfkE!Dn4!7v?ZF|&ll}{cX1dmrlx?fQ#E zExW!1CVK=%uA`^N$!xp)9E2XoeAn#3=fqh-zC1k{pWA4`k^tk|f@tY%EAn`>gR-*x z0}L^q)B~jIFY`0q(SmJD6f_+@i^?sH=4ob~PtfubPZ1bA3)2ar!RyMJkVIYq-iJML zEDtpvn$q|KERj(lf(8nUt}lh%q!6;5*iPbamSVM*{IdrMXG?nVfZiyv`O!cHF!*ug zoZROi?ze7ycn^GXs z96SW@>;eMat=P6C2`uqNcE%jJ_F1z-f)+YwR@a;?hKh)#0?F8c7LEBIT`b=ucIwXNTZ)iiF0{ZiBm$$ zv8bs?6wjJ6FHME3WfvUs;=QdXgjW9<(asSJ=aNu;uFcp|mhY{p^LZA3_K}o{Fpu{G z#$~Qq1LUv%_vYN)`(}(%=}gfd<>)XgN&a5377mYN37>5TE{1ghh$xg-EhEaA-;}}} zTaUpc8WQapvqT|JGk338Sz%rkl*p^?RMKQZQ(p(g?sWL|npwS6X)%xH{MU8n(gebr zQhe9<;-Jh`-gk38CZAo?S?zc0<}h!ZK-TW#c-dNj@y|76*MJYXVPhL-zEtSk-|Bxu z(s+XP_;9hD$9yM^M6OP98g1(D7o0W+!=x+YR0-}!8SU{FS+jf8o|_;9ciMZCNT9$c z-rm~U>M8=EVESNIGJglAgg-Z#6PJEPe~mo-k+Y;|p_eA@cj#8r+U$Je;ek}k=aZ-V zteJw!^M_6<6Ndb5Q|*bi3>vgi-jaBo$Dz#$Un6lA+S^;i1gyIP&^uIVf^A$8WnDAb zwxbHz`Zl6jF;nZ1QSNB@8K7X~obpJv%+PPU_beWY=X*p~TO3sC}l@{7e5Mxut1aRmM;ieQq2nrB-5hhRrk_&jtx!GZH z;rGbC>f_L?g#s}Nuc!uHZp^yAG*jnPTfy#C%%M_axLHgbLt+8G_4A1i$FgY=Xx4!A zqQ!y$ujJTfVfLjEPF6s|OrK_s^l_QFoya~IAY1nm#x)>N&E)hn5g=jnCui!snA}hil4NcKi9>GsGWdysL z@B2l?GqpU|7$Eztwauw_3Pfw~!#jldoWZ$`=kto#`fjkrU#A|Hzx;_bFW<48IZ&4jou?7~v(6TTh{>nNzUM{OkLA4j#+S z7IU%+RH8C+ynXpaC#Ilr>>SVmcG@dIBoW{M4IV_nvH_n3pwPqbPt_*PEcY)pHHAx* z&Y!;js_q_i4l;eTw_@NCF;r;~f&qPYY((+7JhGQNy}+RyA~)rn)z}t0AsAwPoHx`& zOwB$~Yxq~hr(ja)=;$VhWLZShA-5f_>UmUuE@O5$=0v^hM;WYbY3d)a1QvIRo>r_a z_NW#}q<~7c{oJ$|6$-;W&x|?R!xND;|G!s>osI9AofCn8Ke_}Xff06-b0Ua>@Ka>< zfUso;so~gV=ko>wG0)VC6wCo6XzHcR@3Diz zhW4f1t6f4z#a9{Mz}|}x5~PW(o_P}P61=Tg&<)v0oQ+t0hQ;g*Rn1{GOypiOPe_xq zx0GQw2=417Yv1Y+jL+SrzYJvb6Bu9+xxP7WX4tMZ!Vg^ikV<^xQo8fPFOa1NiJRC5 zbn2MelM3l=r`aZ$*HYwjx^fX^rPB5o&bsdPFmT-!L~MT1^$48%5gkm(dcK<|*|$p_ z&IU-6Sa?U5Limxh=sIzr9s4=!*XD~SDHhEcRK#rxH}}(e%kR>8beHT0vg_&DGNA4f z1;HS`w6Bb~1@r>sNmC~o(>fJ?b}oD2UmnnvPmsorqkwL1hy>=7%B!~oFsV0x!~@cMLWiz|>UBEBP} znzrgS{>`>t3*F}pD{&~=G$Eg1PB*izM3rTA73pOWZ^g)Qf|gmrKl&gIeJ z_9csKN00S}&qKCzYcraWMZfIZLCS}?&gTQ}bV+ORA@&-bTeLmxuUF0+ejd|xBFQLe zg^^4UMXQ(bl|NP1ZdON2am0t?XX1ev>&hAl`keF6*g1C4Uwgk&n6SOzI{4Vg$Ve2% zY+mbbOG1<{2QIQ1St|yOZPCPBVC%ee%^F5q#9@&%M6J*2#aoF8+f7*R+1T@4UYi>! zmo|U=lsBv|eyHV19adFn@b2UrXV>l*%Wa>xMdQ}(fT_XUI7dsKt4x}45HqabfjmD+ zx#SA+WHnaWC6A4es>IWNwWv;f!=FvY8rJ0stT(3yAdcD(#V9CoON`F+xQ&MZIXMjA z!1DuE1Em)X8CmsZCm+22rhU#bxaCv$gm{F=#urK@I7xxwA}LP&VhP(dAbumSntRH> zVJmbxqEV0#xp~r2N)6`)`oN!Y})_*K2WeN$YTC5Y5xM$7C|Jf z>T8n31D%%s(B(2C{cRNo!g55p``<4kI&gp(O ze}Twf9$A74ZC`qbEDXdq@B%ZtG!Or^TDU+#MLCc#d44p(6be73Ps6V^R%D5?$NoHC zi!Ll(T)i%N)v(4T;VONv>1%W#_e1$CL{|gITet2uB^V#XT*G9|waa|Y`Hc5bP=2aG zCw(lqIPxx#TcrD@=xUlQFL{I5M(+ zb~X$7u~EuNt9=g%l+IwcZ_^90zs^lN@kKFhe6!f5$;+^0L5WKAWnq!@pLgV_z569A z)Eo_IdwL?2H+7|_u1lf=P2oegq+sMH#=)}ru;V;BT!A4|8u{&;% zT1Jm3jJegk74ZNn3y*qd-X+k@a^`JYV#>S5$lGIrTZ2#OCB={Y)5l#;-C`@Mv0H^< ziC38KA-#2Vad#Dz8A43wHy*dS{%-|7N(rUr4M)7Bc49_OUieXaX z84!vIFw@vCn!58RpNm8_8kZbNE_HevhUe;U+m^93L8)d%p>< zUAC>U=m(bHjaDo0f1=CTt9p^OsBg&2DR8 z_+`f8o|GG4jy7#)4uujCOlxr?DNWb>C#>uLMil)*t<|0}=RGnomHz}GI00BNks+99 z)Ju)LD=Ta~DzT%B4cxedw$f#`Zf}9>tM_9zjxPj`;^N!)m+RC{PH*P|{75F7E8xSTM@t>=cH$UxX0@_}knkOXE9SY9n8$JQe0zZTz% z8D5izCu^*96E&E?tH!L94M#QnCeqrq7hlrG)>)2ZKBKyJjqm!fpHLyvk3CA(wa}e~ zs@5ikV@)U~;!rNGLncL~u8hHQl1$l3g$B1P$UzxycsuOmY5T#dkL3|(F{eYnnW0}E zz>(@&8bUsNSUxG@{x_ZT7&)bqxf9?{vB2M)Cc$aAe(POds>=C8p=dgsKaXvSS^Tq! zhp&H&tF|5*JOr{Y0d!^2*E0TmI`5!15KDBb1x>7W7u&}-3&O)2AD%~lRKzh@^>6($ z&(*hDJx&~#71T1iPO6z?;;tBq{Vny;vCu`tEf^F4^(4lVw5b}ik%psm->v5#?a%v3 z9(49DbE)P=zoWW#leOV?6L-E(xB8=mbmWu7HiWs5=~(iz*!j^h%Z=BRRuR_70_OY zHMRpeEX08cZ~pzx>Op~i9$SX$m4!KaCrQ&D_D?oIMYFH zmzjuC{45wsTg!M73|bNPJ&4*QS>bFh5atEfJ>X)1yAb;O`%69%DVgryK{tqQrvjLZ zm($NZ6;Dr3H{wi|{_{IZVEbGsTn^|ICitrjfIDYMAUe$QB*bmGR?A3EdS>wfdYQ9WRlxQi_dwxYuZl=DSOm-ORY~ zRpURyNhrPe)z#nVCj}n69SES)0AMVz2R^9qkW!>uUJMR_{DXdej30%G$8cx_^!*e9mxK&E+<48?aLSfCrj zjQL$Zv@`{5D7%nrVzBR$#}i4evqE!bNwRm$!8)uzI*w6*Z2l1Y%uI$-$_7=n-$SQt z_Gi6x$cMq_3zshil(*z8b?GFVMeiN5bzJ~XVvRHP5o02NAivGr)Uq@MxXmu6(Bm*= zV&d>mOF(EUGU=k(H1zzkEAH+^Hux*7#2=~1{Rw1pr* zy`mo=0chpX4T{TKqA$r+MXI>Ga0q2b_1DJj^GJmXP?A(ih%@rW1Ub`oF3?C=|NfPs z%*9j}Y;e8^G(AI}bOmxhkymIgl*!ZQE3^kuemgl9$}1Bhj*3jE7uM0gg;u z2saviKo#=1(F$)nHD={~14PG%u@O^_$ zW6z8p-LHi_F})BQMH%|2Z@8`eq-jq_x$h4)ZlAKjkfm^EfBicFgbFNsmiL=XD(5Yo zKuF?O>p>GSM3TqR#;KRC0Va0~0GRVhOh%wh;MAs+mGQ_jGQ9OQC=IlaL!|lZ06bm; z4uw;z!`0cmo827#!OVQ9&0v3xy;B~E7X0h`6Uyctj7|pG-$3+Tz2KcR}cT_D9ZOj$0~O;TJ}C{)ek5634$WuE164!BgMVF(YLcDo!J=<$6x zQg8FUC;TH+6Yrfz0*YHr6cE+l>fYvvK_mVi;i=gq6%czH-k1Vr$=c`x*nWP5-lEpldx{_|3lw?$a+Z4~k|@xHRJLAHtjqpDLu8QiLoC-V%xMJXb5(sa9g zpl{fXKLIV9)t|2ghgWNN=jeNIWCo*cUVwYc*h1xt;-}(sm{p(3NbxG-(2qT(uMs!Ta#Q%wYGp;zFEo?y<+ktRZFYJQD&ZTsyRknG(8bZJLR!~D7NkTj zJQ)cyEjst*PIrh6Khz4^=fZXnge5d3^-x@c!|#GpfUG9mU+VPP1~hjfTK0CPsE8C7 zoxA749dtXgt5Xpq1Tm;6!EL%@be>hQuQ71GARCWX(F;wMJ&U`kH)f@1r;uvOy8li= z7(<%_wLA$sFiyjfaT30}@j+Xt`W$eCQw9863gR>Xcsp&kG>U?iFplFQRBxB8Z*+bv zS5PE{j`&7eA2Om|W3SChH7wDHph`pK+u$N^9E8%_;_-gMasXf#@&U>x)lg7hvj=iu z1vN(?fjf!cljm)?*${*6{ayF&>4gMl$xr`Ge-Gy@FL$AZdT?gif_tICocyN%{f4r+ z*$oNl(DRN)*Yx_5V7^(%Vwm{XTb*hMOIm!^q|<;q%bM8 zz6x-Xj+I&&6m8SWnr=e(+`7tq3!(_OY^}Z6vT#MDj=Ry#GdH>>slj34 zD}4aj_4|lvDV2E%DRnsI6Whc*S}4;F<6$h?EVn$@M2&@jgtAG(=hqj=nZCid=o3zE z0kk&+?`m2+Ex6a&_T^z`eTjvDpZVFQYlAs`rVS$||8!*&rx+xCtB1GAnfN+Plz$%z zjnM>w{mnDCq74Pw2n02+tiP)nkU^F3y6cD~HWl=`T*nL)e)o+m&ECw_e@1@)m>4w! z2AgExYph@kFnlv=3wkw&Oil{qmG5EdjQ*2Nixh)wg90Stqf1zJOS3&@7B}UBPI=;q z7hYk4&#UXC1KPU;b!3A*uK4IyjcuVPJ`BWTOo`>1>RjF2sw>+8-!lf#MnwGdlBT6o zw`2;oq`lJ8Q)S-BkoxR%(OdsXEiGyhQ%j$e&R%);)&KwV|7r)m${oq^ZHS86qZn0) P?@&=xhnL7def>WG%s&!z literal 0 HcmV?d00001 diff --git a/img/gallery/graph/05_social_network.png b/img/gallery/graph/05_social_network.png new file mode 100644 index 0000000000000000000000000000000000000000..980ef836d4fef7bb0a444d1a900f3d0e796289e0 GIT binary patch literal 78216 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 literal 0 HcmV?d00001 diff --git a/img/gallery/graph/07_selections.png b/img/gallery/graph/07_selections.png new file mode 100644 index 0000000000000000000000000000000000000000..16e90a4b0fb979e30f7cd5d7ddce3f2f289a7aef GIT binary patch literal 14025 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 hzvvpu{C9bg3Z1NQem10ul}-Ll3D)OG&qM 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 z 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 SIjT5HGb#!iaQvgEFaHn0T7CZj literal 0 HcmV?d00001 diff --git a/img/gallery/graph/09_sizing.png b/img/gallery/graph/09_sizing.png new file mode 100644 index 0000000000000000000000000000000000000000..1cc1805775f93a9ffc82ce7a16bd220aa60971d6 GIT binary patch literal 27283 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 literal 0 HcmV?d00001 diff --git a/img/gallery/graph/10_multiline_text.png b/img/gallery/graph/10_multiline_text.png new file mode 100644 index 0000000000000000000000000000000000000000..7f95d7a87eef853f19691972d7d292ad33032850 GIT binary patch literal 40747 zcmd?Qg;$hO*Ec-0l%%AjbP59^NC~5Kr__MJP!f{Ts5B}agM=V0B_Yx!QUgdgh;*xz zFvNF;`?=rseD7M{U+}S(3!J&GbN1Q$xAW{BrLCz%O2j|}fj~%AlwrCM2(~fi-wk~5 zNed!v4gz6?sK6fTzsT5`_kBTa`$g_|Vki^LHvSO-UT4adOF~nj6pZ}!uUAE1AL&!q zQOrqDhw6)4=}lC={`xZ-;`n{vm~40Ofw~O zzr7~$%w|t^zX_FX@-^@shNU{=b{)dIGV~L8%y-bt+yc#O#8X$}!j>1a)(Be1aL(=& z^OPi{-b!|g-j85E&GtvolXJt=!Ff~9Cli;sYKVP7f#BT^dP%%X2T8oMq>PTB#GPNu zCw5UoHDv#=k9{mgXFk{(_scx?4o6H$_zgUBJ@1qg^FiC;g3ZZwObWz?)jwr-*X&P_ zI28-W9nfYwu<(#cUSNCoexUa!3LjWB@;mrzR==Js?R&V}negXfi~2>SHo}=N0naqX zc6u+YR1H5WyK-g#BF%nrPJwrQ4m(6&F`J& zM-swA$pj1cIjD?Q`%7b^OPDfp&133l`)iKE{;v2dtz;P;tjur{^ywC^Q#)$@{+m9* zT;UL$W@&7V)4} zY5)l%yK7QT)%zz%)N~7Wd2jzQD}NJs5@{1?cCx2F4%0A&^PH4Pa~KIu8Ev5s_zv)P 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

s*(AIrHpi@3mLmYu#(0mpO^T8q|(9 zCGUm^B31`!P%M7XVBrUl z<0(zE*v@*;kvRDLA#m#)W@nedc4k2X=F&=edCzY#L39bJmOC-b;0Dw3afy@xv@lbS zhqobs)YF(t3@o;mIK3a|@IaQ9mc9VC(Vj5)9QgMs0-sjwP%oP)eFF`upScz9NezDe zXT#yZLjD)+dr3!pqTZ}$bz9`L_$AHETON$);r6`zf;H-}-~V!`fGW2ipPpu4l#daq z9ixCF)s*!=0*V-`r^N;tswherKy#EZV7>~E?6%v9YB9z?;Kd`O_YYA}%AF#voG4KG zba;Ad3b^L_=T8h%YibTM5&uWHD*+SWk$Fy#Z=R7*Df34xdD^wQ_FNnEqmk#_c=-pv zKZ??f4y)QnkR9|$^+BPI%tZ!M#0aNcc7>G@WAnt2RAXQSiUc)7ndo?nT7e0c`g6YE zJc~y~dKO@?P#^dw16!5cAAdwja`8$EIAHB{MD>_;kp*C#uqPRuZ!xfKIME0%w~B@| z>+kUL;}A=b#phX+O&Ng~xI-Pi$cmZQL87KNF@RHhSAUf(XR33vIsNP?CQb^*a2eP! zElqi0?Ba4@X_ZS(QA|vTmidxhH*~;k?>j|bJ|7upicw6hLlFf{F>DH)%86f6SHGc? zZBiwor@3}IBn|1v%r0qcD|B0pmqs_KjID-4bjVZ zyBWRmyGnVAId07TwgM198jbWLEkwmDL090u>>(6b>lhJRrXNgI=5B zT5C-yA+*M7KgHVKiksODX)^hkus1ZxO+;C>rn8;|?GSsqGcZu-ox#`KnPjw>Iw6_o zDETo!*hmJ#Mri-L(732PH#YM_Q1i0 zURAi=zyX*T?D6uYDX~(?z%DVS)ZGwN9(D+OBN-cIOP&9l*LJ`$LQ_hxy%#vu8wTTe zRCz%lYC3GBWBi{?`*$(7tf9az^kt@~!JbvmI6ixv>d9(=2^jN`S-(-k2hIohEuy3M>U(22IAqpegI?rcntX4k1}j&)3B|4yF$~J{Ygox6JT!Bo>!RAW>RD|Y>RI6E&o9tGD2Z$y z)re?%y#FVv*Zo5xoDemg2VhnpO-e_&hnH=*z%r^4Wb^@MVSHLG8}InEL?O2-j8+}% ztwuD%&)j^`noJ(|z3VXnbn{|=u@<_@mWL1)f_9 z8(=YPh8^^LHKsvdWDo(MuIUD&6~vW8%td-D-D5F?geBCm6ToBc1RL_Nicrfaf0#cP z{mOCel4iLbg?w=^b6Q13l=$``D-NOi!StdHVnt#Gs_NW=an1Sw)Wixvk489t>fxkX zBDAo#3^_J-+;jm@1i+aRWQ~#^>p49j<>;!U08V8|`hC3VOz$@9KuE8E zpv=bwAWpS1)RVLdMfli2*&q>ffvvb48V@bHkQTGKG>U?PKKDb8?HKd-U30lcV^~*Z z(S)*j`eLUfF8033fXI2@mV>HC*sgAKUqf7-sBBEN&g9*mS zERD3e(If53Go1lH+rM$#yP%SDJOX%DhIKcrRGPpLAh!l0F_3p1o(1O5di)Vo5l9q;ogaN;Fk zvs*OY6qqxPdUObNt#&Aqu+bnHy_>h0^{&PYrr*pWD{oMMHsvEZ8`h>5<3iCxO9zwz z-wpCY+-+KPBUb7w-0`hU$N|}PG--h9#10}#XN_ju1t=-) zw3|DSu&*J`M@#s1@=t=+fu8sUai>qazoQN7o-ML>_l;E?xO#{0a1Z6E{&8lCs&uKj zoSlIDX1yw6dxw#UJwMTi^Q2guvWBPoJ*Ic*mx?&Aw$GrV%y?^fCH~HGMm1~d!VWMI z_Xl7tzu10GB?(3_jT1+2Cs^G^2PHzMgSpyMI&sSCJ?iK46$LLVnd{&TLQMQ zat=01Bk&Sikxql!BiZ+{&}2ma=jv_uCB*v#i;T`c1lU};d-(&0F;ab-MO%egkM_^( z)T3n67k=a0T~r76E9uVJIB^m%Ai4GC5hYJ1aXSLcl7b`!5hpM9N6U8_Uc3j~@I|<- zrHKbV3+uX7sw%5Sg*y2UglltaMosh@s#FDWF(OnC1+4ST!}lHq`W}H{sPM=t)3Vk* zvSWWWYeggsKbrNeqo9_aiP9`OX}bp`R`Hvci;W!VD4tJ>1;aYu<7hb-uj6oM;I%Ex zFRhq8<#qrFM?hX6c(*~Gqqp`YWtWCJJ2c8SFDoT8(kJqF#dGJcfJ|MRFtf(Utv8E^ zfxJ~=J==|0=qNzbDgw~SxFBWAd}%l(;T#n3@dDVK5SqBp2=~v#P>(c$Mv~O1@JHwt zuph2Hc!2jXK}sZn-aTiA7!f{0xFI{$^#8jz8E0^;Tfj-^kCUaaI$)nRTMs>?RNkKY7s=bHB4N|7+tu4=0+dJ4jQ*^_fZ6SA{-O9Q<` zzVBqo(6$zA&J)dg7oE%<2(m$Jpz6|RtJ-+fA-o%_u8iJ7_jOk2~h zgGIa_p9{o8PIc@)l&uMdj=OEKfeWd*jM)^=>3@8YLaqOWQqz3RYirH9AnYawIzWXs1lg|!{+Gq{DGN8muRZcu(aQ@3#15Sw(b zr^;6og0@@k5P1%tX*9RKh{q4X7v1Dj&G%ttP9IeBUSns#!-W^Kk@7PIzRWvjVze zP4?_*t&wGC6Mdq|Bf4cvUk&8BxZa`Nhb+C1FDGxe)KEW#FN4bLv%@hBg-ELOU75*QzKhZkbFc)DQyIEy9~+dZDjiQY#FB)mc2z!LT`^S9hSB+ z^8?b|>RaGbS?9d8oR;wA(mQ96dP;}6WtCaTcF{J`F4q10PIyj1jnL~ZAg`$r$ z^PNTG`><(Y-1{?B<0XGQu=a?QvAuSzHczgcIj~nXnIH+;Ru{<<(NXU#Jkxk7womsl zhfg(5AGQn zEL|3(W`U^W?nQ_bykJUj)qgx5pS$cJ|VT<~D! zG9%o9gmd}#?R!SU#b#1*IpA7q--oYW3@iE1%<;maW3sU#H*qIcCD;l!>Jkz|9=VYqBcXU`&Idsoev!e z;;}t@8atmEg#T#7x4ZC%BrQ9sPCN=7T2J|$RcKOaG_A`5cYU!_$@u(~x{A3eTRcwC zP%GMZ9Y0vmrlb3TKC6pItZY$3j5&mlCI%e~DXKU3>3N%Ni-J`6enMdUpDa~?5Rz_- z0^%WjNT~wvkexC_L=pAOR*RyAOAOL-+{exoXQzXGqXev-!I)0AH}I2-XKx$n8p)y} zg+E9V(cGw8Eu(~X*hqBM%L+04mbH*Xt*9TYei6uPTAq2lG1U-NYqslXL9%*8>&hfo z@#@oQmwxs;4tvyJU!t5gad0zraxMDvkr>>-xoBAv4QRo>?6t?vi}SUGKn^r=j5I;B z)z<@*vX+DXt4_fD)wK49)n;cRW_IcuWBDLr={wA7!NR;aCm|0>d#)e(tOaO9V%&GR zRKJrhR5*R-w(pLG4&Gme6t!eWtp37Ue}ch*CmtnzffW<+M-AAIKk9JL*@6FCtbNq_)7}#jbg%qx_n|4)-$Mt`mb47@LLLTsi!Vf3Y-T_g z38IO}I79J>#JH}E0^8Cr|6@5A&@%)~1S3obv1i@$_6cFGMuo8lXfIs!E%$#joH&)V zc8-ZSy&zeQsaC2|7$PrWc*T&AjoKX&XJI(2HG=;>oICEdtGz8oet`G+$Ff(2JA|B` zl%TWrnq308GwMxRzxAE(qot&e7({u$dT^iu6i?Zo^bmki`-9#2+>SOe11;>uPfbgj zLu~A?e?moTv7NymQi(566)l${Bq`SB@xZ8&j2LxF=GHse%PYT}QR`_#40CtRC(;6Y zT3v{tS3k1leUt^S`Rf7WdV~TJCtT!ZG;}~1m;J;Z+EZZD(*h&d6!^ln)TZ<~WV91D zvtpbgNv3OM?Y7u(;8;97d~8~Wzjmvs8B%B_nwD`<_b&O*l)hkK)XV2)-&f9UZe@fN zg{zuI4}?)%_?(3>5kdDRuHHsbG;A9{g{X8mPJOA6+ZHV4Tf}vDU8eO)ns+PXEv6f9 zpY)V!^J>Eh)USdKj6dUdeNfn}yUqz1cpGctm~qVl#az_CE9+bA2rF>&03mxWhE;vy z*g2v!1dK2VNz0h_h zK75D@iaU_6Ac8+G;_GgIzWygSd-*3fBW@Kc&iL~Lkbp(lQ84(*FApwi*8i57GT8f` z{^HM5&cIW}t3fYuq3p5DyMBa?4-rpw{U>dUu%nUrxCBHVhd;2mnDUmH_bqK$bAy#56ws>TIP3PyF5)%--=Gp_iv|E6iVFx+?oR2r2i<)(=d5KDo40G%X$uqRL!Ck_JwUObsp(tsrw_mYynSnjUTcxT2&rlL>r*`F51@t;0_1{U9~`4`U~-UV z@qLIPfnsurU33a>34!Rg(kgVs*m<4=KztjK**%3q+AzWB+vQ>P+**8QHFNV5az)$< z9`;WZ3232kE-Y}9>pmY5iCl-gT*RF}3o6IyelD*PoC@s3ICnvaMUXQMh6K^Nn`0zW zFR2by82Vi?RZ{FcaC;x3H^ZU!rYSQ0w^*=AsQrNHn{QSkB(T0?RM2FjUarlUuLj|1 zPtTfyX4x>2-w8z@J}suL_@b@D=@lgQ`|pQVle@ENf>wR)Dr2$(qt7U&I>c$5PM1@x zy-wbUBU9JB)32#;qgT~FO0;4^f9--n4NAD(-4f&@Gp?5I$Tb~G!AKXKAfPqcZnBm{WvJ$~eDg)@FM=}hM$r&{r&iQ?;S1XBfQdmli5-c3^`7-(4 zt2t#ohp)?C8vy~0WaY8QdrKr{lMa7z0XQOOvTE|sh#bEw^LqCxa30yhtSI=95^16P zSqYVofO49^s}V9z5MiU-%&ROuu9xBwXD)akxoa;MCYCQ!KXjr?TT z;Vkz-7qMbZ_gx`+ap@?su8)vKudQbDACKUFN3EIpC9{sKaVec(rCPfm7?0LHZ!oME zQD$QgPw)Vt(nhV^jHW^POC?W#+nqSby3)9#)UimLGrk@@K+0cAe^Xz&)0ogHd_sP_ z4e_h^ZFSGXne=_@fLWhGy%ELK32XfaMu&n{dIL8p6S@~VQQqXjN3kXYO82v8L~@~# zovD~{Nxhhu>YZ(;mK1^?#i5w5%_0eNUNA$Zu$$DEDCpjx@BXNzw#5Zc zOnKc99-J~JIMI85U5pf^wm#bTE11Z{Jc%Iw&4c$z_CsnYpZ<|UnE#nyrI8q&I{2md zHdQ{yC!i~^j%%!hg|13W`sXX8^YcHEYX$eCAQO^oIEyLv$2=8OG&X5C$mpocN({9nw`tr zAsy`4Z}HQ!;8s3+CHDdnn5K-QceP9;5+w6_jqn5)rhMliEk*)!TK%N_Bw;MUMt=3X zH49lb2j6T2b%cUL`KP?m{-)+d*%KDzIC7xQOdZktf||1;S+wD7anbk9ojB#8*CWkq zf?D{Bv+0j0SC3B!5k7qY&bea6!h5va!LY;r+DVP1*AZqfNl)!Ob7Q;^Jm<=cNHm$| zx==YT8y29d839g8yIBwLK!Z+5|Rdv)&uWH7d9VRd}vxGg;dybCemax7N|75r84$O{|!iW!r z3%*bp7YxF|+QXRNnb#%LoCVg*^jR#P4-$ouc~YmF3I4aVJOyr6y(5lU-Y88H?;OHG zw2&q}g=JJ^F{dGWSd}>pw_VP-z9b>2krxMfVBW}|2Fd^^g3aTIVMMz)Xo39m5hJFe$^C__E#a9XtED(+|6gS^f9? z7VU9uot9taIq&M7bn5jZFsRJqA?`%hIU@SZ~6a7*=HjN z$aGb8e%`$@j&TyC3-b=Cnp}`w55L^p1=>t45Aw2#^PHwzeyx0CeQ-CdVLkt_KnmiY zMC3fRknVQG;7bU5HDbDGTTNOSw`(t%u2ti2yRjLMM~^}cI$3%&)n;7G-7|Xb2V@1Y zXh`{zh$-e>G5eJd)cTq?`_!wxgD_hmKiS((cb*gq*(r)x#S2 zAsOmhxUsu!R-ghod zh{3Rj1&Av_1LUVxfPLX0gPX>`YP{q$+(je~R_R=j?53#}NG~gotOLly_?}67UwX=P zD)zvt@SX(cN{0zM)n{Hss$h3!P2wncBKtik%*hCU?%nO|n}W7fi6XOR%v?CCTL8f@ z4<%L)KL%Bm%*m35Ts#CN(ahMg5ZB^XxXipn4(=H<+PUAIS8l@5Q4<3o-KAYyVU3L_y#s3wxvf@R2 zO-I3*e1tiSJ{L4l(lS>Q9FpR;Nv~P@(8t{C#)-utN7QR^AS;RuN6K$vxLQ)K zWtS1q2NFJ(u*>WPzaPK4FVV?6)llQT&=Of+yk`q$zmZPGA)?JBRSHOMDH{UC%?JF{rltHc(PQ%4d^~Dsu1QLRcx&_`@cDNDKK*#Mz z&=x0MUc{~E_#TV3WnYxo!XH(Vfy{-STgX|=ZipGu^flQ zKk$nP+6L@+4O8D_k4A(zZ!*cn0aNuyKRql3Vfv=s?|NpVoWw5$e4MAhzN_ z?aII^XV??3UCgHVkT~!4@!?nX)XtBgWn*FaR>Rytwd`*v5kHdet zJUs}203ymC7@&}~&Sr|{3->VTQtN9Lv3FUYvfX-m&UtDyaD)5a@{1&^R& zoqjVNY6O!X;BqNv!l?MKA829V&fQ~{z0gQWj(JNWu6sJcN7`vyLfSgxv$f0$8yQor z09zV)-L@Y%%wkm2@L}k~-eOK^BjW`l;&8zfA61s(#xhy zgZZ2lR{MboLiU=p0mU{irhxYS_qpIw`Xx!zg~tG#J;!4?pSmrnw+%vW5U$|$@*%ux znv5Ecom5ct|7kMeS5C}7v)7r>-tuZrtmB@eM^7sKkQ4UAeYt3A^SEM|urV;Pnjj-a z`X&u*-IuShwF<6nM5J|3(ZEOy->6jJ^s?*Bh}hV9qrTr-_xz`$hkG3wQJzf+5k=kQ zZYBzU@onr|+2iqoP)S6_ePwx3Y;JvRAC+ifm*^{rhh(I>6a_GvlIn&h>+UoJm*H^rCa_pJnDd@@z$7rFJX6#9{z7+y2!y^yz?M0>&x zof@}i>IWg>L<6@>d!}X6jw=0G8s14z}47f%fbgc&& z6jLAdb3VBMFC<1=Zr>Nnc%=04moN&F-(Bpj)&VSdZ`^iM+CkMG<;tSSBIm^G8dz8;YFj60raYtxBcl==Bq)g?E%FW8LbC9N0-w^ zrBjcf(3sBgVAF{t%=K9kl#RgXY4;@ygbPFm&#RsEi(!DM0o|;8zllv&Vx}VU8Qp1+ z?l$GVtTif5=YERq6`USGeE{PL;2c$A4Pq0u3iSB)bg3y15OZ7sqSujE+c^5B8m+pMKuie zK)*5e;omT_4#1ai0AEu7!IynQe>EApA!H0d685bXmgc@0kAsSIsasdx3rOrUFpAvclz|uNRNNwfg z4NU!l>g6u@3>YB-I1*GsM)xJNp>$|z7I027s11%jWxfsxpOq{9$NEQvb6sWEA^`Fe zr%|4fD;n+Xi=vg8!q8DCn|b5%{oYEQ9=Xv6$Vc_s&EjSY`gvb($%xEv!)JC*>nIw3 za`Y4%sKRoOoV}1$l4{+K9)Bhb-n;IS=B6$ywy$(NOQP$FoS*sNk_Kl0C9Gvp5PG9s zJKy6~kf|${z=aqM{*#o!gZmtBu6GT>0-%zDef^UVqP+3FO{B|-a$ zipm;uQhoG}c)DsXS@6qkmQa^*r#<0?;z6U4SzFJaKF`8Z?o$hYF!d_p?k(X9ff=r6 zCLF9dn@oiF4PKaWu^G@=Y=EUbUKY*sG*$T(jP+nTe%7@@>K8yrk)I*6>`zMBj+|J4 z5K+WWY<-}*g`UqvG+;wmtNYfbaY4*>AFsF%ohQXEFL0iyx zIHpta3kI_)pnw!CGL7%i_$VQU{)SA!a0wm+jP`_!IgGoxmSXD=!Q-ND~jPT@^hB4Soe3t)UlGGMsD;amo*rs zehevsig}>`RTzQN(yH zQ@@3SKM21|2xL2Z^%bE=_|VsgLZaMArbM?}i^_V2b&;E8Be*&$jXi8WM|Cx?MEgQo zqljfvo{>~}y-O#`BuJP0r6j3bFz~^_2hFeM7;ND#h1jb&WfJbW0HMwM1IWF!|E%rI zDjo%|PlUFQrIc#-#PoTRk1maPJ3jz)q`K2{SUVZ-Jvm{T-bB}3-%^yKcPKz_9v05>zPh;*sJZ4CXZ7G(3IDa(IahA;-iMxvH(s%xKgeK zz+gem=I;5<9}e`EDF8Bx^;$EiQc?%{umt-McEk#CUB_B_Hsmh`0<}&7gjDTjZjGXZ zM=1`Ys-#`2D(S`N6&H@ru%AAx44eA-Qa%hnczNnGKfo1B{Hwh|6}1C;EVYG~Kf`yY zoOfq+qolT@`hk1;Thhs(^Jfy+Wwrxm#}(!TI##^V16z=X*{Ng_2ikA|c8E)cmO~M< zNLx%J`f!PvXt)`;HpR3DDfH)BK1)}e<3wQKXvIU$83so_UpJnkEf%0V>3=D|C?#an zF?U^=7cy;6CbS^*#zjg9fKeb9R5Q+sne#M{OVX?FfUO}TuW!%#SDaifGXjRmdx{En zl0C@=!nmx!zK!FU?fhC3vCjrJLHI^Qq}=1A0kn&~QT9NdN9T5j8FC1s!`W~I!Ax>y z9-?Kv_gNRwt0yEphlneeO#swciFaL0Q6?gMGSwLZenQ^AcQ-9FLiB>uP45`$74H4# z8VQ1i`zMkyU(45k)T^pm944IM2MMKc(4RJI-ek12!JwhZo|*{7nZXmHO%+OL4FZ?d zF1}}7+@bJgINh;30flszibMG!Qrx~zj1us!zSzTdl4D&9q;%NG3Gy+BX!;kX1q-OE zmiPSiXWID;Y8T*E#&7*^QH@KQLkDn<$I_+`u66#?7OKD7woj8nIy4WUny-c|Epi~5 zdu9k48jx+K;N=TbTi;4?OlY_8JJjpuH3M`Wn;h)7ukEe&c^ss;z!zWZ4PM8o4vx$D zG?G5mAhmGxP!9)lcgpAaa3zH{ePCKr{`Ge?hccK5J1#d|{?$-ILnmLpxA>WU#^4t0r3h1;U8uBbN2(qPy~d}B8n+w# zBnW0dT8m#Xk{{w?MPyL7L0ho^VLSbJNtSWWvdvT8$YtKJ67 zm9yvu{ZM3yT*0X(X8a?@F8I=JfQR?o^2df?aYupl-l3rM=(R6vRkpDh-%LktYJaA;WQh{*ACD_Tq)cL z{pem+Y+#?hs*sB$jSd$yk zt^-Mcsp6(^P^LO!(tsj=wR5Joc^(-4c_@!et#Y{%Vb=g1^U0@Fzhw(I4b%I{93a4c>>h2_r-MnuJ5IHo)pXAhQ*LQ4-_hUjBCcV$&upa<}b9g3)4gCAK zkNo3dPk><@A}(l_7Iy)JdsBAurGS*>PzB58|9itqo!_hpxo)CiRT;HkYsR&6{X)$K zs#RoBSV{lh(ev9xmnR`QmstGbIs2mxfCWib{xP?X?&Oz#FqL9EZ)p6^?wceBLZQF2Su+YnCCy74CTUBX`il))itj4h&)dK9) z%f`aLzziI3UzJNNf4J5Y;@T5yDGUbqgxvyoGACkC0l&}bVRvJzOCj+IC%F``W+7W5L; z!=02$6&}xE{}jAVa@LTno9LqpjK^eCoI|KzT~ABmJyvWA)CvI{!%sTwJV-tv9C~}( zrVXjh^oG=ON&#v)`SHO7J1`pKjJJ3bm;=lNnSbdPcnE~vn1FpBJr#hJi~$U`u#*EO zn2GbH+s&lsF3t>#6Y>n;){r59lbvtSR&AbzDU|?$nRp;PF2=`%&VS}TE6VZF1lT`! zjjg3@bw{FOhN`lev5Y2k0$?Ty!^J$YnoW>_c?dU+qK$*ERyUkvl`H_aD24zbB*{Na z`?R?^>&=hM%0H3G=mwRB8a7<26769iU%c-8Cl2R~jZY91auL@W8h~(LoiHT$lQ_Iq zd+%Vo=x@wqm-+tG@Ma^VNcgEgskHSq`Kc4J04XPOV|M(sLG1n;Lj-ZYW!pQIh6k9E zlF2809d#@DMc{7`^^9O!9kwXXb~E9XR%~_fmVA4_j1A(yBJGZ8M3^_dHRgb?@m#xh zh%h@7N)&qiA%!b=fJ}X{-*PH-dHRjLNmV#|!GqTGq1Dq3hnKRbSwh6PX0M2z-n>Pt z_!r-&s$u#+d>^OITH;+Pju2gLiPHp}$gK5+h`&%y|3h-?7NC{*nIQ=zyBh$T@;8dP(DO`c0J&A7vTaKB zJy1e!%nT#o-m<;rC99k#IMf$MZp;a`A+NAS*IK+M!g-S|GlgeOAUW~nH7m+pHLCqR z65On&n*Rta(lSqh3ICfp6TVu>z8zn?ksZgd6UoL(Efm!7+nx;|2eV6%W`1N5%mwnM z|3b0FcD&yG1#vmptMqq7qCfF+)0>NddoG$Ke}aV%u06k{Shf3Z6q1tALgNG-XFSYm z**wgy$l~TaIu!fJBp2B!J@sCSbB#!Uz(^lU|9|QQM2-7QpSN5(QYV7hN0J^(d`j-{ey6csQw7kwHo)i#JS34w(9AR%3 z!54}m!$P=x{`0C-ngYAG0+wMne%((X8#zr?1`s|VF zeR6oGqeRK>1vl1&Bl)$T)8DK{id{u^a(v%#d-k)o@yQU+-j9IXe?q@Y(^o}V%)8(z zwmFZ3OI^@Cj4zxPpM|-zXJO71WXmR7p4QJ{o_Uo!gCzb+LEid!>e+K?SC(X)Hd*UD(vjW2XB{V(pS_OjLp@gwJbEd18d#X{0N&n z#n~&g(4H2-t;*U3`)rLgWl41{OkB&;^OUJd4$m$w4;IFFE%4=F;k6VrglHA z9ss?|9e^_DZ!WAR-%507P8WZk3)!BV1P14-~~@qU#vpRcz2YA zgNuloyr>m^We7D)P8L_b_84|2Vqt%74S!VQxPOR5Q){w<{VDk z6{Vk12Op8O&@J|aUEl6wS+EIe1pZ!hDwv@^hl2NBr!wa_VnU|iUy)RM=I=;Kb@lQ2 z;+$6nE-(sGrOVa>z4h-P{L6Du?8<}4t-iz0$UKyR~W z0M5mKu{&Zt8RyE5k_N)f;r{SiBq7m_pNoYORRD(eJMfeigWfLA;QakvK_qI8qQmL* z()ZYPW3*o%O?VCSDYLzN#F*h$*KzCn7o9euj;`?ch>dphp~u);?FrzUY#izjfp|6~ z33#nuDfAIQSpO+;(Vi?H<>J$+KHI-Z`#r_5X{a(dZgp|D=LVpz)Y<;vx!S*l8ybxL z?6X&TasKKtuA3P%W7<<-HaFpM*s2vh&WnHE{idzUZQkdx0NSuR88l$@CGg|>$DbE; z%9^>(jx5Ojme8;gRZ{aLhprCMm{$$>YuwXE2?K%}lB9-GR`eue039B&!Fx_<$%6-U zT`FK%T_BsB^L8HfIMcLuBd7NVU0sG0^p=*s2X^XexVQGB`R|=_QmZI$L<0BXwBXcsqF-@9g3bj$PN9F%|{7gr#_#nzUE$E%%~AQA<^wC&Gy z^9P19U&jWM*3f`4n7M-Pak)L~LiN9cY-$WRFN&HhN00l=Ctp_O`tOq8=MrGC*l`#vyDFFgEikCfdkCft0*x!4}h{c!30dDB%8_6@Lm*~6Xh#9szzWCuHx37kE z@yTL;M=A)*w`{}YM{Y=oUcgTRegi_wAEwC3Gyj$zR;~zsB1Z`gh9_TspK9+J9$@9? zq`zM6_T0gq*mdp!0K2JgJy}7oCLFarkK|E5K#_Rb;ds?it88D;%H%m; zOQ8QhkZ0+)(ip{O6G+6aYh*ini@?B4o?j;58Ovw;qgDP9 z?jTToipPnEz-JAx%Jp0s<<8$qGb&U~3;z0|@i6m@sC5|!g4AuCo-={ zzUI%wEPIIVcuh2zGT(MjTYS!(@C#De=Iqn03k(dfB|jE;Wkt`y^3NgZl6ar70t2Xk z>gMM%*{_fK`sT`dM39vksOQC3;rVjv<%<)Eq4`HXZzQXm;9rsX#mg);)1wnM zMp&7eTzeI(XIMy$yl=Nxth$T@Wj3g@7W61#b+4(V>tw6a>qxX z)BDLpB;?Vo&eXv;JF!|A{B@q0;-&xh-Y*;=r%NiloC`@g{D6#bI~LFvO|$)KT>soj zWQq21w;WEkAMfdJwv)O?ZB2(XES{_)u`N*|o@n@cxv{BJSlyqTdL5>a{ZsB0%8lj= z|3seW;MZkfZg75J6#bqf~+kUj#-=H_E7Z_!@6Zl(|AP$R~Cy@wjEqWt%!{%K(t;_5zUiH!+xlx6zt zo|6KMF9IbJ1LY{9%oO4xNI9{6phN=zm{I`C(?oq|R@! zG~z4g+|QbIxhu)8XUmZO%0m0<4|VOI0JBZxw+o$o((-37QUJ6!-z)XnzVk26U>zqg z;@jT%Q6)!oEbjhpPdmz_!C=q21RWUXKKpcLlM?;K9Wienjwl~!d9w=!8vC}%oVcU( z-vGxj5z@1Dp<~sY0Y)L+L~IRuK8Kpmi(~w`EhrQLRlC^yoy-Y=zdOR9 zOMAL52lxkdJP-Z|hX9qYgn<~ZM85LrkhldV4utbt<>F98Odw3oCNX?eet<7qD{-!f zxS5a<@e%@s;z(dvcI@qw2`|FPNgAg4Y&{md!3DOn<{(Q7TA&Q>bxh#S>g6y5%xtO_ z{T?B#i_gvsgTaBKc%_)><173h!2CGKIZYOr|I^H)WIQWFJf|J*>Zfl%NmI;t`Tcy> zy~5-~j7q$I(a;8{VW9&n7%7u>9VI5tNpL-gJdQqw)v+GxVjKR6BF7K9dBuRAwy*_; z&Y}YXUTW^&VwaeKq78$!e0O%R^kb3tFOq;7EHI85T_ld?RTp@V+pWu#h=bkX z%0b^gU;?xM2s}L?{u5ADWjQ)LqU%|{DCYGE!YC8(mODqLJ#YNT;}KxYtowuJGeExy z+0R^ZEz>iV<)3V-{_L83mv-dgZHE&eygd}8p5o*-=ihs?T>?jx+(|f zr|k6pul$MZ;S_*`6{fO_XOQB$>)sWapMoHfn5dDD1mXOG#<#T@HCOWF(Qhx;RBlM4qniXC|9(sYM z0gNzqg{eG_bm1jhu=C-PE0RNUpv;?yCTAE3xsfKeF4~-FuVLAG`rDB!NN!$bhA`W? zJnsKBSdu0{GgYpEy_!er29|Qn`ATgW=yjrry?m+kJdIVNl<-!rXH}qgMDpFeE<3p@ z#@@)g=-Vt?iee!tOKEYH^{z=^`keZnM)MJGjiq;&b>WV=h8UZY5-8y*1AMu(?Jkw^ zhKYx;G2A5tAVZTAb8_wMhw7yvdNd!4%cWAp=;t?HV@zaWikO|;fAZR#(0X`D*BKLp z-UB1D3=(!;lV>jT6X)z2070Qp5JRGZEcl%Qs;n&EcKK6z%%_+t19CF5&$VQAQB!&u zP?y^>3N}SYY5HG{inx2kskW3StBc{N@N6$%Gl7vGhj_R(ypi5~bI-smoL$`_+_7Lh z+}wYE=-zVgtGH)C@NMLaC-&qGa;A7aKi_Mdw@doc8Urj&zZ31sq`xn^1f+KBc~r5b zw6iW!4^{UY`(l10KJICH@N2mW8a(K zx9}?dQfhxXc#ZSYDVw=Ot>`RP>yxOt_G?KK1EtDi^kyBW`qnWMLT;R^47rr}p~Hy! z<5#RWvY^C_`C%vy?S}ffT(|>F6P+z$zvEvAJsA}X@HLW9n4w)eWwHxAcr^q)yl!6g zhWheM!ytK^^RuShacq+Q&&pI0Tbh&xCx$bmCD|FPM&ZypYm*}dk&U>P_xh*$fI4*L zoscFk?R@h_>oLhqEj&%-M)|QhdA?Fl35B5PZ#1L9_i%Cttl)WuY6w}j?g-6_mv($gruxzPA5~e z<|sOHOP`;<=O4H=SWj4G;c|JR z($av$nzmFUn)L@7ycE}EAYliuwRM;W?tf=6Vbap@d3-ghx!rz*7o2dsS!OUi$mls> zSr*^C+jIIlxBG$Xky_aj<(GC5(uv*fA~FcQp4RVU`BFja9x;NF`4X-Izy4(n(|N_o z>5eZyB+&GO;361Pl~oVLqaq|)vXbH>Mmy9{c9j0U}=-NOx(?^Lm$nI(X`uS}oD@5Ov7FRA%Q zz3j;-esV7^?za;YNt&>VQEGRLhUZ`N$H-G;g)=Z31qvv~x0|Tqm&q3wwL?`-PU@~r z(1M<>xi$w{W767dbz2AIKX8nV8soysO1+C&yk-9Jxkyor^R|f5^R)0;`(X0oRW${lj0Bf@fH=6PyGktM>iS;0HHQ{Q!)WhXDJ&DkUKq4~7F63}(4Ync1 zKd+z_F~zS|w(u$yU-C|s(uS`4g0s-(`B6@?hq0SwXTp#R@M9QS2cc*WI+TC4hjDGN z$dRzslI>SB$d@K`|Gay<=wE1t=e;riI>J@_S=rDv_cg4I7lL^wyrpe6mnij4s3e)Q){3=I$bqM_Girs zU@;o)NWi&<^C{xk;SY*X6&lVDmzpQBc7~S=6$T`;?wGyKb$_6FkGr}g;c8=PAus8q zA8TTwPyaiaQ8!&&uWix4047S-I^T~ix%_b|@U!OXHJm)MM?9rT7(2wo5l(Y9+0AqH z*trZpQ(G@xyQE)4>YdCFh2aTbFsfIePnuiuqiclO=)RYLv>`?PD4<@&$Ou3fQuYG%Pq^Q+`5an^85g}oD$vj_QlclUBD&*xZ z`M9S!ZzhdwUKyxhuj4+N(GiV0nSX2lln{1M*e+d8om#_qRwJBP1qbV3N6F;GC>%PVM3GJk*KPW_}+Is zHAAbXF+dY3_~}&*F)0%EO8H)*V&MA1Qj*OZ808Sj+$e?9eRcnQaLbNYVh3$OnVSU@ z--!V?Y0H$F#IMiSRMTdgOEC%7$JYuChqKeh82#jpnAtAb9_qeK=}|G*GR7_;`c_a3 zE5lptarQl`UE6+UacftRQq&h`63(30P(!#2?wr4+vK`94aSW7SraBGMf{ggTFBSmM z1);{i8{8iejPebEcLT`cMd+z>NzNf3vv|6<=Mv@j=|IOL`JC?ghrX2^3dcNJ8#6|3 zi@S}w1E2EGT>Q}p-Xq8W+I9W4_uR1o@f?>0j$-n0$wf-*9|vydB_0SiD9_VQV;~HQ z8!%`3xcMND-p61|lJD|o)5lxjt8+**Rmm#_<;q(Hr$S$QDu>cP!KHfZUPYY|yPkFS zap}>(IlAr8H*P{AI|dYjK`V>KU&pIe^uC{sp6zUBbB$7X16I+r=67o{B9l9f;1j|P z1@p9{@v$rcD#lLl)w!`i7|Yt?>CK22VpX0Q8Q^b|84qUP9vz-W^|lMvqwf-#C5h}n zP{?ILY$XKu%)x|w)6s20we`pzf%dhCi1IKO$WPKH+XPNb#Oh=TGjHuNTZubQI;FjR zfuE-@WOJOfa$VA|;l9LSpQaa$nrhWwF;20*aX+=B<47fP>H6rJOv|OmCOp(29oujtIXci z6j5yhE0GG(z`u%uA-(rye2|73EbTHw+PN^}vudCa8}0j%L+1!#^Q9CH>GIJBg~9ps zeIaJkogDubo?fSa-rUF8NqaVKGH$nmTdaID)YGTVC|%BO$5Yo|pSd|~+?!`%=bQQ!CbXk~=A|;bYRskb4GdCTpZL8mgA98rKy*<1BR#mEP?%oG~ zl;=<~GhXb&s|vMByUskjKII8G4}v>e*}GuLePn#(d})zP9mhj}Ot`S?Lct8BjlEbz zoVN?}xm()rY5A_-*=(w-l=8S~W$!O!HZq4g-HDQwEj?N+rk}8Q>S95^?${xt*K^bBG!WhWg*(&B|7=36@9a$DNG;~Hv@k{8p7lc!XscoFXDl{>kEK0W|E=bUSefYGu ze135q;L76s-DyE*1IU`IicGFJp0}bQOD|jdEaHh+BV8Tx-6E> zz3qsMavN9Ms0XXa-fO4o*HK5i$xnKmDA5FK|8lfV-u|#qx57!#xNVchUv(}YYXPdl zicKYv0TyKJ5j)Z}2uG*=BH`a80qv--8-O|fRv+T3TSu>_94)REe|Em4=?y7;##vr% zZWtP`4cWVB6!N;CLrf{bNK`Krfq{%SdD-14PT0M$i?pf%&h=Ctc2lQ%5YTsckJ0S; zNDt15Ts)7_T6}$YbF?s6A`nQq?_9SeLQa!bQ?L5;mR!lQQ2w}9-F@j)$VWvvXd9lH z`xaQ>ph%;No|e+7=d)?Xx?NS@dJ+ouUwwjOx+kqy<6t37&I1RY(R5_lcqsb+Cb)zl~R=mzG%5jPF&ytc@jb9Rfw6Ph4S^#WCAP97h zlsVFVehs|f>X(p)@%h?wJe>AZZ@D(z;2;nkwsQ#CEtjbd?h=DfGz8q<;pJ6&{4)8M z8Mh&T+2F5^K4U-U?tC?UPQ=Gs@|q?q>KC_D62o_}Yhl1n9;`UY4an+!1K?y?m{eJq zmIPX$jDh5%jYH>jAx8+&yDwYHc{BvCnpK*h@Zx{s5T~3kBM5EntAzv{WBsM(wC^nR zUjU?IC>2q#&a1A#6$?(%Jx+~6%ZXBheFNthqX8A@40$Tei(m%8a3(R{O;GJLAOW>L z1av!1Pjy)(1^xUFa8pyW0QJ6hnEv;3_$pRv>_O^}?QSyFiYa3%>wEfF;tC$!Au$Y^ z&0$^!88w$`8%KEebrinp2Ce6AFcKE4RZA9@)p} zvGKz!tN5RXYdDi9TBynS|1CyxDHJ8R=g8BofT{{-o4|giM#Am9XO&-VhtD=`fB%8j z)o*YchKz)Dg`%YY_Sz6tXWr3@Pa3lWj`%1Sot&{g2J_a>HPp7+)^SL!$C1}g+CrL^ zI)^1|H;$xLH$(2l?jPM^bAe*vHo0qMi)l3|Q-W$gL4WV9Gms`J=oFmMH4&tEH&~h> z!m0qSLR=6A3@W6wwP+&J@Y4X!xcGjFH9fD{YF>Q!unHa*7xJpPi!A1>w@R3g&#UbY zO$kX}-2DCXjl+V;%-U1V^#{#iBR-v*w|EH)cQCy@drbJbvO?-}kdO~j^qMAe;Nn^T zok(4vkC5YnSjKg{VRBTCewJeD#M`mVG&*VUV)Rd(s+|49t?fv4ew2B)#zrvgqii>z zW^1t5b0gQ>yNMYqrS$3{xLh2-%yuFb_;DF4<=G@XJg3%zPX0ctKzeS5uuV)WRElIG z)gT>N*sK=qXlclUz(I3rBY5l#|{9s6NplA{o z`2IPVhnN`m`M;%B$2x8&+c8yH-PEQaLQ^4^Dvu!W;?A&lwg-NAVe3I=v*G;=BXxxw%`p7xF6v#qYJHlHXKFwm;uMtwg-&>;jVMx>1gN; zGT3}CJ&#sC@y?m52!SDGf;Y*5e%S? zG1!0^BhP&v1p7G) zenX5*?i;SO7Rz{wl72%k`Z+p@puaaa1HW*nrb?`2MB>vWaqEl5wjzBSwZE!^x%K@h zav{eX;Bd6{bg>9F;Iaw=MZfmH0Hyg?gguaF2Ib;O&8p~l)<8)m0nnI@a_`|VN0N^j zK+-(o<{U$W@kxF7dm%i=LiBMk}Ct0Hy1bB->&XOB0aQgM9Lbap%r}Hs1KasZbSQ%QsRQg?| zpe|7={*2EGk5P&7eROm}!17!&hq+byhs~S22jM<*o>W4&9KQC$nY~+IM?ULe{}GSH zGoOQv7BIsn0$Ggz-+om_(5{D3hh8EOJTudHM{1Rc39kN=~_xee_s}U}g*|FWqDsU6SXf5$174YjeUahK!C|nQtv~gcT`@R!D(sD)p}<9RIVY{;G<*8B$Ucg>}XOI>WB- zu26zo;vW=$dWE_t=~slBFz{X?kcZ`KO>*$smXwg2k&1UZJ$nm6caDjH8Ge0?o6t<4 zb=Y(*^zHK#wnc$Yth0^BWn;rh7?JNY2wuN}yDX9LK$Gwb=VqN^X8>umm z#L|B%*w~i&;Cm$IwUT{I;9j;z+&?Qkr032faq!<$s4&U*GgBdlt#Z>%|PlrOI1(gX5w|GfEcjo^zB_mw3vkS#xYst{R4{<(C;XTtI z{n}&Vl<{dCs8`=RBqq^9eBnxY{|%aio;qXy*}{LrKx1KDu?o-BuVku^)5htg6rP!n zEuP)|?-?)napT7Dj66H*T^|Bg=1iGgw59m;2>gjpBO4Ip2OSD!P`Ra|6*XFVF7uO& zCANuLnOgR%+(ib6z}{%1GMNqLD!6 z$BZ2^wa1{f!*eP{{GaK$-2Y7m@~zGRd?)z$a-3d5c*t9uN5c9^y+`J;uStgAU^UR8 zq)V50C|Zge3rINq?@4yJ%iY^ltEK}{wDGWIm65EcH{6k1o3qDX$v9&co*?+mHG9t% zo_w?m--S(91lv~SGHmpjVguIO*dD&3E%hg91EcuHB4S*|y-hLe=a5|mB?Tmc{(Hge z*lwzYSogJ%7o)qxiuez&{?GT>VO2icyB}nWL$f--@!5kJN3Oe|CI<;`E_7tApHc;A zBG_BPs0>A08vo57K})^)nH~Le>{rCCk@Tlflf0HU+rrp^$D&sT#CkAB;Sb6eVZ#sC zi2LuRV}Yhhc;RIZ0lj|&=sw53=A3Y20hEm)C5s;l%v$LY;&&osx^g#zN2ef#I_QN& zBye@gj0o)(BK0P1K#j4+(hK4OOU-)Nzn(r1?2WM#c_u<+q%uoRU95yL3eYm25;6o}DOQ$38o8*A8AVmG+L-Y8c^RQ_!w!XKu>?OSVaDY&VME9lpb zB6fV90>vk~57Y-MTf#23&iz+J{`sU=8!m@=k5Q;JAC`_1TTmTNsl5%uZiN4e;5ghc zq^ljxTX&9LnC2e_jQxF)3IB(p=@1| zP!BABMmoJ?)T1#q3Y~BY1e|Oc6*p~&Y`qDysPD8cu7Ot$@w!IFKb~+V` zwlx29gim~9(I!T;)fW$R&H8j&Yjq2xA52d-=mPv9d|WoXLR@FM|K)GS;9VbS%PB_ zPRek?f==}gRJ#5>Y^BCmrk1-N@9=p_1ig>$~KP064196$ST?F#4@k<%!e( zxuq+VNpJZatVy%rc5!l4Q!BRJhJPn8krUZbj`}F>}Y3ykqF0`e9&9SuJR> zM!YgIi?1iv7sdjrRBUmU+s~OpEFOlIIUe!-CgcDF)+Ith7=xI=e?UjL!MGqnupY9h zU@$odAGsf&zF#G4Ri|ZKK<_hqXFkYp_>#6~RtmL#9{xxRiswYd20J`MbzH#a%0jw$ zBv4^$`oWyOwSo<{AIUP+&~zT)J*t{A-Jn0(IPBzOhBKdrUAAMtWDaqGNfU#0Z@73K zYiacU`Ix{(F@NHL{VG9P4=7*xxbXGvqr>(|jfCa(Sf~wsu~Z&O{8@1Pcd>cGOnV8d zjoux_bU5Ad{T9#zJh0Z4EZ7TlheuBnj3&MOxclwfx5tmxH@=L)-k?k5YN~Dh1;+MP z3?gnZwq$Ui5V)KgFVz+aj}BYV2J1~v2=hoNyEz=oN9I#7e*Af5V4ySa-v;6+*>7T` z;+c3w`)Knd$gkN#yUjY&drd>$AjS(2BTm8c9Hz%F5oZ*p-9_Ir(GQHUJh_nav4r>i zcqC}DPl>lVz<7^mNeKm=Fxu*8a0m>3-Vr?E7Ye%ir^2Hj);ANnXb{5v1+^eDWTG+j z22HA9K^`#hDue{|2PFYV`h92^MP^4emvLourL*p99otbuU8e=ejLmrTJ1WUlyUf{NJ*t5@FNkpvJ|G2FKxxamu9v{W5TJ=%@1F9+9ie$UFLS z6a(9YI_Eeo0yAGcpdML|H3iXugg<(PS6ggka+s7!mI*bbd1OlVw+tC9I8QlDW|JJ) z^}m|hef6Aw`C2O?21Lwzo7nTkjCu)SRY--;5u#Hp?R%8Ab4?_Rk?3ZO<~(j!SEtu3 z=CQ-(wR0k{yQAbKV9{fM>kj-ldbf@n;p(?rNf@=*eKe|t;LhbRP|Cf%TikT|qyU#pE4ef1|W=!`EpobuX25 zDibUAAu0CTkc{?+jziram4_vIIr7T7lkN7k!$>x$aI1^8n18F-F841+D0{Wu>~A4MD7((aZ2{dHf|gUi(shc%M5|uq#U{I6 zENM*m5tjyAF%~kx{}R8=e~Dj8#&*Ju8Su7gdo09=Y1x;Ro`ccw1D3(i7r(bpQ?5s5 z<|;MoS{_z&wlZ#1lO-E0J~^IB2as~U;~JbHWzjU4r{-d0VL^s}1yM)z$yg9sf1nNm zO3Tq_EFL(8=p7lkLV%o%oxXvm zRqe)}e=V7Tm7ZU&oiB;J{@Y~iVN{|wz!Aj7-$ozCL5hoD2chD|hxNbg{f=eL6h4RF zrA$95TIfn@_FqvG^}dQA7+FS!l!nqc;R7m`br}{hYws}r@?b;Vf_SSfTeBtG^(nFI zTI;&H(^n}qM0<1h-~6|#q%4N~gO}AP?=k6dm->$N{@_LSbN#Q*@&@Xxqg>ip1=I<* zmrq*S!$2IGmZ?U5ikKjwtUUd+QOwS7__UN^qSQQw?<*~ka93Zwyy1mquo@=hn|#OVv5ptX)gPq1j1tM4X}ZDp4elRX(dz#7{cq)1A$R3e#( z7uQgar#pE*^YYhra-Ovv%pUJN*T>-SUd8RudTD>r4fes_uYCG_v8`jK?ES=irc~RT z`;Uc7qOeBVaVU6jNmEhm^@)vwBCWxG+^Mpl3Oa$Kx44|(SQt`lpKZ~VOw{p~LFn_| z@4$9>24I0b64Yuec(Z9)icZ!Sro58jt1=N+J(5lONly6AI1KIcl{WepHm}g^(lOiI8x?Lwf1gyo*{wTm z-9}5n=K1@qFhGI;z6=tTIbgwI0brwwG?vyq{hupy&eyNjc;IK^Kuz7$@EiFrD*f7Z zU)CwQI=?dUzzFSS+9swtnX7G(>js9aDu45V>LFoC1>IM%wE>CK{(F-I^t6P?)Wpct zuaUamd!w$0Gk6>fmz*cG19OSejyVTn(dVSif|-T_p?AKZ<`OXli9qJljT)EPz5Lbvr!T-4#x>~3JRXrhSU20If7Ma8Im4|HbQ(Rq-0|aF{jnI>HM{$KZ3=}KT;C+C|N2et0+syh!3N2C z!_%W^?0NK#BFUqaX+JW%gUr{kfQZda{1TzIigWxme%<(daZaw=>rl-#kS*;$I`{A?g2Q_%<5Wr2=QoJqpuU;|73S-1FWQ+lf=Ar#;7pgGfsX zKiv&G9(;MQX({#!%Kaa1n4WyER-C0(UNfmgtUlJ&j zx^91Tnwp`A$uplzO7keN>v4B>)({OAP1vhJ!dl}AHu+5x{#dryk8mhwBDC;z1WNt| z1ALJ1+!0kszO}@6Yh0S$+Go-xAg=DU7qy@N4_5y~{XeYU+x^j3642jz zEE?#+x5<$qz_Xa+fkPUs_+6-X^r1L z)b6f|wsqaYkYfg5*a3SVhMo%rtxGIkt?jLQC9X$zuBVMSZ?)pP)>#veRO+m^dENym z5$UjOnrRR`11F=d&!tGq<4bN(X7kc|y0$!kGJ*k&uQ}mH|C9=F!OpdTJ#D_r>u7({ zr&RW?Y1|=(_EsF*`OW_UlR!m}1l1B{VuQXgrwG=_@YJ9zn&7$(Vn8hJ@|K&(^hR(062>S%1seIVJ;2s?%)H zCRmYE_itxoOWKrFhvxgo^D&r8-poL&O84##g{I5}uM?%Qd8bJaK0 ze7oOze)f>!zF6yHgNru~3Iu6jxt_5h07B;s;dSsP;`qqz|3gdt!9+cx4JP)c)9M!8 zkoB>cd%eDDye?GG-%#aChQ4@4+w8&CZ2q!&aLvfU{V98K4AV+$1OFu%%6@W`#?WiHmjBXskDyA;@$=k4K36H%>Ob}&9;w|Si1AuR!+c4gQD zXGI5H@%0ev72`lAyG5Vnnn)hRhC$yqd3muKT)tN9)vtz zrl?OJh#ikUubNV~iI7-!a;lCR&6em3NaiSD(cx=6|ZQ#AKt#rxaoCA%j>I)iJ(gwLBa;!YX zO9YS5MtEJAJz5d&#D(bZo1U?%oQ4ITsoRl_Q^Y?X{uNf#_YPQYP#KPC$0B9nRtH3(c-Tj7 zFQuDb2(|_554gn{%Bg!r)0wFbyX335c?(;Gv@}Qjw?_gelU}mf`c$bUGC1KOM^ccL0|?e~tM&gH|1= zjvt255c;4l*fnhNcQi$=s*KmI5?%*-4aQUMM09qnhFb-zA8lIf-R|Rs(XY zW3Rpy!1uM}-q5TY76PQXYa&M|JCI;^?U3~F5FDWuf96X#V_yvEB(?XE32L+-=Qrt^tx3;D@w#Em9&?$noC3C$ou~9DM(n zA{x9iWhzHcz3?1SN0D4ZZa+rWX++o6M4cx5S-z*2HY!b$sg!#~bVOyHpR(fups$tX zP|z9L5pyt(^;850p@44Mqc_=LK&`GW&2dfKy~F3Fn(fDQ(L>&fEw52SQTVM&=Y0%+ z(0%GnqkzFllg2Pg`z zptsc`9#?Bj?mL%4HGlg2+?(SstDioPx8-l7uyyyoy!UdQ*`zzGc}H~KJd*n@_cCfa z&tv>U*amNPUH9472wrJK{B9xa5fem`>(FBqTM8|pS$B)UNw`GMvu44VlS&^ zDom6|(E}f2g6O15AFobJ9!?v>#GCis0ybMQZzio_>91OIhSTQ_+#IQLFT~4l7Y6yc-|Z`c1@r|9z6o@Q#*X4*D_J4ttaKV1ur#x(MZatTa17oztm(^`XWF z^ca5G!r?-ddA1vchW&V$SXkK9W-WsM7T}FvZb_FYq5FW=Ay54p@^~*{-p4AN zmI`%PHa|L8Twe+u$35PLH1z&*IZuVDs3@&u@Rh2lDx2FGQ0h9(_K6jc9mRPGnXGv2 zo7T7}+pxb2uSOwS0obic{7}gSh$qNtUB@Rn#h>7CH|hhim35UqSa4R#bA)TSU^SS{xzbwHo21~3$iAPfi=D(^K&ZWI$jdA zdRR6){5U1Qd}l1=yQWMl>Z_C|mR312G0}WG({XlBM7AsTGO*9=(DC^GpAPBMsGDj0 zmLfmej>SN|;-Z|Xot+)=oXjGz_Dg}o^s5}Mi-XjdrN{AoS;9P9<<2C)JFHiX?zFl5 zJ5*VqvdIvst1glh$lyp&yq2jswZSV|Cl^6afJtb=U~WcZUBElh^`@)OUT<||qbZE= zdK+$$z$`-xZbo1CEp%a3a}|W72N#^t=hkei;bUdp-2tQ>QW^=I5oGHlhVvm&D9Chd zAgjvw@g^hO?aN zkhT;0Rd7f4t6&YHP?hYX^@Bm@+bs9*pZD}F?(FWTPZnE-3*T{^_2Rc63UT!x%Dw!U zuvH9;2Vp;D)eYKXQkL%2$b8KgNsP04F5XksuT`ev)XoV6lYu^w(+as@C*nYqhT5JR zj_rHKzgm3iu()u_fJl)Phvx5bH|aWbwt~!ITt~g?e;#{pVt(=kaXwP*d4yo@WjvmH zi25%W7$MH-xc%-)8cj@!PvhTr-&Iwew)dSsECBzu9Ye>*q8^BA%CxR2+MEg5ZBXt` zsq)P_06gwfQ|bvQu#uRnuUa!E!)YNt(4>=u>RIPB4(L*rw)iW1^WwpZE(V~>2EIjr zj{@Wx0SP<8w%+DgPeL{|?cHe`-fX?I=b9hBYhZ`HY@HW6ar>#mZ7+Oc(~nfxoHW0G zu<6-){tih;VnX7HC!aYX4YsgnhUPG(jS3MA0VZ-=&o#p*LN`#MfnS^Y ze3WH9thVcL@TSX<(MbmBiqMrtr}BHU-M3_=HiIUJlFP~Zz=<9u!!J%PuryuTU<2H$ z?nR4X<@z{OIj`KLBhYUC=f~Ls1^kP{ggX>vJA8cE1Iy9p{XQ1dHHP&~413h|F zI75>~9b0r6>A=+gsD4(bB2?5r^=YUwnsz4&~RI(r4(m>fRWLvRkH-kHNJPT zW(|4v?zlTP=yBZBkAw_Xw4)@T#k^zs`$n()Ci>~65>+Dyepc303Bf7KS30)KZaI%{ z_W2j92pGLE(2kM^Hw>&B=SLO-E*GtH11@H>C`&4JG&MEAn)2=owMf$be519uw|7$a%3rK+5^eS@m@dk! z(A1lY?sKKmn7Be66lxRXp;T|(0y40iB~0nI!S3fydpJSJfLV>+&8)-Ej=^Nsuam7_ zP6glD$|%J=Ia=L!x@5z#a$JR}{lN9S5;m(p{v9IQdm;s>2)Pz4I9~o$xkcnDm6C!q zX!|b-3Fxr0*|-MS?K`r&rs( zqKEUXeg{mfUmJ_wl7{pn({cUH7b>Ajn@x{I|9K}?Xm&%e)mHG@vudOm$nF;vH=o7F z&8Ecz#R(WT1Cl~|_sZ4iigWhC-x~9u4>iY;(Xp`>r<+3~a}GZ(%BDmqm-c!;HI*hq z%4+{U3VKy&mG|jm>Vf511y1PhvQD#i9)QJv{|U@ep;KXC{U(muR-EJhE2XeAy>c2? z&Odk2nb*@3Csba@3^mf1WAFkH4}nbws$L_yw-x45o>cHM8WK?vNc9rwG%3V9gfb^}&6fz+z=kAsI) z0$bxiJXbyMqDV!^T6+?+5P0TvyeD68H9va20jqROgY2q!KIFKxF49!qzXy13fta3? zq(w({pR+LqwHgA*cMURx9A3c!6 zjj?U6u;GURD@9B^C0s`nW^e<{k{c@Ld{hFoZ*WoiWBJ2U(>?|G$THXitj8FVBGHB) z`{v!ZHy(&?B54gt`o}bBGsc7|&B)P_kgo;7L4Dv0g^&&srr1gU?csYWLUmRu5w#%FAlxx)C*hcmE%Iw>e$#A z?xN$R*6tkk7eO9i3w8y~0+FOG6czhr$Jw}Y@9VLO5@VR}*oG_g@BW3&L>OmqT5w7R zQtG`4eE3A#3&etw{1+vg6>9+#)DRNc9bz(q#08o*37MmiK4ST{XpH#B@a<*r-7>gz zFxVF~No(}7VuTS3VXDpESSq>_oJgxtTmhXz)ZmHT+@uL~b znq|0reKj%CcvBc!#18FpoC8Hue@`~p!`2J%_o8@X;!Ai}`1Y$|(Jis;RbCffq`BW> zi^qtZygUWIw1{TGn=fXi5NHx$Br?$Y^@oTB8~6`&eoUl`vy+Gl|1xeAj%1XBzvvtl zV4Ogt?S$3$MEm-Puha0~d>OJ0NR;x1?P^mb$U4@h+F*p90)5qC!?X*$w@DVtSiG1M z$uS=Nm5CcyuRvtKk|39TKG8{@l?{r=LNa!S)$#s{0;bd?284qrqrA;3PP$vXGYV5kdTM!%ibJk4Pg9|K`7QugaUrO{`ngoVS&^0r!8Lq{d zlxMx_@f<|gzhm0%V(m=lXrIw$_0VQ*n3n?%vOK1YtT;QgUM~4LwK{vW=jZ3^HM?$1 z0Cu8XcmJS55V;q4BwIpZ?=@bE}V++8OPT0UZ&Mn{`}#dlQ#Z>9|s< zn^I}L%UUnV$gTh{FE2?lgl@zAY5A6o^ZUy)74I+WcM{D1vvaM*!1Jsj!Kt&tsGuUS zMl%l2MeHHt*=8^wWz&|xx4w#pMPLT6C4^-9s%Pu%*W^C2YYOP3+%k2K$-c)cFWIQm zP-?us;uLmW$$(ZvH;)QR5!dI~q#WsHjq^+@>Tyjj5+Rqqpt=X-b>!gMU^mJm6=DrR z=D-e!-JaB6d?`91N5iq~Z7sw3r;VdjO4QzLYtcf-AP1_RbqK>Ea- zBbuyM%!djO0FFy7q(?|Yr{G?tpcv#VcBF|+BoWWswv*o%?OUySzK-th_5b_=yY@XV zkB3GKCSU;O=w9?}m9PY=uwLXZQaYChi?(&MabOlR-+VcQrqa~!-iK6RCvV*1`!ww= z^`N#x$$wsN?qE*b1IL_9BwH6B`qtv5a_x0&I!LDKZ71sRBG=v<>Zw4Y_KK3{0vhfI zftm~2Hq!PrGU1lBasEERsU43MYQc)j@M~&z|6<2uZ(0?mFY~-nM_ZdXhKxJcp+?V` zU&5O4hy`lg`uiberHmAa8@ffw2LH0EJ{0*8%3gK60TygIS)$pCtU^DD&D|!QHI#}X z@{XnUE$h2OtlOz#ptMSC-k6shPI7~N+Rh(VfH6M>xjiLWWHcNeT0Nv1QLh6PK(x-Y=T8&a`3KUuwk{&qT?N`N z2mKmhg;Hj1YZ|Jt3j7gric!5}{B-0-8ndyXl*0BR1CK4l09Z2)Hnwsobb;!Hcb zEVj!cP{L_=q?}h2sbrXGDOH^BTc2*Yuv@W0bB~641T(N1e!W9QN0)kEq(UL$dydck z>Qxd00|P5)*Tii!ydMp!tq+}aS#Ezh7)tIg`LAX1;Nd^Ri4;#X@9z}n3DRn~zHV@s zebw#Q7-Z(FCV#Nz*(!E@Q8&50y)9aF+e`zj_IeZX3Bp#j69}+)6}1yPDv6OI%h{B# zEHEl`?6E+_JD*9K;~~37%k4k?x;|lk2Zk-OK#OjBgYtKbfg^Rpb`5GafRkkIm?mZY zaNimK3|eotSS`|05=ntj0jXAH;(kHRf6%Is^^hj#Nk7=~{GJ?r{KY5q=|vBRmDSbNT1Cij9m~cF6!?UN zg>i!i&ro6(2KGI@F87^Sfl%>I_44byY9{{x06uo9PT&0Ji6SvQug(ry4<*e-6V`j# z4C=Svg77nQ%@h4tp_0e@PFc*Vna@8wkOFQH;BS6k@boq?e8aWEcl9%KY-Hks-cY81 zn012zbNbUD)ofwjc!*u3Q{HX-PM|CMG9Odpb#HUze;VWl#Jc(uMacBuxDoMFoY%6l zKQnSI5?kdJ6qW(8f`|frM4m>-!gzA;|u>iv#KD>8?e$10RzirvYnXz3$vVnSZ3c@jK;( z>0*8`G}#QO?iqtAif=+wTw1UnuB1QbM)mq1q9U-FnE6gePgiaI+dYp^tO? z-QMZPeJyXnW&YPEpFyHox%P>-tkA9$2)h66QWo$k&Sc2f0P~xW|5U>WpxqB!!#P8d z6hY-##MP8Sj{ehTHL-#cGpiTh+TvYA%96(&8(S-O0+DjK>tC`$$!Tbe7Tu+QL#r$9 zqL=486U;HDJel0$bLlBq%{E}00YCJ;`n>_QjnF8hAraHqe9DQup_8yUJDS;*gZz4A zoZo)TVz_bn(UikWA9rhH6UFP1P^9gb%*yB5*dyiG*ho4hzjR@Is?Ux8Q_qvCV zAPv`}eBIxzDJzHJV|Bn5OOt|045b6e(HDaR=l4Hp%!x>(D)YIb+`3Mo-W?r;dBO zyk~5u710UWe{rxHfZwo*d_Krq#Z7LEp=U0V?-~vjk)eqadV{F>N3efMde2wh`u0_^fOdL`d}*Fwmb&TOW=^+pSNOub^l)iQLK?3PS{%%;lZFi7z|JnFtP} zGqy4KS^7!|?1~5u;4=o*spPH6p6^b@01^1T3a~^N3pASLFbPRpsaf@sC~Cpc3w`-& zUsFk6<&x|Cek3O=-R& zx~zyWmg$JFd}4*m^0&JAs1Hkqw z9Yr|kdf#U2s73vSBOj|Gs%IotP_T|W$(XqJ8UYf?T{H(B2s2IhSJRG4m+#yF-=&03 zVl9uArKtdU5QBpONQ4VLA*LLWo=suW7<(6SP0u-SthXTgDCPP1#~UTevKo_$7eVE}iwY!LYPyTKH zRNt8n0P%c+3s>*;oFB4I&Qe-LI6F$YO2`0JC0d!5n|0vPl)nUf zxKPRyjo3$#s{3K_r$9m;&d*&5*3IX-H3~z=FIsez`rupJvp=wQjKU7pxxVO=e;%fC zNsN&UnFuf!9Q!Y>ueID^OowaPzYsHYjduQXx@4bFNm$L8TQ<@LI-T~(WO}uXD*QvN zY?eD9fEc}jQ|24!aPOYDOaz`F3KPCjT4AFC+n@0@RJug-B;(%7@#K3M0e*3D^r9-p zJJoBenV_2ShTn`Fe)Mw0#9gx;qUpbJUHlh1??z4R;?vR2q^F>w{-MLMz4*gulo^EE9a(61{6*#2fCGgeVo=c6@R&zcfkKpaL}_~`Z);_xRqhr~(IPtn3y zoVjnU+l3|USj19myqCr5!FhwLETg!n93%rWG;9-?qmXL0ta`h_pPZDnW|9OL9~u-! zxVH#;I&;cKF?mX)NtPy786-!)iJvlVueM^mBaW2RoM`obtw;f!fTjBRaVmK#28F1) zR%MTjTcmb_bJ^%q77$knlz`J*w;N!ncGFJaT_WUnCD%g0?81KmHRW7X?|18w)vYfF zk>e@XDuqF`S7Siz7wlk`g-~vz7pANvJs%dc>XbgD3Gt(f=$FVM|2*XT1l!wq5vo)Z zu*oEC#}O%E5Z4JhU7QdaOmH;^D{GeWQlDwN>9FU{w2s;&gk29#ekh}TP3|*x8@B>y zKD10>BqP-yJxgCh3M!E@)wLGw3SpLIfj{`Lkei~@QhX|$Ab&i3=}RW8?@k|9+7<`dmdn+LS% z+Dz)cJGleIVNV-{RHXFFgBWf>y8C|;f6#e?>KIfdvD(9DIE-!Dc+8+qaH9xbP3M|&~{4uL3DN@ZUG9kvwN2@bOr2;c6PdCTo zHw2_}W=)%FvSV0J#c&@zFbn(;I;_x7Nr`U7`0KN^)?Ile-XUG-y7Bu3(zcCnWq7{| zt3Xd<{6V^~iy7_2{S`8F(tkN!4shr6*H5=ba48}+v%}u0zzK)DL;|C=45Nt*KWiDr zSX6dXIDXm$4w~X7H9h-$hs7*H_BK1*?F^wi+zIJ53@s7hi3B&k3_)0aeeVt*bxmfn~Yjtpmm2ZA{ zzr%RpTQ2CN)pDTdkh@e7EA%(}VJ(jB6GQ_PmRPqP62mtZUUw{Dy@Dh4nsJ6HB~s>P z=pWF4gEm?}5j}qB9j&!6K5&Wcxo>qa-)OFuDc^lYPlYZ!2gkqU9fG9y?2L?|KpNrz zi7e9Jsi~-_yn|{-L!yCg-ntX00#Q;uyNBgCwvZ*d31j1C1V3HmOQTOjmoBp6Q!#SN zL2E|OG+|6URJ z7{qo9zgPy!_P0u`F%Y}>|I`z<6Zos5Q<&Hc$qG0l<2{NW`c7xY zVP6)F$T<`9icBH_J$CDv!0Xqqzp4O`M~6uv&I0ImPzKK*Lv@LCBSQo9gm=jP{&E# zTPKY*;x2bXWvv)m&do9Kn%yJX-^P?1+%8zL8T<5Ykl2 z(ON1HYd#SrfNC>9Cv7*34D0g&(+qWH*z}-0Kh>4OP!OuSU^$h@{R4m#lXWm zFs`+D+x+*QZaSUUeA~4d0_x{ml7j4MQLLP$$oS;;= zrzcp9z9F$dN+OT(Q;l!vmn`dE5kC1>H$sWe8e;fy{^yihvDWkiAz0NXjazSbzADY< zziNGvLy5KZL~=C4vGG=B;yx-U&c!lph)pNxMK$Mxe$_x*zP;Fl5BwaiGvkxtKS@J-*zx48?dg}vn3SLv01e)JI zzwnVX)Fx$YULshmznAaSkjo4fEL=B|H z8Nnh&TQU~$JpgaJGx|MDkj4P1ba$pI&#rM^N>IW_cELf3wG6WRe!0Cp80>GL%9?_> zrRD{E zco5$7461Dlo#b7Xlutsg5eUSV%18!5W71)BfPqh*zTSwt)GRbPbNkj$49JVC zy)LNbXQuf0OI9;RMx~zgIke@165Nb_C&JWmuXDt_hIwer?wSvpw{o=so{U%;o-0VW z>dOj!d3$jWQ!3?|xHsg6Y8yi*F-;D?0AR_@cwhQ5cRM0 zL)|RI*#B65O{SM_ue3Nff5_^VNE$pr^g>QeV@aSe@Z_E*if?h`9Ps0jTi?`He`NAC zjpSoRE8sFLRnU(P>6Zwnz)*33akY321fx78RIKL;a&qMO{14hs6?FHCBG@^8N8}kJ zGZ3e>Axb$X_eR_HEqV6eFBzui{qH3|0I_;4JvhjX2J!_RxYi0>R;G@~%w4LQ3=YN=TpEcdW z7xIbcE$eyW;bD&saEl(8PmZWV`{7|LCaTEs@CDoFFfDS3oL;_j$^ydr9r`gP37iTm0F8>|0 z`3;JUew`Dz6k%K?Ni=#G>3gqp`<0jx0^uK8*ZelzyTQ!R>bW*wDSR~ONt&1igMWJvffy`D0M#lWu zsB99#%%a&&yP#)Gj7~RF-A)GkF`L6H)b*=a*|mo7Le%%4CbA2*(2C#HHW^l`LY31b z{W|^(P)hjn0||=z(vU(2UAo|{YLueWqxFWig@wh3vis)PD3t4-yl06?I=2PQZscFy ziKk=zQZ}gGk6QC@v-kMJ@1+(zzyDAx9fHIQ6eM+qAZQ^#>z|!`x=8yLi7Jr!oG{Vn zVdM`Qp^N@LJ}9amqeDIK{gY%L_-oy0hfg7F1l+crX41ob6mOW``Qr(AMRcznw~-MO z6Hjym1r3I4DCzaZ(d-<1n*kY)r;O@-!P_B~Tyc@QDC)ByPvhD-y5lKzaSld))w=d4 zB~lOfel-l^OT|vBw-|Izsyk|$s+m}Lffrd&_ko;OUHn+CW#EdImUj5ZyRu$OfD3%6 z>7&K2YxyFOSsxswO>9CzW0|>0M0z_u{phnaz;Bpsfb0y;Z{{Y6O0Bne@BI0cr)T%C zZBpc_W20XXaA?6yA(s3@vvdm;6^|(hP^EcjXsBQu5FsB-;A4zQox5+QZ6IQdul_vh z-zdnP=x_IlK3X@Xy_2*_LVvSHm#c=F|AKQ?GXcAL;%Q#|_z&bGt%j9oie(kF|a%{IF zL1w#?r7iA?lo5QIpRnB*JLi82C%CzU)FoK$hTA!QS*4A)4sdop%5Yq4(dWu`v?5|w zvlvX}+&T9(7pEQZ2hDPuL`Aiw+B_;VK4TE2s(<5VB==lTF7Q0aDxX96k@~T@cxlhg zK8b8t*1mFbhvJ|=brr?>`;RH!$wCmI?J&SCIQjX{REpJdILIKMIXO6D0nS$|gU?zL zpv)UVC8<}GjEsywOt#LYq7-?tGv5`wC5lqSCHzd37{dtJrp=vUXMDT~!qFF$D}75V zOh(j%ndbQX`J|8Yybxl{um1PZ88_lLE&}Sul6tUBIl~y?HoCY=ZU?~=3%&r-tTeE^ z9a2t%(cOByr_$^G=KP(hscCHAnm+!w>%sWu6tfw={kHL*x_uw;Jl-rfibraC-q{=VZ?gsk0CD;VIv{=3_2*S;@Ls6iI%jiws~O$^tA<@SGbb==-3f7*rY zXAi*c4(ERTy(l`^lICZ+k}eF|vTur-MWu?`Wy5btii(kQ*@}K5*jghO7sB0)B{4vw#abQwT zV+}B5rNFsG$O|Oxy+^GTsLjbgRnhiR@P*1D9$Am@%CRkvKJG5IRV`IIBEDrKwv;QB zC7lMQbT&N}_5_U>DpUdt13I;P)#5(%A$=tcSPV98rY0x9a0jdF5Z&wAwc&ER<|byg z>v7GPKSr_R(R7c8i7B#v`oZ&k%OZEW$`&!?4U#4@L43MOXkWzKpJ#JqgoLkIMMukj z1OOP=A>S|N1jVWOQJi!z2CC? znbFTIHR6atb%q+vu114lV2NDZg4RQLbH>VJrg0E|FGA)K*d2rzRSCQyD@l3evsR&+ zJbrY6O8V%o3F5}gSnhYFP-d;TC<^nf-a$axEDBX*#{XiySf&?zlMC;ed8 z`$mb!3f-xP+tV*nCu2^BZ;P(jtl-x?0b!wMT4#JxSBT2i*I$O=xH7a5Y@~Eg5nPhk za+Yu@O|66?LxTyM-@*2cr>`Y3A~k)3qfE2DnQ1<}mQ2lNtp1Qsc=x@VFk5yK+CPae zQZG+oJABDW%4MKnfjg{p5lncG#)BKsI}qM%%%fZ#1ix9&DxXz`DTcvs9ij&*ctofU zLuCi=$lAX)E{8r19u~iXlnX4OImS9+wGB=qZ4&PSwn3fp zd>iRs`V)>bF{cI|YPkCDn&9<)f4^q#;ot6QbsB=B-HCih!2`SZT&Ko?2SO{y# z{`2q>VtJUM%dXAN7_>?e#uWZ?u%Muzxz5{At}`JXaaF{bTzQ$$p!uk~w@S`rhAdX) zn^PnLdT~v*T;ROiyY#V!|KhW{B321%tKaR@ckCFnVaNMa7_C}_LyOpkJ|R=@6W;tp zR*I7&i1FMv?`W}3<%Ry9v$+>c)qIW_AS;x{Ig-Z9f1JS5+kvnB_V0k;rP`@jiCXp^ zjozhAboDxepl-!b=g^y+r*ASL$RcRV7JpVch~<4AB|Dz^UWCAXY*IJh-xna1^Ie?q zRv+UN`b}ZOSe=%-ZM%C@xxVHzT^P(K-1@)4xO4xjALzbmP@zV65Tct^P?V-?V&53~ zq@%QsyW&g&1E$2^v=>S^Fh zLmBzm9Q^>tu2yL;KxUK6P-%P9}k3T)vutg9Aydk^% z;EXo{d4qnj$GzNU{IMNU92}H(9>i`HaJz`iO>oo5PCor73^98y@eUiQ?Skyan^SiP z9Zw%WQyi&w6nXMJZiFbx$X`4tMtzTTyN?$U&yQ$hlMGa<_w8lH?bB_DPf4%wk+9 zA8c#j_xx7<@}ND*TAHiYr-z*F6_%*(6_)VYi;ksJqFZrk(qr*$uGZo`t?Gf#FLgGZ zmDr(F{;Z?X{#op=^)*RZcZ4x|o|g>qdDce6F~d;4QGwyZ!{c4%GKDb$d_Q3{4pM-s zV@0K7N~z=GWT9j>W0r-YVp~C0(5RG8ETpARM5lSV;U+)RacRR*xc{N0efqcvU53w? ztY@1{4lF12B1%UCMgN(M6fI-$w<}J_T%yk3Gfwkiz*m>OciQVkoJ=u(#$i)mIzwZ! z5x2igUI%zJ1yT8-N&mq@Ue>5akfYHWV|Wx{;H6{AML?vdk&48dXwb>;i**ZgDX?;9p# zOg1QV)q49#lv4S*1Z1||vdO$2C0S5MiX^=WQoS)y&SlVX@A!izw(e_@R_XVvyM;iB zd-vp7sp2-aa}!phefMWi8WQ{q4sO?Y;#GoKt(iY12%tv}SW?TzPL|yom&J4G!7;mKe zcc~jR@1B1aX*E_l-O`EEnpfpkyS+#kYn#+GZk>&j4I@@Oa(~t?njmau*^$(B;vPQt zM417q#{h-W3Md~x8WX^P_f_ASw%0&iUiy4)iF;vaPZTo(U0pYPwY*71<~`{_V-QY0 z@*KZ-Ntkk&lL2}hd+~f)#D4Y%$plMBzXR+zq+~NlC#L(G0tF#UbyYKLvqjYlAQB~t)yNfY~^Wm%o7%Nd!Z)e1O9-L zNg?@d^VuKPNZ>+^pPZ*RB`~~~XRSgUQzyHQO*q2{t*oPuh=)_RVVj;tTBk-5`FXks z%{q~&=y7TP{?6I0F!EfBeMyIM*xoeNvKVHJl@H6ogaGp521$(nO>}g{e-lc8xonNd zOAj_cvmEFMhR4&VY4WUC=YN#X`G_(Y|p}oJq-l>)$N#-S@V@cPkvA!rs6*^P6t3RM{w;2oB?ijg@ zSh}uMzn0dTZ-d(`^(yYZDX90RohVCDwD*^HKHkx!$}7BZe=Sk-Hs@;fb8XR!h2J zEdvz$*7)&#)5tORMb^En!;_Ruxi}SP2n&V@zMYU*I(kr0bNYCVgjIBDCmNx0!)o`) zJfAngy%9zC^y!$F!8N>%6V8@mByxEL{b;9s(RUW;pE==44=e@bZ&aC}RTN zp>S5{et4f^8@-q(_FJYA?jNm0F_+MzW@ES@Sxgx8acacfUPCCi70i5g*WANOfYim9 zjeyg-zm`7gn1``pwdmJ8KP;!E%~rCXkNU3ci0;;y1$)27AEYt_?pM)(B|9O5=0PX6 z{LVZ!=`WF$bah%uQv01s>>-6pww;xzuIu^Mo}s}^ZhuI2mBV;=wOriy2c+H1+m}l+wH8bS26b|p!7NReA)Tlhdb8C$=^pqcl9Cn%y)aIM(hO5>pi2_dlE16no+!R zD89e!T~)_aQ_Z=V%ekS;byKTR30)RLTiVMqS{1)vA@@V}-FSjWJdW?Q%kE4hnuN>c zAW0BAWHtI+%7C2Vtc4pwLTgUw3)s5sJ;5ygDmzuS!!wEQFvr+SvQ_pe#yf>S?hFhJ zN^rPvZrO^*p|S1Td;BXM>cz^e8v;=g{Hcxl8p(>U9_2x z$iiUpb+dFJ%428{RYMdKhoks5IU|1Jq0-HB1{;0>|`g2F8MCjtXSAtOdMU(TIKsksmM6-ded?@G;j7Y zaCP$jwS98lc;n0Na{1T3GddZU^%)-;tn@aq`%9v@s7mkj2}kk`bY4S7mbrcl0cZ{$ zPa4An_A610!m1LiSq_FbP?`|gz|wkxZYyhE3xCC{>>A)tYbB~+_Sfjum=9Zfjs4;I zchR`DX~Tet{{zf29ssi}>fN$mIX19$|2ytG_aJ@!IA+?WmaAD1rYEJ= z?Y|gqkX4>@WQDKRWaKDQ^F3sB`-$d~vf6fUzoNaLtn;EyApUH$R0IE05XrnX71Y&b;g7c54hasFD>KZg}aU zl_wWhMnD*SKSeETo(M2H0oGTLfHDdcoG5F9V8h7-!|{l=n{xC)lA)nB*R&Y+4>83d zF-xE0q$TAY{1WC5xf-m>9FMNrE!J1K`x%P+jCGjp<+Wo&bRPUryvbslEMw*tp~9`N z%KU?GEU7OiWO}%LV-1Y`((y?Kx-QUg`&12%rf;I`jEm`!sL|AptJa|E+OWGu*+Vyd zn8$_eRNCF8tSZ=^x&Zck-7s=9bQ1A&&HS?KK=Qo^KJU~xn8e{3U1{HD}1 zSQzugL^1!4&2N4qh%Y||W%_LC5A|>ZHZJR4X(_v+SMZkuW@eP%x$ za|LUs?0oI5>AlHXb5GPAH0VP#7hR%$<1RQ6GoeVM=X-hXxbkGeTTV{MyYv~(MCc!zyE+@Q`bmQUM&;AJnvQM?i0w;6K zKp}_TNb_%rK1-cWSpBA1JevD&dFK8bt&HTk2%Bz=u;P$w)XC^k)|yML?%jR$-OS?g zR#jqrpG{-Ydd0&&$|45ac(E$E!zt9c5FPc~qXu;hF6Edkef%#ZHDg9w^;(#>MGl8IE9Z#p7CrkBwA?% zeo=_@KwkGrU-quw|DY;J3Foe)y?udQXn7hf7Z))NA+DZtYBbN3q4g~mYbapl_Ti67 z+lpFWyq{o@-d8E3*rS5pIER(551)DVy>abpp}W+^0BNx9<3S(g(NuYPEkp4w`=g|| zYiUORC?;?qIQYiRU&K1XopwcBHt3CRelXOvO$LZdVKGcanHsuD-W|M>wZw7iLYc<< zllEHw~%8iwv(BrDa5_8;_|cW{bm=vZp3GFKN> z3-CBj8HpuN&?Z*OZ&<0cuWIpqzg-OS6`_RtTGM!pew#fk16dwhu{8Xs6naxt9(J9R za&^7CJuh_n~VqR)U}cAJTxd?7vKJRrw+jgh=nB1>l%Lc)$>Z66rk#;@7;M#jv^}oaX@zK=beecgoOlQ$NF0)8aCt;@W?yFTilM{++J_Et)xh*<@{!=XZ)Lv> z8+^toltZCyJo3re4=f0%dcqf^NYEnwk3Of1fRrn zH22CY(9v(=PPGt^fOzZkrgS#yQh5F+c#`f)5*}m*p!1=0_ zSfXOu>RS4gkzwIF#__$=xt+__^?I#vKWBNYv@)ZP)bN-qC4Z3_AqcMHgWfaKyB*?1=XHoV}>zi2$LI}C&Ly7rv2@pn*-RoQA8 zexXNmcKxMbkznU|!)Mh3+3Z37pZ0Brc=v07)UDQ?A9 zW7WF4_*wH>>JS%=R`49%nMyUc_T7S=?^m+(Y%Bmw z$zB`+S%pv|A3Sx#*KYjms+M@{94xO9c+f!Rfg1MfB82~S*LLmHJ9SX0XuyQ2pG)8(Yr z*-s&DC--d~N#-XYeLd+?F8{)w`F6gSv);^7wU(T={fi$rU&UMBjukbC3NZfq8lMpP zRY6n)qlO|%rl8ps2rkL8 zp!%eHd7{Y#S%akipxCQNC`Kl4rEC=aY--Z`GhAA9RbMxel*RozL@KSXUN!Y{8_iEL z*5*bQ@Z7P`@7}0TdXn|-P;z2_iS=|&-?*h?xSXxVC15q5)64HQRgKlmaeB)i zel44!>!P36($xrqIn6(R^aeCaph$+OP6RSme@H(4eLNyZ#U;aWuYmTPh4G)~g*MK} zGyCE>{cHu-#>&HJdH(|-yi@Whn4snGK6z-B3heIi zp64t4A5qNnM|gxd%kI;5WdEK$VKazkWxG$COSx}pDO$e1PTt>rQ#78_y`7z~Gd_|b z{@!E_%iU(W#o81>=``?vC(aiRYrCAjp+cFi5Wx1`+d{&OX zs;>mKjOo9QyzQaYz3utB(WCJ*+3kG>?}=a1_v@AZQN_1yG#1&c*qVEPrEfiHmm1D^ zMt9P*obGkv8O*fNmdSluY#N!_X*xs;IxaSm|^k=tfzoI5ob4Fm>$Jo3C@WtGTisH&@1aS^jJ7 zacQgloSRL0Jp25Y>;K~dTxYZ$%wHZ$c-~2jW=alf2~MEZMp1!>x_tuT$!ofdcSw$l_^0q_-EgPPr#1%cxXD|q`_#RWBG~WSPX9( zvJj zSvut_6X21MB5N+s7hdcY%0^fZ5eOb8HNzh%u8K7J>e5mh^sRhf?cvp6wABB}|Ap~f z-qEXD?HYeq!O_gNudA!8;|<4T7rSMhMIAZaY+J`W6jxVx3CE{2Y*Rbpu%54Dif)%ALr7|2Vri*ur*=n`*sXw{}F19Ddv{@ zL4#!50nd{A0mZ%RV-eM!OsnZtP8_c@s^I44)4Z)g-VJffcM<`R5u^*u4^rBV!N)&C zkDXJgoTVntEi*7KB}ZInqg;h3^%guRl^dUecHf)!YOpn%aM}8g2^qDZmaMj@T zOF{~>8tK%NAnVkOS7Vx<^ku8CoGo{}G$MrRS;UNHkKaDepevPT;+9ZB$*6s^rTB`O zUgq4_DwP>TNu0l?C{wx44AcGl&MBt(5urQ{FP78zA5iN;AADf^lx*L{O6 zy4YWto0rI(NQ+#MJb=Uh0a;r`rMhl+&^&f`G(jiYh0#{s?{|Ao@~nl3jY~U}phpD{ zYm5(l?3aeTlWv{LS>`Ij9H8$c!YvxEX}MW&IwbM8SJR$Cp7WceNZUv5Iq!Dw$pgy4 z73y&d0ih#?E+^qtuRU7qV)8F@guQ5R3xUZ$C)kvcvhY6hd)&PWI51YFQ=aWv;ulkZ zMJ)u^iva@C>tpngVTcK`1V#L7$FBqQOZ;lBI)O*Nv2%~;nii$%ntYqev8k&+M#<|N ztIYk}Sp3n-B-q~YJ|3GV>)0vLctybfa5PBq(Q9|ob-yoz&SA$+!N&(eR@vzj_FsR^ zPXSI!Cqc~qt#G642dTtO6;PiS(1Whb`g7zJw`I~`w0nY>Dq&F{A;_;?0sXNJn`iCN5p-d^!^A@zmH?-A-Y@$z7aWoxlVW2askR=$tP@VY;ADr^Q8lH z1CZqG0sUl5zyRJi^$0e`NEiz6&H^a3#sOO4M;e1%=Tt-hniG7M`L2lPl-WA@epHtv z85zdPBKS(#NIISUU?N-zd(bX2e_f=xI){ckg&D7)wzX4~b?P~E$U2}kJR)nrtGq$a zzhqQ7FiYPwG+gze-asx{p^jL8B>{W3N>WD|$y7rR9lkxTbx8rJxW{6uJIPcm0`C{WGbWH?{i7U0aJNHjOBe zvM4^I8-9XZ96F&fjYwFZA7Q_F43!E*Z#j)T9VK82DlHHS2hA83=ooBW6ZzW@Rahoz zjBTRdC|KQta-3HjW!g_`?r{$uaiqOz&v@1z7vp4Af9KKB>tJy|C%IYb(A12D07Hpm zN2iRG%T@@2!A5QP@cxVU?q89X6JFhgqdp3Om)Pv@GAzz}}r2m?N3IMbhRe==T$aN5?*g`lFM zmH_@rB{1j74hq`-{bTPpGd9nRaihvNX!~RhH+x&oX;fMcohs&_-OtZhn}AZGQUH`2xQZqy#|ZWy7N;*w?7 zsYJ3lbIKmo(kO2I*zxsa$Mbm5)rNTnPwo*N(gMFnB4ucaU^?E>LyZV$_Sy(r{NomI zLppyAgSnujr2Nq6dwm8Z*G>5yY^*y|<#dBd-2Rh)-Fhg45BYosZw38c0*!GAJ9MzC z?qmF2TUO}HjP<@yA>S)EPnV0-^ox*oR_OJ9_a!ZA(VKB(CGbrGNueOzog3rOa=nTeP>%^D#S>%bR1`$azzeTimD=8vLg!%4j?WPR? z>lk}A(j<_5yRU;HUr8W1=&24EezO>E*T@%3S&03hKvw<$o9jT;w*mfU0hV`3;(3s@ zL6q!Tr1BqV-z_gm)t7mf+jW;CTM*)v5G5pWX52XLg(zV<^7WkJrn;Br-x(heGnK|k+DJopfH zbYxS7`i%^f8!5bZ5Qs$pWm3QzHxh+Dis?k4JFgC@I_eOrpE262Kgc-N5Fh7D`bQy{ z;z*+t$WpElB1ad8|FWDX>}e3Z#CoDg3rLGwih+w&WoHO}ogvFYRa|H#vw(_Ghyc)w!j26mQ#pS z0kWOLKe{N?WlRjeFw{kAq@n%2!MV>}~j4{xTg(>@=4yr*fRg<3Ql;Je`a zmi>5^9U0pzU>+lYTM6aG9P;p6-^(97E%2?rT;$=);ZKiBxwDJ|2G+`lHQe6>PCO=0 zBe|$+;FczXh%h6iMI+r_Lmags9`WcAUFF_b7ZpeqoAV^59xbl6AQv)anDOJReMTS< z(~B+M23&CUj-Du*!PV~YUZ8==c$v+PdyCeTA6Cw^ykR@%n7X+PMxS#vVH*@!E)B`M zxOZ2^@KfP|CA$(ijjX7ysnNdsgLWr|^F9rw^F=`RTtEp;fQ>iOX{+OiHiAm#gzc*e z`d3}KuYGZM{p+uH2XCmcnbXWi?>hnQb@@xOR; zIu%j=#Dus&o`?s&2??~*3P_bl61ycjG(c)0arywxO_?yLT?JfhrXa3-8NCovM=a>24Z({#|Ph_3Pg$L>o!K zu6N*(SzsPj;PFDhrE-AbSirY?2sO$p8mx6+s$_+Lv;ev60E||QyCLj<-gtj5kPhC6 znk?|qZ)uv;BHu}1bP;}~5;>PtQ}2+c@h$gwOogDi&b@rBElNDLn~LVW+Pvx7aEL!8DA3qZEn0iKLPsMhsd7gRS05u@dTWK~H0|BLG%low|Et zPhnrf{V;)tUw?;{3~qejW~A~5;=m`XYvrh0 zcW+=lp)Z{jGq3%g18@bX0Yt}bjQ^`a?jG^tti4a-dc#4+U-;``(+#EY_ks*|*1vG@ z&w;^oI9tO{3AA^KofHVTXF{>7%{jh+5fEI9gt9J6J zh*3wmLNEgWIXK;voEfmj=>XN)8@yWqAqbWX283j}_&8VLej3!Go*4qPG(Gz#td68M%{uF#Y8`l!I@vY5}bMln+(O&Fl(R(FK$Vg)k}9~P07~Naol^%;6f*_bKu*g4x&gDveKJrJxk{IlH*48WSC}^UuFXLF z`xE9Y9$-bV3Is7NkD|O4eLA(RnHsG1z$62)+Q6TCe`lmI?#`GXGSG9>2w@Hw))%!Ru^5?G}YJaM$I-QB(3n)nRzd)8}-A zUUD!OJ#w2!I&g2jTsw-HXazgU)=4yDq!JwE<3(CKZ}tC}l1qL#vH0c=E>h*jn5Oxi#40yPzw7MCU=69i;)B;z^)$arvwV5xGQPzq#SNlR7d03;1%=-9L#k39P+#JSNRFZr*Y}Hi zX>B`GmCJ{-MjXJVEqvvx(n&4ql3sOn`z5mk81D^$=y>aHA}Ac3qYUGMW99=wXf5d2 z$i+PeJ5dF=;hh0_T-6P_b9o7{zI1Cap@cY*ORCJDU(}nvSG4 zx&3vX8zf_1u*Bo;7#fHVXa5wUdym5>cqa|%2>5w!cVz#aXR6DXKRW#goDQ4 z0*5ReAb)ro;G>PP9kOa7Ob zVB$j3gdJ%ePb2AT^uSea4cIJcLxLxsDei-bb_J7IC9zrfyXV|;;}!i;?RuZMgxuZD z<*7u8W(3@a|&q-;o1Y$;7sdZLAz@Boq?}m?+;p%*G}cFdtR2882}Db(AJg zS&2o$mJTw%qXA9b3EY&N`@x4#%w9SQMPCwF6CwRT`C-*Je5Bl1CHssjriS!dm0;kL zUr8pKTaw*~CCT$Y$nORZAO<+N`JbZAqk~EGMC9o+AV@z`p2RcSxUX06eCvCER+Jtp zLr{F0;dI*2>u%-6{fA{fn1PvTW$x2mNdk!*iQ_OA?jWx!6Eo6J+T^(0ZMTiSgHP8X z&bmor9C6}tOZa3#M~P;)4h-a(2gyXeRgTAs9Pty%R5A<&^u<5kb%s$8VV5{X{aXy! zI7a)0M!=IS>L@DoN9t&M?b05cg(o`fKXdqCPm85hnE#hJBv1J*hsgO&J3j4TVcF}< zJ*cNWn#_ROe2v{kU02*OWR*fonwRsDLQh$E%*8KTD!7oGRjC!#A&3j)Mf8(+~U z?U%hCzF)vEoV;t=dDVK3%`u(sX3o+jpZ3FSD~eM$8=e#pgqDVX9G=00XMG1j0bfmQ zw$V#f)owQw}!Cj~Tl|?OuIXPN@1MUH-22_4i-z_VAK`(5(fa zJBi_mKPwxr$0ZE&9_Dc0ZG6P(sz3tPYy<#m;WX#Lkjm*m7W#3A}#xmj&&xI!c zB`wQ$PBZKEpg?tA;9)5_&A;B&9ePQx%XDHE$wB|IsB-_);C19ioQ1@vViEC())DX3 zD#UY-Nm`zjqBS!2kG069zP)q{p}7+DAK9wsl2N}~nPViLe(XEo@s1!GNFL$XMT%)5 zy^d;YHWmpH;$9_+Pr9X9N{hBcC)5mGAfi_7IWwQ&ps&(Yb)wN30vICla*fzxYB6Dq z+#NY*-G4_98OS$MXxO9@W;MDB#fhM>;)kRf(Da^sn%a4@)Zn^hJNv=#9D@SF<9NKH zbKV!R->payN1#i=UO9D998Dy;|RzzxgwQ(^(4t15j0_|IVK$6VA?H8_$GS0UQicNbg{x3(4x zUqTbSBe&{lH~yj}7x(`xK5yb6zD2fuzGQ=goLqCIK`rI-RQ}GYbGk*5AkakW&TU%o z4mg}tL!OsJ)ot1U9*MM^quxUe*Wj8CO4`xuLb$7o0kGTx@$6|p)A#Ur3!sS?4YQYw z=}g-I_tF=VkIP+X`V+mt(>*yAWs!J2)X`gEJl9xac!osUM=}(_b?-za^GRrx;Qr1O zWrq&~@wKScw1YQ8@i#8Mk|%}h?Rlp~U_$odgrs>A9lkZ9eT7K0*^3sLHgQ*IFV!sK zukI(jX}$V2@+iB6q=2;CCZ<_#JA$39dT2$D2b&_sW5ZrSQiRJwxui}o4#fzB#ZK?5 zpaK+12z@>#zzjsc;Bj71K$H@NP6aP+j+t1=hG{n|Ql_=+2d>4K&b-=+4MD*GZA z`$TuWT@gcO4>UOnE&gVw$M;jXQj!HfJi#}4Vn@g(+>Z zuJ9Qhjo)ws(8a1CvzWOz3+gaH_pi*xJ0H&c;S5udLqjrsjuZyb6!q)Cy@;2dUPh-y zm8sci|7>re$#`reDP;0UKuG{5@-5mC@3%7Qq!4F66A8s zlEW4@ej>0;zGbQL+>b|o`HEG%$hKyUb-J^EGqP8`o0u_{9RG)$c$Cz_FeM+Q=!)rVEz7TDej z;;c~z*lG6~xC%n6#^|zt|1Vtu)b7+2oZ{{+?dDYvl42*ZjL}@pW>^KN-6KMVo@9)qEKs|u>0vsEUN@&Q%G}h?B$RAW~ zy^!fRezjF4F>)?w8|c6=ERduyS*JY!3WQ!Tm_E4WNYc}rsEp+)$2shTn$6T%%WmTH z`6x*6Z(4lrDZPBBO)#_Lw2X_I_)vR|(Y@KB^)>IK6&$H{ zUZ|d#7h{XBP7NI-^-VTBRORZLYSPw*r6%WH0{aDt*07@wYpQ!Ku2y@D zpFa79Klz6W|98!FjaLQ#XP|4L5CEAOeJWF{Bmrsa(C%%g5{b|GuR zhW+JZp}?*4-dBBi3NQEOpYER@dr7_JOYz=ojuTg1Ja67Ac^tC~Jz^*H(tzDTp;m+M zcUy^Lf}lqw@OgXko(`~YNeA(VrbQBBATPX0RfJTHX0uKqayUlrr+RruEcTMUbvREb zqt{b^C`vdIycmFoPG$V}6u<-iprdF!NAJ zIcZNZ($CLd`-xrL-lfaLQ06BMJ&!(mK7UTYH9>3X+r zs()Z$+dOrXWlVr9EidH>6dzoR-|m{Q*;?EaL65${Z-C~74f;3FnoB_06$Zu~0!&b@ z*vQ`|&+T$m9=`9HBuSso7o;M8qD`A19zQIGyD_}O?)-?GG0GPz^XU_x&Ch12a;j}G zsKyhqP24ROG{Od+mG~%y^$F#hy=Ecau+o|;dy~*!1O*YVk1vM}inMXe?XeeY~nvIc@BK39v<)j^G3ZEz%aYvBb#^rv$xBX7+yLf}U07In z&CbpRezT2-uy7oj*B({2vo!BA$T_k^Ciu#ur8ZC{y8JuOTX);9@O0<@g=w&${p^W( zKV5Twv&9vp);8IgxAD5`b2G14j&8KDq$OMaiQRK<1aNt8=6#Y8o7u;>_MuXFO-$Ru zCLr@?-ai35JmH*2vg-9E#^ixcc)+`u*NeC5`k7~1%BvxkCqhk+YwOlrL-ode{?M_O4jGHy4i5(=;#km3yqCvO73=>K+Uk@5r9H?@9Tm zRaeliXtlap`Ooi-NDBlh@)X+S{BN~Oy>3s~W*iP6$)bN4YmzEU5`l7KKfKZLX>VG_ zf^(Rx0i-!Du!{<*8(S-8iGcs8>;23Bf5EN|AZ(>Rl!5(2(%)Z+uJP&mpDZx^MJcJJ zl1=;5DA;%#6S2Dxl+hHmvOP{*Mm-CM=$6|XD^wg4(nfP{g55xREKvK5_>KR zY5t&)KmL_@D;KdgP4$6Sj2N|J+WstWu(ywg?)UDGbnBA z{4J`?ryA3Jsveh{KYAJJ!e3em6zTdB&hK}Sd#+>zC_5|^ zF7wz;Kge%0Qg8??|I|XW{1!`EQH=EcQlyMs_wd6pN9`0AdE&Sh^qo_0H%pu*wpXp8c#`gIPz zj}h_B;apIzroHj!gbk`Nyd<^477qQb<(4%}fGOG^u69RJ#ic^q!0!yvPyTh*A_h3n z<(Y`&wi^f5=kGTq`wLB;m1m6o;pO@GChOyopRLT*6Du7T9^+^)v>GO=Ur<{sP^Em) zb^6O4#JXcu6;21Me)Q@kSy;|tA{8Y8<`$yaqT~PL>@CBhjMi}Bp+!niq{C5^?oP!4 z1*E${q>=6xM241b5TrW<>69+Xp+RYe?&e##_x^sJKj-{~Yun5}u3GSEy-I!L8!xHWX zLM}T;LER9-Ad<+gU(@FjXiGB;d1XS#BWsX98r2G{EQti9H$5ZKCkSXx%eF=W6)t?T-Qc^4_$Y47C@ zp8Qd&#b7IQ`Tg3YU@ps?ZTUb-@w*gish6hl0TSUd+FcxBhj?luv(Ap+TQ2FJ)6}!D z-e`dWF+ZMxsvFiD7_)rom{dRL^tIEsj2!b?pf2S&`%T3KcqP+%9ahyA z&bNe-9^2(wOaB%#1=Mh7z^y!*%l>@+6wkFW3ooNGO)?(&tG2Lft}=caeZQ#@wEc%= zO0=2}DjalT<=!Bh>@`FEUwNPW6HOB*@CS)!9#(jc7amj+CQk%MRIux2x zwhn{Z5|gr#C4mz2rq*e}Ts&O}1wmqu+u>^LHwm4_Y}ea*a5Gd2Mp-sz=R4SRFsKLD zD#K2Kx*cNe<~Ki=AWx5X7n+O0zQ;=c4kl*GGoSWBaZRO`m*|0aAD+0%{%>{e&Sm*} zpw0Ys*#?jEvYx8hL_^TsQ&mYk&!%J_;H5#%yOQH=35DJHw;Vz9W> zIdo&T;ythFK$wxI^u8;Tpug&4*e_+`H9UJQvm|Ht!&N2TSM<87+tXEjcC|X#as*kK zjF@p!K>`G&ST1?lK&NjNm59HvJw$}}@lavZHw z3}5t+XezyvPxux0!~oVsPkzt1G`qtzh4DT3b?uv@wJ21n4YK653T>(fH`Y2a&tkFy zwpQ8Pbp-k59=-l<5an?|baEfV&~f<)55uIOn$@J)owk7rO#a{fX#ov~RO+oHP*1pC z`S!}6v4Z2b7Qv+t7*XZ&)cBJfm-dTdux9%tFeL>8G7*0vt}2q)R^ z0XgOZ$cbWy*)kQrDzjne3=sKuc83sW18~HnVNix;raMz%?2)wv2-kY9_c)_!?Csek z11!}Dhw37?1Pn2;#;}IXo+0#F4T7>9Mz0LFCc8}&a~}BP%^dw%Hm0b_Ql}>*>gmBS z^?l}_obzTBuT1ZDg)S*3n2b5&E#s0Yfzi84g~H!v@IiRq4rQYO+UWgMzF4FUbz6AY zAx_~*0)ODsV!`E+$IOQT4=%{7jhiXdx$=*&rm-P>{K6AF_z_)|*{X$V z1*~cUj!R*DdLvHP5sH_9~Uyjl-n^rMfq~VoMM&M@IwrV5=z>zxmo#cMRD3a z+=fh?o4SX`Jl1udR>9p}5a2kc3iVY5!L6d{Z0d9k`nu)i<)*mpX91&VIW>Yg=7ZH; z+jjo~3F2Sd&goMX#xj2hmX6TnK7J=;pRBl42v1~B`;O^k_>kb8{C7mp-ubWk=xMF~d=E8u6d!HU)(hVpH zxumHvy&HY^qig5Qf94B5w01cPF4YV1qBXVBZSC>Ws{BOwenqkN^;FTQ!hAy$QT(3L z-^mxKu($NzF$b7NvT9BKn_XEXHCybj*LgbvP5S~uM{KQ16FdMU{R9NUhSC)fJ2(&~ z(nG(D`sdPz!)J{nR2%-y;{Cse=V?j8ZWT)epOOjyyrwh4z5PNi!hwZWY4pc#9JA)% zvjnVYB_$<|X76iC*-^FNZn0qR1?~Z5=s}Hn5|_lYv5i+M8u0GXle2!ue?G}B?k;9t ziDgt$Q5lnh6c9NWkd`3bcYulB74zzsJ;r!@A;7$k!ymnVSU!mO#__#?vv)FAT{OT1V&kiq9ZTSUozM;02g`4ggtGe*J=V?V{w4HT&FFf@0M@h|e(cDYThk?Hs_c zfGJ1|Ek+f~timDOhj(LWTfFuYS4`!=H9~yGen{yx?n*vZ}aI@})!PlKmmx2(RPxg=ou_qWP@r;LwsZiNBuu82ANTj~K z6ueFUw^Ej-(v>Cy(k1I9Du$qxmX6Bave8;x4C<7!-pyjCaoW~)S9TSU(v;t=Vq#Vsy-{M!M;oa5JuG>F-e3=S+; zGu&Ozf(x(w^V>wfovt&$rH|^J`ah(hTL7xnjOdD9IjUiVK#aI$FRcOhho?er0su)G z;2couB6eSW`g~Hj--1S920ieW&>Q6*kb&A4=22!ygYXXhQgGovPqtsDc>FkS`=~wh zIlYKTYF$Y>=I_ppSE@Rzg1QJXczF0=zSKu2$q4G}#vF5?R(aVOtn-M_+$VMfuLES@ zKC+`J3R7rVWe*~0rVs+d|7s9)8OVz}cCFo2hT<%T0 zcvLT)_Egb}il%`UZh^WIpL?_yTCBn5NqxQh(?I3GDVCc$nCL-d*Bt~s==|>xxb>S& z|JY#2rJ)|zBqJjO1kyef_OXptm6%?3VBe-dvYv8`LU*DKsVV@dtqw% z`;cNzRybT(`3s`?Yg$^`OQjWJwI|Sn5;!|3Y?S@m4885y$cr@`5?05nS4z4(fNQ#0 z=RLOZNkxaav};Lfn485ENWCqPSh`Yw=bb4$KWFqn2jb5D+ zzwaiDlsRcmUnnDV9~BtsnsC%yeA2ReLy2c z9`Q5w_B(-aTy6BnD7fxZn8d0>3f#df0EY1;FwhiPcf(PzH%}Bf?0n!ZRX+O!VDrn( zC$~PV(ANcwanr%@8rX7!hRFodQ5Xd6_P}i2{M4*85xB9>X$Vfts)Roe|f?vR|4vQ=ZA&no@yT^0g4fbn~3qg7c2 zm(Y!$m6dfKd2F&#cjI$ssGI(LpBao2F0g+;zcJ{QFzBuFa;HJ+y zI3*j=OqWDS^cxswhsBCGsG5zp6;Q&m;=N=EgzkzUc~IQ;$#Gyv9ONkCH!~+ECr6WV z<~ELM7#P36k1D$klJ6=$TWqHYr|Va;qfIz?cmqv07f5;ebkS50B^SkbJg1`r7yhv> zFShzO+l*xONCD==;M!p$o&hgpfw--B({fk>Hn`kjo@62|)s>jz=07PL)S)GqLbM=F9TqX3tVX=KuAH6%msMrg9#k|;Jp0FlnANuJhv~=Z%zYThE?FT1bl8hL8&kL zP9Afi$!iEGGNkxsmq5IH3KTL+ zQLIqev0r+qC{t9VSfUZ1=dD&Vu_23%OkiuecLjT z1&UL^*#tkq&~@+$ayS0FZ+-a3bmQWL}LEi)1NZJa?BT0Pfwt+`R1cJx9U%9ehj}l(ugBn$4%CH-`?!VHvh9n zEt~)gNz<#ch+TT##n92wp*Z?O2jZ1VjoVQLs&%9uI=3tZ7S6E-i19j^gPE-cdMI9M zI1?#hL8J{GvQ2>9=A-6qf4C6gDwwQ6h)^*Dxu$H`qDyKB$in&T{ivT2?YakqEOD^Cf??M2jma4Kd?B!q#lhVwNH=& z72zA;#urf6SC1srRq&zqKSi3v90cR0f0gLg&%TfR$#lLA9JPcXl{z~ulxf@Y!1r!S z?yqfRnop~P#|R|H#jVy57FcCxWwG<}p8Nor4VJG`p(axS36zL+0{z@SR5kv*VeJO_Lbu7Q7E%JxAC@?r`&fPgLJ<_~=`NH!DiNN0 zgi{|P4lU)nl#-`_B}eNS@&{+>6#n-251fMgpmYuY!Mx(p{G+rZ>Sb590=-}S0}#Rw zBac_*QU$BD*vL#ie6YPb+b7|X?E`wroBkzV?uyyxxgyH!9UHC|LeBZ2PEiXcYk6=- zN5PT;ahUfLHJO|jV0Q;TKA)%AvSgpmKLaKGy%AZ&aYPcIO`0y1jKHssj&j5HFH?Zj z4^c1@Tebu|O}X-}OD;k?0jh{LC>K{{J&*#7kgbL@+Y9CtfTl`f2~ihOPzdkX{<)y{ z26kiS!-83MFn+i9g1Tj)2WW(D0^n!Oqr0y%6!-)CKneviLlqF54nBYWT+lkDBnL!Z zWq|IO%OiU^0YXH(3slAee8MTCA-!UdmP;7Io~gj78TRVW^WdKasML+45)<9L7}8$@ zdS%1)u6}U$B~c=6LZNsD#1{neVxUyLA?kIJGFN8kza&|ZH&LoT1mM;?^8Vdx zIDE;E4NK@lMP#B**_E&N{T_{SugQ2Prw#!xFv_9&82Xo?l|NPr)cBnRy(OyJFlgJ< z&@?Ejf(vqsOXxgz>rln?`C7`Edf#&CB7FYtyUMxj&R_R~5Q&mc4cwP#0tl)0AW{nl zfh6(7KyKcjM+sE5b6{_%KL_DrDx9*q3z-79%44YHi_*s_5?+;dqR8{&M*WSUw%uV4 zi9>yhZcE|&2GW4L=mklKoH6;{LI8u2q(uU#7NwxrPTcIeR9B!ZPhLz+^q}essV>%3 zRu7`k`W~K~H>2!f_zpolA&XRyA(S&R2uc}si>HP}Ef%U7R+VOvwE6PBD-3bW1}@i* z7x6sX!@W?Kc<1X*VaU4ST7cn5Gkhc(as)=`6zj$=i17v-45i|#` z!UBMvvH+YratlO7HO75$(p)M*K|v`34$tddcD?I>WbRZ_PAZ6E_43|lR1uAGb8UGn z2>??YLr~6`;$sxCK$2swhP1v9HZxmptsn#Rk6c$VJqfEupVdQy0YQ=bi?qI_5KjWj z$Lr`tnwcTC^A7~_9m+zNrIv@Puc=y)Ww?{}5dRFdq~0)!m-2vsJ+*eY4bGkE=0tHa z6&00N1;Aq0z`cOK&JWid&JR{}>YZ8mtY^EkvYvtA#e$4y5#%m+{&z5$FXFB@3v@6H zN&eU2o`7BHCAyFd2#?e+nSII28@|zt0b%vR3@(Y|mclrznd;(zNs33mEbL)C$Hz}!AgV-X;eQR56-7P$Nr3lf*$-VW=^NW^Bvbk_Rk$EP zWeQqteOVy*PsILQ5T)>8NynBRo}8_=Xep)Oz5Gb4NDqdrWBLM?K67_ma+efU@Bl7# zFw?&*&0`kF4D~K|C(`RNz;h5BB!A}sNj4a_>kX(nT03gjXV|;IpQ!j-SY{Enp+Nsg z{SC}o-Ho{lt$cdxD$`fM?VVr4K)6O&u?&~`WomdSW+qAk+9HJcbu7*r&7O2CnCrQR z&0kcbWk6N%^L2~J6DV*_TRV=z!7TGXy(b*s0 zm-r|Ndp<)@;3Lfgw1V;|VILaco*x$o^g$m$+eX4c+3f><&0jiRl>il0eOCTA^tHDe zMlMaSG>`lgWd2K)6xeEB@NTA)c8h4>>r>vql0v#Ez)(y*%1CVp-KyZN(oTXo7Qy(7 zdh|xwD#yJ{$L!ePwc@b%TgDkyig@w&geHb!edCA@!g6?_I82?LPaTKT$3Hh1Nf=sv3pVW9OxhMP!XEbLvy!{ zzg5e1eZME?z2{E@gLiYexoJX)HdUDKtoDa4I|e2urs;hC0tP(@O@{Pj@iVZY^+4RN_<#W#Xm$bL-~dSwA^zb8tAkrY9F&{S{X6+NPXiW4H%2GMRbMDcMh!??W}hK zQ5IDOq;L_td?4)iD?ys#P#*GKuHB$68eMvNK(44;Y#_prMP~>D@0+eSt<1}rlS}O7=&at6h^s>m)xBhfz?GqYSjn9JKPLmDG(vE8|L%I7WBOLOg z2NM+TBw|--Kt8X#kznCh95IJyNoR`dg15KZU#Gzxr-v>ecyDTS5hG}5j;~jeER(`s z!{yMji#mU{AZiQVN44DQ#dbKKJ*PROdZkg^gExCMsV(fdOdsKOMo1tW-65qInWFC3 zI+BEM+}6%^IN&nBbQu`FxBe;Kb+@3YXxDl9bPwt~r(SPP9BdH;pZzeT=S3MRK}U@8 z2JJWYMChnH9`wHT2{3Nk!7RgUL5F-K zY)~y)GH8tO)fKXN$GG6NtJ!qW<}BAR$jkY}ySn+@o7&Yz=<;(MXS=%ve{p}UYgAF?Xl-c>JB7m>^~wL$U{NbDVlLZ+4VR#7xlUt7su?Ib0nwn zURn!9D&8I-1IEnTgJ$$r>RoV+T;WffwM|jR>JL5^DyRVINWdPoNCXxJHJD`L-Ix_b z%y<09@vXtYe2O370W(+1j!Wc5iYdELPY|u`8WQiOU|ZIXZE%uA(6%5tD53}Do7{p9 zwQ52UWu2~4T;0lj{+<*GE-d}=aIdfGNDhl(eKOFQtzi@LK5~FO|3R3EVp#*7u)EpQY8W*f*Vw3|Og*^h=SMlqKP6^wR9O`(F}JtzLSZ z+MZT6|5@@7TX_f|p1@*6bLWc}0r4Crd{5PPR+__a6K^jsFa}vnaGB`AlKX69$mOe_ zA=B2KJhyxHF>uxRUx*zFA|yPdh2_tFy*Sen*Y1mP7vee&)3=As5$O$$e!<>-oX|RA zlz2RhxH^n{E$o=O%YL(Z>VLp3$r82?x$D`!2OwDBnnU#XI|H}LC zcBhBeB4U5H(q!{y#CA{kR=#R4tk~QqV-DNqZ5n*h8P8)rH_#osyJu@cBN=w~5IcR8+*9?IjN@sSJ7J%?3qaaI#8dF9pVO9V=_}DXke?tLB;H z6vVSmE;-}3pHwT)~%Q|=R8wV%|EHE*h?7(r9y zV3T3&SAW&#{wpTSnIz|G?tB*^9n(>VY14h$9;+*%=Tk0gdZO+|(SKz=r$)Oq{3gm6 zEV2K3DI-`~DTwis$6Q^7W@}n)0p9&hsj0a=tPm1Pv=+a36_~BG zvH@jocfxF;fW)Dh1zEOZFdxBB9hcY{|*(T;&Nl#feTE z*2!(;5VN%^EkTi4B4(JP1NF*qJQ1n(8u>f5M7+mE&rahb_V%l;Cu!Mw8s)GC>yT7C z%|`c-#0mQjJd{IN1kKV8jyN8tSs{kH@p~kJqRUvf?%x%nJl>ws?zrw6iB=gtps;j9 zwD#qo#U0M8r>)hUpbWJN;u*}0TWbYC^BzQoJ0DzV5^5^!dE8MFrdC6sBSZP5#49<( zzK$Am8}d(EX0~G~)$y6Ru3tbX49B+%?mZ>^n)+FWT*J~wKrLS zw8xW{mWV<7M(`+j6VUCrLP(i|fe6@NlE{ed+vc7Pe&XyAYPC;&qY4D#*-YI4qr?LZ zJ>SizkGC3G8ygLN+RYJHwiz|*ki1djW)$w`){g@hFAGh~VWn+hhZKlL^ zwnWVFHJRlJUG>O67Q=fowBjrGGMPK`k#RT;Hj)h97#ajZ36*_V+sx7FRQe)l|s^rP(Y9>ja6c+*G^ZW0yY6HS#J zyuEy#k+%VVt0B-oE_3ivLB!WLeI6q+y0t<`7j3PS(_<|H_;_3O<&gTepj7}uHY2h<*6njTAFdpdtDY`X|K z-JR*1J1sVzrIP2MQ)9EWdgV{t=Kgy3Z{R}o)eueX>7V4u3h0-i@q~xFGed0h4TDpS z)_(^V8hd`;Maie9_UgU&cp3hrJdtFQ<4gy4!{Z+;X7~%&>>AH&ONS8szXZ5jug-f_ zcP9%+@3o*pn*EP|i(oH$V9iG;jWd)^?l+^%;uxSq*d7H>1I%@Gv4WI&lv`bZ%915h zs3`x)*NffVNa=jXW9T53q}t)HQ*|Wve&zMR>0yh<%+!k?F=TOtx947tT)78*(E`TkhhOw^YuW$Il2v zNrrZuO6{I^&qehSd^qfLu~|9;h_cy$z)EYor=8+65sZlA>b0bJ{QYw63msn3Cr!L5 z&RyEVuDATWj0P1tVb2f#yk_I_f^pRcCWkl)u`PPBi4EjNG;4Jm)F#Us93L(YtkcyLC!bK_eLu3I+vEy<7%7VUB86CAw{24qqYZMw@Idd`!3f~Qti z`t}Zp`z(a+Q+9pGtK+=7fF|pshFA}p^q!m!6Y~ZuKCvLK5+<{5D}N^=ZmgW9elLRg zezQhljulO|L;~&@J&kve=t_79jGM!z7=r5;@X=thj(e|G_ZVjSQ{=7lg!OMRMLC2 z7%h4l1lu~7PO8}OMTInMQG&t`{mPIyaWck$%nz^+$Ey9~-`&E}iBXn#(a+jPDWW^Q zhGY$4*b5Fnbp{c7b%|lpNdgS*xN6ZTGUx5OHnz7J?Vdin)H~iMe4d`Wxt^I{TMx>P zFA!(TS$mwFTPDlBjaP_$u|psI=9b!yP(zFr>zn$44-dpAMwH9n zb}xkDJN*6Qj;Y3~N^6c`Am~feW}%XbW{JItt|C%XFh-}rrR-+1xlq* zwKpkqmDo;~YjZa_l=jH_E7>O?gPZF_oc}tjcwSsjR(n82J-F4LM<}*D@AcEc)t_lO zI97FqT_ZZpI~A!NZ&kJ#cFUr_@L}k}%_!lZ^C_ifW~;@(nTzup1#>YKU*omV{4D=^ z)VzGgRXuj0-(!em8>dI}=cC`0 zvGjcd=?MV$u~cGDz8O70ZJ6l=nU&a$4IhcbV;)?+>Ik0zw&GCM6rY$}Ci0?ta$YyG zoj)182j!$Z°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 K42Wl4qyGo;pgddv literal 0 HcmV?d00001 diff --git a/img/gallery/graph/12_scalable_images.png b/img/gallery/graph/12_scalable_images.png new file mode 100644 index 0000000000000000000000000000000000000000..1d3c7ee7e8751191bef56f5f42002aca27d0116b GIT binary patch literal 106967 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

>i_?D`x)NZsjG0 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

a_8K;Xp{=U0lS)#0vE0`kqaijHX<7`v*EceT~Ty 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 literal 0 HcmV?d00001 diff --git a/img/gallery/graph/13_dashed_lines.png b/img/gallery/graph/13_dashed_lines.png new file mode 100644 index 0000000000000000000000000000000000000000..bb6779ce0d611a8a7182f2a8b0b9dad38fac8b8f GIT binary patch literal 26811 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 bws%?obX>}y>$_k04Ky{jyhu8KHS|9KB(lzf literal 0 HcmV?d00001 diff --git a/img/gallery/graph/14_dot_language.png b/img/gallery/graph/14_dot_language.png new file mode 100644 index 0000000000000000000000000000000000000000..a0433e173cb0bc35f23893d4718b076f83cc8fb7 GIT binary patch literal 13090 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 literal 0 HcmV?d00001 diff --git a/img/gallery/graph/15_dot_language_playground.png b/img/gallery/graph/15_dot_language_playground.png new file mode 100644 index 0000000000000000000000000000000000000000..7048da501b2c09a3a84763d83bbb9b13a74844e8 GIT binary patch literal 31298 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 MlM^iy{^Iw405Vk#G5`Po literal 0 HcmV?d00001 diff --git a/img/gallery/graph/graphviz_gallery.png b/img/gallery/graph/graphviz_gallery.png new file mode 100644 index 0000000000000000000000000000000000000000..9aacc6128ee036d79b968152727ad03b09f5a540 GIT binary patch literal 267856 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 z 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 literal 0 HcmV?d00001 diff --git a/img/gallery/timeline/01_basic.png b/img/gallery/timeline/01_basic.png new file mode 100644 index 0000000000000000000000000000000000000000..8be3e577e1857bd692d24b9cff0c1ae61bdee57b GIT binary patch literal 9239 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 literal 0 HcmV?d00001 diff --git a/img/gallery/timeline/04_html_data.png b/img/gallery/timeline/04_html_data.png new file mode 100644 index 0000000000000000000000000000000000000000..5b73a37daf5fc00d2a18070c3e7e83c175eb7112 GIT binary patch literal 15839 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 azkEI)(aIRgWruWP15)DhpDINSg8m1_K=Kg) literal 0 HcmV?d00001 diff --git a/img/gallery/timeline/05_groups.png b/img/gallery/timeline/05_groups.png new file mode 100644 index 0000000000000000000000000000000000000000..04234222801ceb41917f9d5f47af82532e6b00d7 GIT binary patch literal 24442 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 literal 0 HcmV?d00001 diff --git a/index.html b/index.html new file mode 100644 index 00000000..26e4f06b --- /dev/null +++ b/index.html @@ -0,0 +1,294 @@ + + + + + vis.js | a dynamic, browser-based visualization library + + + + + + + + + + + + + + + +

+ + + +

vis.js

+ +

+ Vis.js is a dynamic, browser based visualization library. + The library is designed to be easy to use, to handle large amounts + of dynamic data, and to enable manipulation of the data. + The library consists of the components DataSet, Timeline, and Graph. +

+

+ The vis.js library is developed by Almende B.V. +

+ + +

Install

+ +

npm

+ Install via npm: + +
+npm install vis
+
+ +

bower

+ Install via bower: + +
+bower install vis
+
+ +

download

+ Or download the library from the github project: + https://github.com/almende/vis.git. + +

Example

+ +

+ A basic example demonstrating how to use the vis.js timeline is shown below. +

+ +

+ More examples can be found in the + examples directory. +

+ +
<!doctype html>
+<html>
+<head>
+    <title>Timeline | Basic demo</title>
+    <script src="http://visjs.org/vis.js"></script>
+
+    <style type="text/css">
+        body, html {
+            font-family: sans-serif;
+        }
+    </style>
+</head>
+<body>
+<div id="mytimeline"></div>
+
+<script type="text/javascript">
+    var container = document.getElementById('mytimeline');
+    var data = [
+        {id: 1, content: 'item 1', start: '2013-04-20'},
+        {id: 2, content: 'item 2', start: '2013-04-14'},
+        {id: 3, content: 'item 3', start: '2013-04-18'},
+        {id: 4, content: 'item 4', start: '2013-04-16', end: '2013-04-19'},
+        {id: 5, content: 'item 5', start: '2013-04-25'},
+        {id: 6, content: 'item 6', start: '2013-04-27'}
+    ];
+    var options = {};
+    var timeline = new vis.Timeline(container, data, options);
+</script>
+</body>
+</html>
+
+ + + + +

Timeline

+ + +

Graph

+ + + +

Docs

+ +

+ The following documentation is available: +

+ + + +

License

+ +

+ Copyright (C) 2010-2013 Almende B.V. +

+ +

+ Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at +

+ +

+ http://www.apache.org/licenses/LICENSE-2.0 +

+ +

+ Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +

+ + + Fork me on GitHub + + +
+ + diff --git a/index.md b/index.md deleted file mode 100644 index c5c133ad..00000000 --- a/index.md +++ /dev/null @@ -1,151 +0,0 @@ ---- -layout: default -title: vis.js ---- - -# vis.js - - -Vis.js is a dynamic, browser based visualization library. -The library is designed to be easy to use, to handle large amounts -of dynamic data, and to enable manipulation of the data. -The library consists of Timeline, LineChart, LineChart3d, Graph, and Treegrid. - -Vis.js Library is part of [CHAP](http://chap.almende.com), -the Common Hybrid Agent Platform, developed by [Almende B.V](http://almende.com). - - -## Install - -Install via npm: - - npm install vis - -Install via bower: - - bower install vis - -Or download the library from the github project: -[https://github.com/almende/vis.git](https://github.com/almende/vis.git). - - -## Load - - -To use a component, include the javascript file of vis in your webpage: - - - - - - - - - - - -or load vis.js using require.js: - - require.config({ - paths: { - vis: 'path/to/vis', - } - }); - require(['vis'], function (math) { - // ... load a visualization - }); - - -A timeline can be instantiated as: - - var timeline = new Timeline(container, data, options); - -Where `container` is an HTML element, `data` is an Array with data or a DataSet, -and `options` is an optional object with configuration options for the -component. - - -## Example - -A basic example on loading a Timeline is shown below. More examples can be -found in the [examples directory](https://github.com/almende/vis/tree/master/examples) -of the project. - - - - - Timeline basic demo - - - - - -
- - - - - - -## Build - -To build the library from source, clone the project from github - - git clone git://github.com/almende/vis.git - -The project uses [jake](https://github.com/mde/jake) as build tool. -The build script uses [Browserify](http://browserify.org/) to -bundle the source code into a library, -and uses [UglifyJS](http://lisperator.net/uglifyjs/) to minify the code. -The source code uses the module style of node (require and module.exports) to -organize dependencies. - -To install all dependencies and build the library, run `npm install` in the -root of the project. - - cd vis - npm install - -To be able to run jake from the command line, jake must be installed globally: - - sudo npm install -g jake - -Then, the project can be build by executing jake in the root of the project: - - jake - - -## License - -Copyright (C) 2010-2013 Almende B.V. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - diff --git a/vis.js b/vis.js new file mode 100644 index 00000000..a3917f16 --- /dev/null +++ b/vis.js @@ -0,0 +1,12379 @@ +/** + * vis.js + * https://github.com/almende/vis + * + * A dynamic, browser-based visualization library. + * + * @version 0.0.9 + * @date 2013-06-07 + * + * @license + * Copyright (C) 2011-2013 Almende B.V, http://almende.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +(function(e){if("function"==typeof bootstrap)bootstrap("vis",e);else if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeVis=e}else"undefined"!=typeof window?window.vis=e():global.vis=e()})(function(){var define,ses,bootstrap,module,exports; +return (function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require=="function"&&require;for(var s=0;s= 0) { + action = "DOMMouseScroll"; // For Firefox + } + + element.addEventListener(action, listener, useCapture); + } else { + element.attachEvent("on" + action, listener); // IE browsers + } +}; + +/** + * Remove an event listener from an element + * @param {Element} element An html dom element + * @param {string} action The name of the event, for example "mousedown" + * @param {function} listener The listener function + * @param {boolean} [useCapture] + */ +util.removeEventListener = function removeEventListener(element, action, listener, useCapture) { + if (element.removeEventListener) { + // non-IE browsers + if (useCapture === undefined) + useCapture = false; + + if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) { + action = "DOMMouseScroll"; // For Firefox + } + + element.removeEventListener(action, listener, useCapture); + } else { + // IE browsers + element.detachEvent("on" + action, listener); + } +}; + + +/** + * Get HTML element which is the target of the event + * @param {Event} event + * @return {Element} target element + */ +util.getTarget = function getTarget(event) { + // code from http://www.quirksmode.org/js/events_properties.html + if (!event) { + event = window.event; + } + + var target; + + if (event.target) { + target = event.target; + } + else if (event.srcElement) { + target = event.srcElement; + } + + if (target.nodeType != undefined && target.nodeType == 3) { + // defeat Safari bug + target = target.parentNode; + } + + return target; +}; + +/** + * Stop event propagation + */ +util.stopPropagation = function stopPropagation(event) { + if (!event) + event = window.event; + + if (event.stopPropagation) { + event.stopPropagation(); // non-IE browsers + } + else { + event.cancelBubble = true; // IE browsers + } +}; + + +/** + * Cancels the event if it is cancelable, without stopping further propagation of the event. + */ +util.preventDefault = function preventDefault (event) { + if (!event) + event = window.event; + + if (event.preventDefault) { + event.preventDefault(); // non-IE browsers + } + else { + event.returnValue = false; // IE browsers + } +}; + + +util.option = {}; + +/** + * Cast a value as boolean + * @param {Boolean | function | undefined} value + * @param {Boolean} [defaultValue] + * @returns {Boolean} bool + */ +util.option.asBoolean = function (value, defaultValue) { + if (typeof value == 'function') { + value = value(); + } + + if (value != null) { + return (value != false); + } + + return defaultValue || null; +}; + +/** + * Cast a value as number + * @param {Boolean | function | undefined} value + * @param {Number} [defaultValue] + * @returns {Number} number + */ +util.option.asNumber = function (value, defaultValue) { + if (typeof value == 'function') { + value = value(); + } + + if (value != null) { + return Number(value) || defaultValue || null; + } + + return defaultValue || null; +}; + +/** + * Cast a value as string + * @param {String | function | undefined} value + * @param {String} [defaultValue] + * @returns {String} str + */ +util.option.asString = function (value, defaultValue) { + if (typeof value == 'function') { + value = value(); + } + + if (value != null) { + return String(value); + } + + return defaultValue || null; +}; + +/** + * Cast a size or location in pixels or a percentage + * @param {String | Number | function | undefined} value + * @param {String} [defaultValue] + * @returns {String} size + */ +util.option.asSize = function (value, defaultValue) { + if (typeof value == 'function') { + value = value(); + } + + if (util.isString(value)) { + return value; + } + else if (util.isNumber(value)) { + return value + 'px'; + } + else { + return defaultValue || null; + } +}; + +/** + * Cast a value as DOM element + * @param {HTMLElement | function | undefined} value + * @param {HTMLElement} [defaultValue] + * @returns {HTMLElement | null} dom + */ +util.option.asElement = function (value, defaultValue) { + if (typeof value == 'function') { + value = value(); + } + + return value || defaultValue || null; +}; + +/** + * load css from text + * @param {String} css Text containing css + */ +util.loadCss = function (css) { + if (typeof document === 'undefined') { + return; + } + + // get the script location, and built the css file name from the js file name + // http://stackoverflow.com/a/2161748/1262753 + // var scripts = document.getElementsByTagName('script'); + // var jsFile = scripts[scripts.length-1].src.split('?')[0]; + // var cssFile = jsFile.substring(0, jsFile.length - 2) + 'css'; + + // inject css + // http://stackoverflow.com/questions/524696/how-to-create-a-style-tag-with-javascript + var style = document.createElement('style'); + style.type = 'text/css'; + if (style.styleSheet){ + style.styleSheet.cssText = css; + } else { + style.appendChild(document.createTextNode(css)); + } + + document.getElementsByTagName('head')[0].appendChild(style); +}; + + +// Internet Explorer 8 and older does not support Array.indexOf, so we define +// it here in that case. +// http://soledadpenades.com/2007/05/17/arrayindexof-in-internet-explorer/ +if(!Array.prototype.indexOf) { + Array.prototype.indexOf = function(obj){ + for(var i = 0; i < this.length; i++){ + if(this[i] == obj){ + return i; + } + } + return -1; + }; + + try { + console.log("Warning: Ancient browser detected. Please update your browser"); + } + catch (err) { + } +} + +// Internet Explorer 8 and older does not support Array.forEach, so we define +// it here in that case. +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach +if (!Array.prototype.forEach) { + Array.prototype.forEach = function(fn, scope) { + for(var i = 0, len = this.length; i < len; ++i) { + fn.call(scope || this, this[i], i, this); + } + } +} + +// Internet Explorer 8 and older does not support Array.map, so we define it +// here in that case. +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/map +// Production steps of ECMA-262, Edition 5, 15.4.4.19 +// Reference: http://es5.github.com/#x15.4.4.19 +if (!Array.prototype.map) { + Array.prototype.map = function(callback, thisArg) { + + var T, A, k; + + if (this == null) { + throw new TypeError(" this is null or not defined"); + } + + // 1. Let O be the result of calling ToObject passing the |this| value as the argument. + var O = Object(this); + + // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length". + // 3. Let len be ToUint32(lenValue). + var len = O.length >>> 0; + + // 4. If IsCallable(callback) is false, throw a TypeError exception. + // See: http://es5.github.com/#x9.11 + if (typeof callback !== "function") { + throw new TypeError(callback + " is not a function"); + } + + // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. + if (thisArg) { + T = thisArg; + } + + // 6. Let A be a new array created as if by the expression new Array(len) where Array is + // the standard built-in constructor with that name and len is the value of len. + A = new Array(len); + + // 7. Let k be 0 + k = 0; + + // 8. Repeat, while k < len + while(k < len) { + + var kValue, mappedValue; + + // a. Let Pk be ToString(k). + // This is implicit for LHS operands of the in operator + // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk. + // This step can be combined with c + // c. If kPresent is true, then + if (k in O) { + + // i. Let kValue be the result of calling the Get internal method of O with argument Pk. + kValue = O[ k ]; + + // ii. Let mappedValue be the result of calling the Call internal method of callback + // with T as the this value and argument list containing kValue, k, and O. + mappedValue = callback.call(T, kValue, k, O); + + // iii. Call the DefineOwnProperty internal method of A with arguments + // Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true}, + // and false. + + // In browsers that support Object.defineProperty, use the following: + // Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true }); + + // For best browser support, use the following: + A[ k ] = mappedValue; + } + // d. Increase k by 1. + k++; + } + + // 9. return A + return A; + }; +} + +// Internet Explorer 8 and older does not support Array.filter, so we define it +// here in that case. +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/filter +if (!Array.prototype.filter) { + Array.prototype.filter = function(fun /*, thisp */) { + "use strict"; + + if (this == null) { + throw new TypeError(); + } + + var t = Object(this); + var len = t.length >>> 0; + if (typeof fun != "function") { + throw new TypeError(); + } + + var res = []; + var thisp = arguments[1]; + for (var i = 0; i < len; i++) { + if (i in t) { + var val = t[i]; // in case fun mutates this + if (fun.call(thisp, val, i, t)) + res.push(val); + } + } + + return res; + }; +} + + +// Internet Explorer 8 and older does not support Object.keys, so we define it +// here in that case. +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys +if (!Object.keys) { + Object.keys = (function () { + var hasOwnProperty = Object.prototype.hasOwnProperty, + hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), + dontEnums = [ + 'toString', + 'toLocaleString', + 'valueOf', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'constructor' + ], + dontEnumsLength = dontEnums.length; + + return function (obj) { + if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) { + throw new TypeError('Object.keys called on non-object'); + } + + var result = []; + + for (var prop in obj) { + if (hasOwnProperty.call(obj, prop)) result.push(prop); + } + + if (hasDontEnumBug) { + for (var i=0; i < dontEnumsLength; i++) { + if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]); + } + } + return result; + } + })() +} + +// Internet Explorer 8 and older does not support Array.isArray, +// so we define it here in that case. +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/isArray +if(!Array.isArray) { + Array.isArray = function (vArg) { + return Object.prototype.toString.call(vArg) === "[object Array]"; + }; +} + +// Internet Explorer 8 and older does not support Function.bind, +// so we define it here in that case. +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind +if (!Function.prototype.bind) { + Function.prototype.bind = function (oThis) { + if (typeof this !== "function") { + // closest thing possible to the ECMAScript 5 internal IsCallable function + throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); + } + + var aArgs = Array.prototype.slice.call(arguments, 1), + fToBind = this, + fNOP = function () {}, + fBound = function () { + return fToBind.apply(this instanceof fNOP && oThis + ? this + : oThis, + aArgs.concat(Array.prototype.slice.call(arguments))); + }; + + fNOP.prototype = this.prototype; + fBound.prototype = new fNOP(); + + return fBound; + }; +} + +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create +if (!Object.create) { + Object.create = function (o) { + if (arguments.length > 1) { + throw new Error('Object.create implementation only accepts the first parameter.'); + } + function F() {} + F.prototype = o; + return new F(); + }; +} + +/** + * Event listener (singleton) + */ +// TODO: replace usage of the event listener for the EventBus +var events = { + 'listeners': [], + + /** + * Find a single listener by its object + * @param {Object} object + * @return {Number} index -1 when not found + */ + 'indexOf': function (object) { + var listeners = this.listeners; + for (var i = 0, iMax = this.listeners.length; i < iMax; i++) { + var listener = listeners[i]; + if (listener && listener.object == object) { + return i; + } + } + return -1; + }, + + /** + * Add an event listener + * @param {Object} object + * @param {String} event The name of an event, for example 'select' + * @param {function} callback The callback method, called when the + * event takes place + */ + 'addListener': function (object, event, callback) { + var index = this.indexOf(object); + var listener = this.listeners[index]; + if (!listener) { + listener = { + 'object': object, + 'events': {} + }; + this.listeners.push(listener); + } + + var callbacks = listener.events[event]; + if (!callbacks) { + callbacks = []; + listener.events[event] = callbacks; + } + + // add the callback if it does not yet exist + if (callbacks.indexOf(callback) == -1) { + callbacks.push(callback); + } + }, + + /** + * Remove an event listener + * @param {Object} object + * @param {String} event The name of an event, for example 'select' + * @param {function} callback The registered callback method + */ + 'removeListener': function (object, event, callback) { + var index = this.indexOf(object); + var listener = this.listeners[index]; + if (listener) { + var callbacks = listener.events[event]; + if (callbacks) { + index = callbacks.indexOf(callback); + if (index != -1) { + callbacks.splice(index, 1); + } + + // remove the array when empty + if (callbacks.length == 0) { + delete listener.events[event]; + } + } + + // count the number of registered events. remove listener when empty + var count = 0; + var events = listener.events; + for (var e in events) { + if (events.hasOwnProperty(e)) { + count++; + } + } + if (count == 0) { + delete this.listeners[index]; + } + } + }, + + /** + * Remove all registered event listeners + */ + 'removeAllListeners': function () { + this.listeners = []; + }, + + /** + * Trigger an event. All registered event handlers will be called + * @param {Object} object + * @param {String} event + * @param {Object} properties (optional) + */ + 'trigger': function (object, event, properties) { + var index = this.indexOf(object); + var listener = this.listeners[index]; + if (listener) { + var callbacks = listener.events[event]; + if (callbacks) { + for (var i = 0, iMax = callbacks.length; i < iMax; i++) { + callbacks[i](properties); + } + } + } + } +}; + +/** + * An event bus can be used to emit events, and to subscribe to events + * @constructor EventBus + */ +function EventBus() { + this.subscriptions = []; +} + +/** + * Subscribe to an event + * @param {String | RegExp} event The event can be a regular expression, or + * a string with wildcards, like 'server.*'. + * @param {function} callback. Callback are called with three parameters: + * {String} event, {*} [data], {*} [source] + * @param {*} [target] + * @returns {String} id A subscription id + */ +EventBus.prototype.on = function (event, callback, target) { + var regexp = (event instanceof RegExp) ? + event : + new RegExp(event.replace('*', '\\w+')); + + var subscription = { + id: util.randomUUID(), + event: event, + regexp: regexp, + callback: (typeof callback === 'function') ? callback : null, + target: target + }; + + this.subscriptions.push(subscription); + + return subscription.id; +}; + +/** + * Unsubscribe from an event + * @param {String | Object} filter Filter for subscriptions to be removed + * Filter can be a string containing a + * subscription id, or an object containing + * one or more of the fields id, event, + * callback, and target. + */ +EventBus.prototype.off = function (filter) { + var i = 0; + while (i < this.subscriptions.length) { + var subscription = this.subscriptions[i]; + + var match = true; + if (filter instanceof Object) { + // filter is an object. All fields must match + for (var prop in filter) { + if (filter.hasOwnProperty(prop)) { + if (filter[prop] !== subscription[prop]) { + match = false; + } + } + } + } + else { + // filter is a string, filter on id + match = (subscription.id == filter); + } + + if (match) { + this.subscriptions.splice(i, 1); + } + else { + i++; + } + } +}; + +/** + * Emit an event + * @param {String} event + * @param {*} [data] + * @param {*} [source] + */ +EventBus.prototype.emit = function (event, data, source) { + for (var i =0; i < this.subscriptions.length; i++) { + var subscription = this.subscriptions[i]; + if (subscription.regexp.test(event)) { + if (subscription.callback) { + subscription.callback(event, data, source); + } + } + } +}; + +/** + * DataSet + * + * Usage: + * var dataSet = new DataSet({ + * fieldId: '_id', + * fieldTypes: { + * // ... + * } + * }); + * + * dataSet.add(item); + * dataSet.add(data); + * dataSet.update(item); + * dataSet.update(data); + * dataSet.remove(id); + * dataSet.remove(ids); + * var data = dataSet.get(); + * var data = dataSet.get(id); + * var data = dataSet.get(ids); + * var data = dataSet.get(ids, options, data); + * dataSet.clear(); + * + * A data set can: + * - add/remove/update data + * - gives triggers upon changes in the data + * - can import/export data in various data formats + * + * @param {Object} [options] Available options: + * {String} fieldId Field name of the id in the + * items, 'id' by default. + * {Object.} [fieldTypes] + * {String[]} [fields] field names to be returned + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * {Array | DataTable} [data] If provided, items will be appended to this + * array or table. Required in case of Google + * DataTable. + * + * @throws Error + */ +DataSet.prototype.get = function (args) { + var me = this; + + // parse the arguments + var id, ids, options, data; + var firstType = util.getType(arguments[0]); + if (firstType == 'String' || firstType == 'Number') { + // get(id [, options] [, data]) + id = arguments[0]; + options = arguments[1]; + data = arguments[2]; + } + else if (firstType == 'Array') { + // get(ids [, options] [, data]) + ids = arguments[0]; + options = arguments[1]; + data = arguments[2]; + } + else { + // get([, options] [, data]) + options = arguments[0]; + data = arguments[1]; + } + + // determine the return type + var type; + if (options && options.type) { + type = (options.type == 'DataTable') ? 'DataTable' : 'Array'; + + if (data && (type != util.getType(data))) { + throw new Error('Type of parameter "data" (' + util.getType(data) + ') ' + + 'does not correspond with specified options.type (' + options.type + ')'); + } + if (type == 'DataTable' && !util.isDataTable(data)) { + throw new Error('Parameter "data" must be a DataTable ' + + 'when options.type is "DataTable"'); + } + } + else if (data) { + type = (util.getType(data) == 'DataTable') ? 'DataTable' : 'Array'; + } + else { + type = 'Array'; + } + + // build options + var fieldTypes = options && options.fieldTypes || this.options.fieldTypes; + var filter = options && options.filter; + var items = [], item, itemId, i, len; + + // cast items + if (id != undefined) { + // return a single item + item = me._getItem(id, fieldTypes); + if (filter && !filter(item)) { + item = null; + } + } + else if (ids != undefined) { + // return a subset of items + for (i = 0, len = ids.length; i < len; i++) { + item = me._getItem(ids[i], fieldTypes); + if (!filter || filter(item)) { + items.push(item); + } + } + } + else { + // return all items + for (itemId in this.data) { + if (this.data.hasOwnProperty(itemId)) { + item = me._getItem(itemId, fieldTypes); + if (!filter || filter(item)) { + items.push(item); + } + } + } + } + + // order the results + if (options && options.order && id == undefined) { + this._sort(items, options.order); + } + + // filter fields of the items + if (options && options.fields) { + var fields = options.fields; + if (id != undefined) { + item = this._filterFields(item, fields); + } + else { + for (i = 0, len = items.length; i < len; i++) { + items[i] = this._filterFields(items[i], fields); + } + } + } + + // return the results + if (type == 'DataTable') { + var columns = this._getColumnNames(data); + if (id != undefined) { + // append a single item to the data table + me._appendRow(data, columns, item); + } + else { + // copy the items to the provided data table + for (i = 0, len = items.length; i < len; i++) { + me._appendRow(data, columns, items[i]); + } + } + return data; + } + else { + // return an array + if (id != undefined) { + // a single item + return item; + } + else { + // multiple items + if (data) { + // copy the items to the provided array + for (i = 0, len = items.length; i < len; i++) { + data.push(items[i]); + } + return data; + } + else { + // just return our array + return items; + } + } + } +}; + +/** + * Get ids of all items or from a filtered set of items. + * @param {Object} [options] An Object with options. Available options: + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * @return {Array} ids + */ +DataSet.prototype.getIds = function (options) { + var data = this.data, + filter = options && options.filter, + order = options && options.order, + fieldTypes = options && options.fieldTypes || this.options.fieldTypes, + i, + len, + id, + item, + items, + ids = []; + + if (filter) { + // get filtered items + if (order) { + // create ordered list + items = []; + for (id in data) { + if (data.hasOwnProperty(id)) { + item = this._getItem(id, fieldTypes); + if (filter(item)) { + items.push(item); + } + } + } + + this._sort(items, order); + + for (i = 0, len = items.length; i < len; i++) { + ids[i] = items[i][this.fieldId]; + } + } + else { + // create unordered list + for (id in data) { + if (data.hasOwnProperty(id)) { + item = this._getItem(id, fieldTypes); + if (filter(item)) { + ids.push(item[this.fieldId]); + } + } + } + } + } + else { + // get all items + if (order) { + // create an ordered list + items = []; + for (id in data) { + if (data.hasOwnProperty(id)) { + items.push(data[id]); + } + } + + this._sort(items, order); + + for (i = 0, len = items.length; i < len; i++) { + ids[i] = items[i][this.fieldId]; + } + } + else { + // create unordered list + for (id in data) { + if (data.hasOwnProperty(id)) { + item = data[id]; + ids.push(item[this.fieldId]); + } + } + } + } + + return ids; +}; + +/** + * Execute a callback function for every item in the dataset. + * The order of the items is not determined. + * @param {function} callback + * @param {Object} [options] Available options: + * {Object.} [fieldTypes] + * {String[]} [fields] filter fields + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + */ +DataSet.prototype.forEach = function (callback, options) { + var filter = options && options.filter, + fieldTypes = options && options.fieldTypes || this.options.fieldTypes, + data = this.data, + item, + id; + + if (options && options.order) { + // execute forEach on ordered list + var items = this.get(options); + + for (var i = 0, len = items.length; i < len; i++) { + item = items[i]; + id = item[this.fieldId]; + callback(item, id); + } + } + else { + // unordered + for (id in data) { + if (data.hasOwnProperty(id)) { + item = this._getItem(id, fieldTypes); + if (!filter || filter(item)) { + callback(item, id); + } + } + } + } +}; + +/** + * Map every item in the dataset. + * @param {function} callback + * @param {Object} [options] Available options: + * {Object.} [fieldTypes] + * {String[]} [fields] filter fields + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * @return {Object[]} mappedItems + */ +DataSet.prototype.map = function (callback, options) { + var filter = options && options.filter, + fieldTypes = options && options.fieldTypes || this.options.fieldTypes, + mappedItems = [], + data = this.data, + item; + + // cast and filter items + for (var id in data) { + if (data.hasOwnProperty(id)) { + item = this._getItem(id, fieldTypes); + if (!filter || filter(item)) { + mappedItems.push(callback(item, id)); + } + } + } + + // order items + if (options && options.order) { + this._sort(mappedItems, options.order); + } + + return mappedItems; +}; + +/** + * Filter the fields of an item + * @param {Object} item + * @param {String[]} fields Field names + * @return {Object} filteredItem + * @private + */ +DataSet.prototype._filterFields = function (item, fields) { + var filteredItem = {}; + + for (var field in item) { + if (item.hasOwnProperty(field) && (fields.indexOf(field) != -1)) { + filteredItem[field] = item[field]; + } + } + + return filteredItem; +}; + +/** + * Sort the provided array with items + * @param {Object[]} items + * @param {String | function} order A field name or custom sort function. + * @private + */ +DataSet.prototype._sort = function (items, order) { + if (util.isString(order)) { + // order by provided field name + var name = order; // field name + items.sort(function (a, b) { + var av = a[name]; + var bv = b[name]; + return (av > bv) ? 1 : ((av < bv) ? -1 : 0); + }); + } + else if (typeof order === 'function') { + // order by sort function + items.sort(order); + } + // TODO: extend order by an Object {field:String, direction:String} + // where direction can be 'asc' or 'desc' + else { + throw new TypeError('Order must be a function or a string'); + } +}; + +/** + * Remove an object by pointer or by id + * @param {String | Number | Object | Array} id Object or id, or an array with + * objects or ids to be removed + * @param {String} [senderId] Optional sender id + */ +DataSet.prototype.remove = function (id, senderId) { + var removedItems = [], + i, len; + + if (util.isNumber(id) || util.isString(id)) { + delete this.data[id]; + delete this.internalIds[id]; + removedItems.push(id); + } + else if (id instanceof Array) { + for (i = 0, len = id.length; i < len; i++) { + this.remove(id[i]); + } + removedItems = items.concat(id); + } + else if (id instanceof Object) { + // search for the object + for (i in this.data) { + if (this.data.hasOwnProperty(i)) { + if (this.data[i] == id) { + delete this.data[i]; + delete this.internalIds[i]; + removedItems.push(i); + } + } + } + } + + if (removedItems.length) { + this._trigger('remove', {items: removedItems}, senderId); + } +}; + +/** + * Clear the data + * @param {String} [senderId] Optional sender id + */ +DataSet.prototype.clear = function (senderId) { + var ids = Object.keys(this.data); + + this.data = {}; + this.internalIds = {}; + + this._trigger('remove', {items: ids}, senderId); +}; + +/** + * Find the item with maximum value of a specified field + * @param {String} field + * @return {Object | null} item Item containing max value, or null if no items + */ +DataSet.prototype.max = function (field) { + var data = this.data, + max = null, + maxField = null; + + for (var id in data) { + if (data.hasOwnProperty(id)) { + var item = data[id]; + var itemField = item[field]; + if (itemField != null && (!max || itemField > maxField)) { + max = item; + maxField = itemField; + } + } + } + + return max; +}; + +/** + * Find the item with minimum value of a specified field + * @param {String} field + * @return {Object | null} item Item containing max value, or null if no items + */ +DataSet.prototype.min = function (field) { + var data = this.data, + min = null, + minField = null; + + for (var id in data) { + if (data.hasOwnProperty(id)) { + var item = data[id]; + var itemField = item[field]; + if (itemField != null && (!min || itemField < minField)) { + min = item; + minField = itemField; + } + } + } + + return min; +}; + +/** + * Find all distinct values of a specified field + * @param {String} field + * @return {Array} values Array containing all distinct values. If the data + * items do not contain the specified field, an array + * containing a single value undefined is returned. + * The returned array is unordered. + */ +DataSet.prototype.distinct = function (field) { + var data = this.data, + values = [], + fieldType = this.options.fieldTypes[field], + count = 0; + + for (var prop in data) { + if (data.hasOwnProperty(prop)) { + var item = data[prop]; + var value = util.cast(item[field], fieldType); + var exists = false; + for (var i = 0; i < count; i++) { + if (values[i] == value) { + exists = true; + break; + } + } + if (!exists) { + values[count] = value; + count++; + } + } + } + + return values; +}; + +/** + * Add a single item. Will fail when an item with the same id already exists. + * @param {Object} item + * @return {String} id + * @private + */ +DataSet.prototype._addItem = function (item) { + var id = item[this.fieldId]; + + if (id != undefined) { + // check whether this id is already taken + if (this.data[id]) { + // item already exists + throw new Error('Cannot add item: item with id ' + id + ' already exists'); + } + } + else { + // generate an id + id = util.randomUUID(); + item[this.fieldId] = id; + this.internalIds[id] = item; + } + + var d = {}; + for (var field in item) { + if (item.hasOwnProperty(field)) { + var type = this.fieldTypes[field]; // type may be undefined + d[field] = util.cast(item[field], type); + } + } + this.data[id] = d; + + return id; +}; + +/** + * Get an item. Fields can be casted to a specific type + * @param {String} id + * @param {Object.} [fieldTypes] Cast field types + * @return {Object | null} item + * @private + */ +DataSet.prototype._getItem = function (id, fieldTypes) { + var field, value; + + // get the item from the dataset + var raw = this.data[id]; + if (!raw) { + return null; + } + + // cast the items field types + var casted = {}, + fieldId = this.fieldId, + internalIds = this.internalIds; + if (fieldTypes) { + for (field in raw) { + if (raw.hasOwnProperty(field)) { + value = raw[field]; + // output all fields, except internal ids + if ((field != fieldId) || !(value in internalIds)) { + casted[field] = util.cast(value, fieldTypes[field]); + } + } + } + } + else { + // no field types specified, no casting needed + for (field in raw) { + if (raw.hasOwnProperty(field)) { + value = raw[field]; + // output all fields, except internal ids + if ((field != fieldId) || !(value in internalIds)) { + casted[field] = value; + } + } + } + } + + return casted; +}; + +/** + * Update a single item: merge with existing item. + * Will fail when the item has no id, or when there does not exist an item + * with the same id. + * @param {Object} item + * @return {String} id + * @private + */ +DataSet.prototype._updateItem = function (item) { + var id = item[this.fieldId]; + if (id == undefined) { + throw new Error('Cannot update item: item has no id (item: ' + JSON.stringify(item) + ')'); + } + var d = this.data[id]; + if (!d) { + // item doesn't exist + throw new Error('Cannot update item: no item with id ' + id + ' found'); + } + + // merge with current item + for (var field in item) { + if (item.hasOwnProperty(field)) { + var type = this.fieldTypes[field]; // type may be undefined + d[field] = util.cast(item[field], type); + } + } + + return id; +}; + +/** + * Get an array with the column names of a Google DataTable + * @param {DataTable} dataTable + * @return {String[]} columnNames + * @private + */ +DataSet.prototype._getColumnNames = function (dataTable) { + var columns = []; + for (var col = 0, cols = dataTable.getNumberOfColumns(); col < cols; col++) { + columns[col] = dataTable.getColumnId(col) || dataTable.getColumnLabel(col); + } + return columns; +}; + +/** + * Append an item as a row to the dataTable + * @param dataTable + * @param columns + * @param item + * @private + */ +DataSet.prototype._appendRow = function (dataTable, columns, item) { + var row = dataTable.addRow(); + + for (var col = 0, cols = columns.length; col < cols; col++) { + var field = columns[col]; + dataTable.setValue(row, col, item[field]); + } +}; + +/** + * DataView + * + * a dataview offers a filtered view on a dataset or an other dataview. + * + * @param {DataSet | DataView} data + * @param {Object} [options] Available options: see method get + * + * @constructor DataView + */ +function DataView (data, options) { + this.id = util.randomUUID(); + + this.data = null; + this.ids = {}; // ids of the items currently in memory (just contains a boolean true) + this.options = options || {}; + this.fieldId = 'id'; // name of the field containing id + this.subscribers = {}; // event subscribers + + var me = this; + this.listener = function () { + me._onEvent.apply(me, arguments); + }; + + this.setData(data); +} + +/** + * Set a data source for the view + * @param {DataSet | DataView} data + */ +DataView.prototype.setData = function (data) { + var ids, dataItems, i, len; + + if (this.data) { + // unsubscribe from current dataset + if (this.data.unsubscribe) { + this.data.unsubscribe('*', this.listener); + } + + // trigger a remove of all items in memory + ids = []; + for (var id in this.ids) { + if (this.ids.hasOwnProperty(id)) { + ids.push(id); + } + } + this.ids = {}; + this._trigger('remove', {items: ids}); + } + + this.data = data; + + if (this.data) { + // update fieldId + this.fieldId = this.options.fieldId || + (this.data && this.data.options && this.data.options.fieldId) || + 'id'; + + // trigger an add of all added items + ids = this.data.getIds({filter: this.options && this.options.filter}); + for (i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + this.ids[id] = true; + } + this._trigger('add', {items: ids}); + + // subscribe to new dataset + if (this.data.subscribe) { + this.data.subscribe('*', this.listener); + } + } +}; + +/** + * Get data from the data view + * + * Usage: + * + * get() + * get(options: Object) + * get(options: Object, data: Array | DataTable) + * + * get(id: Number) + * get(id: Number, options: Object) + * get(id: Number, options: Object, data: Array | DataTable) + * + * get(ids: Number[]) + * get(ids: Number[], options: Object) + * get(ids: Number[], options: Object, data: Array | DataTable) + * + * Where: + * + * {Number | String} id The id of an item + * {Number[] | String{}} ids An array with ids of items + * {Object} options An Object with options. Available options: + * {String} [type] Type of data to be returned. Can + * be 'DataTable' or 'Array' (default) + * {Object.} [fieldTypes] + * {String[]} [fields] field names to be returned + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * {Array | DataTable} [data] If provided, items will be appended to this + * array or table. Required in case of Google + * DataTable. + * @param args + */ +DataView.prototype.get = function (args) { + var me = this; + + // parse the arguments + var ids, options, data; + var firstType = util.getType(arguments[0]); + if (firstType == 'String' || firstType == 'Number' || firstType == 'Array') { + // get(id(s) [, options] [, data]) + ids = arguments[0]; // can be a single id or an array with ids + options = arguments[1]; + data = arguments[2]; + } + else { + // get([, options] [, data]) + options = arguments[0]; + data = arguments[1]; + } + + // extend the options with the default options and provided options + var viewOptions = util.extend({}, this.options, options); + + // create a combined filter method when needed + if (this.options.filter && options && options.filter) { + viewOptions.filter = function (item) { + return me.options.filter(item) && options.filter(item); + } + } + + // build up the call to the linked data set + var getArguments = []; + if (ids != undefined) { + getArguments.push(ids); + } + getArguments.push(viewOptions); + getArguments.push(data); + + return this.data && this.data.get.apply(this.data, getArguments); +}; + +/** + * Get ids of all items or from a filtered set of items. + * @param {Object} [options] An Object with options. Available options: + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * @return {Array} ids + */ +DataView.prototype.getIds = function (options) { + var ids; + + if (this.data) { + var defaultFilter = this.options.filter; + var filter; + + if (options && options.filter) { + if (defaultFilter) { + filter = function (item) { + return defaultFilter(item) && options.filter(item); + } + } + else { + filter = options.filter; + } + } + else { + filter = defaultFilter; + } + + ids = this.data.getIds({ + filter: filter, + order: options && options.order + }); + } + else { + ids = []; + } + + return ids; +}; + +/** + * Event listener. Will propagate all events from the connected data set to + * the subscribers of the DataView, but will filter the items and only trigger + * when there are changes in the filtered data set. + * @param {String} event + * @param {Object | null} params + * @param {String} senderId + * @private + */ +DataView.prototype._onEvent = function (event, params, senderId) { + var i, len, id, item, + ids = params && params.items, + data = this.data, + added = [], + updated = [], + removed = []; + + if (ids && data) { + switch (event) { + case 'add': + // filter the ids of the added items + for (i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + item = this.get(id); + if (item) { + this.ids[id] = true; + added.push(id); + } + } + + break; + + case 'update': + // determine the event from the views viewpoint: an updated + // item can be added, updated, or removed from this view. + for (i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + item = this.get(id); + + if (item) { + if (this.ids[id]) { + updated.push(id); + } + else { + this.ids[id] = true; + added.push(id); + } + } + else { + if (this.ids[id]) { + delete this.ids[id]; + removed.push(id); + } + else { + // nothing interesting for me :-( + } + } + } + + break; + + case 'remove': + // filter the ids of the removed items + for (i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + if (this.ids[id]) { + delete this.ids[id]; + removed.push(id); + } + } + + break; + } + + if (added.length) { + this._trigger('add', {items: added}, senderId); + } + if (updated.length) { + this._trigger('update', {items: updated}, senderId); + } + if (removed.length) { + this._trigger('remove', {items: removed}, senderId); + } + } +}; + +// copy subscription functionality from DataSet +DataView.prototype.subscribe = DataSet.prototype.subscribe; +DataView.prototype.unsubscribe = DataSet.prototype.unsubscribe; +DataView.prototype._trigger = DataSet.prototype._trigger; + +/** + * @constructor TimeStep + * The class TimeStep is an iterator for dates. You provide a start date and an + * end date. The class itself determines the best scale (step size) based on the + * provided start Date, end Date, and minimumStep. + * + * If minimumStep is provided, the step size is chosen as close as possible + * to the minimumStep but larger than minimumStep. If minimumStep is not + * provided, the scale is set to 1 DAY. + * The minimumStep should correspond with the onscreen size of about 6 characters + * + * Alternatively, you can set a scale by hand. + * After creation, you can initialize the class by executing first(). Then you + * can iterate from the start date to the end date via next(). You can check if + * the end date is reached with the function hasNext(). After each step, you can + * retrieve the current date via getCurrent(). + * The TimeStep has scales ranging from milliseconds, seconds, minutes, hours, + * days, to years. + * + * Version: 1.2 + * + * @param {Date} [start] The start date, for example new Date(2010, 9, 21) + * or new Date(2010, 9, 21, 23, 45, 00) + * @param {Date} [end] The end date + * @param {Number} [minimumStep] Optional. Minimum step size in milliseconds + */ +TimeStep = function(start, end, minimumStep) { + // variables + this.current = new Date(); + this._start = new Date(); + this._end = new Date(); + + this.autoScale = true; + this.scale = TimeStep.SCALE.DAY; + this.step = 1; + + // initialize the range + this.setRange(start, end, minimumStep); +}; + +/// enum scale +TimeStep.SCALE = { + MILLISECOND: 1, + SECOND: 2, + MINUTE: 3, + HOUR: 4, + DAY: 5, + WEEKDAY: 6, + MONTH: 7, + YEAR: 8 +}; + + +/** + * Set a new range + * If minimumStep is provided, the step size is chosen as close as possible + * to the minimumStep but larger than minimumStep. If minimumStep is not + * provided, the scale is set to 1 DAY. + * The minimumStep should correspond with the onscreen size of about 6 characters + * @param {Date} [start] The start date and time. + * @param {Date} [end] The end date and time. + * @param {int} [minimumStep] Optional. Minimum step size in milliseconds + */ +TimeStep.prototype.setRange = function(start, end, minimumStep) { + if (!(start instanceof Date) || !(end instanceof Date)) { + //throw "No legal start or end date in method setRange"; + return; + } + + this._start = (start != undefined) ? new Date(start.valueOf()) : new Date(); + this._end = (end != undefined) ? new Date(end.valueOf()) : new Date(); + + if (this.autoScale) { + this.setMinimumStep(minimumStep); + } +}; + +/** + * Set the range iterator to the start date. + */ +TimeStep.prototype.first = function() { + this.current = new Date(this._start.valueOf()); + this.roundToMinor(); +}; + +/** + * Round the current date to the first minor date value + * This must be executed once when the current date is set to start Date + */ +TimeStep.prototype.roundToMinor = function() { + // round to floor + // IMPORTANT: we have no breaks in this switch! (this is no bug) + //noinspection FallthroughInSwitchStatementJS + switch (this.scale) { + case TimeStep.SCALE.YEAR: + this.current.setFullYear(this.step * Math.floor(this.current.getFullYear() / this.step)); + this.current.setMonth(0); + case TimeStep.SCALE.MONTH: this.current.setDate(1); + case TimeStep.SCALE.DAY: // intentional fall through + case TimeStep.SCALE.WEEKDAY: this.current.setHours(0); + case TimeStep.SCALE.HOUR: this.current.setMinutes(0); + case TimeStep.SCALE.MINUTE: this.current.setSeconds(0); + case TimeStep.SCALE.SECOND: this.current.setMilliseconds(0); + //case TimeStep.SCALE.MILLISECOND: // nothing to do for milliseconds + } + + if (this.step != 1) { + // round down to the first minor value that is a multiple of the current step size + switch (this.scale) { + case TimeStep.SCALE.MILLISECOND: this.current.setMilliseconds(this.current.getMilliseconds() - this.current.getMilliseconds() % this.step); break; + case TimeStep.SCALE.SECOND: this.current.setSeconds(this.current.getSeconds() - this.current.getSeconds() % this.step); break; + case TimeStep.SCALE.MINUTE: this.current.setMinutes(this.current.getMinutes() - this.current.getMinutes() % this.step); break; + case TimeStep.SCALE.HOUR: this.current.setHours(this.current.getHours() - this.current.getHours() % this.step); break; + case TimeStep.SCALE.WEEKDAY: // intentional fall through + case TimeStep.SCALE.DAY: this.current.setDate((this.current.getDate()-1) - (this.current.getDate()-1) % this.step + 1); break; + case TimeStep.SCALE.MONTH: this.current.setMonth(this.current.getMonth() - this.current.getMonth() % this.step); break; + case TimeStep.SCALE.YEAR: this.current.setFullYear(this.current.getFullYear() - this.current.getFullYear() % this.step); break; + default: break; + } + } +}; + +/** + * Check if the there is a next step + * @return {boolean} true if the current date has not passed the end date + */ +TimeStep.prototype.hasNext = function () { + return (this.current.valueOf() <= this._end.valueOf()); +}; + +/** + * Do the next step + */ +TimeStep.prototype.next = function() { + var prev = this.current.valueOf(); + + // Two cases, needed to prevent issues with switching daylight savings + // (end of March and end of October) + if (this.current.getMonth() < 6) { + switch (this.scale) { + case TimeStep.SCALE.MILLISECOND: + + this.current = new Date(this.current.valueOf() + this.step); break; + case TimeStep.SCALE.SECOND: this.current = new Date(this.current.valueOf() + this.step * 1000); break; + case TimeStep.SCALE.MINUTE: this.current = new Date(this.current.valueOf() + this.step * 1000 * 60); break; + case TimeStep.SCALE.HOUR: + this.current = new Date(this.current.valueOf() + this.step * 1000 * 60 * 60); + // in case of skipping an hour for daylight savings, adjust the hour again (else you get: 0h 5h 9h ... instead of 0h 4h 8h ...) + var h = this.current.getHours(); + this.current.setHours(h - (h % this.step)); + break; + case TimeStep.SCALE.WEEKDAY: // intentional fall through + case TimeStep.SCALE.DAY: this.current.setDate(this.current.getDate() + this.step); break; + case TimeStep.SCALE.MONTH: this.current.setMonth(this.current.getMonth() + this.step); break; + case TimeStep.SCALE.YEAR: this.current.setFullYear(this.current.getFullYear() + this.step); break; + default: break; + } + } + else { + switch (this.scale) { + case TimeStep.SCALE.MILLISECOND: this.current = new Date(this.current.valueOf() + this.step); break; + case TimeStep.SCALE.SECOND: this.current.setSeconds(this.current.getSeconds() + this.step); break; + case TimeStep.SCALE.MINUTE: this.current.setMinutes(this.current.getMinutes() + this.step); break; + case TimeStep.SCALE.HOUR: this.current.setHours(this.current.getHours() + this.step); break; + case TimeStep.SCALE.WEEKDAY: // intentional fall through + case TimeStep.SCALE.DAY: this.current.setDate(this.current.getDate() + this.step); break; + case TimeStep.SCALE.MONTH: this.current.setMonth(this.current.getMonth() + this.step); break; + case TimeStep.SCALE.YEAR: this.current.setFullYear(this.current.getFullYear() + this.step); break; + default: break; + } + } + + if (this.step != 1) { + // round down to the correct major value + switch (this.scale) { + case TimeStep.SCALE.MILLISECOND: if(this.current.getMilliseconds() < this.step) this.current.setMilliseconds(0); break; + case TimeStep.SCALE.SECOND: if(this.current.getSeconds() < this.step) this.current.setSeconds(0); break; + case TimeStep.SCALE.MINUTE: if(this.current.getMinutes() < this.step) this.current.setMinutes(0); break; + case TimeStep.SCALE.HOUR: if(this.current.getHours() < this.step) this.current.setHours(0); break; + case TimeStep.SCALE.WEEKDAY: // intentional fall through + case TimeStep.SCALE.DAY: if(this.current.getDate() < this.step+1) this.current.setDate(1); break; + case TimeStep.SCALE.MONTH: if(this.current.getMonth() < this.step) this.current.setMonth(0); break; + case TimeStep.SCALE.YEAR: break; // nothing to do for year + default: break; + } + } + + // safety mechanism: if current time is still unchanged, move to the end + if (this.current.valueOf() == prev) { + this.current = new Date(this._end.valueOf()); + } +}; + + +/** + * Get the current datetime + * @return {Date} current The current date + */ +TimeStep.prototype.getCurrent = function() { + return this.current; +}; + +/** + * Set a custom scale. Autoscaling will be disabled. + * For example setScale(SCALE.MINUTES, 5) will result + * in minor steps of 5 minutes, and major steps of an hour. + * + * @param {TimeStep.SCALE} newScale + * A scale. Choose from SCALE.MILLISECOND, + * SCALE.SECOND, SCALE.MINUTE, SCALE.HOUR, + * SCALE.WEEKDAY, SCALE.DAY, SCALE.MONTH, + * SCALE.YEAR. + * @param {Number} newStep A step size, by default 1. Choose for + * example 1, 2, 5, or 10. + */ +TimeStep.prototype.setScale = function(newScale, newStep) { + this.scale = newScale; + + if (newStep > 0) { + this.step = newStep; + } + + this.autoScale = false; +}; + +/** + * Enable or disable autoscaling + * @param {boolean} enable If true, autoascaling is set true + */ +TimeStep.prototype.setAutoScale = function (enable) { + this.autoScale = enable; +}; + + +/** + * Automatically determine the scale that bests fits the provided minimum step + * @param {Number} [minimumStep] The minimum step size in milliseconds + */ +TimeStep.prototype.setMinimumStep = function(minimumStep) { + if (minimumStep == undefined) { + return; + } + + var stepYear = (1000 * 60 * 60 * 24 * 30 * 12); + var stepMonth = (1000 * 60 * 60 * 24 * 30); + var stepDay = (1000 * 60 * 60 * 24); + var stepHour = (1000 * 60 * 60); + var stepMinute = (1000 * 60); + var stepSecond = (1000); + var stepMillisecond= (1); + + // find the smallest step that is larger than the provided minimumStep + if (stepYear*1000 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 1000;} + if (stepYear*500 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 500;} + if (stepYear*100 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 100;} + if (stepYear*50 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 50;} + if (stepYear*10 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 10;} + if (stepYear*5 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 5;} + if (stepYear > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 1;} + if (stepMonth*3 > minimumStep) {this.scale = TimeStep.SCALE.MONTH; this.step = 3;} + if (stepMonth > minimumStep) {this.scale = TimeStep.SCALE.MONTH; this.step = 1;} + if (stepDay*5 > minimumStep) {this.scale = TimeStep.SCALE.DAY; this.step = 5;} + if (stepDay*2 > minimumStep) {this.scale = TimeStep.SCALE.DAY; this.step = 2;} + if (stepDay > minimumStep) {this.scale = TimeStep.SCALE.DAY; this.step = 1;} + if (stepDay/2 > minimumStep) {this.scale = TimeStep.SCALE.WEEKDAY; this.step = 1;} + if (stepHour*4 > minimumStep) {this.scale = TimeStep.SCALE.HOUR; this.step = 4;} + if (stepHour > minimumStep) {this.scale = TimeStep.SCALE.HOUR; this.step = 1;} + if (stepMinute*15 > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 15;} + if (stepMinute*10 > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 10;} + if (stepMinute*5 > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 5;} + if (stepMinute > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 1;} + if (stepSecond*15 > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 15;} + if (stepSecond*10 > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 10;} + if (stepSecond*5 > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 5;} + if (stepSecond > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 1;} + if (stepMillisecond*200 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 200;} + if (stepMillisecond*100 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 100;} + if (stepMillisecond*50 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 50;} + if (stepMillisecond*10 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 10;} + if (stepMillisecond*5 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 5;} + if (stepMillisecond > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 1;} +}; + +/** + * Snap a date to a rounded value. The snap intervals are dependent on the + * current scale and step. + * @param {Date} date the date to be snapped + */ +TimeStep.prototype.snap = function(date) { + if (this.scale == TimeStep.SCALE.YEAR) { + var year = date.getFullYear() + Math.round(date.getMonth() / 12); + date.setFullYear(Math.round(year / this.step) * this.step); + date.setMonth(0); + date.setDate(0); + date.setHours(0); + date.setMinutes(0); + date.setSeconds(0); + date.setMilliseconds(0); + } + else if (this.scale == TimeStep.SCALE.MONTH) { + if (date.getDate() > 15) { + date.setDate(1); + date.setMonth(date.getMonth() + 1); + // important: first set Date to 1, after that change the month. + } + else { + date.setDate(1); + } + + date.setHours(0); + date.setMinutes(0); + date.setSeconds(0); + date.setMilliseconds(0); + } + else if (this.scale == TimeStep.SCALE.DAY || + this.scale == TimeStep.SCALE.WEEKDAY) { + //noinspection FallthroughInSwitchStatementJS + switch (this.step) { + case 5: + case 2: + date.setHours(Math.round(date.getHours() / 24) * 24); break; + default: + date.setHours(Math.round(date.getHours() / 12) * 12); break; + } + date.setMinutes(0); + date.setSeconds(0); + date.setMilliseconds(0); + } + else if (this.scale == TimeStep.SCALE.HOUR) { + switch (this.step) { + case 4: + date.setMinutes(Math.round(date.getMinutes() / 60) * 60); break; + default: + date.setMinutes(Math.round(date.getMinutes() / 30) * 30); break; + } + date.setSeconds(0); + date.setMilliseconds(0); + } else if (this.scale == TimeStep.SCALE.MINUTE) { + //noinspection FallthroughInSwitchStatementJS + switch (this.step) { + case 15: + case 10: + date.setMinutes(Math.round(date.getMinutes() / 5) * 5); + date.setSeconds(0); + break; + case 5: + date.setSeconds(Math.round(date.getSeconds() / 60) * 60); break; + default: + date.setSeconds(Math.round(date.getSeconds() / 30) * 30); break; + } + date.setMilliseconds(0); + } + else if (this.scale == TimeStep.SCALE.SECOND) { + //noinspection FallthroughInSwitchStatementJS + switch (this.step) { + case 15: + case 10: + date.setSeconds(Math.round(date.getSeconds() / 5) * 5); + date.setMilliseconds(0); + break; + case 5: + date.setMilliseconds(Math.round(date.getMilliseconds() / 1000) * 1000); break; + default: + date.setMilliseconds(Math.round(date.getMilliseconds() / 500) * 500); break; + } + } + else if (this.scale == TimeStep.SCALE.MILLISECOND) { + var step = this.step > 5 ? this.step / 2 : 1; + date.setMilliseconds(Math.round(date.getMilliseconds() / step) * step); + } +}; + +/** + * Check if the current value is a major value (for example when the step + * is DAY, a major value is each first day of the MONTH) + * @return {boolean} true if current date is major, else false. + */ +TimeStep.prototype.isMajor = function() { + switch (this.scale) { + case TimeStep.SCALE.MILLISECOND: + return (this.current.getMilliseconds() == 0); + case TimeStep.SCALE.SECOND: + return (this.current.getSeconds() == 0); + case TimeStep.SCALE.MINUTE: + return (this.current.getHours() == 0) && (this.current.getMinutes() == 0); + // Note: this is no bug. Major label is equal for both minute and hour scale + case TimeStep.SCALE.HOUR: + return (this.current.getHours() == 0); + case TimeStep.SCALE.WEEKDAY: // intentional fall through + case TimeStep.SCALE.DAY: + return (this.current.getDate() == 1); + case TimeStep.SCALE.MONTH: + return (this.current.getMonth() == 0); + case TimeStep.SCALE.YEAR: + return false; + default: + return false; + } +}; + + +/** + * Returns formatted text for the minor axislabel, depending on the current + * date and the scale. For example when scale is MINUTE, the current time is + * formatted as "hh:mm". + * @param {Date} [date] custom date. if not provided, current date is taken + */ +TimeStep.prototype.getLabelMinor = function(date) { + if (date == undefined) { + date = this.current; + } + + switch (this.scale) { + case TimeStep.SCALE.MILLISECOND: return moment(date).format('SSS'); + case TimeStep.SCALE.SECOND: return moment(date).format('s'); + case TimeStep.SCALE.MINUTE: return moment(date).format('HH:mm'); + case TimeStep.SCALE.HOUR: return moment(date).format('HH:mm'); + case TimeStep.SCALE.WEEKDAY: return moment(date).format('ddd D'); + case TimeStep.SCALE.DAY: return moment(date).format('D'); + case TimeStep.SCALE.MONTH: return moment(date).format('MMM'); + case TimeStep.SCALE.YEAR: return moment(date).format('YYYY'); + default: return ''; + } +}; + + +/** + * Returns formatted text for the major axis label, depending on the current + * date and the scale. For example when scale is MINUTE, the major scale is + * hours, and the hour will be formatted as "hh". + * @param {Date} [date] custom date. if not provided, current date is taken + */ +TimeStep.prototype.getLabelMajor = function(date) { + if (date == undefined) { + date = this.current; + } + + //noinspection FallthroughInSwitchStatementJS + switch (this.scale) { + case TimeStep.SCALE.MILLISECOND:return moment(date).format('HH:mm:ss'); + case TimeStep.SCALE.SECOND: return moment(date).format('D MMMM HH:mm'); + case TimeStep.SCALE.MINUTE: + case TimeStep.SCALE.HOUR: return moment(date).format('ddd D MMMM'); + case TimeStep.SCALE.WEEKDAY: + case TimeStep.SCALE.DAY: return moment(date).format('MMMM YYYY'); + case TimeStep.SCALE.MONTH: return moment(date).format('YYYY'); + case TimeStep.SCALE.YEAR: return ''; + default: return ''; + } +}; + +/** + * @constructor Stack + * Stacks items on top of each other. + * @param {ItemSet} parent + * @param {Object} [options] + */ +function Stack (parent, options) { + this.parent = parent; + + this.options = options || {}; + this.defaultOptions = { + order: function (a, b) { + //return (b.width - a.width) || (a.left - b.left); // TODO: cleanup + // Order: ranges over non-ranges, ranged ordered by width, and + // lastly ordered by start. + if (a instanceof ItemRange) { + if (b instanceof ItemRange) { + var aInt = (a.data.end - a.data.start); + var bInt = (b.data.end - b.data.start); + return (aInt - bInt) || (a.data.start - b.data.start); + } + else { + return -1; + } + } + else { + if (b instanceof ItemRange) { + return 1; + } + else { + return (a.data.start - b.data.start); + } + } + }, + margin: { + item: 10 + } + }; + + this.ordered = []; // ordered items +} + +/** + * Set options for the stack + * @param {Object} options Available options: + * {ItemSet} parent + * {Number} margin + * {function} order Stacking order + */ +Stack.prototype.setOptions = function setOptions (options) { + util.extend(this.options, options); + + // TODO: register on data changes at the connected parent itemset, and update the changed part only and immediately +}; + +/** + * Stack the items such that they don't overlap. The items will have a minimal + * distance equal to options.margin.item. + */ +Stack.prototype.update = function update() { + this._order(); + this._stack(); +}; + +/** + * Order the items. The items are ordered by width first, and by left position + * second. + * If a custom order function has been provided via the options, then this will + * be used. + * @private + */ +Stack.prototype._order = function _order () { + var items = this.parent.items; + if (!items) { + throw new Error('Cannot stack items: parent does not contain items'); + } + + // TODO: store the sorted items, to have less work later on + var ordered = []; + var index = 0; + // items is a map (no array) + util.forEach(items, function (item) { + if (item.visible) { + ordered[index] = item; + index++; + } + }); + + //if a customer stack order function exists, use it. + var order = this.options.order || this.defaultOptions.order; + if (!(typeof order === 'function')) { + throw new Error('Option order must be a function'); + } + + ordered.sort(order); + + this.ordered = ordered; +}; + +/** + * Adjust vertical positions of the events such that they don't overlap each + * other. + * @private + */ +Stack.prototype._stack = function _stack () { + var i, + iMax, + ordered = this.ordered, + options = this.options, + orientation = options.orientation || this.defaultOptions.orientation, + axisOnTop = (orientation == 'top'), + margin; + + if (options.margin && options.margin.item !== undefined) { + margin = options.margin.item; + } + else { + margin = this.defaultOptions.margin.item + } + + // calculate new, non-overlapping positions + for (i = 0, iMax = ordered.length; i < iMax; i++) { + var item = ordered[i]; + var collidingItem = null; + do { + // TODO: optimize checking for overlap. when there is a gap without items, + // you only need to check for items from the next item on, not from zero + collidingItem = this.checkOverlap(ordered, i, 0, i - 1, margin); + if (collidingItem != null) { + // There is a collision. Reposition the event above the colliding element + if (axisOnTop) { + item.top = collidingItem.top + collidingItem.height + margin; + } + else { + item.top = collidingItem.top - item.height - margin; + } + } + } while (collidingItem); + } +}; + +/** + * Check if the destiny position of given item overlaps with any + * of the other items from index itemStart to itemEnd. + * @param {Array} items Array with items + * @param {int} itemIndex Number of the item to be checked for overlap + * @param {int} itemStart First item to be checked. + * @param {int} itemEnd Last item to be checked. + * @return {Object | null} colliding item, or undefined when no collisions + * @param {Number} margin A minimum required margin. + * If margin is provided, the two items will be + * marked colliding when they overlap or + * when the margin between the two is smaller than + * the requested margin. + */ +Stack.prototype.checkOverlap = function checkOverlap (items, itemIndex, + itemStart, itemEnd, margin) { + var collision = this.collision; + + // we loop from end to start, as we suppose that the chance of a + // collision is larger for items at the end, so check these first. + var a = items[itemIndex]; + for (var i = itemEnd; i >= itemStart; i--) { + var b = items[i]; + if (collision(a, b, margin)) { + if (i != itemIndex) { + return b; + } + } + } + + return null; +}; + +/** + * Test if the two provided items collide + * The items must have parameters left, width, top, and height. + * @param {Component} a The first item + * @param {Component} b The second item + * @param {Number} margin A minimum required margin. + * If margin is provided, the two items will be + * marked colliding when they overlap or + * when the margin between the two is smaller than + * the requested margin. + * @return {boolean} true if a and b collide, else false + */ +Stack.prototype.collision = function collision (a, b, margin) { + return ((a.left - margin) < (b.left + b.width) && + (a.left + a.width + margin) > b.left && + (a.top - margin) < (b.top + b.height) && + (a.top + a.height + margin) > b.top); +}; + +/** + * @constructor Range + * A Range controls a numeric range with a start and end value. + * The Range adjusts the range based on mouse events or programmatic changes, + * and triggers events when the range is changing or has been changed. + * @param {Object} [options] See description at Range.setOptions + * @extends Controller + */ +function Range(options) { + this.id = util.randomUUID(); + this.start = 0; // Number + this.end = 0; // Number + + this.options = { + min: null, + max: null, + zoomMin: null, + zoomMax: null + }; + + this.listeners = []; + + this.setOptions(options); +} + +/** + * Set options for the range controller + * @param {Object} options Available options: + * {Number} start Set start value of the range + * {Number} end Set end value of the range + * {Number} min Minimum value for start + * {Number} max Maximum value for end + * {Number} zoomMin Set a minimum value for + * (end - start). + * {Number} zoomMax Set a maximum value for + * (end - start). + */ +Range.prototype.setOptions = function (options) { + util.extend(this.options, options); + + if (options.start != null || options.end != null) { + this.setRange(options.start, options.end); + } +}; + +/** + * Add listeners for mouse and touch events to the component + * @param {Component} component + * @param {String} event Available events: 'move', 'zoom' + * @param {String} direction Available directions: 'horizontal', 'vertical' + */ +Range.prototype.subscribe = function (component, event, direction) { + var me = this; + var listener; + + if (direction != 'horizontal' && direction != 'vertical') { + throw new TypeError('Unknown direction "' + direction + '". ' + + 'Choose "horizontal" or "vertical".'); + } + + //noinspection FallthroughInSwitchStatementJS + if (event == 'move') { + listener = { + component: component, + event: event, + direction: direction, + callback: function (event) { + me._onMouseDown(event, listener); + }, + params: {} + }; + + component.on('mousedown', listener.callback); + me.listeners.push(listener); + } + else if (event == 'zoom') { + listener = { + component: component, + event: event, + direction: direction, + callback: function (event) { + me._onMouseWheel(event, listener); + }, + params: {} + }; + + component.on('mousewheel', listener.callback); + me.listeners.push(listener); + } + else { + throw new TypeError('Unknown event "' + event + '". ' + + 'Choose "move" or "zoom".'); + } +}; + +/** + * Event handler + * @param {String} event name of the event, for example 'click', 'mousemove' + * @param {function} callback callback handler, invoked with the raw HTML Event + * as parameter. + */ +Range.prototype.on = function (event, callback) { + events.addListener(this, event, callback); +}; + +/** + * Trigger an event + * @param {String} event name of the event, available events: 'rangechange', + * 'rangechanged' + * @private + */ +Range.prototype._trigger = function (event) { + events.trigger(this, event, { + start: this.start, + end: this.end + }); +}; + +/** + * Set a new start and end range + * @param {Number} start + * @param {Number} end + */ +Range.prototype.setRange = function(start, end) { + var changed = this._applyRange(start, end); + if (changed) { + this._trigger('rangechange'); + this._trigger('rangechanged'); + } +}; + +/** + * Set a new start and end range. This method is the same as setRange, but + * does not trigger a range change and range changed event, and it returns + * true when the range is changed + * @param {Number} start + * @param {Number} end + * @return {Boolean} changed + * @private + */ +Range.prototype._applyRange = function(start, end) { + var newStart = (start != null) ? util.cast(start, 'Number') : this.start; + var newEnd = (end != null) ? util.cast(end, 'Number') : this.end; + var diff; + + // check for valid number + if (isNaN(newStart)) { + throw new Error('Invalid start "' + start + '"'); + } + if (isNaN(newEnd)) { + throw new Error('Invalid end "' + end + '"'); + } + + // prevent start < end + if (newEnd < newStart) { + newEnd = newStart; + } + + // prevent start < min + if (this.options.min != null) { + var min = this.options.min.valueOf(); + if (newStart < min) { + diff = (min - newStart); + newStart += diff; + newEnd += diff; + } + } + + // prevent end > max + if (this.options.max != null) { + var max = this.options.max.valueOf(); + if (newEnd > max) { + diff = (newEnd - max); + newStart -= diff; + newEnd -= diff; + } + } + + // prevent (end-start) > zoomMin + if (this.options.zoomMin != null) { + var zoomMin = this.options.zoomMin.valueOf(); + if (zoomMin < 0) { + zoomMin = 0; + } + if ((newEnd - newStart) < zoomMin) { + if ((this.end - this.start) > zoomMin) { + // zoom to the minimum + diff = (zoomMin - (newEnd - newStart)); + newStart -= diff / 2; + newEnd += diff / 2; + } + else { + // ingore this action, we are already zoomed to the minimum + newStart = this.start; + newEnd = this.end; + } + } + } + + // prevent (end-start) > zoomMin + if (this.options.zoomMax != null) { + var zoomMax = this.options.zoomMax.valueOf(); + if (zoomMax < 0) { + zoomMax = 0; + } + if ((newEnd - newStart) > zoomMax) { + if ((this.end - this.start) < zoomMax) { + // zoom to the maximum + diff = ((newEnd - newStart) - zoomMax); + newStart += diff / 2; + newEnd -= diff / 2; + } + else { + // ingore this action, we are already zoomed to the maximum + newStart = this.start; + newEnd = this.end; + } + } + } + + var changed = (this.start != newStart || this.end != newEnd); + + this.start = newStart; + this.end = newEnd; + + return changed; +}; + +/** + * Retrieve the current range. + * @return {Object} An object with start and end properties + */ +Range.prototype.getRange = function() { + return { + start: this.start, + end: this.end + }; +}; + +/** + * Calculate the conversion offset and factor for current range, based on + * the provided width + * @param {Number} width + * @returns {{offset: number, factor: number}} conversion + */ +Range.prototype.conversion = function (width) { + var start = this.start; + var end = this.end; + + return Range.conversion(this.start, this.end, width); +}; + +/** + * Static method to calculate the conversion offset and factor for a range, + * based on the provided start, end, and width + * @param {Number} start + * @param {Number} end + * @param {Number} width + * @returns {{offset: number, factor: number}} conversion + */ +Range.conversion = function (start, end, width) { + if (width != 0 && (end - start != 0)) { + return { + offset: start, + factor: width / (end - start) + } + } + else { + return { + offset: 0, + factor: 1 + }; + } +}; + +/** + * Start moving horizontally or vertically + * @param {Event} event + * @param {Object} listener Listener containing the component and params + * @private + */ +Range.prototype._onMouseDown = function(event, listener) { + event = event || window.event; + var params = listener.params; + + // only react on left mouse button down + var leftButtonDown = event.which ? (event.which == 1) : (event.button == 1); + if (!leftButtonDown) { + return; + } + + // get mouse position + params.mouseX = util.getPageX(event); + params.mouseY = util.getPageY(event); + params.previousLeft = 0; + params.previousOffset = 0; + + params.moved = false; + params.start = this.start; + params.end = this.end; + + var frame = listener.component.frame; + if (frame) { + frame.style.cursor = 'move'; + } + + // add event listeners to handle moving the contents + // we store the function onmousemove and onmouseup in the timeaxis, + // so we can remove the eventlisteners lateron in the function onmouseup + var me = this; + if (!params.onMouseMove) { + params.onMouseMove = function (event) { + me._onMouseMove(event, listener); + }; + util.addEventListener(document, "mousemove", params.onMouseMove); + } + if (!params.onMouseUp) { + params.onMouseUp = function (event) { + me._onMouseUp(event, listener); + }; + util.addEventListener(document, "mouseup", params.onMouseUp); + } + + util.preventDefault(event); +}; + +/** + * Perform moving operating. + * This function activated from within the funcion TimeAxis._onMouseDown(). + * @param {Event} event + * @param {Object} listener + * @private + */ +Range.prototype._onMouseMove = function (event, listener) { + event = event || window.event; + + var params = listener.params; + + // calculate change in mouse position + var mouseX = util.getPageX(event); + var mouseY = util.getPageY(event); + + if (params.mouseX == undefined) { + params.mouseX = mouseX; + } + if (params.mouseY == undefined) { + params.mouseY = mouseY; + } + + var diffX = mouseX - params.mouseX; + var diffY = mouseY - params.mouseY; + var diff = (listener.direction == 'horizontal') ? diffX : diffY; + + // if mouse movement is big enough, register it as a "moved" event + if (Math.abs(diff) >= 1) { + params.moved = true; + } + + var interval = (params.end - params.start); + var width = (listener.direction == 'horizontal') ? + listener.component.width : listener.component.height; + var diffRange = -diff / width * interval; + this._applyRange(params.start + diffRange, params.end + diffRange); + + // fire a rangechange event + this._trigger('rangechange'); + + util.preventDefault(event); +}; + +/** + * Stop moving operating. + * This function activated from within the function Range._onMouseDown(). + * @param {event} event + * @param {Object} listener + * @private + */ +Range.prototype._onMouseUp = function (event, listener) { + event = event || window.event; + + var params = listener.params; + + if (listener.component.frame) { + listener.component.frame.style.cursor = 'auto'; + } + + // remove event listeners here, important for Safari + if (params.onMouseMove) { + util.removeEventListener(document, "mousemove", params.onMouseMove); + params.onMouseMove = null; + } + if (params.onMouseUp) { + util.removeEventListener(document, "mouseup", params.onMouseUp); + params.onMouseUp = null; + } + //util.preventDefault(event); + + if (params.moved) { + // fire a rangechanged event + this._trigger('rangechanged'); + } +}; + +/** + * Event handler for mouse wheel event, used to zoom + * Code from http://adomas.org/javascript-mouse-wheel/ + * @param {Event} event + * @param {Object} listener + * @private + */ +Range.prototype._onMouseWheel = function(event, listener) { + event = event || window.event; + + // retrieve delta + var delta = 0; + if (event.wheelDelta) { /* IE/Opera. */ + delta = event.wheelDelta / 120; + } else if (event.detail) { /* Mozilla case. */ + // In Mozilla, sign of delta is different than in IE. + // Also, delta is multiple of 3. + delta = -event.detail / 3; + } + + // If delta is nonzero, handle it. + // Basically, delta is now positive if wheel was scrolled up, + // and negative, if wheel was scrolled down. + if (delta) { + var me = this; + var zoom = function () { + // perform the zoom action. Delta is normally 1 or -1 + var zoomFactor = delta / 5.0; + var zoomAround = null; + var frame = listener.component.frame; + if (frame) { + var size, conversion; + if (listener.direction == 'horizontal') { + size = listener.component.width; + conversion = me.conversion(size); + var frameLeft = util.getAbsoluteLeft(frame); + var mouseX = util.getPageX(event); + zoomAround = (mouseX - frameLeft) / conversion.factor + conversion.offset; + } + else { + size = listener.component.height; + conversion = me.conversion(size); + var frameTop = util.getAbsoluteTop(frame); + var mouseY = util.getPageY(event); + zoomAround = ((frameTop + size - mouseY) - frameTop) / conversion.factor + conversion.offset; + } + } + + me.zoom(zoomFactor, zoomAround); + }; + + zoom(); + } + + // Prevent default actions caused by mouse wheel. + // That might be ugly, but we handle scrolls somehow + // anyway, so don't bother here... + util.preventDefault(event); +}; + + +/** + * Zoom the range the given zoomfactor in or out. Start and end date will + * be adjusted, and the timeline will be redrawn. You can optionally give a + * date around which to zoom. + * For example, try zoomfactor = 0.1 or -0.1 + * @param {Number} zoomFactor Zooming amount. Positive value will zoom in, + * negative value will zoom out + * @param {Number} zoomAround Value around which will be zoomed. Optional + */ +Range.prototype.zoom = function(zoomFactor, zoomAround) { + // if zoomAroundDate is not provided, take it half between start Date and end Date + if (zoomAround == null) { + zoomAround = (this.start + this.end) / 2; + } + + // prevent zoom factor larger than 1 or smaller than -1 (larger than 1 will + // result in a start>=end ) + if (zoomFactor >= 1) { + zoomFactor = 0.9; + } + if (zoomFactor <= -1) { + zoomFactor = -0.9; + } + + // adjust a negative factor such that zooming in with 0.1 equals zooming + // out with a factor -0.1 + if (zoomFactor < 0) { + zoomFactor = zoomFactor / (1 + zoomFactor); + } + + // zoom start and end relative to the zoomAround value + var startDiff = (this.start - zoomAround); + var endDiff = (this.end - zoomAround); + + // calculate new start and end + var newStart = this.start - startDiff * zoomFactor; + var newEnd = this.end - endDiff * zoomFactor; + + this.setRange(newStart, newEnd); +}; + +/** + * Move the range with a given factor to the left or right. Start and end + * value will be adjusted. For example, try moveFactor = 0.1 or -0.1 + * @param {Number} moveFactor Moving amount. Positive value will move right, + * negative value will move left + */ +Range.prototype.move = function(moveFactor) { + // zoom start Date and end Date relative to the zoomAroundDate + var diff = (this.end - this.start); + + // apply new values + var newStart = this.start + diff * moveFactor; + var newEnd = this.end + diff * moveFactor; + + // TODO: reckon with min and max range + + this.start = newStart; + this.end = newEnd; +}; + +/** + * @constructor Controller + * + * A Controller controls the reflows and repaints of all visual components + */ +function Controller () { + this.id = util.randomUUID(); + this.components = {}; + + this.repaintTimer = undefined; + this.reflowTimer = undefined; +} + +/** + * Add a component to the controller + * @param {Component} component + */ +Controller.prototype.add = function add(component) { + // validate the component + if (component.id == undefined) { + throw new Error('Component has no field id'); + } + if (!(component instanceof Component) && !(component instanceof Controller)) { + throw new TypeError('Component must be an instance of ' + + 'prototype Component or Controller'); + } + + // add the component + component.controller = this; + this.components[component.id] = component; +}; + +/** + * Remove a component from the controller + * @param {Component | String} component + */ +Controller.prototype.remove = function remove(component) { + var id; + for (id in this.components) { + if (this.components.hasOwnProperty(id)) { + if (id == component || this.components[id] == component) { + break; + } + } + } + + if (id) { + delete this.components[id]; + } +}; + +/** + * Request a reflow. The controller will schedule a reflow + * @param {Boolean} [force] If true, an immediate reflow is forced. Default + * is false. + */ +Controller.prototype.requestReflow = function requestReflow(force) { + if (force) { + this.reflow(); + } + else { + if (!this.reflowTimer) { + var me = this; + this.reflowTimer = setTimeout(function () { + me.reflowTimer = undefined; + me.reflow(); + }, 0); + } + } +}; + +/** + * Request a repaint. The controller will schedule a repaint + * @param {Boolean} [force] If true, an immediate repaint is forced. Default + * is false. + */ +Controller.prototype.requestRepaint = function requestRepaint(force) { + if (force) { + this.repaint(); + } + else { + if (!this.repaintTimer) { + var me = this; + this.repaintTimer = setTimeout(function () { + me.repaintTimer = undefined; + me.repaint(); + }, 0); + } + } +}; + +/** + * Repaint all components + */ +Controller.prototype.repaint = function repaint() { + var changed = false; + + // cancel any running repaint request + if (this.repaintTimer) { + clearTimeout(this.repaintTimer); + this.repaintTimer = undefined; + } + + var done = {}; + + function repaint(component, id) { + if (!(id in done)) { + // first repaint the components on which this component is dependent + if (component.depends) { + component.depends.forEach(function (dep) { + repaint(dep, dep.id); + }); + } + if (component.parent) { + repaint(component.parent, component.parent.id); + } + + // repaint the component itself and mark as done + changed = component.repaint() || changed; + done[id] = true; + } + } + + util.forEach(this.components, repaint); + + // immediately reflow when needed + if (changed) { + this.reflow(); + } + // TODO: limit the number of nested reflows/repaints, prevent loop +}; + +/** + * Reflow all components + */ +Controller.prototype.reflow = function reflow() { + var resized = false; + + // cancel any running repaint request + if (this.reflowTimer) { + clearTimeout(this.reflowTimer); + this.reflowTimer = undefined; + } + + var done = {}; + + function reflow(component, id) { + if (!(id in done)) { + // first reflow the components on which this component is dependent + if (component.depends) { + component.depends.forEach(function (dep) { + reflow(dep, dep.id); + }); + } + if (component.parent) { + reflow(component.parent, component.parent.id); + } + + // reflow the component itself and mark as done + resized = component.reflow() || resized; + done[id] = true; + } + } + + util.forEach(this.components, reflow); + + // immediately repaint when needed + if (resized) { + this.repaint(); + } + // TODO: limit the number of nested reflows/repaints, prevent loop +}; + +/** + * Prototype for visual components + */ +function Component () { + this.id = null; + this.parent = null; + this.depends = null; + this.controller = null; + this.options = null; + + this.frame = null; // main DOM element + this.top = 0; + this.left = 0; + this.width = 0; + this.height = 0; +} + +/** + * Set parameters for the frame. Parameters will be merged in current parameter + * set. + * @param {Object} options Available parameters: + * {String | function} [className] + * {EventBus} [eventBus] + * {String | Number | function} [left] + * {String | Number | function} [top] + * {String | Number | function} [width] + * {String | Number | function} [height] + */ +Component.prototype.setOptions = function setOptions(options) { + if (options) { + util.extend(this.options, options); + + if (this.controller) { + this.requestRepaint(); + this.requestReflow(); + } + } +}; + +/** + * Get an option value by name + * The function will first check this.options object, and else will check + * this.defaultOptions. + * @param {String} name + * @return {*} value + */ +Component.prototype.getOption = function getOption(name) { + var value; + if (this.options) { + value = this.options[name]; + } + if (value === undefined && this.defaultOptions) { + value = this.defaultOptions[name]; + } + return value; +}; + +/** + * Get the container element of the component, which can be used by a child to + * add its own widgets. Not all components do have a container for childs, in + * that case null is returned. + * @returns {HTMLElement | null} container + */ +Component.prototype.getContainer = function getContainer() { + // should be implemented by the component + return null; +}; + +/** + * Get the frame element of the component, the outer HTML DOM element. + * @returns {HTMLElement | null} frame + */ +Component.prototype.getFrame = function getFrame() { + return this.frame; +}; + +/** + * Repaint the component + * @return {Boolean} changed + */ +Component.prototype.repaint = function repaint() { + // should be implemented by the component + return false; +}; + +/** + * Reflow the component + * @return {Boolean} resized + */ +Component.prototype.reflow = function reflow() { + // should be implemented by the component + return false; +}; + +/** + * Hide the component from the DOM + * @return {Boolean} changed + */ +Component.prototype.hide = function hide() { + if (this.frame && this.frame.parentNode) { + this.frame.parentNode.removeChild(this.frame); + return true; + } + else { + return false; + } +}; + +/** + * Show the component in the DOM (when not already visible). + * A repaint will be executed when the component is not visible + * @return {Boolean} changed + */ +Component.prototype.show = function show() { + if (!this.frame || !this.frame.parentNode) { + return this.repaint(); + } + else { + return false; + } +}; + +/** + * Request a repaint. The controller will schedule a repaint + */ +Component.prototype.requestRepaint = function requestRepaint() { + if (this.controller) { + this.controller.requestRepaint(); + } + else { + throw new Error('Cannot request a repaint: no controller configured'); + // TODO: just do a repaint when no parent is configured? + } +}; + +/** + * Request a reflow. The controller will schedule a reflow + */ +Component.prototype.requestReflow = function requestReflow() { + if (this.controller) { + this.controller.requestReflow(); + } + else { + throw new Error('Cannot request a reflow: no controller configured'); + // TODO: just do a reflow when no parent is configured? + } +}; + +/** + * A panel can contain components + * @param {Component} [parent] + * @param {Component[]} [depends] Components on which this components depends + * (except for the parent) + * @param {Object} [options] Available parameters: + * {String | Number | function} [left] + * {String | Number | function} [top] + * {String | Number | function} [width] + * {String | Number | function} [height] + * {String | function} [className] + * @constructor Panel + * @extends Component + */ +function Panel(parent, depends, options) { + this.id = util.randomUUID(); + this.parent = parent; + this.depends = depends; + + this.options = options || {}; +} + +Panel.prototype = new Component(); + +/** + * Set options. Will extend the current options. + * @param {Object} [options] Available parameters: + * {String | function} [className] + * {String | Number | function} [left] + * {String | Number | function} [top] + * {String | Number | function} [width] + * {String | Number | function} [height] + */ +Panel.prototype.setOptions = Component.prototype.setOptions; + +/** + * Get the container element of the panel, which can be used by a child to + * add its own widgets. + * @returns {HTMLElement} container + */ +Panel.prototype.getContainer = function () { + return this.frame; +}; + +/** + * Repaint the component + * @return {Boolean} changed + */ +Panel.prototype.repaint = function () { + var changed = 0, + update = util.updateProperty, + asSize = util.option.asSize, + options = this.options, + frame = this.frame; + if (!frame) { + frame = document.createElement('div'); + frame.className = 'panel'; + + var className = options.className; + if (className) { + if (typeof className == 'function') { + util.addClassName(frame, String(className())); + } + else { + util.addClassName(frame, String(className)); + } + } + + this.frame = frame; + changed += 1; + } + if (!frame.parentNode) { + if (!this.parent) { + throw new Error('Cannot repaint panel: no parent attached'); + } + var parentContainer = this.parent.getContainer(); + if (!parentContainer) { + throw new Error('Cannot repaint panel: parent has no container element'); + } + parentContainer.appendChild(frame); + changed += 1; + } + + changed += update(frame.style, 'top', asSize(options.top, '0px')); + changed += update(frame.style, 'left', asSize(options.left, '0px')); + changed += update(frame.style, 'width', asSize(options.width, '100%')); + changed += update(frame.style, 'height', asSize(options.height, '100%')); + + return (changed > 0); +}; + +/** + * Reflow the component + * @return {Boolean} resized + */ +Panel.prototype.reflow = function () { + var changed = 0, + update = util.updateProperty, + frame = this.frame; + + if (frame) { + changed += update(this, 'top', frame.offsetTop); + changed += update(this, 'left', frame.offsetLeft); + changed += update(this, 'width', frame.offsetWidth); + changed += update(this, 'height', frame.offsetHeight); + } + else { + changed += 1; + } + + return (changed > 0); +}; + +/** + * A root panel can hold components. The root panel must be initialized with + * a DOM element as container. + * @param {HTMLElement} container + * @param {Object} [options] Available parameters: see RootPanel.setOptions. + * @constructor RootPanel + * @extends Panel + */ +function RootPanel(container, options) { + this.id = util.randomUUID(); + this.container = container; + + this.options = options || {}; + this.defaultOptions = { + autoResize: true + }; + + this.listeners = {}; // event listeners +} + +RootPanel.prototype = new Panel(); + +/** + * Set options. Will extend the current options. + * @param {Object} [options] Available parameters: + * {String | function} [className] + * {String | Number | function} [left] + * {String | Number | function} [top] + * {String | Number | function} [width] + * {String | Number | function} [height] + * {Boolean | function} [autoResize] + */ +RootPanel.prototype.setOptions = Component.prototype.setOptions; + +/** + * Repaint the component + * @return {Boolean} changed + */ +RootPanel.prototype.repaint = function () { + var changed = 0, + update = util.updateProperty, + asSize = util.option.asSize, + options = this.options, + frame = this.frame; + if (!frame) { + frame = document.createElement('div'); + frame.className = 'graph panel'; + + var className = options.className; + if (className) { + util.addClassName(frame, util.option.asString(className)); + } + + this.frame = frame; + changed += 1; + } + if (!frame.parentNode) { + if (!this.container) { + throw new Error('Cannot repaint root panel: no container attached'); + } + this.container.appendChild(frame); + changed += 1; + } + + changed += update(frame.style, 'top', asSize(options.top, '0px')); + changed += update(frame.style, 'left', asSize(options.left, '0px')); + changed += update(frame.style, 'width', asSize(options.width, '100%')); + changed += update(frame.style, 'height', asSize(options.height, '100%')); + + this._updateEventEmitters(); + this._updateWatch(); + + return (changed > 0); +}; + +/** + * Reflow the component + * @return {Boolean} resized + */ +RootPanel.prototype.reflow = function () { + var changed = 0, + update = util.updateProperty, + frame = this.frame; + + if (frame) { + changed += update(this, 'top', frame.offsetTop); + changed += update(this, 'left', frame.offsetLeft); + changed += update(this, 'width', frame.offsetWidth); + changed += update(this, 'height', frame.offsetHeight); + } + else { + changed += 1; + } + + return (changed > 0); +}; + +/** + * Update watching for resize, depending on the current option + * @private + */ +RootPanel.prototype._updateWatch = function () { + var autoResize = this.getOption('autoResize'); + if (autoResize) { + this._watch(); + } + else { + this._unwatch(); + } +}; + +/** + * Watch for changes in the size of the frame. On resize, the Panel will + * automatically redraw itself. + * @private + */ +RootPanel.prototype._watch = function () { + var me = this; + + this._unwatch(); + + var checkSize = function () { + var autoResize = me.getOption('autoResize'); + if (!autoResize) { + // stop watching when the option autoResize is changed to false + me._unwatch(); + return; + } + + if (me.frame) { + // check whether the frame is resized + if ((me.frame.clientWidth != me.width) || + (me.frame.clientHeight != me.height)) { + me.requestReflow(); + } + } + }; + + // TODO: automatically cleanup the event listener when the frame is deleted + util.addEventListener(window, 'resize', checkSize); + + this.watchTimer = setInterval(checkSize, 1000); +}; + +/** + * Stop watching for a resize of the frame. + * @private + */ +RootPanel.prototype._unwatch = function () { + if (this.watchTimer) { + clearInterval(this.watchTimer); + this.watchTimer = undefined; + } + + // TODO: remove event listener on window.resize +}; + +/** + * Event handler + * @param {String} event name of the event, for example 'click', 'mousemove' + * @param {function} callback callback handler, invoked with the raw HTML Event + * as parameter. + */ +RootPanel.prototype.on = function (event, callback) { + // register the listener at this component + var arr = this.listeners[event]; + if (!arr) { + arr = []; + this.listeners[event] = arr; + } + arr.push(callback); + + this._updateEventEmitters(); +}; + +/** + * Update the event listeners for all event emitters + * @private + */ +RootPanel.prototype._updateEventEmitters = function () { + if (this.listeners) { + var me = this; + util.forEach(this.listeners, function (listeners, event) { + if (!me.emitters) { + me.emitters = {}; + } + if (!(event in me.emitters)) { + // create event + var frame = me.frame; + if (frame) { + //console.log('Created a listener for event ' + event + ' on component ' + me.id); // TODO: cleanup logging + var callback = function(event) { + listeners.forEach(function (listener) { + // TODO: filter on event target! + listener(event); + }); + }; + me.emitters[event] = callback; + util.addEventListener(frame, event, callback); + } + } + }); + + // TODO: be able to delete event listeners + // TODO: be able to move event listeners to a parent when available + } +}; + +/** + * A horizontal time axis + * @param {Component} parent + * @param {Component[]} [depends] Components on which this components depends + * (except for the parent) + * @param {Object} [options] See TimeAxis.setOptions for the available + * options. + * @constructor TimeAxis + * @extends Component + */ +function TimeAxis (parent, depends, options) { + this.id = util.randomUUID(); + this.parent = parent; + this.depends = depends; + + this.dom = { + majorLines: [], + majorTexts: [], + minorLines: [], + minorTexts: [], + redundant: { + majorLines: [], + majorTexts: [], + minorLines: [], + minorTexts: [] + } + }; + this.props = { + range: { + start: 0, + end: 0, + minimumStep: 0 + }, + lineTop: 0 + }; + + this.options = options || {}; + this.defaultOptions = { + orientation: 'bottom', // supported: 'top', 'bottom' + // TODO: implement timeaxis orientations 'left' and 'right' + showMinorLabels: true, + showMajorLabels: true + }; + + this.conversion = null; + this.range = null; +} + +TimeAxis.prototype = new Component(); + +// TODO: comment options +TimeAxis.prototype.setOptions = Component.prototype.setOptions; + +/** + * Set a range (start and end) + * @param {Range | Object} range A Range or an object containing start and end. + */ +TimeAxis.prototype.setRange = function (range) { + if (!(range instanceof Range) && (!range || !range.start || !range.end)) { + throw new TypeError('Range must be an instance of Range, ' + + 'or an object containing start and end.'); + } + this.range = range; +}; + +/** + * Convert a position on screen (pixels) to a datetime + * @param {int} x Position on the screen in pixels + * @return {Date} time The datetime the corresponds with given position x + */ +TimeAxis.prototype.toTime = function(x) { + var conversion = this.conversion; + return new Date(x / conversion.factor + conversion.offset); +}; + +/** + * Convert a datetime (Date object) into a position on the screen + * @param {Date} time A date + * @return {int} x The position on the screen in pixels which corresponds + * with the given date. + * @private + */ +TimeAxis.prototype.toScreen = function(time) { + var conversion = this.conversion; + return (time.valueOf() - conversion.offset) * conversion.factor; +}; + +/** + * Repaint the component + * @return {Boolean} changed + */ +TimeAxis.prototype.repaint = function () { + var changed = 0, + update = util.updateProperty, + asSize = util.option.asSize, + options = this.options, + orientation = this.getOption('orientation'), + props = this.props, + step = this.step; + + var frame = this.frame; + if (!frame) { + frame = document.createElement('div'); + this.frame = frame; + changed += 1; + } + frame.className = 'axis ' + orientation; + // TODO: custom className? + + if (!frame.parentNode) { + if (!this.parent) { + throw new Error('Cannot repaint time axis: no parent attached'); + } + var parentContainer = this.parent.getContainer(); + if (!parentContainer) { + throw new Error('Cannot repaint time axis: parent has no container element'); + } + parentContainer.appendChild(frame); + + changed += 1; + } + + var parent = frame.parentNode; + if (parent) { + var beforeChild = frame.nextSibling; + parent.removeChild(frame); // take frame offline while updating (is almost twice as fast) + + var defaultTop = (orientation == 'bottom' && this.props.parentHeight && this.height) ? + (this.props.parentHeight - this.height) + 'px' : + '0px'; + changed += update(frame.style, 'top', asSize(options.top, defaultTop)); + changed += update(frame.style, 'left', asSize(options.left, '0px')); + changed += update(frame.style, 'width', asSize(options.width, '100%')); + changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); + + // get characters width and height + this._repaintMeasureChars(); + + if (this.step) { + this._repaintStart(); + + step.first(); + var xFirstMajorLabel = undefined; + var max = 0; + while (step.hasNext() && max < 1000) { + max++; + var cur = step.getCurrent(), + x = this.toScreen(cur), + isMajor = step.isMajor(); + + // TODO: lines must have a width, such that we can create css backgrounds + + if (this.getOption('showMinorLabels')) { + this._repaintMinorText(x, step.getLabelMinor()); + } + + if (isMajor && this.getOption('showMajorLabels')) { + if (x > 0) { + if (xFirstMajorLabel == undefined) { + xFirstMajorLabel = x; + } + this._repaintMajorText(x, step.getLabelMajor()); + } + this._repaintMajorLine(x); + } + else { + this._repaintMinorLine(x); + } + + step.next(); + } + + // create a major label on the left when needed + if (this.getOption('showMajorLabels')) { + var leftTime = this.toTime(0), + leftText = step.getLabelMajor(leftTime), + widthText = leftText.length * (props.majorCharWidth || 10) + 10; // upper bound estimation + + if (xFirstMajorLabel == undefined || widthText < xFirstMajorLabel) { + this._repaintMajorText(0, leftText); + } + } + + this._repaintEnd(); + } + + this._repaintLine(); + + // put frame online again + if (beforeChild) { + parent.insertBefore(frame, beforeChild); + } + else { + parent.appendChild(frame) + } + } + + return (changed > 0); +}; + +/** + * Start a repaint. Move all DOM elements to a redundant list, where they + * can be picked for re-use, or can be cleaned up in the end + * @private + */ +TimeAxis.prototype._repaintStart = function () { + var dom = this.dom, + redundant = dom.redundant; + + redundant.majorLines = dom.majorLines; + redundant.majorTexts = dom.majorTexts; + redundant.minorLines = dom.minorLines; + redundant.minorTexts = dom.minorTexts; + + dom.majorLines = []; + dom.majorTexts = []; + dom.minorLines = []; + dom.minorTexts = []; +}; + +/** + * End a repaint. Cleanup leftover DOM elements in the redundant list + * @private + */ +TimeAxis.prototype._repaintEnd = function () { + util.forEach(this.dom.redundant, function (arr) { + while (arr.length) { + var elem = arr.pop(); + if (elem && elem.parentNode) { + elem.parentNode.removeChild(elem); + } + } + }); +}; + + +/** + * Create a minor label for the axis at position x + * @param {Number} x + * @param {String} text + * @private + */ +TimeAxis.prototype._repaintMinorText = function (x, text) { + // reuse redundant label + var label = this.dom.redundant.minorTexts.shift(); + + if (!label) { + // create new label + var content = document.createTextNode(''); + label = document.createElement('div'); + label.appendChild(content); + label.className = 'text minor'; + this.frame.appendChild(label); + } + this.dom.minorTexts.push(label); + + label.childNodes[0].nodeValue = text; + label.style.left = x + 'px'; + label.style.top = this.props.minorLabelTop + 'px'; + //label.title = title; // TODO: this is a heavy operation +}; + +/** + * Create a Major label for the axis at position x + * @param {Number} x + * @param {String} text + * @private + */ +TimeAxis.prototype._repaintMajorText = function (x, text) { + // reuse redundant label + var label = this.dom.redundant.majorTexts.shift(); + + if (!label) { + // create label + var content = document.createTextNode(text); + label = document.createElement('div'); + label.className = 'text major'; + label.appendChild(content); + this.frame.appendChild(label); + } + this.dom.majorTexts.push(label); + + label.childNodes[0].nodeValue = text; + label.style.top = this.props.majorLabelTop + 'px'; + label.style.left = x + 'px'; + //label.title = title; // TODO: this is a heavy operation +}; + +/** + * Create a minor line for the axis at position x + * @param {Number} x + * @private + */ +TimeAxis.prototype._repaintMinorLine = function (x) { + // reuse redundant line + var line = this.dom.redundant.minorLines.shift(); + + if (!line) { + // create vertical line + line = document.createElement('div'); + line.className = 'grid vertical minor'; + this.frame.appendChild(line); + } + this.dom.minorLines.push(line); + + var props = this.props; + line.style.top = props.minorLineTop + 'px'; + line.style.height = props.minorLineHeight + 'px'; + line.style.left = (x - props.minorLineWidth / 2) + 'px'; +}; + +/** + * Create a Major line for the axis at position x + * @param {Number} x + * @private + */ +TimeAxis.prototype._repaintMajorLine = function (x) { + // reuse redundant line + var line = this.dom.redundant.majorLines.shift(); + + if (!line) { + // create vertical line + line = document.createElement('DIV'); + line.className = 'grid vertical major'; + this.frame.appendChild(line); + } + this.dom.majorLines.push(line); + + var props = this.props; + line.style.top = props.majorLineTop + 'px'; + line.style.left = (x - props.majorLineWidth / 2) + 'px'; + line.style.height = props.majorLineHeight + 'px'; +}; + + +/** + * Repaint the horizontal line for the axis + * @private + */ +TimeAxis.prototype._repaintLine = function() { + var line = this.dom.line, + frame = this.frame, + options = this.options; + + // line before all axis elements + if (this.getOption('showMinorLabels') || this.getOption('showMajorLabels')) { + if (line) { + // put this line at the end of all childs + frame.removeChild(line); + frame.appendChild(line); + } + else { + // create the axis line + line = document.createElement('div'); + line.className = 'grid horizontal major'; + frame.appendChild(line); + this.dom.line = line; + } + + line.style.top = this.props.lineTop + 'px'; + } + else { + if (line && axis.parentElement) { + frame.removeChild(axis.line); + delete this.dom.line; + } + } +}; + +/** + * Create characters used to determine the size of text on the axis + * @private + */ +TimeAxis.prototype._repaintMeasureChars = function () { + // calculate the width and height of a single character + // this is used to calculate the step size, and also the positioning of the + // axis + var dom = this.dom, + text; + + if (!dom.measureCharMinor) { + text = document.createTextNode('0'); + var measureCharMinor = document.createElement('DIV'); + measureCharMinor.className = 'text minor measure'; + measureCharMinor.appendChild(text); + this.frame.appendChild(measureCharMinor); + + dom.measureCharMinor = measureCharMinor; + } + + if (!dom.measureCharMajor) { + text = document.createTextNode('0'); + var measureCharMajor = document.createElement('DIV'); + measureCharMajor.className = 'text major measure'; + measureCharMajor.appendChild(text); + this.frame.appendChild(measureCharMajor); + + dom.measureCharMajor = measureCharMajor; + } +}; + +/** + * Reflow the component + * @return {Boolean} resized + */ +TimeAxis.prototype.reflow = function () { + var changed = 0, + update = util.updateProperty, + frame = this.frame, + range = this.range; + + if (!range) { + throw new Error('Cannot repaint time axis: no range configured'); + } + + if (frame) { + changed += update(this, 'top', frame.offsetTop); + changed += update(this, 'left', frame.offsetLeft); + + // calculate size of a character + var props = this.props, + showMinorLabels = this.getOption('showMinorLabels'), + showMajorLabels = this.getOption('showMajorLabels'), + measureCharMinor = this.dom.measureCharMinor, + measureCharMajor = this.dom.measureCharMajor; + if (measureCharMinor) { + props.minorCharHeight = measureCharMinor.clientHeight; + props.minorCharWidth = measureCharMinor.clientWidth; + } + if (measureCharMajor) { + props.majorCharHeight = measureCharMajor.clientHeight; + props.majorCharWidth = measureCharMajor.clientWidth; + } + + var parentHeight = frame.parentNode ? frame.parentNode.offsetHeight : 0; + if (parentHeight != props.parentHeight) { + props.parentHeight = parentHeight; + changed += 1; + } + switch (this.getOption('orientation')) { + case 'bottom': + props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; + props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; + + props.minorLabelTop = 0; + props.majorLabelTop = props.minorLabelTop + props.minorLabelHeight; + + props.minorLineTop = -this.top; + props.minorLineHeight = Math.max(this.top + props.majorLabelHeight, 0); + props.minorLineWidth = 1; // TODO: really calculate width + + props.majorLineTop = -this.top; + props.majorLineHeight = Math.max(this.top + props.minorLabelHeight + props.majorLabelHeight, 0); + props.majorLineWidth = 1; // TODO: really calculate width + + props.lineTop = 0; + + break; + + case 'top': + props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; + props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; + + props.majorLabelTop = 0; + props.minorLabelTop = props.majorLabelTop + props.majorLabelHeight; + + props.minorLineTop = props.minorLabelTop; + props.minorLineHeight = Math.max(parentHeight - props.majorLabelHeight - this.top); + props.minorLineWidth = 1; // TODO: really calculate width + + props.majorLineTop = 0; + props.majorLineHeight = Math.max(parentHeight - this.top); + props.majorLineWidth = 1; // TODO: really calculate width + + props.lineTop = props.majorLabelHeight + props.minorLabelHeight; + + break; + + default: + throw new Error('Unkown orientation "' + this.getOption('orientation') + '"'); + } + + var height = props.minorLabelHeight + props.majorLabelHeight; + changed += update(this, 'width', frame.offsetWidth); + changed += update(this, 'height', height); + + // calculate range and step + this._updateConversion(); + + var start = util.cast(range.start, 'Date'), + end = util.cast(range.end, 'Date'), + minimumStep = this.toTime((props.minorCharWidth || 10) * 5) - this.toTime(0); + this.step = new TimeStep(start, end, minimumStep); + changed += update(props.range, 'start', start.valueOf()); + changed += update(props.range, 'end', end.valueOf()); + changed += update(props.range, 'minimumStep', minimumStep.valueOf()); + } + + return (changed > 0); +}; + +/** + * Calculate the factor and offset to convert a position on screen to the + * corresponding date and vice versa. + * After the method _updateConversion is executed once, the methods toTime + * and toScreen can be used. + * @private + */ +TimeAxis.prototype._updateConversion = function() { + var range = this.range; + if (!range) { + throw new Error('No range configured'); + } + + if (range.conversion) { + this.conversion = range.conversion(this.width); + } + else { + this.conversion = Range.conversion(range.start, range.end, this.width); + } +}; + +/** + * An ItemSet holds a set of items and ranges which can be displayed in a + * range. The width is determined by the parent of the ItemSet, and the height + * is determined by the size of the items. + * @param {Component} parent + * @param {Component[]} [depends] Components on which this components depends + * (except for the parent) + * @param {Object} [options] See ItemSet.setOptions for the available + * options. + * @constructor ItemSet + * @extends Panel + */ +// TODO: improve performance by replacing all Array.forEach with a for loop +function ItemSet(parent, depends, options) { + this.id = util.randomUUID(); + this.parent = parent; + this.depends = depends; + + // one options object is shared by this itemset and all its items + this.options = options || {}; + this.defaultOptions = { + type: 'box', + align: 'center', + orientation: 'bottom', + margin: { + axis: 20, + item: 10 + }, + padding: 5 + }; + + this.dom = {}; + + var me = this; + this.itemsData = null; // DataSet + this.range = null; // Range or Object {start: number, end: number} + + this.listeners = { + 'add': function (event, params, senderId) { + if (senderId != me.id) { + me._onAdd(params.items); + } + }, + 'update': function (event, params, senderId) { + if (senderId != me.id) { + me._onUpdate(params.items); + } + }, + 'remove': function (event, params, senderId) { + if (senderId != me.id) { + me._onRemove(params.items); + } + } + }; + + this.items = {}; // object with an Item for every data item + this.queue = {}; // queue with id/actions: 'add', 'update', 'delete' + this.stack = new Stack(this, Object.create(this.options)); + this.conversion = null; + + // TODO: ItemSet should also attach event listeners for rangechange and rangechanged, like timeaxis +} + +ItemSet.prototype = new Panel(); + +// available item types will be registered here +ItemSet.types = { + box: ItemBox, + range: ItemRange, + point: ItemPoint +}; + +/** + * Set options for the ItemSet. Existing options will be extended/overwritten. + * @param {Object} [options] The following options are available: + * {String | function} [className] + * class name for the itemset + * {String} [type] + * Default type for the items. Choose from 'box' + * (default), 'point', or 'range'. The default + * Style can be overwritten by individual items. + * {String} align + * Alignment for the items, only applicable for + * ItemBox. Choose 'center' (default), 'left', or + * 'right'. + * {String} orientation + * Orientation of the item set. Choose 'top' or + * 'bottom' (default). + * {Number} margin.axis + * Margin between the axis and the items in pixels. + * Default is 20. + * {Number} margin.item + * Margin between items in pixels. Default is 10. + * {Number} padding + * Padding of the contents of an item in pixels. + * Must correspond with the items css. Default is 5. + */ +ItemSet.prototype.setOptions = Component.prototype.setOptions; + +/** + * Set range (start and end). + * @param {Range | Object} range A Range or an object containing start and end. + */ +ItemSet.prototype.setRange = function setRange(range) { + if (!(range instanceof Range) && (!range || !range.start || !range.end)) { + throw new TypeError('Range must be an instance of Range, ' + + 'or an object containing start and end.'); + } + this.range = range; +}; + +/** + * Repaint the component + * @return {Boolean} changed + */ +ItemSet.prototype.repaint = function repaint() { + var changed = 0, + update = util.updateProperty, + asSize = util.option.asSize, + options = this.options, + orientation = this.getOption('orientation'), + defaultOptions = this.defaultOptions, + frame = this.frame; + + if (!frame) { + frame = document.createElement('div'); + frame.className = 'itemset'; + + var className = options.className; + if (className) { + util.addClassName(frame, util.option.asString(className)); + } + + // create background panel + var background = document.createElement('div'); + background.className = 'background'; + frame.appendChild(background); + this.dom.background = background; + + // create foreground panel + var foreground = document.createElement('div'); + foreground.className = 'foreground'; + frame.appendChild(foreground); + this.dom.foreground = foreground; + + // create axis panel + var axis = document.createElement('div'); + axis.className = 'itemset-axis'; + //frame.appendChild(axis); + this.dom.axis = axis; + + this.frame = frame; + changed += 1; + } + + if (!this.parent) { + throw new Error('Cannot repaint itemset: no parent attached'); + } + var parentContainer = this.parent.getContainer(); + if (!parentContainer) { + throw new Error('Cannot repaint itemset: parent has no container element'); + } + if (!frame.parentNode) { + parentContainer.appendChild(frame); + changed += 1; + } + if (!this.dom.axis.parentNode) { + parentContainer.appendChild(this.dom.axis); + changed += 1; + } + + // reposition frame + changed += update(frame.style, 'left', asSize(options.left, '0px')); + changed += update(frame.style, 'top', asSize(options.top, '0px')); + changed += update(frame.style, 'width', asSize(options.width, '100%')); + changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); + + // reposition axis + changed += update(this.dom.axis.style, 'left', asSize(options.left, '0px')); + changed += update(this.dom.axis.style, 'width', asSize(options.width, '100%')); + if (orientation == 'bottom') { + changed += update(this.dom.axis.style, 'top', (this.height + this.top) + 'px'); + } + else { // orientation == 'top' + changed += update(this.dom.axis.style, 'top', this.top + 'px'); + } + + this._updateConversion(); + + var me = this, + queue = this.queue, + itemsData = this.itemsData, + items = this.items, + dataOptions = { + fields: [(itemsData && itemsData.fieldId || 'id'), 'start', 'end', 'content', 'type'] + }; + // TODO: copy options from the itemset itself? + + // show/hide added/changed/removed items + Object.keys(queue).forEach(function (id) { + //var entry = queue[id]; + var action = queue[id]; + var item = items[id]; + //var item = entry.item; + //noinspection FallthroughInSwitchStatementJS + switch (action) { + case 'add': + case 'update': + var itemData = itemsData && itemsData.get(id, dataOptions); + + if (itemData) { + var type = itemData.type || + (itemData.start && itemData.end && 'range') || + options.type || + 'box'; + var constructor = ItemSet.types[type]; + + // TODO: how to handle items with invalid data? hide them and give a warning? or throw an error? + if (item) { + // update item + if (!constructor || !(item instanceof constructor)) { + // item type has changed, hide and delete the item + changed += item.hide(); + item = null; + } + else { + item.data = itemData; // TODO: create a method item.setData ? + changed++; + } + } + + if (!item) { + // create item + if (constructor) { + item = new constructor(me, itemData, options, defaultOptions); + changed++; + } + else { + throw new TypeError('Unknown item type "' + type + '"'); + } + } + + // force a repaint (not only a reposition) + item.repaint(); + + items[id] = item; + } + + // update queue + delete queue[id]; + break; + + case 'remove': + if (item) { + // remove DOM of the item + changed += item.hide(); + } + + // update lists + delete items[id]; + delete queue[id]; + break; + + default: + console.log('Error: unknown action "' + action + '"'); + } + }); + + // reposition all items. Show items only when in the visible area + util.forEach(this.items, function (item) { + if (item.visible) { + changed += item.show(); + item.reposition(); + } + else { + changed += item.hide(); + } + }); + + return (changed > 0); +}; + +/** + * Get the foreground container element + * @return {HTMLElement} foreground + */ +ItemSet.prototype.getForeground = function getForeground() { + return this.dom.foreground; +}; + +/** + * Get the background container element + * @return {HTMLElement} background + */ +ItemSet.prototype.getBackground = function getBackground() { + return this.dom.background; +}; + +/** + * Get the axis container element + * @return {HTMLElement} axis + */ +ItemSet.prototype.getAxis = function getAxis() { + return this.dom.axis; +}; + +/** + * Reflow the component + * @return {Boolean} resized + */ +ItemSet.prototype.reflow = function reflow () { + var changed = 0, + options = this.options, + marginAxis = options.margin && options.margin.axis || this.defaultOptions.margin.axis, + marginItem = options.margin && options.margin.item || this.defaultOptions.margin.item, + update = util.updateProperty, + asNumber = util.option.asNumber, + asSize = util.option.asSize, + frame = this.frame; + + if (frame) { + this._updateConversion(); + + util.forEach(this.items, function (item) { + changed += item.reflow(); + }); + + // TODO: stack.update should be triggered via an event, in stack itself + // TODO: only update the stack when there are changed items + this.stack.update(); + + var maxHeight = asNumber(options.maxHeight); + var fixedHeight = (asSize(options.height) != null); + var height; + if (fixedHeight) { + height = frame.offsetHeight; + } + else { + // height is not specified, determine the height from the height and positioned items + var visibleItems = this.stack.ordered; // TODO: not so nice way to get the filtered items + if (visibleItems.length) { + var min = visibleItems[0].top; + var max = visibleItems[0].top + visibleItems[0].height; + util.forEach(visibleItems, function (item) { + min = Math.min(min, item.top); + max = Math.max(max, (item.top + item.height)); + }); + height = (max - min) + marginAxis + marginItem; + } + else { + height = marginAxis + marginItem; + } + } + if (maxHeight != null) { + height = Math.min(height, maxHeight); + } + changed += update(this, 'height', height); + + // calculate height from items + changed += update(this, 'top', frame.offsetTop); + changed += update(this, 'left', frame.offsetLeft); + changed += update(this, 'width', frame.offsetWidth); + } + else { + changed += 1; + } + + return (changed > 0); +}; + +/** + * Hide this component from the DOM + * @return {Boolean} changed + */ +ItemSet.prototype.hide = function hide() { + var changed = false; + + // remove the DOM + if (this.frame && this.frame.parentNode) { + this.frame.parentNode.removeChild(this.frame); + changed = true; + } + if (this.dom.axis && this.dom.axis.parentNode) { + this.dom.axis.parentNode.removeChild(this.dom.axis); + changed = true; + } + + return changed; +}; + +/** + * Set items + * @param {vis.DataSet | null} items + */ +ItemSet.prototype.setItems = function setItems(items) { + var me = this, + ids; + + // unsubscribe from current dataset + var current = this.itemsData; + if (current) { + util.forEach(this.listeners, function (callback, event) { + current.unsubscribe(event, callback); + }); + + // remove all drawn items + ids = current.getIds(); + this._onRemove(ids); + } + + // replace the dataset + if (!items) { + this.itemsData = null; + } + else if (items instanceof DataSet || items instanceof DataView) { + this.itemsData = items; + } + else { + throw new TypeError('Data must be an instance of DataSet'); + } + + if (this.itemsData) { + // subscribe to new dataset + var id = this.id; + util.forEach(this.listeners, function (callback, event) { + me.itemsData.subscribe(event, callback, id); + }); + + // draw all new items + ids = this.itemsData.getIds(); + this._onAdd(ids); + } +}; + +/** + * Get the current items items + * @returns {vis.DataSet | null} + */ +ItemSet.prototype.getItems = function getItems() { + return this.itemsData; +}; + +/** + * Handle updated items + * @param {Number[]} ids + * @private + */ +ItemSet.prototype._onUpdate = function _onUpdate(ids) { + this._toQueue('update', ids); +}; + +/** + * Handle changed items + * @param {Number[]} ids + * @private + */ +ItemSet.prototype._onAdd = function _onAdd(ids) { + this._toQueue('add', ids); +}; + +/** + * Handle removed items + * @param {Number[]} ids + * @private + */ +ItemSet.prototype._onRemove = function _onRemove(ids) { + this._toQueue('remove', ids); +}; + +/** + * Put items in the queue to be added/updated/remove + * @param {String} action can be 'add', 'update', 'remove' + * @param {Number[]} ids + */ +ItemSet.prototype._toQueue = function _toQueue(action, ids) { + var queue = this.queue; + ids.forEach(function (id) { + queue[id] = action; + }); + + if (this.controller) { + //this.requestReflow(); + this.requestRepaint(); + } +}; + +/** + * Calculate the factor and offset to convert a position on screen to the + * corresponding date and vice versa. + * After the method _updateConversion is executed once, the methods toTime + * and toScreen can be used. + * @private + */ +ItemSet.prototype._updateConversion = function _updateConversion() { + var range = this.range; + if (!range) { + throw new Error('No range configured'); + } + + if (range.conversion) { + this.conversion = range.conversion(this.width); + } + else { + this.conversion = Range.conversion(range.start, range.end, this.width); + } +}; + +/** + * Convert a position on screen (pixels) to a datetime + * Before this method can be used, the method _updateConversion must be + * executed once. + * @param {int} x Position on the screen in pixels + * @return {Date} time The datetime the corresponds with given position x + */ +ItemSet.prototype.toTime = function toTime(x) { + var conversion = this.conversion; + return new Date(x / conversion.factor + conversion.offset); +}; + +/** + * Convert a datetime (Date object) into a position on the screen + * Before this method can be used, the method _updateConversion must be + * executed once. + * @param {Date} time A date + * @return {int} x The position on the screen in pixels which corresponds + * with the given date. + */ +ItemSet.prototype.toScreen = function toScreen(time) { + var conversion = this.conversion; + return (time.valueOf() - conversion.offset) * conversion.factor; +}; + +/** + * @constructor Item + * @param {ItemSet} parent + * @param {Object} data Object containing (optional) parameters type, + * start, end, content, group, className. + * @param {Object} [options] Options to set initial property values + * @param {Object} [defaultOptions] default options + * // TODO: describe available options + */ +function Item (parent, data, options, defaultOptions) { + this.parent = parent; + this.data = data; + this.dom = null; + this.options = options || {}; + this.defaultOptions = defaultOptions || {}; + + this.selected = false; + this.visible = false; + this.top = 0; + this.left = 0; + this.width = 0; + this.height = 0; +} + +/** + * Select current item + */ +Item.prototype.select = function select() { + this.selected = true; +}; + +/** + * Unselect current item + */ +Item.prototype.unselect = function unselect() { + this.selected = false; +}; + +/** + * Show the Item in the DOM (when not already visible) + * @return {Boolean} changed + */ +Item.prototype.show = function show() { + return false; +}; + +/** + * Hide the Item from the DOM (when visible) + * @return {Boolean} changed + */ +Item.prototype.hide = function hide() { + return false; +}; + +/** + * Repaint the item + * @return {Boolean} changed + */ +Item.prototype.repaint = function repaint() { + // should be implemented by the item + return false; +}; + +/** + * Reflow the item + * @return {Boolean} resized + */ +Item.prototype.reflow = function reflow() { + // should be implemented by the item + return false; +}; + +/** + * @constructor ItemBox + * @extends Item + * @param {ItemSet} parent + * @param {Object} data Object containing parameters start + * content, className. + * @param {Object} [options] Options to set initial property values + * @param {Object} [defaultOptions] default options + * // TODO: describe available options + */ +function ItemBox (parent, data, options, defaultOptions) { + this.props = { + dot: { + left: 0, + top: 0, + width: 0, + height: 0 + }, + line: { + top: 0, + left: 0, + width: 0, + height: 0 + } + }; + + Item.call(this, parent, data, options, defaultOptions); +} + +ItemBox.prototype = new Item (null, null); + +/** + * Select the item + * @override + */ +ItemBox.prototype.select = function select() { + this.selected = true; + // TODO: select and unselect +}; + +/** + * Unselect the item + * @override + */ +ItemBox.prototype.unselect = function unselect() { + this.selected = false; + // TODO: select and unselect +}; + +/** + * Repaint the item + * @return {Boolean} changed + */ +ItemBox.prototype.repaint = function repaint() { + // TODO: make an efficient repaint + var changed = false; + var dom = this.dom; + + if (!dom) { + this._create(); + dom = this.dom; + changed = true; + } + + if (dom) { + if (!this.parent) { + throw new Error('Cannot repaint item: no parent attached'); + } + var foreground = this.parent.getForeground(); + if (!foreground) { + throw new Error('Cannot repaint time axis: ' + + 'parent has no foreground container element'); + } + var background = this.parent.getBackground(); + if (!background) { + throw new Error('Cannot repaint time axis: ' + + 'parent has no background container element'); + } + var axis = this.parent.getAxis(); + if (!background) { + throw new Error('Cannot repaint time axis: ' + + 'parent has no axis container element'); + } + + if (!dom.box.parentNode) { + foreground.appendChild(dom.box); + changed = true; + } + if (!dom.line.parentNode) { + background.appendChild(dom.line); + changed = true; + } + if (!dom.dot.parentNode) { + axis.appendChild(dom.dot); + changed = true; + } + + // update contents + if (this.data.content != this.content) { + this.content = this.data.content; + if (this.content instanceof Element) { + dom.content.innerHTML = ''; + dom.content.appendChild(this.content); + } + else if (this.data.content != undefined) { + dom.content.innerHTML = this.content; + } + else { + throw new Error('Property "content" missing in item ' + this.data.id); + } + changed = true; + } + + // update class + var className = (this.data.className? ' ' + this.data.className : '') + + (this.selected ? ' selected' : ''); + if (this.className != className) { + this.className = className; + dom.box.className = 'item box' + className; + dom.line.className = 'item line' + className; + dom.dot.className = 'item dot' + className; + changed = true; + } + } + + return changed; +}; + +/** + * Show the item in the DOM (when not already visible). The items DOM will + * be created when needed. + * @return {Boolean} changed + */ +ItemBox.prototype.show = function show() { + if (!this.dom || !this.dom.box.parentNode) { + return this.repaint(); + } + else { + return false; + } +}; + +/** + * Hide the item from the DOM (when visible) + * @return {Boolean} changed + */ +ItemBox.prototype.hide = function hide() { + var changed = false, + dom = this.dom; + if (dom) { + if (dom.box.parentNode) { + dom.box.parentNode.removeChild(dom.box); + changed = true; + } + if (dom.line.parentNode) { + dom.line.parentNode.removeChild(dom.line); + } + if (dom.dot.parentNode) { + dom.dot.parentNode.removeChild(dom.dot); + } + } + return changed; +}; + +/** + * Reflow the item: calculate its actual size and position from the DOM + * @return {boolean} resized returns true if the axis is resized + * @override + */ +ItemBox.prototype.reflow = function reflow() { + var changed = 0, + update, + dom, + props, + options, + margin, + start, + align, + orientation, + top, + left, + data, + range; + + if (this.data.start == undefined) { + throw new Error('Property "start" missing in item ' + this.data.id); + } + + data = this.data; + range = this.parent && this.parent.range; + if (data && range) { + // TODO: account for the width of the item. Take some margin + this.visible = (data.start > range.start) && (data.start < range.end); + } + else { + this.visible = false; + } + + if (this.visible) { + dom = this.dom; + if (dom) { + update = util.updateProperty; + props = this.props; + options = this.options; + start = this.parent.toScreen(this.data.start); + align = options.align || this.defaultOptions.align; + margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; + orientation = options.orientation || this.defaultOptions.orientation; + + changed += update(props.dot, 'height', dom.dot.offsetHeight); + changed += update(props.dot, 'width', dom.dot.offsetWidth); + changed += update(props.line, 'width', dom.line.offsetWidth); + changed += update(props.line, 'height', dom.line.offsetHeight); + changed += update(props.line, 'top', dom.line.offsetTop); + changed += update(this, 'width', dom.box.offsetWidth); + changed += update(this, 'height', dom.box.offsetHeight); + if (align == 'right') { + left = start - this.width; + } + else if (align == 'left') { + left = start; + } + else { + // default or 'center' + left = start - this.width / 2; + } + changed += update(this, 'left', left); + + changed += update(props.line, 'left', start - props.line.width / 2); + changed += update(props.dot, 'left', start - props.dot.width / 2); + changed += update(props.dot, 'top', -props.dot.height / 2); + if (orientation == 'top') { + top = margin; + + changed += update(this, 'top', top); + } + else { + // default or 'bottom' + var parentHeight = this.parent.height; + top = parentHeight - this.height - margin; + + changed += update(this, 'top', top); + } + } + else { + changed += 1; + } + } + + return (changed > 0); +}; + +/** + * Create an items DOM + * @private + */ +ItemBox.prototype._create = function _create() { + var dom = this.dom; + if (!dom) { + this.dom = dom = {}; + + // create the box + dom.box = document.createElement('DIV'); + // className is updated in repaint() + + // contents box (inside the background box). used for making margins + dom.content = document.createElement('DIV'); + dom.content.className = 'content'; + dom.box.appendChild(dom.content); + + // line to axis + dom.line = document.createElement('DIV'); + dom.line.className = 'line'; + + // dot on axis + dom.dot = document.createElement('DIV'); + dom.dot.className = 'dot'; + } +}; + +/** + * Reposition the item, recalculate its left, top, and width, using the current + * range and size of the items itemset + * @override + */ +ItemBox.prototype.reposition = function reposition() { + var dom = this.dom, + props = this.props, + orientation = this.options.orientation || this.defaultOptions.orientation; + + if (dom) { + var box = dom.box, + line = dom.line, + dot = dom.dot; + + box.style.left = this.left + 'px'; + box.style.top = this.top + 'px'; + + line.style.left = props.line.left + 'px'; + if (orientation == 'top') { + line.style.top = 0 + 'px'; + line.style.height = this.top + 'px'; + } + else { + // orientation 'bottom' + line.style.top = (this.top + this.height) + 'px'; + line.style.height = Math.max(this.parent.height - this.top - this.height + + this.props.dot.height / 2, 0) + 'px'; + } + + dot.style.left = props.dot.left + 'px'; + dot.style.top = props.dot.top + 'px'; + } +}; + +/** + * @constructor ItemPoint + * @extends Item + * @param {ItemSet} parent + * @param {Object} data Object containing parameters start + * content, className. + * @param {Object} [options] Options to set initial property values + * @param {Object} [defaultOptions] default options + * // TODO: describe available options + */ +function ItemPoint (parent, data, options, defaultOptions) { + this.props = { + dot: { + top: 0, + width: 0, + height: 0 + }, + content: { + height: 0, + marginLeft: 0 + } + }; + + Item.call(this, parent, data, options, defaultOptions); +} + +ItemPoint.prototype = new Item (null, null); + +/** + * Select the item + * @override + */ +ItemPoint.prototype.select = function select() { + this.selected = true; + // TODO: select and unselect +}; + +/** + * Unselect the item + * @override + */ +ItemPoint.prototype.unselect = function unselect() { + this.selected = false; + // TODO: select and unselect +}; + +/** + * Repaint the item + * @return {Boolean} changed + */ +ItemPoint.prototype.repaint = function repaint() { + // TODO: make an efficient repaint + var changed = false; + var dom = this.dom; + + if (!dom) { + this._create(); + dom = this.dom; + changed = true; + } + + if (dom) { + if (!this.parent) { + throw new Error('Cannot repaint item: no parent attached'); + } + var foreground = this.parent.getForeground(); + if (!foreground) { + throw new Error('Cannot repaint time axis: ' + + 'parent has no foreground container element'); + } + + if (!dom.point.parentNode) { + foreground.appendChild(dom.point); + foreground.appendChild(dom.point); + changed = true; + } + + // update contents + if (this.data.content != this.content) { + this.content = this.data.content; + if (this.content instanceof Element) { + dom.content.innerHTML = ''; + dom.content.appendChild(this.content); + } + else if (this.data.content != undefined) { + dom.content.innerHTML = this.content; + } + else { + throw new Error('Property "content" missing in item ' + this.data.id); + } + changed = true; + } + + // update class + var className = (this.data.className? ' ' + this.data.className : '') + + (this.selected ? ' selected' : ''); + if (this.className != className) { + this.className = className; + dom.point.className = 'item point' + className; + changed = true; + } + } + + return changed; +}; + +/** + * Show the item in the DOM (when not already visible). The items DOM will + * be created when needed. + * @return {Boolean} changed + */ +ItemPoint.prototype.show = function show() { + if (!this.dom || !this.dom.point.parentNode) { + return this.repaint(); + } + else { + return false; + } +}; + +/** + * Hide the item from the DOM (when visible) + * @return {Boolean} changed + */ +ItemPoint.prototype.hide = function hide() { + var changed = false, + dom = this.dom; + if (dom) { + if (dom.point.parentNode) { + dom.point.parentNode.removeChild(dom.point); + changed = true; + } + } + return changed; +}; + +/** + * Reflow the item: calculate its actual size from the DOM + * @return {boolean} resized returns true if the axis is resized + * @override + */ +ItemPoint.prototype.reflow = function reflow() { + var changed = 0, + update, + dom, + props, + options, + margin, + orientation, + start, + top, + data, + range; + + if (this.data.start == undefined) { + throw new Error('Property "start" missing in item ' + this.data.id); + } + + data = this.data; + range = this.parent && this.parent.range; + if (data && range) { + // TODO: account for the width of the item. Take some margin + this.visible = (data.start > range.start) && (data.start < range.end); + } + else { + this.visible = false; + } + + if (this.visible) { + dom = this.dom; + if (dom) { + update = util.updateProperty; + props = this.props; + options = this.options; + orientation = options.orientation || this.defaultOptions.orientation; + margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; + start = this.parent.toScreen(this.data.start); + + changed += update(this, 'width', dom.point.offsetWidth); + changed += update(this, 'height', dom.point.offsetHeight); + changed += update(props.dot, 'width', dom.dot.offsetWidth); + changed += update(props.dot, 'height', dom.dot.offsetHeight); + changed += update(props.content, 'height', dom.content.offsetHeight); + + if (orientation == 'top') { + top = margin; + } + else { + // default or 'bottom' + var parentHeight = this.parent.height; + top = Math.max(parentHeight - this.height - margin, 0); + } + changed += update(this, 'top', top); + changed += update(this, 'left', start - props.dot.width / 2); + changed += update(props.content, 'marginLeft', 1.5 * props.dot.width); + //changed += update(props.content, 'marginRight', 0.5 * props.dot.width); // TODO + + changed += update(props.dot, 'top', (this.height - props.dot.height) / 2); + } + else { + changed += 1; + } + } + + return (changed > 0); +}; + +/** + * Create an items DOM + * @private + */ +ItemPoint.prototype._create = function _create() { + var dom = this.dom; + if (!dom) { + this.dom = dom = {}; + + // background box + dom.point = document.createElement('div'); + // className is updated in repaint() + + // contents box, right from the dot + dom.content = document.createElement('div'); + dom.content.className = 'content'; + dom.point.appendChild(dom.content); + + // dot at start + dom.dot = document.createElement('div'); + dom.dot.className = 'dot'; + dom.point.appendChild(dom.dot); + } +}; + +/** + * Reposition the item, recalculate its left, top, and width, using the current + * range and size of the items itemset + * @override + */ +ItemPoint.prototype.reposition = function reposition() { + var dom = this.dom, + props = this.props; + + if (dom) { + dom.point.style.top = this.top + 'px'; + dom.point.style.left = this.left + 'px'; + + dom.content.style.marginLeft = props.content.marginLeft + 'px'; + //dom.content.style.marginRight = props.content.marginRight + 'px'; // TODO + + dom.dot.style.top = props.dot.top + 'px'; + } +}; + +/** + * @constructor ItemRange + * @extends Item + * @param {ItemSet} parent + * @param {Object} data Object containing parameters start, end + * content, className. + * @param {Object} [options] Options to set initial property values + * @param {Object} [defaultOptions] default options + * // TODO: describe available options + */ +function ItemRange (parent, data, options, defaultOptions) { + this.props = { + content: { + left: 0, + width: 0 + } + }; + + Item.call(this, parent, data, options, defaultOptions); +} + +ItemRange.prototype = new Item (null, null); + +/** + * Select the item + * @override + */ +ItemRange.prototype.select = function select() { + this.selected = true; + // TODO: select and unselect +}; + +/** + * Unselect the item + * @override + */ +ItemRange.prototype.unselect = function unselect() { + this.selected = false; + // TODO: select and unselect +}; + +/** + * Repaint the item + * @return {Boolean} changed + */ +ItemRange.prototype.repaint = function repaint() { + // TODO: make an efficient repaint + var changed = false; + var dom = this.dom; + + if (!dom) { + this._create(); + dom = this.dom; + changed = true; + } + + if (dom) { + if (!this.parent) { + throw new Error('Cannot repaint item: no parent attached'); + } + var foreground = this.parent.getForeground(); + if (!foreground) { + throw new Error('Cannot repaint time axis: ' + + 'parent has no foreground container element'); + } + + if (!dom.box.parentNode) { + foreground.appendChild(dom.box); + changed = true; + } + + // update content + if (this.data.content != this.content) { + this.content = this.data.content; + if (this.content instanceof Element) { + dom.content.innerHTML = ''; + dom.content.appendChild(this.content); + } + else if (this.data.content != undefined) { + dom.content.innerHTML = this.content; + } + else { + throw new Error('Property "content" missing in item ' + this.data.id); + } + changed = true; + } + + // update class + var className = this.data.className ? ('' + this.data.className) : ''; + if (this.className != className) { + this.className = className; + dom.box.className = 'item range' + className; + changed = true; + } + } + + return changed; +}; + +/** + * Show the item in the DOM (when not already visible). The items DOM will + * be created when needed. + * @return {Boolean} changed + */ +ItemRange.prototype.show = function show() { + if (!this.dom || !this.dom.box.parentNode) { + return this.repaint(); + } + else { + return false; + } +}; + +/** + * Hide the item from the DOM (when visible) + * @return {Boolean} changed + */ +ItemRange.prototype.hide = function hide() { + var changed = false, + dom = this.dom; + if (dom) { + if (dom.box.parentNode) { + dom.box.parentNode.removeChild(dom.box); + changed = true; + } + } + return changed; +}; + +/** + * Reflow the item: calculate its actual size from the DOM + * @return {boolean} resized returns true if the axis is resized + * @override + */ +ItemRange.prototype.reflow = function reflow() { + var changed = 0, + dom, + props, + options, + margin, + padding, + parent, + start, + end, + data, + range, + update, + box, + parentWidth, + contentLeft, + orientation, + top; + + if (this.data.start == undefined) { + throw new Error('Property "start" missing in item ' + this.data.id); + } + if (this.data.end == undefined) { + throw new Error('Property "end" missing in item ' + this.data.id); + } + + data = this.data; + range = this.parent && this.parent.range; + if (data && range) { + // TODO: account for the width of the item. Take some margin + this.visible = (data.start < range.end) && (data.end > range.start); + } + else { + this.visible = false; + } + + if (this.visible) { + dom = this.dom; + if (dom) { + props = this.props; + options = this.options; + parent = this.parent; + start = parent.toScreen(this.data.start); + end = parent.toScreen(this.data.end); + update = util.updateProperty; + box = dom.box; + parentWidth = parent.width; + orientation = options.orientation || this.defaultOptions.orientation; + margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; + padding = options.padding || this.defaultOptions.padding; + + changed += update(props.content, 'width', dom.content.offsetWidth); + + changed += update(this, 'height', box.offsetHeight); + + // limit the width of the this, as browsers cannot draw very wide divs + if (start < -parentWidth) { + start = -parentWidth; + } + if (end > 2 * parentWidth) { + end = 2 * parentWidth; + } + + // when range exceeds left of the window, position the contents at the left of the visible area + if (start < 0) { + contentLeft = Math.min(-start, + (end - start - props.content.width - 2 * padding)); + // TODO: remove the need for options.padding. it's terrible. + } + else { + contentLeft = 0; + } + changed += update(props.content, 'left', contentLeft); + + if (orientation == 'top') { + top = margin; + changed += update(this, 'top', top); + } + else { + // default or 'bottom' + top = parent.height - this.height - margin; + changed += update(this, 'top', top); + } + + changed += update(this, 'left', start); + changed += update(this, 'width', Math.max(end - start, 1)); // TODO: reckon with border width; + } + else { + changed += 1; + } + } + + return (changed > 0); +}; + +/** + * Create an items DOM + * @private + */ +ItemRange.prototype._create = function _create() { + var dom = this.dom; + if (!dom) { + this.dom = dom = {}; + // background box + dom.box = document.createElement('div'); + // className is updated in repaint() + + // contents box + dom.content = document.createElement('div'); + dom.content.className = 'content'; + dom.box.appendChild(dom.content); + } +}; + +/** + * Reposition the item, recalculate its left, top, and width, using the current + * range and size of the items itemset + * @override + */ +ItemRange.prototype.reposition = function reposition() { + var dom = this.dom, + props = this.props; + + if (dom) { + dom.box.style.top = this.top + 'px'; + dom.box.style.left = this.left + 'px'; + dom.box.style.width = this.width + 'px'; + + dom.content.style.left = props.content.left + 'px'; + } +}; + +/** + * @constructor Group + * @param {GroupSet} parent + * @param {Number | String} groupId + * @param {Object} [options] Options to set initial property values + * // TODO: describe available options + * @extends Component + */ +function Group (parent, groupId, options) { + this.id = util.randomUUID(); + this.parent = parent; + + this.groupId = groupId; + this.itemsData = null; // DataSet + this.itemset = null; // ItemSet + this.options = options || {}; + this.options.top = 0; + + this.top = 0; + this.left = 0; + this.width = 0; + this.height = 0; +} + +Group.prototype = new Component(); + +// TODO: comment +Group.prototype.setOptions = Component.prototype.setOptions; + +/** + * Get the container element of the panel, which can be used by a child to + * add its own widgets. + * @returns {HTMLElement} container + */ +Group.prototype.getContainer = function () { + return this.parent.getContainer(); +}; + +/** + * Set item set for the group. The group will create a view on the itemset, + * filtered by the groups id. + * @param {DataSet | DataView} items + */ +Group.prototype.setItems = function setItems(items) { + if (this.itemset) { + // remove current item set + this.itemset.hide(); + this.itemset.setItems(); + + this.parent.controller.remove(this.itemset); + this.itemset = null; + } + + if (items) { + var groupId = this.groupId; + + var itemsetOptions = Object.create(this.options); + this.itemset = new ItemSet(this, null, itemsetOptions); + this.itemset.setRange(this.parent.range); + + this.view = new DataView(items, { + filter: function (item) { + return item.group == groupId; + } + }); + this.itemset.setItems(this.view); + + this.parent.controller.add(this.itemset); + } +}; + +/** + * Repaint the item + * @return {Boolean} changed + */ +Group.prototype.repaint = function repaint() { + return false; +}; + +/** + * Reflow the item + * @return {Boolean} resized + */ +Group.prototype.reflow = function reflow() { + var changed = 0, + update = util.updateProperty; + + changed += update(this, 'top', this.itemset ? this.itemset.top : 0); + changed += update(this, 'height', this.itemset ? this.itemset.height : 0); + + return (changed > 0); +}; + +/** + * An GroupSet holds a set of groups + * @param {Component} parent + * @param {Component[]} [depends] Components on which this components depends + * (except for the parent) + * @param {Object} [options] See GroupSet.setOptions for the available + * options. + * @constructor GroupSet + * @extends Panel + */ +function GroupSet(parent, depends, options) { + this.id = util.randomUUID(); + this.parent = parent; + this.depends = depends; + + this.options = options || {}; + + this.range = null; // Range or Object {start: number, end: number} + this.itemsData = null; // DataSet with items + this.groupsData = null; // DataSet with groups + + this.groups = {}; // map with groups + + // changes in groups are queued key/value map containing id/action + this.queue = {}; + + var me = this; + this.listeners = { + 'add': function (event, params) { + me._onAdd(params.items); + }, + 'update': function (event, params) { + me._onUpdate(params.items); + }, + 'remove': function (event, params) { + me._onRemove(params.items); + } + }; +} + +GroupSet.prototype = new Panel(); + +/** + * Set options for the GroupSet. Existing options will be extended/overwritten. + * @param {Object} [options] The following options are available: + * {String | function} groupsOrder + * TODO: describe options + */ +GroupSet.prototype.setOptions = Component.prototype.setOptions; + +GroupSet.prototype.setRange = function (range) { + // TODO: implement setRange +}; + +/** + * Set items + * @param {vis.DataSet | null} items + */ +GroupSet.prototype.setItems = function setItems(items) { + this.itemsData = items; + + for (var id in this.groups) { + if (this.groups.hasOwnProperty(id)) { + var group = this.groups[id]; + group.setItems(items); + } + } +}; + +/** + * Get items + * @return {vis.DataSet | null} items + */ +GroupSet.prototype.getItems = function getItems() { + return this.itemsData; +}; + +/** + * Set range (start and end). + * @param {Range | Object} range A Range or an object containing start and end. + */ +GroupSet.prototype.setRange = function setRange(range) { + this.range = range; +}; + +/** + * Set groups + * @param {vis.DataSet} groups + */ +GroupSet.prototype.setGroups = function setGroups(groups) { + var me = this, + ids; + + // unsubscribe from current dataset + if (this.groupsData) { + util.forEach(this.listeners, function (callback, event) { + me.groupsData.unsubscribe(event, callback); + }); + + // remove all drawn groups + ids = this.groupsData.getIds(); + this._onRemove(ids); + } + + // replace the dataset + if (!groups) { + this.groupsData = null; + } + else if (groups instanceof DataSet) { + this.groupsData = groups; + } + else { + this.groupsData = new DataSet({ + fieldTypes: { + start: 'Date', + end: 'Date' + } + }); + this.groupsData.add(groups); + } + + if (this.groupsData) { + // subscribe to new dataset + var id = this.id; + util.forEach(this.listeners, function (callback, event) { + me.groupsData.subscribe(event, callback, id); + }); + + // draw all new groups + ids = this.groupsData.getIds(); + this._onAdd(ids); + } +}; + +/** + * Get groups + * @return {vis.DataSet | null} groups + */ +GroupSet.prototype.getGroups = function getGroups() { + return this.groupsData; +}; + +/** + * Repaint the component + * @return {Boolean} changed + */ +GroupSet.prototype.repaint = function repaint() { + var changed = 0, + update = util.updateProperty, + asSize = util.option.asSize, + options = this.options, + frame = this.frame; + + if (!frame) { + frame = document.createElement('div'); + frame.className = 'groupset'; + + var className = options.className; + if (className) { + util.addClassName(frame, util.option.asString(className)); + } + + this.frame = frame; + changed += 1; + } + + if (!this.parent) { + throw new Error('Cannot repaint groupset: no parent attached'); + } + var parentContainer = this.parent.getContainer(); + if (!parentContainer) { + throw new Error('Cannot repaint groupset: parent has no container element'); + } + if (!frame.parentNode) { + parentContainer.appendChild(frame); + changed += 1; + } + + // reposition frame + changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); + changed += update(frame.style, 'top', asSize(options.top, '0px')); + changed += update(frame.style, 'left', asSize(options.left, '0px')); + changed += update(frame.style, 'width', asSize(options.width, '100%')); + + var me = this, + queue = this.queue, + groups = this.groups, + groupsData = this.groupsData; + + // show/hide added/changed/removed items + var ids = Object.keys(queue); + if (ids.length) { + ids.forEach(function (id) { + var action = queue[id]; + var group = groups[id]; + + //noinspection FallthroughInSwitchStatementJS + switch (action) { + case 'add': + case 'update': + if (!group) { + var groupOptions = Object.create(me.options); + group = new Group(me, id, groupOptions); + group.setItems(me.itemsData); // attach items data + groups[id] = group; + + me.controller.add(group); + } + + // TODO: update group data + group.data = groupsData.get(id); + + delete queue[id]; + break; + + case 'remove': + if (group) { + group.setItems(); // detach items data + delete groups[id]; + + me.controller.remove(group); + } + + // update lists + delete queue[id]; + break; + + default: + console.log('Error: unknown action "' + action + '"'); + } + }); + + // the groupset depends on each of the groups + //this.depends = this.groups; // TODO: gives a circular reference through the parent + + // TODO: apply dependencies of the groupset + + // update the top positions of the groups in the correct order + var orderedGroups = this.groupsData.getIds({ + order: this.options.groupsOrder + }); + for (var i = 0; i < orderedGroups.length; i++) { + (function (group, prevGroup) { + var top = 0; + if (prevGroup) { + top = function () { + // TODO: top must reckon with options.maxHeight + return prevGroup.top + prevGroup.height; + } + } + group.setOptions({ + top: top + }); + })(groups[orderedGroups[i]], groups[orderedGroups[i - 1]]); + } + + changed++; + } + + return (changed > 0); +}; + +/** + * Get container element + * @return {HTMLElement} container + */ +GroupSet.prototype.getContainer = function getContainer() { + // TODO: replace later on with container element for holding itemsets + return this.frame; +}; + +/** + * Reflow the component + * @return {Boolean} resized + */ +GroupSet.prototype.reflow = function reflow() { + var changed = 0, + options = this.options, + update = util.updateProperty, + asNumber = util.option.asNumber, + asSize = util.option.asSize, + frame = this.frame; + + if (frame) { + var maxHeight = asNumber(options.maxHeight); + var fixedHeight = (asSize(options.height) != null); + var height; + if (fixedHeight) { + height = frame.offsetHeight; + } + else { + // height is not specified, calculate the sum of the height of all groups + height = 0; + + for (var id in this.groups) { + if (this.groups.hasOwnProperty(id)) { + var group = this.groups[id]; + height += group.height; + } + } + } + if (maxHeight != null) { + height = Math.min(height, maxHeight); + } + changed += update(this, 'height', height); + + changed += update(this, 'top', frame.offsetTop); + changed += update(this, 'left', frame.offsetLeft); + changed += update(this, 'width', frame.offsetWidth); + } + + return (changed > 0); +}; + +/** + * Hide the component from the DOM + * @return {Boolean} changed + */ +GroupSet.prototype.hide = function hide() { + if (this.frame && this.frame.parentNode) { + this.frame.parentNode.removeChild(this.frame); + return true; + } + else { + return false; + } +}; + +/** + * Show the component in the DOM (when not already visible). + * A repaint will be executed when the component is not visible + * @return {Boolean} changed + */ +GroupSet.prototype.show = function show() { + if (!this.frame || !this.frame.parentNode) { + return this.repaint(); + } + else { + return false; + } +}; + +/** + * Handle updated groups + * @param {Number[]} ids + * @private + */ +GroupSet.prototype._onUpdate = function _onUpdate(ids) { + this._toQueue(ids, 'update'); +}; + +/** + * Handle changed groups + * @param {Number[]} ids + * @private + */ +GroupSet.prototype._onAdd = function _onAdd(ids) { + this._toQueue(ids, 'add'); +}; + +/** + * Handle removed groups + * @param {Number[]} ids + * @private + */ +GroupSet.prototype._onRemove = function _onRemove(ids) { + this._toQueue(ids, 'remove'); +}; + +/** + * Put groups in the queue to be added/updated/remove + * @param {Number[]} ids + * @param {String} action can be 'add', 'update', 'remove' + */ +GroupSet.prototype._toQueue = function _toQueue(ids, action) { + var queue = this.queue; + ids.forEach(function (id) { + queue[id] = action; + }); + + if (this.controller) { + //this.requestReflow(); + this.requestRepaint(); + } +}; + +/** + * Create a timeline visualization + * @param {HTMLElement} container + * @param {vis.DataSet | Array | DataTable} [items] + * @param {Object} [options] See Timeline.setOptions for the available options. + * @constructor + */ +function Timeline (container, items, options) { + var me = this; + this.options = util.extend({ + orientation: 'bottom', + min: null, + max: null, + zoomMin: 10, // milliseconds + zoomMax: 1000 * 60 * 60 * 24 * 365 * 10000, // milliseconds + // moveable: true, // TODO: option moveable + // zoomable: true, // TODO: option zoomable + showMinorLabels: true, + showMajorLabels: true, + autoResize: false + }, options); + + // controller + this.controller = new Controller(); + + // root panel + if (!container) { + throw new Error('No container element provided'); + } + var mainOptions = Object.create(this.options); + mainOptions.height = function () { + if (me.options.height) { + // fixed height + return me.options.height; + } + else { + // auto height + return me.timeaxis.height + me.content.height; + } + }; + this.root = new RootPanel(container, mainOptions); + this.controller.add(this.root); + + // range + var now = moment().hours(0).minutes(0).seconds(0).milliseconds(0); + this.range = new Range({ + start: now.clone().add('days', -3).valueOf(), + end: now.clone().add('days', 4).valueOf() + }); + // TODO: reckon with options moveable and zoomable + this.range.subscribe(this.root, 'move', 'horizontal'); + this.range.subscribe(this.root, 'zoom', 'horizontal'); + this.range.on('rangechange', function () { + var force = true; + me.controller.requestReflow(force); + }); + this.range.on('rangechanged', function () { + var force = true; + me.controller.requestReflow(force); + }); + + // TODO: put the listeners in setOptions, be able to dynamically change with options moveable and zoomable + + // time axis + var timeaxisOptions = Object.create(mainOptions); + timeaxisOptions.range = this.range; + this.timeaxis = new TimeAxis(this.root, [], timeaxisOptions); + this.timeaxis.setRange(this.range); + this.controller.add(this.timeaxis); + + // create itemset or groupset + this.setGroups(null); + + this.itemsData = null; // DataSet + this.groupsData = null; // DataSet + + // set data + if (items) { + this.setItems(items); + } +} + +/** + * Set options + * @param {Object} options TODO: describe the available options + */ +Timeline.prototype.setOptions = function (options) { + if (options) { + util.extend(this.options, options); + } + + this.controller.reflow(); + this.controller.repaint(); +}; + +/** + * Set items + * @param {vis.DataSet | Array | DataTable | null} items + */ +Timeline.prototype.setItems = function(items) { + var initialLoad = (this.itemsData == null); + + // convert to type DataSet when needed + var newItemSet; + if (!items) { + newItemSet = null; + } + else if (items instanceof DataSet) { + newItemSet = items; + } + if (!(items instanceof DataSet)) { + newItemSet = new DataSet({ + fieldTypes: { + start: 'Date', + end: 'Date' + } + }); + newItemSet.add(items); + } + + // set items + this.itemsData = newItemSet; + this.content.setItems(newItemSet); + + if (initialLoad && (this.options.start == undefined || this.options.end == undefined)) { + // apply the data range as range + var dataRange = this.getItemRange(); + + // add 5% on both sides + var min = dataRange.min; + var max = dataRange.max; + if (min != null && max != null) { + var interval = (max.valueOf() - min.valueOf()); + min = new Date(min.valueOf() - interval * 0.05); + max = new Date(max.valueOf() + interval * 0.05); + } + + // override specified start and/or end date + if (this.options.start != undefined) { + min = new Date(this.options.start.valueOf()); + } + if (this.options.end != undefined) { + max = new Date(this.options.end.valueOf()); + } + + // apply range if there is a min or max available + if (min != null || max != null) { + this.range.setRange(min, max); + } + } +}; + +/** + * Set groups + * @param {vis.DataSet | Array | DataTable} groups + */ +Timeline.prototype.setGroups = function(groups) { + var me = this; + this.groupsData = groups; + + // switch content type between ItemSet or GroupSet when needed + var type = this.groupsData ? GroupSet : ItemSet; + if (!(this.content instanceof type)) { + // remove old content set + if (this.content) { + this.content.hide(); + if (this.content.setItems) { + this.content.setItems(); // disconnect from items + } + if (this.content.setGroups) { + this.content.setGroups(); // disconnect from groups + } + this.controller.remove(this.content); + } + + // create new content set + var options = Object.create(this.options); + util.extend(options, { + top: function () { + if (me.options.orientation == 'top') { + return me.timeaxis.height; + } + else { + return me.root.height - me.timeaxis.height - me.content.height; + } + }, + height: function () { + if (me.options.height) { + return me.root.height - me.timeaxis.height; + } + else { + return null; + } + }, + maxHeight: function () { + if (me.options.maxHeight) { + if (!util.isNumber(me.options.maxHeight)) { + throw new TypeError('Number expected for property maxHeight'); + } + return me.options.maxHeight - me.timeaxis.height; + } + else { + return null; + } + } + }); + this.content = new type(this.root, [this.timeaxis], options); + if (this.content.setRange) { + this.content.setRange(this.range); + } + if (this.content.setItems) { + this.content.setItems(this.itemsData); + } + if (this.content.setGroups) { + this.content.setGroups(this.groupsData); + } + this.controller.add(this.content); + } +}; + +/** + * Get the data range of the item set. + * @returns {{min: Date, max: Date}} range A range with a start and end Date. + * When no minimum is found, min==null + * When no maximum is found, max==null + */ +Timeline.prototype.getItemRange = function getItemRange() { + // calculate min from start filed + var itemsData = this.itemsData, + min = null, + max = null; + + if (itemsData) { + // calculate the minimum value of the field 'start' + var minItem = itemsData.min('start'); + min = minItem ? minItem.start.valueOf() : null; + + // calculate maximum value of fields 'start' and 'end' + var maxStartItem = itemsData.max('start'); + if (maxStartItem) { + max = maxStartItem.start.valueOf(); + } + var maxEndItem = itemsData.max('end'); + if (maxEndItem) { + if (max == null) { + max = maxEndItem.end.valueOf(); + } + else { + max = Math.max(max, maxEndItem.end.valueOf()); + } + } + } + + return { + min: (min != null) ? new Date(min) : null, + max: (max != null) ? new Date(max) : null + }; +}; + +(function(exports) { + /** + * Parse a text source containing data in DOT language into a JSON object. + * The object contains two lists: one with nodes and one with edges. + * @param {String} data Text containing a graph in DOT-notation + * @return {Object} graph An object containing two parameters: + * {Object[]} nodes + * {Object[]} edges + */ + function parseDOT (data) { + dot = data; + return parseGraph(); + } + + // token types enumeration + var TOKENTYPE = { + NULL : 0, + DELIMITER : 1, + IDENTIFIER: 2, + UNKNOWN : 3 + }; + + // map with all delimiters + var DELIMITERS = { + '{': true, + '}': true, + '[': true, + ']': true, + ';': true, + '=': true, + ',': true, + + '->': true, + '--': true + }; + + var dot = ''; // current dot file + var index = 0; // current index in dot file + var c = ''; // current token character in expr + var token = ''; // current token + var tokenType = TOKENTYPE.NULL; // type of the token + + var graph = null; // object with the graph to be build + var nodeAttr = null; // global node attributes + var edgeAttr = null; // global edge attributes + + /** + * Get the first character from the dot file. + * The character is stored into the char c. If the end of the dot file is + * reached, the function puts an empty string in c. + */ + function first() { + index = 0; + c = dot.charAt(0); + } + + /** + * Get the next character from the dot file. + * The character is stored into the char c. If the end of the dot file is + * reached, the function puts an empty string in c. + */ + function next() { + index++; + c = dot.charAt(index); + } + + /** + * Preview the next character from the dot file. + * @return {String} cNext + */ + function nextPreview() { + return dot.charAt(index + 1); + } + + /** + * Test whether given character is alphabetic or numeric + * @param {String} c + * @return {Boolean} isAlphaNumeric + */ + var regexAlphaNumeric = /[a-zA-Z_0-9.#]/; + function isAlphaNumeric(c) { + return regexAlphaNumeric.test(c); + } + + /** + * Merge all properties of object b into object b + * @param {Object} a + * @param {Object} b + * @return {Object} a + */ + function merge (a, b) { + if (!a) { + a = {}; + } + + if (b) { + for (var name in b) { + if (b.hasOwnProperty(name)) { + a[name] = b[name]; + } + } + } + return a; + } + + /** + * Add a node to the current graph object. If there is already a node with + * the same id, their attributes will be merged. + * @param {Object} node + */ + function addNode(node) { + if (!graph.nodes) { + graph.nodes = {}; + } + var current = graph.nodes[node.id]; + if (current) { + // merge attributes + if (node.attr) { + current.attr = merge(current.attr, node.attr); + } + } + else { + // add + graph.nodes[node.id] = node; + if (nodeAttr) { + var attr = merge({}, nodeAttr); // clone global attributes + node.attr = merge(attr, node.attr); // merge attributes + } + } + } + + /** + * Add an edge to the current graph obect + * @param {Object} edge + */ + function addEdge(edge) { + if (!graph.edges) { + graph.edges = []; + } + graph.edges.push(edge); + if (edgeAttr) { + var attr = merge({}, edgeAttr); // clone global attributes + edge.attr = merge(attr, edge.attr); // merge attributes + } + } + + /** + * Get next token in the current dot file. + * The token and token type are available as token and tokenType + */ + function getToken() { + tokenType = TOKENTYPE.NULL; + token = ''; + + // skip over whitespaces + while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter + next(); + } + + do { + var isComment = false; + + // skip comment + if (c == '#') { + // find the previous non-space character + var i = index - 1; + while (dot.charAt(i) == ' ' || dot.charAt(i) == '\t') { + i--; + } + if (dot.charAt(i) == '\n' || dot.charAt(i) == '') { + // the # is at the start of a line, this is indeed a line comment + while (c != '' && c != '\n') { + next(); + } + isComment = true; + } + } + if (c == '/' && nextPreview() == '/') { + // skip line comment + while (c != '' && c != '\n') { + next(); + } + isComment = true; + } + if (c == '/' && nextPreview() == '*') { + // skip block comment + while (c != '') { + if (c == '*' && nextPreview() == '/') { + // end of block comment found. skip these last two characters + next(); + next(); + break; + } + else { + next(); + } + } + isComment = true; + } + + // skip over whitespaces + while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter + next(); + } + } + while (isComment); + + // check for end of dot file + if (c == '') { + // token is still empty + tokenType = TOKENTYPE.DELIMITER; + return; + } + + // check for delimiters consisting of 2 characters + var c2 = c + nextPreview(); + if (DELIMITERS[c2]) { + tokenType = TOKENTYPE.DELIMITER; + token = c2; + next(); + next(); + return; + } + + // check for delimiters consisting of 1 character + if (DELIMITERS[c]) { + tokenType = TOKENTYPE.DELIMITER; + token = c; + next(); + return; + } + + // check for an identifier (number or string) + // TODO: more precise parsing of numbers/strings + if (isAlphaNumeric(c) || c == '-') { + token += c; + next(); + + while (isAlphaNumeric(c)) { + token += c; + next(); + } + if (token == 'false') { + token = false; // cast to boolean + } + else if (token == 'true') { + token = true; // cast to boolean + } + else if (!isNaN(Number(token))) { + token = Number(token); // cast to number + } + tokenType = TOKENTYPE.IDENTIFIER; + return; + } + + // check for a string enclosed by double quotes + if (c == '"') { + next(); + while (c != '' && (c != '"' || (c == '"' && nextPreview() == '"'))) { + token += c; + if (c == '"') { // skip the escape character + next(); + } + next(); + } + if (c != '"') { + throw newSyntaxError('End of string " expected'); + } + next(); + tokenType = TOKENTYPE.IDENTIFIER; + return; + } + + // something unknown is found, wrong characters, a syntax error + tokenType = TOKENTYPE.UNKNOWN; + while (c != '') { + token += c; + next(); + } + throw new SyntaxError('Syntax error in part "' + chop(token, 30) + '"'); + } + + /** + * Parse a graph. + * @returns {Object} graph + */ + function parseGraph() { + graph = {}; + nodeAttr = null; + edgeAttr = null; + + first(); + getToken(); + + // optional strict keyword + if (token == 'strict') { + graph.strict = true; + getToken(); + } + + // graph or digraph keyword + if (token == 'graph' || token == 'digraph') { + graph.type = token; + getToken(); + } + + // graph id + if (tokenType == TOKENTYPE.IDENTIFIER) { + graph.id = token; + getToken(); + } + + // open angle bracket + if (token != '{') { + throw newSyntaxError('Angle bracket { expected'); + } + getToken(); + + // statements + parseStatements(); + + // close angle bracket + if (token != '}') { + throw newSyntaxError('Angle bracket } expected'); + } + getToken(); + + // end of file + if (token !== '') { + throw newSyntaxError('End of file expected'); + } + getToken(); + + return graph; + } + + /** + * Parse a list with statements. + */ + function parseStatements () { + while (token !== '' && token != '}') { + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Identifier expected'); + } + + parseStatement(); + if (token == ';') { + getToken(); + } + } + } + + /** + * Parse a single statement. Can be a an attribute statement, node + * statement, a series of node statements and edge statements, or a + * parameter. + */ + function parseStatement() { + var attr; + var id = token; // can be as string or a number + getToken(); + + // attribute statements + if (id == 'node') { + // node attributes + attr = parseAttributes(); + if (attr) { + nodeAttr = merge(nodeAttr, attr); + } + } + else if (id == 'edge') { + // edge attributes + attr = parseAttributes(); + if (attr) { + edgeAttr = merge(edgeAttr, attr); + } + } + else if (id == 'graph') { + // graph attributes + attr = parseAttributes(); + if (attr) { + graph.attr = merge(graph.attr, attr); + } + } + else { + if (token == '=') { + // id statement + getToken(); + if (!graph.attr) { + graph.attr = {}; + } + graph.attr[id] = token; + getToken(); + } + else { + // node statement + var node = { + id: String(id) + }; + attr = parseAttributes(); + if (attr) { + node.attr = attr; + } + addNode(node); + + // edge statements + var from = id; + while (token == '->' || token == '--') { + var type = token; + getToken(); + + var to = token; + addNode({ + id: String(to) + }); + getToken(); + attr = parseAttributes(); + + // create edge + var edge = { + from: String(from), + to: String(to), + type: type + }; + if (attr) { + edge.attr = attr; + } + addEdge(edge); + + from = to; + } + } + } + } + + /** + * Parse a set with attributes, + * for example [label="1.000", shape=solid] + * @return {Object | undefined} attr + */ + function parseAttributes() { + if (token == '[') { + getToken(); + var attr = {}; + while (token !== '' && token != ']') { + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Attribute name expected'); + } + var name = token; + + getToken(); + if (token != '=') { + throw newSyntaxError('Equal sign = expected'); + } + getToken(); + + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Attribute value expected'); + } + var value = token; + attr[name] = value; + + getToken(); + if (token ==',') { + getToken(); + } + } + getToken(); + + return attr; + } + else { + return undefined; + } + } + + /** + * Create a syntax error with extra information on current token and index. + * @param {String} message + * @returns {SyntaxError} err + */ + function newSyntaxError(message) { + return new SyntaxError(message + ', got "' + chop(token, 30) + '" (char ' + index + ')'); + } + + /** + * Chop off text after a maximum length + * @param {String} text + * @param {Number} maxLength + * @returns {String} + */ + function chop (text, maxLength) { + return (text.length <= maxLength) ? text : (text.substr(0, 27) + '...'); + } + + /** + * Convert a string containing a graph in DOT language into a map containing + * with nodes and edges in the format of graph. + * @param {String} data Text containing a graph in DOT-notation + * @return {Object} graphData + */ + function DOTToGraph (data) { + // parse the DOT file + var dotData = parseDOT(data); + var graphData = { + nodes: [], + edges: [], + options: {} + }; + + // copy the nodes + if (dotData.nodes) { + for (var id in dotData.nodes) { + if (dotData.nodes.hasOwnProperty(id)) { + var node = { + id: id, + label: id + }; + merge(node, dotData.nodes[id].attr); + if (node.image) { + node.shape = 'image'; + } + graphData.nodes.push(node); + } + } + } + + // copy the edges + if (dotData.edges) { + dotData.edges.forEach(function (dotEdge) { + var graphEdge = { + from: dotEdge.from, + to: dotEdge.to + }; + merge(graphEdge, dotEdge.attr); + graphEdge.style = (dotEdge.type == '->') ? 'arrow' : 'line'; + graphData.edges.push(graphEdge); + }); + } + + // copy the options + if (dotData.attr) { + graphData.options = dotData.attr; + } + + return graphData; + } + + // exports + exports.parseDOT = parseDOT; + exports.DOTToGraph = DOTToGraph; + +})(typeof util !== 'undefined' ? util : exports); + +/** + * Canvas shapes used by the Graph + */ +if (typeof CanvasRenderingContext2D !== 'undefined') { + + /** + * Draw a circle shape + */ + CanvasRenderingContext2D.prototype.circle = function(x, y, r) { + this.beginPath(); + this.arc(x, y, r, 0, 2*Math.PI, false); + }; + + /** + * Draw a square shape + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r size, width and height of the square + */ + CanvasRenderingContext2D.prototype.square = function(x, y, r) { + this.beginPath(); + this.rect(x - r, y - r, r * 2, r * 2); + }; + + /** + * Draw a triangle shape + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r radius, half the length of the sides of the triangle + */ + CanvasRenderingContext2D.prototype.triangle = function(x, y, r) { + // http://en.wikipedia.org/wiki/Equilateral_triangle + this.beginPath(); + + var s = r * 2; + var s2 = s / 2; + var ir = Math.sqrt(3) / 6 * s; // radius of inner circle + var h = Math.sqrt(s * s - s2 * s2); // height + + this.moveTo(x, y - (h - ir)); + this.lineTo(x + s2, y + ir); + this.lineTo(x - s2, y + ir); + this.lineTo(x, y - (h - ir)); + this.closePath(); + }; + + /** + * Draw a triangle shape in downward orientation + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r radius + */ + CanvasRenderingContext2D.prototype.triangleDown = function(x, y, r) { + // http://en.wikipedia.org/wiki/Equilateral_triangle + this.beginPath(); + + var s = r * 2; + var s2 = s / 2; + var ir = Math.sqrt(3) / 6 * s; // radius of inner circle + var h = Math.sqrt(s * s - s2 * s2); // height + + this.moveTo(x, y + (h - ir)); + this.lineTo(x + s2, y - ir); + this.lineTo(x - s2, y - ir); + this.lineTo(x, y + (h - ir)); + this.closePath(); + }; + + /** + * Draw a star shape, a star with 5 points + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r radius, half the length of the sides of the triangle + */ + CanvasRenderingContext2D.prototype.star = function(x, y, r) { + // http://www.html5canvastutorials.com/labs/html5-canvas-star-spinner/ + this.beginPath(); + + for (var n = 0; n < 10; n++) { + var radius = (n % 2 === 0) ? r * 1.3 : r * 0.5; + this.lineTo( + x + radius * Math.sin(n * 2 * Math.PI / 10), + y - radius * Math.cos(n * 2 * Math.PI / 10) + ); + } + + this.closePath(); + }; + + /** + * http://stackoverflow.com/questions/1255512/how-to-draw-a-rounded-rectangle-on-html-canvas + */ + CanvasRenderingContext2D.prototype.roundRect = function(x, y, w, h, r) { + var r2d = Math.PI/180; + if( w - ( 2 * r ) < 0 ) { r = ( w / 2 ); } //ensure that the radius isn't too large for x + if( h - ( 2 * r ) < 0 ) { r = ( h / 2 ); } //ensure that the radius isn't too large for y + this.beginPath(); + this.moveTo(x+r,y); + this.lineTo(x+w-r,y); + this.arc(x+w-r,y+r,r,r2d*270,r2d*360,false); + this.lineTo(x+w,y+h-r); + this.arc(x+w-r,y+h-r,r,0,r2d*90,false); + this.lineTo(x+r,y+h); + this.arc(x+r,y+h-r,r,r2d*90,r2d*180,false); + this.lineTo(x,y+r); + this.arc(x+r,y+r,r,r2d*180,r2d*270,false); + }; + + /** + * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + */ + CanvasRenderingContext2D.prototype.ellipse = function(x, y, w, h) { + var kappa = .5522848, + ox = (w / 2) * kappa, // control point offset horizontal + oy = (h / 2) * kappa, // control point offset vertical + xe = x + w, // x-end + ye = y + h, // y-end + xm = x + w / 2, // x-middle + ym = y + h / 2; // y-middle + + this.beginPath(); + this.moveTo(x, ym); + this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); + this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); + this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); + this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); + }; + + + + /** + * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + */ + CanvasRenderingContext2D.prototype.database = function(x, y, w, h) { + var f = 1/3; + var wEllipse = w; + var hEllipse = h * f; + + var kappa = .5522848, + ox = (wEllipse / 2) * kappa, // control point offset horizontal + oy = (hEllipse / 2) * kappa, // control point offset vertical + xe = x + wEllipse, // x-end + ye = y + hEllipse, // y-end + xm = x + wEllipse / 2, // x-middle + ym = y + hEllipse / 2, // y-middle + ymb = y + (h - hEllipse/2), // y-midlle, bottom ellipse + yeb = y + h; // y-end, bottom ellipse + + this.beginPath(); + this.moveTo(xe, ym); + + this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); + this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); + + this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); + this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); + + this.lineTo(xe, ymb); + + this.bezierCurveTo(xe, ymb + oy, xm + ox, yeb, xm, yeb); + this.bezierCurveTo(xm - ox, yeb, x, ymb + oy, x, ymb); + + this.lineTo(x, ym); + }; + + + /** + * Draw an arrow point (no line) + */ + CanvasRenderingContext2D.prototype.arrow = function(x, y, angle, length) { + // tail + var xt = x - length * Math.cos(angle); + var yt = y - length * Math.sin(angle); + + // inner tail + // TODO: allow to customize different shapes + var xi = x - length * 0.9 * Math.cos(angle); + var yi = y - length * 0.9 * Math.sin(angle); + + // left + var xl = xt + length / 3 * Math.cos(angle + 0.5 * Math.PI); + var yl = yt + length / 3 * Math.sin(angle + 0.5 * Math.PI); + + // right + var xr = xt + length / 3 * Math.cos(angle - 0.5 * Math.PI); + var yr = yt + length / 3 * Math.sin(angle - 0.5 * Math.PI); + + this.beginPath(); + this.moveTo(x, y); + this.lineTo(xl, yl); + this.lineTo(xi, yi); + this.lineTo(xr, yr); + this.closePath(); + }; + + /** + * Sets up the dashedLine functionality for drawing + * Original code came from http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas + * @author David Jordan + * @date 2012-08-08 + */ + CanvasRenderingContext2D.prototype.dashedLine = function(x,y,x2,y2,dashArray){ + if (!dashArray) dashArray=[10,5]; + if (dashLength==0) dashLength = 0.001; // Hack for Safari + var dashCount = dashArray.length; + this.moveTo(x, y); + var dx = (x2-x), dy = (y2-y); + var slope = dy/dx; + var distRemaining = Math.sqrt( dx*dx + dy*dy ); + var dashIndex=0, draw=true; + while (distRemaining>=0.1){ + var dashLength = dashArray[dashIndex++%dashCount]; + if (dashLength > distRemaining) dashLength = distRemaining; + var xStep = Math.sqrt( dashLength*dashLength / (1 + slope*slope) ); + if (dx<0) xStep = -xStep; + x += xStep; + y += slope*xStep; + this[draw ? 'lineTo' : 'moveTo'](x,y); + distRemaining -= dashLength; + draw = !draw; + } + }; + + // TODO: add diamond shape +} + +/** + * @class Node + * A node. A node can be connected to other nodes via one or multiple edges. + * @param {object} properties An object containing properties for the node. All + * properties are optional, except for the id. + * {number} id Id of the node. Required + * {string} label Text label for the node + * {number} x Horizontal position of the node + * {number} y Vertical position of the node + * {string} shape Node shape, available: + * "database", "circle", "ellipse", + * "box", "image", "text", "dot", + * "star", "triangle", "triangleDown", + * "square" + * {string} image An image url + * {string} title An title text, can be HTML + * {anytype} group A group name or number + * @param {Graph.Images} imagelist A list with images. Only needed + * when the node has an image + * @param {Graph.Groups} grouplist A list with groups. Needed for + * retrieving group properties + * @param {Object} constants An object with default values for + * example for the color + */ +function Node(properties, imagelist, grouplist, constants) { + this.selected = false; + + this.edges = []; // all edges connected to this node + this.group = constants.nodes.group; + + this.fontSize = constants.nodes.fontSize; + this.fontFace = constants.nodes.fontFace; + this.fontColor = constants.nodes.fontColor; + + this.color = constants.nodes.color; + + // set defaults for the properties + this.id = undefined; + this.shape = constants.nodes.shape; + this.image = constants.nodes.image; + this.x = 0; + this.y = 0; + this.xFixed = false; + this.yFixed = false; + this.radius = constants.nodes.radius; + this.radiusFixed = false; + this.radiusMin = constants.nodes.radiusMin; + this.radiusMax = constants.nodes.radiusMax; + + this.imagelist = imagelist; + this.grouplist = grouplist; + + this.setProperties(properties, constants); + + // mass, force, velocity + this.mass = 50; // kg (mass is adjusted for the number of connected edges) + this.fx = 0.0; // external force x + this.fy = 0.0; // external force y + this.vx = 0.0; // velocity x + this.vy = 0.0; // velocity y + this.minForce = constants.minForce; + this.damping = 0.9; // damping factor +}; + +/** + * Attach a edge to the node + * @param {Edge} edge + */ +Node.prototype.attachEdge = function(edge) { + this.edges.push(edge); + this._updateMass(); +}; + +/** + * Detach a edge from the node + * @param {Edge} edge + */ +Node.prototype.detachEdge = function(edge) { + var index = this.edges.indexOf(edge); + if (index != -1) { + this.edges.splice(index, 1); + } + this._updateMass(); +}; + +/** + * Update the nodes mass, which is determined by the number of edges connecting + * to it (more edges -> heavier node). + * @private + */ +Node.prototype._updateMass = function() { + this.mass = 50 + 20 * this.edges.length; // kg +}; + +/** + * Set or overwrite properties for the node + * @param {Object} properties an object with properties + * @param {Object} constants and object with default, global properties + */ +Node.prototype.setProperties = function(properties, constants) { + if (!properties) { + return; + } + + // basic properties + if (properties.id != undefined) {this.id = properties.id;} + if (properties.label != undefined) {this.label = properties.label;} + if (properties.title != undefined) {this.title = properties.title;} + if (properties.group != undefined) {this.group = properties.group;} + if (properties.x != undefined) {this.x = properties.x;} + if (properties.y != undefined) {this.y = properties.y;} + if (properties.value != undefined) {this.value = properties.value;} + + if (this.id === undefined) { + throw "Node must have an id"; + } + + // copy group properties + if (this.group) { + var groupObj = this.grouplist.get(this.group); + for (var prop in groupObj) { + if (groupObj.hasOwnProperty(prop)) { + this[prop] = groupObj[prop]; + } + } + } + + // individual shape properties + if (properties.shape != undefined) {this.shape = properties.shape;} + if (properties.image != undefined) {this.image = properties.image;} + if (properties.radius != undefined) {this.radius = properties.radius;} + if (properties.color != undefined) {this.color = Node.parseColor(properties.color);} + + if (properties.fontColor != undefined) {this.fontColor = properties.fontColor;} + if (properties.fontSize != undefined) {this.fontSize = properties.fontSize;} + if (properties.fontFace != undefined) {this.fontFace = properties.fontFace;} + + + if (this.image != undefined) { + if (this.imagelist) { + this.imageObj = this.imagelist.load(this.image); + } + else { + throw "No imagelist provided"; + } + } + + this.xFixed = this.xFixed || (properties.x != undefined); + this.yFixed = this.yFixed || (properties.y != undefined); + this.radiusFixed = this.radiusFixed || (properties.radius != undefined); + + if (this.shape == 'image') { + this.radiusMin = constants.nodes.widthMin; + this.radiusMax = constants.nodes.widthMax; + } + + // choose draw method depending on the shape + switch (this.shape) { + case 'database': this.draw = this._drawDatabase; this.resize = this._resizeDatabase; break; + case 'box': this.draw = this._drawBox; this.resize = this._resizeBox; break; + case 'circle': this.draw = this._drawCircle; this.resize = this._resizeCircle; break; + case 'ellipse': this.draw = this._drawEllipse; this.resize = this._resizeEllipse; break; + // TODO: add diamond shape + case 'image': this.draw = this._drawImage; this.resize = this._resizeImage; break; + case 'text': this.draw = this._drawText; this.resize = this._resizeText; break; + case 'dot': this.draw = this._drawDot; this.resize = this._resizeShape; break; + case 'square': this.draw = this._drawSquare; this.resize = this._resizeShape; break; + case 'triangle': this.draw = this._drawTriangle; this.resize = this._resizeShape; break; + case 'triangleDown': this.draw = this._drawTriangleDown; this.resize = this._resizeShape; break; + case 'star': this.draw = this._drawStar; this.resize = this._resizeShape; break; + default: this.draw = this._drawEllipse; this.resize = this._resizeEllipse; break; + } + + // reset the size of the node, this can be changed + this._reset(); +}; + +/** + * Parse a color property into an object with border, background, and + * hightlight colors + * @param {Object | String} color + * @return {Object} colorObject + */ +Node.parseColor = function(color) { + var c; + if (util.isString(color)) { + c = { + border: color, + background: color, + highlight: { + border: color, + background: color + } + }; + // TODO: automatically generate a nice highlight color + } + else { + c = {}; + c.background = color.background || 'white'; + c.border = color.border || c.background; + if (util.isString(color.highlight)) { + c.highlight = { + border: color.highlight, + background: color.highlight + } + } + else { + c.highlight = {}; + c.highlight.background = color.highlight && color.highlight.background || c.background; + c.highlight.border = color.highlight && color.highlight.border || c.border; + } + } + return c; +}; + +/** + * select this node + */ +Node.prototype.select = function() { + this.selected = true; + this._reset(); +}; + +/** + * unselect this node + */ +Node.prototype.unselect = function() { + this.selected = false; + this._reset(); +}; + +/** + * Reset the calculated size of the node, forces it to recalculate its size + * @private + */ +Node.prototype._reset = function() { + this.width = undefined; + this.height = undefined; +}; + +/** + * get the title of this node. + * @return {string} title The title of the node, or undefined when no title + * has been set. + */ +Node.prototype.getTitle = function() { + return this.title; +}; + +/** + * Calculate the distance to the border of the Node + * @param {CanvasRenderingContext2D} ctx + * @param {Number} angle Angle in radians + * @returns {number} distance Distance to the border in pixels + */ +Node.prototype.distanceToBorder = function (ctx, angle) { + var borderWidth = 1; + + if (!this.width) { + this.resize(ctx); + } + + //noinspection FallthroughInSwitchStatementJS + switch (this.shape) { + case 'circle': + case 'dot': + return this.radius + borderWidth; + + case 'ellipse': + var a = this.width / 2; + var b = this.height / 2; + var w = (Math.sin(angle) * a); + var h = (Math.cos(angle) * b); + return a * b / Math.sqrt(w * w + h * h); + + // TODO: implement distanceToBorder for database + // TODO: implement distanceToBorder for triangle + // TODO: implement distanceToBorder for triangleDown + + case 'box': + case 'image': + case 'text': + default: + if (this.width) { + return Math.min( + Math.abs(this.width / 2 / Math.cos(angle)), + Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth; + // TODO: reckon with border radius too in case of box + } + else { + return 0; + } + + } + + // TODO: implement calculation of distance to border for all shapes +}; + +/** + * Set forces acting on the node + * @param {number} fx Force in horizontal direction + * @param {number} fy Force in vertical direction + */ +Node.prototype._setForce = function(fx, fy) { + this.fx = fx; + this.fy = fy; +}; + +/** + * Add forces acting on the node + * @param {number} fx Force in horizontal direction + * @param {number} fy Force in vertical direction + * @private + */ +Node.prototype._addForce = function(fx, fy) { + this.fx += fx; + this.fy += fy; +}; + +/** + * Perform one discrete step for the node + * @param {number} interval Time interval in seconds + */ +Node.prototype.discreteStep = function(interval) { + if (!this.xFixed) { + var dx = -this.damping * this.vx; // damping force + var ax = (this.fx + dx) / this.mass; // acceleration + this.vx += ax / interval; // velocity + this.x += this.vx / interval; // position + } + + if (!this.yFixed) { + var dy = -this.damping * this.vy; // damping force + var ay = (this.fy + dy) / this.mass; // acceleration + this.vy += ay / interval; // velocity + this.y += this.vy / interval; // position + } +}; + + +/** + * Check if this node has a fixed x and y position + * @return {boolean} true if fixed, false if not + */ +Node.prototype.isFixed = function() { + return (this.xFixed && this.yFixed); +}; + +/** + * Check if this node is moving + * @param {number} vmin the minimum velocity considered as "moving" + * @return {boolean} true if moving, false if it has no velocity + */ +// TODO: replace this method with calculating the kinetic energy +Node.prototype.isMoving = function(vmin) { + return (Math.abs(this.vx) > vmin || Math.abs(this.vy) > vmin || + (!this.xFixed && Math.abs(this.fx) > this.minForce) || + (!this.yFixed && Math.abs(this.fy) > this.minForce)); +}; + +/** + * check if this node is selecte + * @return {boolean} selected True if node is selected, else false + */ +Node.prototype.isSelected = function() { + return this.selected; +}; + +/** + * Retrieve the value of the node. Can be undefined + * @return {Number} value + */ +Node.prototype.getValue = function() { + return this.value; +}; + +/** + * Calculate the distance from the nodes location to the given location (x,y) + * @param {Number} x + * @param {Number} y + * @return {Number} value + */ +Node.prototype.getDistance = function(x, y) { + var dx = this.x - x, + dy = this.y - y; + return Math.sqrt(dx * dx + dy * dy); +}; + + +/** + * Adjust the value range of the node. The node will adjust it's radius + * based on its value. + * @param {Number} min + * @param {Number} max + */ +Node.prototype.setValueRange = function(min, max) { + if (!this.radiusFixed && this.value !== undefined) { + var scale = (this.radiusMax - this.radiusMin) / (max - min); + this.radius = (this.value - min) * scale + this.radiusMin; + } +}; + +/** + * Draw this node in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + */ +Node.prototype.draw = function(ctx) { + throw "Draw method not initialized for node"; +}; + +/** + * Recalculate the size of this node in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + */ +Node.prototype.resize = function(ctx) { + throw "Resize method not initialized for node"; +}; + +/** + * Check if this object is overlapping with the provided object + * @param {Object} obj an object with parameters left, top, right, bottom + * @return {boolean} True if location is located on node + */ +Node.prototype.isOverlappingWith = function(obj) { + return (this.left < obj.right && + this.left + this.width > obj.left && + this.top < obj.bottom && + this.top + this.height > obj.top); +}; + +Node.prototype._resizeImage = function (ctx) { + // TODO: pre calculate the image size + if (!this.width) { // undefined or 0 + var width, height; + if (this.value) { + var scale = this.imageObj.height / this.imageObj.width; + width = this.radius || this.imageObj.width; + height = this.radius * scale || this.imageObj.height; + } + else { + width = this.imageObj.width; + height = this.imageObj.height; + } + this.width = width; + this.height = height; + } +}; + +Node.prototype._drawImage = function (ctx) { + this._resizeImage(ctx); + + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; + + var yLabel; + if (this.imageObj) { + ctx.drawImage(this.imageObj, this.left, this.top, this.width, this.height); + yLabel = this.y + this.height / 2; + } + else { + // image still loading... just draw the label for now + yLabel = this.y; + } + + this._label(ctx, this.label, this.x, yLabel, undefined, "top"); +}; + + +Node.prototype._resizeBox = function (ctx) { + if (!this.width) { + var margin = 5; + var textSize = this.getTextSize(ctx); + this.width = textSize.width + 2 * margin; + this.height = textSize.height + 2 * margin; + } +}; + +Node.prototype._drawBox = function (ctx) { + this._resizeBox(ctx); + + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; + + ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; + ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; + ctx.lineWidth = this.selected ? 2.0 : 1.0; + ctx.roundRect(this.left, this.top, this.width, this.height, this.radius); + ctx.fill(); + ctx.stroke(); + + this._label(ctx, this.label, this.x, this.y); +}; + + +Node.prototype._resizeDatabase = function (ctx) { + if (!this.width) { + var margin = 5; + var textSize = this.getTextSize(ctx); + var size = textSize.width + 2 * margin; + this.width = size; + this.height = size; + } +}; + +Node.prototype._drawDatabase = function (ctx) { + this._resizeDatabase(ctx); + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; + + ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; + ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; + ctx.lineWidth = this.selected ? 2.0 : 1.0; + ctx.database(this.x - this.width/2, this.y - this.height*0.5, this.width, this.height); + ctx.fill(); + ctx.stroke(); + + this._label(ctx, this.label, this.x, this.y); +}; + + +Node.prototype._resizeCircle = function (ctx) { + if (!this.width) { + var margin = 5; + var textSize = this.getTextSize(ctx); + var diameter = Math.max(textSize.width, textSize.height) + 2 * margin; + this.radius = diameter / 2; + + this.width = diameter; + this.height = diameter; + } +}; + +Node.prototype._drawCircle = function (ctx) { + this._resizeCircle(ctx); + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; + + ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; + ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; + ctx.lineWidth = this.selected ? 2.0 : 1.0; + ctx.circle(this.x, this.y, this.radius); + ctx.fill(); + ctx.stroke(); + + this._label(ctx, this.label, this.x, this.y); +}; + +Node.prototype._resizeEllipse = function (ctx) { + if (!this.width) { + var textSize = this.getTextSize(ctx); + + this.width = textSize.width * 1.5; + this.height = textSize.height * 2; + if (this.width < this.height) { + this.width = this.height; + } + } +}; + +Node.prototype._drawEllipse = function (ctx) { + this._resizeEllipse(ctx); + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; + + ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; + ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; + ctx.lineWidth = this.selected ? 2.0 : 1.0; + ctx.ellipse(this.left, this.top, this.width, this.height); + ctx.fill(); + ctx.stroke(); + + this._label(ctx, this.label, this.x, this.y); +}; + +Node.prototype._drawDot = function (ctx) { + this._drawShape(ctx, 'circle'); +}; + +Node.prototype._drawTriangle = function (ctx) { + this._drawShape(ctx, 'triangle'); +}; + +Node.prototype._drawTriangleDown = function (ctx) { + this._drawShape(ctx, 'triangleDown'); +}; + +Node.prototype._drawSquare = function (ctx) { + this._drawShape(ctx, 'square'); +}; + +Node.prototype._drawStar = function (ctx) { + this._drawShape(ctx, 'star'); +}; + +Node.prototype._resizeShape = function (ctx) { + if (!this.width) { + var size = 2 * this.radius; + this.width = size; + this.height = size; + } +}; + +Node.prototype._drawShape = function (ctx, shape) { + this._resizeShape(ctx); + + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; + + ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; + ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; + ctx.lineWidth = this.selected ? 2.0 : 1.0; + + ctx[shape](this.x, this.y, this.radius); + ctx.fill(); + ctx.stroke(); + + if (this.label) { + this._label(ctx, this.label, this.x, this.y + this.height / 2, undefined, 'top'); + } +}; + +Node.prototype._resizeText = function (ctx) { + if (!this.width) { + var margin = 5; + var textSize = this.getTextSize(ctx); + this.width = textSize.width + 2 * margin; + this.height = textSize.height + 2 * margin; + } +}; + +Node.prototype._drawText = function (ctx) { + this._resizeText(ctx); + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; + + this._label(ctx, this.label, this.x, this.y); +}; + + +Node.prototype._label = function (ctx, text, x, y, align, baseline) { + if (text) { + ctx.font = (this.selected ? "bold " : "") + this.fontSize + "px " + this.fontFace; + ctx.fillStyle = this.fontColor || "black"; + ctx.textAlign = align || "center"; + ctx.textBaseline = baseline || "middle"; + + var lines = text.split('\n'), + lineCount = lines.length, + fontSize = (this.fontSize + 4), + yLine = y + (1 - lineCount) / 2 * fontSize; + + for (var i = 0; i < lineCount; i++) { + ctx.fillText(lines[i], x, yLine); + yLine += fontSize; + } + } +}; + + +Node.prototype.getTextSize = function(ctx) { + if (this.label != undefined) { + ctx.font = (this.selected ? "bold " : "") + this.fontSize + "px " + this.fontFace; + + var lines = this.label.split('\n'), + height = (this.fontSize + 4) * lines.length, + width = 0; + + for (var i = 0, iMax = lines.length; i < iMax; i++) { + width = Math.max(width, ctx.measureText(lines[i]).width); + } + + return {"width": width, "height": height}; + } + else { + return {"width": 0, "height": 0}; + } +}; + +/** + * @class Edge + * + * A edge connects two nodes + * @param {Object} properties Object with properties. Must contain + * At least properties from and to. + * Available properties: from (number), + * to (number), label (string, color (string), + * width (number), style (string), + * length (number), title (string) + * @param {Graph} graph A graph object, used to find and edge to + * nodes. + * @param {Object} constants An object with default values for + * example for the color + */ +function Edge (properties, graph, constants) { + if (!graph) { + throw "No graph provided"; + } + this.graph = graph; + + // initialize constants + this.widthMin = constants.edges.widthMin; + this.widthMax = constants.edges.widthMax; + + // initialize variables + this.id = undefined; + this.style = constants.edges.style; + this.title = undefined; + this.width = constants.edges.width; + this.value = undefined; + this.length = constants.edges.length; + + // Added to support dashed lines + // David Jordan + // 2012-08-08 + this.dash = util.extend({}, constants.edges.dash); // contains properties length, gaph, altLength + + this.stiffness = undefined; // depends on the length of the edge + this.color = constants.edges.color; + this.widthFixed = false; + this.lengthFixed = false; + + this.setProperties(properties, constants); +}; + +/** + * Set or overwrite properties for the edge + * @param {Object} properties an object with properties + * @param {Object} constants and object with default, global properties + */ +Edge.prototype.setProperties = function(properties, constants) { + if (!properties) { + return; + } + + if (properties.from != undefined) {this.from = this.graph._getNode(properties.from);} + if (properties.to != undefined) {this.to = this.graph._getNode(properties.to);} + + if (properties.id != undefined) {this.id = properties.id;} + if (properties.style != undefined) {this.style = properties.style;} + if (properties.label != undefined) {this.label = properties.label;} + if (this.label) { + this.fontSize = constants.edges.fontSize; + this.fontFace = constants.edges.fontFace; + this.fontColor = constants.edges.fontColor; + if (properties.fontColor != undefined) {this.fontColor = properties.fontColor;} + if (properties.fontSize != undefined) {this.fontSize = properties.fontSize;} + if (properties.fontFace != undefined) {this.fontFace = properties.fontFace;} + } + if (properties.title != undefined) {this.title = properties.title;} + if (properties.width != undefined) {this.width = properties.width;} + if (properties.value != undefined) {this.value = properties.value;} + if (properties.length != undefined) {this.length = properties.length;} + + // Added to support dashed lines + // David Jordan + // 2012-08-08 + if (properties.dash) { + if (properties.dash.length != undefined) {this.dash.length = properties.dash.length;} + if (properties.dash.gap != undefined) {this.dash.gap = properties.dash.gap;} + if (properties.dash.altLength != undefined) {this.dash.altLength = properties.dash.altLength;} + } + + if (properties.color != undefined) {this.color = properties.color;} + + if (!this.from) { + throw "Node with id " + properties.from + " not found"; + } + if (!this.to) { + throw "Node with id " + properties.to + " not found"; + } + + this.widthFixed = this.widthFixed || (properties.width != undefined); + this.lengthFixed = this.lengthFixed || (properties.length != undefined); + + this.stiffness = 1 / this.length; + + // set draw method based on style + switch (this.style) { + case 'line': this.draw = this._drawLine; break; + case 'arrow': this.draw = this._drawArrow; break; + case 'arrow-center': this.draw = this._drawArrowCenter; break; + case 'dash-line': this.draw = this._drawDashLine; break; + default: this.draw = this._drawLine; break; + } +}; + +/** + * get the title of this edge. + * @return {string} title The title of the edge, or undefined when no title + * has been set. + */ +Edge.prototype.getTitle = function() { + return this.title; +}; + + +/** + * Retrieve the value of the edge. Can be undefined + * @return {Number} value + */ +Edge.prototype.getValue = function() { + return this.value; +}; + +/** + * Adjust the value range of the edge. The edge will adjust it's width + * based on its value. + * @param {Number} min + * @param {Number} max + */ +Edge.prototype.setValueRange = function(min, max) { + if (!this.widthFixed && this.value !== undefined) { + var factor = (this.widthMax - this.widthMin) / (max - min); + this.width = (this.value - min) * factor + this.widthMin; + } +}; + +/** + * Redraw a edge + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + */ +Edge.prototype.draw = function(ctx) { + throw "Method draw not initialized in edge"; +}; + +/** + * Check if this object is overlapping with the provided object + * @param {Object} obj an object with parameters left, top + * @return {boolean} True if location is located on the edge + */ +Edge.prototype.isOverlappingWith = function(obj) { + var distMax = 10; + + var xFrom = this.from.x; + var yFrom = this.from.y; + var xTo = this.to.x; + var yTo = this.to.y; + var xObj = obj.left; + var yObj = obj.top; + + + var dist = Edge._dist(xFrom, yFrom, xTo, yTo, xObj, yObj); + + return (dist < distMax); +}; + + +/** + * Redraw a edge as a line + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private + */ +Edge.prototype._drawLine = function(ctx) { + // set style + ctx.strokeStyle = this.color; + ctx.lineWidth = this._getLineWidth(); + + var point; + if (this.from != this.to) { + // draw line + this._line(ctx); + + // draw label + if (this.label) { + point = this._pointOnLine(0.5); + this._label(ctx, this.label, point.x, point.y); + } + } + else { + var x, y; + var radius = this.length / 4; + var node = this.from; + if (!node.width) { + node.resize(ctx); + } + if (node.width > node.height) { + x = node.x + node.width / 2; + y = node.y - radius; + } + else { + x = node.x + radius; + y = node.y - node.height / 2; + } + this._circle(ctx, x, y, radius); + point = this._pointOnCircle(x, y, radius, 0.5); + this._label(ctx, this.label, point.x, point.y); + } +}; + +/** + * Get the line width of the edge. Depends on width and whether one of the + * connected nodes is selected. + * @return {Number} width + * @private + */ +Edge.prototype._getLineWidth = function() { + if (this.from.selected || this.to.selected) { + return Math.min(this.width * 2, this.widthMax); + } + else { + return this.width; + } +}; + +/** + * Draw a line between two nodes + * @param {CanvasRenderingContext2D} ctx + * @private + */ +Edge.prototype._line = function (ctx) { + // draw a straight line + ctx.beginPath(); + ctx.moveTo(this.from.x, this.from.y); + ctx.lineTo(this.to.x, this.to.y); + ctx.stroke(); +}; + +/** + * Draw a line from a node to itself, a circle + * @param {CanvasRenderingContext2D} ctx + * @param {Number} x + * @param {Number} y + * @param {Number} radius + * @private + */ +Edge.prototype._circle = function (ctx, x, y, radius) { + // draw a circle + ctx.beginPath(); + ctx.arc(x, y, radius, 0, 2 * Math.PI, false); + ctx.stroke(); +}; + +/** + * Draw label with white background and with the middle at (x, y) + * @param {CanvasRenderingContext2D} ctx + * @param {String} text + * @param {Number} x + * @param {Number} y + * @private + */ +Edge.prototype._label = function (ctx, text, x, y) { + if (text) { + // TODO: cache the calculated size + ctx.font = ((this.from.selected || this.to.selected) ? "bold " : "") + + this.fontSize + "px " + this.fontFace; + ctx.fillStyle = 'white'; + var width = ctx.measureText(text).width; + var height = this.fontSize; + var left = x - width / 2; + var top = y - height / 2; + + ctx.fillRect(left, top, width, height); + + // draw text + ctx.fillStyle = this.fontColor || "black"; + ctx.textAlign = "left"; + ctx.textBaseline = "top"; + ctx.fillText(text, left, top); + } +}; + +/** + * Redraw a edge as a dashed line + * Draw this edge in the given canvas + * @author David Jordan + * @date 2012-08-08 + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private + */ +Edge.prototype._drawDashLine = function(ctx) { + // set style + ctx.strokeStyle = this.color; + ctx.lineWidth = this._getLineWidth(); + + // draw dashed line + ctx.beginPath(); + ctx.lineCap = 'round'; + if (this.dash.altLength != undefined) //If an alt dash value has been set add to the array this value + { + ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, + [this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]); + } + else if (this.dash.length != undefined && this.dash.gap != undefined) //If a dash and gap value has been set add to the array this value + { + ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, + [this.dash.length,this.dash.gap]); + } + else //If all else fails draw a line + { + ctx.moveTo(this.from.x, this.from.y); + ctx.lineTo(this.to.x, this.to.y); + } + ctx.stroke(); + + // draw label + if (this.label) { + var point = this._pointOnLine(0.5); + this._label(ctx, this.label, point.x, point.y); + } +}; + +/** + * Get a point on a line + * @param {Number} percentage. Value between 0 (line start) and 1 (line end) + * @return {Object} point + * @private + */ +Edge.prototype._pointOnLine = function (percentage) { + return { + x: (1 - percentage) * this.from.x + percentage * this.to.x, + y: (1 - percentage) * this.from.y + percentage * this.to.y + } +}; + +/** + * Get a point on a circle + * @param {Number} x + * @param {Number} y + * @param {Number} radius + * @param {Number} percentage. Value between 0 (line start) and 1 (line end) + * @return {Object} point + * @private + */ +Edge.prototype._pointOnCircle = function (x, y, radius, percentage) { + var angle = (percentage - 3/8) * 2 * Math.PI; + return { + x: x + radius * Math.cos(angle), + y: y - radius * Math.sin(angle) + } +}; + +/** + * Redraw a edge as a line with an arrow halfway the line + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private + */ +Edge.prototype._drawArrowCenter = function(ctx) { + var point; + // set style + ctx.strokeStyle = this.color; + ctx.fillStyle = this.color; + ctx.lineWidth = this._getLineWidth(); + + if (this.from != this.to) { + // draw line + this._line(ctx); + + // draw an arrow halfway the line + var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); + var length = 10 + 5 * this.width; // TODO: make customizable? + point = this._pointOnLine(0.5); + ctx.arrow(point.x, point.y, angle, length); + ctx.fill(); + ctx.stroke(); + + // draw label + if (this.label) { + point = this._pointOnLine(0.5); + this._label(ctx, this.label, point.x, point.y); + } + } + else { + // draw circle + var x, y; + var radius = this.length / 4; + var node = this.from; + if (!node.width) { + node.resize(ctx); + } + if (node.width > node.height) { + x = node.x + node.width / 2; + y = node.y - radius; + } + else { + x = node.x + radius; + y = node.y - node.height / 2; + } + this._circle(ctx, x, y, radius); + + // draw all arrows + var angle = 0.2 * Math.PI; + var length = 10 + 5 * this.width; // TODO: make customizable? + point = this._pointOnCircle(x, y, radius, 0.5); + ctx.arrow(point.x, point.y, angle, length); + ctx.fill(); + ctx.stroke(); + + // draw label + if (this.label) { + point = this._pointOnCircle(x, y, radius, 0.5); + this._label(ctx, this.label, point.x, point.y); + } + } +}; + + + +/** + * Redraw a edge as a line with an arrow + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private + */ +Edge.prototype._drawArrow = function(ctx) { + // set style + ctx.strokeStyle = this.color; + ctx.fillStyle = this.color; + ctx.lineWidth = this._getLineWidth(); + + // draw line + var angle, length; + if (this.from != this.to) { + // calculate length and angle of the line + angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); + var dx = (this.to.x - this.from.x); + var dy = (this.to.y - this.from.y); + var lEdge = Math.sqrt(dx * dx + dy * dy); + + var lFrom = this.from.distanceToBorder(ctx, angle + Math.PI); + var pFrom = (lEdge - lFrom) / lEdge; + var xFrom = (pFrom) * this.from.x + (1 - pFrom) * this.to.x; + var yFrom = (pFrom) * this.from.y + (1 - pFrom) * this.to.y; + + var lTo = this.to.distanceToBorder(ctx, angle); + var pTo = (lEdge - lTo) / lEdge; + var xTo = (1 - pTo) * this.from.x + pTo * this.to.x; + var yTo = (1 - pTo) * this.from.y + pTo * this.to.y; + + ctx.beginPath(); + ctx.moveTo(xFrom, yFrom); + ctx.lineTo(xTo, yTo); + ctx.stroke(); + + // draw arrow at the end of the line + length = 10 + 5 * this.width; // TODO: make customizable? + ctx.arrow(xTo, yTo, angle, length); + ctx.fill(); + ctx.stroke(); + + // draw label + if (this.label) { + var point = this._pointOnLine(0.5); + this._label(ctx, this.label, point.x, point.y); + } + } + else { + // draw circle + var node = this.from; + var x, y, arrow; + var radius = this.length / 4; + if (!node.width) { + node.resize(ctx); + } + if (node.width > node.height) { + x = node.x + node.width / 2; + y = node.y - radius; + arrow = { + x: x, + y: node.y, + angle: 0.9 * Math.PI + }; + } + else { + x = node.x + radius; + y = node.y - node.height / 2; + arrow = { + x: node.x, + y: y, + angle: 0.6 * Math.PI + }; + } + ctx.beginPath(); + // TODO: do not draw a circle, but an arc + // TODO: similarly, for a line without arrows, draw to the border of the nodes instead of the center + ctx.arc(x, y, radius, 0, 2 * Math.PI, false); + ctx.stroke(); + + // draw all arrows + length = 10 + 5 * this.width; // TODO: make customizable? + ctx.arrow(arrow.x, arrow.y, arrow.angle, length); + ctx.fill(); + ctx.stroke(); + + // draw label + if (this.label) { + point = this._pointOnCircle(x, y, radius, 0.5); + this._label(ctx, this.label, point.x, point.y); + } + } +}; + + + +/** + * Calculate the distance between a point (x3,y3) and a line segment from + * (x1,y1) to (x2,y2). + * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment + * @param {number} x1 + * @param {number} y1 + * @param {number} x2 + * @param {number} y2 + * @param {number} x3 + * @param {number} y3 + * @private + */ +Edge._dist = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point + var px = x2-x1, + py = y2-y1, + something = px*px + py*py, + u = ((x3 - x1) * px + (y3 - y1) * py) / something; + + if (u > 1) { + u = 1; + } + else if (u < 0) { + u = 0; + } + + var x = x1 + u * px, + y = y1 + u * py, + dx = x - x3, + dy = y - y3; + + //# Note: If the actual distance does not matter, + //# if you only want to compare what this function + //# returns to other results of this function, you + //# can just return the squared distance instead + //# (i.e. remove the sqrt) to gain a little performance + + return Math.sqrt(dx*dx + dy*dy); +}; + +/** + * Popup is a class to create a popup window with some text + * @param {Element} container The container object. + * @param {Number} [x] + * @param {Number} [y] + * @param {String} [text] + */ +function Popup(container, x, y, text) { + if (container) { + this.container = container; + } + else { + this.container = document.body; + } + this.x = 0; + this.y = 0; + this.padding = 5; + + if (x !== undefined && y !== undefined ) { + this.setPosition(x, y); + } + if (text !== undefined) { + this.setText(text); + } + + // create the frame + this.frame = document.createElement("div"); + var style = this.frame.style; + style.position = "absolute"; + style.visibility = "hidden"; + style.border = "1px solid #666"; + style.color = "black"; + style.padding = this.padding + "px"; + style.backgroundColor = "#FFFFC6"; + style.borderRadius = "3px"; + style.MozBorderRadius = "3px"; + style.WebkitBorderRadius = "3px"; + style.boxShadow = "3px 3px 10px rgba(128, 128, 128, 0.5)"; + style.whiteSpace = "nowrap"; + this.container.appendChild(this.frame); +}; + +/** + * @param {number} x Horizontal position of the popup window + * @param {number} y Vertical position of the popup window + */ +Popup.prototype.setPosition = function(x, y) { + this.x = parseInt(x); + this.y = parseInt(y); +}; + +/** + * Set the text for the popup window. This can be HTML code + * @param {string} text + */ +Popup.prototype.setText = function(text) { + this.frame.innerHTML = text; +}; + +/** + * Show the popup window + * @param {boolean} show Optional. Show or hide the window + */ +Popup.prototype.show = function (show) { + if (show === undefined) { + show = true; + } + + if (show) { + var height = this.frame.clientHeight; + var width = this.frame.clientWidth; + var maxHeight = this.frame.parentNode.clientHeight; + var maxWidth = this.frame.parentNode.clientWidth; + + var top = (this.y - height); + if (top + height + this.padding > maxHeight) { + top = maxHeight - height - this.padding; + } + if (top < this.padding) { + top = this.padding; + } + + var left = this.x; + if (left + width + this.padding > maxWidth) { + left = maxWidth - width - this.padding; + } + if (left < this.padding) { + left = this.padding; + } + + this.frame.style.left = left + "px"; + this.frame.style.top = top + "px"; + this.frame.style.visibility = "visible"; + } + else { + this.hide(); + } +}; + +/** + * Hide the popup window + */ +Popup.prototype.hide = function () { + this.frame.style.visibility = "hidden"; +}; + +/** + * @class Groups + * This class can store groups and properties specific for groups. + */ +Groups = function () { + this.clear(); + this.defaultIndex = 0; +}; + + +/** + * default constants for group colors + */ +Groups.DEFAULT = [ + {border: "#2B7CE9", background: "#97C2FC", highlight: {border: "#2B7CE9", background: "#D2E5FF"}}, // blue + {border: "#FFA500", background: "#FFFF00", highlight: {border: "#FFA500", background: "#FFFFA3"}}, // yellow + {border: "#FA0A10", background: "#FB7E81", highlight: {border: "#FA0A10", background: "#FFAFB1"}}, // red + {border: "#41A906", background: "#7BE141", highlight: {border: "#41A906", background: "#A1EC76"}}, // green + {border: "#E129F0", background: "#EB7DF4", highlight: {border: "#E129F0", background: "#F0B3F5"}}, // magenta + {border: "#7C29F0", background: "#AD85E4", highlight: {border: "#7C29F0", background: "#D3BDF0"}}, // purple + {border: "#C37F00", background: "#FFA807", highlight: {border: "#C37F00", background: "#FFCA66"}}, // orange + {border: "#4220FB", background: "#6E6EFD", highlight: {border: "#4220FB", background: "#9B9BFD"}}, // darkblue + {border: "#FD5A77", background: "#FFC0CB", highlight: {border: "#FD5A77", background: "#FFD1D9"}}, // pink + {border: "#4AD63A", background: "#C2FABC", highlight: {border: "#4AD63A", background: "#E6FFE3"}} // mint +]; + + +/** + * Clear all groups + */ +Groups.prototype.clear = function () { + this.groups = {}; + this.groups.length = function() + { + var i = 0; + for ( var p in this ) { + if (this.hasOwnProperty(p)) { + i++; + } + } + return i; + } +}; + + +/** + * get group properties of a groupname. If groupname is not found, a new group + * is added. + * @param {*} groupname Can be a number, string, Date, etc. + * @return {Object} group The created group, containing all group properties + */ +Groups.prototype.get = function (groupname) { + var group = this.groups[groupname]; + + if (group == undefined) { + // create new group + var index = this.defaultIndex % Groups.DEFAULT.length; + this.defaultIndex++; + group = {}; + group.color = Groups.DEFAULT[index]; + this.groups[groupname] = group; + } + + return group; +}; + +/** + * Add a custom group style + * @param {String} groupname + * @param {Object} style An object containing borderColor, + * backgroundColor, etc. + * @return {Object} group The created group object + */ +Groups.prototype.add = function (groupname, style) { + this.groups[groupname] = style; + if (style.color) { + style.color = Node.parseColor(style.color); + } + return style; +}; + +/** + * @class Images + * This class loads images and keeps them stored. + */ +Images = function () { + this.images = {}; + + this.callback = undefined; +}; + +/** + * Set an onload callback function. This will be called each time an image + * is loaded + * @param {function} callback + */ +Images.prototype.setOnloadCallback = function(callback) { + this.callback = callback; +}; + +/** + * + * @param {string} url Url of the image + * @return {Image} img The image object + */ +Images.prototype.load = function(url) { + var img = this.images[url]; + if (img == undefined) { + // create the image + var images = this; + img = new Image(); + this.images[url] = img; + img.onload = function() { + if (images.callback) { + images.callback(this); + } + }; + img.src = url; + } + + return img; +}; + +/** + * @constructor Graph + * Create a graph visualization, displaying nodes and edges. + * + * @param {Element} container The DOM element in which the Graph will + * be created. Normally a div element. + * @param {Object} data An object containing parameters + * {Array} nodes + * {Array} edges + * @param {Object} options Options + */ +function Graph (container, data, options) { + // create variables and set default values + this.containerElement = container; + this.width = '100%'; + this.height = '100%'; + this.refreshRate = 50; // milliseconds + this.stabilize = true; // stabilize before displaying the graph + this.selectable = true; + + // set constant values + this.constants = { + nodes: { + radiusMin: 5, + radiusMax: 20, + radius: 5, + distance: 100, // px + shape: 'ellipse', + image: undefined, + widthMin: 16, // px + widthMax: 64, // px + fontColor: 'black', + fontSize: 14, // px + //fontFace: verdana, + fontFace: 'arial', + color: { + border: '#2B7CE9', + background: '#97C2FC', + highlight: { + border: '#2B7CE9', + background: '#D2E5FF' + } + }, + borderColor: '#2B7CE9', + backgroundColor: '#97C2FC', + highlightColor: '#D2E5FF', + group: undefined + }, + edges: { + widthMin: 1, + widthMax: 15, + width: 1, + style: 'line', + color: '#343434', + fontColor: '#343434', + fontSize: 14, // px + fontFace: 'arial', + //distance: 100, //px + length: 100, // px + dash: { + length: 10, + gap: 5, + altLength: undefined + } + }, + minForce: 0.05, + minVelocity: 0.02, // px/s + maxIterations: 1000 // maximum number of iteration to stabilize + }; + + var graph = this; + this.nodes = []; // array with Node objects + this.edges = []; // array with Edge objects + + this.groups = new Groups(); // object with groups + this.images = new Images(); // object with images + this.images.setOnloadCallback(function () { + graph._redraw(); + }); + + // properties of the data + this.moving = false; // True if any of the nodes have an undefined position + + this.selection = []; + this.timer = undefined; + + // create a frame and canvas + this._create(); + + // apply options + this.setOptions(options); + + // draw data + this.setData(data); +} + +/** + * Set nodes and edges, and optionally options as well. + * + * @param {Object} data Object containing parameters: + * {Array} [nodes] Array with nodes. + * Required when format is 'vis' + * {Array} [edges] Array with edges + * Required when format is 'vis' + * {String} [dot] String containing data in DOT + * format. + * {Options} [options] Object with options + */ +Graph.prototype.setData = function(data) { + if (data && data.dot && (data.nodes || data.edges)) { + throw new SyntaxError('Data must contain either parameter "dot" or ' + + ' parameter pair "nodes" and "edges", but not both.'); + } + + // set options + this.setOptions(data && data.options); + + // set all data + if (data && data.dot) { + // parse DOT file + if(data && data.dot) { + var dotData = vis.util.DOTToGraph(data.dot); + this.setData(dotData); + return; + } + } + else { + this._setNodes(data && data.nodes); + this._setEdges(data && data.edges); + } + + + // find a stable position or start animating to a stable position + if (this.stabilize) { + this._doStabilize(); + } + this.start(); +}; + +/** + * Set options + * @param {Object} options + */ +Graph.prototype.setOptions = function (options) { + if (options) { + // retrieve parameter values + if (options.width != undefined) {this.width = options.width;} + if (options.height != undefined) {this.height = options.height;} + if (options.stabilize != undefined) {this.stabilize = options.stabilize;} + if (options.selectable != undefined) {this.selectable = options.selectable;} + + // TODO: work out these options and document them + if (options.edges) { + for (var prop in options.edges) { + if (options.edges.hasOwnProperty(prop)) { + this.constants.edges[prop] = options.edges[prop]; + } + } + + if (options.edges.length != undefined && + options.nodes && options.nodes.distance == undefined) { + this.constants.edges.length = options.edges.length; + this.constants.nodes.distance = options.edges.length * 1.25; + } + + if (!options.edges.fontColor) { + this.constants.edges.fontColor = options.edges.color; + } + + // Added to support dashed lines + // David Jordan + // 2012-08-08 + if (options.edges.dash) { + if (options.edges.dash.length != undefined) { + this.constants.edges.dash.length = options.edges.dash.length; + } + if (options.edges.dash.gap != undefined) { + this.constants.edges.dash.gap = options.edges.dash.gap; + } + if (options.edges.dash.altLength != undefined) { + this.constants.edges.dash.altLength = options.edges.dash.altLength; + } + } + } + + if (options.nodes) { + for (prop in options.nodes) { + if (options.nodes.hasOwnProperty(prop)) { + this.constants.nodes[prop] = options.nodes[prop]; + } + } + + if (options.nodes.color) { + this.constants.nodes.color = Node.parseColor(options.nodes.color); + } + + /* + if (options.nodes.widthMin) this.constants.nodes.radiusMin = options.nodes.widthMin; + if (options.nodes.widthMax) this.constants.nodes.radiusMax = options.nodes.widthMax; + */ + } + + if (options.groups) { + for (var groupname in options.groups) { + if (options.groups.hasOwnProperty(groupname)) { + var group = options.groups[groupname]; + this.groups.add(groupname, group); + } + } + } + } + + this.setSize(this.width, this.height); + this._setTranslation(0, 0); + this._setScale(1); +}; + +/** + * fire an event + * @param {String} event The name of an event, for example "select" + * @param {Object} params Optional object with event parameters + * @private + */ +Graph.prototype._trigger = function (event, params) { + events.trigger(this, event, params); +}; + + +/** + * Create the main frame for the Graph. + * This function is executed once when a Graph object is created. The frame + * contains a canvas, and this canvas contains all objects like the axis and + * nodes. + * @private + */ +Graph.prototype._create = function () { + // remove all elements from the container element. + while (this.containerElement.hasChildNodes()) { + this.containerElement.removeChild(this.containerElement.firstChild); + } + + this.frame = document.createElement("div"); + this.frame.className = "graph-frame"; + this.frame.style.position = "relative"; + this.frame.style.overflow = "hidden"; + + // create the graph canvas (HTML canvas element) + this.frame.canvas = document.createElement( "canvas" ); + this.frame.canvas.style.position = "relative"; + this.frame.appendChild(this.frame.canvas); + if (!this.frame.canvas.getContext) { + var noCanvas = document.createElement( "DIV" ); + noCanvas.style.color = "red"; + noCanvas.style.fontWeight = "bold" ; + noCanvas.style.padding = "10px"; + noCanvas.innerHTML = "Error: your browser does not support HTML canvas"; + this.frame.canvas.appendChild(noCanvas); + } + + // create event listeners + var me = this; + var onmousedown = function (event) {me._onMouseDown(event);}; + var onmousemove = function (event) {me._onMouseMoveTitle(event);}; + var onmousewheel = function (event) {me._onMouseWheel(event);}; + var ontouchstart = function (event) {me._onTouchStart(event);}; + vis.util.addEventListener(this.frame.canvas, "mousedown", onmousedown); + vis.util.addEventListener(this.frame.canvas, "mousemove", onmousemove); + vis.util.addEventListener(this.frame.canvas, "mousewheel", onmousewheel); + vis.util.addEventListener(this.frame.canvas, "touchstart", ontouchstart); + + // add the frame to the container element + this.containerElement.appendChild(this.frame); +}; + +/** + * handle on mouse down event + * @private + */ +Graph.prototype._onMouseDown = function (event) { + event = event || window.event; + + if (!this.selectable) { + return; + } + + // check if mouse is still down (may be up when focus is lost for example + // in an iframe) + if (this.leftButtonDown) { + this._onMouseUp(event); + } + + // only react on left mouse button down + this.leftButtonDown = event.which ? (event.which == 1) : (event.button == 1); + if (!this.leftButtonDown && !this.touchDown) { + return; + } + + // add event listeners to handle moving the contents + // we store the function onmousemove and onmouseup in the timeline, so we can + // remove the eventlisteners lateron in the function mouseUp() + var me = this; + if (!this.onmousemove) { + this.onmousemove = function (event) {me._onMouseMove(event);}; + vis.util.addEventListener(document, "mousemove", me.onmousemove); + } + if (!this.onmouseup) { + this.onmouseup = function (event) {me._onMouseUp(event);}; + vis.util.addEventListener(document, "mouseup", me.onmouseup); + } + vis.util.preventDefault(event); + + // store the start x and y position of the mouse + this.startMouseX = event.clientX || event.targetTouches[0].clientX; + this.startMouseY = event.clientY || event.targetTouches[0].clientY; + this.startFrameLeft = vis.util.getAbsoluteLeft(this.frame.canvas); + this.startFrameTop = vis.util.getAbsoluteTop(this.frame.canvas); + this.startTranslation = this._getTranslation(); + + this.ctrlKeyDown = event.ctrlKey; + this.shiftKeyDown = event.shiftKey; + + var obj = { + "left" : this._xToCanvas(this.startMouseX - this.startFrameLeft), + "top" : this._yToCanvas(this.startMouseY - this.startFrameTop), + "right" : this._xToCanvas(this.startMouseX - this.startFrameLeft), + "bottom" : this._yToCanvas(this.startMouseY - this.startFrameTop) + }; + var overlappingNodes = this._getNodesOverlappingWith(obj); + // if there are overlapping nodes, select the last one, this is the + // one which is drawn on top of the others + this.startClickedObj = (overlappingNodes.length > 0) ? + overlappingNodes[overlappingNodes.length - 1] : undefined; + + if (this.startClickedObj) { + // move clicked node with the mouse + + // make the clicked node temporarily fixed, and store their original state + var node = this.nodes[this.startClickedObj.row]; + this.startClickedObj.xFixed = node.xFixed; + this.startClickedObj.yFixed = node.yFixed; + node.xFixed = true; + node.yFixed = true; + + if (!this.ctrlKeyDown || !node.isSelected()) { + // select this node + this._selectNodes([this.startClickedObj], this.ctrlKeyDown); + } + else { + // unselect this node + this._unselectNodes([this.startClickedObj]); + } + + if (!this.moving) { + this._redraw(); + } + } + else if (this.shiftKeyDown) { + // start selection of multiple nodes + } + else { + // start moving the graph + this.moved = false; + } +}; + +/** + * handle on mouse move event + * @param {Event} event + * @private + */ +Graph.prototype._onMouseMove = function (event) { + event = event || window.event; + + if (!this.selectable) { + return; + } + + var mouseX = event.clientX || (event.targetTouches && event.targetTouches[0].clientX) || 0; + var mouseY = event.clientY || (event.targetTouches && event.targetTouches[0].clientY) || 0; + this.mouseX = mouseX; + this.mouseY = mouseY; + + if (this.startClickedObj) { + var node = this.nodes[this.startClickedObj.row]; + + if (!this.startClickedObj.xFixed) + node.x = this._xToCanvas(mouseX - this.startFrameLeft); + + if (!this.startClickedObj.yFixed) + node.y = this._yToCanvas(mouseY - this.startFrameTop); + + // start animation if not yet running + if (!this.moving) { + this.moving = true; + this.start(); + } + } + else if (this.shiftKeyDown) { + // draw a rect from start mouse location to current mouse location + if (this.frame.selRect == undefined) { + this.frame.selRect = document.createElement("DIV"); + this.frame.appendChild(this.frame.selRect); + + this.frame.selRect.style.position = "absolute"; + this.frame.selRect.style.border = "1px dashed red"; + } + + var left = Math.min(this.startMouseX, mouseX) - this.startFrameLeft; + var top = Math.min(this.startMouseY, mouseY) - this.startFrameTop; + var right = Math.max(this.startMouseX, mouseX) - this.startFrameLeft; + var bottom = Math.max(this.startMouseY, mouseY) - this.startFrameTop; + + this.frame.selRect.style.left = left + "px"; + this.frame.selRect.style.top = top + "px"; + this.frame.selRect.style.width = (right - left) + "px"; + this.frame.selRect.style.height = (bottom - top) + "px"; + } + else { + // move the graph + var diffX = mouseX - this.startMouseX; + var diffY = mouseY - this.startMouseY; + + this._setTranslation( + this.startTranslation.x + diffX, + this.startTranslation.y + diffY); + this._redraw(); + + this.moved = true; + } + + vis.util.preventDefault(event); +}; + +/** + * handle on mouse up event + * @param {Event} event + * @private + */ +Graph.prototype._onMouseUp = function (event) { + event = event || window.event; + + if (!this.selectable) { + return; + } + + // remove event listeners here, important for Safari + if (this.onmousemove) { + vis.util.removeEventListener(document, "mousemove", this.onmousemove); + this.onmousemove = undefined; + } + if (this.onmouseup) { + vis.util.removeEventListener(document, "mouseup", this.onmouseup); + this.onmouseup = undefined; + } + vis.util.preventDefault(event); + + // check selected nodes + var endMouseX = event.clientX || this.mouseX || 0; + var endMouseY = event.clientY || this.mouseY || 0; + + var ctrlKey = event ? event.ctrlKey : window.event.ctrlKey; + + if (this.startClickedObj) { + // restore the original fixed state + var node = this.nodes[this.startClickedObj.row]; + node.xFixed = this.startClickedObj.xFixed; + node.yFixed = this.startClickedObj.yFixed; + } + else if (this.shiftKeyDown) { + // select nodes inside selection area + var obj = { + "left": this._xToCanvas(Math.min(this.startMouseX, endMouseX) - this.startFrameLeft), + "top": this._yToCanvas(Math.min(this.startMouseY, endMouseY) - this.startFrameTop), + "right": this._xToCanvas(Math.max(this.startMouseX, endMouseX) - this.startFrameLeft), + "bottom": this._yToCanvas(Math.max(this.startMouseY, endMouseY) - this.startFrameTop) + }; + var overlappingNodes = this._getNodesOverlappingWith(obj); + this._selectNodes(overlappingNodes, ctrlKey); + this.redraw(); + + // remove the selection rectangle + if (this.frame.selRect) { + this.frame.removeChild(this.frame.selRect); + this.frame.selRect = undefined; + } + } + else { + if (!this.ctrlKeyDown && !this.moved) { + // remove selection + this._unselectNodes(); + this._redraw(); + } + } + + this.leftButtonDown = false; + this.ctrlKeyDown = false; +}; + + +/** + * Event handler for mouse wheel event, used to zoom the timeline + * Code from http://adomas.org/javascript-mouse-wheel/ + * @param {Event} event + * @private + */ +Graph.prototype._onMouseWheel = function(event) { + event = event || window.event; + var mouseX = event.clientX; + var mouseY = event.clientY; + + // retrieve delta + var delta = 0; + if (event.wheelDelta) { /* IE/Opera. */ + delta = event.wheelDelta/120; + } else if (event.detail) { /* Mozilla case. */ + // In Mozilla, sign of delta is different than in IE. + // Also, delta is multiple of 3. + delta = -event.detail/3; + } + + // If delta is nonzero, handle it. + // Basically, delta is now positive if wheel was scrolled up, + // and negative, if wheel was scrolled down. + if (delta) { + // determine zoom factor, and adjust the zoom factor such that zooming in + // and zooming out correspond wich each other + var zoom = delta / 10; + if (delta < 0) { + zoom = zoom / (1 - zoom); + } + + var scaleOld = this._getScale(); + var scaleNew = scaleOld * (1 + zoom); + if (scaleNew < 0.01) { + scaleNew = 0.01; + } + if (scaleNew > 10) { + scaleNew = 10; + } + + var frameLeft = vis.util.getAbsoluteLeft(this.frame.canvas); + var frameTop = vis.util.getAbsoluteTop(this.frame.canvas); + var x = mouseX - frameLeft; + var y = mouseY - frameTop; + + var translation = this._getTranslation(); + var scaleFrac = scaleNew / scaleOld; + var tx = (1 - scaleFrac) * x + translation.x * scaleFrac; + var ty = (1 - scaleFrac) * y + translation.y * scaleFrac; + + this._setScale(scaleNew); + this._setTranslation(tx, ty); + this._redraw(); + } + + // Prevent default actions caused by mouse wheel. + // That might be ugly, but we handle scrolls somehow + // anyway, so don't bother here... + vis.util.preventDefault(event); +}; + + +/** + * Mouse move handler for checking whether the title moves over a node with a title. + * @param {Event} event + * @private + */ +Graph.prototype._onMouseMoveTitle = function (event) { + event = event || window.event; + + var startMouseX = event.clientX; + var startMouseY = event.clientY; + this.startFrameLeft = this.startFrameLeft || vis.util.getAbsoluteLeft(this.frame.canvas); + this.startFrameTop = this.startFrameTop || vis.util.getAbsoluteTop(this.frame.canvas); + + var x = startMouseX - this.startFrameLeft; + var y = startMouseY - this.startFrameTop; + + // check if the previously selected node is still selected + if (this.popupNode) { + this._checkHidePopup(x, y); + } + + // start a timeout that will check if the mouse is positioned above + // an element + var me = this; + var checkShow = function() { + me._checkShowPopup(x, y); + }; + if (this.popupTimer) { + clearInterval(this.popupTimer); // stop any running timer + } + if (!this.leftButtonDown) { + this.popupTimer = setTimeout(checkShow, 300); + } +}; + +/** + * Check if there is an element on the given position in the graph + * (a node or edge). If so, and if this element has a title, + * show a popup window with its title. + * + * @param {number} x + * @param {number} y + * @private + */ +Graph.prototype._checkShowPopup = function (x, y) { + var obj = { + "left" : this._xToCanvas(x), + "top" : this._yToCanvas(y), + "right" : this._xToCanvas(x), + "bottom" : this._yToCanvas(y) + }; + + var i, len; + var lastPopupNode = this.popupNode; + + if (this.popupNode == undefined) { + // search the nodes for overlap, select the top one in case of multiple nodes + var nodes = this.nodes; + for (i = nodes.length - 1; i >= 0; i--) { + var node = nodes[i]; + if (node.getTitle() != undefined && node.isOverlappingWith(obj)) { + this.popupNode = node; + break; + } + } + } + + if (this.popupNode == undefined) { + // search the edges for overlap + var allEdges = this.edges; + for (i = 0, len = allEdges.length; i < len; i++) { + var edge = allEdges[i]; + if (edge.getTitle() != undefined && edge.isOverlappingWith(obj)) { + this.popupNode = edge; + break; + } + } + } + + if (this.popupNode) { + // show popup message window + if (this.popupNode != lastPopupNode) { + var me = this; + if (!me.popup) { + me.popup = new Popup(me.frame); + } + + // adjust a small offset such that the mouse cursor is located in the + // bottom left location of the popup, and you can easily move over the + // popup area + me.popup.setPosition(x - 3, y - 3); + me.popup.setText(me.popupNode.getTitle()); + me.popup.show(); + } + } + else { + if (this.popup) { + this.popup.hide(); + } + } +}; + +/** + * Check if the popup must be hided, which is the case when the mouse is no + * longer hovering on the object + * @param {number} x + * @param {number} y + * @private + */ +Graph.prototype._checkHidePopup = function (x, y) { + var obj = { + "left" : x, + "top" : y, + "right" : x, + "bottom" : y + }; + + if (!this.popupNode || !this.popupNode.isOverlappingWith(obj) ) { + this.popupNode = undefined; + if (this.popup) { + this.popup.hide(); + } + } +}; + +/** + * Event handler for touchstart event on mobile devices + * @param {Event} event + * @private + */ +Graph.prototype._onTouchStart = function(event) { + vis.util.preventDefault(event); + + if (this.touchDown) { + // if already moving, return + return; + } + this.touchDown = true; + + var me = this; + if (!this.ontouchmove) { + this.ontouchmove = function (event) {me._onTouchMove(event);}; + vis.util.addEventListener(document, "touchmove", this.ontouchmove); + } + if (!this.ontouchend) { + this.ontouchend = function (event) {me._onTouchEnd(event);}; + vis.util.addEventListener(document, "touchend", this.ontouchend); + } + + this._onMouseDown(event); +}; + +/** + * Event handler for touchmove event on mobile devices + * @param {Event} event + * @private + */ +Graph.prototype._onTouchMove = function(event) { + vis.util.preventDefault(event); + this._onMouseMove(event); +}; + +/** + * Event handler for touchend event on mobile devices + * @param {Event} event + * @private + */ +Graph.prototype._onTouchEnd = function(event) { + vis.util.preventDefault(event); + + this.touchDown = false; + + if (this.ontouchmove) { + vis.util.removeEventListener(document, "touchmove", this.ontouchmove); + this.ontouchmove = undefined; + } + if (this.ontouchend) { + vis.util.removeEventListener(document, "touchend", this.ontouchend); + this.ontouchend = undefined; + } + + this._onMouseUp(event); +}; + + +/** + * Unselect selected nodes. If no selection array is provided, all nodes + * are unselected + * @param {Object[]} selection Array with selection objects, each selection + * object has a parameter row. Optional + * @param {Boolean} triggerSelect If true (default), the select event + * is triggered when nodes are unselected + * @return {Boolean} changed True if the selection is changed + * @private + */ +Graph.prototype._unselectNodes = function(selection, triggerSelect) { + var changed = false; + var i, iMax, row; + + if (selection) { + // remove provided selections + for (i = 0, iMax = selection.length; i < iMax; i++) { + row = selection[i].row; + this.nodes[row].unselect(); + + var j = 0; + while (j < this.selection.length) { + if (this.selection[j].row == row) { + this.selection.splice(j, 1); + changed = true; + } + else { + j++; + } + } + } + } + else if (this.selection && this.selection.length) { + // remove all selections + for (i = 0, iMax = this.selection.length; i < iMax; i++) { + row = this.selection[i].row; + this.nodes[row].unselect(); + changed = true; + } + this.selection = []; + } + + if (changed && (triggerSelect == true || triggerSelect == undefined)) { + // fire the select event + this._trigger('select'); + } + + return changed; +}; + +/** + * select all nodes on given location x, y + * @param {Array} selection an array with selection objects. Each selection + * object has a parameter row + * @param {boolean} append If true, the new selection will be appended to the + * current selection (except for duplicate entries) + * @return {Boolean} changed True if the selection is changed + * @private + */ +Graph.prototype._selectNodes = function(selection, append) { + var changed = false; + var i, iMax; + + // TODO: the selectNodes method is a little messy, rework this + + // check if the current selection equals the desired selection + var selectionAlreadyDone = true; + if (selection.length != this.selection.length) { + selectionAlreadyDone = false; + } + else { + for (i = 0, iMax = Math.min(selection.length, this.selection.length); i < iMax; i++) { + if (selection[i].row != this.selection[i].row) { + selectionAlreadyDone = false; + break; + } + } + } + if (selectionAlreadyDone) { + return changed; + } + + if (append == undefined || append == false) { + // first deselect any selected node + var triggerSelect = false; + changed = this._unselectNodes(undefined, triggerSelect); + } + + for (i = 0, iMax = selection.length; i < iMax; i++) { + // add each of the new selections, but only when they are not duplicate + var row = selection[i].row; + var isDuplicate = false; + for (var j = 0, jMax = this.selection.length; j < jMax; j++) { + if (this.selection[j].row == row) { + isDuplicate = true; + break; + } + } + + if (!isDuplicate) { + this.nodes[row].select(); + this.selection.push(selection[i]); + changed = true; + } + } + + if (changed) { + // fire the select event + this._trigger('select'); + } + + return changed; +}; + +/** + * retrieve all nodes overlapping with given object + * @param {Object} obj An object with parameters left, top, right, bottom + * @return {Object[]} An array with selection objects containing + * the parameter row. + * @private + */ +Graph.prototype._getNodesOverlappingWith = function (obj) { + var overlappingNodes = []; + + for (var i = 0; i < this.nodes.length; i++) { + if (this.nodes[i].isOverlappingWith(obj)) { + var sel = {"row": i}; + overlappingNodes.push(sel); + } + } + + return overlappingNodes; +}; + +/** + * retrieve the currently selected nodes + * @return {Object[]} an array with zero or more objects. Each object + * contains the parameter row + */ +Graph.prototype.getSelection = function() { + var selection = []; + + for (var i = 0; i < this.selection.length; i++) { + var row = this.selection[i].row; + selection.push({"row": row}); + } + + return selection; +}; + +/** + * select zero or more nodes + * @param {object[]} selection an array with zero or more objects. Each object + * contains the parameter row + */ +Graph.prototype.setSelection = function(selection) { + var i, iMax, row; + + if (selection.length == undefined) + throw "Selection must be an array with objects"; + + // first unselect any selected node + for (i = 0, iMax = this.selection.length; i < iMax; i++) { + row = this.selection[i].row; + this.nodes[row].unselect(); + } + + this.selection = []; + + for (i = 0, iMax = selection.length; i < iMax; i++) { + row = selection[i].row; + + if (row == undefined) + throw "Parameter row missing in selection object"; + if (row > this.nodes.length-1) + throw "Parameter row out of range"; + + var sel = {"row": row}; + this.selection.push(sel); + this.nodes[row].select(); + } + + this.redraw(); +}; + + +/** + * Temporary method to test calculating a hub value for the nodes + * @param {number} level Maximum number edges between two nodes in order + * to call them connected. Optional, 1 by default + * @return {Number[]} connectioncount array with the connection count + * for each node + * @private + */ +Graph.prototype._getConnectionCount = function(level) { + var conn = this.edges; + if (level == undefined) { + level = 1; + } + + // get the nodes connected to given nodes + function getConnectedNodes(nodes) { + var connectedNodes = []; + + for (var j = 0, jMax = nodes.length; j < jMax; j++) { + var node = nodes[j]; + + // find all nodes connected to this node + for (var i = 0, iMax = conn.length; i < iMax; i++) { + var other = null; + + // check if connected + if (conn[i].from == node) + other = conn[i].to; + else if (conn[i].to == node) + other = conn[i].from; + + // check if the other node is not already in the list with nodes + var k, kMax; + if (other) { + for (k = 0, kMax = nodes.length; k < kMax; k++) { + if (nodes[k] == other) { + other = null; + break; + } + } + } + if (other) { + for (k = 0, kMax = connectedNodes.length; k < kMax; k++) { + if (connectedNodes[k] == other) { + other = null; + break; + } + } + } + + if (other) + connectedNodes.push(other); + } + } + + return connectedNodes; + } + + var connections = []; + var level0 = []; + var nodes = this.nodes; + var i, iMax; + for (i = 0, iMax = nodes.length; i < iMax; i++) { + var c = [nodes[i]]; + for (var l = 0; l < level; l++) { + c = c.concat(getConnectedNodes(c)); + } + connections.push(c); + } + + var hubs = []; + for (i = 0, len = connections.length; i < len; i++) { + hubs.push(connections[i].length); + } + + return hubs; +}; + + +/** + * Set a new size for the graph + * @param {string} width Width in pixels or percentage (for example "800px" + * or "50%") + * @param {string} height Height in pixels or percentage (for example "400px" + * or "30%") + */ +Graph.prototype.setSize = function(width, height) { + this.frame.style.width = width; + this.frame.style.height = height; + + this.frame.canvas.style.width = "100%"; + this.frame.canvas.style.height = "100%"; + + this.frame.canvas.width = this.frame.canvas.clientWidth; + this.frame.canvas.height = this.frame.canvas.clientHeight; +}; + +/** + * Set a data set with nodes for the graph + * @param {Array} nodes The data containing the nodes. + * @private + */ +Graph.prototype._setNodes = function(nodes) { + this.selection = []; + this.nodes = []; + this.moving = false; + if (!nodes) { + return; + } + + var hasValues = false; + var rowCount = nodes.length; + for (var i = 0; i < rowCount; i++) { + var properties = nodes[i]; + + if (properties.value != undefined) { + hasValues = true; + } + if (properties.id == undefined) { + throw "Column 'id' missing in table with nodes (row " + i + ")"; + } + this._createNode(properties); + } + + // calculate scaling function when value is provided + if (hasValues) { + this._updateValueRange(this.nodes); + } + + // give the nodes some first (random) position + this._reposition(); // TODO: bad solution +}; + +/** + * Create a node with the given properties + * If the new node has an id identical to an existing node, the existing + * node will be overwritten. + * The properties can contain a property "action", which can have values + * "create", "update", or "delete" + * @param {Object} properties An object with properties + * @private + */ +Graph.prototype._createNode = function(properties) { + var action = properties.action ? properties.action : "update"; + var id, index, newNode, oldNode; + + if (action === "create") { + // create the node + newNode = new Node(properties, this.images, this.groups, this.constants); + id = properties.id; + index = (id !== undefined) ? this._findNode(id) : undefined; + + if (index !== undefined) { + // replace node + oldNode = this.nodes[index]; + this.nodes[index] = newNode; + + // remove selection of old node + if (oldNode.selected) { + this._unselectNodes([{'row': index}], false); + } + + /* TODO: implement this? -> will give performance issues, searching all edges and nodes... + // update edges linking to this node + var edgesTable = this.edges; + for (var i = 0, iMax = edgesTable.length; i < iMax; i++) { + var edge = edgesTable[i]; + if (edge.from == oldNode) { + edge.from = newNode; + } + if (edge.to == oldNode) { + edge.to = newNode; + } + } + */ + } + else { + // add new node + this.nodes.push(newNode); + } + + if (!newNode.isFixed()) { + // note: no not use node.isMoving() here, as that gives the current + // velocity of the node, which is zero after creation of the node. + this.moving = true; + } + } + else if (action === "update") { + // update existing node, or create it when not yet existing + id = properties.id; + if (id === undefined) { + throw "Cannot update a node without id"; + } + + index = this._findNode(id); + if (index !== undefined) { + // update node + this.nodes[index].setProperties(properties, this.constants); + } + else { + // create node + newNode = new Node(properties, this.images, this.groups, this.constants); + this.nodes.push(newNode); + + if (!newNode.isFixed()) { + // note: no not use node.isMoving() here, as that gives the current + // velocity of the node, which is zero after creation of the node. + this.moving = true; + } + } + } + else if (action === "delete") { + // delete existing node + id = properties.id; + if (id === undefined) { + throw "Cannot delete node without its id"; + } + + index = this._findNode(id); + if (index !== undefined) { + oldNode = this.nodes[index]; + // remove selection of old node + if (oldNode.selected) { + this._unselectNodes([{'row': index}], false); + } + this.nodes.splice(index, 1); + } + else { + throw "Node with id " + id + " not found"; + } + } + else { + throw "Unknown action " + action + ". Choose 'create', 'update', or 'delete'."; + } +}; + +/** + * Find a node by its id + * @param {Number} id Id of the node + * @return {Number | undefined} index Index of the node in the array + * this.nodes, or undefined when not found + * @private + */ +Graph.prototype._findNode = function (id) { + var nodes = this.nodes; + for (var n = 0, len = nodes.length; n < len; n++) { + if (nodes[n].id === id) { + return n; + } + } + + return undefined; +}; + +/** + * Find a node by its rowNumber + * @param {Number} row Row number of the node + * @return {Node} node     The node with the given row number, or + *                            undefined when not found. + * @private + */ +Graph.prototype._findNodeByRow = function (row) { + return this.nodes[row]; +}; + +/** + * Load edges by reading the data table + * @param {Array} edges The data containing the edges. + * @private + * @private + */ +Graph.prototype._setEdges = function(edges) { + this.edges = []; + if (!edges) { + return; + } + + var hasValues = false; + var rowCount = edges.length; + for (var i = 0; i < rowCount; i++) { + var properties = edges[i]; + + if (properties.from === undefined) { + throw "Column 'from' missing in table with edges (row " + i + ")"; + } + if (properties.to === undefined) { + throw "Column 'to' missing in table with edges (row " + i + ")"; + } + if (properties.value != undefined) { + hasValues = true; + } + + this._createEdge(properties); + } + + // calculate scaling function when value is provided + if (hasValues) { + this._updateValueRange(this.edges); + } +}; + +/** + * Create a edge with the given properties + * If the new edge has an id identical to an existing edge, the existing + * edge will be overwritten or updated. + * The properties can contain a property "action", which can have values + * "create", "update", or "delete" + * @param {Object} properties An object with properties + * @private + */ +Graph.prototype._createEdge = function(properties) { + var action = properties.action ? properties.action : "create"; + var id, index, edge, oldEdge, newEdge; + + if (action === "create") { + // create the edge, or replace it if already existing + id = properties.id; + index = (id !== undefined) ? this._findEdge(id) : undefined; + edge = new Edge(properties, this, this.constants); + + if (index !== undefined) { + // replace existing edge + oldEdge = this.edges[index]; + oldEdge.from.detachEdge(oldEdge); + oldEdge.to.detachEdge(oldEdge); + this.edges[index] = edge; + } + else { + // add new edge + this.edges.push(edge); + } + edge.from.attachEdge(edge); + edge.to.attachEdge(edge); + } + else if (action === "update") { + // update existing edge, or create the edge if not existing + id = properties.id; + if (id === undefined) { + throw "Cannot update a edge without id"; + } + + index = this._findEdge(id); + if (index !== undefined) { + // update edge + edge = this.edges[index]; + edge.from.detachEdge(edge); + edge.to.detachEdge(edge); + + edge.setProperties(properties, this.constants); + edge.from.attachEdge(edge); + edge.to.attachEdge(edge); + } + else { + // add new edge + edge = new Edge(properties, this, this.constants); + edge.from.attachEdge(edge); + edge.to.attachEdge(edge); + this.edges.push(edge); + } + } + else if (action === "delete") { + // delete existing edge + id = properties.id; + if (id === undefined) { + throw "Cannot delete edge without its id"; + } + + index = this._findEdge(id); + if (index !== undefined) { + oldEdge = this.edges[id]; + edge.from.detachEdge(oldEdge); + edge.to.detachEdge(oldEdge); + this.edges.splice(index, 1); + } + else { + throw "Edge with id " + id + " not found"; + } + } + else { + throw "Unknown action " + action + ". Choose 'create', 'update', or 'delete'."; + } +}; + +/** + * Update the references to oldNode in all edges. + * @param {Node} oldNode + * @param {Node} newNode + * @private + */ +// TODO: start utilizing this method _updateNodeReferences +Graph.prototype._updateNodeReferences = function(oldNode, newNode) { + var edges = this.edges; + for (var i = 0, iMax = edges.length; i < iMax; i++) { + var edge = edges[i]; + if (edge.from === oldNode) { + edge.from = newNode; + } + if (edge.to === oldNode) { + edge.to = newNode; + } + } +}; + +/** + * Find a edge by its id + * @param {Number} id Id of the edge + * @return {Number | undefined} index Index of the edge in the array + * this.edges, or undefined when not found + * @private + */ +Graph.prototype._findEdge = function (id) { + var edges = this.edges; + for (var n = 0, len = edges.length; n < len; n++) { + if (edges[n].id === id) { + return n; + } + } + + return undefined; +}; + +/** + * Find a edge by its row + * @param {Number} row Row of the edge + * @return {Edge | undefined} the found edge, or undefined when not found + * @private + */ +Graph.prototype._findEdgeByRow = function (row) { + return this.edges[row]; +}; + +/** + * Update the values of all object in the given array according to the current + * value range of the objects in the array. + * @param {Array} array. An array with objects like Edges or Nodes + * The objects must have a method getValue() and + * setValueRange(min, max). + * @private + */ +Graph.prototype._updateValueRange = function(array) { + var count = array.length; + var i; + + // determine the range of the node values + var valueMin = undefined; + var valueMax = undefined; + for (i = 0; i < count; i++) { + var value = array[i].getValue(); + if (value !== undefined) { + valueMin = (valueMin === undefined) ? value : Math.min(value, valueMin); + valueMax = (valueMax === undefined) ? value : Math.max(value, valueMax); + } + } + + // adjust the range of all nodes + if (valueMin !== undefined && valueMax !== undefined) { + for (i = 0; i < count; i++) { + array[i].setValueRange(valueMin, valueMax); + } + } +}; + +/** + * Redraw the graph with the current data + * chart will be resized too. + */ +Graph.prototype.redraw = function() { + this.setSize(this.width, this.height); + + this._redraw(); +}; + +/** + * Redraw the graph with the current data + * @private + */ +Graph.prototype._redraw = function() { + var ctx = this.frame.canvas.getContext("2d"); + + // clear the canvas + var w = this.frame.canvas.width; + var h = this.frame.canvas.height; + ctx.clearRect(0, 0, w, h); + + // set scaling and translation + ctx.save(); + ctx.translate(this.translation.x, this.translation.y); + ctx.scale(this.scale, this.scale); + + this._drawEdges(ctx); + this._drawNodes(ctx); + + // restore original scaling and translation + ctx.restore(); +}; + +/** + * Set the translation of the graph + * @param {Number} offsetX Horizontal offset + * @param {Number} offsetY Vertical offset + * @private + */ +Graph.prototype._setTranslation = function(offsetX, offsetY) { + if (this.translation === undefined) { + this.translation = { + "x": 0, + "y": 0 + }; + } + + if (offsetX !== undefined) { + this.translation.x = offsetX; + } + if (offsetY !== undefined) { + this.translation.y = offsetY; + } +}; + +/** + * Get the translation of the graph + * @return {Object} translation An object with parameters x and y, both a number + * @private + */ +Graph.prototype._getTranslation = function() { + return { + "x": this.translation.x, + "y": this.translation.y + }; +}; + +/** + * Scale the graph + * @param {Number} scale Scaling factor 1.0 is unscaled + * @private + */ +Graph.prototype._setScale = function(scale) { + this.scale = scale; +}; +/** + * Get the current scale of the graph + * @return {Number} scale Scaling factor 1.0 is unscaled + * @private + */ +Graph.prototype._getScale = function() { + return this.scale; +}; + +Graph.prototype._xToCanvas = function(x) { + return (x - this.translation.x) / this.scale; +}; + +Graph.prototype._canvasToX = function(x) { + return x * this.scale + this.translation.x; +}; + +Graph.prototype._yToCanvas = function(y) { + return (y - this.translation.y) / this.scale; +}; + +Graph.prototype._canvasToY = function(y) { + return y * this.scale + this.translation.y ; +}; + + + +/** + * Get a node by its id + * @param {number} id + * @return {Node} node, or null if not found + * @private + */ +Graph.prototype._getNode = function(id) { + for (var i = 0; i < this.nodes.length; i++) { + if (this.nodes[i].id == id) + return this.nodes[i]; + } + + return null; +}; + +/** + * Redraw all nodes + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private + */ +Graph.prototype._drawNodes = function(ctx) { + // first draw the unselected nodes + var nodes = this.nodes; + var selected = []; + for (var i = 0, iMax = nodes.length; i < iMax; i++) { + if (nodes[i].isSelected()) { + selected.push(i); + } + else { + nodes[i].draw(ctx); + } + } + + // draw the selected nodes on top + for (var s = 0, sMax = selected.length; s < sMax; s++) { + nodes[selected[s]].draw(ctx); + } +}; + +/** + * Redraw all edges + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private + */ +Graph.prototype._drawEdges = function(ctx) { + var edges = this.edges; + for (var i = 0, iMax = edges.length; i < iMax; i++) { + edges[i].draw(ctx); + } +}; + +/** + * Recalculate the best positions for all nodes + * @private + */ +Graph.prototype._reposition = function() { + // TODO: implement function reposition + + + /* + var w = this.frame.canvas.clientWidth; + var h = this.frame.canvas.clientHeight; + for (var i = 0; i < this.nodes.length; i++) { + if (!this.nodes[i].xFixed) this.nodes[i].x = w * Math.random(); + if (!this.nodes[i].yFixed) this.nodes[i].y = h * Math.random(); + } + //*/ + + //* + // TODO + var radius = this.constants.edges.length * 2; + var cx = this.frame.canvas.clientWidth / 2; + var cy = this.frame.canvas.clientHeight / 2; + for (var i = 0; i < this.nodes.length; i++) { + var angle = 2*Math.PI * (i / this.nodes.length); + + if (!this.nodes[i].xFixed) this.nodes[i].x = cx + radius * Math.cos(angle); + if (!this.nodes[i].yFixed) this.nodes[i].y = cy + radius * Math.sin(angle); + + } + //*/ + + /* + // TODO + var radius = this.constants.edges.length * 2; + var w = this.frame.canvas.clientWidth, + h = this.frame.canvas.clientHeight; + var cx = this.frame.canvas.clientWidth / 2; + var cy = this.frame.canvas.clientHeight / 2; + var s = Math.sqrt(this.nodes.length); + for (var i = 0; i < this.nodes.length; i++) { + //var angle = 2*Math.PI * (i / this.nodes.length); + + if (!this.nodes[i].xFixed) this.nodes[i].x = w/s * (i % s); + if (!this.nodes[i].yFixed) this.nodes[i].y = h/s * (i / s); + } + //*/ + + + /* + var cx = this.frame.canvas.clientWidth / 2; + var cy = this.frame.canvas.clientHeight / 2; + for (var i = 0; i < this.nodes.length; i++) { + this.nodes[i].x = cx; + this.nodes[i].y = cy; + } + + //*/ + +}; + + +/** + * Find a stable position for all nodes + * @private + */ +Graph.prototype._doStabilize = function() { + var start = new Date(); + + // find stable position + var count = 0; + var vmin = this.constants.minVelocity; + var stable = false; + while (!stable && count < this.constants.maxIterations) { + this._calculateForces(); + this._discreteStepNodes(); + stable = !this._isMoving(vmin); + count++; + } + + var end = new Date(); + + // console.log("Stabilized in " + (end-start) + " ms, " + count + " iterations" ); // TODO: cleanup +}; + +/** + * Calculate the external forces acting on the nodes + * Forces are caused by: edges, repulsing forces between nodes, gravity + * @private + */ +Graph.prototype._calculateForces = function() { + // create a local edge to the nodes and edges, that is faster + var nodes = this.nodes, + edges = this.edges; + + // gravity, add a small constant force to pull the nodes towards the center of + // the graph + // Also, the forces are reset to zero in this loop by using _setForce instead + // of _addForce + var gravity = 0.01, + gx = this.frame.canvas.clientWidth / 2, + gy = this.frame.canvas.clientHeight / 2; + for (var n = 0; n < nodes.length; n++) { + var dx = gx - nodes[n].x, + dy = gy - nodes[n].y, + angle = Math.atan2(dy, dx), + fx = Math.cos(angle) * gravity, + fy = Math.sin(angle) * gravity; + + this.nodes[n]._setForce(fx, fy); + } + + // repulsing forces between nodes + var minimumDistance = this.constants.nodes.distance, + steepness = 10; // higher value gives steeper slope of the force around the given minimumDistance + for (var n = 0; n < nodes.length; n++) { + for (var n2 = n + 1; n2 < this.nodes.length; n2++) { + //var dmin = (nodes[n].width + nodes[n].height + nodes[n2].width + nodes[n2].height) / 1 || minimumDistance, // TODO: dmin + //var dmin = (nodes[n].width + nodes[n2].width)/2 || minimumDistance, // TODO: dmin + //dmin = 40 + ((nodes[n].width/2 + nodes[n2].width/2) || 0), + + // calculate normally distributed force + var dx = nodes[n2].x - nodes[n].x, + dy = nodes[n2].y - nodes[n].y, + distance = Math.sqrt(dx * dx + dy * dy), + angle = Math.atan2(dy, dx), + + // TODO: correct factor for repulsing force + //var repulsingforce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force + //repulsingforce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ), // TODO: customize the repulsing force + repulsingforce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)), // TODO: customize the repulsing force + fx = Math.cos(angle) * repulsingforce, + fy = Math.sin(angle) * repulsingforce; + + this.nodes[n]._addForce(-fx, -fy); + this.nodes[n2]._addForce(fx, fy); + } + /* TODO: re-implement repulsion of edges + for (var l = 0; l < edges.length; l++) { + var lx = edges[l].from.x+(edges[l].to.x - edges[l].from.x)/2, + ly = edges[l].from.y+(edges[l].to.y - edges[l].from.y)/2, + + // calculate normally distributed force + dx = nodes[n].x - lx, + dy = nodes[n].y - ly, + distance = Math.sqrt(dx * dx + dy * dy), + angle = Math.atan2(dy, dx), + + + // TODO: correct factor for repulsing force + //var repulsingforce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force + //repulsingforce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ), // TODO: customize the repulsing force + repulsingforce = 1 / (1 + Math.exp((distance / (minimumDistance / 2) - 1) * steepness)), // TODO: customize the repulsing force + fx = Math.cos(angle) * repulsingforce, + fy = Math.sin(angle) * repulsingforce; + nodes[n]._addForce(fx, fy); + edges[l].from._addForce(-fx/2,-fy/2); + edges[l].to._addForce(-fx/2,-fy/2); + } + */ + } + + // forces caused by the edges, modelled as springs + for (var l = 0, lMax = edges.length; l < lMax; l++) { + var edge = edges[l], + + dx = (edge.to.x - edge.from.x), + dy = (edge.to.y - edge.from.y), + //edgeLength = (edge.from.width + edge.from.height + edge.to.width + edge.to.height)/2 || edge.length, // TODO: dmin + //edgeLength = (edge.from.width + edge.to.width)/2 || edge.length, // TODO: dmin + //edgeLength = 20 + ((edge.from.width + edge.to.width) || 0) / 2, + edgeLength = edge.length, + length = Math.sqrt(dx * dx + dy * dy), + angle = Math.atan2(dy, dx), + + springforce = edge.stiffness * (edgeLength - length), + + fx = Math.cos(angle) * springforce, + fy = Math.sin(angle) * springforce; + + edge.from._addForce(-fx, -fy); + edge.to._addForce(fx, fy); + } + + /* TODO: re-implement repulsion of edges + // repulsing forces between edges + var minimumDistance = this.constants.edges.distance, + steepness = 10; // higher value gives steeper slope of the force around the given minimumDistance + for (var l = 0; l < edges.length; l++) { + //Keep distance from other edge centers + for (var l2 = l + 1; l2 < this.edges.length; l2++) { + //var dmin = (nodes[n].width + nodes[n].height + nodes[n2].width + nodes[n2].height) / 1 || minimumDistance, // TODO: dmin + //var dmin = (nodes[n].width + nodes[n2].width)/2 || minimumDistance, // TODO: dmin + //dmin = 40 + ((nodes[n].width/2 + nodes[n2].width/2) || 0), + var lx = edges[l].from.x+(edges[l].to.x - edges[l].from.x)/2, + ly = edges[l].from.y+(edges[l].to.y - edges[l].from.y)/2, + l2x = edges[l2].from.x+(edges[l2].to.x - edges[l2].from.x)/2, + l2y = edges[l2].from.y+(edges[l2].to.y - edges[l2].from.y)/2, + + // calculate normally distributed force + dx = l2x - lx, + dy = l2y - ly, + distance = Math.sqrt(dx * dx + dy * dy), + angle = Math.atan2(dy, dx), + + + // TODO: correct factor for repulsing force + //var repulsingforce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force + //repulsingforce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ), // TODO: customize the repulsing force + repulsingforce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)), // TODO: customize the repulsing force + fx = Math.cos(angle) * repulsingforce, + fy = Math.sin(angle) * repulsingforce; + + edges[l].from._addForce(-fx, -fy); + edges[l].to._addForce(-fx, -fy); + edges[l2].from._addForce(fx, fy); + edges[l2].to._addForce(fx, fy); + } + } + */ +}; + + +/** + * Check if any of the nodes is still moving + * @param {number} vmin the minimum velocity considered as "moving" + * @return {boolean} true if moving, false if non of the nodes is moving + * @private + */ +Graph.prototype._isMoving = function(vmin) { + // TODO: ismoving does not work well: should check the kinetic energy, not its velocity + var nodes = this.nodes; + for (var n = 0, nMax = nodes.length; n < nMax; n++) { + if (nodes[n].isMoving(vmin)) { + return true; + } + } + return false; +}; + + +/** + * Perform one discrete step for all nodes + * @private + */ +Graph.prototype._discreteStepNodes = function() { + var interval = this.refreshRate / 1000.0; // in seconds + var nodes = this.nodes; + for (var n = 0, nMax = nodes.length; n < nMax; n++) { + nodes[n].discreteStep(interval); + } +}; + +/** + * Start animating nodes and edges + */ +Graph.prototype.start = function() { + if (this.moving) { + this._calculateForces(); + this._discreteStepNodes(); + + var vmin = this.constants.minVelocity; + this.moving = this._isMoving(vmin); + } + + if (this.moving) { + // start animation. only start timer if it is not already running + if (!this.timer) { + var graph = this; + this.timer = window.setTimeout(function () { + graph.timer = undefined; + graph.start(); + graph._redraw(); + }, this.refreshRate); + } + } + else { + this._redraw(); + } +}; + +/** + * Stop animating nodes and edges. + */ +Graph.prototype.stop = function () { + if (this.timer) { + window.clearInterval(this.timer); + this.timer = undefined; + } +}; + +/** + * vis.js module exports + */ +var vis = { + util: util, + events: events, + + Controller: Controller, + DataSet: DataSet, + DataView: DataView, + Range: Range, + Stack: Stack, + TimeStep: TimeStep, + EventBus: EventBus, + + components: { + items: { + Item: Item, + ItemBox: ItemBox, + ItemPoint: ItemPoint, + ItemRange: ItemRange + }, + + Component: Component, + Panel: Panel, + RootPanel: RootPanel, + ItemSet: ItemSet, + TimeAxis: TimeAxis + }, + + graph: { + Node: Node, + Edge: Edge, + Popup: Popup, + Groups: Groups, + Images: Images + }, + + Timeline: Timeline, + Graph: Graph +}; + +/** + * CommonJS module exports + */ +if (typeof exports !== 'undefined') { + exports = vis; +} +if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { + module.exports = vis; +} + +/** + * AMD module exports + */ +if (typeof(define) === 'function') { + define(function () { + return vis; + }); +} + +/** + * Window exports + */ +if (typeof window !== 'undefined') { + // attach the module to the window, load as a regular javascript file + window['vis'] = vis; +} + +// inject css +util.loadCss("/* vis.js stylesheet */\n\n.graph {\n position: relative;\n border: 1px solid #bfbfbf;\n}\n\n.graph .panel {\n position: absolute;\n}\n\n.graph .groupset {\n position: absolute;\n padding: 0;\n margin: 0;\n}\n\n\n.graph .itemset {\n position: absolute;\n padding: 0;\n margin: 0;\n overflow: hidden;\n}\n\n.graph .background {\n}\n\n.graph .foreground {\n}\n\n.graph .itemset-axis {\n position: absolute;\n}\n\n.graph .groupset .itemset-axis {\n border-top: 1px solid #bfbfbf;\n}\n\n/* TODO: with orientation=='bottom', this will more or less overlap with timeline axis\n.graph .groupset .itemset-axis:last-child {\n border-top: none;\n}\n*/\n\n\n.graph .item {\n position: absolute;\n color: #1A1A1A;\n border-color: #97B0F8;\n background-color: #D5DDF6;\n display: inline-block;\n}\n\n.graph .item.selected {\n border-color: #FFC200;\n background-color: #FFF785;\n z-index: 999;\n}\n\n.graph .item.cluster {\n /* TODO: use another color or pattern? */\n background: #97B0F8 url('img/cluster_bg.png');\n color: white;\n}\n.graph .item.cluster.point {\n border-color: #D5DDF6;\n}\n\n.graph .item.box {\n text-align: center;\n border-style: solid;\n border-width: 1px;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.graph .item.point {\n background: none;\n}\n\n.graph .dot {\n border: 5px solid #97B0F8;\n position: absolute;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.graph .item.range {\n overflow: hidden;\n border-style: solid;\n border-width: 1px;\n border-radius: 2px;\n -moz-border-radius: 2px; /* For Firefox 3.6 and older */\n}\n\n.graph .item.range .drag-left {\n cursor: w-resize;\n z-index: 1000;\n}\n\n.graph .item.range .drag-right {\n cursor: e-resize;\n z-index: 1000;\n}\n\n.graph .item.range .content {\n position: relative;\n display: inline-block;\n}\n\n.graph .item.line {\n position: absolute;\n width: 0;\n border-left-width: 1px;\n border-left-style: solid;\n}\n\n.graph .item .content {\n margin: 5px;\n white-space: nowrap;\n overflow: hidden;\n}\n\n/* TODO: better css name, 'graph' is way to generic */\n\n.graph {\n overflow: hidden;\n}\n\n.graph .axis {\n position: relative;\n}\n\n.graph .axis .text {\n position: absolute;\n color: #4d4d4d;\n padding: 3px;\n white-space: nowrap;\n}\n\n.graph .axis .text.measure {\n position: absolute;\n padding-left: 0;\n padding-right: 0;\n margin-left: 0;\n margin-right: 0;\n visibility: hidden;\n}\n\n.graph .axis .grid.vertical {\n position: absolute;\n width: 0;\n border-right: 1px solid;\n}\n\n.graph .axis .grid.horizontal {\n position: absolute;\n left: 0;\n width: 100%;\n height: 0;\n border-bottom: 1px solid;\n}\n\n.graph .axis .grid.minor {\n border-color: #e5e5e5;\n}\n\n.graph .axis .grid.major {\n border-color: #bfbfbf;\n}\n\n"); + +})() +},{"moment":2}],2:[function(require,module,exports){ +(function(){// moment.js +// version : 2.0.0 +// author : Tim Wood +// license : MIT +// momentjs.com + +(function (undefined) { + + /************************************ + Constants + ************************************/ + + var moment, + VERSION = "2.0.0", + round = Math.round, i, + // internal storage for language config files + languages = {}, + + // check for nodeJS + hasModule = (typeof module !== 'undefined' && module.exports), + + // ASP.NET json date format regex + aspNetJsonRegex = /^\/?Date\((\-?\d+)/i, + + // format tokens + formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYY|YYYY|YY|a|A|hh?|HH?|mm?|ss?|SS?S?|X|zz?|ZZ?|.)/g, + localFormattingTokens = /(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g, + + // parsing tokens + parseMultipleFormatChunker = /([0-9a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)/gi, + + // parsing token regexes + parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99 + parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999 + parseTokenThreeDigits = /\d{3}/, // 000 - 999 + parseTokenFourDigits = /\d{1,4}/, // 0 - 9999 + parseTokenSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999 + parseTokenWord = /[0-9]*[a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF]+\s*?[\u0600-\u06FF]+/i, // any word (or two) characters or numbers including two word month in arabic. + parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/i, // +00:00 -00:00 +0000 -0000 or Z + parseTokenT = /T/i, // T (ISO seperator) + parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123 + + // preliminary iso regex + // 0000-00-00 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 + isoRegex = /^\s*\d{4}-\d\d-\d\d((T| )(\d\d(:\d\d(:\d\d(\.\d\d?\d?)?)?)?)?([\+\-]\d\d:?\d\d)?)?/, + isoFormat = 'YYYY-MM-DDTHH:mm:ssZ', + + // iso time formats and regexes + isoTimes = [ + ['HH:mm:ss.S', /(T| )\d\d:\d\d:\d\d\.\d{1,3}/], + ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/], + ['HH:mm', /(T| )\d\d:\d\d/], + ['HH', /(T| )\d\d/] + ], + + // timezone chunker "+10:00" > ["10", "00"] or "-1530" > ["-15", "30"] + parseTimezoneChunker = /([\+\-]|\d\d)/gi, + + // getter and setter names + proxyGettersAndSetters = 'Month|Date|Hours|Minutes|Seconds|Milliseconds'.split('|'), + unitMillisecondFactors = { + 'Milliseconds' : 1, + 'Seconds' : 1e3, + 'Minutes' : 6e4, + 'Hours' : 36e5, + 'Days' : 864e5, + 'Months' : 2592e6, + 'Years' : 31536e6 + }, + + // format function strings + formatFunctions = {}, + + // tokens to ordinalize and pad + ordinalizeTokens = 'DDD w W M D d'.split(' '), + paddedTokens = 'M D H h m s w W'.split(' '), + + formatTokenFunctions = { + M : function () { + return this.month() + 1; + }, + MMM : function (format) { + return this.lang().monthsShort(this, format); + }, + MMMM : function (format) { + return this.lang().months(this, format); + }, + D : function () { + return this.date(); + }, + DDD : function () { + return this.dayOfYear(); + }, + d : function () { + return this.day(); + }, + dd : function (format) { + return this.lang().weekdaysMin(this, format); + }, + ddd : function (format) { + return this.lang().weekdaysShort(this, format); + }, + dddd : function (format) { + return this.lang().weekdays(this, format); + }, + w : function () { + return this.week(); + }, + W : function () { + return this.isoWeek(); + }, + YY : function () { + return leftZeroFill(this.year() % 100, 2); + }, + YYYY : function () { + return leftZeroFill(this.year(), 4); + }, + YYYYY : function () { + return leftZeroFill(this.year(), 5); + }, + a : function () { + return this.lang().meridiem(this.hours(), this.minutes(), true); + }, + A : function () { + return this.lang().meridiem(this.hours(), this.minutes(), false); + }, + H : function () { + return this.hours(); + }, + h : function () { + return this.hours() % 12 || 12; + }, + m : function () { + return this.minutes(); + }, + s : function () { + return this.seconds(); + }, + S : function () { + return ~~(this.milliseconds() / 100); + }, + SS : function () { + return leftZeroFill(~~(this.milliseconds() / 10), 2); + }, + SSS : function () { + return leftZeroFill(this.milliseconds(), 3); + }, + Z : function () { + var a = -this.zone(), + b = "+"; + if (a < 0) { + a = -a; + b = "-"; + } + return b + leftZeroFill(~~(a / 60), 2) + ":" + leftZeroFill(~~a % 60, 2); + }, + ZZ : function () { + var a = -this.zone(), + b = "+"; + if (a < 0) { + a = -a; + b = "-"; + } + return b + leftZeroFill(~~(10 * a / 6), 4); + }, + X : function () { + return this.unix(); + } + }; + + function padToken(func, count) { + return function (a) { + return leftZeroFill(func.call(this, a), count); + }; + } + function ordinalizeToken(func) { + return function (a) { + return this.lang().ordinal(func.call(this, a)); + }; + } + + while (ordinalizeTokens.length) { + i = ordinalizeTokens.pop(); + formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i]); + } + while (paddedTokens.length) { + i = paddedTokens.pop(); + formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2); + } + formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3); + + + /************************************ + Constructors + ************************************/ + + function Language() { + + } + + // Moment prototype object + function Moment(config) { + extend(this, config); + } + + // Duration Constructor + function Duration(duration) { + var data = this._data = {}, + years = duration.years || duration.year || duration.y || 0, + months = duration.months || duration.month || duration.M || 0, + weeks = duration.weeks || duration.week || duration.w || 0, + days = duration.days || duration.day || duration.d || 0, + hours = duration.hours || duration.hour || duration.h || 0, + minutes = duration.minutes || duration.minute || duration.m || 0, + seconds = duration.seconds || duration.second || duration.s || 0, + milliseconds = duration.milliseconds || duration.millisecond || duration.ms || 0; + + // representation for dateAddRemove + this._milliseconds = milliseconds + + seconds * 1e3 + // 1000 + minutes * 6e4 + // 1000 * 60 + hours * 36e5; // 1000 * 60 * 60 + // Because of dateAddRemove treats 24 hours as different from a + // day when working around DST, we need to store them separately + this._days = days + + weeks * 7; + // It is impossible translate months into days without knowing + // which months you are are talking about, so we have to store + // it separately. + this._months = months + + years * 12; + + // The following code bubbles up values, see the tests for + // examples of what that means. + data.milliseconds = milliseconds % 1000; + seconds += absRound(milliseconds / 1000); + + data.seconds = seconds % 60; + minutes += absRound(seconds / 60); + + data.minutes = minutes % 60; + hours += absRound(minutes / 60); + + data.hours = hours % 24; + days += absRound(hours / 24); + + days += weeks * 7; + data.days = days % 30; + + months += absRound(days / 30); + + data.months = months % 12; + years += absRound(months / 12); + + data.years = years; + } + + + /************************************ + Helpers + ************************************/ + + + function extend(a, b) { + for (var i in b) { + if (b.hasOwnProperty(i)) { + a[i] = b[i]; + } + } + return a; + } + + function absRound(number) { + if (number < 0) { + return Math.ceil(number); + } else { + return Math.floor(number); + } + } + + // left zero fill a number + // see http://jsperf.com/left-zero-filling for performance comparison + function leftZeroFill(number, targetLength) { + var output = number + ''; + while (output.length < targetLength) { + output = '0' + output; + } + return output; + } + + // helper function for _.addTime and _.subtractTime + function addOrSubtractDurationFromMoment(mom, duration, isAdding) { + var ms = duration._milliseconds, + d = duration._days, + M = duration._months, + currentDate; + + if (ms) { + mom._d.setTime(+mom + ms * isAdding); + } + if (d) { + mom.date(mom.date() + d * isAdding); + } + if (M) { + currentDate = mom.date(); + mom.date(1) + .month(mom.month() + M * isAdding) + .date(Math.min(currentDate, mom.daysInMonth())); + } + } + + // check if is an array + function isArray(input) { + return Object.prototype.toString.call(input) === '[object Array]'; + } + + // compare two arrays, return the number of differences + function compareArrays(array1, array2) { + var len = Math.min(array1.length, array2.length), + lengthDiff = Math.abs(array1.length - array2.length), + diffs = 0, + i; + for (i = 0; i < len; i++) { + if (~~array1[i] !== ~~array2[i]) { + diffs++; + } + } + return diffs + lengthDiff; + } + + + /************************************ + Languages + ************************************/ + + + Language.prototype = { + set : function (config) { + var prop, i; + for (i in config) { + prop = config[i]; + if (typeof prop === 'function') { + this[i] = prop; + } else { + this['_' + i] = prop; + } + } + }, + + _months : "January_February_March_April_May_June_July_August_September_October_November_December".split("_"), + months : function (m) { + return this._months[m.month()]; + }, + + _monthsShort : "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"), + monthsShort : function (m) { + return this._monthsShort[m.month()]; + }, + + monthsParse : function (monthName) { + var i, mom, regex, output; + + if (!this._monthsParse) { + this._monthsParse = []; + } + + for (i = 0; i < 12; i++) { + // make the regex if we don't have it already + if (!this._monthsParse[i]) { + mom = moment([2000, i]); + regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); + this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (this._monthsParse[i].test(monthName)) { + return i; + } + } + }, + + _weekdays : "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), + weekdays : function (m) { + return this._weekdays[m.day()]; + }, + + _weekdaysShort : "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"), + weekdaysShort : function (m) { + return this._weekdaysShort[m.day()]; + }, + + _weekdaysMin : "Su_Mo_Tu_We_Th_Fr_Sa".split("_"), + weekdaysMin : function (m) { + return this._weekdaysMin[m.day()]; + }, + + _longDateFormat : { + LT : "h:mm A", + L : "MM/DD/YYYY", + LL : "MMMM D YYYY", + LLL : "MMMM D YYYY LT", + LLLL : "dddd, MMMM D YYYY LT" + }, + longDateFormat : function (key) { + var output = this._longDateFormat[key]; + if (!output && this._longDateFormat[key.toUpperCase()]) { + output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) { + return val.slice(1); + }); + this._longDateFormat[key] = output; + } + return output; + }, + + meridiem : function (hours, minutes, isLower) { + if (hours > 11) { + return isLower ? 'pm' : 'PM'; + } else { + return isLower ? 'am' : 'AM'; + } + }, + + _calendar : { + sameDay : '[Today at] LT', + nextDay : '[Tomorrow at] LT', + nextWeek : 'dddd [at] LT', + lastDay : '[Yesterday at] LT', + lastWeek : '[last] dddd [at] LT', + sameElse : 'L' + }, + calendar : function (key, mom) { + var output = this._calendar[key]; + return typeof output === 'function' ? output.apply(mom) : output; + }, + + _relativeTime : { + future : "in %s", + past : "%s ago", + s : "a few seconds", + m : "a minute", + mm : "%d minutes", + h : "an hour", + hh : "%d hours", + d : "a day", + dd : "%d days", + M : "a month", + MM : "%d months", + y : "a year", + yy : "%d years" + }, + relativeTime : function (number, withoutSuffix, string, isFuture) { + var output = this._relativeTime[string]; + return (typeof output === 'function') ? + output(number, withoutSuffix, string, isFuture) : + output.replace(/%d/i, number); + }, + pastFuture : function (diff, output) { + var format = this._relativeTime[diff > 0 ? 'future' : 'past']; + return typeof format === 'function' ? format(output) : format.replace(/%s/i, output); + }, + + ordinal : function (number) { + return this._ordinal.replace("%d", number); + }, + _ordinal : "%d", + + preparse : function (string) { + return string; + }, + + postformat : function (string) { + return string; + }, + + week : function (mom) { + return weekOfYear(mom, this._week.dow, this._week.doy); + }, + _week : { + dow : 0, // Sunday is the first day of the week. + doy : 6 // The week that contains Jan 1st is the first week of the year. + } + }; + + // Loads a language definition into the `languages` cache. The function + // takes a key and optionally values. If not in the browser and no values + // are provided, it will load the language file module. As a convenience, + // this function also returns the language values. + function loadLang(key, values) { + values.abbr = key; + if (!languages[key]) { + languages[key] = new Language(); + } + languages[key].set(values); + return languages[key]; + } + + // Determines which language definition to use and returns it. + // + // With no parameters, it will return the global language. If you + // pass in a language key, such as 'en', it will return the + // definition for 'en', so long as 'en' has already been loaded using + // moment.lang. + function getLangDefinition(key) { + if (!key) { + return moment.fn._lang; + } + if (!languages[key] && hasModule) { + require('./lang/' + key); + } + return languages[key]; + } + + + /************************************ + Formatting + ************************************/ + + + function removeFormattingTokens(input) { + if (input.match(/\[.*\]/)) { + return input.replace(/^\[|\]$/g, ""); + } + return input.replace(/\\/g, ""); + } + + function makeFormatFunction(format) { + var array = format.match(formattingTokens), i, length; + + for (i = 0, length = array.length; i < length; i++) { + if (formatTokenFunctions[array[i]]) { + array[i] = formatTokenFunctions[array[i]]; + } else { + array[i] = removeFormattingTokens(array[i]); + } + } + + return function (mom) { + var output = ""; + for (i = 0; i < length; i++) { + output += typeof array[i].call === 'function' ? array[i].call(mom, format) : array[i]; + } + return output; + }; + } + + // format date using native date object + function formatMoment(m, format) { + var i = 5; + + function replaceLongDateFormatTokens(input) { + return m.lang().longDateFormat(input) || input; + } + + while (i-- && localFormattingTokens.test(format)) { + format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); + } + + if (!formatFunctions[format]) { + formatFunctions[format] = makeFormatFunction(format); + } + + return formatFunctions[format](m); + } + + + /************************************ + Parsing + ************************************/ + + + // get the regex to find the next token + function getParseRegexForToken(token) { + switch (token) { + case 'DDDD': + return parseTokenThreeDigits; + case 'YYYY': + return parseTokenFourDigits; + case 'YYYYY': + return parseTokenSixDigits; + case 'S': + case 'SS': + case 'SSS': + case 'DDD': + return parseTokenOneToThreeDigits; + case 'MMM': + case 'MMMM': + case 'dd': + case 'ddd': + case 'dddd': + case 'a': + case 'A': + return parseTokenWord; + case 'X': + return parseTokenTimestampMs; + case 'Z': + case 'ZZ': + return parseTokenTimezone; + case 'T': + return parseTokenT; + case 'MM': + case 'DD': + case 'YY': + case 'HH': + case 'hh': + case 'mm': + case 'ss': + case 'M': + case 'D': + case 'd': + case 'H': + case 'h': + case 'm': + case 's': + return parseTokenOneOrTwoDigits; + default : + return new RegExp(token.replace('\\', '')); + } + } + + // function to convert string input to date + function addTimeToArrayFromToken(token, input, config) { + var a, b, + datePartArray = config._a; + + switch (token) { + // MONTH + case 'M' : // fall through to MM + case 'MM' : + datePartArray[1] = (input == null) ? 0 : ~~input - 1; + break; + case 'MMM' : // fall through to MMMM + case 'MMMM' : + a = getLangDefinition(config._l).monthsParse(input); + // if we didn't find a month name, mark the date as invalid. + if (a != null) { + datePartArray[1] = a; + } else { + config._isValid = false; + } + break; + // DAY OF MONTH + case 'D' : // fall through to DDDD + case 'DD' : // fall through to DDDD + case 'DDD' : // fall through to DDDD + case 'DDDD' : + if (input != null) { + datePartArray[2] = ~~input; + } + break; + // YEAR + case 'YY' : + datePartArray[0] = ~~input + (~~input > 68 ? 1900 : 2000); + break; + case 'YYYY' : + case 'YYYYY' : + datePartArray[0] = ~~input; + break; + // AM / PM + case 'a' : // fall through to A + case 'A' : + config._isPm = ((input + '').toLowerCase() === 'pm'); + break; + // 24 HOUR + case 'H' : // fall through to hh + case 'HH' : // fall through to hh + case 'h' : // fall through to hh + case 'hh' : + datePartArray[3] = ~~input; + break; + // MINUTE + case 'm' : // fall through to mm + case 'mm' : + datePartArray[4] = ~~input; + break; + // SECOND + case 's' : // fall through to ss + case 'ss' : + datePartArray[5] = ~~input; + break; + // MILLISECOND + case 'S' : + case 'SS' : + case 'SSS' : + datePartArray[6] = ~~ (('0.' + input) * 1000); + break; + // UNIX TIMESTAMP WITH MS + case 'X': + config._d = new Date(parseFloat(input) * 1000); + break; + // TIMEZONE + case 'Z' : // fall through to ZZ + case 'ZZ' : + config._useUTC = true; + a = (input + '').match(parseTimezoneChunker); + if (a && a[1]) { + config._tzh = ~~a[1]; + } + if (a && a[2]) { + config._tzm = ~~a[2]; + } + // reverse offsets + if (a && a[0] === '+') { + config._tzh = -config._tzh; + config._tzm = -config._tzm; + } + break; + } + + // if the input is null, the date is not valid + if (input == null) { + config._isValid = false; + } + } + + // convert an array to a date. + // the array should mirror the parameters below + // note: all values past the year are optional and will default to the lowest possible value. + // [year, month, day , hour, minute, second, millisecond] + function dateFromArray(config) { + var i, date, input = []; + + if (config._d) { + return; + } + + for (i = 0; i < 7; i++) { + config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; + } + + // add the offsets to the time to be parsed so that we can have a clean array for checking isValid + input[3] += config._tzh || 0; + input[4] += config._tzm || 0; + + date = new Date(0); + + if (config._useUTC) { + date.setUTCFullYear(input[0], input[1], input[2]); + date.setUTCHours(input[3], input[4], input[5], input[6]); + } else { + date.setFullYear(input[0], input[1], input[2]); + date.setHours(input[3], input[4], input[5], input[6]); + } + + config._d = date; + } + + // date from string and format string + function makeDateFromStringAndFormat(config) { + // This array is used to make a Date, either with `new Date` or `Date.UTC` + var tokens = config._f.match(formattingTokens), + string = config._i, + i, parsedInput; + + config._a = []; + + for (i = 0; i < tokens.length; i++) { + parsedInput = (getParseRegexForToken(tokens[i]).exec(string) || [])[0]; + if (parsedInput) { + string = string.slice(string.indexOf(parsedInput) + parsedInput.length); + } + // don't parse if its not a known token + if (formatTokenFunctions[tokens[i]]) { + addTimeToArrayFromToken(tokens[i], parsedInput, config); + } + } + // handle am pm + if (config._isPm && config._a[3] < 12) { + config._a[3] += 12; + } + // if is 12 am, change hours to 0 + if (config._isPm === false && config._a[3] === 12) { + config._a[3] = 0; + } + // return + dateFromArray(config); + } + + // date from string and array of format strings + function makeDateFromStringAndArray(config) { + var tempConfig, + tempMoment, + bestMoment, + + scoreToBeat = 99, + i, + currentDate, + currentScore; + + while (config._f.length) { + tempConfig = extend({}, config); + tempConfig._f = config._f.pop(); + makeDateFromStringAndFormat(tempConfig); + tempMoment = new Moment(tempConfig); + + if (tempMoment.isValid()) { + bestMoment = tempMoment; + break; + } + + currentScore = compareArrays(tempConfig._a, tempMoment.toArray()); + + if (currentScore < scoreToBeat) { + scoreToBeat = currentScore; + bestMoment = tempMoment; + } + } + + extend(config, bestMoment); + } + + // date from iso format + function makeDateFromString(config) { + var i, + string = config._i; + if (isoRegex.exec(string)) { + config._f = 'YYYY-MM-DDT'; + for (i = 0; i < 4; i++) { + if (isoTimes[i][1].exec(string)) { + config._f += isoTimes[i][0]; + break; + } + } + if (parseTokenTimezone.exec(string)) { + config._f += " Z"; + } + makeDateFromStringAndFormat(config); + } else { + config._d = new Date(string); + } + } + + function makeDateFromInput(config) { + var input = config._i, + matched = aspNetJsonRegex.exec(input); + + if (input === undefined) { + config._d = new Date(); + } else if (matched) { + config._d = new Date(+matched[1]); + } else if (typeof input === 'string') { + makeDateFromString(config); + } else if (isArray(input)) { + config._a = input.slice(0); + dateFromArray(config); + } else { + config._d = input instanceof Date ? new Date(+input) : new Date(input); + } + } + + + /************************************ + Relative Time + ************************************/ + + + // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize + function substituteTimeAgo(string, number, withoutSuffix, isFuture, lang) { + return lang.relativeTime(number || 1, !!withoutSuffix, string, isFuture); + } + + function relativeTime(milliseconds, withoutSuffix, lang) { + var seconds = round(Math.abs(milliseconds) / 1000), + minutes = round(seconds / 60), + hours = round(minutes / 60), + days = round(hours / 24), + years = round(days / 365), + args = seconds < 45 && ['s', seconds] || + minutes === 1 && ['m'] || + minutes < 45 && ['mm', minutes] || + hours === 1 && ['h'] || + hours < 22 && ['hh', hours] || + days === 1 && ['d'] || + days <= 25 && ['dd', days] || + days <= 45 && ['M'] || + days < 345 && ['MM', round(days / 30)] || + years === 1 && ['y'] || ['yy', years]; + args[2] = withoutSuffix; + args[3] = milliseconds > 0; + args[4] = lang; + return substituteTimeAgo.apply({}, args); + } + + + /************************************ + Week of Year + ************************************/ + + + // firstDayOfWeek 0 = sun, 6 = sat + // the day of the week that starts the week + // (usually sunday or monday) + // firstDayOfWeekOfYear 0 = sun, 6 = sat + // the first week is the week that contains the first + // of this day of the week + // (eg. ISO weeks use thursday (4)) + function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { + var end = firstDayOfWeekOfYear - firstDayOfWeek, + daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(); + + + if (daysToDayOfWeek > end) { + daysToDayOfWeek -= 7; + } + + if (daysToDayOfWeek < end - 7) { + daysToDayOfWeek += 7; + } + + return Math.ceil(moment(mom).add('d', daysToDayOfWeek).dayOfYear() / 7); + } + + + /************************************ + Top Level Functions + ************************************/ + + function makeMoment(config) { + var input = config._i, + format = config._f; + + if (input === null || input === '') { + return null; + } + + if (typeof input === 'string') { + config._i = input = getLangDefinition().preparse(input); + } + + if (moment.isMoment(input)) { + config = extend({}, input); + config._d = new Date(+input._d); + } else if (format) { + if (isArray(format)) { + makeDateFromStringAndArray(config); + } else { + makeDateFromStringAndFormat(config); + } + } else { + makeDateFromInput(config); + } + + return new Moment(config); + } + + moment = function (input, format, lang) { + return makeMoment({ + _i : input, + _f : format, + _l : lang, + _isUTC : false + }); + }; + + // creating with utc + moment.utc = function (input, format, lang) { + return makeMoment({ + _useUTC : true, + _isUTC : true, + _l : lang, + _i : input, + _f : format + }); + }; + + // creating with unix timestamp (in seconds) + moment.unix = function (input) { + return moment(input * 1000); + }; + + // duration + moment.duration = function (input, key) { + var isDuration = moment.isDuration(input), + isNumber = (typeof input === 'number'), + duration = (isDuration ? input._data : (isNumber ? {} : input)), + ret; + + if (isNumber) { + if (key) { + duration[key] = input; + } else { + duration.milliseconds = input; + } + } + + ret = new Duration(duration); + + if (isDuration && input.hasOwnProperty('_lang')) { + ret._lang = input._lang; + } + + return ret; + }; + + // version number + moment.version = VERSION; + + // default format + moment.defaultFormat = isoFormat; + + // This function will load languages and then set the global language. If + // no arguments are passed in, it will simply return the current global + // language key. + moment.lang = function (key, values) { + var i; + + if (!key) { + return moment.fn._lang._abbr; + } + if (values) { + loadLang(key, values); + } else if (!languages[key]) { + getLangDefinition(key); + } + moment.duration.fn._lang = moment.fn._lang = getLangDefinition(key); + }; + + // returns language data + moment.langData = function (key) { + if (key && key._lang && key._lang._abbr) { + key = key._lang._abbr; + } + return getLangDefinition(key); + }; + + // compare moment object + moment.isMoment = function (obj) { + return obj instanceof Moment; + }; + + // for typechecking Duration objects + moment.isDuration = function (obj) { + return obj instanceof Duration; + }; + + + /************************************ + Moment Prototype + ************************************/ + + + moment.fn = Moment.prototype = { + + clone : function () { + return moment(this); + }, + + valueOf : function () { + return +this._d; + }, + + unix : function () { + return Math.floor(+this._d / 1000); + }, + + toString : function () { + return this.format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ"); + }, + + toDate : function () { + return this._d; + }, + + toJSON : function () { + return moment.utc(this).format('YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); + }, + + toArray : function () { + var m = this; + return [ + m.year(), + m.month(), + m.date(), + m.hours(), + m.minutes(), + m.seconds(), + m.milliseconds() + ]; + }, + + isValid : function () { + if (this._isValid == null) { + if (this._a) { + this._isValid = !compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()); + } else { + this._isValid = !isNaN(this._d.getTime()); + } + } + return !!this._isValid; + }, + + utc : function () { + this._isUTC = true; + return this; + }, + + local : function () { + this._isUTC = false; + return this; + }, + + format : function (inputString) { + var output = formatMoment(this, inputString || moment.defaultFormat); + return this.lang().postformat(output); + }, + + add : function (input, val) { + var dur; + // switch args to support add('s', 1) and add(1, 's') + if (typeof input === 'string') { + dur = moment.duration(+val, input); + } else { + dur = moment.duration(input, val); + } + addOrSubtractDurationFromMoment(this, dur, 1); + return this; + }, + + subtract : function (input, val) { + var dur; + // switch args to support subtract('s', 1) and subtract(1, 's') + if (typeof input === 'string') { + dur = moment.duration(+val, input); + } else { + dur = moment.duration(input, val); + } + addOrSubtractDurationFromMoment(this, dur, -1); + return this; + }, + + diff : function (input, units, asFloat) { + var that = this._isUTC ? moment(input).utc() : moment(input).local(), + zoneDiff = (this.zone() - that.zone()) * 6e4, + diff, output; + + if (units) { + // standardize on singular form + units = units.replace(/s$/, ''); + } + + if (units === 'year' || units === 'month') { + diff = (this.daysInMonth() + that.daysInMonth()) * 432e5; // 24 * 60 * 60 * 1000 / 2 + output = ((this.year() - that.year()) * 12) + (this.month() - that.month()); + output += ((this - moment(this).startOf('month')) - (that - moment(that).startOf('month'))) / diff; + if (units === 'year') { + output = output / 12; + } + } else { + diff = (this - that) - zoneDiff; + output = units === 'second' ? diff / 1e3 : // 1000 + units === 'minute' ? diff / 6e4 : // 1000 * 60 + units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60 + units === 'day' ? diff / 864e5 : // 1000 * 60 * 60 * 24 + units === 'week' ? diff / 6048e5 : // 1000 * 60 * 60 * 24 * 7 + diff; + } + return asFloat ? output : absRound(output); + }, + + from : function (time, withoutSuffix) { + return moment.duration(this.diff(time)).lang(this.lang()._abbr).humanize(!withoutSuffix); + }, + + fromNow : function (withoutSuffix) { + return this.from(moment(), withoutSuffix); + }, + + calendar : function () { + var diff = this.diff(moment().startOf('day'), 'days', true), + format = diff < -6 ? 'sameElse' : + diff < -1 ? 'lastWeek' : + diff < 0 ? 'lastDay' : + diff < 1 ? 'sameDay' : + diff < 2 ? 'nextDay' : + diff < 7 ? 'nextWeek' : 'sameElse'; + return this.format(this.lang().calendar(format, this)); + }, + + isLeapYear : function () { + var year = this.year(); + return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; + }, + + isDST : function () { + return (this.zone() < moment([this.year()]).zone() || + this.zone() < moment([this.year(), 5]).zone()); + }, + + day : function (input) { + var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); + return input == null ? day : + this.add({ d : input - day }); + }, + + startOf: function (units) { + units = units.replace(/s$/, ''); + // the following switch intentionally omits break keywords + // to utilize falling through the cases. + switch (units) { + case 'year': + this.month(0); + /* falls through */ + case 'month': + this.date(1); + /* falls through */ + case 'week': + case 'day': + this.hours(0); + /* falls through */ + case 'hour': + this.minutes(0); + /* falls through */ + case 'minute': + this.seconds(0); + /* falls through */ + case 'second': + this.milliseconds(0); + /* falls through */ + } + + // weeks are a special case + if (units === 'week') { + this.day(0); + } + + return this; + }, + + endOf: function (units) { + return this.startOf(units).add(units.replace(/s?$/, 's'), 1).subtract('ms', 1); + }, + + isAfter: function (input, units) { + units = typeof units !== 'undefined' ? units : 'millisecond'; + return +this.clone().startOf(units) > +moment(input).startOf(units); + }, + + isBefore: function (input, units) { + units = typeof units !== 'undefined' ? units : 'millisecond'; + return +this.clone().startOf(units) < +moment(input).startOf(units); + }, + + isSame: function (input, units) { + units = typeof units !== 'undefined' ? units : 'millisecond'; + return +this.clone().startOf(units) === +moment(input).startOf(units); + }, + + zone : function () { + return this._isUTC ? 0 : this._d.getTimezoneOffset(); + }, + + daysInMonth : function () { + return moment.utc([this.year(), this.month() + 1, 0]).date(); + }, + + dayOfYear : function (input) { + var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1; + return input == null ? dayOfYear : this.add("d", (input - dayOfYear)); + }, + + isoWeek : function (input) { + var week = weekOfYear(this, 1, 4); + return input == null ? week : this.add("d", (input - week) * 7); + }, + + week : function (input) { + var week = this.lang().week(this); + return input == null ? week : this.add("d", (input - week) * 7); + }, + + // If passed a language key, it will set the language for this + // instance. Otherwise, it will return the language configuration + // variables for this instance. + lang : function (key) { + if (key === undefined) { + return this._lang; + } else { + this._lang = getLangDefinition(key); + return this; + } + } + }; + + // helper for adding shortcuts + function makeGetterAndSetter(name, key) { + moment.fn[name] = moment.fn[name + 's'] = function (input) { + var utc = this._isUTC ? 'UTC' : ''; + if (input != null) { + this._d['set' + utc + key](input); + return this; + } else { + return this._d['get' + utc + key](); + } + }; + } + + // loop through and add shortcuts (Month, Date, Hours, Minutes, Seconds, Milliseconds) + for (i = 0; i < proxyGettersAndSetters.length; i ++) { + makeGetterAndSetter(proxyGettersAndSetters[i].toLowerCase().replace(/s$/, ''), proxyGettersAndSetters[i]); + } + + // add shortcut for year (uses different syntax than the getter/setter 'year' == 'FullYear') + makeGetterAndSetter('year', 'FullYear'); + + // add plural methods + moment.fn.days = moment.fn.day; + moment.fn.weeks = moment.fn.week; + moment.fn.isoWeeks = moment.fn.isoWeek; + + /************************************ + Duration Prototype + ************************************/ + + + moment.duration.fn = Duration.prototype = { + weeks : function () { + return absRound(this.days() / 7); + }, + + valueOf : function () { + return this._milliseconds + + this._days * 864e5 + + this._months * 2592e6; + }, + + humanize : function (withSuffix) { + var difference = +this, + output = relativeTime(difference, !withSuffix, this.lang()); + + if (withSuffix) { + output = this.lang().pastFuture(difference, output); + } + + return this.lang().postformat(output); + }, + + lang : moment.fn.lang + }; + + function makeDurationGetter(name) { + moment.duration.fn[name] = function () { + return this._data[name]; + }; + } + + function makeDurationAsGetter(name, factor) { + moment.duration.fn['as' + name] = function () { + return +this / factor; + }; + } + + for (i in unitMillisecondFactors) { + if (unitMillisecondFactors.hasOwnProperty(i)) { + makeDurationAsGetter(i, unitMillisecondFactors[i]); + makeDurationGetter(i.toLowerCase()); + } + } + + makeDurationAsGetter('Weeks', 6048e5); + + + /************************************ + Default Lang + ************************************/ + + + // Set default language, other languages will inherit from English. + moment.lang('en', { + ordinal : function (number) { + var b = number % 10, + output = (~~ (number % 100 / 10) === 1) ? 'th' : + (b === 1) ? 'st' : + (b === 2) ? 'nd' : + (b === 3) ? 'rd' : 'th'; + return number + output; + } + }); + + + /************************************ + Exposing Moment + ************************************/ + + + // CommonJS module is defined + if (hasModule) { + module.exports = moment; + } + /*global ender:false */ + if (typeof ender === 'undefined') { + // here, `this` means `window` in the browser, or `global` on the server + // add `moment` as a global object via a string identifier, + // for Closure Compiler "advanced" mode + this['moment'] = moment; + } + /*global define:false */ + if (typeof define === "function" && define.amd) { + define("moment", [], function () { + return moment; + }); + } +}).call(this); + +})() +},{}]},{},[1])(1) +}); +; \ No newline at end of file diff --git a/vis.min.js b/vis.min.js new file mode 100644 index 00000000..6ee20a95 --- /dev/null +++ b/vis.min.js @@ -0,0 +1,29 @@ +/** + * vis.js + * https://github.com/almende/vis + * + * A dynamic, browser-based visualization library. + * + * @version 0.0.9 + * @date 2013-06-07 + * + * @license + * Copyright (C) 2011-2013 Almende B.V, http://almende.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +(function(t){if("function"==typeof bootstrap)bootstrap("vis",t);else if("object"==typeof exports)module.exports=t();else if("function"==typeof define&&define.amd)define(t);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeVis=t}else"undefined"!=typeof window?window.vis=t():global.vis=t()})(function(){var t;return function(t,e,i){function s(i,n){if(!e[i]){if(!t[i]){var r="function"==typeof require&&require;if(!n&&r)return r(i,!0);if(o)return o(i,!0);throw Error("Cannot find module '"+i+"'")}var a=e[i]={exports:{}};t[i][0].call(a.exports,function(e){var o=t[i][1][e];return s(o?o:e)},a,a.exports)}return e[i].exports}for(var o="function"==typeof require&&require,n=0;i.length>n;n++)s(i[n]);return s}({1:[function(e,i,s){(function(){function o(){this.subscriptions=[]}function n(t){if(this.id=C.randomUUID(),this.options=t||{},this.data={},this.fieldId=this.options.fieldId||"id",this.fieldTypes={},this.options.fieldTypes)for(var e in this.options.fieldTypes)if(this.options.fieldTypes.hasOwnProperty(e)){var i=this.options.fieldTypes[e];this.fieldTypes[e]="Date"==i||"ISODate"==i||"ASPDate"==i?"Date":i}this.subscribers={},this.internalIds={}}function r(t,e){this.id=C.randomUUID(),this.data=null,this.ids={},this.options=e||{},this.fieldId="id",this.subscribers={};var i=this;this.listener=function(){i._onEvent.apply(i,arguments)},this.setData(t)}function a(t,e){this.parent=t,this.options=e||{},this.defaultOptions={order:function(t,e){if(t instanceof y){if(e instanceof y){var i=t.data.end-t.data.start,s=e.data.end-e.data.start;return i-s||t.data.start-e.data.start}return-1}return e instanceof y?1:t.data.start-e.data.start},margin:{item:10}},this.ordered=[]}function h(t){this.id=C.randomUUID(),this.start=0,this.end=0,this.options={min:null,max:null,zoomMin:null,zoomMax:null},this.listeners=[],this.setOptions(t)}function d(){this.id=C.randomUUID(),this.components={},this.repaintTimer=void 0,this.reflowTimer=void 0}function l(){this.id=null,this.parent=null,this.depends=null,this.controller=null,this.options=null,this.frame=null,this.top=0,this.left=0,this.width=0,this.height=0}function p(t,e,i){this.id=C.randomUUID(),this.parent=t,this.depends=e,this.options=i||{}}function u(t,e){this.id=C.randomUUID(),this.container=t,this.options=e||{},this.defaultOptions={autoResize:!0},this.listeners={}}function c(t,e,i){this.id=C.randomUUID(),this.parent=t,this.depends=e,this.dom={majorLines:[],majorTexts:[],minorLines:[],minorTexts:[],redundant:{majorLines:[],majorTexts:[],minorLines:[],minorTexts:[]}},this.props={range:{start:0,end:0,minimumStep:0},lineTop:0},this.options=i||{},this.defaultOptions={orientation:"bottom",showMinorLabels:!0,showMajorLabels:!0},this.conversion=null,this.range=null}function f(t,e,i){this.id=C.randomUUID(),this.parent=t,this.depends=e,this.options=i||{},this.defaultOptions={type:"box",align:"center",orientation:"bottom",margin:{axis:20,item:10},padding:5},this.dom={};var s=this;this.itemsData=null,this.range=null,this.listeners={add:function(t,e,i){i!=s.id&&s._onAdd(e.items)},update:function(t,e,i){i!=s.id&&s._onUpdate(e.items)},remove:function(t,e,i){i!=s.id&&s._onRemove(e.items)}},this.items={},this.queue={},this.stack=new a(this,Object.create(this.options)),this.conversion=null}function m(t,e,i,s){this.parent=t,this.data=e,this.dom=null,this.options=i||{},this.defaultOptions=s||{},this.selected=!1,this.visible=!1,this.top=0,this.left=0,this.width=0,this.height=0}function g(t,e,i,s){this.props={dot:{left:0,top:0,width:0,height:0},line:{top:0,left:0,width:0,height:0}},m.call(this,t,e,i,s)}function v(t,e,i,s){this.props={dot:{top:0,width:0,height:0},content:{height:0,marginLeft:0}},m.call(this,t,e,i,s)}function y(t,e,i,s){this.props={content:{left:0,width:0}},m.call(this,t,e,i,s)}function w(t,e,i){this.id=C.randomUUID(),this.parent=t,this.groupId=e,this.itemsData=null,this.itemset=null,this.options=i||{},this.options.top=0,this.top=0,this.left=0,this.width=0,this.height=0}function b(t,e,i){this.id=C.randomUUID(),this.parent=t,this.depends=e,this.options=i||{},this.range=null,this.itemsData=null,this.groupsData=null,this.groups={},this.queue={};var s=this;this.listeners={add:function(t,e){s._onAdd(e.items)},update:function(t,e){s._onUpdate(e.items)},remove:function(t,e){s._onRemove(e.items)}}}function _(t,e,i){var s=this;if(this.options=C.extend({orientation:"bottom",min:null,max:null,zoomMin:10,zoomMax:31536e10,showMinorLabels:!0,showMajorLabels:!0,autoResize:!1},i),this.controller=new d,!t)throw Error("No container element provided");var o=Object.create(this.options);o.height=function(){return s.options.height?s.options.height:s.timeaxis.height+s.content.height},this.root=new u(t,o),this.controller.add(this.root);var n=E().hours(0).minutes(0).seconds(0).milliseconds(0);this.range=new h({start:n.clone().add("days",-3).valueOf(),end:n.clone().add("days",4).valueOf()}),this.range.subscribe(this.root,"move","horizontal"),this.range.subscribe(this.root,"zoom","horizontal"),this.range.on("rangechange",function(){var t=!0;s.controller.requestReflow(t)}),this.range.on("rangechanged",function(){var t=!0;s.controller.requestReflow(t)});var r=Object.create(o);r.range=this.range,this.timeaxis=new c(this.root,[],r),this.timeaxis.setRange(this.range),this.controller.add(this.timeaxis),this.setGroups(null),this.itemsData=null,this.groupsData=null,e&&this.setItems(e)}function x(t,e,i,s){this.selected=!1,this.edges=[],this.group=s.nodes.group,this.fontSize=s.nodes.fontSize,this.fontFace=s.nodes.fontFace,this.fontColor=s.nodes.fontColor,this.color=s.nodes.color,this.id=void 0,this.shape=s.nodes.shape,this.image=s.nodes.image,this.x=0,this.y=0,this.xFixed=!1,this.yFixed=!1,this.radius=s.nodes.radius,this.radiusFixed=!1,this.radiusMin=s.nodes.radiusMin,this.radiusMax=s.nodes.radiusMax,this.imagelist=e,this.grouplist=i,this.setProperties(t,s),this.mass=50,this.fx=0,this.fy=0,this.vx=0,this.vy=0,this.minForce=s.minForce,this.damping=.9}function T(t,e,i){if(!e)throw"No graph provided";this.graph=e,this.widthMin=i.edges.widthMin,this.widthMax=i.edges.widthMax,this.id=void 0,this.style=i.edges.style,this.title=void 0,this.width=i.edges.width,this.value=void 0,this.length=i.edges.length,this.dash=C.extend({},i.edges.dash),this.stiffness=void 0,this.color=i.edges.color,this.widthFixed=!1,this.lengthFixed=!1,this.setProperties(t,i)}function M(t,e,i,s){this.container=t?t:document.body,this.x=0,this.y=0,this.padding=5,void 0!==e&&void 0!==i&&this.setPosition(e,i),void 0!==s&&this.setText(s),this.frame=document.createElement("div");var o=this.frame.style;o.position="absolute",o.visibility="hidden",o.border="1px solid #666",o.color="black",o.padding=this.padding+"px",o.backgroundColor="#FFFFC6",o.borderRadius="3px",o.MozBorderRadius="3px",o.WebkitBorderRadius="3px",o.boxShadow="3px 3px 10px rgba(128, 128, 128, 0.5)",o.whiteSpace="nowrap",this.container.appendChild(this.frame)}function S(t,e,i){this.containerElement=t,this.width="100%",this.height="100%",this.refreshRate=50,this.stabilize=!0,this.selectable=!0,this.constants={nodes:{radiusMin:5,radiusMax:20,radius:5,distance:100,shape:"ellipse",image:void 0,widthMin:16,widthMax:64,fontColor:"black",fontSize:14,fontFace:"arial",color:{border:"#2B7CE9",background:"#97C2FC",highlight:{border:"#2B7CE9",background:"#D2E5FF"}},borderColor:"#2B7CE9",backgroundColor:"#97C2FC",highlightColor:"#D2E5FF",group:void 0},edges:{widthMin:1,widthMax:15,width:1,style:"line",color:"#343434",fontColor:"#343434",fontSize:14,fontFace:"arial",length:100,dash:{length:10,gap:5,altLength:void 0}},minForce:.05,minVelocity:.02,maxIterations:1e3};var s=this;this.nodes=[],this.edges=[],this.groups=new Groups,this.images=new Images,this.images.setOnloadCallback(function(){s._redraw()}),this.moving=!1,this.selection=[],this.timer=void 0,this._create(),this.setOptions(i),this.setData(e)}var E=e("moment"),C={};C.isNumber=function(t){return t instanceof Number||"number"==typeof t},C.isString=function(t){return t instanceof String||"string"==typeof t},C.isDate=function(t){if(t instanceof Date)return!0;if(C.isString(t)){var e=D.exec(t);if(e)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},C.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},C.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},C.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var s=arguments[e];for(var o in s)s.hasOwnProperty(o)&&void 0!==s[o]&&(t[o]=s[o])}return t},C.cast=function(t,e){var i;if(void 0===t)return void 0;if(null===t)return null;if(!e)return t;if("string"!=typeof e&&!(e instanceof String))throw Error("Type must be a string");switch(e){case"boolean":case"Boolean":return Boolean(t);case"number":case"Number":return Number(t);case"string":case"String":return t+"";case"Date":if(C.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(E.isMoment(t))return new Date(t.valueOf());if(C.isString(t))return i=D.exec(t),i?new Date(Number(i[1])):E(t).toDate();throw Error("Cannot cast object of type "+C.getType(t)+" to type Date");case"Moment":if(C.isNumber(t))return E(t);if(t instanceof Date)return E(t.valueOf());if(E.isMoment(t))return E.clone();if(C.isString(t))return i=D.exec(t),i?E(Number(i[1])):E(t);throw Error("Cannot cast object of type "+C.getType(t)+" to type Date");case"ISODate":if(t instanceof Date)return t.toISOString();if(E.isMoment(t))return t.toDate().toISOString();if(C.isNumber(t)||C.isString(t))return E(t).toDate().toISOString();throw Error("Cannot cast object of type "+C.getType(t)+" to type ISODate");case"ASPDate":if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(C.isNumber(t)||C.isString(t))return"/Date("+E(t).valueOf()+")/";throw Error("Cannot cast object of type "+C.getType(t)+" to type ASPDate");default:throw Error("Cannot cast object of type "+C.getType(t)+' to type "'+e+'"')}};var D=/^\/?Date\((\-?\d+)/i;if(C.getType=function(t){var e=typeof t;return"object"==e?null==t?"null":t instanceof Boolean?"Boolean":t instanceof Number?"Number":t instanceof String?"String":t instanceof Array?"Array":t instanceof Date?"Date":"Object":"number"==e?"Number":"boolean"==e?"Boolean":"string"==e?"String":e},C.getAbsoluteLeft=function(t){for(var e=document.documentElement,i=document.body,s=t.offsetLeft,o=t.offsetParent;null!=o&&o!=i&&o!=e;)s+=o.offsetLeft,s-=o.scrollLeft,o=o.offsetParent;return s},C.getAbsoluteTop=function(t){for(var e=document.documentElement,i=document.body,s=t.offsetTop,o=t.offsetParent;null!=o&&o!=i&&o!=e;)s+=o.offsetTop,s-=o.scrollTop,o=o.offsetParent;return s},C.getPageY=function(t){if("pageY"in t)return t.pageY;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientY:t.clientY;var i=document.documentElement,s=document.body;return e+(i&&i.scrollTop||s&&s.scrollTop||0)-(i&&i.clientTop||s&&s.clientTop||0)},C.getPageX=function(t){if("pageY"in t)return t.pageX;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientX:t.clientX;var i=document.documentElement,s=document.body;return e+(i&&i.scrollLeft||s&&s.scrollLeft||0)-(i&&i.clientLeft||s&&s.clientLeft||0)},C.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},C.removeClassName=function(t,e){var i=t.className.split(" "),s=i.indexOf(e);-1!=s&&(i.splice(s,1),t.className=i.join(" "))},C.forEach=function(t,e){var i,s;if(t instanceof Array)for(i=0,s=t.length;s>i;i++)e(t[i],i,t);else for(i in t)t.hasOwnProperty(i)&&e(t[i],i,t)},C.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},C.addEventListener=function(t,e,i,s){t.addEventListener?(void 0===s&&(s=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.addEventListener(e,i,s)):t.attachEvent("on"+e,i)},C.removeEventListener=function(t,e,i,s){t.removeEventListener?(void 0===s&&(s=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.removeEventListener(e,i,s)):t.detachEvent("on"+e,i)},C.getTarget=function(t){t||(t=window.event);var e;return t.target?e=t.target:t.srcElement&&(e=t.srcElement),void 0!=e.nodeType&&3==e.nodeType&&(e=e.parentNode),e},C.stopPropagation=function(t){t||(t=window.event),t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},C.preventDefault=function(t){t||(t=window.event),t.preventDefault?t.preventDefault():t.returnValue=!1},C.option={},C.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},C.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},C.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?t+"":e||null},C.option.asSize=function(t,e){return"function"==typeof t&&(t=t()),C.isString(t)?t:C.isNumber(t)?t+"px":e||null},C.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null},C.loadCss=function(t){if("undefined"!=typeof document){var e=document.createElement("style");e.type="text/css",e.styleSheet?e.styleSheet.cssText=t:e.appendChild(document.createTextNode(t)),document.getElementsByTagName("head")[0].appendChild(e)}},!Array.prototype.indexOf){Array.prototype.indexOf=function(t){for(var e=0;this.length>e;e++)if(this[e]==t)return e;return-1};try{console.log("Warning: Ancient browser detected. Please update your browser")}catch(L){}}Array.prototype.forEach||(Array.prototype.forEach=function(t,e){for(var i=0,s=this.length;s>i;++i)t.call(e||this,this[i],i,this)}),Array.prototype.map||(Array.prototype.map=function(t,e){var i,s,o;if(null==this)throw new TypeError(" this is null or not defined");var n=Object(this),r=n.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(e&&(i=e),s=Array(r),o=0;r>o;){var a,h;o in n&&(a=n[o],h=t.call(i,a,o,n),s[o]=h),o++}return s}),Array.prototype.filter||(Array.prototype.filter=function(t){"use strict";if(null==this)throw new TypeError;var e=Object(this),i=e.length>>>0;if("function"!=typeof t)throw new TypeError;for(var s=[],o=arguments[1],n=0;i>n;n++)if(n in e){var r=e[n];t.call(o,r,n,e)&&s.push(r)}return s}),Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,e=!{toString:null}.propertyIsEnumerable("toString"),i=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],s=i.length;return function(o){if("object"!=typeof o&&"function"!=typeof o||null===o)throw new TypeError("Object.keys called on non-object");var n=[];for(var r in o)t.call(o,r)&&n.push(r);if(e)for(var a=0;s>a;a++)t.call(o,i[a])&&n.push(i[a]);return n}}()),Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,s=function(){},o=function(){return i.apply(this instanceof s&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return s.prototype=this.prototype,o.prototype=new s,o}),Object.create||(Object.create=function(t){function e(){}if(arguments.length>1)throw Error("Object.create implementation only accepts the first parameter.");return e.prototype=t,new e});var O={listeners:[],indexOf:function(t){for(var e=this.listeners,i=0,s=this.listeners.length;s>i;i++){var o=e[i];if(o&&o.object==t)return i}return-1},addListener:function(t,e,i){var s=this.indexOf(t),o=this.listeners[s];o||(o={object:t,events:{}},this.listeners.push(o));var n=o.events[e];n||(n=[],o.events[e]=n),-1==n.indexOf(i)&&n.push(i)},removeListener:function(t,e,i){var s=this.indexOf(t),o=this.listeners[s];if(o){var n=o.events[e];n&&(s=n.indexOf(i),-1!=s&&n.splice(s,1),0==n.length&&delete o.events[e]);var r=0,a=o.events;for(var h in a)a.hasOwnProperty(h)&&r++;0==r&&delete this.listeners[s]}},removeAllListeners:function(){this.listeners=[]},trigger:function(t,e,i){var s=this.indexOf(t),o=this.listeners[s];if(o){var n=o.events[e];if(n)for(var r=0,a=n.length;a>r;r++)n[r](i)}}};o.prototype.on=function(t,e,i){var s=t instanceof RegExp?t:RegExp(t.replace("*","\\w+")),o={id:C.randomUUID(),event:t,regexp:s,callback:"function"==typeof e?e:null,target:i};return this.subscriptions.push(o),o.id},o.prototype.off=function(t){for(var e=0;this.subscriptions.length>e;){var i=this.subscriptions[e],s=!0;if(t instanceof Object)for(var o in t)t.hasOwnProperty(o)&&t[o]!==i[o]&&(s=!1);else s=i.id==t;s?this.subscriptions.splice(e,1):e++}},o.prototype.emit=function(t,e,i){for(var s=0;this.subscriptions.length>s;s++){var o=this.subscriptions[s];o.regexp.test(t)&&o.callback&&o.callback(t,e,i)}},n.prototype.subscribe=function(t,e,i){var s=this.subscribers[t];s||(s=[],this.subscribers[t]=s),s.push({id:i?i+"":null,callback:e})},n.prototype.unsubscribe=function(t,e){var i=this.subscribers[t];i&&(this.subscribers[t]=i.filter(function(t){return t.callback!=e}))},n.prototype._trigger=function(t,e,i){if("*"==t)throw Error("Cannot trigger event *");var s=[];t in this.subscribers&&(s=s.concat(this.subscribers[t])),"*"in this.subscribers&&(s=s.concat(this.subscribers["*"]));for(var o=0;s.length>o;o++){var n=s[o];n.callback&&n.callback(t,e,i||null)}},n.prototype.add=function(t,e){var i,s=[],o=this;if(t instanceof Array)for(var n=0,r=t.length;r>n;n++)i=o._addItem(t[n]),s.push(i);else if(C.isDataTable(t))for(var a=this._getColumnNames(t),h=0,d=t.getNumberOfRows();d>h;h++){for(var l={},p=0,u=a.length;u>p;p++){var c=a[p];l[c]=t.getValue(h,p)}i=o._addItem(l),s.push(i)}else{if(!(t instanceof Object))throw Error("Unknown dataType");i=o._addItem(t),s.push(i)}s.length&&this._trigger("add",{items:s},e)},n.prototype.update=function(t,e){var i=[],s=[],o=this,n=o.fieldId,r=function(t){var e=t[n];o.data[e]?(e=o._updateItem(t),s.push(e)):(e=o._addItem(t),i.push(e))};if(t instanceof Array)for(var a=0,h=t.length;h>a;a++)r(t[a]);else if(C.isDataTable(t))for(var d=this._getColumnNames(t),l=0,p=t.getNumberOfRows();p>l;l++){for(var u={},c=0,f=d.length;f>c;c++){var m=d[c];u[m]=t.getValue(l,c)}r(u)}else{if(!(t instanceof Object))throw Error("Unknown dataType");r(t)}i.length&&this._trigger("add",{items:i},e),s.length&&this._trigger("update",{items:s},e)},n.prototype.get=function(){var t,e,i,s,o=this,n=C.getType(arguments[0]);"String"==n||"Number"==n?(t=arguments[0],i=arguments[1],s=arguments[2]):"Array"==n?(e=arguments[0],i=arguments[1],s=arguments[2]):(i=arguments[0],s=arguments[1]);var r;if(i&&i.type){if(r="DataTable"==i.type?"DataTable":"Array",s&&r!=C.getType(s))throw Error('Type of parameter "data" ('+C.getType(s)+") "+"does not correspond with specified options.type ("+i.type+")");if("DataTable"==r&&!C.isDataTable(s))throw Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else r=s?"DataTable"==C.getType(s)?"DataTable":"Array":"Array";var a,h,d,l,p=i&&i.fieldTypes||this.options.fieldTypes,u=i&&i.filter,c=[];if(void 0!=t)a=o._getItem(t,p),u&&!u(a)&&(a=null);else if(void 0!=e)for(d=0,l=e.length;l>d;d++)a=o._getItem(e[d],p),(!u||u(a))&&c.push(a);else for(h in this.data)this.data.hasOwnProperty(h)&&(a=o._getItem(h,p),(!u||u(a))&&c.push(a));if(i&&i.order&&void 0==t&&this._sort(c,i.order),i&&i.fields){var f=i.fields;if(void 0!=t)a=this._filterFields(a,f);else for(d=0,l=c.length;l>d;d++)c[d]=this._filterFields(c[d],f)}if("DataTable"==r){var m=this._getColumnNames(s);if(void 0!=t)o._appendRow(s,m,a);else for(d=0,l=c.length;l>d;d++)o._appendRow(s,m,c[d]);return s}if(void 0!=t)return a;if(s){for(d=0,l=c.length;l>d;d++)s.push(c[d]);return s}return c},n.prototype.getIds=function(t){var e,i,s,o,n,r=this.data,a=t&&t.filter,h=t&&t.order,d=t&&t.fieldTypes||this.options.fieldTypes,l=[];if(a)if(h){n=[];for(s in r)r.hasOwnProperty(s)&&(o=this._getItem(s,d),a(o)&&n.push(o));for(this._sort(n,h),e=0,i=n.length;i>e;e++)l[e]=n[e][this.fieldId]}else for(s in r)r.hasOwnProperty(s)&&(o=this._getItem(s,d),a(o)&&l.push(o[this.fieldId]));else if(h){n=[];for(s in r)r.hasOwnProperty(s)&&n.push(r[s]);for(this._sort(n,h),e=0,i=n.length;i>e;e++)l[e]=n[e][this.fieldId]}else for(s in r)r.hasOwnProperty(s)&&(o=r[s],l.push(o[this.fieldId]));return l},n.prototype.forEach=function(t,e){var i,s,o=e&&e.filter,n=e&&e.fieldTypes||this.options.fieldTypes,r=this.data;if(e&&e.order)for(var a=this.get(e),h=0,d=a.length;d>h;h++)i=a[h],s=i[this.fieldId],t(i,s);else for(s in r)r.hasOwnProperty(s)&&(i=this._getItem(s,n),(!o||o(i))&&t(i,s))},n.prototype.map=function(t,e){var i,s=e&&e.filter,o=e&&e.fieldTypes||this.options.fieldTypes,n=[],r=this.data;for(var a in r)r.hasOwnProperty(a)&&(i=this._getItem(a,o),(!s||s(i))&&n.push(t(i,a)));return e&&e.order&&this._sort(n,e.order),n},n.prototype._filterFields=function(t,e){var i={};for(var s in t)t.hasOwnProperty(s)&&-1!=e.indexOf(s)&&(i[s]=t[s]);return i},n.prototype._sort=function(t,e){if(C.isString(e)){var i=e;t.sort(function(t,e){var s=t[i],o=e[i];return s>o?1:o>s?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},n.prototype.remove=function(t,e){var i,s,o=[];if(C.isNumber(t)||C.isString(t))delete this.data[t],delete this.internalIds[t],o.push(t);else if(t instanceof Array){for(i=0,s=t.length;s>i;i++)this.remove(t[i]);o=items.concat(t)}else if(t instanceof Object)for(i in this.data)this.data.hasOwnProperty(i)&&this.data[i]==t&&(delete this.data[i],delete this.internalIds[i],o.push(i));o.length&&this._trigger("remove",{items:o},e)},n.prototype.clear=function(t){var e=Object.keys(this.data);this.data={},this.internalIds={},this._trigger("remove",{items:e},t)},n.prototype.max=function(t){var e=this.data,i=null,s=null;for(var o in e)if(e.hasOwnProperty(o)){var n=e[o],r=n[t];null!=r&&(!i||r>s)&&(i=n,s=r)}return i},n.prototype.min=function(t){var e=this.data,i=null,s=null;for(var o in e)if(e.hasOwnProperty(o)){var n=e[o],r=n[t];null!=r&&(!i||s>r)&&(i=n,s=r)}return i},n.prototype.distinct=function(t){var e=this.data,i=[],s=this.options.fieldTypes[t],o=0;for(var n in e)if(e.hasOwnProperty(n)){for(var r=e[n],a=C.cast(r[t],s),h=!1,d=0;o>d;d++)if(i[d]==a){h=!0;break}h||(i[o]=a,o++)}return i},n.prototype._addItem=function(t){var e=t[this.fieldId];if(void 0!=e){if(this.data[e])throw Error("Cannot add item: item with id "+e+" already exists")}else e=C.randomUUID(),t[this.fieldId]=e,this.internalIds[e]=t;var i={};for(var s in t)if(t.hasOwnProperty(s)){var o=this.fieldTypes[s];i[s]=C.cast(t[s],o)}return this.data[e]=i,e},n.prototype._getItem=function(t,e){var i,s,o=this.data[t];if(!o)return null;var n={},r=this.fieldId,a=this.internalIds;if(e)for(i in o)o.hasOwnProperty(i)&&(s=o[i],i==r&&s in a||(n[i]=C.cast(s,e[i])));else for(i in o)o.hasOwnProperty(i)&&(s=o[i],i==r&&s in a||(n[i]=s));return n},n.prototype._updateItem=function(t){var e=t[this.fieldId];if(void 0==e)throw Error("Cannot update item: item has no id (item: "+JSON.stringify(t)+")");var i=this.data[e];if(!i)throw Error("Cannot update item: no item with id "+e+" found");for(var s in t)if(t.hasOwnProperty(s)){var o=this.fieldTypes[s];i[s]=C.cast(t[s],o)}return e},n.prototype._getColumnNames=function(t){for(var e=[],i=0,s=t.getNumberOfColumns();s>i;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},n.prototype._appendRow=function(t,e,i){for(var s=t.addRow(),o=0,n=e.length;n>o;o++){var r=e[o];t.setValue(s,o,i[r])}},r.prototype.setData=function(t){var e,i,s;if(this.data){this.data.unsubscribe&&this.data.unsubscribe("*",this.listener),e=[];for(var o in this.ids)this.ids.hasOwnProperty(o)&&e.push(o);this.ids={},this._trigger("remove",{items:e})}if(this.data=t,this.data){for(this.fieldId=this.options.fieldId||this.data&&this.data.options&&this.data.options.fieldId||"id",e=this.data.getIds({filter:this.options&&this.options.filter}),i=0,s=e.length;s>i;i++)o=e[i],this.ids[o]=!0;this._trigger("add",{items:e}),this.data.subscribe&&this.data.subscribe("*",this.listener)}},r.prototype.get=function(){var t,e,i,s=this,o=C.getType(arguments[0]);"String"==o||"Number"==o||"Array"==o?(t=arguments[0],e=arguments[1],i=arguments[2]):(e=arguments[0],i=arguments[1]);var n=C.extend({},this.options,e);this.options.filter&&e&&e.filter&&(n.filter=function(t){return s.options.filter(t)&&e.filter(t)});var r=[];return void 0!=t&&r.push(t),r.push(n),r.push(i),this.data&&this.data.get.apply(this.data,r)},r.prototype.getIds=function(t){var e;if(this.data){var i,s=this.options.filter;i=t&&t.filter?s?function(e){return s(e)&&t.filter(e)}:t.filter:s,e=this.data.getIds({filter:i,order:t&&t.order})}else e=[];return e},r.prototype._onEvent=function(t,e,i){var s,o,n,r,a=e&&e.items,h=this.data,d=[],l=[],p=[];if(a&&h){switch(t){case"add":for(s=0,o=a.length;o>s;s++)n=a[s],r=this.get(n),r&&(this.ids[n]=!0,d.push(n));break;case"update":for(s=0,o=a.length;o>s;s++)n=a[s],r=this.get(n),r?this.ids[n]?l.push(n):(this.ids[n]=!0,d.push(n)):this.ids[n]&&(delete this.ids[n],p.push(n));break;case"remove":for(s=0,o=a.length;o>s;s++)n=a[s],this.ids[n]&&(delete this.ids[n],p.push(n))}d.length&&this._trigger("add",{items:d},i),l.length&&this._trigger("update",{items:l},i),p.length&&this._trigger("remove",{items:p},i)}},r.prototype.subscribe=n.prototype.subscribe,r.prototype.unsubscribe=n.prototype.unsubscribe,r.prototype._trigger=n.prototype._trigger,TimeStep=function(t,e,i){this.current=new Date,this._start=new Date,this._end=new Date,this.autoScale=!0,this.scale=TimeStep.SCALE.DAY,this.step=1,this.setRange(t,e,i)},TimeStep.SCALE={MILLISECOND:1,SECOND:2,MINUTE:3,HOUR:4,DAY:5,WEEKDAY:6,MONTH:7,YEAR:8},TimeStep.prototype.setRange=function(t,e,i){t instanceof Date&&e instanceof Date&&(this._start=void 0!=t?new Date(t.valueOf()):new Date,this._end=void 0!=e?new Date(e.valueOf()):new Date,this.autoScale&&this.setMinimumStep(i))},TimeStep.prototype.first=function(){this.current=new Date(this._start.valueOf()),this.roundToMinor()},TimeStep.prototype.roundToMinor=function(){switch(this.scale){case TimeStep.SCALE.YEAR:this.current.setFullYear(this.step*Math.floor(this.current.getFullYear()/this.step)),this.current.setMonth(0);case TimeStep.SCALE.MONTH:this.current.setDate(1);case TimeStep.SCALE.DAY:case TimeStep.SCALE.WEEKDAY:this.current.setHours(0);case TimeStep.SCALE.HOUR:this.current.setMinutes(0);case TimeStep.SCALE.MINUTE:this.current.setSeconds(0);case TimeStep.SCALE.SECOND:this.current.setMilliseconds(0)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.setMilliseconds(this.current.getMilliseconds()-this.current.getMilliseconds()%this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()-this.current.getSeconds()%this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()-this.current.getMinutes()%this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()-this.current.getHours()%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()-1-(this.current.getDate()-1)%this.step+1);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()-this.current.getMonth()%this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()-this.current.getFullYear()%this.step);break;default:}},TimeStep.prototype.hasNext=function(){return this.current.valueOf()<=this._end.valueOf()},TimeStep.prototype.next=function(){var t=this.current.valueOf();if(6>this.current.getMonth())switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current=new Date(this.current.valueOf()+1e3*this.step);break;case TimeStep.SCALE.MINUTE:this.current=new Date(this.current.valueOf()+60*1e3*this.step);break;case TimeStep.SCALE.HOUR:this.current=new Date(this.current.valueOf()+60*60*1e3*this.step);var e=this.current.getHours();this.current.setHours(e-e%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step);break;default:}else switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()+this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()+this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()+this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step);break;default:}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.getMilliseconds()0&&(this.step=e),this.autoScale=!1},TimeStep.prototype.setAutoScale=function(t){this.autoScale=t},TimeStep.prototype.setMinimumStep=function(t){if(void 0!=t){var e=31104e6,i=2592e6,s=864e5,o=36e5,n=6e4,r=1e3,a=1;1e3*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1e3),500*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=500),100*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=100),50*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=50),10*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=10),5*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=5),e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1),3*i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=3),i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=1),5*s>t&&(this.scale=TimeStep.SCALE.DAY,this.step=5),2*s>t&&(this.scale=TimeStep.SCALE.DAY,this.step=2),s>t&&(this.scale=TimeStep.SCALE.DAY,this.step=1),s/2>t&&(this.scale=TimeStep.SCALE.WEEKDAY,this.step=1),4*o>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=4),o>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=1),15*n>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=15),10*n>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=10),5*n>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=5),n>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=1),15*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=15),10*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=10),5*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=5),r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=1),200*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=200),100*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=100),50*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=50),10*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=10),5*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=5),a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=1)}},TimeStep.prototype.snap=function(t){if(this.scale==TimeStep.SCALE.YEAR){var e=t.getFullYear()+Math.round(t.getMonth()/12);t.setFullYear(Math.round(e/this.step)*this.step),t.setMonth(0),t.setDate(0),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MONTH)t.getDate()>15?(t.setDate(1),t.setMonth(t.getMonth()+1)):t.setDate(1),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0); +else if(this.scale==TimeStep.SCALE.DAY||this.scale==TimeStep.SCALE.WEEKDAY){switch(this.step){case 5:case 2:t.setHours(24*Math.round(t.getHours()/24));break;default:t.setHours(12*Math.round(t.getHours()/12))}t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.HOUR){switch(this.step){case 4:t.setMinutes(60*Math.round(t.getMinutes()/60));break;default:t.setMinutes(30*Math.round(t.getMinutes()/30))}t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MINUTE){switch(this.step){case 15:case 10:t.setMinutes(5*Math.round(t.getMinutes()/5)),t.setSeconds(0);break;case 5:t.setSeconds(60*Math.round(t.getSeconds()/60));break;default:t.setSeconds(30*Math.round(t.getSeconds()/30))}t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.SECOND)switch(this.step){case 15:case 10:t.setSeconds(5*Math.round(t.getSeconds()/5)),t.setMilliseconds(0);break;case 5:t.setMilliseconds(1e3*Math.round(t.getMilliseconds()/1e3));break;default:t.setMilliseconds(500*Math.round(t.getMilliseconds()/500))}else if(this.scale==TimeStep.SCALE.MILLISECOND){var i=this.step>5?this.step/2:1;t.setMilliseconds(Math.round(t.getMilliseconds()/i)*i)}},TimeStep.prototype.isMajor=function(){switch(this.scale){case TimeStep.SCALE.MILLISECOND:return 0==this.current.getMilliseconds();case TimeStep.SCALE.SECOND:return 0==this.current.getSeconds();case TimeStep.SCALE.MINUTE:return 0==this.current.getHours()&&0==this.current.getMinutes();case TimeStep.SCALE.HOUR:return 0==this.current.getHours();case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return 1==this.current.getDate();case TimeStep.SCALE.MONTH:return 0==this.current.getMonth();case TimeStep.SCALE.YEAR:return!1;default:return!1}},TimeStep.prototype.getLabelMinor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return E(t).format("SSS");case TimeStep.SCALE.SECOND:return E(t).format("s");case TimeStep.SCALE.MINUTE:return E(t).format("HH:mm");case TimeStep.SCALE.HOUR:return E(t).format("HH:mm");case TimeStep.SCALE.WEEKDAY:return E(t).format("ddd D");case TimeStep.SCALE.DAY:return E(t).format("D");case TimeStep.SCALE.MONTH:return E(t).format("MMM");case TimeStep.SCALE.YEAR:return E(t).format("YYYY");default:return""}},TimeStep.prototype.getLabelMajor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return E(t).format("HH:mm:ss");case TimeStep.SCALE.SECOND:return E(t).format("D MMMM HH:mm");case TimeStep.SCALE.MINUTE:case TimeStep.SCALE.HOUR:return E(t).format("ddd D MMMM");case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return E(t).format("MMMM YYYY");case TimeStep.SCALE.MONTH:return E(t).format("YYYY");case TimeStep.SCALE.YEAR:return"";default:return""}},a.prototype.setOptions=function(t){C.extend(this.options,t)},a.prototype.update=function(){this._order(),this._stack()},a.prototype._order=function(){var t=this.parent.items;if(!t)throw Error("Cannot stack items: parent does not contain items");var e=[],i=0;C.forEach(t,function(t){t.visible&&(e[i]=t,i++)});var s=this.options.order||this.defaultOptions.order;if("function"!=typeof s)throw Error("Option order must be a function");e.sort(s),this.ordered=e},a.prototype._stack=function(){var t,e,i,s=this.ordered,o=this.options,n=o.orientation||this.defaultOptions.orientation,r="top"==n;for(i=o.margin&&void 0!==o.margin.item?o.margin.item:this.defaultOptions.margin.item,t=0,e=s.length;e>t;t++){var a=s[t],h=null;do h=this.checkOverlap(s,t,0,t-1,i),null!=h&&(a.top=r?h.top+h.height+i:h.top-a.height-i);while(h)}},a.prototype.checkOverlap=function(t,e,i,s,o){for(var n=this.collision,r=t[e],a=s;a>=i;a--){var h=t[a];if(n(r,h,o)&&a!=e)return h}return null},a.prototype.collision=function(t,e,i){return t.left-ie.left&&t.top-ie.top},h.prototype.setOptions=function(t){C.extend(this.options,t),(null!=t.start||null!=t.end)&&this.setRange(t.start,t.end)},h.prototype.subscribe=function(t,e,i){var s,o=this;if("horizontal"!=i&&"vertical"!=i)throw new TypeError('Unknown direction "'+i+'". '+'Choose "horizontal" or "vertical".');if("move"==e)s={component:t,event:e,direction:i,callback:function(t){o._onMouseDown(t,s)},params:{}},t.on("mousedown",s.callback),o.listeners.push(s);else{if("zoom"!=e)throw new TypeError('Unknown event "'+e+'". '+'Choose "move" or "zoom".');s={component:t,event:e,direction:i,callback:function(t){o._onMouseWheel(t,s)},params:{}},t.on("mousewheel",s.callback),o.listeners.push(s)}},h.prototype.on=function(t,e){O.addListener(this,t,e)},h.prototype._trigger=function(t){O.trigger(this,t,{start:this.start,end:this.end})},h.prototype.setRange=function(t,e){var i=this._applyRange(t,e);i&&(this._trigger("rangechange"),this._trigger("rangechanged"))},h.prototype._applyRange=function(t,e){var i,s=null!=t?C.cast(t,"Number"):this.start,o=null!=e?C.cast(e,"Number"):this.end;if(isNaN(s))throw Error('Invalid start "'+t+'"');if(isNaN(o))throw Error('Invalid end "'+e+'"');if(s>o&&(o=s),null!=this.options.min){var n=this.options.min.valueOf();n>s&&(i=n-s,s+=i,o+=i)}if(null!=this.options.max){var r=this.options.max.valueOf();o>r&&(i=o-r,s-=i,o-=i)}if(null!=this.options.zoomMin){var a=this.options.zoomMin.valueOf();0>a&&(a=0),a>o-s&&(this.end-this.start>a?(i=a-(o-s),s-=i/2,o+=i/2):(s=this.start,o=this.end))}if(null!=this.options.zoomMax){var h=this.options.zoomMax.valueOf();0>h&&(h=0),o-s>h&&(h>this.end-this.start?(i=o-s-h,s+=i/2,o-=i/2):(s=this.start,o=this.end))}var d=this.start!=s||this.end!=o;return this.start=s,this.end=o,d},h.prototype.getRange=function(){return{start:this.start,end:this.end}},h.prototype.conversion=function(t){return this.start,this.end,h.conversion(this.start,this.end,t)},h.conversion=function(t,e,i){return 0!=i&&0!=e-t?{offset:t,factor:i/(e-t)}:{offset:0,factor:1}},h.prototype._onMouseDown=function(t,e){t=t||window.event;var i=e.params,s=t.which?1==t.which:1==t.button;if(s){i.mouseX=C.getPageX(t),i.mouseY=C.getPageY(t),i.previousLeft=0,i.previousOffset=0,i.moved=!1,i.start=this.start,i.end=this.end;var o=e.component.frame;o&&(o.style.cursor="move");var n=this;i.onMouseMove||(i.onMouseMove=function(t){n._onMouseMove(t,e)},C.addEventListener(document,"mousemove",i.onMouseMove)),i.onMouseUp||(i.onMouseUp=function(t){n._onMouseUp(t,e)},C.addEventListener(document,"mouseup",i.onMouseUp)),C.preventDefault(t)}},h.prototype._onMouseMove=function(t,e){t=t||window.event;var i=e.params,s=C.getPageX(t),o=C.getPageY(t);void 0==i.mouseX&&(i.mouseX=s),void 0==i.mouseY&&(i.mouseY=o);var n=s-i.mouseX,r=o-i.mouseY,a="horizontal"==e.direction?n:r;Math.abs(a)>=1&&(i.moved=!0);var h=i.end-i.start,d="horizontal"==e.direction?e.component.width:e.component.height,l=-a/d*h;this._applyRange(i.start+l,i.end+l),this._trigger("rangechange"),C.preventDefault(t)},h.prototype._onMouseUp=function(t,e){t=t||window.event;var i=e.params;e.component.frame&&(e.component.frame.style.cursor="auto"),i.onMouseMove&&(C.removeEventListener(document,"mousemove",i.onMouseMove),i.onMouseMove=null),i.onMouseUp&&(C.removeEventListener(document,"mouseup",i.onMouseUp),i.onMouseUp=null),i.moved&&this._trigger("rangechanged")},h.prototype._onMouseWheel=function(t,e){t=t||window.event;var i=0;if(t.wheelDelta?i=t.wheelDelta/120:t.detail&&(i=-t.detail/3),i){var s=this,o=function(){var o=i/5,n=null,r=e.component.frame;if(r){var a,h;if("horizontal"==e.direction){a=e.component.width,h=s.conversion(a);var d=C.getAbsoluteLeft(r),l=C.getPageX(t);n=(l-d)/h.factor+h.offset}else{a=e.component.height,h=s.conversion(a);var p=C.getAbsoluteTop(r),u=C.getPageY(t);n=(p+a-u-p)/h.factor+h.offset}}s.zoom(o,n)};o()}C.preventDefault(t)},h.prototype.zoom=function(t,e){null==e&&(e=(this.start+this.end)/2),t>=1&&(t=.9),-1>=t&&(t=-.9),0>t&&(t/=1+t);var i=this.start-e,s=this.end-e,o=this.start-i*t,n=this.end-s*t;this.setRange(o,n)},h.prototype.move=function(t){var e=this.end-this.start,i=this.start+e*t,s=this.end+e*t;this.start=i,this.end=s},d.prototype.add=function(t){if(void 0==t.id)throw Error("Component has no field id");if(!(t instanceof l||t instanceof d))throw new TypeError("Component must be an instance of prototype Component or Controller");t.controller=this,this.components[t.id]=t},d.prototype.remove=function(t){var e;for(e in this.components)if(this.components.hasOwnProperty(e)&&(e==t||this.components[e]==t))break;e&&delete this.components[e]},d.prototype.requestReflow=function(t){if(t)this.reflow();else if(!this.reflowTimer){var e=this;this.reflowTimer=setTimeout(function(){e.reflowTimer=void 0,e.reflow()},0)}},d.prototype.requestRepaint=function(t){if(t)this.repaint();else if(!this.repaintTimer){var e=this;this.repaintTimer=setTimeout(function(){e.repaintTimer=void 0,e.repaint()},0)}},d.prototype.repaint=function(){function t(s,o){o in i||(s.depends&&s.depends.forEach(function(e){t(e,e.id)}),s.parent&&t(s.parent,s.parent.id),e=s.repaint()||e,i[o]=!0)}var e=!1;this.repaintTimer&&(clearTimeout(this.repaintTimer),this.repaintTimer=void 0);var i={};C.forEach(this.components,t),e&&this.reflow()},d.prototype.reflow=function(){function t(s,o){o in i||(s.depends&&s.depends.forEach(function(e){t(e,e.id)}),s.parent&&t(s.parent,s.parent.id),e=s.reflow()||e,i[o]=!0)}var e=!1;this.reflowTimer&&(clearTimeout(this.reflowTimer),this.reflowTimer=void 0);var i={};C.forEach(this.components,t),e&&this.repaint()},l.prototype.setOptions=function(t){t&&(C.extend(this.options,t),this.controller&&(this.requestRepaint(),this.requestReflow()))},l.prototype.getOption=function(t){var e;return this.options&&(e=this.options[t]),void 0===e&&this.defaultOptions&&(e=this.defaultOptions[t]),e},l.prototype.getContainer=function(){return null},l.prototype.getFrame=function(){return this.frame},l.prototype.repaint=function(){return!1},l.prototype.reflow=function(){return!1},l.prototype.hide=function(){return this.frame&&this.frame.parentNode?(this.frame.parentNode.removeChild(this.frame),!0):!1},l.prototype.show=function(){return this.frame&&this.frame.parentNode?!1:this.repaint()},l.prototype.requestRepaint=function(){if(!this.controller)throw Error("Cannot request a repaint: no controller configured");this.controller.requestRepaint()},l.prototype.requestReflow=function(){if(!this.controller)throw Error("Cannot request a reflow: no controller configured");this.controller.requestReflow()},p.prototype=new l,p.prototype.setOptions=l.prototype.setOptions,p.prototype.getContainer=function(){return this.frame},p.prototype.repaint=function(){var t=0,e=C.updateProperty,i=C.option.asSize,s=this.options,o=this.frame;if(!o){o=document.createElement("div"),o.className="panel";var n=s.className;n&&("function"==typeof n?C.addClassName(o,n()+""):C.addClassName(o,n+"")),this.frame=o,t+=1}if(!o.parentNode){if(!this.parent)throw Error("Cannot repaint panel: no parent attached");var r=this.parent.getContainer();if(!r)throw Error("Cannot repaint panel: parent has no container element");r.appendChild(o),t+=1}return t+=e(o.style,"top",i(s.top,"0px")),t+=e(o.style,"left",i(s.left,"0px")),t+=e(o.style,"width",i(s.width,"100%")),t+=e(o.style,"height",i(s.height,"100%")),t>0},p.prototype.reflow=function(){var t=0,e=C.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},u.prototype=new p,u.prototype.setOptions=l.prototype.setOptions,u.prototype.repaint=function(){var t=0,e=C.updateProperty,i=C.option.asSize,s=this.options,o=this.frame;if(!o){o=document.createElement("div"),o.className="graph panel";var n=s.className;n&&C.addClassName(o,C.option.asString(n)),this.frame=o,t+=1}if(!o.parentNode){if(!this.container)throw Error("Cannot repaint root panel: no container attached");this.container.appendChild(o),t+=1}return t+=e(o.style,"top",i(s.top,"0px")),t+=e(o.style,"left",i(s.left,"0px")),t+=e(o.style,"width",i(s.width,"100%")),t+=e(o.style,"height",i(s.height,"100%")),this._updateEventEmitters(),this._updateWatch(),t>0},u.prototype.reflow=function(){var t=0,e=C.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},u.prototype._updateWatch=function(){var t=this.getOption("autoResize");t?this._watch():this._unwatch()},u.prototype._watch=function(){var t=this;this._unwatch();var e=function(){var e=t.getOption("autoResize");return e?(t.frame&&(t.frame.clientWidth!=t.width||t.frame.clientHeight!=t.height)&&t.requestReflow(),void 0):(t._unwatch(),void 0)};C.addEventListener(window,"resize",e),this.watchTimer=setInterval(e,1e3)},u.prototype._unwatch=function(){this.watchTimer&&(clearInterval(this.watchTimer),this.watchTimer=void 0)},u.prototype.on=function(t,e){var i=this.listeners[t];i||(i=[],this.listeners[t]=i),i.push(e),this._updateEventEmitters()},u.prototype._updateEventEmitters=function(){if(this.listeners){var t=this;C.forEach(this.listeners,function(e,i){if(t.emitters||(t.emitters={}),!(i in t.emitters)){var s=t.frame;if(s){var o=function(t){e.forEach(function(e){e(t)})};t.emitters[i]=o,C.addEventListener(s,i,o)}}})}},c.prototype=new l,c.prototype.setOptions=l.prototype.setOptions,c.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},c.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.factor+e.offset)},c.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.factor},c.prototype.repaint=function(){var t=0,e=C.updateProperty,i=C.option.asSize,s=this.options,o=this.getOption("orientation"),n=this.props,r=this.step,a=this.frame;if(a||(a=document.createElement("div"),this.frame=a,t+=1),a.className="axis "+o,!a.parentNode){if(!this.parent)throw Error("Cannot repaint time axis: no parent attached");var h=this.parent.getContainer();if(!h)throw Error("Cannot repaint time axis: parent has no container element");h.appendChild(a),t+=1}var d=a.parentNode;if(d){var l=a.nextSibling;d.removeChild(a);var p="bottom"==o&&this.props.parentHeight&&this.height?this.props.parentHeight-this.height+"px":"0px";if(t+=e(a.style,"top",i(s.top,p)),t+=e(a.style,"left",i(s.left,"0px")),t+=e(a.style,"width",i(s.width,"100%")),t+=e(a.style,"height",i(s.height,this.height+"px")),this._repaintMeasureChars(),this.step){this._repaintStart(),r.first();for(var u=void 0,c=0;r.hasNext()&&1e3>c;){c++;var f=r.getCurrent(),m=this.toScreen(f),g=r.isMajor();this.getOption("showMinorLabels")&&this._repaintMinorText(m,r.getLabelMinor()),g&&this.getOption("showMajorLabels")?(m>0&&(void 0==u&&(u=m),this._repaintMajorText(m,r.getLabelMajor())),this._repaintMajorLine(m)):this._repaintMinorLine(m),r.next()}if(this.getOption("showMajorLabels")){var v=this.toTime(0),y=r.getLabelMajor(v),w=y.length*(n.majorCharWidth||10)+10;(void 0==u||u>w)&&this._repaintMajorText(0,y)}this._repaintEnd()}this._repaintLine(),l?d.insertBefore(a,l):d.appendChild(a)}return t>0},c.prototype._repaintStart=function(){var t=this.dom,e=t.redundant;e.majorLines=t.majorLines,e.majorTexts=t.majorTexts,e.minorLines=t.minorLines,e.minorTexts=t.minorTexts,t.majorLines=[],t.majorTexts=[],t.minorLines=[],t.minorTexts=[]},c.prototype._repaintEnd=function(){C.forEach(this.dom.redundant,function(t){for(;t.length;){var e=t.pop();e&&e.parentNode&&e.parentNode.removeChild(e)}})},c.prototype._repaintMinorText=function(t,e){var i=this.dom.redundant.minorTexts.shift();if(!i){var s=document.createTextNode("");i=document.createElement("div"),i.appendChild(s),i.className="text minor",this.frame.appendChild(i)}this.dom.minorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.left=t+"px",i.style.top=this.props.minorLabelTop+"px"},c.prototype._repaintMajorText=function(t,e){var i=this.dom.redundant.majorTexts.shift();if(!i){var s=document.createTextNode(e);i=document.createElement("div"),i.className="text major",i.appendChild(s),this.frame.appendChild(i)}this.dom.majorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.top=this.props.majorLabelTop+"px",i.style.left=t+"px"},c.prototype._repaintMinorLine=function(t){var e=this.dom.redundant.minorLines.shift();e||(e=document.createElement("div"),e.className="grid vertical minor",this.frame.appendChild(e)),this.dom.minorLines.push(e);var i=this.props;e.style.top=i.minorLineTop+"px",e.style.height=i.minorLineHeight+"px",e.style.left=t-i.minorLineWidth/2+"px"},c.prototype._repaintMajorLine=function(t){var e=this.dom.redundant.majorLines.shift();e||(e=document.createElement("DIV"),e.className="grid vertical major",this.frame.appendChild(e)),this.dom.majorLines.push(e);var i=this.props;e.style.top=i.majorLineTop+"px",e.style.left=t-i.majorLineWidth/2+"px",e.style.height=i.majorLineHeight+"px"},c.prototype._repaintLine=function(){var t=this.dom.line,e=this.frame;this.options,this.getOption("showMinorLabels")||this.getOption("showMajorLabels")?(t?(e.removeChild(t),e.appendChild(t)):(t=document.createElement("div"),t.className="grid horizontal major",e.appendChild(t),this.dom.line=t),t.style.top=this.props.lineTop+"px"):t&&axis.parentElement&&(e.removeChild(axis.line),delete this.dom.line)},c.prototype._repaintMeasureChars=function(){var t,e=this.dom;if(!e.measureCharMinor){t=document.createTextNode("0");var i=document.createElement("DIV");i.className="text minor measure",i.appendChild(t),this.frame.appendChild(i),e.measureCharMinor=i}if(!e.measureCharMajor){t=document.createTextNode("0");var s=document.createElement("DIV");s.className="text major measure",s.appendChild(t),this.frame.appendChild(s),e.measureCharMajor=s}},c.prototype.reflow=function(){var t=0,e=C.updateProperty,i=this.frame,s=this.range;if(!s)throw Error("Cannot repaint time axis: no range configured");if(i){t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft);var o=this.props,n=this.getOption("showMinorLabels"),r=this.getOption("showMajorLabels"),a=this.dom.measureCharMinor,h=this.dom.measureCharMajor;a&&(o.minorCharHeight=a.clientHeight,o.minorCharWidth=a.clientWidth),h&&(o.majorCharHeight=h.clientHeight,o.majorCharWidth=h.clientWidth);var d=i.parentNode?i.parentNode.offsetHeight:0;switch(d!=o.parentHeight&&(o.parentHeight=d,t+=1),this.getOption("orientation")){case"bottom":o.minorLabelHeight=n?o.minorCharHeight:0,o.majorLabelHeight=r?o.majorCharHeight:0,o.minorLabelTop=0,o.majorLabelTop=o.minorLabelTop+o.minorLabelHeight,o.minorLineTop=-this.top,o.minorLineHeight=Math.max(this.top+o.majorLabelHeight,0),o.minorLineWidth=1,o.majorLineTop=-this.top,o.majorLineHeight=Math.max(this.top+o.minorLabelHeight+o.majorLabelHeight,0),o.majorLineWidth=1,o.lineTop=0;break;case"top":o.minorLabelHeight=n?o.minorCharHeight:0,o.majorLabelHeight=r?o.majorCharHeight:0,o.majorLabelTop=0,o.minorLabelTop=o.majorLabelTop+o.majorLabelHeight,o.minorLineTop=o.minorLabelTop,o.minorLineHeight=Math.max(d-o.majorLabelHeight-this.top),o.minorLineWidth=1,o.majorLineTop=0,o.majorLineHeight=Math.max(d-this.top),o.majorLineWidth=1,o.lineTop=o.majorLabelHeight+o.minorLabelHeight;break;default:throw Error('Unkown orientation "'+this.getOption("orientation")+'"')}var l=o.minorLabelHeight+o.majorLabelHeight;t+=e(this,"width",i.offsetWidth),t+=e(this,"height",l),this._updateConversion();var p=C.cast(s.start,"Date"),u=C.cast(s.end,"Date"),c=this.toTime(5*(o.minorCharWidth||10))-this.toTime(0);this.step=new TimeStep(p,u,c),t+=e(o.range,"start",p.valueOf()),t+=e(o.range,"end",u.valueOf()),t+=e(o.range,"minimumStep",c.valueOf())}return t>0},c.prototype._updateConversion=function(){var t=this.range;if(!t)throw Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},f.prototype=new p,f.types={box:g,range:y,point:v},f.prototype.setOptions=l.prototype.setOptions,f.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},f.prototype.repaint=function(){var t=0,e=C.updateProperty,i=C.option.asSize,s=this.options,o=this.getOption("orientation"),n=this.defaultOptions,r=this.frame;if(!r){r=document.createElement("div"),r.className="itemset";var a=s.className;a&&C.addClassName(r,C.option.asString(a));var h=document.createElement("div");h.className="background",r.appendChild(h),this.dom.background=h;var d=document.createElement("div");d.className="foreground",r.appendChild(d),this.dom.foreground=d;var l=document.createElement("div");l.className="itemset-axis",this.dom.axis=l,this.frame=r,t+=1}if(!this.parent)throw Error("Cannot repaint itemset: no parent attached");var p=this.parent.getContainer();if(!p)throw Error("Cannot repaint itemset: parent has no container element");r.parentNode||(p.appendChild(r),t+=1),this.dom.axis.parentNode||(p.appendChild(this.dom.axis),t+=1),t+=e(r.style,"left",i(s.left,"0px")),t+=e(r.style,"top",i(s.top,"0px")),t+=e(r.style,"width",i(s.width,"100%")),t+=e(r.style,"height",i(s.height,this.height+"px")),t+=e(this.dom.axis.style,"left",i(s.left,"0px")),t+=e(this.dom.axis.style,"width",i(s.width,"100%")),t+="bottom"==o?e(this.dom.axis.style,"top",this.height+this.top+"px"):e(this.dom.axis.style,"top",this.top+"px"),this._updateConversion();var u=this,c=this.queue,m=this.itemsData,g=this.items,v={fields:[m&&m.fieldId||"id","start","end","content","type"]};return Object.keys(c).forEach(function(e){var i=c[e],o=g[e];switch(i){case"add":case"update":var r=m&&m.get(e,v);if(r){var a=r.type||r.start&&r.end&&"range"||s.type||"box",h=f.types[a];if(o&&(h&&o instanceof h?(o.data=r,t++):(t+=o.hide(),o=null)),!o){if(!h)throw new TypeError('Unknown item type "'+a+'"');o=new h(u,r,s,n),t++}o.repaint(),g[e]=o}delete c[e];break;case"remove":o&&(t+=o.hide()),delete g[e],delete c[e];break;default:console.log('Error: unknown action "'+i+'"')}}),C.forEach(this.items,function(e){e.visible?(t+=e.show(),e.reposition()):t+=e.hide()}),t>0},f.prototype.getForeground=function(){return this.dom.foreground},f.prototype.getBackground=function(){return this.dom.background},f.prototype.getAxis=function(){return this.dom.axis},f.prototype.reflow=function(){var t=0,e=this.options,i=e.margin&&e.margin.axis||this.defaultOptions.margin.axis,s=e.margin&&e.margin.item||this.defaultOptions.margin.item,o=C.updateProperty,n=C.option.asNumber,r=C.option.asSize,a=this.frame;if(a){this._updateConversion(),C.forEach(this.items,function(e){t+=e.reflow()}),this.stack.update();var h,d=n(e.maxHeight),l=null!=r(e.height);if(l)h=a.offsetHeight;else{var p=this.stack.ordered;if(p.length){var u=p[0].top,c=p[0].top+p[0].height;C.forEach(p,function(t){u=Math.min(u,t.top),c=Math.max(c,t.top+t.height)}),h=c-u+i+s}else h=i+s}null!=d&&(h=Math.min(h,d)),t+=o(this,"height",h),t+=o(this,"top",a.offsetTop),t+=o(this,"left",a.offsetLeft),t+=o(this,"width",a.offsetWidth)}else t+=1;return t>0},f.prototype.hide=function(){var t=!1;return this.frame&&this.frame.parentNode&&(this.frame.parentNode.removeChild(this.frame),t=!0),this.dom.axis&&this.dom.axis.parentNode&&(this.dom.axis.parentNode.removeChild(this.dom.axis),t=!0),t},f.prototype.setItems=function(t){var e,i=this,s=this.itemsData;if(s&&(C.forEach(this.listeners,function(t,e){s.unsubscribe(e,t)}),e=s.getIds(),this._onRemove(e)),t){if(!(t instanceof n||t instanceof r))throw new TypeError("Data must be an instance of DataSet");this.itemsData=t}else this.itemsData=null;if(this.itemsData){var o=this.id;C.forEach(this.listeners,function(t,e){i.itemsData.subscribe(e,t,o)}),e=this.itemsData.getIds(),this._onAdd(e)}},f.prototype.getItems=function(){return this.itemsData},f.prototype._onUpdate=function(t){this._toQueue("update",t)},f.prototype._onAdd=function(t){this._toQueue("add",t)},f.prototype._onRemove=function(t){this._toQueue("remove",t)},f.prototype._toQueue=function(t,e){var i=this.queue;e.forEach(function(e){i[e]=t}),this.controller&&this.requestRepaint()},f.prototype._updateConversion=function(){var t=this.range;if(!t)throw Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},f.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.factor+e.offset)},f.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.factor},m.prototype.select=function(){this.selected=!0},m.prototype.unselect=function(){this.selected=!1},m.prototype.show=function(){return!1},m.prototype.hide=function(){return!1},m.prototype.repaint=function(){return!1},m.prototype.reflow=function(){return!1},g.prototype=new m(null,null),g.prototype.select=function(){this.selected=!0},g.prototype.unselect=function(){this.selected=!1},g.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw Error("Cannot repaint time axis: parent has no foreground container element");var s=this.parent.getBackground();if(!s)throw Error("Cannot repaint time axis: parent has no background container element");var o=this.parent.getAxis();if(!s)throw Error("Cannot repaint time axis: parent has no axis container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),e.line.parentNode||(s.appendChild(e.line),t=!0),e.dot.parentNode||(o.appendChild(e.dot),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.box.className="item box"+n,e.line.className="item line"+n,e.dot.className="item dot"+n,t=!0)}return t},g.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},g.prototype.hide=function(){var t=!1,e=this.dom;return e&&(e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),e.line.parentNode&&e.line.parentNode.removeChild(e.line),e.dot.parentNode&&e.dot.parentNode.removeChild(e.dot)),t},g.prototype.reflow=function(){var t,e,i,s,o,n,r,a,h,d,l,p,u=0;if(void 0==this.data.start)throw Error('Property "start" missing in item '+this.data.id);if(l=this.data,p=this.parent&&this.parent.range,this.visible=l&&p?l.start>p.start&&l.start0},g.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("DIV"),t.content=document.createElement("DIV"),t.content.className="content",t.box.appendChild(t.content),t.line=document.createElement("DIV"),t.line.className="line",t.dot=document.createElement("DIV"),t.dot.className="dot")},g.prototype.reposition=function(){var t=this.dom,e=this.props,i=this.options.orientation||this.defaultOptions.orientation;if(t){var s=t.box,o=t.line,n=t.dot;s.style.left=this.left+"px",s.style.top=this.top+"px",o.style.left=e.line.left+"px","top"==i?(o.style.top="0px",o.style.height=this.top+"px"):(o.style.top=this.top+this.height+"px",o.style.height=Math.max(this.parent.height-this.top-this.height+this.props.dot.height/2,0)+"px"),n.style.left=e.dot.left+"px",n.style.top=e.dot.top+"px"}},v.prototype=new m(null,null),v.prototype.select=function(){this.selected=!0},v.prototype.unselect=function(){this.selected=!1},v.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw Error("Cannot repaint time axis: parent has no foreground container element");if(e.point.parentNode||(i.appendChild(e.point),i.appendChild(e.point),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var s=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=s&&(this.className=s,e.point.className="item point"+s,t=!0)}return t},v.prototype.show=function(){return this.dom&&this.dom.point.parentNode?!1:this.repaint()},v.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.point.parentNode&&(e.point.parentNode.removeChild(e.point),t=!0),t},v.prototype.reflow=function(){var t,e,i,s,o,n,r,a,h,d,l=0;if(void 0==this.data.start)throw Error('Property "start" missing in item '+this.data.id);if(h=this.data,d=this.parent&&this.parent.range,this.visible=h&&d?h.start>d.start&&h.start0},v.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.point=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.point.appendChild(t.content),t.dot=document.createElement("div"),t.dot.className="dot",t.point.appendChild(t.dot))},v.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.point.style.top=this.top+"px",t.point.style.left=this.left+"px",t.content.style.marginLeft=e.content.marginLeft+"px",t.dot.style.top=e.dot.top+"px")},y.prototype=new m(null,null),y.prototype.select=function(){this.selected=!0},y.prototype.unselect=function(){this.selected=!1},y.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var s=this.data.className?""+this.data.className:"";this.className!=s&&(this.className=s,e.box.className="item range"+s,t=!0)}return t},y.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},y.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),t},y.prototype.reflow=function(){var t,e,i,s,o,n,r,a,h,d,l,p,u,c,f,m,g=0;if(void 0==this.data.start)throw Error('Property "start" missing in item '+this.data.id);if(void 0==this.data.end)throw Error('Property "end" missing in item '+this.data.id); +return h=this.data,d=this.parent&&this.parent.range,this.visible=h&&d?h.startd.start:!1,this.visible&&(t=this.dom,t?(e=this.props,i=this.options,n=this.parent,r=n.toScreen(this.data.start),a=n.toScreen(this.data.end),l=C.updateProperty,p=t.box,u=n.width,f=i.orientation||this.defaultOptions.orientation,s=i.margin&&i.margin.axis||this.defaultOptions.margin.axis,o=i.padding||this.defaultOptions.padding,g+=l(e.content,"width",t.content.offsetWidth),g+=l(this,"height",p.offsetHeight),-u>r&&(r=-u),a>2*u&&(a=2*u),c=0>r?Math.min(-r,a-r-e.content.width-2*o):0,g+=l(e.content,"left",c),"top"==f?(m=s,g+=l(this,"top",m)):(m=n.height-this.height-s,g+=l(this,"top",m)),g+=l(this,"left",r),g+=l(this,"width",Math.max(a-r,1))):g+=1),g>0},y.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content))},y.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.box.style.top=this.top+"px",t.box.style.left=this.left+"px",t.box.style.width=this.width+"px",t.content.style.left=e.content.left+"px")},w.prototype=new l,w.prototype.setOptions=l.prototype.setOptions,w.prototype.getContainer=function(){return this.parent.getContainer()},w.prototype.setItems=function(t){if(this.itemset&&(this.itemset.hide(),this.itemset.setItems(),this.parent.controller.remove(this.itemset),this.itemset=null),t){var e=this.groupId,i=Object.create(this.options);this.itemset=new f(this,null,i),this.itemset.setRange(this.parent.range),this.view=new r(t,{filter:function(t){return t.group==e}}),this.itemset.setItems(this.view),this.parent.controller.add(this.itemset)}},w.prototype.repaint=function(){return!1},w.prototype.reflow=function(){var t=0,e=C.updateProperty;return t+=e(this,"top",this.itemset?this.itemset.top:0),t+=e(this,"height",this.itemset?this.itemset.height:0),t>0},b.prototype=new p,b.prototype.setOptions=l.prototype.setOptions,b.prototype.setRange=function(){},b.prototype.setItems=function(t){this.itemsData=t;for(var e in this.groups)if(this.groups.hasOwnProperty(e)){var i=this.groups[e];i.setItems(t)}},b.prototype.getItems=function(){return this.itemsData},b.prototype.setRange=function(t){this.range=t},b.prototype.setGroups=function(t){var e,i=this;if(this.groupsData&&(C.forEach(this.listeners,function(t,e){i.groupsData.unsubscribe(e,t)}),e=this.groupsData.getIds(),this._onRemove(e)),t?t instanceof n?this.groupsData=t:(this.groupsData=new n({fieldTypes:{start:"Date",end:"Date"}}),this.groupsData.add(t)):this.groupsData=null,this.groupsData){var s=this.id;C.forEach(this.listeners,function(t,e){i.groupsData.subscribe(e,t,s)}),e=this.groupsData.getIds(),this._onAdd(e)}},b.prototype.getGroups=function(){return this.groupsData},b.prototype.repaint=function(){var t=0,e=C.updateProperty,i=C.option.asSize,s=this.options,o=this.frame;if(!o){o=document.createElement("div"),o.className="groupset";var n=s.className;n&&C.addClassName(o,C.option.asString(n)),this.frame=o,t+=1}if(!this.parent)throw Error("Cannot repaint groupset: no parent attached");var r=this.parent.getContainer();if(!r)throw Error("Cannot repaint groupset: parent has no container element");o.parentNode||(r.appendChild(o),t+=1),t+=e(o.style,"height",i(s.height,this.height+"px")),t+=e(o.style,"top",i(s.top,"0px")),t+=e(o.style,"left",i(s.left,"0px")),t+=e(o.style,"width",i(s.width,"100%"));var a=this,h=this.queue,d=this.groups,l=this.groupsData,p=Object.keys(h);if(p.length){p.forEach(function(t){var e=h[t],i=d[t];switch(e){case"add":case"update":if(!i){var s=Object.create(a.options);i=new w(a,t,s),i.setItems(a.itemsData),d[t]=i,a.controller.add(i)}i.data=l.get(t),delete h[t];break;case"remove":i&&(i.setItems(),delete d[t],a.controller.remove(i)),delete h[t];break;default:console.log('Error: unknown action "'+e+'"')}});for(var u=this.groupsData.getIds({order:this.options.groupsOrder}),c=0;u.length>c;c++)(function(t,e){var i=0;e&&(i=function(){return e.top+e.height}),t.setOptions({top:i})})(d[u[c]],d[u[c-1]]);t++}return t>0},b.prototype.getContainer=function(){return this.frame},b.prototype.reflow=function(){var t=0,e=this.options,i=C.updateProperty,s=C.option.asNumber,o=C.option.asSize,n=this.frame;if(n){var r,a=s(e.maxHeight),h=null!=o(e.height);if(h)r=n.offsetHeight;else{r=0;for(var d in this.groups)if(this.groups.hasOwnProperty(d)){var l=this.groups[d];r+=l.height}}null!=a&&(r=Math.min(r,a)),t+=i(this,"height",r),t+=i(this,"top",n.offsetTop),t+=i(this,"left",n.offsetLeft),t+=i(this,"width",n.offsetWidth)}return t>0},b.prototype.hide=function(){return this.frame&&this.frame.parentNode?(this.frame.parentNode.removeChild(this.frame),!0):!1},b.prototype.show=function(){return this.frame&&this.frame.parentNode?!1:this.repaint()},b.prototype._onUpdate=function(t){this._toQueue(t,"update")},b.prototype._onAdd=function(t){this._toQueue(t,"add")},b.prototype._onRemove=function(t){this._toQueue(t,"remove")},b.prototype._toQueue=function(t,e){var i=this.queue;t.forEach(function(t){i[t]=e}),this.controller&&this.requestRepaint()},_.prototype.setOptions=function(t){t&&C.extend(this.options,t),this.controller.reflow(),this.controller.repaint()},_.prototype.setItems=function(t){var e,i=null==this.itemsData;if(t?t instanceof n&&(e=t):e=null,t instanceof n||(e=new n({fieldTypes:{start:"Date",end:"Date"}}),e.add(t)),this.itemsData=e,this.content.setItems(e),i&&(void 0==this.options.start||void 0==this.options.end)){var s=this.getItemRange(),o=s.min,r=s.max;if(null!=o&&null!=r){var a=r.valueOf()-o.valueOf();o=new Date(o.valueOf()-.05*a),r=new Date(r.valueOf()+.05*a)}void 0!=this.options.start&&(o=new Date(this.options.start.valueOf())),void 0!=this.options.end&&(r=new Date(this.options.end.valueOf())),(null!=o||null!=r)&&this.range.setRange(o,r)}},_.prototype.setGroups=function(t){var e=this;this.groupsData=t;var i=this.groupsData?b:f;if(!(this.content instanceof i)){this.content&&(this.content.hide(),this.content.setItems&&this.content.setItems(),this.content.setGroups&&this.content.setGroups(),this.controller.remove(this.content));var s=Object.create(this.options);C.extend(s,{top:function(){return"top"==e.options.orientation?e.timeaxis.height:e.root.height-e.timeaxis.height-e.content.height},height:function(){return e.options.height?e.root.height-e.timeaxis.height:null},maxHeight:function(){if(e.options.maxHeight){if(!C.isNumber(e.options.maxHeight))throw new TypeError("Number expected for property maxHeight");return e.options.maxHeight-e.timeaxis.height}return null}}),this.content=new i(this.root,[this.timeaxis],s),this.content.setRange&&this.content.setRange(this.range),this.content.setItems&&this.content.setItems(this.itemsData),this.content.setGroups&&this.content.setGroups(this.groupsData),this.controller.add(this.content)}},_.prototype.getItemRange=function(){var t=this.itemsData,e=null,i=null;if(t){var s=t.min("start");e=s?s.start.valueOf():null;var o=t.max("start");o&&(i=o.start.valueOf());var n=t.max("end");n&&(i=null==i?n.end.valueOf():Math.max(i,n.end.valueOf()))}return{min:null!=e?new Date(e):null,max:null!=i?new Date(i):null}},function(t){function e(t){return w=t,l()}function i(){b=0,_=w.charAt(0)}function s(){b++,_=w.charAt(b)}function o(){return w.charAt(b+1)}function n(t){return C.test(t)}function r(t,e){if(t||(t={}),e)for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function a(t){M.nodes||(M.nodes={});var e=M.nodes[t.id];if(e)t.attr&&(e.attr=r(e.attr,t.attr));else if(M.nodes[t.id]=t,S){var i=r({},S);t.attr=r(i,t.attr)}}function h(t){if(M.edges||(M.edges=[]),M.edges.push(t),E){var e=r({},E);t.attr=r(e,t.attr)}}function d(){for(T=v.NULL,x="";" "==_||" "==_||"\n"==_||"\r"==_;)s();do{var t=!1;if("#"==_){for(var e=b-1;" "==w.charAt(e)||" "==w.charAt(e);)e--;if("\n"==w.charAt(e)||""==w.charAt(e)){for(;""!=_&&"\n"!=_;)s();t=!0}}if("/"==_&&"/"==o()){for(;""!=_&&"\n"!=_;)s();t=!0}if("/"==_&&"*"==o()){for(;""!=_;){if("*"==_&&"/"==o()){s(),s();break}s()}t=!0}for(;" "==_||" "==_||"\n"==_||"\r"==_;)s()}while(t);if(""==_)return T=v.DELIMITER,void 0;var i=_+o();if(y[i])return T=v.DELIMITER,x=i,s(),s(),void 0;if(y[_])return T=v.DELIMITER,x=_,s(),void 0;if(n(_)||"-"==_){for(x+=_,s();n(_);)x+=_,s();return"false"==x?x=!1:"true"==x?x=!0:isNaN(Number(x))||(x=Number(x)),T=v.IDENTIFIER,void 0}if('"'==_){for(s();""!=_&&('"'!=_||'"'==_&&'"'==o());)x+=_,'"'==_&&s(),s();if('"'!=_)throw f('End of string " expected');return s(),T=v.IDENTIFIER,void 0}for(T=v.UNKNOWN;""!=_;)x+=_,s();throw new SyntaxError('Syntax error in part "'+m(x,30)+'"')}function l(){if(M={},S=null,E=null,i(),d(),"strict"==x&&(M.strict=!0,d()),("graph"==x||"digraph"==x)&&(M.type=x,d()),T==v.IDENTIFIER&&(M.id=x,d()),"{"!=x)throw f("Angle bracket { expected");if(d(),p(),"}"!=x)throw f("Angle bracket } expected");if(d(),""!==x)throw f("End of file expected");return d(),M}function p(){for(;""!==x&&"}"!=x;){if(T!=v.IDENTIFIER)throw f("Identifier expected");u(),";"==x&&d()}}function u(){var t,e=x;if(d(),"node"==e)t=c(),t&&(S=r(S,t));else if("edge"==e)t=c(),t&&(E=r(E,t));else if("graph"==e)t=c(),t&&(M.attr=r(M.attr,t));else if("="==x)d(),M.attr||(M.attr={}),M.attr[e]=x,d();else{var i={id:e+""};t=c(),t&&(i.attr=t),a(i);for(var s=e;"->"==x||"--"==x;){var o=x;d();var n=x;a({id:n+""}),d(),t=c();var l={from:s+"",to:n+"",type:o};t&&(l.attr=t),h(l),s=n}}}function c(){if("["==x){d();for(var t={};""!==x&&"]"!=x;){if(T!=v.IDENTIFIER)throw f("Attribute name expected");var e=x;if(d(),"="!=x)throw f("Equal sign = expected");if(d(),T!=v.IDENTIFIER)throw f("Attribute value expected");var i=x;t[e]=i,d(),","==x&&d()}return d(),t}return void 0}function f(t){return new SyntaxError(t+', got "'+m(x,30)+'" (char '+b+")")}function m(t,e){return e>=t.length?t:t.substr(0,27)+"..."}function g(t){var i=e(t),s={nodes:[],edges:[],options:{}};if(i.nodes)for(var o in i.nodes)if(i.nodes.hasOwnProperty(o)){var n={id:o,label:o};r(n,i.nodes[o].attr),n.image&&(n.shape="image"),s.nodes.push(n)}return i.edges&&i.edges.forEach(function(t){var e={from:t.from,to:t.to};r(e,t.attr),e.style="->"==t.type?"arrow":"line",s.edges.push(e)}),i.attr&&(s.options=i.attr),s}var v={NULL:0,DELIMITER:1,IDENTIFIER:2,UNKNOWN:3},y={"{":!0,"}":!0,"[":!0,"]":!0,";":!0,"=":!0,",":!0,"->":!0,"--":!0},w="",b=0,_="",x="",T=v.NULL,M=null,S=null,E=null,C=/[a-zA-Z_0-9.#]/;t.parseDOT=e,t.DOTToGraph=g}(C!==void 0?C:s),"undefined"!=typeof CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.circle=function(t,e,i){this.beginPath(),this.arc(t,e,i,0,2*Math.PI,!1)},CanvasRenderingContext2D.prototype.square=function(t,e,i){this.beginPath(),this.rect(t-i,e-i,2*i,2*i)},CanvasRenderingContext2D.prototype.triangle=function(t,e,i){this.beginPath();var s=2*i,o=s/2,n=Math.sqrt(3)/6*s,r=Math.sqrt(s*s-o*o);this.moveTo(t,e-(r-n)),this.lineTo(t+o,e+n),this.lineTo(t-o,e+n),this.lineTo(t,e-(r-n)),this.closePath()},CanvasRenderingContext2D.prototype.triangleDown=function(t,e,i){this.beginPath();var s=2*i,o=s/2,n=Math.sqrt(3)/6*s,r=Math.sqrt(s*s-o*o);this.moveTo(t,e+(r-n)),this.lineTo(t+o,e-n),this.lineTo(t-o,e-n),this.lineTo(t,e+(r-n)),this.closePath()},CanvasRenderingContext2D.prototype.star=function(t,e,i){this.beginPath();for(var s=0;10>s;s++){var o=0===s%2?1.3*i:.5*i;this.lineTo(t+o*Math.sin(2*s*Math.PI/10),e-o*Math.cos(2*s*Math.PI/10))}this.closePath()},CanvasRenderingContext2D.prototype.roundRect=function(t,e,i,s,o){var n=Math.PI/180;0>i-2*o&&(o=i/2),0>s-2*o&&(o=s/2),this.beginPath(),this.moveTo(t+o,e),this.lineTo(t+i-o,e),this.arc(t+i-o,e+o,o,270*n,360*n,!1),this.lineTo(t+i,e+s-o),this.arc(t+i-o,e+s-o,o,0,90*n,!1),this.lineTo(t+o,e+s),this.arc(t+o,e+s-o,o,90*n,180*n,!1),this.lineTo(t,e+o),this.arc(t+o,e+o,o,180*n,270*n,!1)},CanvasRenderingContext2D.prototype.ellipse=function(t,e,i,s){var o=.5522848,n=i/2*o,r=s/2*o,a=t+i,h=e+s,d=t+i/2,l=e+s/2;this.beginPath(),this.moveTo(t,l),this.bezierCurveTo(t,l-r,d-n,e,d,e),this.bezierCurveTo(d+n,e,a,l-r,a,l),this.bezierCurveTo(a,l+r,d+n,h,d,h),this.bezierCurveTo(d-n,h,t,l+r,t,l)},CanvasRenderingContext2D.prototype.database=function(t,e,i,s){var o=1/3,n=i,r=s*o,a=.5522848,h=n/2*a,d=r/2*a,l=t+n,p=e+r,u=t+n/2,c=e+r/2,f=e+(s-r/2),m=e+s;this.beginPath(),this.moveTo(l,c),this.bezierCurveTo(l,c+d,u+h,p,u,p),this.bezierCurveTo(u-h,p,t,c+d,t,c),this.bezierCurveTo(t,c-d,u-h,e,u,e),this.bezierCurveTo(u+h,e,l,c-d,l,c),this.lineTo(l,f),this.bezierCurveTo(l,f+d,u+h,m,u,m),this.bezierCurveTo(u-h,m,t,f+d,t,f),this.lineTo(t,c)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,s){var o=t-s*Math.cos(i),n=e-s*Math.sin(i),r=t-.9*s*Math.cos(i),a=e-.9*s*Math.sin(i),h=o+s/3*Math.cos(i+.5*Math.PI),d=n+s/3*Math.sin(i+.5*Math.PI),l=o+s/3*Math.cos(i-.5*Math.PI),p=n+s/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,d),this.lineTo(r,a),this.lineTo(l,p),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,s,o){o||(o=[10,5]),0==u&&(u=.001);var n=o.length;this.moveTo(t,e);for(var r=i-t,a=s-e,h=a/r,d=Math.sqrt(r*r+a*a),l=0,p=!0;d>=.1;){var u=o[l++%n];u>d&&(u=d);var c=Math.sqrt(u*u/(1+h*h));0>r&&(c=-c),t+=c,e+=h*c,this[p?"lineTo":"moveTo"](t,e),d-=u,p=!p}}),x.prototype.attachEdge=function(t){this.edges.push(t),this._updateMass()},x.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&this.edges.splice(e,1),this._updateMass()},x.prototype._updateMass=function(){this.mass=50+20*this.edges.length},x.prototype.setProperties=function(t,e){if(t){if(void 0!=t.id&&(this.id=t.id),void 0!=t.label&&(this.label=t.label),void 0!=t.title&&(this.title=t.title),void 0!=t.group&&(this.group=t.group),void 0!=t.x&&(this.x=t.x),void 0!=t.y&&(this.y=t.y),void 0!=t.value&&(this.value=t.value),void 0===this.id)throw"Node must have an id";if(this.group){var i=this.grouplist.get(this.group);for(var s in i)i.hasOwnProperty(s)&&(this[s]=i[s])}if(void 0!=t.shape&&(this.shape=t.shape),void 0!=t.image&&(this.image=t.image),void 0!=t.radius&&(this.radius=t.radius),void 0!=t.color&&(this.color=x.parseColor(t.color)),void 0!=t.fontColor&&(this.fontColor=t.fontColor),void 0!=t.fontSize&&(this.fontSize=t.fontSize),void 0!=t.fontFace&&(this.fontFace=t.fontFace),void 0!=this.image){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.image)}switch(this.xFixed=this.xFixed||void 0!=t.x,this.yFixed=this.yFixed||void 0!=t.y,this.radiusFixed=this.radiusFixed||void 0!=t.radius,"image"==this.shape&&(this.radiusMin=e.nodes.widthMin,this.radiusMax=e.nodes.widthMax),this.shape){case"database":this.draw=this._drawDatabase,this.resize=this._resizeDatabase;break;case"box":this.draw=this._drawBox,this.resize=this._resizeBox;break;case"circle":this.draw=this._drawCircle,this.resize=this._resizeCircle;break;case"ellipse":this.draw=this._drawEllipse,this.resize=this._resizeEllipse;break;case"image":this.draw=this._drawImage,this.resize=this._resizeImage;break;case"text":this.draw=this._drawText,this.resize=this._resizeText;break;case"dot":this.draw=this._drawDot,this.resize=this._resizeShape;break;case"square":this.draw=this._drawSquare,this.resize=this._resizeShape;break;case"triangle":this.draw=this._drawTriangle,this.resize=this._resizeShape;break;case"triangleDown":this.draw=this._drawTriangleDown,this.resize=this._resizeShape;break;case"star":this.draw=this._drawStar,this.resize=this._resizeShape;break;default:this.draw=this._drawEllipse,this.resize=this._resizeEllipse}this._reset()}},x.parseColor=function(t){var e;return C.isString(t)?e={border:t,background:t,highlight:{border:t,background:t}}:(e={},e.background=t.background||"white",e.border=t.border||e.background,C.isString(t.highlight)?e.highlight={border:t.highlight,background:t.highlight}:(e.highlight={},e.highlight.background=t.highlight&&t.highlight.background||e.background,e.highlight.border=t.highlight&&t.highlight.border||e.border)),e},x.prototype.select=function(){this.selected=!0,this._reset()},x.prototype.unselect=function(){this.selected=!1,this._reset()},x.prototype._reset=function(){this.width=void 0,this.height=void 0},x.prototype.getTitle=function(){return this.title},x.prototype.distanceToBorder=function(t,e){var i=1;switch(this.width||this.resize(t),this.shape){case"circle":case"dot":return this.radius+i;case"ellipse":var s=this.width/2,o=this.height/2,n=Math.sin(e)*s,r=Math.cos(e)*o;return s*o/Math.sqrt(n*n+r*r);case"box":case"image":case"text":default:return this.width?Math.min(Math.abs(this.width/2/Math.cos(e)),Math.abs(this.height/2/Math.sin(e)))+i:0}},x.prototype._setForce=function(t,e){this.fx=t,this.fy=e},x.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},x.prototype.discreteStep=function(t){if(!this.xFixed){var e=-this.damping*this.vx,i=(this.fx+e)/this.mass;this.vx+=i/t,this.x+=this.vx/t}if(!this.yFixed){var s=-this.damping*this.vy,o=(this.fy+s)/this.mass;this.vy+=o/t,this.y+=this.vy/t}},x.prototype.isFixed=function(){return this.xFixed&&this.yFixed},x.prototype.isMoving=function(t){return Math.abs(this.vx)>t||Math.abs(this.vy)>t||!this.xFixed&&Math.abs(this.fx)>this.minForce||!this.yFixed&&Math.abs(this.fy)>this.minForce},x.prototype.isSelected=function(){return this.selected},x.prototype.getValue=function(){return this.value},x.prototype.getDistance=function(t,e){var i=this.x-t,s=this.y-e;return Math.sqrt(i*i+s*s)},x.prototype.setValueRange=function(t,e){if(!this.radiusFixed&&void 0!==this.value){var i=(this.radiusMax-this.radiusMin)/(e-t);this.radius=(this.value-t)*i+this.radiusMin}},x.prototype.draw=function(){throw"Draw method not initialized for node"},x.prototype.resize=function(){throw"Resize method not initialized for node"},x.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},x.prototype._resizeImage=function(){if(!this.width){var t,e;if(this.value){var i=this.imageObj.height/this.imageObj.width;t=this.radius||this.imageObj.width,e=this.radius*i||this.imageObj.height}else t=this.imageObj.width,e=this.imageObj.height;this.width=t,this.height=e}},x.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e;this.imageObj?(t.drawImage(this.imageObj,this.left,this.top,this.width,this.height),e=this.y+this.height/2):e=this.y,this._label(t,this.label,this.x,e,void 0,"top")},x.prototype._resizeBox=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e}},x.prototype._drawBox=function(t){this._resizeBox(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,t.roundRect(this.left,this.top,this.width,this.height,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},x.prototype._resizeDatabase=function(t){if(!this.width){var e=5,i=this.getTextSize(t),s=i.width+2*e;this.width=s,this.height=s}},x.prototype._drawDatabase=function(t){this._resizeDatabase(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,t.database(this.x-this.width/2,this.y-.5*this.height,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},x.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),s=Math.max(i.width,i.height)+2*e;this.radius=s/2,this.width=s,this.height=s}},x.prototype._drawCircle=function(t){this._resizeCircle(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,t.circle(this.x,this.y,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},x.prototype._resizeEllipse=function(t){if(!this.width){var e=this.getTextSize(t);this.width=1.5*e.width,this.height=2*e.height,this.widthl;l++)t.fillText(r[l],i,d),d+=h}},x.prototype.getTextSize=function(t){if(void 0!=this.label){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace;for(var e=this.label.split("\n"),i=(this.fontSize+4)*e.length,s=0,o=0,n=e.length;n>o;o++)s=Math.max(s,t.measureText(e[o]).width);return{width:s,height:i}}return{width:0,height:0}},T.prototype.setProperties=function(t,e){if(t){if(void 0!=t.from&&(this.from=this.graph._getNode(t.from)),void 0!=t.to&&(this.to=this.graph._getNode(t.to)),void 0!=t.id&&(this.id=t.id),void 0!=t.style&&(this.style=t.style),void 0!=t.label&&(this.label=t.label),this.label&&(this.fontSize=e.edges.fontSize,this.fontFace=e.edges.fontFace,this.fontColor=e.edges.fontColor,void 0!=t.fontColor&&(this.fontColor=t.fontColor),void 0!=t.fontSize&&(this.fontSize=t.fontSize),void 0!=t.fontFace&&(this.fontFace=t.fontFace)),void 0!=t.title&&(this.title=t.title),void 0!=t.width&&(this.width=t.width),void 0!=t.value&&(this.value=t.value),void 0!=t.length&&(this.length=t.length),t.dash&&(void 0!=t.dash.length&&(this.dash.length=t.dash.length),void 0!=t.dash.gap&&(this.dash.gap=t.dash.gap),void 0!=t.dash.altLength&&(this.dash.altLength=t.dash.altLength)),void 0!=t.color&&(this.color=t.color),!this.from)throw"Node with id "+t.from+" not found";if(!this.to)throw"Node with id "+t.to+" not found";switch(this.widthFixed=this.widthFixed||void 0!=t.width,this.lengthFixed=this.lengthFixed||void 0!=t.length,this.stiffness=1/this.length,this.style){case"line":this.draw=this._drawLine;break;case"arrow":this.draw=this._drawArrow;break;case"arrow-center":this.draw=this._drawArrowCenter;break;case"dash-line":this.draw=this._drawDashLine;break;default:this.draw=this._drawLine}}},T.prototype.getTitle=function(){return this.title},T.prototype.getValue=function(){return this.value},T.prototype.setValueRange=function(t,e){if(!this.widthFixed&&void 0!==this.value){var i=(this.widthMax-this.widthMin)/(e-t);this.width=(this.value-t)*i+this.widthMin}},T.prototype.draw=function(){throw"Method draw not initialized in edge"},T.prototype.isOverlappingWith=function(t){var e=10,i=this.from.x,s=this.from.y,o=this.to.x,n=this.to.y,r=t.left,a=t.top,h=T._dist(i,s,o,n,r,a);return e>h},T.prototype._drawLine=function(t){t.strokeStyle=this.color,t.lineWidth=this._getLineWidth();var e;if(this.from!=this.to)this._line(t),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y));else{var i,s,o=this.length/4,n=this.from;n.width||n.resize(t),n.width>n.height?(i=n.x+n.width/2,s=n.y-o):(i=n.x+o,s=n.y-n.height/2),this._circle(t,i,s,o),e=this._pointOnCircle(i,s,o,.5),this._label(t,this.label,e.x,e.y)}},T.prototype._getLineWidth=function(){return this.from.selected||this.to.selected?Math.min(2*this.width,this.widthMax):this.width},T.prototype._line=function(t){t.beginPath(),t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y),t.stroke()},T.prototype._circle=function(t,e,i,s){t.beginPath(),t.arc(e,i,s,0,2*Math.PI,!1),t.stroke()},T.prototype._label=function(t,e,i,s){if(e){t.font=(this.from.selected||this.to.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle="white";var o=t.measureText(e).width,n=this.fontSize,r=i-o/2,a=s-n/2;t.fillRect(r,a,o,n),t.fillStyle=this.fontColor||"black",t.textAlign="left",t.textBaseline="top",t.fillText(e,r,a)}},T.prototype._drawDashLine=function(t){if(t.strokeStyle=this.color,t.lineWidth=this._getLineWidth(),t.beginPath(),t.lineCap="round",void 0!=this.dash.altLength?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]):void 0!=this.dash.length&&void 0!=this.dash.gap?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap]):(t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y)),t.stroke(),this.label){var e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}},T.prototype._pointOnLine=function(t){return{x:(1-t)*this.from.x+t*this.to.x,y:(1-t)*this.from.y+t*this.to.y}},T.prototype._pointOnCircle=function(t,e,i,s){var o=2*(s-3/8)*Math.PI;return{x:t+i*Math.cos(o),y:e-i*Math.sin(o)}},T.prototype._drawArrowCenter=function(t){var e;if(t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth(),this.from!=this.to){this._line(t);var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),s=10+5*this.width;e=this._pointOnLine(.5),t.arrow(e.x,e.y,i,s),t.fill(),t.stroke(),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y))}else{var o,n,r=this.length/4,a=this.from;a.width||a.resize(t),a.width>a.height?(o=a.x+a.width/2,n=a.y-r):(o=a.x+r,n=a.y-a.height/2),this._circle(t,o,n,r);var i=.2*Math.PI,s=10+5*this.width;e=this._pointOnCircle(o,n,r,.5),t.arrow(e.x,e.y,i,s),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(o,n,r,.5),this._label(t,this.label,e.x,e.y))}},T.prototype._drawArrow=function(t){t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth();var e,i;if(this.from!=this.to){e=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x);var s=this.to.x-this.from.x,o=this.to.y-this.from.y,n=Math.sqrt(s*s+o*o),r=this.from.distanceToBorder(t,e+Math.PI),a=(n-r)/n,h=a*this.from.x+(1-a)*this.to.x,d=a*this.from.y+(1-a)*this.to.y,l=this.to.distanceToBorder(t,e),p=(n-l)/n,u=(1-p)*this.from.x+p*this.to.x,c=(1-p)*this.from.y+p*this.to.y;if(t.beginPath(),t.moveTo(h,d),t.lineTo(u,c),t.stroke(),i=10+5*this.width,t.arrow(u,c,e,i),t.fill(),t.stroke(),this.label){var f=this._pointOnLine(.5);this._label(t,this.label,f.x,f.y)}}else{var m,g,v,y=this.from,w=this.length/4;y.width||y.resize(t),y.width>y.height?(m=y.x+y.width/2,g=y.y-w,v={x:m,y:y.y,angle:.9*Math.PI}):(m=y.x+w,g=y.y-y.height/2,v={x:y.x,y:g,angle:.6*Math.PI}),t.beginPath(),t.arc(m,g,w,0,2*Math.PI,!1),t.stroke(),i=10+5*this.width,t.arrow(v.x,v.y,v.angle,i),t.fill(),t.stroke(),this.label&&(f=this._pointOnCircle(m,g,w,.5),this._label(t,this.label,f.x,f.y))}},T._dist=function(t,e,i,s,o,n){var r=i-t,a=s-e,h=r*r+a*a,d=((o-t)*r+(n-e)*a)/h;d>1?d=1:0>d&&(d=0);var l=t+d*r,p=e+d*a,u=l-o,c=p-n;return Math.sqrt(u*u+c*c)},M.prototype.setPosition=function(t,e){this.x=parseInt(t),this.y=parseInt(e)},M.prototype.setText=function(t){this.frame.innerHTML=t},M.prototype.show=function(t){if(void 0===t&&(t=!0),t){var e=this.frame.clientHeight,i=this.frame.clientWidth,s=this.frame.parentNode.clientHeight,o=this.frame.parentNode.clientWidth,n=this.y-e;n+e+this.padding>s&&(n=s-e-this.padding),this.padding>n&&(n=this.padding);var r=this.x;r+i+this.padding>o&&(r=o-i-this.padding),this.padding>r&&(r=this.padding),this.frame.style.left=r+"px",this.frame.style.top=n+"px",this.frame.style.visibility="visible"}else this.hide()},M.prototype.hide=function(){this.frame.style.visibility="hidden"},Groups=function(){this.clear(),this.defaultIndex=0},Groups.DEFAULT=[{border:"#2B7CE9",background:"#97C2FC",highlight:{border:"#2B7CE9",background:"#D2E5FF"}},{border:"#FFA500",background:"#FFFF00",highlight:{border:"#FFA500",background:"#FFFFA3"}},{border:"#FA0A10",background:"#FB7E81",highlight:{border:"#FA0A10",background:"#FFAFB1"}},{border:"#41A906",background:"#7BE141",highlight:{border:"#41A906",background:"#A1EC76"}},{border:"#E129F0",background:"#EB7DF4",highlight:{border:"#E129F0",background:"#F0B3F5"}},{border:"#7C29F0",background:"#AD85E4",highlight:{border:"#7C29F0",background:"#D3BDF0"}},{border:"#C37F00",background:"#FFA807",highlight:{border:"#C37F00",background:"#FFCA66"}},{border:"#4220FB",background:"#6E6EFD",highlight:{border:"#4220FB",background:"#9B9BFD"}},{border:"#FD5A77",background:"#FFC0CB",highlight:{border:"#FD5A77",background:"#FFD1D9"}},{border:"#4AD63A",background:"#C2FABC",highlight:{border:"#4AD63A",background:"#E6FFE3"}}],Groups.prototype.clear=function(){this.groups={},this.groups.length=function(){var t=0;for(var e in this)this.hasOwnProperty(e)&&t++;return t}},Groups.prototype.get=function(t){var e=this.groups[t];if(void 0==e){var i=this.defaultIndex%Groups.DEFAULT.length;this.defaultIndex++,e={},e.color=Groups.DEFAULT[i],this.groups[t]=e}return e},Groups.prototype.add=function(t,e){return this.groups[t]=e,e.color&&(e.color=x.parseColor(e.color)),e},Images=function(){this.images={},this.callback=void 0},Images.prototype.setOnloadCallback=function(t){this.callback=t},Images.prototype.load=function(t){var e=this.images[t];if(void 0==e){var i=this;e=new Image,this.images[t]=e,e.onload=function(){i.callback&&i.callback(this)},e.src=t}return e},S.prototype.setData=function(t){if(t&&t.dot&&(t.nodes||t.edges))throw new SyntaxError('Data must contain either parameter "dot" or parameter pair "nodes" and "edges", but not both.');if(this.setOptions(t&&t.options),t&&t.dot){if(t&&t.dot){var e=N.util.DOTToGraph(t.dot);return this.setData(e),void 0}}else this._setNodes(t&&t.nodes),this._setEdges(t&&t.edges);this.stabilize&&this._doStabilize(),this.start()},S.prototype.setOptions=function(t){if(t){if(void 0!=t.width&&(this.width=t.width),void 0!=t.height&&(this.height=t.height),void 0!=t.stabilize&&(this.stabilize=t.stabilize),void 0!=t.selectable&&(this.selectable=t.selectable),t.edges){for(var e in t.edges)t.edges.hasOwnProperty(e)&&(this.constants.edges[e]=t.edges[e]);void 0!=t.edges.length&&t.nodes&&void 0==t.nodes.distance&&(this.constants.edges.length=t.edges.length,this.constants.nodes.distance=1.25*t.edges.length),t.edges.fontColor||(this.constants.edges.fontColor=t.edges.color),t.edges.dash&&(void 0!=t.edges.dash.length&&(this.constants.edges.dash.length=t.edges.dash.length),void 0!=t.edges.dash.gap&&(this.constants.edges.dash.gap=t.edges.dash.gap),void 0!=t.edges.dash.altLength&&(this.constants.edges.dash.altLength=t.edges.dash.altLength))}if(t.nodes){for(e in t.nodes)t.nodes.hasOwnProperty(e)&&(this.constants.nodes[e]=t.nodes[e]);t.nodes.color&&(this.constants.nodes.color=x.parseColor(t.nodes.color))}if(t.groups)for(var i in t.groups)if(t.groups.hasOwnProperty(i)){var s=t.groups[i];this.groups.add(i,s)}}this.setSize(this.width,this.height),this._setTranslation(0,0),this._setScale(1)},S.prototype._trigger=function(t,e){O.trigger(this,t,e) +},S.prototype._create=function(){for(;this.containerElement.hasChildNodes();)this.containerElement.removeChild(this.containerElement.firstChild);if(this.frame=document.createElement("div"),this.frame.className="graph-frame",this.frame.style.position="relative",this.frame.style.overflow="hidden",this.frame.canvas=document.createElement("canvas"),this.frame.canvas.style.position="relative",this.frame.appendChild(this.frame.canvas),!this.frame.canvas.getContext){var t=document.createElement("DIV");t.style.color="red",t.style.fontWeight="bold",t.style.padding="10px",t.innerHTML="Error: your browser does not support HTML canvas",this.frame.canvas.appendChild(t)}var e=this,i=function(t){e._onMouseDown(t)},s=function(t){e._onMouseMoveTitle(t)},o=function(t){e._onMouseWheel(t)},n=function(t){e._onTouchStart(t)};N.util.addEventListener(this.frame.canvas,"mousedown",i),N.util.addEventListener(this.frame.canvas,"mousemove",s),N.util.addEventListener(this.frame.canvas,"mousewheel",o),N.util.addEventListener(this.frame.canvas,"touchstart",n),this.containerElement.appendChild(this.frame)},S.prototype._onMouseDown=function(t){if(t=t||window.event,this.selectable&&(this.leftButtonDown&&this._onMouseUp(t),this.leftButtonDown=t.which?1==t.which:1==t.button,this.leftButtonDown||this.touchDown)){var e=this;this.onmousemove||(this.onmousemove=function(t){e._onMouseMove(t)},N.util.addEventListener(document,"mousemove",e.onmousemove)),this.onmouseup||(this.onmouseup=function(t){e._onMouseUp(t)},N.util.addEventListener(document,"mouseup",e.onmouseup)),N.util.preventDefault(t),this.startMouseX=t.clientX||t.targetTouches[0].clientX,this.startMouseY=t.clientY||t.targetTouches[0].clientY,this.startFrameLeft=N.util.getAbsoluteLeft(this.frame.canvas),this.startFrameTop=N.util.getAbsoluteTop(this.frame.canvas),this.startTranslation=this._getTranslation(),this.ctrlKeyDown=t.ctrlKey,this.shiftKeyDown=t.shiftKey;var i={left:this._xToCanvas(this.startMouseX-this.startFrameLeft),top:this._yToCanvas(this.startMouseY-this.startFrameTop),right:this._xToCanvas(this.startMouseX-this.startFrameLeft),bottom:this._yToCanvas(this.startMouseY-this.startFrameTop)},s=this._getNodesOverlappingWith(i);if(this.startClickedObj=s.length>0?s[s.length-1]:void 0,this.startClickedObj){var o=this.nodes[this.startClickedObj.row];this.startClickedObj.xFixed=o.xFixed,this.startClickedObj.yFixed=o.yFixed,o.xFixed=!0,o.yFixed=!0,this.ctrlKeyDown&&o.isSelected()?this._unselectNodes([this.startClickedObj]):this._selectNodes([this.startClickedObj],this.ctrlKeyDown),this.moving||this._redraw()}else this.shiftKeyDown||(this.moved=!1)}},S.prototype._onMouseMove=function(t){if(t=t||window.event,this.selectable){var e=t.clientX||t.targetTouches&&t.targetTouches[0].clientX||0,i=t.clientY||t.targetTouches&&t.targetTouches[0].clientY||0;if(this.mouseX=e,this.mouseY=i,this.startClickedObj){var s=this.nodes[this.startClickedObj.row];this.startClickedObj.xFixed||(s.x=this._xToCanvas(e-this.startFrameLeft)),this.startClickedObj.yFixed||(s.y=this._yToCanvas(i-this.startFrameTop)),this.moving||(this.moving=!0,this.start())}else if(this.shiftKeyDown){void 0==this.frame.selRect&&(this.frame.selRect=document.createElement("DIV"),this.frame.appendChild(this.frame.selRect),this.frame.selRect.style.position="absolute",this.frame.selRect.style.border="1px dashed red");var o=Math.min(this.startMouseX,e)-this.startFrameLeft,n=Math.min(this.startMouseY,i)-this.startFrameTop,r=Math.max(this.startMouseX,e)-this.startFrameLeft,a=Math.max(this.startMouseY,i)-this.startFrameTop;this.frame.selRect.style.left=o+"px",this.frame.selRect.style.top=n+"px",this.frame.selRect.style.width=r-o+"px",this.frame.selRect.style.height=a-n+"px"}else{var h=e-this.startMouseX,d=i-this.startMouseY;this._setTranslation(this.startTranslation.x+h,this.startTranslation.y+d),this._redraw(),this.moved=!0}N.util.preventDefault(t)}},S.prototype._onMouseUp=function(t){if(t=t||window.event,this.selectable){this.onmousemove&&(N.util.removeEventListener(document,"mousemove",this.onmousemove),this.onmousemove=void 0),this.onmouseup&&(N.util.removeEventListener(document,"mouseup",this.onmouseup),this.onmouseup=void 0),N.util.preventDefault(t);var e=t.clientX||this.mouseX||0,i=t.clientY||this.mouseY||0,s=t?t.ctrlKey:window.event.ctrlKey;if(this.startClickedObj){var o=this.nodes[this.startClickedObj.row];o.xFixed=this.startClickedObj.xFixed,o.yFixed=this.startClickedObj.yFixed}else if(this.shiftKeyDown){var n={left:this._xToCanvas(Math.min(this.startMouseX,e)-this.startFrameLeft),top:this._yToCanvas(Math.min(this.startMouseY,i)-this.startFrameTop),right:this._xToCanvas(Math.max(this.startMouseX,e)-this.startFrameLeft),bottom:this._yToCanvas(Math.max(this.startMouseY,i)-this.startFrameTop)},r=this._getNodesOverlappingWith(n);this._selectNodes(r,s),this.redraw(),this.frame.selRect&&(this.frame.removeChild(this.frame.selRect),this.frame.selRect=void 0)}else this.ctrlKeyDown||this.moved||(this._unselectNodes(),this._redraw());this.leftButtonDown=!1,this.ctrlKeyDown=!1}},S.prototype._onMouseWheel=function(t){t=t||window.event;var e=t.clientX,i=t.clientY,s=0;if(t.wheelDelta?s=t.wheelDelta/120:t.detail&&(s=-t.detail/3),s){var o=s/10;0>s&&(o/=1-o);var n=this._getScale(),r=n*(1+o);.01>r&&(r=.01),r>10&&(r=10);var a=N.util.getAbsoluteLeft(this.frame.canvas),h=N.util.getAbsoluteTop(this.frame.canvas),d=e-a,l=i-h,p=this._getTranslation(),u=r/n,c=(1-u)*d+p.x*u,f=(1-u)*l+p.y*u;this._setScale(r),this._setTranslation(c,f),this._redraw()}N.util.preventDefault(t)},S.prototype._onMouseMoveTitle=function(t){t=t||window.event;var e=t.clientX,i=t.clientY;this.startFrameLeft=this.startFrameLeft||N.util.getAbsoluteLeft(this.frame.canvas),this.startFrameTop=this.startFrameTop||N.util.getAbsoluteTop(this.frame.canvas);var s=e-this.startFrameLeft,o=i-this.startFrameTop;this.popupNode&&this._checkHidePopup(s,o);var n=this,r=function(){n._checkShowPopup(s,o)};this.popupTimer&&clearInterval(this.popupTimer),this.leftButtonDown||(this.popupTimer=setTimeout(r,300))},S.prototype._checkShowPopup=function(t,e){var i,s,o={left:this._xToCanvas(t),top:this._yToCanvas(e),right:this._xToCanvas(t),bottom:this._yToCanvas(e)},n=this.popupNode;if(void 0==this.popupNode){var r=this.nodes;for(i=r.length-1;i>=0;i--){var a=r[i];if(void 0!=a.getTitle()&&a.isOverlappingWith(o)){this.popupNode=a;break}}}if(void 0==this.popupNode){var h=this.edges;for(i=0,s=h.length;s>i;i++){var d=h[i];if(void 0!=d.getTitle()&&d.isOverlappingWith(o)){this.popupNode=d;break}}}if(this.popupNode){if(this.popupNode!=n){var l=this;l.popup||(l.popup=new M(l.frame)),l.popup.setPosition(t-3,e-3),l.popup.setText(l.popupNode.getTitle()),l.popup.show()}}else this.popup&&this.popup.hide()},S.prototype._checkHidePopup=function(t,e){var i={left:t,top:e,right:t,bottom:e};this.popupNode&&this.popupNode.isOverlappingWith(i)||(this.popupNode=void 0,this.popup&&this.popup.hide())},S.prototype._onTouchStart=function(t){if(N.util.preventDefault(t),!this.touchDown){this.touchDown=!0;var e=this;this.ontouchmove||(this.ontouchmove=function(t){e._onTouchMove(t)},N.util.addEventListener(document,"touchmove",this.ontouchmove)),this.ontouchend||(this.ontouchend=function(t){e._onTouchEnd(t)},N.util.addEventListener(document,"touchend",this.ontouchend)),this._onMouseDown(t)}},S.prototype._onTouchMove=function(t){N.util.preventDefault(t),this._onMouseMove(t)},S.prototype._onTouchEnd=function(t){N.util.preventDefault(t),this.touchDown=!1,this.ontouchmove&&(N.util.removeEventListener(document,"touchmove",this.ontouchmove),this.ontouchmove=void 0),this.ontouchend&&(N.util.removeEventListener(document,"touchend",this.ontouchend),this.ontouchend=void 0),this._onMouseUp(t)},S.prototype._unselectNodes=function(t,e){var i,s,o,n=!1;if(t)for(i=0,s=t.length;s>i;i++){o=t[i].row,this.nodes[o].unselect();for(var r=0;this.selection.length>r;)this.selection[r].row==o?(this.selection.splice(r,1),n=!0):r++}else if(this.selection&&this.selection.length){for(i=0,s=this.selection.length;s>i;i++)o=this.selection[i].row,this.nodes[o].unselect(),n=!0;this.selection=[]}return!n||1!=e&&void 0!=e||this._trigger("select"),n},S.prototype._selectNodes=function(t,e){var i,s,o=!1,n=!0;if(t.length!=this.selection.length)n=!1;else for(i=0,s=Math.min(t.length,this.selection.length);s>i;i++)if(t[i].row!=this.selection[i].row){n=!1;break}if(n)return o;if(void 0==e||0==e){var r=!1;o=this._unselectNodes(void 0,r)}for(i=0,s=t.length;s>i;i++){for(var a=t[i].row,h=!1,d=0,l=this.selection.length;l>d;d++)if(this.selection[d].row==a){h=!0;break}h||(this.nodes[a].select(),this.selection.push(t[i]),o=!0)}return o&&this._trigger("select"),o},S.prototype._getNodesOverlappingWith=function(t){for(var e=[],i=0;this.nodes.length>i;i++)if(this.nodes[i].isOverlappingWith(t)){var s={row:i};e.push(s)}return e},S.prototype.getSelection=function(){for(var t=[],e=0;this.selection.length>e;e++){var i=this.selection[e].row;t.push({row:i})}return t},S.prototype.setSelection=function(t){var e,i,s;if(void 0==t.length)throw"Selection must be an array with objects";for(e=0,i=this.selection.length;i>e;e++)s=this.selection[e].row,this.nodes[s].unselect();for(this.selection=[],e=0,i=t.length;i>e;e++){if(s=t[e].row,void 0==s)throw"Parameter row missing in selection object";if(s>this.nodes.length-1)throw"Parameter row out of range";var o={row:s};this.selection.push(o),this.nodes[s].select()}this.redraw()},S.prototype._getConnectionCount=function(t){function e(t){for(var e=[],s=0,o=t.length;o>s;s++)for(var n=t[s],r=0,a=i.length;a>r;r++){var h=null;i[r].from==n?h=i[r].to:i[r].to==n&&(h=i[r].from);var d,l;if(h)for(d=0,l=t.length;l>d;d++)if(t[d]==h){h=null;break}if(h)for(d=0,l=e.length;l>d;d++)if(e[d]==h){h=null;break}h&&e.push(h)}return e}var i=this.edges;void 0==t&&(t=1);var s,o,n=[],r=this.nodes;for(s=0,o=r.length;o>s;s++){for(var a=[r[s]],h=0;t>h;h++)a=a.concat(e(a));n.push(a)}var d=[];for(s=0,len=n.length;len>s;s++)d.push(n[s].length);return d},S.prototype.setSize=function(t,e){this.frame.style.width=t,this.frame.style.height=e,this.frame.canvas.style.width="100%",this.frame.canvas.style.height="100%",this.frame.canvas.width=this.frame.canvas.clientWidth,this.frame.canvas.height=this.frame.canvas.clientHeight},S.prototype._setNodes=function(t){if(this.selection=[],this.nodes=[],this.moving=!1,t){for(var e=!1,i=t.length,s=0;i>s;s++){var o=t[s];if(void 0!=o.value&&(e=!0),void 0==o.id)throw"Column 'id' missing in table with nodes (row "+s+")";this._createNode(o)}e&&this._updateValueRange(this.nodes),this._reposition()}},S.prototype._createNode=function(t){var e,i,s,o,n=t.action?t.action:"update";if("create"===n)s=new x(t,this.images,this.groups,this.constants),e=t.id,i=void 0!==e?this._findNode(e):void 0,void 0!==i?(o=this.nodes[i],this.nodes[i]=s,o.selected&&this._unselectNodes([{row:i}],!1)):this.nodes.push(s),s.isFixed()||(this.moving=!0);else if("update"===n){if(e=t.id,void 0===e)throw"Cannot update a node without id";i=this._findNode(e),void 0!==i?this.nodes[i].setProperties(t,this.constants):(s=new x(t,this.images,this.groups,this.constants),this.nodes.push(s),s.isFixed()||(this.moving=!0))}else{if("delete"!==n)throw"Unknown action "+n+". Choose 'create', 'update', or 'delete'.";if(e=t.id,void 0===e)throw"Cannot delete node without its id";if(i=this._findNode(e),void 0===i)throw"Node with id "+e+" not found";o=this.nodes[i],o.selected&&this._unselectNodes([{row:i}],!1),this.nodes.splice(i,1)}},S.prototype._findNode=function(t){for(var e=this.nodes,i=0,s=e.length;s>i;i++)if(e[i].id===t)return i;return void 0},S.prototype._findNodeByRow=function(t){return this.nodes[t]},S.prototype._setEdges=function(t){if(this.edges=[],t){for(var e=!1,i=t.length,s=0;i>s;s++){var o=t[s];if(void 0===o.from)throw"Column 'from' missing in table with edges (row "+s+")";if(void 0===o.to)throw"Column 'to' missing in table with edges (row "+s+")";void 0!=o.value&&(e=!0),this._createEdge(o)}e&&this._updateValueRange(this.edges)}},S.prototype._createEdge=function(t){var e,i,s,o,n=t.action?t.action:"create";if("create"===n)e=t.id,i=void 0!==e?this._findEdge(e):void 0,s=new T(t,this,this.constants),void 0!==i?(o=this.edges[i],o.from.detachEdge(o),o.to.detachEdge(o),this.edges[i]=s):this.edges.push(s),s.from.attachEdge(s),s.to.attachEdge(s);else if("update"===n){if(e=t.id,void 0===e)throw"Cannot update a edge without id";i=this._findEdge(e),void 0!==i?(s=this.edges[i],s.from.detachEdge(s),s.to.detachEdge(s),s.setProperties(t,this.constants),s.from.attachEdge(s),s.to.attachEdge(s)):(s=new T(t,this,this.constants),s.from.attachEdge(s),s.to.attachEdge(s),this.edges.push(s))}else{if("delete"!==n)throw"Unknown action "+n+". Choose 'create', 'update', or 'delete'.";if(e=t.id,void 0===e)throw"Cannot delete edge without its id";if(i=this._findEdge(e),void 0===i)throw"Edge with id "+e+" not found";o=this.edges[e],s.from.detachEdge(o),s.to.detachEdge(o),this.edges.splice(i,1)}},S.prototype._updateNodeReferences=function(t,e){for(var i=this.edges,s=0,o=i.length;o>s;s++){var n=i[s];n.from===t&&(n.from=e),n.to===t&&(n.to=e)}},S.prototype._findEdge=function(t){for(var e=this.edges,i=0,s=e.length;s>i;i++)if(e[i].id===t)return i;return void 0},S.prototype._findEdgeByRow=function(t){return this.edges[t]},S.prototype._updateValueRange=function(t){var e,i=t.length,s=void 0,o=void 0;for(e=0;i>e;e++){var n=t[e].getValue();void 0!==n&&(s=void 0===s?n:Math.min(n,s),o=void 0===o?n:Math.max(n,o))}if(void 0!==s&&void 0!==o)for(e=0;i>e;e++)t[e].setValueRange(s,o)},S.prototype.redraw=function(){this.setSize(this.width,this.height),this._redraw()},S.prototype._redraw=function(){var t=this.frame.canvas.getContext("2d"),e=this.frame.canvas.width,i=this.frame.canvas.height;t.clearRect(0,0,e,i),t.save(),t.translate(this.translation.x,this.translation.y),t.scale(this.scale,this.scale),this._drawEdges(t),this._drawNodes(t),t.restore()},S.prototype._setTranslation=function(t,e){void 0===this.translation&&(this.translation={x:0,y:0}),void 0!==t&&(this.translation.x=t),void 0!==e&&(this.translation.y=e)},S.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},S.prototype._setScale=function(t){this.scale=t},S.prototype._getScale=function(){return this.scale},S.prototype._xToCanvas=function(t){return(t-this.translation.x)/this.scale},S.prototype._canvasToX=function(t){return t*this.scale+this.translation.x},S.prototype._yToCanvas=function(t){return(t-this.translation.y)/this.scale},S.prototype._canvasToY=function(t){return t*this.scale+this.translation.y},S.prototype._getNode=function(t){for(var e=0;this.nodes.length>e;e++)if(this.nodes[e].id==t)return this.nodes[e];return null},S.prototype._drawNodes=function(t){for(var e=this.nodes,i=[],s=0,o=e.length;o>s;s++)e[s].isSelected()?i.push(s):e[s].draw(t);for(var n=0,r=i.length;r>n;n++)e[i[n]].draw(t)},S.prototype._drawEdges=function(t){for(var e=this.edges,i=0,s=e.length;s>i;i++)e[i].draw(t)},S.prototype._reposition=function(){for(var t=2*this.constants.edges.length,e=this.frame.canvas.clientWidth/2,i=this.frame.canvas.clientHeight/2,s=0;this.nodes.length>s;s++){var o=2*Math.PI*(s/this.nodes.length);this.nodes[s].xFixed||(this.nodes[s].x=e+t*Math.cos(o)),this.nodes[s].yFixed||(this.nodes[s].y=i+t*Math.sin(o))}},S.prototype._doStabilize=function(){new Date;for(var t=0,e=this.constants.minVelocity,i=!1;!i&&this.constants.maxIterations>t;)this._calculateForces(),this._discreteStepNodes(),i=!this._isMoving(e),t++;new Date},S.prototype._calculateForces=function(){for(var t=this.nodes,e=this.edges,i=.01,s=this.frame.canvas.clientWidth/2,o=this.frame.canvas.clientHeight/2,n=0;t.length>n;n++){var r=s-t[n].x,a=o-t[n].y,h=Math.atan2(a,r),d=Math.cos(h)*i,l=Math.sin(h)*i;this.nodes[n]._setForce(d,l)}for(var p=this.constants.nodes.distance,u=10,n=0;t.length>n;n++)for(var c=n+1;this.nodes.length>c;c++){var r=t[c].x-t[n].x,a=t[c].y-t[n].y,f=Math.sqrt(r*r+a*a),h=Math.atan2(a,r),m=1/(1+Math.exp((f/p-1)*u)),d=Math.cos(h)*m,l=Math.sin(h)*m;this.nodes[n]._addForce(-d,-l),this.nodes[c]._addForce(d,l)}for(var g=0,v=e.length;v>g;g++){var y=e[g],r=y.to.x-y.from.x,a=y.to.y-y.from.y,w=y.length,b=Math.sqrt(r*r+a*a),h=Math.atan2(a,r),_=y.stiffness*(w-b),d=Math.cos(h)*_,l=Math.sin(h)*_;y.from._addForce(-d,-l),y.to._addForce(d,l)}},S.prototype._isMoving=function(t){for(var e=this.nodes,i=0,s=e.length;s>i;i++)if(e[i].isMoving(t))return!0;return!1},S.prototype._discreteStepNodes=function(){for(var t=this.refreshRate/1e3,e=this.nodes,i=0,s=e.length;s>i;i++)e[i].discreteStep(t)},S.prototype.start=function(){if(this.moving){this._calculateForces(),this._discreteStepNodes();var t=this.constants.minVelocity;this.moving=this._isMoving(t)}if(this.moving){if(!this.timer){var e=this;this.timer=window.setTimeout(function(){e.timer=void 0,e.start(),e._redraw()},this.refreshRate)}}else this._redraw()},S.prototype.stop=function(){this.timer&&(window.clearInterval(this.timer),this.timer=void 0)};var N={util:C,events:O,Controller:d,DataSet:n,DataView:r,Range:h,Stack:a,TimeStep:TimeStep,EventBus:o,components:{items:{Item:m,ItemBox:g,ItemPoint:v,ItemRange:y},Component:l,Panel:p,RootPanel:u,ItemSet:f,TimeAxis:c},graph:{Node:x,Edge:T,Popup:M,Groups:Groups,Images:Images},Timeline:_,Graph:S};s!==void 0&&(s=N),i!==void 0&&i.exports!==void 0&&(i.exports=N),"function"==typeof t&&t(function(){return N}),"undefined"!=typeof window&&(window.vis=N),C.loadCss("/* vis.js stylesheet */\n\n.graph {\n position: relative;\n border: 1px solid #bfbfbf;\n}\n\n.graph .panel {\n position: absolute;\n}\n\n.graph .groupset {\n position: absolute;\n padding: 0;\n margin: 0;\n}\n\n\n.graph .itemset {\n position: absolute;\n padding: 0;\n margin: 0;\n overflow: hidden;\n}\n\n.graph .background {\n}\n\n.graph .foreground {\n}\n\n.graph .itemset-axis {\n position: absolute;\n}\n\n.graph .groupset .itemset-axis {\n border-top: 1px solid #bfbfbf;\n}\n\n/* TODO: with orientation=='bottom', this will more or less overlap with timeline axis\n.graph .groupset .itemset-axis:last-child {\n border-top: none;\n}\n*/\n\n\n.graph .item {\n position: absolute;\n color: #1A1A1A;\n border-color: #97B0F8;\n background-color: #D5DDF6;\n display: inline-block;\n}\n\n.graph .item.selected {\n border-color: #FFC200;\n background-color: #FFF785;\n z-index: 999;\n}\n\n.graph .item.cluster {\n /* TODO: use another color or pattern? */\n background: #97B0F8 url('img/cluster_bg.png');\n color: white;\n}\n.graph .item.cluster.point {\n border-color: #D5DDF6;\n}\n\n.graph .item.box {\n text-align: center;\n border-style: solid;\n border-width: 1px;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.graph .item.point {\n background: none;\n}\n\n.graph .dot {\n border: 5px solid #97B0F8;\n position: absolute;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.graph .item.range {\n overflow: hidden;\n border-style: solid;\n border-width: 1px;\n border-radius: 2px;\n -moz-border-radius: 2px; /* For Firefox 3.6 and older */\n}\n\n.graph .item.range .drag-left {\n cursor: w-resize;\n z-index: 1000;\n}\n\n.graph .item.range .drag-right {\n cursor: e-resize;\n z-index: 1000;\n}\n\n.graph .item.range .content {\n position: relative;\n display: inline-block;\n}\n\n.graph .item.line {\n position: absolute;\n width: 0;\n border-left-width: 1px;\n border-left-style: solid;\n}\n\n.graph .item .content {\n margin: 5px;\n white-space: nowrap;\n overflow: hidden;\n}\n\n/* TODO: better css name, 'graph' is way to generic */\n\n.graph {\n overflow: hidden;\n}\n\n.graph .axis {\n position: relative;\n}\n\n.graph .axis .text {\n position: absolute;\n color: #4d4d4d;\n padding: 3px;\n white-space: nowrap;\n}\n\n.graph .axis .text.measure {\n position: absolute;\n padding-left: 0;\n padding-right: 0;\n margin-left: 0;\n margin-right: 0;\n visibility: hidden;\n}\n\n.graph .axis .grid.vertical {\n position: absolute;\n width: 0;\n border-right: 1px solid;\n}\n\n.graph .axis .grid.horizontal {\n position: absolute;\n left: 0;\n width: 100%;\n height: 0;\n border-bottom: 1px solid;\n}\n\n.graph .axis .grid.minor {\n border-color: #e5e5e5;\n}\n\n.graph .axis .grid.major {\n border-color: #bfbfbf;\n}\n\n")})()},{moment:2}],2:[function(e,i){(function(){(function(s){function o(t,e){return function(i){return p(t.call(this,i),e)}}function n(t){return function(e){return this.lang().ordinal(t.call(this,e))}}function r(){}function a(t){d(this,t)}function h(t){var e=this._data={},i=t.years||t.year||t.y||0,s=t.months||t.month||t.M||0,o=t.weeks||t.week||t.w||0,n=t.days||t.day||t.d||0,r=t.hours||t.hour||t.h||0,a=t.minutes||t.minute||t.m||0,h=t.seconds||t.second||t.s||0,d=t.milliseconds||t.millisecond||t.ms||0;this._milliseconds=d+1e3*h+6e4*a+36e5*r,this._days=n+7*o,this._months=s+12*i,e.milliseconds=d%1e3,h+=l(d/1e3),e.seconds=h%60,a+=l(h/60),e.minutes=a%60,r+=l(a/60),e.hours=r%24,n+=l(r/24),n+=7*o,e.days=n%30,s+=l(n/30),e.months=s%12,i+=l(s/12),e.years=i}function d(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function l(t){return 0>t?Math.ceil(t):Math.floor(t)}function p(t,e){for(var i=t+"";e>i.length;)i="0"+i;return i}function u(t,e,i){var s,o=e._milliseconds,n=e._days,r=e._months;o&&t._d.setTime(+t+o*i),n&&t.date(t.date()+n*i),r&&(s=t.date(),t.date(1).month(t.month()+r*i).date(Math.min(s,t.daysInMonth())))}function c(t){return"[object Array]"===Object.prototype.toString.call(t)}function f(t,e){var i,s=Math.min(t.length,e.length),o=Math.abs(t.length-e.length),n=0;for(i=0;s>i;i++)~~t[i]!==~~e[i]&&n++;return n+o}function m(t,e){return e.abbr=t,H[t]||(H[t]=new r),H[t].set(e),H[t]}function g(t){return t?(!H[t]&&P&&e("./lang/"+t),H[t]):F.fn._lang}function v(t){return t.match(/\[.*\]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function y(t){var e,i,s=t.match(j);for(e=0,i=s.length;i>e;e++)s[e]=ae[s[e]]?ae[s[e]]:v(s[e]);return function(o){var n="";for(e=0;i>e;e++)n+="function"==typeof s[e].call?s[e].call(o,t):s[e];return n}}function w(t,e){function i(e){return t.lang().longDateFormat(e)||e}for(var s=5;s--&&U.test(e);)e=e.replace(U,i);return oe[e]||(oe[e]=y(e)),oe[e](t)}function b(t){switch(t){case"DDDD":return q;case"YYYY":return V;case"YYYYY":return X;case"S":case"SS":case"SSS":case"DDD":return B;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":case"a":case"A":return K;case"X":return J;case"Z":case"ZZ":return G;case"T":return Z;case"MM":case"DD":case"YY":case"HH":case"hh":case"mm":case"ss":case"M":case"D":case"d":case"H":case"h":case"m":case"s":return W;default:return RegExp(t.replace("\\",""))}}function _(t,e,i){var s,o=i._a;switch(t){case"M":case"MM":o[1]=null==e?0:~~e-1;break;case"MMM":case"MMMM":s=g(i._l).monthsParse(e),null!=s?o[1]=s:i._isValid=!1;break;case"D":case"DD":case"DDD":case"DDDD":null!=e&&(o[2]=~~e);break;case"YY":o[0]=~~e+(~~e>68?1900:2e3);break;case"YYYY":case"YYYYY":o[0]=~~e;break;case"a":case"A":i._isPm="pm"===(e+"").toLowerCase();break;case"H":case"HH":case"h":case"hh":o[3]=~~e;break;case"m":case"mm":o[4]=~~e;break;case"s":case"ss":o[5]=~~e;break;case"S":case"SS":case"SSS":o[6]=~~(1e3*("0."+e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,s=(e+"").match(ee),s&&s[1]&&(i._tzh=~~s[1]),s&&s[2]&&(i._tzm=~~s[2]),s&&"+"===s[0]&&(i._tzh=-i._tzh,i._tzm=-i._tzm)}null==e&&(i._isValid=!1)}function x(t){var e,i,s=[];if(!t._d){for(e=0;7>e;e++)t._a[e]=s[e]=null==t._a[e]?2===e?1:0:t._a[e];s[3]+=t._tzh||0,s[4]+=t._tzm||0,i=new Date(0),t._useUTC?(i.setUTCFullYear(s[0],s[1],s[2]),i.setUTCHours(s[3],s[4],s[5],s[6])):(i.setFullYear(s[0],s[1],s[2]),i.setHours(s[3],s[4],s[5],s[6])),t._d=i}}function T(t){var e,i,s=t._f.match(j),o=t._i;for(t._a=[],e=0;s.length>e;e++)i=(b(s[e]).exec(o)||[])[0],i&&(o=o.slice(o.indexOf(i)+i.length)),ae[s[e]]&&_(s[e],i,t);t._isPm&&12>t._a[3]&&(t._a[3]+=12),t._isPm===!1&&12===t._a[3]&&(t._a[3]=0),x(t)}function M(t){for(var e,i,s,o,n=99;t._f.length;){if(e=d({},t),e._f=t._f.pop(),T(e),i=new a(e),i.isValid()){s=i;break}o=f(e._a,i.toArray()),n>o&&(n=o,s=i)}d(t,s)}function S(t){var e,i=t._i;if(Q.exec(i)){for(t._f="YYYY-MM-DDT",e=0;4>e;e++)if(te[e][1].exec(i)){t._f+=te[e][0];break}G.exec(i)&&(t._f+=" Z"),T(t)}else t._d=new Date(i)}function E(t){var e=t._i,i=R.exec(e);e===s?t._d=new Date:i?t._d=new Date(+i[1]):"string"==typeof e?S(t):c(e)?(t._a=e.slice(0),x(t)):t._d=e instanceof Date?new Date(+e):new Date(e)}function C(t,e,i,s,o){return o.relativeTime(e||1,!!i,t,s)}function D(t,e,i){var s=z(Math.abs(t)/1e3),o=z(s/60),n=z(o/60),r=z(n/24),a=z(r/365),h=45>s&&["s",s]||1===o&&["m"]||45>o&&["mm",o]||1===n&&["h"]||22>n&&["hh",n]||1===r&&["d"]||25>=r&&["dd",r]||45>=r&&["M"]||345>r&&["MM",z(r/30)]||1===a&&["y"]||["yy",a];return h[2]=e,h[3]=t>0,h[4]=i,C.apply({},h)}function L(t,e,i){var s=i-e,o=i-t.day();return o>s&&(o-=7),s-7>o&&(o+=7),Math.ceil(F(t).add("d",o).dayOfYear()/7)}function O(t){var e=t._i,i=t._f;return null===e||""===e?null:("string"==typeof e&&(t._i=e=g().preparse(e)),F.isMoment(e)?(t=d({},e),t._d=new Date(+e._d)):i?c(i)?M(t):T(t):E(t),new a(t))}function N(t,e){F.fn[t]=F.fn[t+"s"]=function(t){var i=this._isUTC?"UTC":"";return null!=t?(this._d["set"+i+e](t),this):this._d["get"+i+e]()}}function k(t){F.duration.fn[t]=function(){return this._data[t]}}function A(t,e){F.duration.fn["as"+t]=function(){return+this/e}}for(var F,I,Y="2.0.0",z=Math.round,H={},P=i!==s&&i.exports,R=/^\/?Date\((\-?\d+)/i,j=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYY|YYYY|YY|a|A|hh?|HH?|mm?|ss?|SS?S?|X|zz?|ZZ?|.)/g,U=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,W=/\d\d?/,B=/\d{1,3}/,q=/\d{3}/,V=/\d{1,4}/,X=/[+\-]?\d{1,6}/,K=/[0-9]*[a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF]+\s*?[\u0600-\u06FF]+/i,G=/Z|[\+\-]\d\d:?\d\d/i,Z=/T/i,J=/[\+\-]?\d+(\.\d{1,3})?/,Q=/^\s*\d{4}-\d\d-\d\d((T| )(\d\d(:\d\d(:\d\d(\.\d\d?\d?)?)?)?)?([\+\-]\d\d:?\d\d)?)?/,$="YYYY-MM-DDTHH:mm:ssZ",te=[["HH:mm:ss.S",/(T| )\d\d:\d\d:\d\d\.\d{1,3}/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],ee=/([\+\-]|\d\d)/gi,ie="Month|Date|Hours|Minutes|Seconds|Milliseconds".split("|"),se={Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6},oe={},ne="DDD w W M D d".split(" "),re="M D H h m s w W".split(" "),ae={M:function(){return this.month()+1},MMM:function(t){return this.lang().monthsShort(this,t)},MMMM:function(t){return this.lang().months(this,t)},D:function(){return this.date()},DDD:function(){return this.dayOfYear()},d:function(){return this.day()},dd:function(t){return this.lang().weekdaysMin(this,t)},ddd:function(t){return this.lang().weekdaysShort(this,t)},dddd:function(t){return this.lang().weekdays(this,t)},w:function(){return this.week()},W:function(){return this.isoWeek()},YY:function(){return p(this.year()%100,2)},YYYY:function(){return p(this.year(),4)},YYYYY:function(){return p(this.year(),5)},a:function(){return this.lang().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.lang().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return~~(this.milliseconds()/100)},SS:function(){return p(~~(this.milliseconds()/10),2)},SSS:function(){return p(this.milliseconds(),3)},Z:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(~~(t/60),2)+":"+p(~~t%60,2)},ZZ:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(~~(10*t/6),4)},X:function(){return this.unix()}};ne.length;)I=ne.pop(),ae[I+"o"]=n(ae[I]);for(;re.length;)I=re.pop(),ae[I+I]=o(ae[I],2);for(ae.DDDD=o(ae.DDD,3),r.prototype={set:function(t){var e,i;for(i in t)e=t[i],"function"==typeof e?this[i]=e:this["_"+i]=e},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(t){return this._months[t.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(t){return this._monthsShort[t.month()]},monthsParse:function(t){var e,i,s;for(this._monthsParse||(this._monthsParse=[]),e=0;12>e;e++)if(this._monthsParse[e]||(i=F([2e3,e]),s="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[e]=RegExp(s.replace(".",""),"i")),this._monthsParse[e].test(t))return e},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(t){return this._weekdays[t.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(t){return this._weekdaysShort[t.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(t){return this._weekdaysMin[t.day()]},_longDateFormat:{LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D YYYY",LLL:"MMMM D YYYY LT",LLLL:"dddd, MMMM D YYYY LT"},longDateFormat:function(t){var e=this._longDateFormat[t];return!e&&this._longDateFormat[t.toUpperCase()]&&(e=this._longDateFormat[t.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t]=e),e},meridiem:function(t,e,i){return t>11?i?"pm":"PM":i?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[last] dddd [at] LT",sameElse:"L"},calendar:function(t,e){var i=this._calendar[t];return"function"==typeof i?i.apply(e):i},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(t,e,i,s){var o=this._relativeTime[i];return"function"==typeof o?o(t,e,i,s):o.replace(/%d/i,t)},pastFuture:function(t,e){var i=this._relativeTime[t>0?"future":"past"];return"function"==typeof i?i(e):i.replace(/%s/i,e)},ordinal:function(t){return this._ordinal.replace("%d",t)},_ordinal:"%d",preparse:function(t){return t},postformat:function(t){return t},week:function(t){return L(t,this._week.dow,this._week.doy)},_week:{dow:0,doy:6}},F=function(t,e,i){return O({_i:t,_f:e,_l:i,_isUTC:!1})},F.utc=function(t,e,i){return O({_useUTC:!0,_isUTC:!0,_l:i,_i:t,_f:e})},F.unix=function(t){return F(1e3*t)},F.duration=function(t,e){var i,s=F.isDuration(t),o="number"==typeof t,n=s?t._data:o?{}:t;return o&&(e?n[e]=t:n.milliseconds=t),i=new h(n),s&&t.hasOwnProperty("_lang")&&(i._lang=t._lang),i},F.version=Y,F.defaultFormat=$,F.lang=function(t,e){return t?(e?m(t,e):H[t]||g(t),F.duration.fn._lang=F.fn._lang=g(t),s):F.fn._lang._abbr},F.langData=function(t){return t&&t._lang&&t._lang._abbr&&(t=t._lang._abbr),g(t)},F.isMoment=function(t){return t instanceof a},F.isDuration=function(t){return t instanceof h},F.fn=a.prototype={clone:function(){return F(this)},valueOf:function(){return+this._d},unix:function(){return Math.floor(+this._d/1e3)},toString:function(){return this.format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._d},toJSON:function(){return F.utc(this).format("YYYY-MM-DD[T]HH:mm:ss.SSS[Z]")},toArray:function(){var t=this;return[t.year(),t.month(),t.date(),t.hours(),t.minutes(),t.seconds(),t.milliseconds()]},isValid:function(){return null==this._isValid&&(this._isValid=this._a?!f(this._a,(this._isUTC?F.utc(this._a):F(this._a)).toArray()):!isNaN(this._d.getTime())),!!this._isValid},utc:function(){return this._isUTC=!0,this},local:function(){return this._isUTC=!1,this},format:function(t){var e=w(this,t||F.defaultFormat);return this.lang().postformat(e)},add:function(t,e){var i;return i="string"==typeof t?F.duration(+e,t):F.duration(t,e),u(this,i,1),this},subtract:function(t,e){var i;return i="string"==typeof t?F.duration(+e,t):F.duration(t,e),u(this,i,-1),this},diff:function(t,e,i){var s,o,n=this._isUTC?F(t).utc():F(t).local(),r=6e4*(this.zone()-n.zone());return e&&(e=e.replace(/s$/,"")),"year"===e||"month"===e?(s=432e5*(this.daysInMonth()+n.daysInMonth()),o=12*(this.year()-n.year())+(this.month()-n.month()),o+=(this-F(this).startOf("month")-(n-F(n).startOf("month")))/s,"year"===e&&(o/=12)):(s=this-n-r,o="second"===e?s/1e3:"minute"===e?s/6e4:"hour"===e?s/36e5:"day"===e?s/864e5:"week"===e?s/6048e5:s),i?o:l(o) +},from:function(t,e){return F.duration(this.diff(t)).lang(this.lang()._abbr).humanize(!e)},fromNow:function(t){return this.from(F(),t)},calendar:function(){var t=this.diff(F().startOf("day"),"days",!0),e=-6>t?"sameElse":-1>t?"lastWeek":0>t?"lastDay":1>t?"sameDay":2>t?"nextDay":7>t?"nextWeek":"sameElse";return this.format(this.lang().calendar(e,this))},isLeapYear:function(){var t=this.year();return 0===t%4&&0!==t%100||0===t%400},isDST:function(){return this.zone()+F(t).startOf(e)},isBefore:function(t,e){return e=e!==s?e:"millisecond",+this.clone().startOf(e)<+F(t).startOf(e)},isSame:function(t,e){return e=e!==s?e:"millisecond",+this.clone().startOf(e)===+F(t).startOf(e)},zone:function(){return this._isUTC?0:this._d.getTimezoneOffset()},daysInMonth:function(){return F.utc([this.year(),this.month()+1,0]).date()},dayOfYear:function(t){var e=z((F(this).startOf("day")-F(this).startOf("year"))/864e5)+1;return null==t?e:this.add("d",t-e)},isoWeek:function(t){var e=L(this,1,4);return null==t?e:this.add("d",7*(t-e))},week:function(t){var e=this.lang().week(this);return null==t?e:this.add("d",7*(t-e))},lang:function(t){return t===s?this._lang:(this._lang=g(t),this)}},I=0;ie.length>I;I++)N(ie[I].toLowerCase().replace(/s$/,""),ie[I]);N("year","FullYear"),F.fn.days=F.fn.day,F.fn.weeks=F.fn.week,F.fn.isoWeeks=F.fn.isoWeek,F.duration.fn=h.prototype={weeks:function(){return l(this.days()/7)},valueOf:function(){return this._milliseconds+864e5*this._days+2592e6*this._months},humanize:function(t){var e=+this,i=D(e,!t,this.lang());return t&&(i=this.lang().pastFuture(e,i)),this.lang().postformat(i)},lang:F.fn.lang};for(I in se)se.hasOwnProperty(I)&&(A(I,se[I]),k(I.toLowerCase()));A("Weeks",6048e5),F.lang("en",{ordinal:function(t){var e=t%10,i=1===~~(t%100/10)?"th":1===e?"st":2===e?"nd":3===e?"rd":"th";return t+i}}),P&&(i.exports=F),"undefined"==typeof ender&&(this.moment=F),"function"==typeof t&&t.amd&&t("moment",[],function(){return F})}).call(this)})()},{}]},{},[1])(1)}); \ No newline at end of file From 2914715858585e8f2194476e14718f0651def4ea Mon Sep 17 00:00:00 2001 From: josdejong Date: Fri, 7 Jun 2013 14:59:53 +0200 Subject: [PATCH 11/52] Index page updated --- css/style.css | 10 ++--- index.html | 39 ++++++++++++++---- updateversion.js | 102 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 12 deletions(-) create mode 100644 updateversion.js diff --git a/css/style.css b/css/style.css index 5852141a..07dca978 100644 --- a/css/style.css +++ b/css/style.css @@ -32,7 +32,6 @@ div.nav ul li { text-transform: uppercase; font-weight: normal; font-size: 11pt; - color: #2B7CE9; list-style: none; margin-top: 5px; @@ -48,12 +47,13 @@ div.nav ul li ul li { list-style: none; } -a.nav { - color: #4D4D4D; +div.nav a { + color: #2B7CE9; } -a.nav:hover { - color: #2B7CE9; +.download td { + border: none; + padding: 5px 20px 5px 0; } .gallery .thumb { diff --git a/index.html b/index.html index 26e4f06b..a2eadac1 100644 --- a/index.html +++ b/index.html @@ -50,30 +50,45 @@

Install

npm

- Install via npm:
 npm install vis
 

bower

- Install via bower:
 bower install vis
 

download

- Or download the library from the github project: - https://github.com/almende/vis.git. + + + + + + + + + + +
+ Development + (version 0.0.9) + + 372 kB, uncompressed with comments +
+ Production + (version 0.0.9) + + 33 kB, minified and gzipped +
+

Example

A basic example demonstrating how to use the vis.js timeline is shown below. -

- -

More examples can be found in the examples directory.

@@ -112,8 +127,14 @@ bower install vis + This gallery gives an idea of the features and possibilities of the library. + The source code of the examples can be found in the + examples directory.

Timeline

+

+ The timeline from vis.js displays different types of data on a timeline. +

@@ -67,19 +67,19 @@ bower install vis Development - (version 0.0.9) + (version 0.1.0) - 372 kB, uncompressed with comments + 384 kB, uncompressed with comments Production - (version 0.0.9) + (version 0.1.0) - 33 kB, minified and gzipped + 34 kB, minified and gzipped @@ -275,14 +275,9 @@ bower install vis

Docs

- The following documentation is available: + Documentation is available here: + Documentation

-

License

diff --git a/vis.js b/vis.js index a3917f16..b4a4d086 100644 --- a/vis.js +++ b/vis.js @@ -4,8 +4,8 @@ * * A dynamic, browser-based visualization library. * - * @version 0.0.9 - * @date 2013-06-07 + * @version 0.1.0 + * @date 2013-06-20 * * @license * Copyright (C) 2011-2013 Almende B.V, http://almende.com @@ -129,7 +129,7 @@ util.extend = function (a, b) { }; /** - * Cast an object to another type + * Convert an object to another type * @param {Boolean | Number | String | Date | Moment | Null | undefined} object * @param {String | undefined} type Name of the type. Available types: * 'Boolean', 'Number', 'String', @@ -137,7 +137,7 @@ util.extend = function (a, b) { * @return {*} object * @throws Error */ -util.cast = function cast(object, type) { +util.convert = function convert(object, type) { var match; if (object === undefined) { @@ -162,7 +162,7 @@ util.cast = function cast(object, type) { case 'number': case 'Number': - return Number(object); + return Number(object.valueOf()); case 'string': case 'String': @@ -179,11 +179,9 @@ util.cast = function cast(object, type) { return new Date(object.valueOf()); } if (util.isString(object)) { - // parse ASP.Net Date pattern, - // for example '/Date(1198908717056)/' or '/Date(1198908717056-0700)/' - // code from http://momentjs.com/ match = ASPDateRegex.exec(object); if (match) { + // object is an ASP date return new Date(Number(match[1])); // parse number } else { @@ -192,7 +190,7 @@ util.cast = function cast(object, type) { } else { throw new Error( - 'Cannot cast object of type ' + util.getType(object) + + 'Cannot convert object of type ' + util.getType(object) + ' to type Date'); } @@ -207,11 +205,9 @@ util.cast = function cast(object, type) { return moment.clone(); } if (util.isString(object)) { - // parse ASP.Net Date pattern, - // for example '/Date(1198908717056)/' or '/Date(1198908717056-0700)/' - // code from http://momentjs.com/ match = ASPDateRegex.exec(object); if (match) { + // object is an ASP date return moment(Number(match[1])); // parse number } else { @@ -220,45 +216,70 @@ util.cast = function cast(object, type) { } else { throw new Error( - 'Cannot cast object of type ' + util.getType(object) + + 'Cannot convert object of type ' + util.getType(object) + ' to type Date'); } case 'ISODate': - if (object instanceof Date) { + if (util.isNumber(object)) { + return new Date(object); + } + else if (object instanceof Date) { return object.toISOString(); } else if (moment.isMoment(object)) { return object.toDate().toISOString(); } - else if (util.isNumber(object) || util.isString(object)) { - return moment(object).toDate().toISOString(); + else if (util.isString(object)) { + match = ASPDateRegex.exec(object); + if (match) { + // object is an ASP date + return new Date(Number(match[1])).toISOString(); // parse number + } + else { + return new Date(object).toISOString(); // parse string + } } else { throw new Error( - 'Cannot cast object of type ' + util.getType(object) + + 'Cannot convert object of type ' + util.getType(object) + ' to type ISODate'); } case 'ASPDate': - if (object instanceof Date) { + if (util.isNumber(object)) { + return '/Date(' + object + ')/'; + } + else if (object instanceof Date) { return '/Date(' + object.valueOf() + ')/'; } - else if (util.isNumber(object) || util.isString(object)) { - return '/Date(' + moment(object).valueOf() + ')/'; + else if (util.isString(object)) { + match = ASPDateRegex.exec(object); + var value; + if (match) { + // object is an ASP date + value = new Date(Number(match[1])).valueOf(); // parse number + } + else { + value = new Date(object).valueOf(); // parse string + } + return '/Date(' + value + ')/'; } else { throw new Error( - 'Cannot cast object of type ' + util.getType(object) + + 'Cannot convert object of type ' + util.getType(object) + ' to type ASPDate'); } default: - throw new Error('Cannot cast object of type ' + util.getType(object) + + throw new Error('Cannot convert object of type ' + util.getType(object) + ' to type "' + type + '"'); } }; +// parse ASP.Net Date pattern, +// for example '/Date(1198908717056)/' or '/Date(1198908717056-0700)/' +// code from http://momentjs.com/ var ASPDateRegex = /^\/?Date\((\-?\d+)/i; /** @@ -578,7 +599,7 @@ util.preventDefault = function preventDefault (event) { util.option = {}; /** - * Cast a value as boolean + * Convert a value into a boolean * @param {Boolean | function | undefined} value * @param {Boolean} [defaultValue] * @returns {Boolean} bool @@ -596,7 +617,7 @@ util.option.asBoolean = function (value, defaultValue) { }; /** - * Cast a value as number + * Convert a value into a number * @param {Boolean | function | undefined} value * @param {Number} [defaultValue] * @returns {Number} number @@ -614,7 +635,7 @@ util.option.asNumber = function (value, defaultValue) { }; /** - * Cast a value as string + * Convert a value into a string * @param {String | function | undefined} value * @param {String} [defaultValue] * @returns {String} str @@ -632,7 +653,7 @@ util.option.asString = function (value, defaultValue) { }; /** - * Cast a size or location in pixels or a percentage + * Convert a size or location into a string with pixels or a percentage * @param {String | Number | function | undefined} value * @param {String} [defaultValue] * @returns {String} size @@ -654,7 +675,7 @@ util.option.asSize = function (value, defaultValue) { }; /** - * Cast a value as DOM element + * Convert a value into a DOM element * @param {HTMLElement | function | undefined} value * @param {HTMLElement} [defaultValue] * @returns {HTMLElement | null} dom @@ -1136,7 +1157,7 @@ EventBus.prototype.emit = function (event, data, source) { * Usage: * var dataSet = new DataSet({ * fieldId: '_id', - * fieldTypes: { + * convert: { * // ... * } * }); @@ -1161,28 +1182,29 @@ EventBus.prototype.emit = function (event, data, source) { * @param {Object} [options] Available options: * {String} fieldId Field name of the id in the * items, 'id' by default. - * {Object.} [fieldTypes] + * {Object.} [convert] * {String[]} [fields] field names to be returned * {function} [filter] filter items * {String | function} [order] Order the items by @@ -1447,14 +1472,14 @@ DataSet.prototype.get = function (args) { } // build options - var fieldTypes = options && options.fieldTypes || this.options.fieldTypes; + var convert = options && options.convert || this.options.convert; var filter = options && options.filter; var items = [], item, itemId, i, len; - // cast items + // convert items if (id != undefined) { // return a single item - item = me._getItem(id, fieldTypes); + item = me._getItem(id, convert); if (filter && !filter(item)) { item = null; } @@ -1462,7 +1487,7 @@ DataSet.prototype.get = function (args) { else if (ids != undefined) { // return a subset of items for (i = 0, len = ids.length; i < len; i++) { - item = me._getItem(ids[i], fieldTypes); + item = me._getItem(ids[i], convert); if (!filter || filter(item)) { items.push(item); } @@ -1472,7 +1497,7 @@ DataSet.prototype.get = function (args) { // return all items for (itemId in this.data) { if (this.data.hasOwnProperty(itemId)) { - item = me._getItem(itemId, fieldTypes); + item = me._getItem(itemId, convert); if (!filter || filter(item)) { items.push(item); } @@ -1548,7 +1573,7 @@ DataSet.prototype.getIds = function (options) { var data = this.data, filter = options && options.filter, order = options && options.order, - fieldTypes = options && options.fieldTypes || this.options.fieldTypes, + convert = options && options.convert || this.options.convert, i, len, id, @@ -1563,7 +1588,7 @@ DataSet.prototype.getIds = function (options) { items = []; for (id in data) { if (data.hasOwnProperty(id)) { - item = this._getItem(id, fieldTypes); + item = this._getItem(id, convert); if (filter(item)) { items.push(item); } @@ -1580,7 +1605,7 @@ DataSet.prototype.getIds = function (options) { // create unordered list for (id in data) { if (data.hasOwnProperty(id)) { - item = this._getItem(id, fieldTypes); + item = this._getItem(id, convert); if (filter(item)) { ids.push(item[this.fieldId]); } @@ -1624,7 +1649,7 @@ DataSet.prototype.getIds = function (options) { * The order of the items is not determined. * @param {function} callback * @param {Object} [options] Available options: - * {Object.} [fieldTypes] + * {Object.} [convert] * {String[]} [fields] filter fields * {function} [filter] filter items * {String | function} [order] Order the items by @@ -1632,7 +1657,7 @@ DataSet.prototype.getIds = function (options) { */ DataSet.prototype.forEach = function (callback, options) { var filter = options && options.filter, - fieldTypes = options && options.fieldTypes || this.options.fieldTypes, + convert = options && options.convert || this.options.convert, data = this.data, item, id; @@ -1651,7 +1676,7 @@ DataSet.prototype.forEach = function (callback, options) { // unordered for (id in data) { if (data.hasOwnProperty(id)) { - item = this._getItem(id, fieldTypes); + item = this._getItem(id, convert); if (!filter || filter(item)) { callback(item, id); } @@ -1664,7 +1689,7 @@ DataSet.prototype.forEach = function (callback, options) { * Map every item in the dataset. * @param {function} callback * @param {Object} [options] Available options: - * {Object.} [fieldTypes] + * {Object.} [convert] * {String[]} [fields] filter fields * {function} [filter] filter items * {String | function} [order] Order the items by @@ -1673,15 +1698,15 @@ DataSet.prototype.forEach = function (callback, options) { */ DataSet.prototype.map = function (callback, options) { var filter = options && options.filter, - fieldTypes = options && options.fieldTypes || this.options.fieldTypes, + convert = options && options.convert || this.options.convert, mappedItems = [], data = this.data, item; - // cast and filter items + // convert and filter items for (var id in data) { if (data.hasOwnProperty(id)) { - item = this._getItem(id, fieldTypes); + item = this._getItem(id, convert); if (!filter || filter(item)) { mappedItems.push(callback(item, id)); } @@ -1744,46 +1769,66 @@ DataSet.prototype._sort = function (items, order) { /** * Remove an object by pointer or by id - * @param {String | Number | Object | Array} id Object or id, or an array with - * objects or ids to be removed + * @param {String | Number | Object | Array} id Object or id, or an array with + * objects or ids to be removed * @param {String} [senderId] Optional sender id + * @return {Array} removedIds */ DataSet.prototype.remove = function (id, senderId) { - var removedItems = [], - i, len; + var removedIds = [], + i, len, removedId; - if (util.isNumber(id) || util.isString(id)) { - delete this.data[id]; - delete this.internalIds[id]; - removedItems.push(id); - } - else if (id instanceof Array) { + if (id instanceof Array) { for (i = 0, len = id.length; i < len; i++) { - this.remove(id[i]); + removedId = this._remove(id[i]); + if (removedId != null) { + removedIds.push(removedId); + } } - removedItems = items.concat(id); } - else if (id instanceof Object) { - // search for the object - for (i in this.data) { - if (this.data.hasOwnProperty(i)) { - if (this.data[i] == id) { - delete this.data[i]; - delete this.internalIds[i]; - removedItems.push(i); - } - } + else { + removedId = this._remove(id); + if (removedId != null) { + removedIds.push(removedId); } } - if (removedItems.length) { - this._trigger('remove', {items: removedItems}, senderId); + if (removedIds.length) { + this._trigger('remove', {items: removedIds}, senderId); + } + + return removedIds; +}; + +/** + * Remove an item by its id + * @param {Number | String | Object} id id or item + * @returns {Number | String | null} id + * @private + */ +DataSet.prototype._remove = function (id) { + if (util.isNumber(id) || util.isString(id)) { + if (this.data[id]) { + delete this.data[id]; + delete this.internalIds[id]; + return id; + } } + else if (id instanceof Object) { + var itemId = id[this.fieldId]; + if (itemId && this.data[itemId]) { + delete this.data[itemId]; + delete this.internalIds[itemId]; + return itemId; + } + } + return null; }; /** * Clear the data * @param {String} [senderId] Optional sender id + * @return {Array} removedIds The ids of all removed items */ DataSet.prototype.clear = function (senderId) { var ids = Object.keys(this.data); @@ -1792,6 +1837,8 @@ DataSet.prototype.clear = function (senderId) { this.internalIds = {}; this._trigger('remove', {items: ids}, senderId); + + return ids; }; /** @@ -1853,13 +1900,13 @@ DataSet.prototype.min = function (field) { DataSet.prototype.distinct = function (field) { var data = this.data, values = [], - fieldType = this.options.fieldTypes[field], + fieldType = this.options.convert[field], count = 0; for (var prop in data) { if (data.hasOwnProperty(prop)) { var item = data[prop]; - var value = util.cast(item[field], fieldType); + var value = util.convert(item[field], fieldType); var exists = false; for (var i = 0; i < count; i++) { if (values[i] == value) { @@ -1903,8 +1950,8 @@ DataSet.prototype._addItem = function (item) { var d = {}; for (var field in item) { if (item.hasOwnProperty(field)) { - var type = this.fieldTypes[field]; // type may be undefined - d[field] = util.cast(item[field], type); + var fieldType = this.convert[field]; // type may be undefined + d[field] = util.convert(item[field], fieldType); } } this.data[id] = d; @@ -1913,13 +1960,13 @@ DataSet.prototype._addItem = function (item) { }; /** - * Get an item. Fields can be casted to a specific type + * Get an item. Fields can be converted to a specific type * @param {String} id - * @param {Object.} [fieldTypes] Cast field types + * @param {Object.} [convert] field types to convert * @return {Object | null} item * @private */ -DataSet.prototype._getItem = function (id, fieldTypes) { +DataSet.prototype._getItem = function (id, convert) { var field, value; // get the item from the dataset @@ -1928,35 +1975,35 @@ DataSet.prototype._getItem = function (id, fieldTypes) { return null; } - // cast the items field types - var casted = {}, + // convert the items field types + var converted = {}, fieldId = this.fieldId, internalIds = this.internalIds; - if (fieldTypes) { + if (convert) { for (field in raw) { if (raw.hasOwnProperty(field)) { value = raw[field]; // output all fields, except internal ids if ((field != fieldId) || !(value in internalIds)) { - casted[field] = util.cast(value, fieldTypes[field]); + converted[field] = util.convert(value, convert[field]); } } } } else { - // no field types specified, no casting needed + // no field types specified, no converting needed for (field in raw) { if (raw.hasOwnProperty(field)) { value = raw[field]; // output all fields, except internal ids if ((field != fieldId) || !(value in internalIds)) { - casted[field] = value; + converted[field] = value; } } } } - return casted; + return converted; }; /** @@ -1981,8 +2028,8 @@ DataSet.prototype._updateItem = function (item) { // merge with current item for (var field in item) { if (item.hasOwnProperty(field)) { - var type = this.fieldTypes[field]; // type may be undefined - d[field] = util.cast(item[field], type); + var fieldType = this.convert[field]; // type may be undefined + d[field] = util.convert(item[field], fieldType); } } @@ -2117,7 +2164,7 @@ DataView.prototype.setData = function (data) { * {Object} options An Object with options. Available options: * {String} [type] Type of data to be returned. Can * be 'DataTable' or 'Array' (default) - * {Object.} [fieldTypes] + * {Object.} [convert] * {String[]} [fields] field names to be returned * {function} [filter] filter items * {String | function} [order] Order the items by @@ -3083,8 +3130,8 @@ Range.prototype.setRange = function(start, end) { * @private */ Range.prototype._applyRange = function(start, end) { - var newStart = (start != null) ? util.cast(start, 'Number') : this.start; - var newEnd = (end != null) ? util.cast(end, 'Number') : this.end; + var newStart = (start != null) ? util.convert(start, 'Number') : this.start; + var newEnd = (end != null) ? util.convert(end, 'Number') : this.end; var diff; // check for valid number @@ -3703,6 +3750,7 @@ Component.prototype.getOption = function getOption(name) { * that case null is returned. * @returns {HTMLElement | null} container */ +// TODO: get rid of the getContainer and getFrame methods, provide these via the options Component.prototype.getContainer = function getContainer() { // should be implemented by the component return null; @@ -3945,9 +3993,10 @@ RootPanel.prototype.repaint = function () { asSize = util.option.asSize, options = this.options, frame = this.frame; + if (!frame) { frame = document.createElement('div'); - frame.className = 'graph panel'; + frame.className = 'vis timeline rootpanel'; var className = options.className; if (className) { @@ -3955,6 +4004,7 @@ RootPanel.prototype.repaint = function () { } this.frame = frame; + changed += 1; } if (!frame.parentNode) { @@ -4598,8 +4648,8 @@ TimeAxis.prototype.reflow = function () { // calculate range and step this._updateConversion(); - var start = util.cast(range.start, 'Date'), - end = util.cast(range.end, 'Date'), + var start = util.convert(range.start, 'Date'), + end = util.convert(range.end, 'Date'), minimumStep = this.toTime((props.minorCharWidth || 10) * 5) - this.toTime(0); this.step = new TimeStep(start, end, minimumStep); changed += update(props.range, 'start', start.valueOf()); @@ -5027,19 +5077,8 @@ ItemSet.prototype.hide = function hide() { */ ItemSet.prototype.setItems = function setItems(items) { var me = this, - ids; - - // unsubscribe from current dataset - var current = this.itemsData; - if (current) { - util.forEach(this.listeners, function (callback, event) { - current.unsubscribe(event, callback); - }); - - // remove all drawn items - ids = current.getIds(); - this._onRemove(ids); - } + ids, + oldItemsData = this.itemsData; // replace the dataset if (!items) { @@ -5052,6 +5091,17 @@ ItemSet.prototype.setItems = function setItems(items) { throw new TypeError('Data must be an instance of DataSet'); } + if (oldItemsData) { + // unsubscribe from old dataset + util.forEach(this.listeners, function (callback, event) { + oldItemsData.unsubscribe(event, callback); + }); + + // remove all drawn items + ids = oldItemsData.getIds(); + this._onRemove(ids); + } + if (this.itemsData) { // subscribe to new dataset var id = this.id; @@ -5426,8 +5476,9 @@ ItemBox.prototype.reflow = function reflow() { data = this.data; range = this.parent && this.parent.range; if (data && range) { - // TODO: account for the width of the item. Take some margin - this.visible = (data.start > range.start) && (data.start < range.end); + // TODO: account for the width of the item + var interval = (range.end - range.start); + this.visible = (data.start > range.start - interval) && (data.start < range.end + interval); } else { this.visible = false; @@ -5711,8 +5762,9 @@ ItemPoint.prototype.reflow = function reflow() { data = this.data; range = this.parent && this.parent.range; if (data && range) { - // TODO: account for the width of the item. Take some margin - this.visible = (data.start > range.start) && (data.start < range.end); + // TODO: account for the width of the item + var interval = (range.end - range.start); + this.visible = (data.start > range.start - interval) && (data.start < range.end); } else { this.visible = false; @@ -6086,6 +6138,13 @@ function Group (parent, groupId, options) { this.options = options || {}; this.options.top = 0; + this.props = { + label: { + width: 0, + height: 0 + } + }; + this.top = 0; this.left = 0; this.width = 0; @@ -6158,6 +6217,18 @@ Group.prototype.reflow = function reflow() { changed += update(this, 'top', this.itemset ? this.itemset.top : 0); changed += update(this, 'height', this.itemset ? this.itemset.height : 0); + // TODO: reckon with the height of the group label + + if (this.label) { + var inner = this.label.firstChild; + changed += update(this.props.label, 'width', inner.clientWidth); + changed += update(this.props.label, 'height', inner.clientHeight); + } + else { + changed += update(this.props.label, 'width', 0); + changed += update(this.props.label, 'height', 0); + } + return (changed > 0); }; @@ -6184,6 +6255,15 @@ function GroupSet(parent, depends, options) { this.groups = {}; // map with groups + this.dom = {}; + this.props = { + labels: { + width: 0 + } + }; + + // TODO: implement right orientation of the labels + // changes in groups are queued key/value map containing id/action this.queue = {}; @@ -6274,7 +6354,7 @@ GroupSet.prototype.setGroups = function setGroups(groups) { } else { this.groupsData = new DataSet({ - fieldTypes: { + convert: { start: 'Date', end: 'Date' } @@ -6309,48 +6389,72 @@ GroupSet.prototype.getGroups = function getGroups() { */ GroupSet.prototype.repaint = function repaint() { var changed = 0, + i, id, group, label, update = util.updateProperty, asSize = util.option.asSize, + asElement = util.option.asElement, options = this.options, - frame = this.frame; + frame = this.dom.frame, + labels = this.dom.labels; + // create frame + if (!this.parent) { + throw new Error('Cannot repaint groupset: no parent attached'); + } + var parentContainer = this.parent.getContainer(); + if (!parentContainer) { + throw new Error('Cannot repaint groupset: parent has no container element'); + } if (!frame) { frame = document.createElement('div'); frame.className = 'groupset'; + this.dom.frame = frame; var className = options.className; if (className) { util.addClassName(frame, util.option.asString(className)); } - this.frame = frame; changed += 1; } - - if (!this.parent) { - throw new Error('Cannot repaint groupset: no parent attached'); - } - var parentContainer = this.parent.getContainer(); - if (!parentContainer) { - throw new Error('Cannot repaint groupset: parent has no container element'); - } if (!frame.parentNode) { parentContainer.appendChild(frame); changed += 1; } + // create labels + var labelContainer = asElement(options.labelContainer); + if (!labelContainer) { + throw new Error('Cannot repaint groupset: option "labelContainer" not defined'); + } + if (!labels) { + labels = document.createElement('div'); + labels.className = 'labels'; + //frame.appendChild(labels); + this.dom.labels = labels; + } + if (!labels.parentNode || labels.parentNode != labelContainer) { + if (labels.parentNode) { + labels.parentNode.removeChild(labels.parentNode); + } + labelContainer.appendChild(labels); + } + // reposition frame changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); changed += update(frame.style, 'top', asSize(options.top, '0px')); changed += update(frame.style, 'left', asSize(options.left, '0px')); changed += update(frame.style, 'width', asSize(options.width, '100%')); + // reposition labels + changed += update(labels.style, 'top', asSize(options.top, '0px')); + var me = this, queue = this.queue, groups = this.groups, groupsData = this.groupsData; - // show/hide added/changed/removed items + // show/hide added/changed/removed groups var ids = Object.keys(queue); if (ids.length) { ids.forEach(function (id) { @@ -6402,7 +6506,7 @@ GroupSet.prototype.repaint = function repaint() { var orderedGroups = this.groupsData.getIds({ order: this.options.groupsOrder }); - for (var i = 0; i < orderedGroups.length; i++) { + for (i = 0; i < orderedGroups.length; i++) { (function (group, prevGroup) { var top = 0; if (prevGroup) { @@ -6417,19 +6521,82 @@ GroupSet.prototype.repaint = function repaint() { })(groups[orderedGroups[i]], groups[orderedGroups[i - 1]]); } + // (re)create the labels + while (labels.firstChild) { + labels.removeChild(labels.firstChild); + } + for (i = 0; i < orderedGroups.length; i++) { + id = orderedGroups[i]; + label = this._createLabel(id); + labels.appendChild(label); + } + changed++; } + // reposition the labels + // TODO: labels are not displayed correctly when orientation=='top' + // TODO: width of labelPanel is not immediately updated on a change in groups + for (id in groups) { + if (groups.hasOwnProperty(id)) { + group = groups[id]; + label = group.label; + if (label) { + label.style.top = group.top + 'px'; + label.style.height = group.height + 'px'; + } + } + } + return (changed > 0); }; +/** + * Create a label for group with given id + * @param {Number} id + * @return {Element} label + * @private + */ +GroupSet.prototype._createLabel = function(id) { + var group = this.groups[id]; + var label = document.createElement('div'); + label.className = 'label'; + var inner = document.createElement('div'); + inner.className = 'inner'; + label.appendChild(inner); + + var content = group.data && group.data.content; + if (content instanceof Element) { + inner.appendChild(content); + } + else if (content != undefined) { + inner.innerHTML = content; + } + + var className = group.data && group.data.className; + if (className) { + util.addClassName(label, className); + } + + group.label = label; // TODO: not so nice, parking labels in the group this way!!! + + return label; +}; + /** * Get container element * @return {HTMLElement} container */ GroupSet.prototype.getContainer = function getContainer() { - // TODO: replace later on with container element for holding itemsets - return this.frame; + return this.dom.frame; +}; + +/** + * Get the width of the group labels + * @return {Number} width + */ +GroupSet.prototype.getLabelsWidth = function getContainer() { + return this.props.labels.width; }; /** @@ -6438,11 +6605,12 @@ GroupSet.prototype.getContainer = function getContainer() { */ GroupSet.prototype.reflow = function reflow() { var changed = 0, + id, group, options = this.options, update = util.updateProperty, asNumber = util.option.asNumber, asSize = util.option.asSize, - frame = this.frame; + frame = this.dom.frame; if (frame) { var maxHeight = asNumber(options.maxHeight); @@ -6455,9 +6623,9 @@ GroupSet.prototype.reflow = function reflow() { // height is not specified, calculate the sum of the height of all groups height = 0; - for (var id in this.groups) { + for (id in this.groups) { if (this.groups.hasOwnProperty(id)) { - var group = this.groups[id]; + group = this.groups[id]; height += group.height; } } @@ -6472,6 +6640,17 @@ GroupSet.prototype.reflow = function reflow() { changed += update(this, 'width', frame.offsetWidth); } + // calculate the maximum width of the labels + var width = 0; + for (id in this.groups) { + if (this.groups.hasOwnProperty(id)) { + group = this.groups[id]; + var labelWidth = group.props && group.props.label && group.props.label.width || 0; + width = Math.max(width, labelWidth); + } + } + changed += update(this.props.labels, 'width', width); + return (changed > 0); }; @@ -6480,8 +6659,8 @@ GroupSet.prototype.reflow = function reflow() { * @return {Boolean} changed */ GroupSet.prototype.hide = function hide() { - if (this.frame && this.frame.parentNode) { - this.frame.parentNode.removeChild(this.frame); + if (this.dom.frame && this.dom.frame.parentNode) { + this.dom.frame.parentNode.removeChild(this.dom.frame); return true; } else { @@ -6495,7 +6674,7 @@ GroupSet.prototype.hide = function hide() { * @return {Boolean} changed */ GroupSet.prototype.show = function show() { - if (!this.frame || !this.frame.parentNode) { + if (!this.dom.frame || !this.dom.frame.parentNode) { return this.repaint(); } else { @@ -6576,8 +6755,8 @@ function Timeline (container, items, options) { if (!container) { throw new Error('No container element provided'); } - var mainOptions = Object.create(this.options); - mainOptions.height = function () { + var rootOptions = Object.create(this.options); + rootOptions.height = function () { if (me.options.height) { // fixed height return me.options.height; @@ -6587,8 +6766,37 @@ function Timeline (container, items, options) { return me.timeaxis.height + me.content.height; } }; - this.root = new RootPanel(container, mainOptions); - this.controller.add(this.root); + this.rootPanel = new RootPanel(container, rootOptions); + this.controller.add(this.rootPanel); + + // item panel + var itemOptions = Object.create(this.options); + itemOptions.left = function () { + return me.labelPanel.width; + }; + itemOptions.width = function () { + return me.rootPanel.width - me.labelPanel.width; + }; + itemOptions.top = null; + itemOptions.height = null; + this.itemPanel = new Panel(this.rootPanel, [], itemOptions); + this.controller.add(this.itemPanel); + + // label panel + var labelOptions = Object.create(this.options); + labelOptions.top = null; + labelOptions.left = null; + labelOptions.height = null; + labelOptions.width = function () { + if (me.content && typeof me.content.getLabelsWidth === 'function') { + return me.content.getLabelsWidth(); + } + else { + return 0; + } + }; + this.labelPanel = new Panel(this.rootPanel, [], labelOptions); + this.controller.add(this.labelPanel); // range var now = moment().hours(0).minutes(0).seconds(0).milliseconds(0); @@ -6597,8 +6805,8 @@ function Timeline (container, items, options) { end: now.clone().add('days', 4).valueOf() }); // TODO: reckon with options moveable and zoomable - this.range.subscribe(this.root, 'move', 'horizontal'); - this.range.subscribe(this.root, 'zoom', 'horizontal'); + this.range.subscribe(this.rootPanel, 'move', 'horizontal'); + this.range.subscribe(this.rootPanel, 'zoom', 'horizontal'); this.range.on('rangechange', function () { var force = true; me.controller.requestReflow(force); @@ -6611,9 +6819,13 @@ function Timeline (container, items, options) { // TODO: put the listeners in setOptions, be able to dynamically change with options moveable and zoomable // time axis - var timeaxisOptions = Object.create(mainOptions); + var timeaxisOptions = Object.create(rootOptions); timeaxisOptions.range = this.range; - this.timeaxis = new TimeAxis(this.root, [], timeaxisOptions); + timeaxisOptions.left = null; + timeaxisOptions.top = null; + timeaxisOptions.width = '100%'; + timeaxisOptions.height = null; + this.timeaxis = new TimeAxis(this.itemPanel, [], timeaxisOptions); this.timeaxis.setRange(this.range); this.controller.add(this.timeaxis); @@ -6659,7 +6871,7 @@ Timeline.prototype.setItems = function(items) { } if (!(items instanceof DataSet)) { newItemSet = new DataSet({ - fieldTypes: { + convert: { start: 'Date', end: 'Date' } @@ -6730,12 +6942,14 @@ Timeline.prototype.setGroups = function(groups) { return me.timeaxis.height; } else { - return me.root.height - me.timeaxis.height - me.content.height; + return me.itemPanel.height - me.timeaxis.height - me.content.height; } }, + left: null, + width: '100%', height: function () { if (me.options.height) { - return me.root.height - me.timeaxis.height; + return me.itemPanel.height - me.timeaxis.height; } else { return null; @@ -6751,9 +6965,12 @@ Timeline.prototype.setGroups = function(groups) { else { return null; } + }, + labelContainer: function () { + return me.labelPanel.getContainer(); } }); - this.content = new type(this.root, [this.timeaxis], options); + this.content = new type(this.itemPanel, [this.timeaxis], options); if (this.content.setRange) { this.content.setRange(this.range); } @@ -6810,6 +7027,9 @@ Timeline.prototype.getItemRange = function getItemRange() { /** * Parse a text source containing data in DOT language into a JSON object. * The object contains two lists: one with nodes and one with edges. + * + * DOT language reference: http://www.graphviz.org/doc/info/lang.html + * * @param {String} data Text containing a graph in DOT-notation * @return {Object} graph An object containing two parameters: * {Object[]} nodes @@ -6848,10 +7068,6 @@ Timeline.prototype.getItemRange = function getItemRange() { var token = ''; // current token var tokenType = TOKENTYPE.NULL; // type of the token - var graph = null; // object with the graph to be build - var nodeAttr = null; // global node attributes - var edgeAttr = null; // global edge attributes - /** * Get the first character from the dot file. * The character is stored into the char c. If the end of the dot file is @@ -6885,7 +7101,7 @@ Timeline.prototype.getItemRange = function getItemRange() { * @param {String} c * @return {Boolean} isAlphaNumeric */ - var regexAlphaNumeric = /[a-zA-Z_0-9.#]/; + var regexAlphaNumeric = /[a-zA-Z_0-9.:#]/; function isAlphaNumeric(c) { return regexAlphaNumeric.test(c); } @@ -6912,46 +7128,133 @@ Timeline.prototype.getItemRange = function getItemRange() { } /** - * Add a node to the current graph object. If there is already a node with + * Set a value in an object, where the provided parameter name can be a + * path with nested parameters. For example: + * + * var obj = {a: 2}; + * setValue(obj, 'b.c', 3); // obj = {a: 2, b: {c: 3}} + * + * @param {Object} obj + * @param {String} path A parameter name or dot-separated parameter path, + * like "color.highlight.border". + * @param {*} value + */ + function setValue(obj, path, value) { + var keys = path.split('.'); + var o = obj; + while (keys.length) { + var key = keys.shift(); + if (keys.length) { + // this isn't the end point + if (!o[key]) { + o[key] = {}; + } + o = o[key]; + } + else { + // this is the end point + o[key] = value; + } + } + } + + /** + * Add a node to a graph object. If there is already a node with * the same id, their attributes will be merged. + * @param {Object} graph * @param {Object} node */ - function addNode(node) { - if (!graph.nodes) { - graph.nodes = {}; + function addNode(graph, node) { + var i, len; + var current = null; + + // find root graph (in case of subgraph) + var graphs = [graph]; // list with all graphs from current graph to root graph + var root = graph; + while (root.parent) { + graphs.push(root.parent); + root = root.parent; + } + + // find existing node (at root level) by its id + if (root.nodes) { + for (i = 0, len = root.nodes.length; i < len; i++) { + if (node.id === root.nodes[i].id) { + current = root.nodes[i]; + break; + } + } } - var current = graph.nodes[node.id]; - if (current) { - // merge attributes - if (node.attr) { - current.attr = merge(current.attr, node.attr); + + if (!current) { + // this is a new node + current = { + id: node.id + }; + if (graph.node) { + // clone default attributes + current.attr = merge(current.attr, graph.node); } } - else { - // add - graph.nodes[node.id] = node; - if (nodeAttr) { - var attr = merge({}, nodeAttr); // clone global attributes - node.attr = merge(attr, node.attr); // merge attributes + + // add node to this (sub)graph and all its parent graphs + for (i = graphs.length - 1; i >= 0; i--) { + var g = graphs[i]; + + if (!g.nodes) { + g.nodes = []; } + if (g.nodes.indexOf(current) == -1) { + g.nodes.push(current); + } + } + + // merge attributes + if (node.attr) { + current.attr = merge(current.attr, node.attr); } } /** - * Add an edge to the current graph obect + * Add an edge to a graph object + * @param {Object} graph * @param {Object} edge */ - function addEdge(edge) { + function addEdge(graph, edge) { if (!graph.edges) { graph.edges = []; } graph.edges.push(edge); - if (edgeAttr) { - var attr = merge({}, edgeAttr); // clone global attributes + if (graph.edge) { + var attr = merge({}, graph.edge); // clone default attributes edge.attr = merge(attr, edge.attr); // merge attributes } } + /** + * Create an edge to a graph object + * @param {Object} graph + * @param {String | Number | Object} from + * @param {String | Number | Object} to + * @param {String} type + * @param {Object | null} attr + * @return {Object} edge + */ + function createEdge(graph, from, to, type, attr) { + var edge = { + from: from, + to: to, + type: type + }; + + if (graph.edge) { + edge.attr = merge({}, graph.edge); // clone default attributes + } + edge.attr = merge(edge.attr || {}, attr); // merge attributes + + return edge; + } + /** * Get next token in the current dot file. * The token and token type are available as token and tokenType @@ -7039,7 +7342,7 @@ Timeline.prototype.getItemRange = function getItemRange() { } // check for an identifier (number or string) - // TODO: more precise parsing of numbers/strings + // TODO: more precise parsing of numbers/strings (and the port separator ':') if (isAlphaNumeric(c) || c == '-') { token += c; next(); @@ -7049,13 +7352,13 @@ Timeline.prototype.getItemRange = function getItemRange() { next(); } if (token == 'false') { - token = false; // cast to boolean + token = false; // convert to boolean } else if (token == 'true') { - token = true; // cast to boolean + token = true; // convert to boolean } else if (!isNaN(Number(token))) { - token = Number(token); // cast to number + token = Number(token); // convert to number } tokenType = TOKENTYPE.IDENTIFIER; return; @@ -7093,9 +7396,7 @@ Timeline.prototype.getItemRange = function getItemRange() { * @returns {Object} graph */ function parseGraph() { - graph = {}; - nodeAttr = null; - edgeAttr = null; + var graph = {}; first(); getToken(); @@ -7112,7 +7413,7 @@ Timeline.prototype.getItemRange = function getItemRange() { getToken(); } - // graph id + // optional graph id if (tokenType == TOKENTYPE.IDENTIFIER) { graph.id = token; getToken(); @@ -7125,7 +7426,7 @@ Timeline.prototype.getItemRange = function getItemRange() { getToken(); // statements - parseStatements(); + parseStatements(graph); // close angle bracket if (token != '}') { @@ -7139,19 +7440,21 @@ Timeline.prototype.getItemRange = function getItemRange() { } getToken(); + // remove temporary default properties + delete graph.node; + delete graph.edge; + delete graph.graph; + return graph; } /** * Parse a list with statements. + * @param {Object} graph */ - function parseStatements () { + function parseStatements (graph) { while (token !== '' && token != '}') { - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Identifier expected'); - } - - parseStatement(); + parseStatement(graph); if (token == ';') { getToken(); } @@ -7162,134 +7465,249 @@ Timeline.prototype.getItemRange = function getItemRange() { * Parse a single statement. Can be a an attribute statement, node * statement, a series of node statements and edge statements, or a * parameter. + * @param {Object} graph */ - function parseStatement() { - var attr; - var id = token; // can be as string or a number - getToken(); + function parseStatement(graph) { + // parse subgraph + var subgraph = parseSubgraph(graph); + if (subgraph) { + // edge statements + parseEdge(graph, subgraph); - // attribute statements - if (id == 'node') { - // node attributes - attr = parseAttributes(); - if (attr) { - nodeAttr = merge(nodeAttr, attr); - } - } - else if (id == 'edge') { - // edge attributes - attr = parseAttributes(); - if (attr) { - edgeAttr = merge(edgeAttr, attr); - } - } - else if (id == 'graph') { - // graph attributes - attr = parseAttributes(); - if (attr) { - graph.attr = merge(graph.attr, attr); - } + return; } - else { - if (token == '=') { - // id statement - getToken(); - if (!graph.attr) { - graph.attr = {}; - } - graph.attr[id] = token; - getToken(); - } - else { - // node statement - var node = { - id: String(id) - }; - attr = parseAttributes(); - if (attr) { - node.attr = attr; - } - addNode(node); - - // edge statements - var from = id; - while (token == '->' || token == '--') { - var type = token; - getToken(); - var to = token; - addNode({ - id: String(to) - }); - getToken(); - attr = parseAttributes(); + // parse an attribute statement + var attr = parseAttributeStatement(graph); + if (attr) { + return; + } - // create edge - var edge = { - from: String(from), - to: String(to), - type: type - }; - if (attr) { - edge.attr = attr; - } - addEdge(edge); + // parse node + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Identifier expected'); + } + var id = token; // id can be a string or a number + getToken(); - from = to; - } + if (token == '=') { + // id statement + getToken(); + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Identifier expected'); } + graph[id] = token; + getToken(); + // TODO: implement comma separated list with "a_list: ID=ID [','] [a_list] " + } + else { + parseNodeStatement(graph, id); } } /** - * Parse a set with attributes, - * for example [label="1.000", shape=solid] - * @return {Object | undefined} attr + * Parse a subgraph + * @param {Object} graph parent graph object + * @return {Object | null} subgraph */ - function parseAttributes() { - if (token == '[') { + function parseSubgraph (graph) { + var subgraph = null; + + // optional subgraph keyword + if (token == 'subgraph') { + subgraph = {}; + subgraph.type = 'subgraph'; getToken(); - var attr = {}; - while (token !== '' && token != ']') { - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Attribute name expected'); - } - var name = token; + // optional graph id + if (tokenType == TOKENTYPE.IDENTIFIER) { + subgraph.id = token; getToken(); - if (token != '=') { - throw newSyntaxError('Equal sign = expected'); - } - getToken(); + } + } - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Attribute value expected'); - } - var value = token; - attr[name] = value; + // open angle bracket + if (token == '{') { + getToken(); - getToken(); - if (token ==',') { - getToken(); - } + if (!subgraph) { + subgraph = {}; + } + subgraph.parent = graph; + subgraph.node = graph.node; + subgraph.edge = graph.edge; + subgraph.graph = graph.graph; + + // statements + parseStatements(subgraph); + + // close angle bracket + if (token != '}') { + throw newSyntaxError('Angle bracket } expected'); } getToken(); - return attr; - } - else { - return undefined; + // remove temporary default properties + delete subgraph.node; + delete subgraph.edge; + delete subgraph.graph; + delete subgraph.parent; + + // register at the parent graph + if (!graph.subgraphs) { + graph.subgraphs = []; + } + graph.subgraphs.push(subgraph); } + + return subgraph; } /** - * Create a syntax error with extra information on current token and index. - * @param {String} message - * @returns {SyntaxError} err + * parse an attribute statement like "node [shape=circle fontSize=16]". + * Available keywords are 'node', 'edge', 'graph'. + * The previous list with default attributes will be replaced + * @param {Object} graph + * @returns {String | null} keyword Returns the name of the parsed attribute + * (node, edge, graph), or null if nothing + * is parsed. */ - function newSyntaxError(message) { - return new SyntaxError(message + ', got "' + chop(token, 30) + '" (char ' + index + ')'); - } + function parseAttributeStatement (graph) { + // attribute statements + if (token == 'node') { + getToken(); + + // node attributes + graph.node = parseAttributeList(); + return 'node'; + } + else if (token == 'edge') { + getToken(); + + // edge attributes + graph.edge = parseAttributeList(); + return 'edge'; + } + else if (token == 'graph') { + getToken(); + + // graph attributes + graph.graph = parseAttributeList(); + return 'graph'; + } + + return null; + } + + /** + * parse a node statement + * @param {Object} graph + * @param {String | Number} id + */ + function parseNodeStatement(graph, id) { + // node statement + var node = { + id: id + }; + var attr = parseAttributeList(); + if (attr) { + node.attr = attr; + } + addNode(graph, node); + + // edge statements + parseEdge(graph, id); + } + + /** + * Parse an edge or a series of edges + * @param {Object} graph + * @param {String | Number} from Id of the from node + */ + function parseEdge(graph, from) { + while (token == '->' || token == '--') { + var to; + var type = token; + getToken(); + + var subgraph = parseSubgraph(graph); + if (subgraph) { + to = subgraph; + } + else { + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Identifier or subgraph expected'); + } + to = token; + addNode(graph, { + id: to + }); + getToken(); + } + + // parse edge attributes + var attr = parseAttributeList(); + + // create edge + var edge = createEdge(graph, from, to, type, attr); + addEdge(graph, edge); + + from = to; + } + } + + /** + * Parse a set with attributes, + * for example [label="1.000", shape=solid] + * @return {Object | null} attr + */ + function parseAttributeList() { + var attr = null; + + while (token == '[') { + getToken(); + attr = {}; + while (token !== '' && token != ']') { + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Attribute name expected'); + } + var name = token; + + getToken(); + if (token != '=') { + throw newSyntaxError('Equal sign = expected'); + } + getToken(); + + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Attribute value expected'); + } + var value = token; + setValue(attr, name, value); // name can be a path + + getToken(); + if (token ==',') { + getToken(); + } + } + + if (token != ']') { + throw newSyntaxError('Bracket ] expected'); + } + getToken(); + } + + return attr; + } + + /** + * Create a syntax error with extra information on current token and index. + * @param {String} message + * @returns {SyntaxError} err + */ + function newSyntaxError(message) { + return new SyntaxError(message + ', got "' + chop(token, 30) + '" (char ' + index + ')'); + } /** * Chop off text after a maximum length @@ -7301,6 +7719,37 @@ Timeline.prototype.getItemRange = function getItemRange() { return (text.length <= maxLength) ? text : (text.substr(0, 27) + '...'); } + /** + * Execute a function fn for each pair of elements in two arrays + * @param {Array | *} array1 + * @param {Array | *} array2 + * @param {function} fn + */ + function forEach2(array1, array2, fn) { + if (array1 instanceof Array) { + array1.forEach(function (elem1) { + if (array2 instanceof Array) { + array2.forEach(function (elem2) { + fn(elem1, elem2); + }); + } + else { + fn(elem1, array2); + } + }); + } + else { + if (array2 instanceof Array) { + array2.forEach(function (elem2) { + fn(array1, elem2); + }); + } + else { + fn(array1, array2); + } + } + } + /** * Convert a string containing a graph in DOT language into a map containing * with nodes and edges in the format of graph. @@ -7318,31 +7767,75 @@ Timeline.prototype.getItemRange = function getItemRange() { // copy the nodes if (dotData.nodes) { - for (var id in dotData.nodes) { - if (dotData.nodes.hasOwnProperty(id)) { - var node = { - id: id, - label: id - }; - merge(node, dotData.nodes[id].attr); - if (node.image) { - node.shape = 'image'; - } - graphData.nodes.push(node); + dotData.nodes.forEach(function (dotNode) { + var graphNode = { + id: dotNode.id, + label: String(dotNode.label || dotNode.id) + }; + merge(graphNode, dotNode.attr); + if (graphNode.image) { + graphNode.shape = 'image'; } - } + graphData.nodes.push(graphNode); + }); } // copy the edges if (dotData.edges) { - dotData.edges.forEach(function (dotEdge) { + /** + * Convert an edge in DOT format to an edge with VisGraph format + * @param {Object} dotEdge + * @returns {Object} graphEdge + */ + function convertEdge(dotEdge) { var graphEdge = { from: dotEdge.from, to: dotEdge.to }; merge(graphEdge, dotEdge.attr); graphEdge.style = (dotEdge.type == '->') ? 'arrow' : 'line'; - graphData.edges.push(graphEdge); + return graphEdge; + } + + dotData.edges.forEach(function (dotEdge) { + var from, to; + if (dotEdge.from instanceof Object) { + from = dotEdge.from.nodes; + } + else { + from = { + id: dotEdge.from + } + } + + if (dotEdge.to instanceof Object) { + to = dotEdge.to.nodes; + } + else { + to = { + id: dotEdge.to + } + } + + if (dotEdge.from instanceof Object && dotEdge.from.edges) { + dotEdge.from.edges.forEach(function (subEdge) { + var graphEdge = convertEdge(subEdge); + graphData.edges.push(graphEdge); + }); + } + + forEach2(from, to, function (from, to) { + var subEdge = createEdge(graphData, from.id, to.id, dotEdge.type, dotEdge.attr); + var graphEdge = convertEdge(subEdge); + graphData.edges.push(graphEdge); + }); + + if (dotEdge.to instanceof Object && dotEdge.to.edges) { + dotEdge.to.edges.forEach(function (subEdge) { + var graphEdge = convertEdge(subEdge); + graphData.edges.push(graphEdge); + }); + } }); } @@ -7655,7 +8148,9 @@ function Node(properties, imagelist, grouplist, constants) { * @param {Edge} edge */ Node.prototype.attachEdge = function(edge) { - this.edges.push(edge); + if (this.edges.indexOf(edge) == -1) { + this.edges.push(edge); + } this._updateMass(); }; @@ -8293,24 +8788,30 @@ function Edge (properties, graph, constants) { // initialize variables this.id = undefined; + this.fromId = undefined; + this.toId = undefined; this.style = constants.edges.style; this.title = undefined; this.width = constants.edges.width; this.value = undefined; this.length = constants.edges.length; + this.from = null; // a node + this.to = null; // a node + this.connected = false; + // Added to support dashed lines // David Jordan // 2012-08-08 - this.dash = util.extend({}, constants.edges.dash); // contains properties length, gaph, altLength + this.dash = util.extend({}, constants.edges.dash); // contains properties length, gap, altLength - this.stiffness = undefined; // depends on the length of the edge - this.color = constants.edges.color; - this.widthFixed = false; + this.stiffness = undefined; // depends on the length of the edge + this.color = constants.edges.color; + this.widthFixed = false; this.lengthFixed = false; this.setProperties(properties, constants); -}; +} /** * Set or overwrite properties for the edge @@ -8322,12 +8823,12 @@ Edge.prototype.setProperties = function(properties, constants) { return; } - if (properties.from != undefined) {this.from = this.graph._getNode(properties.from);} - if (properties.to != undefined) {this.to = this.graph._getNode(properties.to);} + if (properties.from != undefined) {this.fromId = properties.from;} + if (properties.to != undefined) {this.toId = properties.to;} - if (properties.id != undefined) {this.id = properties.id;} - if (properties.style != undefined) {this.style = properties.style;} - if (properties.label != undefined) {this.label = properties.label;} + if (properties.id != undefined) {this.id = properties.id;} + if (properties.style != undefined) {this.style = properties.style;} + if (properties.label != undefined) {this.label = properties.label;} if (this.label) { this.fontSize = constants.edges.fontSize; this.fontFace = constants.edges.fontFace; @@ -8336,32 +8837,27 @@ Edge.prototype.setProperties = function(properties, constants) { if (properties.fontSize != undefined) {this.fontSize = properties.fontSize;} if (properties.fontFace != undefined) {this.fontFace = properties.fontFace;} } - if (properties.title != undefined) {this.title = properties.title;} - if (properties.width != undefined) {this.width = properties.width;} - if (properties.value != undefined) {this.value = properties.value;} - if (properties.length != undefined) {this.length = properties.length;} + if (properties.title != undefined) {this.title = properties.title;} + if (properties.width != undefined) {this.width = properties.width;} + if (properties.value != undefined) {this.value = properties.value;} + if (properties.length != undefined) {this.length = properties.length;} // Added to support dashed lines // David Jordan // 2012-08-08 if (properties.dash) { - if (properties.dash.length != undefined) {this.dash.length = properties.dash.length;} - if (properties.dash.gap != undefined) {this.dash.gap = properties.dash.gap;} + if (properties.dash.length != undefined) {this.dash.length = properties.dash.length;} + if (properties.dash.gap != undefined) {this.dash.gap = properties.dash.gap;} if (properties.dash.altLength != undefined) {this.dash.altLength = properties.dash.altLength;} } if (properties.color != undefined) {this.color = properties.color;} - if (!this.from) { - throw "Node with id " + properties.from + " not found"; - } - if (!this.to) { - throw "Node with id " + properties.to + " not found"; - } + // A node is connected when it has a from and to node. + this.connect(); this.widthFixed = this.widthFixed || (properties.width != undefined); this.lengthFixed = this.lengthFixed || (properties.length != undefined); - this.stiffness = 1 / this.length; // set draw method based on style @@ -8374,6 +8870,46 @@ Edge.prototype.setProperties = function(properties, constants) { } }; +/** + * Connect an edge to its nodes + */ +Edge.prototype.connect = function () { + this.disconnect(); + + this.from = this.graph.nodes[this.fromId] || null; + this.to = this.graph.nodes[this.toId] || null; + this.connected = (this.from && this.to); + + if (this.connected) { + this.from.attachEdge(this); + this.to.attachEdge(this); + } + else { + if (this.from) { + this.from.detachEdge(this); + } + if (this.to) { + this.to.detachEdge(this); + } + } +}; + +/** + * Disconnect an edge from its nodes + */ +Edge.prototype.disconnect = function () { + if (this.from) { + this.from.detachEdge(this); + this.from = null; + } + if (this.to) { + this.to.detachEdge(this); + this.to = null; + } + + this.connected = false; +}; + /** * get the title of this edge. * @return {string} title The title of the edge, or undefined when no title @@ -9128,8 +9664,45 @@ function Graph (container, data, options) { }; var graph = this; - this.nodes = []; // array with Node objects - this.edges = []; // array with Edge objects + this.nodes = {}; // object with Node objects + this.edges = {}; // object with Edge objects + // TODO: create a counter to keep track on the number of nodes having values + // TODO: create a counter to keep track on the number of nodes currently moving + // TODO: create a counter to keep track on the number of edges having values + + this.nodesData = null; // A DataSet or DataView + this.edgesData = null; // A DataSet or DataView + + // create event listeners used to subscribe on the DataSets of the nodes and edges + var me = this; + this.nodesListeners = { + 'add': function (event, params) { + me._addNodes(params.items); + me.start(); + }, + 'update': function (event, params) { + me._updateNodes(params.items); + me.start(); + }, + 'remove': function (event, params) { + me._removeNodes(params.items); + me.start(); + } + }; + this.edgesListeners = { + 'add': function (event, params) { + me._addEdges(params.items); + me.start(); + }, + 'update': function (event, params) { + me._updateEdges(params.items); + me.start(); + }, + 'remove': function (event, params) { + me._removeEdges(params.items); + me.start(); + } + }; this.groups = new Groups(); // object with groups this.images = new Images(); // object with images @@ -9157,12 +9730,9 @@ function Graph (container, data, options) { * Set nodes and edges, and optionally options as well. * * @param {Object} data Object containing parameters: - * {Array} [nodes] Array with nodes. - * Required when format is 'vis' - * {Array} [edges] Array with edges - * Required when format is 'vis' - * {String} [dot] String containing data in DOT - * format. + * {Array | DataSet | DataView} [nodes] Array with nodes + * {Array | DataSet | DataView} [edges] Array with edges + * {String} [dot] String containing data in DOT format * {Options} [options] Object with options */ Graph.prototype.setData = function(data) { @@ -9270,7 +9840,7 @@ Graph.prototype.setOptions = function (options) { } this.setSize(this.width, this.height); - this._setTranslation(0, 0); + this._setTranslation(this.frame.clientWidth / 2, this.frame.clientHeight / 2); this._setScale(1); }; @@ -9369,8 +9939,8 @@ Graph.prototype._onMouseDown = function (event) { vis.util.preventDefault(event); // store the start x and y position of the mouse - this.startMouseX = event.clientX || event.targetTouches[0].clientX; - this.startMouseY = event.clientY || event.targetTouches[0].clientY; + this.startMouseX = util.getPageX(event); + this.startMouseY = util.getPageY(event); this.startFrameLeft = vis.util.getAbsoluteLeft(this.frame.canvas); this.startFrameTop = vis.util.getAbsoluteTop(this.frame.canvas); this.startTranslation = this._getTranslation(); @@ -9379,10 +9949,10 @@ Graph.prototype._onMouseDown = function (event) { this.shiftKeyDown = event.shiftKey; var obj = { - "left" : this._xToCanvas(this.startMouseX - this.startFrameLeft), - "top" : this._yToCanvas(this.startMouseY - this.startFrameTop), - "right" : this._xToCanvas(this.startMouseX - this.startFrameLeft), - "bottom" : this._yToCanvas(this.startMouseY - this.startFrameTop) + left: this._xToCanvas(this.startMouseX - this.startFrameLeft), + top: this._yToCanvas(this.startMouseY - this.startFrameTop), + right: this._xToCanvas(this.startMouseX - this.startFrameLeft), + bottom: this._yToCanvas(this.startMouseY - this.startFrameTop) }; var overlappingNodes = this._getNodesOverlappingWith(obj); // if there are overlapping nodes, select the last one, this is the @@ -9394,7 +9964,7 @@ Graph.prototype._onMouseDown = function (event) { // move clicked node with the mouse // make the clicked node temporarily fixed, and store their original state - var node = this.nodes[this.startClickedObj.row]; + var node = this.nodes[this.startClickedObj]; this.startClickedObj.xFixed = node.xFixed; this.startClickedObj.yFixed = node.yFixed; node.xFixed = true; @@ -9434,13 +10004,13 @@ Graph.prototype._onMouseMove = function (event) { return; } - var mouseX = event.clientX || (event.targetTouches && event.targetTouches[0].clientX) || 0; - var mouseY = event.clientY || (event.targetTouches && event.targetTouches[0].clientY) || 0; + var mouseX = util.getPageX(event); + var mouseY = util.getPageY(event); this.mouseX = mouseX; this.mouseY = mouseY; if (this.startClickedObj) { - var node = this.nodes[this.startClickedObj.row]; + var node = this.nodes[this.startClickedObj]; if (!this.startClickedObj.xFixed) node.x = this._xToCanvas(mouseX - this.startFrameLeft); @@ -9514,14 +10084,14 @@ Graph.prototype._onMouseUp = function (event) { vis.util.preventDefault(event); // check selected nodes - var endMouseX = event.clientX || this.mouseX || 0; - var endMouseY = event.clientY || this.mouseY || 0; + var endMouseX = util.getPageX(event) || this.mouseX || 0; + var endMouseY = util.getPageY(event) || this.mouseY || 0; var ctrlKey = event ? event.ctrlKey : window.event.ctrlKey; if (this.startClickedObj) { // restore the original fixed state - var node = this.nodes[this.startClickedObj.row]; + var node = this.nodes[this.startClickedObj]; node.xFixed = this.startClickedObj.xFixed; node.yFixed = this.startClickedObj.yFixed; } @@ -9564,8 +10134,8 @@ Graph.prototype._onMouseUp = function (event) { */ Graph.prototype._onMouseWheel = function(event) { event = event || window.event; - var mouseX = event.clientX; - var mouseY = event.clientY; + var mouseX = util.getPageX(event); + var mouseY = util.getPageY(event); // retrieve delta var delta = 0; @@ -9627,8 +10197,8 @@ Graph.prototype._onMouseWheel = function(event) { Graph.prototype._onMouseMoveTitle = function (event) { event = event || window.event; - var startMouseX = event.clientX; - var startMouseY = event.clientY; + var startMouseX = util.getPageX(event); + var startMouseY = util.getPageY(event); this.startFrameLeft = this.startFrameLeft || vis.util.getAbsoluteLeft(this.frame.canvas); this.startFrameTop = this.startFrameTop || vis.util.getAbsoluteTop(this.frame.canvas); @@ -9671,29 +10241,34 @@ Graph.prototype._checkShowPopup = function (x, y) { "bottom" : this._yToCanvas(y) }; - var i, len; + var id; var lastPopupNode = this.popupNode; if (this.popupNode == undefined) { // search the nodes for overlap, select the top one in case of multiple nodes var nodes = this.nodes; - for (i = nodes.length - 1; i >= 0; i--) { - var node = nodes[i]; - if (node.getTitle() != undefined && node.isOverlappingWith(obj)) { - this.popupNode = node; - break; + for (id in nodes) { + if (nodes.hasOwnProperty(id)) { + var node = nodes[id]; + if (node.getTitle() != undefined && node.isOverlappingWith(obj)) { + this.popupNode = node; + break; + } } } } if (this.popupNode == undefined) { // search the edges for overlap - var allEdges = this.edges; - for (i = 0, len = allEdges.length; i < len; i++) { - var edge = allEdges[i]; - if (edge.getTitle() != undefined && edge.isOverlappingWith(obj)) { - this.popupNode = edge; - break; + var edges = this.edges; + for (id in edges) { + if (edges.hasOwnProperty(id)) { + var edge = edges[id]; + if (edge.connected && (edge.getTitle() != undefined) && + edge.isOverlappingWith(obj)) { + this.popupNode = edge; + break; + } } } } @@ -9816,17 +10391,17 @@ Graph.prototype._onTouchEnd = function(event) { */ Graph.prototype._unselectNodes = function(selection, triggerSelect) { var changed = false; - var i, iMax, row; + var i, iMax, id; if (selection) { // remove provided selections for (i = 0, iMax = selection.length; i < iMax; i++) { - row = selection[i].row; - this.nodes[row].unselect(); + id = selection[i]; + this.nodes[id].unselect(); var j = 0; while (j < this.selection.length) { - if (this.selection[j].row == row) { + if (this.selection[j] == id) { this.selection.splice(j, 1); changed = true; } @@ -9839,8 +10414,8 @@ Graph.prototype._unselectNodes = function(selection, triggerSelect) { else if (this.selection && this.selection.length) { // remove all selections for (i = 0, iMax = this.selection.length; i < iMax; i++) { - row = this.selection[i].row; - this.nodes[row].unselect(); + id = this.selection[i]; + this.nodes[id].unselect(); changed = true; } this.selection = []; @@ -9856,8 +10431,7 @@ Graph.prototype._unselectNodes = function(selection, triggerSelect) { /** * select all nodes on given location x, y - * @param {Array} selection an array with selection objects. Each selection - * object has a parameter row + * @param {Array} selection an array with node ids * @param {boolean} append If true, the new selection will be appended to the * current selection (except for duplicate entries) * @return {Boolean} changed True if the selection is changed @@ -9870,19 +10444,19 @@ Graph.prototype._selectNodes = function(selection, append) { // TODO: the selectNodes method is a little messy, rework this // check if the current selection equals the desired selection - var selectionAlreadyDone = true; + var selectionAlreadyThere = true; if (selection.length != this.selection.length) { - selectionAlreadyDone = false; + selectionAlreadyThere = false; } else { for (i = 0, iMax = Math.min(selection.length, this.selection.length); i < iMax; i++) { - if (selection[i].row != this.selection[i].row) { - selectionAlreadyDone = false; + if (selection[i] != this.selection[i]) { + selectionAlreadyThere = false; break; } } } - if (selectionAlreadyDone) { + if (selectionAlreadyThere) { return changed; } @@ -9894,18 +10468,11 @@ Graph.prototype._selectNodes = function(selection, append) { for (i = 0, iMax = selection.length; i < iMax; i++) { // add each of the new selections, but only when they are not duplicate - var row = selection[i].row; - var isDuplicate = false; - for (var j = 0, jMax = this.selection.length; j < jMax; j++) { - if (this.selection[j].row == row) { - isDuplicate = true; - break; - } - } - + var id = selection[i]; + var isDuplicate = (this.selection.indexOf(id) != -1); if (!isDuplicate) { - this.nodes[row].select(); - this.selection.push(selection[i]); + this.nodes[id].select(); + this.selection.push(id); changed = true; } } @@ -9926,12 +10493,14 @@ Graph.prototype._selectNodes = function(selection, append) { * @private */ Graph.prototype._getNodesOverlappingWith = function (obj) { - var overlappingNodes = []; + var nodes = this.nodes, + overlappingNodes = []; - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].isOverlappingWith(obj)) { - var sel = {"row": i}; - overlappingNodes.push(sel); + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + if (nodes[id].isOverlappingWith(obj)) { + overlappingNodes.push(id); + } } } @@ -9940,55 +10509,62 @@ Graph.prototype._getNodesOverlappingWith = function (obj) { /** * retrieve the currently selected nodes - * @return {Object[]} an array with zero or more objects. Each object - * contains the parameter row + * @return {Number[] | String[]} selection An array with the ids of the + * selected nodes. */ Graph.prototype.getSelection = function() { - var selection = []; - - for (var i = 0; i < this.selection.length; i++) { - var row = this.selection[i].row; - selection.push({"row": row}); - } - - return selection; + return this.selection.concat([]); }; /** * select zero or more nodes - * @param {object[]} selection an array with zero or more objects. Each object - * contains the parameter row + * @param {Number[] | String[]} selection An array with the ids of the + * selected nodes. */ Graph.prototype.setSelection = function(selection) { - var i, iMax, row; + var i, iMax, id; if (selection.length == undefined) - throw "Selection must be an array with objects"; + throw "Selection must be an array with ids"; // first unselect any selected node for (i = 0, iMax = this.selection.length; i < iMax; i++) { - row = this.selection[i].row; - this.nodes[row].unselect(); + id = this.selection[i]; + this.nodes[id].unselect(); } this.selection = []; for (i = 0, iMax = selection.length; i < iMax; i++) { - row = selection[i].row; - - if (row == undefined) - throw "Parameter row missing in selection object"; - if (row > this.nodes.length-1) - throw "Parameter row out of range"; + id = selection[i]; - var sel = {"row": row}; - this.selection.push(sel); - this.nodes[row].select(); + var node = this.nodes[id]; + if (!node) { + throw new RangeError('Node with id "' + id + '" not found'); + } + node.select(); + this.selection.push(id); } this.redraw(); }; +/** + * Validate the selection: remove ids of nodes which no longer exist + * @private + */ +Graph.prototype._updateSelection = function () { + var i = 0; + while (i < this.selection.length) { + var id = this.selection[i]; + if (!this.nodes[id]) { + this.selection.splice(i, 1); + } + else { + i++; + } + } +}; /** * Temporary method to test calculating a hub value for the nodes @@ -9999,7 +10575,6 @@ Graph.prototype.setSelection = function(selection) { * @private */ Graph.prototype._getConnectionCount = function(level) { - var conn = this.edges; if (level == undefined) { level = 1; } @@ -10012,14 +10587,16 @@ Graph.prototype._getConnectionCount = function(level) { var node = nodes[j]; // find all nodes connected to this node - for (var i = 0, iMax = conn.length; i < iMax; i++) { + var edges = node.edges; + for (var i = 0, iMax = edges.length; i < iMax; i++) { + var edge = edges[i]; var other = null; // check if connected - if (conn[i].from == node) - other = conn[i].to; - else if (conn[i].to == node) - other = conn[i].from; + if (edge.from == node) + other = edge.to; + else if (edge.to == node) + other = edge.from; // check if the other node is not already in the list with nodes var k, kMax; @@ -10049,19 +10626,19 @@ Graph.prototype._getConnectionCount = function(level) { } var connections = []; - var level0 = []; var nodes = this.nodes; - var i, iMax; - for (i = 0, iMax = nodes.length; i < iMax; i++) { - var c = [nodes[i]]; - for (var l = 0; l < level; l++) { - c = c.concat(getConnectedNodes(c)); + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + var c = [nodes[id]]; + for (var l = 0; l < level; l++) { + c = c.concat(getConnectedNodes(c)); + } + connections.push(c); } - connections.push(c); } var hubs = []; - for (i = 0, len = connections.length; i < len; i++) { + for (var i = 0, len = connections.length; i < len; i++) { hubs.push(connections[i].length); } @@ -10089,365 +10666,306 @@ Graph.prototype.setSize = function(width, height) { /** * Set a data set with nodes for the graph - * @param {Array} nodes The data containing the nodes. + * @param {Array | DataSet | DataView} nodes The data containing the nodes. * @private */ Graph.prototype._setNodes = function(nodes) { - this.selection = []; - this.nodes = []; - this.moving = false; - if (!nodes) { - return; - } + var oldNodesData = this.nodesData; - var hasValues = false; - var rowCount = nodes.length; - for (var i = 0; i < rowCount; i++) { - var properties = nodes[i]; + if (nodes instanceof DataSet || nodes instanceof DataView) { + this.nodesData = nodes; + } + else if (nodes instanceof Array) { + this.nodesData = new DataSet(); + this.nodesData.add(nodes); + } + else if (!nodes) { + this.nodesData = new DataSet(); + } + else { + throw new TypeError('Array or DataSet expected'); + } - if (properties.value != undefined) { - hasValues = true; - } - if (properties.id == undefined) { - throw "Column 'id' missing in table with nodes (row " + i + ")"; - } - this._createNode(properties); + if (oldNodesData) { + // unsubscribe from old dataset + util.forEach(this.nodesListeners, function (callback, event) { + oldNodesData.unsubscribe(event, callback); + }); } - // calculate scaling function when value is provided - if (hasValues) { - this._updateValueRange(this.nodes); + // remove drawn nodes + this.nodes = {}; + + if (this.nodesData) { + // subscribe to new dataset + var me = this; + util.forEach(this.nodesListeners, function (callback, event) { + me.nodesData.subscribe(event, callback); + }); + + // draw all new nodes + var ids = this.nodesData.getIds(); + this._addNodes(ids); } - // give the nodes some first (random) position - this._reposition(); // TODO: bad solution + this._updateSelection(); }; /** - * Create a node with the given properties - * If the new node has an id identical to an existing node, the existing - * node will be overwritten. - * The properties can contain a property "action", which can have values - * "create", "update", or "delete" - * @param {Object} properties An object with properties + * Add nodes + * @param {Number[] | String[]} ids * @private */ -Graph.prototype._createNode = function(properties) { - var action = properties.action ? properties.action : "update"; - var id, index, newNode, oldNode; - - if (action === "create") { - // create the node - newNode = new Node(properties, this.images, this.groups, this.constants); - id = properties.id; - index = (id !== undefined) ? this._findNode(id) : undefined; - - if (index !== undefined) { - // replace node - oldNode = this.nodes[index]; - this.nodes[index] = newNode; - - // remove selection of old node - if (oldNode.selected) { - this._unselectNodes([{'row': index}], false); - } - - /* TODO: implement this? -> will give performance issues, searching all edges and nodes... - // update edges linking to this node - var edgesTable = this.edges; - for (var i = 0, iMax = edgesTable.length; i < iMax; i++) { - var edge = edgesTable[i]; - if (edge.from == oldNode) { - edge.from = newNode; - } - if (edge.to == oldNode) { - edge.to = newNode; - } - } - */ - } - else { - // add new node - this.nodes.push(newNode); - } +Graph.prototype._addNodes = function(ids) { + var id; + for (var i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + var data = this.nodesData.get(id); + var node = new Node(data, this.images, this.groups, this.constants); + this.nodes[id] = node; // note: this may replace an existing node + + if (!node.isFixed()) { + // TODO: position new nodes in a smarter way! + var radius = this.constants.edges.length * 2; + var count = ids.length; + var angle = 2 * Math.PI * (i / count); + node.x = radius * Math.cos(angle); + node.y = radius * Math.sin(angle); - if (!newNode.isFixed()) { // note: no not use node.isMoving() here, as that gives the current // velocity of the node, which is zero after creation of the node. this.moving = true; } } - else if (action === "update") { - // update existing node, or create it when not yet existing - id = properties.id; - if (id === undefined) { - throw "Cannot update a node without id"; - } - index = this._findNode(id); - if (index !== undefined) { + this._reconnectEdges(); + this._updateValueRange(this.nodes); +}; + +/** + * Update existing nodes, or create them when not yet existing + * @param {Number[] | String[]} ids + * @private + */ +Graph.prototype._updateNodes = function(ids) { + var nodes = this.nodes, + nodesData = this.nodesData; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + var node = nodes[id]; + var data = nodesData.get(id); + if (node) { // update node - this.nodes[index].setProperties(properties, this.constants); + node.setProperties(data, this.constants); } else { // create node - newNode = new Node(properties, this.images, this.groups, this.constants); - this.nodes.push(newNode); + node = new Node(properties, this.images, this.groups, this.constants); + nodes[id] = node; - if (!newNode.isFixed()) { - // note: no not use node.isMoving() here, as that gives the current - // velocity of the node, which is zero after creation of the node. + if (!node.isFixed()) { this.moving = true; } } } - else if (action === "delete") { - // delete existing node - id = properties.id; - if (id === undefined) { - throw "Cannot delete node without its id"; - } - index = this._findNode(id); - if (index !== undefined) { - oldNode = this.nodes[index]; - // remove selection of old node - if (oldNode.selected) { - this._unselectNodes([{'row': index}], false); - } - this.nodes.splice(index, 1); - } - else { - throw "Node with id " + id + " not found"; - } - } - else { - throw "Unknown action " + action + ". Choose 'create', 'update', or 'delete'."; - } + this._reconnectEdges(); + this._updateValueRange(nodes); }; /** - * Find a node by its id - * @param {Number} id Id of the node - * @return {Number | undefined} index Index of the node in the array - * this.nodes, or undefined when not found + * Remove existing nodes. If nodes do not exist, the method will just ignore it. + * @param {Number[] | String[]} ids * @private */ -Graph.prototype._findNode = function (id) { +Graph.prototype._removeNodes = function(ids) { var nodes = this.nodes; - for (var n = 0, len = nodes.length; n < len; n++) { - if (nodes[n].id === id) { - return n; - } + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + delete nodes[id]; } - return undefined; -}; - -/** - * Find a node by its rowNumber - * @param {Number} row Row number of the node - * @return {Node} node     The node with the given row number, or - *                            undefined when not found. - * @private - */ -Graph.prototype._findNodeByRow = function (row) { - return this.nodes[row]; + this._reconnectEdges(); + this._updateSelection(); + this._updateValueRange(nodes); }; /** * Load edges by reading the data table - * @param {Array} edges The data containing the edges. + * @param {Array | DataSet | DataView} edges The data containing the edges. * @private * @private */ Graph.prototype._setEdges = function(edges) { - this.edges = []; - if (!edges) { - return; + var oldEdgesData = this.edgesData; + + if (edges instanceof DataSet || edges instanceof DataView) { + this.edgesData = edges; + } + else if (edges instanceof Array) { + this.edgesData = new DataSet(); + this.edgesData.add(edges); + } + else if (!edges) { + this.edgesData = new DataSet(); + } + else { + throw new TypeError('Array or DataSet expected'); } - var hasValues = false; - var rowCount = edges.length; - for (var i = 0; i < rowCount; i++) { - var properties = edges[i]; + if (oldEdgesData) { + // unsubscribe from old dataset + util.forEach(this.edgesListeners, function (callback, event) { + oldEdgesData.unsubscribe(event, callback); + }); + } - if (properties.from === undefined) { - throw "Column 'from' missing in table with edges (row " + i + ")"; - } - if (properties.to === undefined) { - throw "Column 'to' missing in table with edges (row " + i + ")"; - } - if (properties.value != undefined) { - hasValues = true; - } + // remove drawn edges + this.edges = {}; - this._createEdge(properties); - } + if (this.edgesData) { + // subscribe to new dataset + var me = this; + util.forEach(this.edgesListeners, function (callback, event) { + me.edgesData.subscribe(event, callback); + }); - // calculate scaling function when value is provided - if (hasValues) { - this._updateValueRange(this.edges); + // draw all new nodes + var ids = this.edgesData.getIds(); + this._addEdges(ids); } + + this._reconnectEdges(); }; /** - * Create a edge with the given properties - * If the new edge has an id identical to an existing edge, the existing - * edge will be overwritten or updated. - * The properties can contain a property "action", which can have values - * "create", "update", or "delete" - * @param {Object} properties An object with properties + * Add edges + * @param {Number[] | String[]} ids * @private */ -Graph.prototype._createEdge = function(properties) { - var action = properties.action ? properties.action : "create"; - var id, index, edge, oldEdge, newEdge; +Graph.prototype._addEdges = function (ids) { + var edges = this.edges, + edgesData = this.edgesData; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; - if (action === "create") { - // create the edge, or replace it if already existing - id = properties.id; - index = (id !== undefined) ? this._findEdge(id) : undefined; - edge = new Edge(properties, this, this.constants); - - if (index !== undefined) { - // replace existing edge - oldEdge = this.edges[index]; - oldEdge.from.detachEdge(oldEdge); - oldEdge.to.detachEdge(oldEdge); - this.edges[index] = edge; - } - else { - // add new edge - this.edges.push(edge); - } - edge.from.attachEdge(edge); - edge.to.attachEdge(edge); - } - else if (action === "update") { - // update existing edge, or create the edge if not existing - id = properties.id; - if (id === undefined) { - throw "Cannot update a edge without id"; + var oldEdge = edges[id]; + if (oldEdge) { + oldEdge.disconnect(); } - index = this._findEdge(id); - if (index !== undefined) { - // update edge - edge = this.edges[index]; - edge.from.detachEdge(edge); - edge.to.detachEdge(edge); - - edge.setProperties(properties, this.constants); - edge.from.attachEdge(edge); - edge.to.attachEdge(edge); - } - else { - // add new edge - edge = new Edge(properties, this, this.constants); - edge.from.attachEdge(edge); - edge.to.attachEdge(edge); - this.edges.push(edge); - } + var data = edgesData.get(id); + edges[id] = new Edge(data, this, this.constants); } - else if (action === "delete") { - // delete existing edge - id = properties.id; - if (id === undefined) { - throw "Cannot delete edge without its id"; - } - index = this._findEdge(id); - if (index !== undefined) { - oldEdge = this.edges[id]; - edge.from.detachEdge(oldEdge); - edge.to.detachEdge(oldEdge); - this.edges.splice(index, 1); - } - else { - throw "Edge with id " + id + " not found"; - } - } - else { - throw "Unknown action " + action + ". Choose 'create', 'update', or 'delete'."; - } + this.moving = true; + this._updateValueRange(edges); }; /** - * Update the references to oldNode in all edges. - * @param {Node} oldNode - * @param {Node} newNode + * Update existing edges, or create them when not yet existing + * @param {Number[] | String[]} ids * @private */ -// TODO: start utilizing this method _updateNodeReferences -Graph.prototype._updateNodeReferences = function(oldNode, newNode) { - var edges = this.edges; - for (var i = 0, iMax = edges.length; i < iMax; i++) { - var edge = edges[i]; - if (edge.from === oldNode) { - edge.from = newNode; +Graph.prototype._updateEdges = function (ids) { + var edges = this.edges, + edgesData = this.edgesData; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + + var data = edgesData.get(id); + var edge = edges[id]; + if (edge) { + // update edge + edge.disconnect(); + edge.setProperties(data, this.constants); + edge.connect(); } - if (edge.to === oldNode) { - edge.to = newNode; + else { + // create edge + edge = new Edge(data, this, this.constants); + this.edges[id] = edge; } } + + this.moving = true; + this._updateValueRange(edges); }; /** - * Find a edge by its id - * @param {Number} id Id of the edge - * @return {Number | undefined} index Index of the edge in the array - * this.edges, or undefined when not found + * Remove existing edges. Non existing ids will be ignored + * @param {Number[] | String[]} ids * @private */ -Graph.prototype._findEdge = function (id) { +Graph.prototype._removeEdges = function (ids) { var edges = this.edges; - for (var n = 0, len = edges.length; n < len; n++) { - if (edges[n].id === id) { - return n; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + var edge = edges[id]; + if (edge) { + edge.disconnect(); + delete edges[id]; } } - return undefined; + this.moving = true; + this._updateValueRange(edges); }; /** - * Find a edge by its row - * @param {Number} row Row of the edge - * @return {Edge | undefined} the found edge, or undefined when not found + * Reconnect all edges * @private */ -Graph.prototype._findEdgeByRow = function (row) { - return this.edges[row]; +Graph.prototype._reconnectEdges = function() { + var id, + nodes = this.nodes, + edges = this.edges; + for (id in nodes) { + if (nodes.hasOwnProperty(id)) { + nodes[id].edges = []; + } + } + + for (id in edges) { + if (edges.hasOwnProperty(id)) { + var edge = edges[id]; + edge.from = null; + edge.to = null; + edge.connect(); + } + } }; /** * Update the values of all object in the given array according to the current * value range of the objects in the array. - * @param {Array} array. An array with objects like Edges or Nodes + * @param {Object} obj An object containing a set of Edges or Nodes * The objects must have a method getValue() and * setValueRange(min, max). * @private */ -Graph.prototype._updateValueRange = function(array) { - var count = array.length; - var i; +Graph.prototype._updateValueRange = function(obj) { + var id; - // determine the range of the node values + // determine the range of the objects var valueMin = undefined; var valueMax = undefined; - for (i = 0; i < count; i++) { - var value = array[i].getValue(); - if (value !== undefined) { - valueMin = (valueMin === undefined) ? value : Math.min(value, valueMin); - valueMax = (valueMax === undefined) ? value : Math.max(value, valueMax); + for (id in obj) { + if (obj.hasOwnProperty(id)) { + var value = obj[id].getValue(); + if (value !== undefined) { + valueMin = (valueMin === undefined) ? value : Math.min(value, valueMin); + valueMax = (valueMax === undefined) ? value : Math.max(value, valueMax); + } } } - // adjust the range of all nodes + // adjust the range of all objects if (valueMin !== undefined && valueMax !== undefined) { - for (i = 0; i < count; i++) { - array[i].setValueRange(valueMin, valueMax); + for (id in obj) { + if (obj.hasOwnProperty(id)) { + obj[id].setValueRange(valueMin, valueMax); + } } } }; @@ -10553,23 +11071,6 @@ Graph.prototype._canvasToY = function(y) { return y * this.scale + this.translation.y ; }; - - -/** - * Get a node by its id - * @param {number} id - * @return {Node} node, or null if not found - * @private - */ -Graph.prototype._getNode = function(id) { - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].id == id) - return this.nodes[i]; - } - - return null; -}; - /** * Redraw all nodes * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); @@ -10580,12 +11081,14 @@ Graph.prototype._drawNodes = function(ctx) { // first draw the unselected nodes var nodes = this.nodes; var selected = []; - for (var i = 0, iMax = nodes.length; i < iMax; i++) { - if (nodes[i].isSelected()) { - selected.push(i); - } - else { - nodes[i].draw(ctx); + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + if (nodes[id].isSelected()) { + selected.push(id); + } + else { + nodes[id].draw(ctx); + } } } @@ -10603,72 +11106,16 @@ Graph.prototype._drawNodes = function(ctx) { */ Graph.prototype._drawEdges = function(ctx) { var edges = this.edges; - for (var i = 0, iMax = edges.length; i < iMax; i++) { - edges[i].draw(ctx); + for (var id in edges) { + if (edges.hasOwnProperty(id)) { + var edge = edges[id]; + if (edge.connected) { + edges[id].draw(ctx); + } + } } }; -/** - * Recalculate the best positions for all nodes - * @private - */ -Graph.prototype._reposition = function() { - // TODO: implement function reposition - - - /* - var w = this.frame.canvas.clientWidth; - var h = this.frame.canvas.clientHeight; - for (var i = 0; i < this.nodes.length; i++) { - if (!this.nodes[i].xFixed) this.nodes[i].x = w * Math.random(); - if (!this.nodes[i].yFixed) this.nodes[i].y = h * Math.random(); - } - //*/ - - //* - // TODO - var radius = this.constants.edges.length * 2; - var cx = this.frame.canvas.clientWidth / 2; - var cy = this.frame.canvas.clientHeight / 2; - for (var i = 0; i < this.nodes.length; i++) { - var angle = 2*Math.PI * (i / this.nodes.length); - - if (!this.nodes[i].xFixed) this.nodes[i].x = cx + radius * Math.cos(angle); - if (!this.nodes[i].yFixed) this.nodes[i].y = cy + radius * Math.sin(angle); - - } - //*/ - - /* - // TODO - var radius = this.constants.edges.length * 2; - var w = this.frame.canvas.clientWidth, - h = this.frame.canvas.clientHeight; - var cx = this.frame.canvas.clientWidth / 2; - var cy = this.frame.canvas.clientHeight / 2; - var s = Math.sqrt(this.nodes.length); - for (var i = 0; i < this.nodes.length; i++) { - //var angle = 2*Math.PI * (i / this.nodes.length); - - if (!this.nodes[i].xFixed) this.nodes[i].x = w/s * (i % s); - if (!this.nodes[i].yFixed) this.nodes[i].y = h/s * (i / s); - } - //*/ - - - /* - var cx = this.frame.canvas.clientWidth / 2; - var cy = this.frame.canvas.clientHeight / 2; - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].x = cx; - this.nodes[i].y = cy; - } - - //*/ - -}; - - /** * Find a stable position for all nodes * @private @@ -10699,7 +11146,9 @@ Graph.prototype._doStabilize = function() { */ Graph.prototype._calculateForces = function() { // create a local edge to the nodes and edges, that is faster - var nodes = this.nodes, + var id, dx, dy, angle, distance, fx, fy, + repulsingForce, springForce, length, edgeLength, + nodes = this.nodes, edges = this.edges; // gravity, add a small constant force to pull the nodes towards the center of @@ -10709,42 +11158,51 @@ Graph.prototype._calculateForces = function() { var gravity = 0.01, gx = this.frame.canvas.clientWidth / 2, gy = this.frame.canvas.clientHeight / 2; - for (var n = 0; n < nodes.length; n++) { - var dx = gx - nodes[n].x, - dy = gy - nodes[n].y, - angle = Math.atan2(dy, dx), - fx = Math.cos(angle) * gravity, + for (id in nodes) { + if (nodes.hasOwnProperty(id)) { + var node = nodes[id]; + dx = gx - node.x; + dy = gy - node.y; + angle = Math.atan2(dy, dx); + fx = Math.cos(angle) * gravity; fy = Math.sin(angle) * gravity; - this.nodes[n]._setForce(fx, fy); + node._setForce(fx, fy); + } } // repulsing forces between nodes var minimumDistance = this.constants.nodes.distance, steepness = 10; // higher value gives steeper slope of the force around the given minimumDistance + + for (var id1 in nodes) { + if (nodes.hasOwnProperty(id1)) { + var node1 = nodes[id1]; + for (var id2 in nodes) { + if (nodes.hasOwnProperty(id2)) { + var node2 = nodes[id2]; + // calculate normally distributed force + dx = node2.x - node1.x; + dy = node2.y - node1.y; + distance = Math.sqrt(dx * dx + dy * dy); + angle = Math.atan2(dy, dx); + + // TODO: correct factor for repulsing force + //repulsingForce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force + //repulsingForce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force + repulsingForce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)); // TODO: customize the repulsing force + fx = Math.cos(angle) * repulsingForce; + fy = Math.sin(angle) * repulsingForce; + + node1._addForce(-fx, -fy); + node2._addForce(fx, fy); + } + } + } + } + + /* TODO: re-implement repulsion of edges for (var n = 0; n < nodes.length; n++) { - for (var n2 = n + 1; n2 < this.nodes.length; n2++) { - //var dmin = (nodes[n].width + nodes[n].height + nodes[n2].width + nodes[n2].height) / 1 || minimumDistance, // TODO: dmin - //var dmin = (nodes[n].width + nodes[n2].width)/2 || minimumDistance, // TODO: dmin - //dmin = 40 + ((nodes[n].width/2 + nodes[n2].width/2) || 0), - - // calculate normally distributed force - var dx = nodes[n2].x - nodes[n].x, - dy = nodes[n2].y - nodes[n].y, - distance = Math.sqrt(dx * dx + dy * dy), - angle = Math.atan2(dy, dx), - - // TODO: correct factor for repulsing force - //var repulsingforce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force - //repulsingforce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ), // TODO: customize the repulsing force - repulsingforce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)), // TODO: customize the repulsing force - fx = Math.cos(angle) * repulsingforce, - fy = Math.sin(angle) * repulsingforce; - - this.nodes[n]._addForce(-fx, -fy); - this.nodes[n2]._addForce(fx, fy); - } - /* TODO: re-implement repulsion of edges for (var l = 0; l < edges.length; l++) { var lx = edges[l].from.x+(edges[l].to.x - edges[l].from.x)/2, ly = edges[l].from.y+(edges[l].to.y - edges[l].from.y)/2, @@ -10766,29 +11224,32 @@ Graph.prototype._calculateForces = function() { edges[l].from._addForce(-fx/2,-fy/2); edges[l].to._addForce(-fx/2,-fy/2); } - */ } + */ // forces caused by the edges, modelled as springs - for (var l = 0, lMax = edges.length; l < lMax; l++) { - var edge = edges[l], - - dx = (edge.to.x - edge.from.x), - dy = (edge.to.y - edge.from.y), - //edgeLength = (edge.from.width + edge.from.height + edge.to.width + edge.to.height)/2 || edge.length, // TODO: dmin - //edgeLength = (edge.from.width + edge.to.width)/2 || edge.length, // TODO: dmin - //edgeLength = 20 + ((edge.from.width + edge.to.width) || 0) / 2, - edgeLength = edge.length, - length = Math.sqrt(dx * dx + dy * dy), - angle = Math.atan2(dy, dx), + for (id in edges) { + if (edges.hasOwnProperty(id)) { + var edge = edges[id]; + if (edge.connected) { + dx = (edge.to.x - edge.from.x); + dy = (edge.to.y - edge.from.y); + //edgeLength = (edge.from.width + edge.from.height + edge.to.width + edge.to.height)/2 || edge.length; // TODO: dmin + //edgeLength = (edge.from.width + edge.to.width)/2 || edge.length; // TODO: dmin + //edgeLength = 20 + ((edge.from.width + edge.to.width) || 0) / 2; + edgeLength = edge.length; + length = Math.sqrt(dx * dx + dy * dy); + angle = Math.atan2(dy, dx); - springforce = edge.stiffness * (edgeLength - length), + springForce = edge.stiffness * (edgeLength - length); - fx = Math.cos(angle) * springforce, - fy = Math.sin(angle) * springforce; + fx = Math.cos(angle) * springForce; + fy = Math.sin(angle) * springForce; - edge.from._addForce(-fx, -fy); - edge.to._addForce(fx, fy); + edge.from._addForce(-fx, -fy); + edge.to._addForce(fx, fy); + } + } } /* TODO: re-implement repulsion of edges @@ -10839,8 +11300,8 @@ Graph.prototype._calculateForces = function() { Graph.prototype._isMoving = function(vmin) { // TODO: ismoving does not work well: should check the kinetic energy, not its velocity var nodes = this.nodes; - for (var n = 0, nMax = nodes.length; n < nMax; n++) { - if (nodes[n].isMoving(vmin)) { + for (var id in nodes) { + if (nodes.hasOwnProperty(id) && nodes[id].isMoving(vmin)) { return true; } } @@ -10855,8 +11316,10 @@ Graph.prototype._isMoving = function(vmin) { Graph.prototype._discreteStepNodes = function() { var interval = this.refreshRate / 1000.0; // in seconds var nodes = this.nodes; - for (var n = 0, nMax = nodes.length; n < nMax; n++) { - nodes[n].discreteStep(interval); + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + nodes[id].discreteStep(interval); + } } }; @@ -10968,7 +11431,7 @@ if (typeof window !== 'undefined') { } // inject css -util.loadCss("/* vis.js stylesheet */\n\n.graph {\n position: relative;\n border: 1px solid #bfbfbf;\n}\n\n.graph .panel {\n position: absolute;\n}\n\n.graph .groupset {\n position: absolute;\n padding: 0;\n margin: 0;\n}\n\n\n.graph .itemset {\n position: absolute;\n padding: 0;\n margin: 0;\n overflow: hidden;\n}\n\n.graph .background {\n}\n\n.graph .foreground {\n}\n\n.graph .itemset-axis {\n position: absolute;\n}\n\n.graph .groupset .itemset-axis {\n border-top: 1px solid #bfbfbf;\n}\n\n/* TODO: with orientation=='bottom', this will more or less overlap with timeline axis\n.graph .groupset .itemset-axis:last-child {\n border-top: none;\n}\n*/\n\n\n.graph .item {\n position: absolute;\n color: #1A1A1A;\n border-color: #97B0F8;\n background-color: #D5DDF6;\n display: inline-block;\n}\n\n.graph .item.selected {\n border-color: #FFC200;\n background-color: #FFF785;\n z-index: 999;\n}\n\n.graph .item.cluster {\n /* TODO: use another color or pattern? */\n background: #97B0F8 url('img/cluster_bg.png');\n color: white;\n}\n.graph .item.cluster.point {\n border-color: #D5DDF6;\n}\n\n.graph .item.box {\n text-align: center;\n border-style: solid;\n border-width: 1px;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.graph .item.point {\n background: none;\n}\n\n.graph .dot {\n border: 5px solid #97B0F8;\n position: absolute;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.graph .item.range {\n overflow: hidden;\n border-style: solid;\n border-width: 1px;\n border-radius: 2px;\n -moz-border-radius: 2px; /* For Firefox 3.6 and older */\n}\n\n.graph .item.range .drag-left {\n cursor: w-resize;\n z-index: 1000;\n}\n\n.graph .item.range .drag-right {\n cursor: e-resize;\n z-index: 1000;\n}\n\n.graph .item.range .content {\n position: relative;\n display: inline-block;\n}\n\n.graph .item.line {\n position: absolute;\n width: 0;\n border-left-width: 1px;\n border-left-style: solid;\n}\n\n.graph .item .content {\n margin: 5px;\n white-space: nowrap;\n overflow: hidden;\n}\n\n/* TODO: better css name, 'graph' is way to generic */\n\n.graph {\n overflow: hidden;\n}\n\n.graph .axis {\n position: relative;\n}\n\n.graph .axis .text {\n position: absolute;\n color: #4d4d4d;\n padding: 3px;\n white-space: nowrap;\n}\n\n.graph .axis .text.measure {\n position: absolute;\n padding-left: 0;\n padding-right: 0;\n margin-left: 0;\n margin-right: 0;\n visibility: hidden;\n}\n\n.graph .axis .grid.vertical {\n position: absolute;\n width: 0;\n border-right: 1px solid;\n}\n\n.graph .axis .grid.horizontal {\n position: absolute;\n left: 0;\n width: 100%;\n height: 0;\n border-bottom: 1px solid;\n}\n\n.graph .axis .grid.minor {\n border-color: #e5e5e5;\n}\n\n.graph .axis .grid.major {\n border-color: #bfbfbf;\n}\n\n"); +util.loadCss("/* vis.js stylesheet */\n.vis.timeline {\n}\n\n\n.vis.timeline.rootpanel {\n position: relative;\n overflow: hidden;\n\n border: 1px solid #bfbfbf;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n\n.vis.timeline .panel {\n position: absolute;\n overflow: hidden;\n}\n\n\n.vis.timeline .groupset {\n position: absolute;\n padding: 0;\n margin: 0;\n}\n\n.vis.timeline .labels {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n\n padding: 0;\n margin: 0;\n\n border-right: 1px solid #bfbfbf;\n box-sizing: border-box;\n -moz-box-sizing: border-box;\n}\n\n.vis.timeline .labels .label {\n position: absolute;\n left: 0;\n top: 0;\n width: 100%;\n border-bottom: 1px solid #bfbfbf;\n color: #4d4d4d;\n}\n\n.vis.timeline .labels .label .inner {\n display: inline-block;\n padding: 5px;\n}\n\n\n.vis.timeline .itemset {\n position: absolute;\n padding: 0;\n margin: 0;\n overflow: hidden;\n}\n\n.vis.timeline .background {\n}\n\n.vis.timeline .foreground {\n}\n\n.vis.timeline .itemset-axis {\n position: absolute;\n}\n\n.vis.timeline .groupset .itemset-axis {\n border-top: 1px solid #bfbfbf;\n}\n\n/* TODO: with orientation=='bottom', this will more or less overlap with timeline axis\n.vis.timeline .groupset .itemset-axis:last-child {\n border-top: none;\n}\n*/\n\n\n.vis.timeline .item {\n position: absolute;\n color: #1A1A1A;\n border-color: #97B0F8;\n background-color: #D5DDF6;\n display: inline-block;\n}\n\n.vis.timeline .item.selected {\n border-color: #FFC200;\n background-color: #FFF785;\n z-index: 999;\n}\n\n.vis.timeline .item.cluster {\n /* TODO: use another color or pattern? */\n background: #97B0F8 url('img/cluster_bg.png');\n color: white;\n}\n.vis.timeline .item.cluster.point {\n border-color: #D5DDF6;\n}\n\n.vis.timeline .item.box {\n text-align: center;\n border-style: solid;\n border-width: 1px;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.point {\n background: none;\n}\n\n.vis.timeline .dot {\n border: 5px solid #97B0F8;\n position: absolute;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.range {\n overflow: hidden;\n border-style: solid;\n border-width: 1px;\n border-radius: 2px;\n -moz-border-radius: 2px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.range .drag-left {\n cursor: w-resize;\n z-index: 1000;\n}\n\n.vis.timeline .item.range .drag-right {\n cursor: e-resize;\n z-index: 1000;\n}\n\n.vis.timeline .item.range .content {\n position: relative;\n display: inline-block;\n}\n\n.vis.timeline .item.line {\n position: absolute;\n width: 0;\n border-left-width: 1px;\n border-left-style: solid;\n}\n\n.vis.timeline .item .content {\n margin: 5px;\n white-space: nowrap;\n overflow: hidden;\n}\n\n.vis.timeline .axis {\n position: relative;\n}\n\n.vis.timeline .axis .text {\n position: absolute;\n color: #4d4d4d;\n padding: 3px;\n white-space: nowrap;\n}\n\n.vis.timeline .axis .text.measure {\n position: absolute;\n padding-left: 0;\n padding-right: 0;\n margin-left: 0;\n margin-right: 0;\n visibility: hidden;\n}\n\n.vis.timeline .axis .grid.vertical {\n position: absolute;\n width: 0;\n border-right: 1px solid;\n}\n\n.vis.timeline .axis .grid.horizontal {\n position: absolute;\n left: 0;\n width: 100%;\n height: 0;\n border-bottom: 1px solid;\n}\n\n.vis.timeline .axis .grid.minor {\n border-color: #e5e5e5;\n}\n\n.vis.timeline .axis .grid.major {\n border-color: #bfbfbf;\n}\n\n"); })() },{"moment":2}],2:[function(require,module,exports){ diff --git a/vis.min.js b/vis.min.js index 6ee20a95..523f7179 100644 --- a/vis.min.js +++ b/vis.min.js @@ -4,8 +4,8 @@ * * A dynamic, browser-based visualization library. * - * @version 0.0.9 - * @date 2013-06-07 + * @version 0.1.0 + * @date 2013-06-20 * * @license * Copyright (C) 2011-2013 Almende B.V, http://almende.com @@ -22,8 +22,8 @@ * License for the specific language governing permissions and limitations under * the License. */ -(function(t){if("function"==typeof bootstrap)bootstrap("vis",t);else if("object"==typeof exports)module.exports=t();else if("function"==typeof define&&define.amd)define(t);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeVis=t}else"undefined"!=typeof window?window.vis=t():global.vis=t()})(function(){var t;return function(t,e,i){function s(i,n){if(!e[i]){if(!t[i]){var r="function"==typeof require&&require;if(!n&&r)return r(i,!0);if(o)return o(i,!0);throw Error("Cannot find module '"+i+"'")}var a=e[i]={exports:{}};t[i][0].call(a.exports,function(e){var o=t[i][1][e];return s(o?o:e)},a,a.exports)}return e[i].exports}for(var o="function"==typeof require&&require,n=0;i.length>n;n++)s(i[n]);return s}({1:[function(e,i,s){(function(){function o(){this.subscriptions=[]}function n(t){if(this.id=C.randomUUID(),this.options=t||{},this.data={},this.fieldId=this.options.fieldId||"id",this.fieldTypes={},this.options.fieldTypes)for(var e in this.options.fieldTypes)if(this.options.fieldTypes.hasOwnProperty(e)){var i=this.options.fieldTypes[e];this.fieldTypes[e]="Date"==i||"ISODate"==i||"ASPDate"==i?"Date":i}this.subscribers={},this.internalIds={}}function r(t,e){this.id=C.randomUUID(),this.data=null,this.ids={},this.options=e||{},this.fieldId="id",this.subscribers={};var i=this;this.listener=function(){i._onEvent.apply(i,arguments)},this.setData(t)}function a(t,e){this.parent=t,this.options=e||{},this.defaultOptions={order:function(t,e){if(t instanceof y){if(e instanceof y){var i=t.data.end-t.data.start,s=e.data.end-e.data.start;return i-s||t.data.start-e.data.start}return-1}return e instanceof y?1:t.data.start-e.data.start},margin:{item:10}},this.ordered=[]}function h(t){this.id=C.randomUUID(),this.start=0,this.end=0,this.options={min:null,max:null,zoomMin:null,zoomMax:null},this.listeners=[],this.setOptions(t)}function d(){this.id=C.randomUUID(),this.components={},this.repaintTimer=void 0,this.reflowTimer=void 0}function l(){this.id=null,this.parent=null,this.depends=null,this.controller=null,this.options=null,this.frame=null,this.top=0,this.left=0,this.width=0,this.height=0}function p(t,e,i){this.id=C.randomUUID(),this.parent=t,this.depends=e,this.options=i||{}}function u(t,e){this.id=C.randomUUID(),this.container=t,this.options=e||{},this.defaultOptions={autoResize:!0},this.listeners={}}function c(t,e,i){this.id=C.randomUUID(),this.parent=t,this.depends=e,this.dom={majorLines:[],majorTexts:[],minorLines:[],minorTexts:[],redundant:{majorLines:[],majorTexts:[],minorLines:[],minorTexts:[]}},this.props={range:{start:0,end:0,minimumStep:0},lineTop:0},this.options=i||{},this.defaultOptions={orientation:"bottom",showMinorLabels:!0,showMajorLabels:!0},this.conversion=null,this.range=null}function f(t,e,i){this.id=C.randomUUID(),this.parent=t,this.depends=e,this.options=i||{},this.defaultOptions={type:"box",align:"center",orientation:"bottom",margin:{axis:20,item:10},padding:5},this.dom={};var s=this;this.itemsData=null,this.range=null,this.listeners={add:function(t,e,i){i!=s.id&&s._onAdd(e.items)},update:function(t,e,i){i!=s.id&&s._onUpdate(e.items)},remove:function(t,e,i){i!=s.id&&s._onRemove(e.items)}},this.items={},this.queue={},this.stack=new a(this,Object.create(this.options)),this.conversion=null}function m(t,e,i,s){this.parent=t,this.data=e,this.dom=null,this.options=i||{},this.defaultOptions=s||{},this.selected=!1,this.visible=!1,this.top=0,this.left=0,this.width=0,this.height=0}function g(t,e,i,s){this.props={dot:{left:0,top:0,width:0,height:0},line:{top:0,left:0,width:0,height:0}},m.call(this,t,e,i,s)}function v(t,e,i,s){this.props={dot:{top:0,width:0,height:0},content:{height:0,marginLeft:0}},m.call(this,t,e,i,s)}function y(t,e,i,s){this.props={content:{left:0,width:0}},m.call(this,t,e,i,s)}function w(t,e,i){this.id=C.randomUUID(),this.parent=t,this.groupId=e,this.itemsData=null,this.itemset=null,this.options=i||{},this.options.top=0,this.top=0,this.left=0,this.width=0,this.height=0}function b(t,e,i){this.id=C.randomUUID(),this.parent=t,this.depends=e,this.options=i||{},this.range=null,this.itemsData=null,this.groupsData=null,this.groups={},this.queue={};var s=this;this.listeners={add:function(t,e){s._onAdd(e.items)},update:function(t,e){s._onUpdate(e.items)},remove:function(t,e){s._onRemove(e.items)}}}function _(t,e,i){var s=this;if(this.options=C.extend({orientation:"bottom",min:null,max:null,zoomMin:10,zoomMax:31536e10,showMinorLabels:!0,showMajorLabels:!0,autoResize:!1},i),this.controller=new d,!t)throw Error("No container element provided");var o=Object.create(this.options);o.height=function(){return s.options.height?s.options.height:s.timeaxis.height+s.content.height},this.root=new u(t,o),this.controller.add(this.root);var n=E().hours(0).minutes(0).seconds(0).milliseconds(0);this.range=new h({start:n.clone().add("days",-3).valueOf(),end:n.clone().add("days",4).valueOf()}),this.range.subscribe(this.root,"move","horizontal"),this.range.subscribe(this.root,"zoom","horizontal"),this.range.on("rangechange",function(){var t=!0;s.controller.requestReflow(t)}),this.range.on("rangechanged",function(){var t=!0;s.controller.requestReflow(t)});var r=Object.create(o);r.range=this.range,this.timeaxis=new c(this.root,[],r),this.timeaxis.setRange(this.range),this.controller.add(this.timeaxis),this.setGroups(null),this.itemsData=null,this.groupsData=null,e&&this.setItems(e)}function x(t,e,i,s){this.selected=!1,this.edges=[],this.group=s.nodes.group,this.fontSize=s.nodes.fontSize,this.fontFace=s.nodes.fontFace,this.fontColor=s.nodes.fontColor,this.color=s.nodes.color,this.id=void 0,this.shape=s.nodes.shape,this.image=s.nodes.image,this.x=0,this.y=0,this.xFixed=!1,this.yFixed=!1,this.radius=s.nodes.radius,this.radiusFixed=!1,this.radiusMin=s.nodes.radiusMin,this.radiusMax=s.nodes.radiusMax,this.imagelist=e,this.grouplist=i,this.setProperties(t,s),this.mass=50,this.fx=0,this.fy=0,this.vx=0,this.vy=0,this.minForce=s.minForce,this.damping=.9}function T(t,e,i){if(!e)throw"No graph provided";this.graph=e,this.widthMin=i.edges.widthMin,this.widthMax=i.edges.widthMax,this.id=void 0,this.style=i.edges.style,this.title=void 0,this.width=i.edges.width,this.value=void 0,this.length=i.edges.length,this.dash=C.extend({},i.edges.dash),this.stiffness=void 0,this.color=i.edges.color,this.widthFixed=!1,this.lengthFixed=!1,this.setProperties(t,i)}function M(t,e,i,s){this.container=t?t:document.body,this.x=0,this.y=0,this.padding=5,void 0!==e&&void 0!==i&&this.setPosition(e,i),void 0!==s&&this.setText(s),this.frame=document.createElement("div");var o=this.frame.style;o.position="absolute",o.visibility="hidden",o.border="1px solid #666",o.color="black",o.padding=this.padding+"px",o.backgroundColor="#FFFFC6",o.borderRadius="3px",o.MozBorderRadius="3px",o.WebkitBorderRadius="3px",o.boxShadow="3px 3px 10px rgba(128, 128, 128, 0.5)",o.whiteSpace="nowrap",this.container.appendChild(this.frame)}function S(t,e,i){this.containerElement=t,this.width="100%",this.height="100%",this.refreshRate=50,this.stabilize=!0,this.selectable=!0,this.constants={nodes:{radiusMin:5,radiusMax:20,radius:5,distance:100,shape:"ellipse",image:void 0,widthMin:16,widthMax:64,fontColor:"black",fontSize:14,fontFace:"arial",color:{border:"#2B7CE9",background:"#97C2FC",highlight:{border:"#2B7CE9",background:"#D2E5FF"}},borderColor:"#2B7CE9",backgroundColor:"#97C2FC",highlightColor:"#D2E5FF",group:void 0},edges:{widthMin:1,widthMax:15,width:1,style:"line",color:"#343434",fontColor:"#343434",fontSize:14,fontFace:"arial",length:100,dash:{length:10,gap:5,altLength:void 0}},minForce:.05,minVelocity:.02,maxIterations:1e3};var s=this;this.nodes=[],this.edges=[],this.groups=new Groups,this.images=new Images,this.images.setOnloadCallback(function(){s._redraw()}),this.moving=!1,this.selection=[],this.timer=void 0,this._create(),this.setOptions(i),this.setData(e)}var E=e("moment"),C={};C.isNumber=function(t){return t instanceof Number||"number"==typeof t},C.isString=function(t){return t instanceof String||"string"==typeof t},C.isDate=function(t){if(t instanceof Date)return!0;if(C.isString(t)){var e=D.exec(t);if(e)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},C.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},C.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},C.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var s=arguments[e];for(var o in s)s.hasOwnProperty(o)&&void 0!==s[o]&&(t[o]=s[o])}return t},C.cast=function(t,e){var i;if(void 0===t)return void 0;if(null===t)return null;if(!e)return t;if("string"!=typeof e&&!(e instanceof String))throw Error("Type must be a string");switch(e){case"boolean":case"Boolean":return Boolean(t);case"number":case"Number":return Number(t);case"string":case"String":return t+"";case"Date":if(C.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(E.isMoment(t))return new Date(t.valueOf());if(C.isString(t))return i=D.exec(t),i?new Date(Number(i[1])):E(t).toDate();throw Error("Cannot cast object of type "+C.getType(t)+" to type Date");case"Moment":if(C.isNumber(t))return E(t);if(t instanceof Date)return E(t.valueOf());if(E.isMoment(t))return E.clone();if(C.isString(t))return i=D.exec(t),i?E(Number(i[1])):E(t);throw Error("Cannot cast object of type "+C.getType(t)+" to type Date");case"ISODate":if(t instanceof Date)return t.toISOString();if(E.isMoment(t))return t.toDate().toISOString();if(C.isNumber(t)||C.isString(t))return E(t).toDate().toISOString();throw Error("Cannot cast object of type "+C.getType(t)+" to type ISODate");case"ASPDate":if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(C.isNumber(t)||C.isString(t))return"/Date("+E(t).valueOf()+")/";throw Error("Cannot cast object of type "+C.getType(t)+" to type ASPDate");default:throw Error("Cannot cast object of type "+C.getType(t)+' to type "'+e+'"')}};var D=/^\/?Date\((\-?\d+)/i;if(C.getType=function(t){var e=typeof t;return"object"==e?null==t?"null":t instanceof Boolean?"Boolean":t instanceof Number?"Number":t instanceof String?"String":t instanceof Array?"Array":t instanceof Date?"Date":"Object":"number"==e?"Number":"boolean"==e?"Boolean":"string"==e?"String":e},C.getAbsoluteLeft=function(t){for(var e=document.documentElement,i=document.body,s=t.offsetLeft,o=t.offsetParent;null!=o&&o!=i&&o!=e;)s+=o.offsetLeft,s-=o.scrollLeft,o=o.offsetParent;return s},C.getAbsoluteTop=function(t){for(var e=document.documentElement,i=document.body,s=t.offsetTop,o=t.offsetParent;null!=o&&o!=i&&o!=e;)s+=o.offsetTop,s-=o.scrollTop,o=o.offsetParent;return s},C.getPageY=function(t){if("pageY"in t)return t.pageY;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientY:t.clientY;var i=document.documentElement,s=document.body;return e+(i&&i.scrollTop||s&&s.scrollTop||0)-(i&&i.clientTop||s&&s.clientTop||0)},C.getPageX=function(t){if("pageY"in t)return t.pageX;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientX:t.clientX;var i=document.documentElement,s=document.body;return e+(i&&i.scrollLeft||s&&s.scrollLeft||0)-(i&&i.clientLeft||s&&s.clientLeft||0)},C.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},C.removeClassName=function(t,e){var i=t.className.split(" "),s=i.indexOf(e);-1!=s&&(i.splice(s,1),t.className=i.join(" "))},C.forEach=function(t,e){var i,s;if(t instanceof Array)for(i=0,s=t.length;s>i;i++)e(t[i],i,t);else for(i in t)t.hasOwnProperty(i)&&e(t[i],i,t)},C.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},C.addEventListener=function(t,e,i,s){t.addEventListener?(void 0===s&&(s=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.addEventListener(e,i,s)):t.attachEvent("on"+e,i)},C.removeEventListener=function(t,e,i,s){t.removeEventListener?(void 0===s&&(s=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.removeEventListener(e,i,s)):t.detachEvent("on"+e,i)},C.getTarget=function(t){t||(t=window.event);var e;return t.target?e=t.target:t.srcElement&&(e=t.srcElement),void 0!=e.nodeType&&3==e.nodeType&&(e=e.parentNode),e},C.stopPropagation=function(t){t||(t=window.event),t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},C.preventDefault=function(t){t||(t=window.event),t.preventDefault?t.preventDefault():t.returnValue=!1},C.option={},C.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},C.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},C.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?t+"":e||null},C.option.asSize=function(t,e){return"function"==typeof t&&(t=t()),C.isString(t)?t:C.isNumber(t)?t+"px":e||null},C.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null},C.loadCss=function(t){if("undefined"!=typeof document){var e=document.createElement("style");e.type="text/css",e.styleSheet?e.styleSheet.cssText=t:e.appendChild(document.createTextNode(t)),document.getElementsByTagName("head")[0].appendChild(e)}},!Array.prototype.indexOf){Array.prototype.indexOf=function(t){for(var e=0;this.length>e;e++)if(this[e]==t)return e;return-1};try{console.log("Warning: Ancient browser detected. Please update your browser")}catch(L){}}Array.prototype.forEach||(Array.prototype.forEach=function(t,e){for(var i=0,s=this.length;s>i;++i)t.call(e||this,this[i],i,this)}),Array.prototype.map||(Array.prototype.map=function(t,e){var i,s,o;if(null==this)throw new TypeError(" this is null or not defined");var n=Object(this),r=n.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(e&&(i=e),s=Array(r),o=0;r>o;){var a,h;o in n&&(a=n[o],h=t.call(i,a,o,n),s[o]=h),o++}return s}),Array.prototype.filter||(Array.prototype.filter=function(t){"use strict";if(null==this)throw new TypeError;var e=Object(this),i=e.length>>>0;if("function"!=typeof t)throw new TypeError;for(var s=[],o=arguments[1],n=0;i>n;n++)if(n in e){var r=e[n];t.call(o,r,n,e)&&s.push(r)}return s}),Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,e=!{toString:null}.propertyIsEnumerable("toString"),i=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],s=i.length;return function(o){if("object"!=typeof o&&"function"!=typeof o||null===o)throw new TypeError("Object.keys called on non-object");var n=[];for(var r in o)t.call(o,r)&&n.push(r);if(e)for(var a=0;s>a;a++)t.call(o,i[a])&&n.push(i[a]);return n}}()),Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,s=function(){},o=function(){return i.apply(this instanceof s&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return s.prototype=this.prototype,o.prototype=new s,o}),Object.create||(Object.create=function(t){function e(){}if(arguments.length>1)throw Error("Object.create implementation only accepts the first parameter.");return e.prototype=t,new e});var O={listeners:[],indexOf:function(t){for(var e=this.listeners,i=0,s=this.listeners.length;s>i;i++){var o=e[i];if(o&&o.object==t)return i}return-1},addListener:function(t,e,i){var s=this.indexOf(t),o=this.listeners[s];o||(o={object:t,events:{}},this.listeners.push(o));var n=o.events[e];n||(n=[],o.events[e]=n),-1==n.indexOf(i)&&n.push(i)},removeListener:function(t,e,i){var s=this.indexOf(t),o=this.listeners[s];if(o){var n=o.events[e];n&&(s=n.indexOf(i),-1!=s&&n.splice(s,1),0==n.length&&delete o.events[e]);var r=0,a=o.events;for(var h in a)a.hasOwnProperty(h)&&r++;0==r&&delete this.listeners[s]}},removeAllListeners:function(){this.listeners=[]},trigger:function(t,e,i){var s=this.indexOf(t),o=this.listeners[s];if(o){var n=o.events[e];if(n)for(var r=0,a=n.length;a>r;r++)n[r](i)}}};o.prototype.on=function(t,e,i){var s=t instanceof RegExp?t:RegExp(t.replace("*","\\w+")),o={id:C.randomUUID(),event:t,regexp:s,callback:"function"==typeof e?e:null,target:i};return this.subscriptions.push(o),o.id},o.prototype.off=function(t){for(var e=0;this.subscriptions.length>e;){var i=this.subscriptions[e],s=!0;if(t instanceof Object)for(var o in t)t.hasOwnProperty(o)&&t[o]!==i[o]&&(s=!1);else s=i.id==t;s?this.subscriptions.splice(e,1):e++}},o.prototype.emit=function(t,e,i){for(var s=0;this.subscriptions.length>s;s++){var o=this.subscriptions[s];o.regexp.test(t)&&o.callback&&o.callback(t,e,i)}},n.prototype.subscribe=function(t,e,i){var s=this.subscribers[t];s||(s=[],this.subscribers[t]=s),s.push({id:i?i+"":null,callback:e})},n.prototype.unsubscribe=function(t,e){var i=this.subscribers[t];i&&(this.subscribers[t]=i.filter(function(t){return t.callback!=e}))},n.prototype._trigger=function(t,e,i){if("*"==t)throw Error("Cannot trigger event *");var s=[];t in this.subscribers&&(s=s.concat(this.subscribers[t])),"*"in this.subscribers&&(s=s.concat(this.subscribers["*"]));for(var o=0;s.length>o;o++){var n=s[o];n.callback&&n.callback(t,e,i||null)}},n.prototype.add=function(t,e){var i,s=[],o=this;if(t instanceof Array)for(var n=0,r=t.length;r>n;n++)i=o._addItem(t[n]),s.push(i);else if(C.isDataTable(t))for(var a=this._getColumnNames(t),h=0,d=t.getNumberOfRows();d>h;h++){for(var l={},p=0,u=a.length;u>p;p++){var c=a[p];l[c]=t.getValue(h,p)}i=o._addItem(l),s.push(i)}else{if(!(t instanceof Object))throw Error("Unknown dataType");i=o._addItem(t),s.push(i)}s.length&&this._trigger("add",{items:s},e)},n.prototype.update=function(t,e){var i=[],s=[],o=this,n=o.fieldId,r=function(t){var e=t[n];o.data[e]?(e=o._updateItem(t),s.push(e)):(e=o._addItem(t),i.push(e))};if(t instanceof Array)for(var a=0,h=t.length;h>a;a++)r(t[a]);else if(C.isDataTable(t))for(var d=this._getColumnNames(t),l=0,p=t.getNumberOfRows();p>l;l++){for(var u={},c=0,f=d.length;f>c;c++){var m=d[c];u[m]=t.getValue(l,c)}r(u)}else{if(!(t instanceof Object))throw Error("Unknown dataType");r(t)}i.length&&this._trigger("add",{items:i},e),s.length&&this._trigger("update",{items:s},e)},n.prototype.get=function(){var t,e,i,s,o=this,n=C.getType(arguments[0]);"String"==n||"Number"==n?(t=arguments[0],i=arguments[1],s=arguments[2]):"Array"==n?(e=arguments[0],i=arguments[1],s=arguments[2]):(i=arguments[0],s=arguments[1]);var r;if(i&&i.type){if(r="DataTable"==i.type?"DataTable":"Array",s&&r!=C.getType(s))throw Error('Type of parameter "data" ('+C.getType(s)+") "+"does not correspond with specified options.type ("+i.type+")");if("DataTable"==r&&!C.isDataTable(s))throw Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else r=s?"DataTable"==C.getType(s)?"DataTable":"Array":"Array";var a,h,d,l,p=i&&i.fieldTypes||this.options.fieldTypes,u=i&&i.filter,c=[];if(void 0!=t)a=o._getItem(t,p),u&&!u(a)&&(a=null);else if(void 0!=e)for(d=0,l=e.length;l>d;d++)a=o._getItem(e[d],p),(!u||u(a))&&c.push(a);else for(h in this.data)this.data.hasOwnProperty(h)&&(a=o._getItem(h,p),(!u||u(a))&&c.push(a));if(i&&i.order&&void 0==t&&this._sort(c,i.order),i&&i.fields){var f=i.fields;if(void 0!=t)a=this._filterFields(a,f);else for(d=0,l=c.length;l>d;d++)c[d]=this._filterFields(c[d],f)}if("DataTable"==r){var m=this._getColumnNames(s);if(void 0!=t)o._appendRow(s,m,a);else for(d=0,l=c.length;l>d;d++)o._appendRow(s,m,c[d]);return s}if(void 0!=t)return a;if(s){for(d=0,l=c.length;l>d;d++)s.push(c[d]);return s}return c},n.prototype.getIds=function(t){var e,i,s,o,n,r=this.data,a=t&&t.filter,h=t&&t.order,d=t&&t.fieldTypes||this.options.fieldTypes,l=[];if(a)if(h){n=[];for(s in r)r.hasOwnProperty(s)&&(o=this._getItem(s,d),a(o)&&n.push(o));for(this._sort(n,h),e=0,i=n.length;i>e;e++)l[e]=n[e][this.fieldId]}else for(s in r)r.hasOwnProperty(s)&&(o=this._getItem(s,d),a(o)&&l.push(o[this.fieldId]));else if(h){n=[];for(s in r)r.hasOwnProperty(s)&&n.push(r[s]);for(this._sort(n,h),e=0,i=n.length;i>e;e++)l[e]=n[e][this.fieldId]}else for(s in r)r.hasOwnProperty(s)&&(o=r[s],l.push(o[this.fieldId]));return l},n.prototype.forEach=function(t,e){var i,s,o=e&&e.filter,n=e&&e.fieldTypes||this.options.fieldTypes,r=this.data;if(e&&e.order)for(var a=this.get(e),h=0,d=a.length;d>h;h++)i=a[h],s=i[this.fieldId],t(i,s);else for(s in r)r.hasOwnProperty(s)&&(i=this._getItem(s,n),(!o||o(i))&&t(i,s))},n.prototype.map=function(t,e){var i,s=e&&e.filter,o=e&&e.fieldTypes||this.options.fieldTypes,n=[],r=this.data;for(var a in r)r.hasOwnProperty(a)&&(i=this._getItem(a,o),(!s||s(i))&&n.push(t(i,a)));return e&&e.order&&this._sort(n,e.order),n},n.prototype._filterFields=function(t,e){var i={};for(var s in t)t.hasOwnProperty(s)&&-1!=e.indexOf(s)&&(i[s]=t[s]);return i},n.prototype._sort=function(t,e){if(C.isString(e)){var i=e;t.sort(function(t,e){var s=t[i],o=e[i];return s>o?1:o>s?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},n.prototype.remove=function(t,e){var i,s,o=[];if(C.isNumber(t)||C.isString(t))delete this.data[t],delete this.internalIds[t],o.push(t);else if(t instanceof Array){for(i=0,s=t.length;s>i;i++)this.remove(t[i]);o=items.concat(t)}else if(t instanceof Object)for(i in this.data)this.data.hasOwnProperty(i)&&this.data[i]==t&&(delete this.data[i],delete this.internalIds[i],o.push(i));o.length&&this._trigger("remove",{items:o},e)},n.prototype.clear=function(t){var e=Object.keys(this.data);this.data={},this.internalIds={},this._trigger("remove",{items:e},t)},n.prototype.max=function(t){var e=this.data,i=null,s=null;for(var o in e)if(e.hasOwnProperty(o)){var n=e[o],r=n[t];null!=r&&(!i||r>s)&&(i=n,s=r)}return i},n.prototype.min=function(t){var e=this.data,i=null,s=null;for(var o in e)if(e.hasOwnProperty(o)){var n=e[o],r=n[t];null!=r&&(!i||s>r)&&(i=n,s=r)}return i},n.prototype.distinct=function(t){var e=this.data,i=[],s=this.options.fieldTypes[t],o=0;for(var n in e)if(e.hasOwnProperty(n)){for(var r=e[n],a=C.cast(r[t],s),h=!1,d=0;o>d;d++)if(i[d]==a){h=!0;break}h||(i[o]=a,o++)}return i},n.prototype._addItem=function(t){var e=t[this.fieldId];if(void 0!=e){if(this.data[e])throw Error("Cannot add item: item with id "+e+" already exists")}else e=C.randomUUID(),t[this.fieldId]=e,this.internalIds[e]=t;var i={};for(var s in t)if(t.hasOwnProperty(s)){var o=this.fieldTypes[s];i[s]=C.cast(t[s],o)}return this.data[e]=i,e},n.prototype._getItem=function(t,e){var i,s,o=this.data[t];if(!o)return null;var n={},r=this.fieldId,a=this.internalIds;if(e)for(i in o)o.hasOwnProperty(i)&&(s=o[i],i==r&&s in a||(n[i]=C.cast(s,e[i])));else for(i in o)o.hasOwnProperty(i)&&(s=o[i],i==r&&s in a||(n[i]=s));return n},n.prototype._updateItem=function(t){var e=t[this.fieldId];if(void 0==e)throw Error("Cannot update item: item has no id (item: "+JSON.stringify(t)+")");var i=this.data[e];if(!i)throw Error("Cannot update item: no item with id "+e+" found");for(var s in t)if(t.hasOwnProperty(s)){var o=this.fieldTypes[s];i[s]=C.cast(t[s],o)}return e},n.prototype._getColumnNames=function(t){for(var e=[],i=0,s=t.getNumberOfColumns();s>i;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},n.prototype._appendRow=function(t,e,i){for(var s=t.addRow(),o=0,n=e.length;n>o;o++){var r=e[o];t.setValue(s,o,i[r])}},r.prototype.setData=function(t){var e,i,s;if(this.data){this.data.unsubscribe&&this.data.unsubscribe("*",this.listener),e=[];for(var o in this.ids)this.ids.hasOwnProperty(o)&&e.push(o);this.ids={},this._trigger("remove",{items:e})}if(this.data=t,this.data){for(this.fieldId=this.options.fieldId||this.data&&this.data.options&&this.data.options.fieldId||"id",e=this.data.getIds({filter:this.options&&this.options.filter}),i=0,s=e.length;s>i;i++)o=e[i],this.ids[o]=!0;this._trigger("add",{items:e}),this.data.subscribe&&this.data.subscribe("*",this.listener)}},r.prototype.get=function(){var t,e,i,s=this,o=C.getType(arguments[0]);"String"==o||"Number"==o||"Array"==o?(t=arguments[0],e=arguments[1],i=arguments[2]):(e=arguments[0],i=arguments[1]);var n=C.extend({},this.options,e);this.options.filter&&e&&e.filter&&(n.filter=function(t){return s.options.filter(t)&&e.filter(t)});var r=[];return void 0!=t&&r.push(t),r.push(n),r.push(i),this.data&&this.data.get.apply(this.data,r)},r.prototype.getIds=function(t){var e;if(this.data){var i,s=this.options.filter;i=t&&t.filter?s?function(e){return s(e)&&t.filter(e)}:t.filter:s,e=this.data.getIds({filter:i,order:t&&t.order})}else e=[];return e},r.prototype._onEvent=function(t,e,i){var s,o,n,r,a=e&&e.items,h=this.data,d=[],l=[],p=[];if(a&&h){switch(t){case"add":for(s=0,o=a.length;o>s;s++)n=a[s],r=this.get(n),r&&(this.ids[n]=!0,d.push(n));break;case"update":for(s=0,o=a.length;o>s;s++)n=a[s],r=this.get(n),r?this.ids[n]?l.push(n):(this.ids[n]=!0,d.push(n)):this.ids[n]&&(delete this.ids[n],p.push(n));break;case"remove":for(s=0,o=a.length;o>s;s++)n=a[s],this.ids[n]&&(delete this.ids[n],p.push(n))}d.length&&this._trigger("add",{items:d},i),l.length&&this._trigger("update",{items:l},i),p.length&&this._trigger("remove",{items:p},i)}},r.prototype.subscribe=n.prototype.subscribe,r.prototype.unsubscribe=n.prototype.unsubscribe,r.prototype._trigger=n.prototype._trigger,TimeStep=function(t,e,i){this.current=new Date,this._start=new Date,this._end=new Date,this.autoScale=!0,this.scale=TimeStep.SCALE.DAY,this.step=1,this.setRange(t,e,i)},TimeStep.SCALE={MILLISECOND:1,SECOND:2,MINUTE:3,HOUR:4,DAY:5,WEEKDAY:6,MONTH:7,YEAR:8},TimeStep.prototype.setRange=function(t,e,i){t instanceof Date&&e instanceof Date&&(this._start=void 0!=t?new Date(t.valueOf()):new Date,this._end=void 0!=e?new Date(e.valueOf()):new Date,this.autoScale&&this.setMinimumStep(i))},TimeStep.prototype.first=function(){this.current=new Date(this._start.valueOf()),this.roundToMinor()},TimeStep.prototype.roundToMinor=function(){switch(this.scale){case TimeStep.SCALE.YEAR:this.current.setFullYear(this.step*Math.floor(this.current.getFullYear()/this.step)),this.current.setMonth(0);case TimeStep.SCALE.MONTH:this.current.setDate(1);case TimeStep.SCALE.DAY:case TimeStep.SCALE.WEEKDAY:this.current.setHours(0);case TimeStep.SCALE.HOUR:this.current.setMinutes(0);case TimeStep.SCALE.MINUTE:this.current.setSeconds(0);case TimeStep.SCALE.SECOND:this.current.setMilliseconds(0)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.setMilliseconds(this.current.getMilliseconds()-this.current.getMilliseconds()%this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()-this.current.getSeconds()%this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()-this.current.getMinutes()%this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()-this.current.getHours()%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()-1-(this.current.getDate()-1)%this.step+1);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()-this.current.getMonth()%this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()-this.current.getFullYear()%this.step);break;default:}},TimeStep.prototype.hasNext=function(){return this.current.valueOf()<=this._end.valueOf()},TimeStep.prototype.next=function(){var t=this.current.valueOf();if(6>this.current.getMonth())switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current=new Date(this.current.valueOf()+1e3*this.step);break;case TimeStep.SCALE.MINUTE:this.current=new Date(this.current.valueOf()+60*1e3*this.step);break;case TimeStep.SCALE.HOUR:this.current=new Date(this.current.valueOf()+60*60*1e3*this.step);var e=this.current.getHours();this.current.setHours(e-e%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step);break;default:}else switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()+this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()+this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()+this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step);break;default:}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.getMilliseconds()0&&(this.step=e),this.autoScale=!1},TimeStep.prototype.setAutoScale=function(t){this.autoScale=t},TimeStep.prototype.setMinimumStep=function(t){if(void 0!=t){var e=31104e6,i=2592e6,s=864e5,o=36e5,n=6e4,r=1e3,a=1;1e3*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1e3),500*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=500),100*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=100),50*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=50),10*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=10),5*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=5),e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1),3*i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=3),i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=1),5*s>t&&(this.scale=TimeStep.SCALE.DAY,this.step=5),2*s>t&&(this.scale=TimeStep.SCALE.DAY,this.step=2),s>t&&(this.scale=TimeStep.SCALE.DAY,this.step=1),s/2>t&&(this.scale=TimeStep.SCALE.WEEKDAY,this.step=1),4*o>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=4),o>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=1),15*n>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=15),10*n>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=10),5*n>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=5),n>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=1),15*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=15),10*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=10),5*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=5),r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=1),200*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=200),100*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=100),50*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=50),10*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=10),5*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=5),a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=1)}},TimeStep.prototype.snap=function(t){if(this.scale==TimeStep.SCALE.YEAR){var e=t.getFullYear()+Math.round(t.getMonth()/12);t.setFullYear(Math.round(e/this.step)*this.step),t.setMonth(0),t.setDate(0),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MONTH)t.getDate()>15?(t.setDate(1),t.setMonth(t.getMonth()+1)):t.setDate(1),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0); -else if(this.scale==TimeStep.SCALE.DAY||this.scale==TimeStep.SCALE.WEEKDAY){switch(this.step){case 5:case 2:t.setHours(24*Math.round(t.getHours()/24));break;default:t.setHours(12*Math.round(t.getHours()/12))}t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.HOUR){switch(this.step){case 4:t.setMinutes(60*Math.round(t.getMinutes()/60));break;default:t.setMinutes(30*Math.round(t.getMinutes()/30))}t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MINUTE){switch(this.step){case 15:case 10:t.setMinutes(5*Math.round(t.getMinutes()/5)),t.setSeconds(0);break;case 5:t.setSeconds(60*Math.round(t.getSeconds()/60));break;default:t.setSeconds(30*Math.round(t.getSeconds()/30))}t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.SECOND)switch(this.step){case 15:case 10:t.setSeconds(5*Math.round(t.getSeconds()/5)),t.setMilliseconds(0);break;case 5:t.setMilliseconds(1e3*Math.round(t.getMilliseconds()/1e3));break;default:t.setMilliseconds(500*Math.round(t.getMilliseconds()/500))}else if(this.scale==TimeStep.SCALE.MILLISECOND){var i=this.step>5?this.step/2:1;t.setMilliseconds(Math.round(t.getMilliseconds()/i)*i)}},TimeStep.prototype.isMajor=function(){switch(this.scale){case TimeStep.SCALE.MILLISECOND:return 0==this.current.getMilliseconds();case TimeStep.SCALE.SECOND:return 0==this.current.getSeconds();case TimeStep.SCALE.MINUTE:return 0==this.current.getHours()&&0==this.current.getMinutes();case TimeStep.SCALE.HOUR:return 0==this.current.getHours();case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return 1==this.current.getDate();case TimeStep.SCALE.MONTH:return 0==this.current.getMonth();case TimeStep.SCALE.YEAR:return!1;default:return!1}},TimeStep.prototype.getLabelMinor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return E(t).format("SSS");case TimeStep.SCALE.SECOND:return E(t).format("s");case TimeStep.SCALE.MINUTE:return E(t).format("HH:mm");case TimeStep.SCALE.HOUR:return E(t).format("HH:mm");case TimeStep.SCALE.WEEKDAY:return E(t).format("ddd D");case TimeStep.SCALE.DAY:return E(t).format("D");case TimeStep.SCALE.MONTH:return E(t).format("MMM");case TimeStep.SCALE.YEAR:return E(t).format("YYYY");default:return""}},TimeStep.prototype.getLabelMajor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return E(t).format("HH:mm:ss");case TimeStep.SCALE.SECOND:return E(t).format("D MMMM HH:mm");case TimeStep.SCALE.MINUTE:case TimeStep.SCALE.HOUR:return E(t).format("ddd D MMMM");case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return E(t).format("MMMM YYYY");case TimeStep.SCALE.MONTH:return E(t).format("YYYY");case TimeStep.SCALE.YEAR:return"";default:return""}},a.prototype.setOptions=function(t){C.extend(this.options,t)},a.prototype.update=function(){this._order(),this._stack()},a.prototype._order=function(){var t=this.parent.items;if(!t)throw Error("Cannot stack items: parent does not contain items");var e=[],i=0;C.forEach(t,function(t){t.visible&&(e[i]=t,i++)});var s=this.options.order||this.defaultOptions.order;if("function"!=typeof s)throw Error("Option order must be a function");e.sort(s),this.ordered=e},a.prototype._stack=function(){var t,e,i,s=this.ordered,o=this.options,n=o.orientation||this.defaultOptions.orientation,r="top"==n;for(i=o.margin&&void 0!==o.margin.item?o.margin.item:this.defaultOptions.margin.item,t=0,e=s.length;e>t;t++){var a=s[t],h=null;do h=this.checkOverlap(s,t,0,t-1,i),null!=h&&(a.top=r?h.top+h.height+i:h.top-a.height-i);while(h)}},a.prototype.checkOverlap=function(t,e,i,s,o){for(var n=this.collision,r=t[e],a=s;a>=i;a--){var h=t[a];if(n(r,h,o)&&a!=e)return h}return null},a.prototype.collision=function(t,e,i){return t.left-ie.left&&t.top-ie.top},h.prototype.setOptions=function(t){C.extend(this.options,t),(null!=t.start||null!=t.end)&&this.setRange(t.start,t.end)},h.prototype.subscribe=function(t,e,i){var s,o=this;if("horizontal"!=i&&"vertical"!=i)throw new TypeError('Unknown direction "'+i+'". '+'Choose "horizontal" or "vertical".');if("move"==e)s={component:t,event:e,direction:i,callback:function(t){o._onMouseDown(t,s)},params:{}},t.on("mousedown",s.callback),o.listeners.push(s);else{if("zoom"!=e)throw new TypeError('Unknown event "'+e+'". '+'Choose "move" or "zoom".');s={component:t,event:e,direction:i,callback:function(t){o._onMouseWheel(t,s)},params:{}},t.on("mousewheel",s.callback),o.listeners.push(s)}},h.prototype.on=function(t,e){O.addListener(this,t,e)},h.prototype._trigger=function(t){O.trigger(this,t,{start:this.start,end:this.end})},h.prototype.setRange=function(t,e){var i=this._applyRange(t,e);i&&(this._trigger("rangechange"),this._trigger("rangechanged"))},h.prototype._applyRange=function(t,e){var i,s=null!=t?C.cast(t,"Number"):this.start,o=null!=e?C.cast(e,"Number"):this.end;if(isNaN(s))throw Error('Invalid start "'+t+'"');if(isNaN(o))throw Error('Invalid end "'+e+'"');if(s>o&&(o=s),null!=this.options.min){var n=this.options.min.valueOf();n>s&&(i=n-s,s+=i,o+=i)}if(null!=this.options.max){var r=this.options.max.valueOf();o>r&&(i=o-r,s-=i,o-=i)}if(null!=this.options.zoomMin){var a=this.options.zoomMin.valueOf();0>a&&(a=0),a>o-s&&(this.end-this.start>a?(i=a-(o-s),s-=i/2,o+=i/2):(s=this.start,o=this.end))}if(null!=this.options.zoomMax){var h=this.options.zoomMax.valueOf();0>h&&(h=0),o-s>h&&(h>this.end-this.start?(i=o-s-h,s+=i/2,o-=i/2):(s=this.start,o=this.end))}var d=this.start!=s||this.end!=o;return this.start=s,this.end=o,d},h.prototype.getRange=function(){return{start:this.start,end:this.end}},h.prototype.conversion=function(t){return this.start,this.end,h.conversion(this.start,this.end,t)},h.conversion=function(t,e,i){return 0!=i&&0!=e-t?{offset:t,factor:i/(e-t)}:{offset:0,factor:1}},h.prototype._onMouseDown=function(t,e){t=t||window.event;var i=e.params,s=t.which?1==t.which:1==t.button;if(s){i.mouseX=C.getPageX(t),i.mouseY=C.getPageY(t),i.previousLeft=0,i.previousOffset=0,i.moved=!1,i.start=this.start,i.end=this.end;var o=e.component.frame;o&&(o.style.cursor="move");var n=this;i.onMouseMove||(i.onMouseMove=function(t){n._onMouseMove(t,e)},C.addEventListener(document,"mousemove",i.onMouseMove)),i.onMouseUp||(i.onMouseUp=function(t){n._onMouseUp(t,e)},C.addEventListener(document,"mouseup",i.onMouseUp)),C.preventDefault(t)}},h.prototype._onMouseMove=function(t,e){t=t||window.event;var i=e.params,s=C.getPageX(t),o=C.getPageY(t);void 0==i.mouseX&&(i.mouseX=s),void 0==i.mouseY&&(i.mouseY=o);var n=s-i.mouseX,r=o-i.mouseY,a="horizontal"==e.direction?n:r;Math.abs(a)>=1&&(i.moved=!0);var h=i.end-i.start,d="horizontal"==e.direction?e.component.width:e.component.height,l=-a/d*h;this._applyRange(i.start+l,i.end+l),this._trigger("rangechange"),C.preventDefault(t)},h.prototype._onMouseUp=function(t,e){t=t||window.event;var i=e.params;e.component.frame&&(e.component.frame.style.cursor="auto"),i.onMouseMove&&(C.removeEventListener(document,"mousemove",i.onMouseMove),i.onMouseMove=null),i.onMouseUp&&(C.removeEventListener(document,"mouseup",i.onMouseUp),i.onMouseUp=null),i.moved&&this._trigger("rangechanged")},h.prototype._onMouseWheel=function(t,e){t=t||window.event;var i=0;if(t.wheelDelta?i=t.wheelDelta/120:t.detail&&(i=-t.detail/3),i){var s=this,o=function(){var o=i/5,n=null,r=e.component.frame;if(r){var a,h;if("horizontal"==e.direction){a=e.component.width,h=s.conversion(a);var d=C.getAbsoluteLeft(r),l=C.getPageX(t);n=(l-d)/h.factor+h.offset}else{a=e.component.height,h=s.conversion(a);var p=C.getAbsoluteTop(r),u=C.getPageY(t);n=(p+a-u-p)/h.factor+h.offset}}s.zoom(o,n)};o()}C.preventDefault(t)},h.prototype.zoom=function(t,e){null==e&&(e=(this.start+this.end)/2),t>=1&&(t=.9),-1>=t&&(t=-.9),0>t&&(t/=1+t);var i=this.start-e,s=this.end-e,o=this.start-i*t,n=this.end-s*t;this.setRange(o,n)},h.prototype.move=function(t){var e=this.end-this.start,i=this.start+e*t,s=this.end+e*t;this.start=i,this.end=s},d.prototype.add=function(t){if(void 0==t.id)throw Error("Component has no field id");if(!(t instanceof l||t instanceof d))throw new TypeError("Component must be an instance of prototype Component or Controller");t.controller=this,this.components[t.id]=t},d.prototype.remove=function(t){var e;for(e in this.components)if(this.components.hasOwnProperty(e)&&(e==t||this.components[e]==t))break;e&&delete this.components[e]},d.prototype.requestReflow=function(t){if(t)this.reflow();else if(!this.reflowTimer){var e=this;this.reflowTimer=setTimeout(function(){e.reflowTimer=void 0,e.reflow()},0)}},d.prototype.requestRepaint=function(t){if(t)this.repaint();else if(!this.repaintTimer){var e=this;this.repaintTimer=setTimeout(function(){e.repaintTimer=void 0,e.repaint()},0)}},d.prototype.repaint=function(){function t(s,o){o in i||(s.depends&&s.depends.forEach(function(e){t(e,e.id)}),s.parent&&t(s.parent,s.parent.id),e=s.repaint()||e,i[o]=!0)}var e=!1;this.repaintTimer&&(clearTimeout(this.repaintTimer),this.repaintTimer=void 0);var i={};C.forEach(this.components,t),e&&this.reflow()},d.prototype.reflow=function(){function t(s,o){o in i||(s.depends&&s.depends.forEach(function(e){t(e,e.id)}),s.parent&&t(s.parent,s.parent.id),e=s.reflow()||e,i[o]=!0)}var e=!1;this.reflowTimer&&(clearTimeout(this.reflowTimer),this.reflowTimer=void 0);var i={};C.forEach(this.components,t),e&&this.repaint()},l.prototype.setOptions=function(t){t&&(C.extend(this.options,t),this.controller&&(this.requestRepaint(),this.requestReflow()))},l.prototype.getOption=function(t){var e;return this.options&&(e=this.options[t]),void 0===e&&this.defaultOptions&&(e=this.defaultOptions[t]),e},l.prototype.getContainer=function(){return null},l.prototype.getFrame=function(){return this.frame},l.prototype.repaint=function(){return!1},l.prototype.reflow=function(){return!1},l.prototype.hide=function(){return this.frame&&this.frame.parentNode?(this.frame.parentNode.removeChild(this.frame),!0):!1},l.prototype.show=function(){return this.frame&&this.frame.parentNode?!1:this.repaint()},l.prototype.requestRepaint=function(){if(!this.controller)throw Error("Cannot request a repaint: no controller configured");this.controller.requestRepaint()},l.prototype.requestReflow=function(){if(!this.controller)throw Error("Cannot request a reflow: no controller configured");this.controller.requestReflow()},p.prototype=new l,p.prototype.setOptions=l.prototype.setOptions,p.prototype.getContainer=function(){return this.frame},p.prototype.repaint=function(){var t=0,e=C.updateProperty,i=C.option.asSize,s=this.options,o=this.frame;if(!o){o=document.createElement("div"),o.className="panel";var n=s.className;n&&("function"==typeof n?C.addClassName(o,n()+""):C.addClassName(o,n+"")),this.frame=o,t+=1}if(!o.parentNode){if(!this.parent)throw Error("Cannot repaint panel: no parent attached");var r=this.parent.getContainer();if(!r)throw Error("Cannot repaint panel: parent has no container element");r.appendChild(o),t+=1}return t+=e(o.style,"top",i(s.top,"0px")),t+=e(o.style,"left",i(s.left,"0px")),t+=e(o.style,"width",i(s.width,"100%")),t+=e(o.style,"height",i(s.height,"100%")),t>0},p.prototype.reflow=function(){var t=0,e=C.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},u.prototype=new p,u.prototype.setOptions=l.prototype.setOptions,u.prototype.repaint=function(){var t=0,e=C.updateProperty,i=C.option.asSize,s=this.options,o=this.frame;if(!o){o=document.createElement("div"),o.className="graph panel";var n=s.className;n&&C.addClassName(o,C.option.asString(n)),this.frame=o,t+=1}if(!o.parentNode){if(!this.container)throw Error("Cannot repaint root panel: no container attached");this.container.appendChild(o),t+=1}return t+=e(o.style,"top",i(s.top,"0px")),t+=e(o.style,"left",i(s.left,"0px")),t+=e(o.style,"width",i(s.width,"100%")),t+=e(o.style,"height",i(s.height,"100%")),this._updateEventEmitters(),this._updateWatch(),t>0},u.prototype.reflow=function(){var t=0,e=C.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},u.prototype._updateWatch=function(){var t=this.getOption("autoResize");t?this._watch():this._unwatch()},u.prototype._watch=function(){var t=this;this._unwatch();var e=function(){var e=t.getOption("autoResize");return e?(t.frame&&(t.frame.clientWidth!=t.width||t.frame.clientHeight!=t.height)&&t.requestReflow(),void 0):(t._unwatch(),void 0)};C.addEventListener(window,"resize",e),this.watchTimer=setInterval(e,1e3)},u.prototype._unwatch=function(){this.watchTimer&&(clearInterval(this.watchTimer),this.watchTimer=void 0)},u.prototype.on=function(t,e){var i=this.listeners[t];i||(i=[],this.listeners[t]=i),i.push(e),this._updateEventEmitters()},u.prototype._updateEventEmitters=function(){if(this.listeners){var t=this;C.forEach(this.listeners,function(e,i){if(t.emitters||(t.emitters={}),!(i in t.emitters)){var s=t.frame;if(s){var o=function(t){e.forEach(function(e){e(t)})};t.emitters[i]=o,C.addEventListener(s,i,o)}}})}},c.prototype=new l,c.prototype.setOptions=l.prototype.setOptions,c.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},c.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.factor+e.offset)},c.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.factor},c.prototype.repaint=function(){var t=0,e=C.updateProperty,i=C.option.asSize,s=this.options,o=this.getOption("orientation"),n=this.props,r=this.step,a=this.frame;if(a||(a=document.createElement("div"),this.frame=a,t+=1),a.className="axis "+o,!a.parentNode){if(!this.parent)throw Error("Cannot repaint time axis: no parent attached");var h=this.parent.getContainer();if(!h)throw Error("Cannot repaint time axis: parent has no container element");h.appendChild(a),t+=1}var d=a.parentNode;if(d){var l=a.nextSibling;d.removeChild(a);var p="bottom"==o&&this.props.parentHeight&&this.height?this.props.parentHeight-this.height+"px":"0px";if(t+=e(a.style,"top",i(s.top,p)),t+=e(a.style,"left",i(s.left,"0px")),t+=e(a.style,"width",i(s.width,"100%")),t+=e(a.style,"height",i(s.height,this.height+"px")),this._repaintMeasureChars(),this.step){this._repaintStart(),r.first();for(var u=void 0,c=0;r.hasNext()&&1e3>c;){c++;var f=r.getCurrent(),m=this.toScreen(f),g=r.isMajor();this.getOption("showMinorLabels")&&this._repaintMinorText(m,r.getLabelMinor()),g&&this.getOption("showMajorLabels")?(m>0&&(void 0==u&&(u=m),this._repaintMajorText(m,r.getLabelMajor())),this._repaintMajorLine(m)):this._repaintMinorLine(m),r.next()}if(this.getOption("showMajorLabels")){var v=this.toTime(0),y=r.getLabelMajor(v),w=y.length*(n.majorCharWidth||10)+10;(void 0==u||u>w)&&this._repaintMajorText(0,y)}this._repaintEnd()}this._repaintLine(),l?d.insertBefore(a,l):d.appendChild(a)}return t>0},c.prototype._repaintStart=function(){var t=this.dom,e=t.redundant;e.majorLines=t.majorLines,e.majorTexts=t.majorTexts,e.minorLines=t.minorLines,e.minorTexts=t.minorTexts,t.majorLines=[],t.majorTexts=[],t.minorLines=[],t.minorTexts=[]},c.prototype._repaintEnd=function(){C.forEach(this.dom.redundant,function(t){for(;t.length;){var e=t.pop();e&&e.parentNode&&e.parentNode.removeChild(e)}})},c.prototype._repaintMinorText=function(t,e){var i=this.dom.redundant.minorTexts.shift();if(!i){var s=document.createTextNode("");i=document.createElement("div"),i.appendChild(s),i.className="text minor",this.frame.appendChild(i)}this.dom.minorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.left=t+"px",i.style.top=this.props.minorLabelTop+"px"},c.prototype._repaintMajorText=function(t,e){var i=this.dom.redundant.majorTexts.shift();if(!i){var s=document.createTextNode(e);i=document.createElement("div"),i.className="text major",i.appendChild(s),this.frame.appendChild(i)}this.dom.majorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.top=this.props.majorLabelTop+"px",i.style.left=t+"px"},c.prototype._repaintMinorLine=function(t){var e=this.dom.redundant.minorLines.shift();e||(e=document.createElement("div"),e.className="grid vertical minor",this.frame.appendChild(e)),this.dom.minorLines.push(e);var i=this.props;e.style.top=i.minorLineTop+"px",e.style.height=i.minorLineHeight+"px",e.style.left=t-i.minorLineWidth/2+"px"},c.prototype._repaintMajorLine=function(t){var e=this.dom.redundant.majorLines.shift();e||(e=document.createElement("DIV"),e.className="grid vertical major",this.frame.appendChild(e)),this.dom.majorLines.push(e);var i=this.props;e.style.top=i.majorLineTop+"px",e.style.left=t-i.majorLineWidth/2+"px",e.style.height=i.majorLineHeight+"px"},c.prototype._repaintLine=function(){var t=this.dom.line,e=this.frame;this.options,this.getOption("showMinorLabels")||this.getOption("showMajorLabels")?(t?(e.removeChild(t),e.appendChild(t)):(t=document.createElement("div"),t.className="grid horizontal major",e.appendChild(t),this.dom.line=t),t.style.top=this.props.lineTop+"px"):t&&axis.parentElement&&(e.removeChild(axis.line),delete this.dom.line)},c.prototype._repaintMeasureChars=function(){var t,e=this.dom;if(!e.measureCharMinor){t=document.createTextNode("0");var i=document.createElement("DIV");i.className="text minor measure",i.appendChild(t),this.frame.appendChild(i),e.measureCharMinor=i}if(!e.measureCharMajor){t=document.createTextNode("0");var s=document.createElement("DIV");s.className="text major measure",s.appendChild(t),this.frame.appendChild(s),e.measureCharMajor=s}},c.prototype.reflow=function(){var t=0,e=C.updateProperty,i=this.frame,s=this.range;if(!s)throw Error("Cannot repaint time axis: no range configured");if(i){t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft);var o=this.props,n=this.getOption("showMinorLabels"),r=this.getOption("showMajorLabels"),a=this.dom.measureCharMinor,h=this.dom.measureCharMajor;a&&(o.minorCharHeight=a.clientHeight,o.minorCharWidth=a.clientWidth),h&&(o.majorCharHeight=h.clientHeight,o.majorCharWidth=h.clientWidth);var d=i.parentNode?i.parentNode.offsetHeight:0;switch(d!=o.parentHeight&&(o.parentHeight=d,t+=1),this.getOption("orientation")){case"bottom":o.minorLabelHeight=n?o.minorCharHeight:0,o.majorLabelHeight=r?o.majorCharHeight:0,o.minorLabelTop=0,o.majorLabelTop=o.minorLabelTop+o.minorLabelHeight,o.minorLineTop=-this.top,o.minorLineHeight=Math.max(this.top+o.majorLabelHeight,0),o.minorLineWidth=1,o.majorLineTop=-this.top,o.majorLineHeight=Math.max(this.top+o.minorLabelHeight+o.majorLabelHeight,0),o.majorLineWidth=1,o.lineTop=0;break;case"top":o.minorLabelHeight=n?o.minorCharHeight:0,o.majorLabelHeight=r?o.majorCharHeight:0,o.majorLabelTop=0,o.minorLabelTop=o.majorLabelTop+o.majorLabelHeight,o.minorLineTop=o.minorLabelTop,o.minorLineHeight=Math.max(d-o.majorLabelHeight-this.top),o.minorLineWidth=1,o.majorLineTop=0,o.majorLineHeight=Math.max(d-this.top),o.majorLineWidth=1,o.lineTop=o.majorLabelHeight+o.minorLabelHeight;break;default:throw Error('Unkown orientation "'+this.getOption("orientation")+'"')}var l=o.minorLabelHeight+o.majorLabelHeight;t+=e(this,"width",i.offsetWidth),t+=e(this,"height",l),this._updateConversion();var p=C.cast(s.start,"Date"),u=C.cast(s.end,"Date"),c=this.toTime(5*(o.minorCharWidth||10))-this.toTime(0);this.step=new TimeStep(p,u,c),t+=e(o.range,"start",p.valueOf()),t+=e(o.range,"end",u.valueOf()),t+=e(o.range,"minimumStep",c.valueOf())}return t>0},c.prototype._updateConversion=function(){var t=this.range;if(!t)throw Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},f.prototype=new p,f.types={box:g,range:y,point:v},f.prototype.setOptions=l.prototype.setOptions,f.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},f.prototype.repaint=function(){var t=0,e=C.updateProperty,i=C.option.asSize,s=this.options,o=this.getOption("orientation"),n=this.defaultOptions,r=this.frame;if(!r){r=document.createElement("div"),r.className="itemset";var a=s.className;a&&C.addClassName(r,C.option.asString(a));var h=document.createElement("div");h.className="background",r.appendChild(h),this.dom.background=h;var d=document.createElement("div");d.className="foreground",r.appendChild(d),this.dom.foreground=d;var l=document.createElement("div");l.className="itemset-axis",this.dom.axis=l,this.frame=r,t+=1}if(!this.parent)throw Error("Cannot repaint itemset: no parent attached");var p=this.parent.getContainer();if(!p)throw Error("Cannot repaint itemset: parent has no container element");r.parentNode||(p.appendChild(r),t+=1),this.dom.axis.parentNode||(p.appendChild(this.dom.axis),t+=1),t+=e(r.style,"left",i(s.left,"0px")),t+=e(r.style,"top",i(s.top,"0px")),t+=e(r.style,"width",i(s.width,"100%")),t+=e(r.style,"height",i(s.height,this.height+"px")),t+=e(this.dom.axis.style,"left",i(s.left,"0px")),t+=e(this.dom.axis.style,"width",i(s.width,"100%")),t+="bottom"==o?e(this.dom.axis.style,"top",this.height+this.top+"px"):e(this.dom.axis.style,"top",this.top+"px"),this._updateConversion();var u=this,c=this.queue,m=this.itemsData,g=this.items,v={fields:[m&&m.fieldId||"id","start","end","content","type"]};return Object.keys(c).forEach(function(e){var i=c[e],o=g[e];switch(i){case"add":case"update":var r=m&&m.get(e,v);if(r){var a=r.type||r.start&&r.end&&"range"||s.type||"box",h=f.types[a];if(o&&(h&&o instanceof h?(o.data=r,t++):(t+=o.hide(),o=null)),!o){if(!h)throw new TypeError('Unknown item type "'+a+'"');o=new h(u,r,s,n),t++}o.repaint(),g[e]=o}delete c[e];break;case"remove":o&&(t+=o.hide()),delete g[e],delete c[e];break;default:console.log('Error: unknown action "'+i+'"')}}),C.forEach(this.items,function(e){e.visible?(t+=e.show(),e.reposition()):t+=e.hide()}),t>0},f.prototype.getForeground=function(){return this.dom.foreground},f.prototype.getBackground=function(){return this.dom.background},f.prototype.getAxis=function(){return this.dom.axis},f.prototype.reflow=function(){var t=0,e=this.options,i=e.margin&&e.margin.axis||this.defaultOptions.margin.axis,s=e.margin&&e.margin.item||this.defaultOptions.margin.item,o=C.updateProperty,n=C.option.asNumber,r=C.option.asSize,a=this.frame;if(a){this._updateConversion(),C.forEach(this.items,function(e){t+=e.reflow()}),this.stack.update();var h,d=n(e.maxHeight),l=null!=r(e.height);if(l)h=a.offsetHeight;else{var p=this.stack.ordered;if(p.length){var u=p[0].top,c=p[0].top+p[0].height;C.forEach(p,function(t){u=Math.min(u,t.top),c=Math.max(c,t.top+t.height)}),h=c-u+i+s}else h=i+s}null!=d&&(h=Math.min(h,d)),t+=o(this,"height",h),t+=o(this,"top",a.offsetTop),t+=o(this,"left",a.offsetLeft),t+=o(this,"width",a.offsetWidth)}else t+=1;return t>0},f.prototype.hide=function(){var t=!1;return this.frame&&this.frame.parentNode&&(this.frame.parentNode.removeChild(this.frame),t=!0),this.dom.axis&&this.dom.axis.parentNode&&(this.dom.axis.parentNode.removeChild(this.dom.axis),t=!0),t},f.prototype.setItems=function(t){var e,i=this,s=this.itemsData;if(s&&(C.forEach(this.listeners,function(t,e){s.unsubscribe(e,t)}),e=s.getIds(),this._onRemove(e)),t){if(!(t instanceof n||t instanceof r))throw new TypeError("Data must be an instance of DataSet");this.itemsData=t}else this.itemsData=null;if(this.itemsData){var o=this.id;C.forEach(this.listeners,function(t,e){i.itemsData.subscribe(e,t,o)}),e=this.itemsData.getIds(),this._onAdd(e)}},f.prototype.getItems=function(){return this.itemsData},f.prototype._onUpdate=function(t){this._toQueue("update",t)},f.prototype._onAdd=function(t){this._toQueue("add",t)},f.prototype._onRemove=function(t){this._toQueue("remove",t)},f.prototype._toQueue=function(t,e){var i=this.queue;e.forEach(function(e){i[e]=t}),this.controller&&this.requestRepaint()},f.prototype._updateConversion=function(){var t=this.range;if(!t)throw Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},f.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.factor+e.offset)},f.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.factor},m.prototype.select=function(){this.selected=!0},m.prototype.unselect=function(){this.selected=!1},m.prototype.show=function(){return!1},m.prototype.hide=function(){return!1},m.prototype.repaint=function(){return!1},m.prototype.reflow=function(){return!1},g.prototype=new m(null,null),g.prototype.select=function(){this.selected=!0},g.prototype.unselect=function(){this.selected=!1},g.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw Error("Cannot repaint time axis: parent has no foreground container element");var s=this.parent.getBackground();if(!s)throw Error("Cannot repaint time axis: parent has no background container element");var o=this.parent.getAxis();if(!s)throw Error("Cannot repaint time axis: parent has no axis container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),e.line.parentNode||(s.appendChild(e.line),t=!0),e.dot.parentNode||(o.appendChild(e.dot),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.box.className="item box"+n,e.line.className="item line"+n,e.dot.className="item dot"+n,t=!0)}return t},g.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},g.prototype.hide=function(){var t=!1,e=this.dom;return e&&(e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),e.line.parentNode&&e.line.parentNode.removeChild(e.line),e.dot.parentNode&&e.dot.parentNode.removeChild(e.dot)),t},g.prototype.reflow=function(){var t,e,i,s,o,n,r,a,h,d,l,p,u=0;if(void 0==this.data.start)throw Error('Property "start" missing in item '+this.data.id);if(l=this.data,p=this.parent&&this.parent.range,this.visible=l&&p?l.start>p.start&&l.start0},g.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("DIV"),t.content=document.createElement("DIV"),t.content.className="content",t.box.appendChild(t.content),t.line=document.createElement("DIV"),t.line.className="line",t.dot=document.createElement("DIV"),t.dot.className="dot")},g.prototype.reposition=function(){var t=this.dom,e=this.props,i=this.options.orientation||this.defaultOptions.orientation;if(t){var s=t.box,o=t.line,n=t.dot;s.style.left=this.left+"px",s.style.top=this.top+"px",o.style.left=e.line.left+"px","top"==i?(o.style.top="0px",o.style.height=this.top+"px"):(o.style.top=this.top+this.height+"px",o.style.height=Math.max(this.parent.height-this.top-this.height+this.props.dot.height/2,0)+"px"),n.style.left=e.dot.left+"px",n.style.top=e.dot.top+"px"}},v.prototype=new m(null,null),v.prototype.select=function(){this.selected=!0},v.prototype.unselect=function(){this.selected=!1},v.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw Error("Cannot repaint time axis: parent has no foreground container element");if(e.point.parentNode||(i.appendChild(e.point),i.appendChild(e.point),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var s=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=s&&(this.className=s,e.point.className="item point"+s,t=!0)}return t},v.prototype.show=function(){return this.dom&&this.dom.point.parentNode?!1:this.repaint()},v.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.point.parentNode&&(e.point.parentNode.removeChild(e.point),t=!0),t},v.prototype.reflow=function(){var t,e,i,s,o,n,r,a,h,d,l=0;if(void 0==this.data.start)throw Error('Property "start" missing in item '+this.data.id);if(h=this.data,d=this.parent&&this.parent.range,this.visible=h&&d?h.start>d.start&&h.start0},v.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.point=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.point.appendChild(t.content),t.dot=document.createElement("div"),t.dot.className="dot",t.point.appendChild(t.dot))},v.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.point.style.top=this.top+"px",t.point.style.left=this.left+"px",t.content.style.marginLeft=e.content.marginLeft+"px",t.dot.style.top=e.dot.top+"px")},y.prototype=new m(null,null),y.prototype.select=function(){this.selected=!0},y.prototype.unselect=function(){this.selected=!1},y.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var s=this.data.className?""+this.data.className:"";this.className!=s&&(this.className=s,e.box.className="item range"+s,t=!0)}return t},y.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},y.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),t},y.prototype.reflow=function(){var t,e,i,s,o,n,r,a,h,d,l,p,u,c,f,m,g=0;if(void 0==this.data.start)throw Error('Property "start" missing in item '+this.data.id);if(void 0==this.data.end)throw Error('Property "end" missing in item '+this.data.id); -return h=this.data,d=this.parent&&this.parent.range,this.visible=h&&d?h.startd.start:!1,this.visible&&(t=this.dom,t?(e=this.props,i=this.options,n=this.parent,r=n.toScreen(this.data.start),a=n.toScreen(this.data.end),l=C.updateProperty,p=t.box,u=n.width,f=i.orientation||this.defaultOptions.orientation,s=i.margin&&i.margin.axis||this.defaultOptions.margin.axis,o=i.padding||this.defaultOptions.padding,g+=l(e.content,"width",t.content.offsetWidth),g+=l(this,"height",p.offsetHeight),-u>r&&(r=-u),a>2*u&&(a=2*u),c=0>r?Math.min(-r,a-r-e.content.width-2*o):0,g+=l(e.content,"left",c),"top"==f?(m=s,g+=l(this,"top",m)):(m=n.height-this.height-s,g+=l(this,"top",m)),g+=l(this,"left",r),g+=l(this,"width",Math.max(a-r,1))):g+=1),g>0},y.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content))},y.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.box.style.top=this.top+"px",t.box.style.left=this.left+"px",t.box.style.width=this.width+"px",t.content.style.left=e.content.left+"px")},w.prototype=new l,w.prototype.setOptions=l.prototype.setOptions,w.prototype.getContainer=function(){return this.parent.getContainer()},w.prototype.setItems=function(t){if(this.itemset&&(this.itemset.hide(),this.itemset.setItems(),this.parent.controller.remove(this.itemset),this.itemset=null),t){var e=this.groupId,i=Object.create(this.options);this.itemset=new f(this,null,i),this.itemset.setRange(this.parent.range),this.view=new r(t,{filter:function(t){return t.group==e}}),this.itemset.setItems(this.view),this.parent.controller.add(this.itemset)}},w.prototype.repaint=function(){return!1},w.prototype.reflow=function(){var t=0,e=C.updateProperty;return t+=e(this,"top",this.itemset?this.itemset.top:0),t+=e(this,"height",this.itemset?this.itemset.height:0),t>0},b.prototype=new p,b.prototype.setOptions=l.prototype.setOptions,b.prototype.setRange=function(){},b.prototype.setItems=function(t){this.itemsData=t;for(var e in this.groups)if(this.groups.hasOwnProperty(e)){var i=this.groups[e];i.setItems(t)}},b.prototype.getItems=function(){return this.itemsData},b.prototype.setRange=function(t){this.range=t},b.prototype.setGroups=function(t){var e,i=this;if(this.groupsData&&(C.forEach(this.listeners,function(t,e){i.groupsData.unsubscribe(e,t)}),e=this.groupsData.getIds(),this._onRemove(e)),t?t instanceof n?this.groupsData=t:(this.groupsData=new n({fieldTypes:{start:"Date",end:"Date"}}),this.groupsData.add(t)):this.groupsData=null,this.groupsData){var s=this.id;C.forEach(this.listeners,function(t,e){i.groupsData.subscribe(e,t,s)}),e=this.groupsData.getIds(),this._onAdd(e)}},b.prototype.getGroups=function(){return this.groupsData},b.prototype.repaint=function(){var t=0,e=C.updateProperty,i=C.option.asSize,s=this.options,o=this.frame;if(!o){o=document.createElement("div"),o.className="groupset";var n=s.className;n&&C.addClassName(o,C.option.asString(n)),this.frame=o,t+=1}if(!this.parent)throw Error("Cannot repaint groupset: no parent attached");var r=this.parent.getContainer();if(!r)throw Error("Cannot repaint groupset: parent has no container element");o.parentNode||(r.appendChild(o),t+=1),t+=e(o.style,"height",i(s.height,this.height+"px")),t+=e(o.style,"top",i(s.top,"0px")),t+=e(o.style,"left",i(s.left,"0px")),t+=e(o.style,"width",i(s.width,"100%"));var a=this,h=this.queue,d=this.groups,l=this.groupsData,p=Object.keys(h);if(p.length){p.forEach(function(t){var e=h[t],i=d[t];switch(e){case"add":case"update":if(!i){var s=Object.create(a.options);i=new w(a,t,s),i.setItems(a.itemsData),d[t]=i,a.controller.add(i)}i.data=l.get(t),delete h[t];break;case"remove":i&&(i.setItems(),delete d[t],a.controller.remove(i)),delete h[t];break;default:console.log('Error: unknown action "'+e+'"')}});for(var u=this.groupsData.getIds({order:this.options.groupsOrder}),c=0;u.length>c;c++)(function(t,e){var i=0;e&&(i=function(){return e.top+e.height}),t.setOptions({top:i})})(d[u[c]],d[u[c-1]]);t++}return t>0},b.prototype.getContainer=function(){return this.frame},b.prototype.reflow=function(){var t=0,e=this.options,i=C.updateProperty,s=C.option.asNumber,o=C.option.asSize,n=this.frame;if(n){var r,a=s(e.maxHeight),h=null!=o(e.height);if(h)r=n.offsetHeight;else{r=0;for(var d in this.groups)if(this.groups.hasOwnProperty(d)){var l=this.groups[d];r+=l.height}}null!=a&&(r=Math.min(r,a)),t+=i(this,"height",r),t+=i(this,"top",n.offsetTop),t+=i(this,"left",n.offsetLeft),t+=i(this,"width",n.offsetWidth)}return t>0},b.prototype.hide=function(){return this.frame&&this.frame.parentNode?(this.frame.parentNode.removeChild(this.frame),!0):!1},b.prototype.show=function(){return this.frame&&this.frame.parentNode?!1:this.repaint()},b.prototype._onUpdate=function(t){this._toQueue(t,"update")},b.prototype._onAdd=function(t){this._toQueue(t,"add")},b.prototype._onRemove=function(t){this._toQueue(t,"remove")},b.prototype._toQueue=function(t,e){var i=this.queue;t.forEach(function(t){i[t]=e}),this.controller&&this.requestRepaint()},_.prototype.setOptions=function(t){t&&C.extend(this.options,t),this.controller.reflow(),this.controller.repaint()},_.prototype.setItems=function(t){var e,i=null==this.itemsData;if(t?t instanceof n&&(e=t):e=null,t instanceof n||(e=new n({fieldTypes:{start:"Date",end:"Date"}}),e.add(t)),this.itemsData=e,this.content.setItems(e),i&&(void 0==this.options.start||void 0==this.options.end)){var s=this.getItemRange(),o=s.min,r=s.max;if(null!=o&&null!=r){var a=r.valueOf()-o.valueOf();o=new Date(o.valueOf()-.05*a),r=new Date(r.valueOf()+.05*a)}void 0!=this.options.start&&(o=new Date(this.options.start.valueOf())),void 0!=this.options.end&&(r=new Date(this.options.end.valueOf())),(null!=o||null!=r)&&this.range.setRange(o,r)}},_.prototype.setGroups=function(t){var e=this;this.groupsData=t;var i=this.groupsData?b:f;if(!(this.content instanceof i)){this.content&&(this.content.hide(),this.content.setItems&&this.content.setItems(),this.content.setGroups&&this.content.setGroups(),this.controller.remove(this.content));var s=Object.create(this.options);C.extend(s,{top:function(){return"top"==e.options.orientation?e.timeaxis.height:e.root.height-e.timeaxis.height-e.content.height},height:function(){return e.options.height?e.root.height-e.timeaxis.height:null},maxHeight:function(){if(e.options.maxHeight){if(!C.isNumber(e.options.maxHeight))throw new TypeError("Number expected for property maxHeight");return e.options.maxHeight-e.timeaxis.height}return null}}),this.content=new i(this.root,[this.timeaxis],s),this.content.setRange&&this.content.setRange(this.range),this.content.setItems&&this.content.setItems(this.itemsData),this.content.setGroups&&this.content.setGroups(this.groupsData),this.controller.add(this.content)}},_.prototype.getItemRange=function(){var t=this.itemsData,e=null,i=null;if(t){var s=t.min("start");e=s?s.start.valueOf():null;var o=t.max("start");o&&(i=o.start.valueOf());var n=t.max("end");n&&(i=null==i?n.end.valueOf():Math.max(i,n.end.valueOf()))}return{min:null!=e?new Date(e):null,max:null!=i?new Date(i):null}},function(t){function e(t){return w=t,l()}function i(){b=0,_=w.charAt(0)}function s(){b++,_=w.charAt(b)}function o(){return w.charAt(b+1)}function n(t){return C.test(t)}function r(t,e){if(t||(t={}),e)for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function a(t){M.nodes||(M.nodes={});var e=M.nodes[t.id];if(e)t.attr&&(e.attr=r(e.attr,t.attr));else if(M.nodes[t.id]=t,S){var i=r({},S);t.attr=r(i,t.attr)}}function h(t){if(M.edges||(M.edges=[]),M.edges.push(t),E){var e=r({},E);t.attr=r(e,t.attr)}}function d(){for(T=v.NULL,x="";" "==_||" "==_||"\n"==_||"\r"==_;)s();do{var t=!1;if("#"==_){for(var e=b-1;" "==w.charAt(e)||" "==w.charAt(e);)e--;if("\n"==w.charAt(e)||""==w.charAt(e)){for(;""!=_&&"\n"!=_;)s();t=!0}}if("/"==_&&"/"==o()){for(;""!=_&&"\n"!=_;)s();t=!0}if("/"==_&&"*"==o()){for(;""!=_;){if("*"==_&&"/"==o()){s(),s();break}s()}t=!0}for(;" "==_||" "==_||"\n"==_||"\r"==_;)s()}while(t);if(""==_)return T=v.DELIMITER,void 0;var i=_+o();if(y[i])return T=v.DELIMITER,x=i,s(),s(),void 0;if(y[_])return T=v.DELIMITER,x=_,s(),void 0;if(n(_)||"-"==_){for(x+=_,s();n(_);)x+=_,s();return"false"==x?x=!1:"true"==x?x=!0:isNaN(Number(x))||(x=Number(x)),T=v.IDENTIFIER,void 0}if('"'==_){for(s();""!=_&&('"'!=_||'"'==_&&'"'==o());)x+=_,'"'==_&&s(),s();if('"'!=_)throw f('End of string " expected');return s(),T=v.IDENTIFIER,void 0}for(T=v.UNKNOWN;""!=_;)x+=_,s();throw new SyntaxError('Syntax error in part "'+m(x,30)+'"')}function l(){if(M={},S=null,E=null,i(),d(),"strict"==x&&(M.strict=!0,d()),("graph"==x||"digraph"==x)&&(M.type=x,d()),T==v.IDENTIFIER&&(M.id=x,d()),"{"!=x)throw f("Angle bracket { expected");if(d(),p(),"}"!=x)throw f("Angle bracket } expected");if(d(),""!==x)throw f("End of file expected");return d(),M}function p(){for(;""!==x&&"}"!=x;){if(T!=v.IDENTIFIER)throw f("Identifier expected");u(),";"==x&&d()}}function u(){var t,e=x;if(d(),"node"==e)t=c(),t&&(S=r(S,t));else if("edge"==e)t=c(),t&&(E=r(E,t));else if("graph"==e)t=c(),t&&(M.attr=r(M.attr,t));else if("="==x)d(),M.attr||(M.attr={}),M.attr[e]=x,d();else{var i={id:e+""};t=c(),t&&(i.attr=t),a(i);for(var s=e;"->"==x||"--"==x;){var o=x;d();var n=x;a({id:n+""}),d(),t=c();var l={from:s+"",to:n+"",type:o};t&&(l.attr=t),h(l),s=n}}}function c(){if("["==x){d();for(var t={};""!==x&&"]"!=x;){if(T!=v.IDENTIFIER)throw f("Attribute name expected");var e=x;if(d(),"="!=x)throw f("Equal sign = expected");if(d(),T!=v.IDENTIFIER)throw f("Attribute value expected");var i=x;t[e]=i,d(),","==x&&d()}return d(),t}return void 0}function f(t){return new SyntaxError(t+', got "'+m(x,30)+'" (char '+b+")")}function m(t,e){return e>=t.length?t:t.substr(0,27)+"..."}function g(t){var i=e(t),s={nodes:[],edges:[],options:{}};if(i.nodes)for(var o in i.nodes)if(i.nodes.hasOwnProperty(o)){var n={id:o,label:o};r(n,i.nodes[o].attr),n.image&&(n.shape="image"),s.nodes.push(n)}return i.edges&&i.edges.forEach(function(t){var e={from:t.from,to:t.to};r(e,t.attr),e.style="->"==t.type?"arrow":"line",s.edges.push(e)}),i.attr&&(s.options=i.attr),s}var v={NULL:0,DELIMITER:1,IDENTIFIER:2,UNKNOWN:3},y={"{":!0,"}":!0,"[":!0,"]":!0,";":!0,"=":!0,",":!0,"->":!0,"--":!0},w="",b=0,_="",x="",T=v.NULL,M=null,S=null,E=null,C=/[a-zA-Z_0-9.#]/;t.parseDOT=e,t.DOTToGraph=g}(C!==void 0?C:s),"undefined"!=typeof CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.circle=function(t,e,i){this.beginPath(),this.arc(t,e,i,0,2*Math.PI,!1)},CanvasRenderingContext2D.prototype.square=function(t,e,i){this.beginPath(),this.rect(t-i,e-i,2*i,2*i)},CanvasRenderingContext2D.prototype.triangle=function(t,e,i){this.beginPath();var s=2*i,o=s/2,n=Math.sqrt(3)/6*s,r=Math.sqrt(s*s-o*o);this.moveTo(t,e-(r-n)),this.lineTo(t+o,e+n),this.lineTo(t-o,e+n),this.lineTo(t,e-(r-n)),this.closePath()},CanvasRenderingContext2D.prototype.triangleDown=function(t,e,i){this.beginPath();var s=2*i,o=s/2,n=Math.sqrt(3)/6*s,r=Math.sqrt(s*s-o*o);this.moveTo(t,e+(r-n)),this.lineTo(t+o,e-n),this.lineTo(t-o,e-n),this.lineTo(t,e+(r-n)),this.closePath()},CanvasRenderingContext2D.prototype.star=function(t,e,i){this.beginPath();for(var s=0;10>s;s++){var o=0===s%2?1.3*i:.5*i;this.lineTo(t+o*Math.sin(2*s*Math.PI/10),e-o*Math.cos(2*s*Math.PI/10))}this.closePath()},CanvasRenderingContext2D.prototype.roundRect=function(t,e,i,s,o){var n=Math.PI/180;0>i-2*o&&(o=i/2),0>s-2*o&&(o=s/2),this.beginPath(),this.moveTo(t+o,e),this.lineTo(t+i-o,e),this.arc(t+i-o,e+o,o,270*n,360*n,!1),this.lineTo(t+i,e+s-o),this.arc(t+i-o,e+s-o,o,0,90*n,!1),this.lineTo(t+o,e+s),this.arc(t+o,e+s-o,o,90*n,180*n,!1),this.lineTo(t,e+o),this.arc(t+o,e+o,o,180*n,270*n,!1)},CanvasRenderingContext2D.prototype.ellipse=function(t,e,i,s){var o=.5522848,n=i/2*o,r=s/2*o,a=t+i,h=e+s,d=t+i/2,l=e+s/2;this.beginPath(),this.moveTo(t,l),this.bezierCurveTo(t,l-r,d-n,e,d,e),this.bezierCurveTo(d+n,e,a,l-r,a,l),this.bezierCurveTo(a,l+r,d+n,h,d,h),this.bezierCurveTo(d-n,h,t,l+r,t,l)},CanvasRenderingContext2D.prototype.database=function(t,e,i,s){var o=1/3,n=i,r=s*o,a=.5522848,h=n/2*a,d=r/2*a,l=t+n,p=e+r,u=t+n/2,c=e+r/2,f=e+(s-r/2),m=e+s;this.beginPath(),this.moveTo(l,c),this.bezierCurveTo(l,c+d,u+h,p,u,p),this.bezierCurveTo(u-h,p,t,c+d,t,c),this.bezierCurveTo(t,c-d,u-h,e,u,e),this.bezierCurveTo(u+h,e,l,c-d,l,c),this.lineTo(l,f),this.bezierCurveTo(l,f+d,u+h,m,u,m),this.bezierCurveTo(u-h,m,t,f+d,t,f),this.lineTo(t,c)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,s){var o=t-s*Math.cos(i),n=e-s*Math.sin(i),r=t-.9*s*Math.cos(i),a=e-.9*s*Math.sin(i),h=o+s/3*Math.cos(i+.5*Math.PI),d=n+s/3*Math.sin(i+.5*Math.PI),l=o+s/3*Math.cos(i-.5*Math.PI),p=n+s/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,d),this.lineTo(r,a),this.lineTo(l,p),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,s,o){o||(o=[10,5]),0==u&&(u=.001);var n=o.length;this.moveTo(t,e);for(var r=i-t,a=s-e,h=a/r,d=Math.sqrt(r*r+a*a),l=0,p=!0;d>=.1;){var u=o[l++%n];u>d&&(u=d);var c=Math.sqrt(u*u/(1+h*h));0>r&&(c=-c),t+=c,e+=h*c,this[p?"lineTo":"moveTo"](t,e),d-=u,p=!p}}),x.prototype.attachEdge=function(t){this.edges.push(t),this._updateMass()},x.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&this.edges.splice(e,1),this._updateMass()},x.prototype._updateMass=function(){this.mass=50+20*this.edges.length},x.prototype.setProperties=function(t,e){if(t){if(void 0!=t.id&&(this.id=t.id),void 0!=t.label&&(this.label=t.label),void 0!=t.title&&(this.title=t.title),void 0!=t.group&&(this.group=t.group),void 0!=t.x&&(this.x=t.x),void 0!=t.y&&(this.y=t.y),void 0!=t.value&&(this.value=t.value),void 0===this.id)throw"Node must have an id";if(this.group){var i=this.grouplist.get(this.group);for(var s in i)i.hasOwnProperty(s)&&(this[s]=i[s])}if(void 0!=t.shape&&(this.shape=t.shape),void 0!=t.image&&(this.image=t.image),void 0!=t.radius&&(this.radius=t.radius),void 0!=t.color&&(this.color=x.parseColor(t.color)),void 0!=t.fontColor&&(this.fontColor=t.fontColor),void 0!=t.fontSize&&(this.fontSize=t.fontSize),void 0!=t.fontFace&&(this.fontFace=t.fontFace),void 0!=this.image){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.image)}switch(this.xFixed=this.xFixed||void 0!=t.x,this.yFixed=this.yFixed||void 0!=t.y,this.radiusFixed=this.radiusFixed||void 0!=t.radius,"image"==this.shape&&(this.radiusMin=e.nodes.widthMin,this.radiusMax=e.nodes.widthMax),this.shape){case"database":this.draw=this._drawDatabase,this.resize=this._resizeDatabase;break;case"box":this.draw=this._drawBox,this.resize=this._resizeBox;break;case"circle":this.draw=this._drawCircle,this.resize=this._resizeCircle;break;case"ellipse":this.draw=this._drawEllipse,this.resize=this._resizeEllipse;break;case"image":this.draw=this._drawImage,this.resize=this._resizeImage;break;case"text":this.draw=this._drawText,this.resize=this._resizeText;break;case"dot":this.draw=this._drawDot,this.resize=this._resizeShape;break;case"square":this.draw=this._drawSquare,this.resize=this._resizeShape;break;case"triangle":this.draw=this._drawTriangle,this.resize=this._resizeShape;break;case"triangleDown":this.draw=this._drawTriangleDown,this.resize=this._resizeShape;break;case"star":this.draw=this._drawStar,this.resize=this._resizeShape;break;default:this.draw=this._drawEllipse,this.resize=this._resizeEllipse}this._reset()}},x.parseColor=function(t){var e;return C.isString(t)?e={border:t,background:t,highlight:{border:t,background:t}}:(e={},e.background=t.background||"white",e.border=t.border||e.background,C.isString(t.highlight)?e.highlight={border:t.highlight,background:t.highlight}:(e.highlight={},e.highlight.background=t.highlight&&t.highlight.background||e.background,e.highlight.border=t.highlight&&t.highlight.border||e.border)),e},x.prototype.select=function(){this.selected=!0,this._reset()},x.prototype.unselect=function(){this.selected=!1,this._reset()},x.prototype._reset=function(){this.width=void 0,this.height=void 0},x.prototype.getTitle=function(){return this.title},x.prototype.distanceToBorder=function(t,e){var i=1;switch(this.width||this.resize(t),this.shape){case"circle":case"dot":return this.radius+i;case"ellipse":var s=this.width/2,o=this.height/2,n=Math.sin(e)*s,r=Math.cos(e)*o;return s*o/Math.sqrt(n*n+r*r);case"box":case"image":case"text":default:return this.width?Math.min(Math.abs(this.width/2/Math.cos(e)),Math.abs(this.height/2/Math.sin(e)))+i:0}},x.prototype._setForce=function(t,e){this.fx=t,this.fy=e},x.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},x.prototype.discreteStep=function(t){if(!this.xFixed){var e=-this.damping*this.vx,i=(this.fx+e)/this.mass;this.vx+=i/t,this.x+=this.vx/t}if(!this.yFixed){var s=-this.damping*this.vy,o=(this.fy+s)/this.mass;this.vy+=o/t,this.y+=this.vy/t}},x.prototype.isFixed=function(){return this.xFixed&&this.yFixed},x.prototype.isMoving=function(t){return Math.abs(this.vx)>t||Math.abs(this.vy)>t||!this.xFixed&&Math.abs(this.fx)>this.minForce||!this.yFixed&&Math.abs(this.fy)>this.minForce},x.prototype.isSelected=function(){return this.selected},x.prototype.getValue=function(){return this.value},x.prototype.getDistance=function(t,e){var i=this.x-t,s=this.y-e;return Math.sqrt(i*i+s*s)},x.prototype.setValueRange=function(t,e){if(!this.radiusFixed&&void 0!==this.value){var i=(this.radiusMax-this.radiusMin)/(e-t);this.radius=(this.value-t)*i+this.radiusMin}},x.prototype.draw=function(){throw"Draw method not initialized for node"},x.prototype.resize=function(){throw"Resize method not initialized for node"},x.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},x.prototype._resizeImage=function(){if(!this.width){var t,e;if(this.value){var i=this.imageObj.height/this.imageObj.width;t=this.radius||this.imageObj.width,e=this.radius*i||this.imageObj.height}else t=this.imageObj.width,e=this.imageObj.height;this.width=t,this.height=e}},x.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e;this.imageObj?(t.drawImage(this.imageObj,this.left,this.top,this.width,this.height),e=this.y+this.height/2):e=this.y,this._label(t,this.label,this.x,e,void 0,"top")},x.prototype._resizeBox=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e}},x.prototype._drawBox=function(t){this._resizeBox(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,t.roundRect(this.left,this.top,this.width,this.height,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},x.prototype._resizeDatabase=function(t){if(!this.width){var e=5,i=this.getTextSize(t),s=i.width+2*e;this.width=s,this.height=s}},x.prototype._drawDatabase=function(t){this._resizeDatabase(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,t.database(this.x-this.width/2,this.y-.5*this.height,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},x.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),s=Math.max(i.width,i.height)+2*e;this.radius=s/2,this.width=s,this.height=s}},x.prototype._drawCircle=function(t){this._resizeCircle(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,t.circle(this.x,this.y,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},x.prototype._resizeEllipse=function(t){if(!this.width){var e=this.getTextSize(t);this.width=1.5*e.width,this.height=2*e.height,this.widthl;l++)t.fillText(r[l],i,d),d+=h}},x.prototype.getTextSize=function(t){if(void 0!=this.label){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace;for(var e=this.label.split("\n"),i=(this.fontSize+4)*e.length,s=0,o=0,n=e.length;n>o;o++)s=Math.max(s,t.measureText(e[o]).width);return{width:s,height:i}}return{width:0,height:0}},T.prototype.setProperties=function(t,e){if(t){if(void 0!=t.from&&(this.from=this.graph._getNode(t.from)),void 0!=t.to&&(this.to=this.graph._getNode(t.to)),void 0!=t.id&&(this.id=t.id),void 0!=t.style&&(this.style=t.style),void 0!=t.label&&(this.label=t.label),this.label&&(this.fontSize=e.edges.fontSize,this.fontFace=e.edges.fontFace,this.fontColor=e.edges.fontColor,void 0!=t.fontColor&&(this.fontColor=t.fontColor),void 0!=t.fontSize&&(this.fontSize=t.fontSize),void 0!=t.fontFace&&(this.fontFace=t.fontFace)),void 0!=t.title&&(this.title=t.title),void 0!=t.width&&(this.width=t.width),void 0!=t.value&&(this.value=t.value),void 0!=t.length&&(this.length=t.length),t.dash&&(void 0!=t.dash.length&&(this.dash.length=t.dash.length),void 0!=t.dash.gap&&(this.dash.gap=t.dash.gap),void 0!=t.dash.altLength&&(this.dash.altLength=t.dash.altLength)),void 0!=t.color&&(this.color=t.color),!this.from)throw"Node with id "+t.from+" not found";if(!this.to)throw"Node with id "+t.to+" not found";switch(this.widthFixed=this.widthFixed||void 0!=t.width,this.lengthFixed=this.lengthFixed||void 0!=t.length,this.stiffness=1/this.length,this.style){case"line":this.draw=this._drawLine;break;case"arrow":this.draw=this._drawArrow;break;case"arrow-center":this.draw=this._drawArrowCenter;break;case"dash-line":this.draw=this._drawDashLine;break;default:this.draw=this._drawLine}}},T.prototype.getTitle=function(){return this.title},T.prototype.getValue=function(){return this.value},T.prototype.setValueRange=function(t,e){if(!this.widthFixed&&void 0!==this.value){var i=(this.widthMax-this.widthMin)/(e-t);this.width=(this.value-t)*i+this.widthMin}},T.prototype.draw=function(){throw"Method draw not initialized in edge"},T.prototype.isOverlappingWith=function(t){var e=10,i=this.from.x,s=this.from.y,o=this.to.x,n=this.to.y,r=t.left,a=t.top,h=T._dist(i,s,o,n,r,a);return e>h},T.prototype._drawLine=function(t){t.strokeStyle=this.color,t.lineWidth=this._getLineWidth();var e;if(this.from!=this.to)this._line(t),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y));else{var i,s,o=this.length/4,n=this.from;n.width||n.resize(t),n.width>n.height?(i=n.x+n.width/2,s=n.y-o):(i=n.x+o,s=n.y-n.height/2),this._circle(t,i,s,o),e=this._pointOnCircle(i,s,o,.5),this._label(t,this.label,e.x,e.y)}},T.prototype._getLineWidth=function(){return this.from.selected||this.to.selected?Math.min(2*this.width,this.widthMax):this.width},T.prototype._line=function(t){t.beginPath(),t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y),t.stroke()},T.prototype._circle=function(t,e,i,s){t.beginPath(),t.arc(e,i,s,0,2*Math.PI,!1),t.stroke()},T.prototype._label=function(t,e,i,s){if(e){t.font=(this.from.selected||this.to.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle="white";var o=t.measureText(e).width,n=this.fontSize,r=i-o/2,a=s-n/2;t.fillRect(r,a,o,n),t.fillStyle=this.fontColor||"black",t.textAlign="left",t.textBaseline="top",t.fillText(e,r,a)}},T.prototype._drawDashLine=function(t){if(t.strokeStyle=this.color,t.lineWidth=this._getLineWidth(),t.beginPath(),t.lineCap="round",void 0!=this.dash.altLength?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]):void 0!=this.dash.length&&void 0!=this.dash.gap?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap]):(t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y)),t.stroke(),this.label){var e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}},T.prototype._pointOnLine=function(t){return{x:(1-t)*this.from.x+t*this.to.x,y:(1-t)*this.from.y+t*this.to.y}},T.prototype._pointOnCircle=function(t,e,i,s){var o=2*(s-3/8)*Math.PI;return{x:t+i*Math.cos(o),y:e-i*Math.sin(o)}},T.prototype._drawArrowCenter=function(t){var e;if(t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth(),this.from!=this.to){this._line(t);var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),s=10+5*this.width;e=this._pointOnLine(.5),t.arrow(e.x,e.y,i,s),t.fill(),t.stroke(),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y))}else{var o,n,r=this.length/4,a=this.from;a.width||a.resize(t),a.width>a.height?(o=a.x+a.width/2,n=a.y-r):(o=a.x+r,n=a.y-a.height/2),this._circle(t,o,n,r);var i=.2*Math.PI,s=10+5*this.width;e=this._pointOnCircle(o,n,r,.5),t.arrow(e.x,e.y,i,s),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(o,n,r,.5),this._label(t,this.label,e.x,e.y))}},T.prototype._drawArrow=function(t){t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth();var e,i;if(this.from!=this.to){e=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x);var s=this.to.x-this.from.x,o=this.to.y-this.from.y,n=Math.sqrt(s*s+o*o),r=this.from.distanceToBorder(t,e+Math.PI),a=(n-r)/n,h=a*this.from.x+(1-a)*this.to.x,d=a*this.from.y+(1-a)*this.to.y,l=this.to.distanceToBorder(t,e),p=(n-l)/n,u=(1-p)*this.from.x+p*this.to.x,c=(1-p)*this.from.y+p*this.to.y;if(t.beginPath(),t.moveTo(h,d),t.lineTo(u,c),t.stroke(),i=10+5*this.width,t.arrow(u,c,e,i),t.fill(),t.stroke(),this.label){var f=this._pointOnLine(.5);this._label(t,this.label,f.x,f.y)}}else{var m,g,v,y=this.from,w=this.length/4;y.width||y.resize(t),y.width>y.height?(m=y.x+y.width/2,g=y.y-w,v={x:m,y:y.y,angle:.9*Math.PI}):(m=y.x+w,g=y.y-y.height/2,v={x:y.x,y:g,angle:.6*Math.PI}),t.beginPath(),t.arc(m,g,w,0,2*Math.PI,!1),t.stroke(),i=10+5*this.width,t.arrow(v.x,v.y,v.angle,i),t.fill(),t.stroke(),this.label&&(f=this._pointOnCircle(m,g,w,.5),this._label(t,this.label,f.x,f.y))}},T._dist=function(t,e,i,s,o,n){var r=i-t,a=s-e,h=r*r+a*a,d=((o-t)*r+(n-e)*a)/h;d>1?d=1:0>d&&(d=0);var l=t+d*r,p=e+d*a,u=l-o,c=p-n;return Math.sqrt(u*u+c*c)},M.prototype.setPosition=function(t,e){this.x=parseInt(t),this.y=parseInt(e)},M.prototype.setText=function(t){this.frame.innerHTML=t},M.prototype.show=function(t){if(void 0===t&&(t=!0),t){var e=this.frame.clientHeight,i=this.frame.clientWidth,s=this.frame.parentNode.clientHeight,o=this.frame.parentNode.clientWidth,n=this.y-e;n+e+this.padding>s&&(n=s-e-this.padding),this.padding>n&&(n=this.padding);var r=this.x;r+i+this.padding>o&&(r=o-i-this.padding),this.padding>r&&(r=this.padding),this.frame.style.left=r+"px",this.frame.style.top=n+"px",this.frame.style.visibility="visible"}else this.hide()},M.prototype.hide=function(){this.frame.style.visibility="hidden"},Groups=function(){this.clear(),this.defaultIndex=0},Groups.DEFAULT=[{border:"#2B7CE9",background:"#97C2FC",highlight:{border:"#2B7CE9",background:"#D2E5FF"}},{border:"#FFA500",background:"#FFFF00",highlight:{border:"#FFA500",background:"#FFFFA3"}},{border:"#FA0A10",background:"#FB7E81",highlight:{border:"#FA0A10",background:"#FFAFB1"}},{border:"#41A906",background:"#7BE141",highlight:{border:"#41A906",background:"#A1EC76"}},{border:"#E129F0",background:"#EB7DF4",highlight:{border:"#E129F0",background:"#F0B3F5"}},{border:"#7C29F0",background:"#AD85E4",highlight:{border:"#7C29F0",background:"#D3BDF0"}},{border:"#C37F00",background:"#FFA807",highlight:{border:"#C37F00",background:"#FFCA66"}},{border:"#4220FB",background:"#6E6EFD",highlight:{border:"#4220FB",background:"#9B9BFD"}},{border:"#FD5A77",background:"#FFC0CB",highlight:{border:"#FD5A77",background:"#FFD1D9"}},{border:"#4AD63A",background:"#C2FABC",highlight:{border:"#4AD63A",background:"#E6FFE3"}}],Groups.prototype.clear=function(){this.groups={},this.groups.length=function(){var t=0;for(var e in this)this.hasOwnProperty(e)&&t++;return t}},Groups.prototype.get=function(t){var e=this.groups[t];if(void 0==e){var i=this.defaultIndex%Groups.DEFAULT.length;this.defaultIndex++,e={},e.color=Groups.DEFAULT[i],this.groups[t]=e}return e},Groups.prototype.add=function(t,e){return this.groups[t]=e,e.color&&(e.color=x.parseColor(e.color)),e},Images=function(){this.images={},this.callback=void 0},Images.prototype.setOnloadCallback=function(t){this.callback=t},Images.prototype.load=function(t){var e=this.images[t];if(void 0==e){var i=this;e=new Image,this.images[t]=e,e.onload=function(){i.callback&&i.callback(this)},e.src=t}return e},S.prototype.setData=function(t){if(t&&t.dot&&(t.nodes||t.edges))throw new SyntaxError('Data must contain either parameter "dot" or parameter pair "nodes" and "edges", but not both.');if(this.setOptions(t&&t.options),t&&t.dot){if(t&&t.dot){var e=N.util.DOTToGraph(t.dot);return this.setData(e),void 0}}else this._setNodes(t&&t.nodes),this._setEdges(t&&t.edges);this.stabilize&&this._doStabilize(),this.start()},S.prototype.setOptions=function(t){if(t){if(void 0!=t.width&&(this.width=t.width),void 0!=t.height&&(this.height=t.height),void 0!=t.stabilize&&(this.stabilize=t.stabilize),void 0!=t.selectable&&(this.selectable=t.selectable),t.edges){for(var e in t.edges)t.edges.hasOwnProperty(e)&&(this.constants.edges[e]=t.edges[e]);void 0!=t.edges.length&&t.nodes&&void 0==t.nodes.distance&&(this.constants.edges.length=t.edges.length,this.constants.nodes.distance=1.25*t.edges.length),t.edges.fontColor||(this.constants.edges.fontColor=t.edges.color),t.edges.dash&&(void 0!=t.edges.dash.length&&(this.constants.edges.dash.length=t.edges.dash.length),void 0!=t.edges.dash.gap&&(this.constants.edges.dash.gap=t.edges.dash.gap),void 0!=t.edges.dash.altLength&&(this.constants.edges.dash.altLength=t.edges.dash.altLength))}if(t.nodes){for(e in t.nodes)t.nodes.hasOwnProperty(e)&&(this.constants.nodes[e]=t.nodes[e]);t.nodes.color&&(this.constants.nodes.color=x.parseColor(t.nodes.color))}if(t.groups)for(var i in t.groups)if(t.groups.hasOwnProperty(i)){var s=t.groups[i];this.groups.add(i,s)}}this.setSize(this.width,this.height),this._setTranslation(0,0),this._setScale(1)},S.prototype._trigger=function(t,e){O.trigger(this,t,e) -},S.prototype._create=function(){for(;this.containerElement.hasChildNodes();)this.containerElement.removeChild(this.containerElement.firstChild);if(this.frame=document.createElement("div"),this.frame.className="graph-frame",this.frame.style.position="relative",this.frame.style.overflow="hidden",this.frame.canvas=document.createElement("canvas"),this.frame.canvas.style.position="relative",this.frame.appendChild(this.frame.canvas),!this.frame.canvas.getContext){var t=document.createElement("DIV");t.style.color="red",t.style.fontWeight="bold",t.style.padding="10px",t.innerHTML="Error: your browser does not support HTML canvas",this.frame.canvas.appendChild(t)}var e=this,i=function(t){e._onMouseDown(t)},s=function(t){e._onMouseMoveTitle(t)},o=function(t){e._onMouseWheel(t)},n=function(t){e._onTouchStart(t)};N.util.addEventListener(this.frame.canvas,"mousedown",i),N.util.addEventListener(this.frame.canvas,"mousemove",s),N.util.addEventListener(this.frame.canvas,"mousewheel",o),N.util.addEventListener(this.frame.canvas,"touchstart",n),this.containerElement.appendChild(this.frame)},S.prototype._onMouseDown=function(t){if(t=t||window.event,this.selectable&&(this.leftButtonDown&&this._onMouseUp(t),this.leftButtonDown=t.which?1==t.which:1==t.button,this.leftButtonDown||this.touchDown)){var e=this;this.onmousemove||(this.onmousemove=function(t){e._onMouseMove(t)},N.util.addEventListener(document,"mousemove",e.onmousemove)),this.onmouseup||(this.onmouseup=function(t){e._onMouseUp(t)},N.util.addEventListener(document,"mouseup",e.onmouseup)),N.util.preventDefault(t),this.startMouseX=t.clientX||t.targetTouches[0].clientX,this.startMouseY=t.clientY||t.targetTouches[0].clientY,this.startFrameLeft=N.util.getAbsoluteLeft(this.frame.canvas),this.startFrameTop=N.util.getAbsoluteTop(this.frame.canvas),this.startTranslation=this._getTranslation(),this.ctrlKeyDown=t.ctrlKey,this.shiftKeyDown=t.shiftKey;var i={left:this._xToCanvas(this.startMouseX-this.startFrameLeft),top:this._yToCanvas(this.startMouseY-this.startFrameTop),right:this._xToCanvas(this.startMouseX-this.startFrameLeft),bottom:this._yToCanvas(this.startMouseY-this.startFrameTop)},s=this._getNodesOverlappingWith(i);if(this.startClickedObj=s.length>0?s[s.length-1]:void 0,this.startClickedObj){var o=this.nodes[this.startClickedObj.row];this.startClickedObj.xFixed=o.xFixed,this.startClickedObj.yFixed=o.yFixed,o.xFixed=!0,o.yFixed=!0,this.ctrlKeyDown&&o.isSelected()?this._unselectNodes([this.startClickedObj]):this._selectNodes([this.startClickedObj],this.ctrlKeyDown),this.moving||this._redraw()}else this.shiftKeyDown||(this.moved=!1)}},S.prototype._onMouseMove=function(t){if(t=t||window.event,this.selectable){var e=t.clientX||t.targetTouches&&t.targetTouches[0].clientX||0,i=t.clientY||t.targetTouches&&t.targetTouches[0].clientY||0;if(this.mouseX=e,this.mouseY=i,this.startClickedObj){var s=this.nodes[this.startClickedObj.row];this.startClickedObj.xFixed||(s.x=this._xToCanvas(e-this.startFrameLeft)),this.startClickedObj.yFixed||(s.y=this._yToCanvas(i-this.startFrameTop)),this.moving||(this.moving=!0,this.start())}else if(this.shiftKeyDown){void 0==this.frame.selRect&&(this.frame.selRect=document.createElement("DIV"),this.frame.appendChild(this.frame.selRect),this.frame.selRect.style.position="absolute",this.frame.selRect.style.border="1px dashed red");var o=Math.min(this.startMouseX,e)-this.startFrameLeft,n=Math.min(this.startMouseY,i)-this.startFrameTop,r=Math.max(this.startMouseX,e)-this.startFrameLeft,a=Math.max(this.startMouseY,i)-this.startFrameTop;this.frame.selRect.style.left=o+"px",this.frame.selRect.style.top=n+"px",this.frame.selRect.style.width=r-o+"px",this.frame.selRect.style.height=a-n+"px"}else{var h=e-this.startMouseX,d=i-this.startMouseY;this._setTranslation(this.startTranslation.x+h,this.startTranslation.y+d),this._redraw(),this.moved=!0}N.util.preventDefault(t)}},S.prototype._onMouseUp=function(t){if(t=t||window.event,this.selectable){this.onmousemove&&(N.util.removeEventListener(document,"mousemove",this.onmousemove),this.onmousemove=void 0),this.onmouseup&&(N.util.removeEventListener(document,"mouseup",this.onmouseup),this.onmouseup=void 0),N.util.preventDefault(t);var e=t.clientX||this.mouseX||0,i=t.clientY||this.mouseY||0,s=t?t.ctrlKey:window.event.ctrlKey;if(this.startClickedObj){var o=this.nodes[this.startClickedObj.row];o.xFixed=this.startClickedObj.xFixed,o.yFixed=this.startClickedObj.yFixed}else if(this.shiftKeyDown){var n={left:this._xToCanvas(Math.min(this.startMouseX,e)-this.startFrameLeft),top:this._yToCanvas(Math.min(this.startMouseY,i)-this.startFrameTop),right:this._xToCanvas(Math.max(this.startMouseX,e)-this.startFrameLeft),bottom:this._yToCanvas(Math.max(this.startMouseY,i)-this.startFrameTop)},r=this._getNodesOverlappingWith(n);this._selectNodes(r,s),this.redraw(),this.frame.selRect&&(this.frame.removeChild(this.frame.selRect),this.frame.selRect=void 0)}else this.ctrlKeyDown||this.moved||(this._unselectNodes(),this._redraw());this.leftButtonDown=!1,this.ctrlKeyDown=!1}},S.prototype._onMouseWheel=function(t){t=t||window.event;var e=t.clientX,i=t.clientY,s=0;if(t.wheelDelta?s=t.wheelDelta/120:t.detail&&(s=-t.detail/3),s){var o=s/10;0>s&&(o/=1-o);var n=this._getScale(),r=n*(1+o);.01>r&&(r=.01),r>10&&(r=10);var a=N.util.getAbsoluteLeft(this.frame.canvas),h=N.util.getAbsoluteTop(this.frame.canvas),d=e-a,l=i-h,p=this._getTranslation(),u=r/n,c=(1-u)*d+p.x*u,f=(1-u)*l+p.y*u;this._setScale(r),this._setTranslation(c,f),this._redraw()}N.util.preventDefault(t)},S.prototype._onMouseMoveTitle=function(t){t=t||window.event;var e=t.clientX,i=t.clientY;this.startFrameLeft=this.startFrameLeft||N.util.getAbsoluteLeft(this.frame.canvas),this.startFrameTop=this.startFrameTop||N.util.getAbsoluteTop(this.frame.canvas);var s=e-this.startFrameLeft,o=i-this.startFrameTop;this.popupNode&&this._checkHidePopup(s,o);var n=this,r=function(){n._checkShowPopup(s,o)};this.popupTimer&&clearInterval(this.popupTimer),this.leftButtonDown||(this.popupTimer=setTimeout(r,300))},S.prototype._checkShowPopup=function(t,e){var i,s,o={left:this._xToCanvas(t),top:this._yToCanvas(e),right:this._xToCanvas(t),bottom:this._yToCanvas(e)},n=this.popupNode;if(void 0==this.popupNode){var r=this.nodes;for(i=r.length-1;i>=0;i--){var a=r[i];if(void 0!=a.getTitle()&&a.isOverlappingWith(o)){this.popupNode=a;break}}}if(void 0==this.popupNode){var h=this.edges;for(i=0,s=h.length;s>i;i++){var d=h[i];if(void 0!=d.getTitle()&&d.isOverlappingWith(o)){this.popupNode=d;break}}}if(this.popupNode){if(this.popupNode!=n){var l=this;l.popup||(l.popup=new M(l.frame)),l.popup.setPosition(t-3,e-3),l.popup.setText(l.popupNode.getTitle()),l.popup.show()}}else this.popup&&this.popup.hide()},S.prototype._checkHidePopup=function(t,e){var i={left:t,top:e,right:t,bottom:e};this.popupNode&&this.popupNode.isOverlappingWith(i)||(this.popupNode=void 0,this.popup&&this.popup.hide())},S.prototype._onTouchStart=function(t){if(N.util.preventDefault(t),!this.touchDown){this.touchDown=!0;var e=this;this.ontouchmove||(this.ontouchmove=function(t){e._onTouchMove(t)},N.util.addEventListener(document,"touchmove",this.ontouchmove)),this.ontouchend||(this.ontouchend=function(t){e._onTouchEnd(t)},N.util.addEventListener(document,"touchend",this.ontouchend)),this._onMouseDown(t)}},S.prototype._onTouchMove=function(t){N.util.preventDefault(t),this._onMouseMove(t)},S.prototype._onTouchEnd=function(t){N.util.preventDefault(t),this.touchDown=!1,this.ontouchmove&&(N.util.removeEventListener(document,"touchmove",this.ontouchmove),this.ontouchmove=void 0),this.ontouchend&&(N.util.removeEventListener(document,"touchend",this.ontouchend),this.ontouchend=void 0),this._onMouseUp(t)},S.prototype._unselectNodes=function(t,e){var i,s,o,n=!1;if(t)for(i=0,s=t.length;s>i;i++){o=t[i].row,this.nodes[o].unselect();for(var r=0;this.selection.length>r;)this.selection[r].row==o?(this.selection.splice(r,1),n=!0):r++}else if(this.selection&&this.selection.length){for(i=0,s=this.selection.length;s>i;i++)o=this.selection[i].row,this.nodes[o].unselect(),n=!0;this.selection=[]}return!n||1!=e&&void 0!=e||this._trigger("select"),n},S.prototype._selectNodes=function(t,e){var i,s,o=!1,n=!0;if(t.length!=this.selection.length)n=!1;else for(i=0,s=Math.min(t.length,this.selection.length);s>i;i++)if(t[i].row!=this.selection[i].row){n=!1;break}if(n)return o;if(void 0==e||0==e){var r=!1;o=this._unselectNodes(void 0,r)}for(i=0,s=t.length;s>i;i++){for(var a=t[i].row,h=!1,d=0,l=this.selection.length;l>d;d++)if(this.selection[d].row==a){h=!0;break}h||(this.nodes[a].select(),this.selection.push(t[i]),o=!0)}return o&&this._trigger("select"),o},S.prototype._getNodesOverlappingWith=function(t){for(var e=[],i=0;this.nodes.length>i;i++)if(this.nodes[i].isOverlappingWith(t)){var s={row:i};e.push(s)}return e},S.prototype.getSelection=function(){for(var t=[],e=0;this.selection.length>e;e++){var i=this.selection[e].row;t.push({row:i})}return t},S.prototype.setSelection=function(t){var e,i,s;if(void 0==t.length)throw"Selection must be an array with objects";for(e=0,i=this.selection.length;i>e;e++)s=this.selection[e].row,this.nodes[s].unselect();for(this.selection=[],e=0,i=t.length;i>e;e++){if(s=t[e].row,void 0==s)throw"Parameter row missing in selection object";if(s>this.nodes.length-1)throw"Parameter row out of range";var o={row:s};this.selection.push(o),this.nodes[s].select()}this.redraw()},S.prototype._getConnectionCount=function(t){function e(t){for(var e=[],s=0,o=t.length;o>s;s++)for(var n=t[s],r=0,a=i.length;a>r;r++){var h=null;i[r].from==n?h=i[r].to:i[r].to==n&&(h=i[r].from);var d,l;if(h)for(d=0,l=t.length;l>d;d++)if(t[d]==h){h=null;break}if(h)for(d=0,l=e.length;l>d;d++)if(e[d]==h){h=null;break}h&&e.push(h)}return e}var i=this.edges;void 0==t&&(t=1);var s,o,n=[],r=this.nodes;for(s=0,o=r.length;o>s;s++){for(var a=[r[s]],h=0;t>h;h++)a=a.concat(e(a));n.push(a)}var d=[];for(s=0,len=n.length;len>s;s++)d.push(n[s].length);return d},S.prototype.setSize=function(t,e){this.frame.style.width=t,this.frame.style.height=e,this.frame.canvas.style.width="100%",this.frame.canvas.style.height="100%",this.frame.canvas.width=this.frame.canvas.clientWidth,this.frame.canvas.height=this.frame.canvas.clientHeight},S.prototype._setNodes=function(t){if(this.selection=[],this.nodes=[],this.moving=!1,t){for(var e=!1,i=t.length,s=0;i>s;s++){var o=t[s];if(void 0!=o.value&&(e=!0),void 0==o.id)throw"Column 'id' missing in table with nodes (row "+s+")";this._createNode(o)}e&&this._updateValueRange(this.nodes),this._reposition()}},S.prototype._createNode=function(t){var e,i,s,o,n=t.action?t.action:"update";if("create"===n)s=new x(t,this.images,this.groups,this.constants),e=t.id,i=void 0!==e?this._findNode(e):void 0,void 0!==i?(o=this.nodes[i],this.nodes[i]=s,o.selected&&this._unselectNodes([{row:i}],!1)):this.nodes.push(s),s.isFixed()||(this.moving=!0);else if("update"===n){if(e=t.id,void 0===e)throw"Cannot update a node without id";i=this._findNode(e),void 0!==i?this.nodes[i].setProperties(t,this.constants):(s=new x(t,this.images,this.groups,this.constants),this.nodes.push(s),s.isFixed()||(this.moving=!0))}else{if("delete"!==n)throw"Unknown action "+n+". Choose 'create', 'update', or 'delete'.";if(e=t.id,void 0===e)throw"Cannot delete node without its id";if(i=this._findNode(e),void 0===i)throw"Node with id "+e+" not found";o=this.nodes[i],o.selected&&this._unselectNodes([{row:i}],!1),this.nodes.splice(i,1)}},S.prototype._findNode=function(t){for(var e=this.nodes,i=0,s=e.length;s>i;i++)if(e[i].id===t)return i;return void 0},S.prototype._findNodeByRow=function(t){return this.nodes[t]},S.prototype._setEdges=function(t){if(this.edges=[],t){for(var e=!1,i=t.length,s=0;i>s;s++){var o=t[s];if(void 0===o.from)throw"Column 'from' missing in table with edges (row "+s+")";if(void 0===o.to)throw"Column 'to' missing in table with edges (row "+s+")";void 0!=o.value&&(e=!0),this._createEdge(o)}e&&this._updateValueRange(this.edges)}},S.prototype._createEdge=function(t){var e,i,s,o,n=t.action?t.action:"create";if("create"===n)e=t.id,i=void 0!==e?this._findEdge(e):void 0,s=new T(t,this,this.constants),void 0!==i?(o=this.edges[i],o.from.detachEdge(o),o.to.detachEdge(o),this.edges[i]=s):this.edges.push(s),s.from.attachEdge(s),s.to.attachEdge(s);else if("update"===n){if(e=t.id,void 0===e)throw"Cannot update a edge without id";i=this._findEdge(e),void 0!==i?(s=this.edges[i],s.from.detachEdge(s),s.to.detachEdge(s),s.setProperties(t,this.constants),s.from.attachEdge(s),s.to.attachEdge(s)):(s=new T(t,this,this.constants),s.from.attachEdge(s),s.to.attachEdge(s),this.edges.push(s))}else{if("delete"!==n)throw"Unknown action "+n+". Choose 'create', 'update', or 'delete'.";if(e=t.id,void 0===e)throw"Cannot delete edge without its id";if(i=this._findEdge(e),void 0===i)throw"Edge with id "+e+" not found";o=this.edges[e],s.from.detachEdge(o),s.to.detachEdge(o),this.edges.splice(i,1)}},S.prototype._updateNodeReferences=function(t,e){for(var i=this.edges,s=0,o=i.length;o>s;s++){var n=i[s];n.from===t&&(n.from=e),n.to===t&&(n.to=e)}},S.prototype._findEdge=function(t){for(var e=this.edges,i=0,s=e.length;s>i;i++)if(e[i].id===t)return i;return void 0},S.prototype._findEdgeByRow=function(t){return this.edges[t]},S.prototype._updateValueRange=function(t){var e,i=t.length,s=void 0,o=void 0;for(e=0;i>e;e++){var n=t[e].getValue();void 0!==n&&(s=void 0===s?n:Math.min(n,s),o=void 0===o?n:Math.max(n,o))}if(void 0!==s&&void 0!==o)for(e=0;i>e;e++)t[e].setValueRange(s,o)},S.prototype.redraw=function(){this.setSize(this.width,this.height),this._redraw()},S.prototype._redraw=function(){var t=this.frame.canvas.getContext("2d"),e=this.frame.canvas.width,i=this.frame.canvas.height;t.clearRect(0,0,e,i),t.save(),t.translate(this.translation.x,this.translation.y),t.scale(this.scale,this.scale),this._drawEdges(t),this._drawNodes(t),t.restore()},S.prototype._setTranslation=function(t,e){void 0===this.translation&&(this.translation={x:0,y:0}),void 0!==t&&(this.translation.x=t),void 0!==e&&(this.translation.y=e)},S.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},S.prototype._setScale=function(t){this.scale=t},S.prototype._getScale=function(){return this.scale},S.prototype._xToCanvas=function(t){return(t-this.translation.x)/this.scale},S.prototype._canvasToX=function(t){return t*this.scale+this.translation.x},S.prototype._yToCanvas=function(t){return(t-this.translation.y)/this.scale},S.prototype._canvasToY=function(t){return t*this.scale+this.translation.y},S.prototype._getNode=function(t){for(var e=0;this.nodes.length>e;e++)if(this.nodes[e].id==t)return this.nodes[e];return null},S.prototype._drawNodes=function(t){for(var e=this.nodes,i=[],s=0,o=e.length;o>s;s++)e[s].isSelected()?i.push(s):e[s].draw(t);for(var n=0,r=i.length;r>n;n++)e[i[n]].draw(t)},S.prototype._drawEdges=function(t){for(var e=this.edges,i=0,s=e.length;s>i;i++)e[i].draw(t)},S.prototype._reposition=function(){for(var t=2*this.constants.edges.length,e=this.frame.canvas.clientWidth/2,i=this.frame.canvas.clientHeight/2,s=0;this.nodes.length>s;s++){var o=2*Math.PI*(s/this.nodes.length);this.nodes[s].xFixed||(this.nodes[s].x=e+t*Math.cos(o)),this.nodes[s].yFixed||(this.nodes[s].y=i+t*Math.sin(o))}},S.prototype._doStabilize=function(){new Date;for(var t=0,e=this.constants.minVelocity,i=!1;!i&&this.constants.maxIterations>t;)this._calculateForces(),this._discreteStepNodes(),i=!this._isMoving(e),t++;new Date},S.prototype._calculateForces=function(){for(var t=this.nodes,e=this.edges,i=.01,s=this.frame.canvas.clientWidth/2,o=this.frame.canvas.clientHeight/2,n=0;t.length>n;n++){var r=s-t[n].x,a=o-t[n].y,h=Math.atan2(a,r),d=Math.cos(h)*i,l=Math.sin(h)*i;this.nodes[n]._setForce(d,l)}for(var p=this.constants.nodes.distance,u=10,n=0;t.length>n;n++)for(var c=n+1;this.nodes.length>c;c++){var r=t[c].x-t[n].x,a=t[c].y-t[n].y,f=Math.sqrt(r*r+a*a),h=Math.atan2(a,r),m=1/(1+Math.exp((f/p-1)*u)),d=Math.cos(h)*m,l=Math.sin(h)*m;this.nodes[n]._addForce(-d,-l),this.nodes[c]._addForce(d,l)}for(var g=0,v=e.length;v>g;g++){var y=e[g],r=y.to.x-y.from.x,a=y.to.y-y.from.y,w=y.length,b=Math.sqrt(r*r+a*a),h=Math.atan2(a,r),_=y.stiffness*(w-b),d=Math.cos(h)*_,l=Math.sin(h)*_;y.from._addForce(-d,-l),y.to._addForce(d,l)}},S.prototype._isMoving=function(t){for(var e=this.nodes,i=0,s=e.length;s>i;i++)if(e[i].isMoving(t))return!0;return!1},S.prototype._discreteStepNodes=function(){for(var t=this.refreshRate/1e3,e=this.nodes,i=0,s=e.length;s>i;i++)e[i].discreteStep(t)},S.prototype.start=function(){if(this.moving){this._calculateForces(),this._discreteStepNodes();var t=this.constants.minVelocity;this.moving=this._isMoving(t)}if(this.moving){if(!this.timer){var e=this;this.timer=window.setTimeout(function(){e.timer=void 0,e.start(),e._redraw()},this.refreshRate)}}else this._redraw()},S.prototype.stop=function(){this.timer&&(window.clearInterval(this.timer),this.timer=void 0)};var N={util:C,events:O,Controller:d,DataSet:n,DataView:r,Range:h,Stack:a,TimeStep:TimeStep,EventBus:o,components:{items:{Item:m,ItemBox:g,ItemPoint:v,ItemRange:y},Component:l,Panel:p,RootPanel:u,ItemSet:f,TimeAxis:c},graph:{Node:x,Edge:T,Popup:M,Groups:Groups,Images:Images},Timeline:_,Graph:S};s!==void 0&&(s=N),i!==void 0&&i.exports!==void 0&&(i.exports=N),"function"==typeof t&&t(function(){return N}),"undefined"!=typeof window&&(window.vis=N),C.loadCss("/* vis.js stylesheet */\n\n.graph {\n position: relative;\n border: 1px solid #bfbfbf;\n}\n\n.graph .panel {\n position: absolute;\n}\n\n.graph .groupset {\n position: absolute;\n padding: 0;\n margin: 0;\n}\n\n\n.graph .itemset {\n position: absolute;\n padding: 0;\n margin: 0;\n overflow: hidden;\n}\n\n.graph .background {\n}\n\n.graph .foreground {\n}\n\n.graph .itemset-axis {\n position: absolute;\n}\n\n.graph .groupset .itemset-axis {\n border-top: 1px solid #bfbfbf;\n}\n\n/* TODO: with orientation=='bottom', this will more or less overlap with timeline axis\n.graph .groupset .itemset-axis:last-child {\n border-top: none;\n}\n*/\n\n\n.graph .item {\n position: absolute;\n color: #1A1A1A;\n border-color: #97B0F8;\n background-color: #D5DDF6;\n display: inline-block;\n}\n\n.graph .item.selected {\n border-color: #FFC200;\n background-color: #FFF785;\n z-index: 999;\n}\n\n.graph .item.cluster {\n /* TODO: use another color or pattern? */\n background: #97B0F8 url('img/cluster_bg.png');\n color: white;\n}\n.graph .item.cluster.point {\n border-color: #D5DDF6;\n}\n\n.graph .item.box {\n text-align: center;\n border-style: solid;\n border-width: 1px;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.graph .item.point {\n background: none;\n}\n\n.graph .dot {\n border: 5px solid #97B0F8;\n position: absolute;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.graph .item.range {\n overflow: hidden;\n border-style: solid;\n border-width: 1px;\n border-radius: 2px;\n -moz-border-radius: 2px; /* For Firefox 3.6 and older */\n}\n\n.graph .item.range .drag-left {\n cursor: w-resize;\n z-index: 1000;\n}\n\n.graph .item.range .drag-right {\n cursor: e-resize;\n z-index: 1000;\n}\n\n.graph .item.range .content {\n position: relative;\n display: inline-block;\n}\n\n.graph .item.line {\n position: absolute;\n width: 0;\n border-left-width: 1px;\n border-left-style: solid;\n}\n\n.graph .item .content {\n margin: 5px;\n white-space: nowrap;\n overflow: hidden;\n}\n\n/* TODO: better css name, 'graph' is way to generic */\n\n.graph {\n overflow: hidden;\n}\n\n.graph .axis {\n position: relative;\n}\n\n.graph .axis .text {\n position: absolute;\n color: #4d4d4d;\n padding: 3px;\n white-space: nowrap;\n}\n\n.graph .axis .text.measure {\n position: absolute;\n padding-left: 0;\n padding-right: 0;\n margin-left: 0;\n margin-right: 0;\n visibility: hidden;\n}\n\n.graph .axis .grid.vertical {\n position: absolute;\n width: 0;\n border-right: 1px solid;\n}\n\n.graph .axis .grid.horizontal {\n position: absolute;\n left: 0;\n width: 100%;\n height: 0;\n border-bottom: 1px solid;\n}\n\n.graph .axis .grid.minor {\n border-color: #e5e5e5;\n}\n\n.graph .axis .grid.major {\n border-color: #bfbfbf;\n}\n\n")})()},{moment:2}],2:[function(e,i){(function(){(function(s){function o(t,e){return function(i){return p(t.call(this,i),e)}}function n(t){return function(e){return this.lang().ordinal(t.call(this,e))}}function r(){}function a(t){d(this,t)}function h(t){var e=this._data={},i=t.years||t.year||t.y||0,s=t.months||t.month||t.M||0,o=t.weeks||t.week||t.w||0,n=t.days||t.day||t.d||0,r=t.hours||t.hour||t.h||0,a=t.minutes||t.minute||t.m||0,h=t.seconds||t.second||t.s||0,d=t.milliseconds||t.millisecond||t.ms||0;this._milliseconds=d+1e3*h+6e4*a+36e5*r,this._days=n+7*o,this._months=s+12*i,e.milliseconds=d%1e3,h+=l(d/1e3),e.seconds=h%60,a+=l(h/60),e.minutes=a%60,r+=l(a/60),e.hours=r%24,n+=l(r/24),n+=7*o,e.days=n%30,s+=l(n/30),e.months=s%12,i+=l(s/12),e.years=i}function d(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function l(t){return 0>t?Math.ceil(t):Math.floor(t)}function p(t,e){for(var i=t+"";e>i.length;)i="0"+i;return i}function u(t,e,i){var s,o=e._milliseconds,n=e._days,r=e._months;o&&t._d.setTime(+t+o*i),n&&t.date(t.date()+n*i),r&&(s=t.date(),t.date(1).month(t.month()+r*i).date(Math.min(s,t.daysInMonth())))}function c(t){return"[object Array]"===Object.prototype.toString.call(t)}function f(t,e){var i,s=Math.min(t.length,e.length),o=Math.abs(t.length-e.length),n=0;for(i=0;s>i;i++)~~t[i]!==~~e[i]&&n++;return n+o}function m(t,e){return e.abbr=t,H[t]||(H[t]=new r),H[t].set(e),H[t]}function g(t){return t?(!H[t]&&P&&e("./lang/"+t),H[t]):F.fn._lang}function v(t){return t.match(/\[.*\]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function y(t){var e,i,s=t.match(j);for(e=0,i=s.length;i>e;e++)s[e]=ae[s[e]]?ae[s[e]]:v(s[e]);return function(o){var n="";for(e=0;i>e;e++)n+="function"==typeof s[e].call?s[e].call(o,t):s[e];return n}}function w(t,e){function i(e){return t.lang().longDateFormat(e)||e}for(var s=5;s--&&U.test(e);)e=e.replace(U,i);return oe[e]||(oe[e]=y(e)),oe[e](t)}function b(t){switch(t){case"DDDD":return q;case"YYYY":return V;case"YYYYY":return X;case"S":case"SS":case"SSS":case"DDD":return B;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":case"a":case"A":return K;case"X":return J;case"Z":case"ZZ":return G;case"T":return Z;case"MM":case"DD":case"YY":case"HH":case"hh":case"mm":case"ss":case"M":case"D":case"d":case"H":case"h":case"m":case"s":return W;default:return RegExp(t.replace("\\",""))}}function _(t,e,i){var s,o=i._a;switch(t){case"M":case"MM":o[1]=null==e?0:~~e-1;break;case"MMM":case"MMMM":s=g(i._l).monthsParse(e),null!=s?o[1]=s:i._isValid=!1;break;case"D":case"DD":case"DDD":case"DDDD":null!=e&&(o[2]=~~e);break;case"YY":o[0]=~~e+(~~e>68?1900:2e3);break;case"YYYY":case"YYYYY":o[0]=~~e;break;case"a":case"A":i._isPm="pm"===(e+"").toLowerCase();break;case"H":case"HH":case"h":case"hh":o[3]=~~e;break;case"m":case"mm":o[4]=~~e;break;case"s":case"ss":o[5]=~~e;break;case"S":case"SS":case"SSS":o[6]=~~(1e3*("0."+e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,s=(e+"").match(ee),s&&s[1]&&(i._tzh=~~s[1]),s&&s[2]&&(i._tzm=~~s[2]),s&&"+"===s[0]&&(i._tzh=-i._tzh,i._tzm=-i._tzm)}null==e&&(i._isValid=!1)}function x(t){var e,i,s=[];if(!t._d){for(e=0;7>e;e++)t._a[e]=s[e]=null==t._a[e]?2===e?1:0:t._a[e];s[3]+=t._tzh||0,s[4]+=t._tzm||0,i=new Date(0),t._useUTC?(i.setUTCFullYear(s[0],s[1],s[2]),i.setUTCHours(s[3],s[4],s[5],s[6])):(i.setFullYear(s[0],s[1],s[2]),i.setHours(s[3],s[4],s[5],s[6])),t._d=i}}function T(t){var e,i,s=t._f.match(j),o=t._i;for(t._a=[],e=0;s.length>e;e++)i=(b(s[e]).exec(o)||[])[0],i&&(o=o.slice(o.indexOf(i)+i.length)),ae[s[e]]&&_(s[e],i,t);t._isPm&&12>t._a[3]&&(t._a[3]+=12),t._isPm===!1&&12===t._a[3]&&(t._a[3]=0),x(t)}function M(t){for(var e,i,s,o,n=99;t._f.length;){if(e=d({},t),e._f=t._f.pop(),T(e),i=new a(e),i.isValid()){s=i;break}o=f(e._a,i.toArray()),n>o&&(n=o,s=i)}d(t,s)}function S(t){var e,i=t._i;if(Q.exec(i)){for(t._f="YYYY-MM-DDT",e=0;4>e;e++)if(te[e][1].exec(i)){t._f+=te[e][0];break}G.exec(i)&&(t._f+=" Z"),T(t)}else t._d=new Date(i)}function E(t){var e=t._i,i=R.exec(e);e===s?t._d=new Date:i?t._d=new Date(+i[1]):"string"==typeof e?S(t):c(e)?(t._a=e.slice(0),x(t)):t._d=e instanceof Date?new Date(+e):new Date(e)}function C(t,e,i,s,o){return o.relativeTime(e||1,!!i,t,s)}function D(t,e,i){var s=z(Math.abs(t)/1e3),o=z(s/60),n=z(o/60),r=z(n/24),a=z(r/365),h=45>s&&["s",s]||1===o&&["m"]||45>o&&["mm",o]||1===n&&["h"]||22>n&&["hh",n]||1===r&&["d"]||25>=r&&["dd",r]||45>=r&&["M"]||345>r&&["MM",z(r/30)]||1===a&&["y"]||["yy",a];return h[2]=e,h[3]=t>0,h[4]=i,C.apply({},h)}function L(t,e,i){var s=i-e,o=i-t.day();return o>s&&(o-=7),s-7>o&&(o+=7),Math.ceil(F(t).add("d",o).dayOfYear()/7)}function O(t){var e=t._i,i=t._f;return null===e||""===e?null:("string"==typeof e&&(t._i=e=g().preparse(e)),F.isMoment(e)?(t=d({},e),t._d=new Date(+e._d)):i?c(i)?M(t):T(t):E(t),new a(t))}function N(t,e){F.fn[t]=F.fn[t+"s"]=function(t){var i=this._isUTC?"UTC":"";return null!=t?(this._d["set"+i+e](t),this):this._d["get"+i+e]()}}function k(t){F.duration.fn[t]=function(){return this._data[t]}}function A(t,e){F.duration.fn["as"+t]=function(){return+this/e}}for(var F,I,Y="2.0.0",z=Math.round,H={},P=i!==s&&i.exports,R=/^\/?Date\((\-?\d+)/i,j=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYY|YYYY|YY|a|A|hh?|HH?|mm?|ss?|SS?S?|X|zz?|ZZ?|.)/g,U=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,W=/\d\d?/,B=/\d{1,3}/,q=/\d{3}/,V=/\d{1,4}/,X=/[+\-]?\d{1,6}/,K=/[0-9]*[a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF]+\s*?[\u0600-\u06FF]+/i,G=/Z|[\+\-]\d\d:?\d\d/i,Z=/T/i,J=/[\+\-]?\d+(\.\d{1,3})?/,Q=/^\s*\d{4}-\d\d-\d\d((T| )(\d\d(:\d\d(:\d\d(\.\d\d?\d?)?)?)?)?([\+\-]\d\d:?\d\d)?)?/,$="YYYY-MM-DDTHH:mm:ssZ",te=[["HH:mm:ss.S",/(T| )\d\d:\d\d:\d\d\.\d{1,3}/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],ee=/([\+\-]|\d\d)/gi,ie="Month|Date|Hours|Minutes|Seconds|Milliseconds".split("|"),se={Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6},oe={},ne="DDD w W M D d".split(" "),re="M D H h m s w W".split(" "),ae={M:function(){return this.month()+1},MMM:function(t){return this.lang().monthsShort(this,t)},MMMM:function(t){return this.lang().months(this,t)},D:function(){return this.date()},DDD:function(){return this.dayOfYear()},d:function(){return this.day()},dd:function(t){return this.lang().weekdaysMin(this,t)},ddd:function(t){return this.lang().weekdaysShort(this,t)},dddd:function(t){return this.lang().weekdays(this,t)},w:function(){return this.week()},W:function(){return this.isoWeek()},YY:function(){return p(this.year()%100,2)},YYYY:function(){return p(this.year(),4)},YYYYY:function(){return p(this.year(),5)},a:function(){return this.lang().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.lang().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return~~(this.milliseconds()/100)},SS:function(){return p(~~(this.milliseconds()/10),2)},SSS:function(){return p(this.milliseconds(),3)},Z:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(~~(t/60),2)+":"+p(~~t%60,2)},ZZ:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(~~(10*t/6),4)},X:function(){return this.unix()}};ne.length;)I=ne.pop(),ae[I+"o"]=n(ae[I]);for(;re.length;)I=re.pop(),ae[I+I]=o(ae[I],2);for(ae.DDDD=o(ae.DDD,3),r.prototype={set:function(t){var e,i;for(i in t)e=t[i],"function"==typeof e?this[i]=e:this["_"+i]=e},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(t){return this._months[t.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(t){return this._monthsShort[t.month()]},monthsParse:function(t){var e,i,s;for(this._monthsParse||(this._monthsParse=[]),e=0;12>e;e++)if(this._monthsParse[e]||(i=F([2e3,e]),s="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[e]=RegExp(s.replace(".",""),"i")),this._monthsParse[e].test(t))return e},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(t){return this._weekdays[t.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(t){return this._weekdaysShort[t.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(t){return this._weekdaysMin[t.day()]},_longDateFormat:{LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D YYYY",LLL:"MMMM D YYYY LT",LLLL:"dddd, MMMM D YYYY LT"},longDateFormat:function(t){var e=this._longDateFormat[t];return!e&&this._longDateFormat[t.toUpperCase()]&&(e=this._longDateFormat[t.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t]=e),e},meridiem:function(t,e,i){return t>11?i?"pm":"PM":i?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[last] dddd [at] LT",sameElse:"L"},calendar:function(t,e){var i=this._calendar[t];return"function"==typeof i?i.apply(e):i},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(t,e,i,s){var o=this._relativeTime[i];return"function"==typeof o?o(t,e,i,s):o.replace(/%d/i,t)},pastFuture:function(t,e){var i=this._relativeTime[t>0?"future":"past"];return"function"==typeof i?i(e):i.replace(/%s/i,e)},ordinal:function(t){return this._ordinal.replace("%d",t)},_ordinal:"%d",preparse:function(t){return t},postformat:function(t){return t},week:function(t){return L(t,this._week.dow,this._week.doy)},_week:{dow:0,doy:6}},F=function(t,e,i){return O({_i:t,_f:e,_l:i,_isUTC:!1})},F.utc=function(t,e,i){return O({_useUTC:!0,_isUTC:!0,_l:i,_i:t,_f:e})},F.unix=function(t){return F(1e3*t)},F.duration=function(t,e){var i,s=F.isDuration(t),o="number"==typeof t,n=s?t._data:o?{}:t;return o&&(e?n[e]=t:n.milliseconds=t),i=new h(n),s&&t.hasOwnProperty("_lang")&&(i._lang=t._lang),i},F.version=Y,F.defaultFormat=$,F.lang=function(t,e){return t?(e?m(t,e):H[t]||g(t),F.duration.fn._lang=F.fn._lang=g(t),s):F.fn._lang._abbr},F.langData=function(t){return t&&t._lang&&t._lang._abbr&&(t=t._lang._abbr),g(t)},F.isMoment=function(t){return t instanceof a},F.isDuration=function(t){return t instanceof h},F.fn=a.prototype={clone:function(){return F(this)},valueOf:function(){return+this._d},unix:function(){return Math.floor(+this._d/1e3)},toString:function(){return this.format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._d},toJSON:function(){return F.utc(this).format("YYYY-MM-DD[T]HH:mm:ss.SSS[Z]")},toArray:function(){var t=this;return[t.year(),t.month(),t.date(),t.hours(),t.minutes(),t.seconds(),t.milliseconds()]},isValid:function(){return null==this._isValid&&(this._isValid=this._a?!f(this._a,(this._isUTC?F.utc(this._a):F(this._a)).toArray()):!isNaN(this._d.getTime())),!!this._isValid},utc:function(){return this._isUTC=!0,this},local:function(){return this._isUTC=!1,this},format:function(t){var e=w(this,t||F.defaultFormat);return this.lang().postformat(e)},add:function(t,e){var i;return i="string"==typeof t?F.duration(+e,t):F.duration(t,e),u(this,i,1),this},subtract:function(t,e){var i;return i="string"==typeof t?F.duration(+e,t):F.duration(t,e),u(this,i,-1),this},diff:function(t,e,i){var s,o,n=this._isUTC?F(t).utc():F(t).local(),r=6e4*(this.zone()-n.zone());return e&&(e=e.replace(/s$/,"")),"year"===e||"month"===e?(s=432e5*(this.daysInMonth()+n.daysInMonth()),o=12*(this.year()-n.year())+(this.month()-n.month()),o+=(this-F(this).startOf("month")-(n-F(n).startOf("month")))/s,"year"===e&&(o/=12)):(s=this-n-r,o="second"===e?s/1e3:"minute"===e?s/6e4:"hour"===e?s/36e5:"day"===e?s/864e5:"week"===e?s/6048e5:s),i?o:l(o) -},from:function(t,e){return F.duration(this.diff(t)).lang(this.lang()._abbr).humanize(!e)},fromNow:function(t){return this.from(F(),t)},calendar:function(){var t=this.diff(F().startOf("day"),"days",!0),e=-6>t?"sameElse":-1>t?"lastWeek":0>t?"lastDay":1>t?"sameDay":2>t?"nextDay":7>t?"nextWeek":"sameElse";return this.format(this.lang().calendar(e,this))},isLeapYear:function(){var t=this.year();return 0===t%4&&0!==t%100||0===t%400},isDST:function(){return this.zone()+F(t).startOf(e)},isBefore:function(t,e){return e=e!==s?e:"millisecond",+this.clone().startOf(e)<+F(t).startOf(e)},isSame:function(t,e){return e=e!==s?e:"millisecond",+this.clone().startOf(e)===+F(t).startOf(e)},zone:function(){return this._isUTC?0:this._d.getTimezoneOffset()},daysInMonth:function(){return F.utc([this.year(),this.month()+1,0]).date()},dayOfYear:function(t){var e=z((F(this).startOf("day")-F(this).startOf("year"))/864e5)+1;return null==t?e:this.add("d",t-e)},isoWeek:function(t){var e=L(this,1,4);return null==t?e:this.add("d",7*(t-e))},week:function(t){var e=this.lang().week(this);return null==t?e:this.add("d",7*(t-e))},lang:function(t){return t===s?this._lang:(this._lang=g(t),this)}},I=0;ie.length>I;I++)N(ie[I].toLowerCase().replace(/s$/,""),ie[I]);N("year","FullYear"),F.fn.days=F.fn.day,F.fn.weeks=F.fn.week,F.fn.isoWeeks=F.fn.isoWeek,F.duration.fn=h.prototype={weeks:function(){return l(this.days()/7)},valueOf:function(){return this._milliseconds+864e5*this._days+2592e6*this._months},humanize:function(t){var e=+this,i=D(e,!t,this.lang());return t&&(i=this.lang().pastFuture(e,i)),this.lang().postformat(i)},lang:F.fn.lang};for(I in se)se.hasOwnProperty(I)&&(A(I,se[I]),k(I.toLowerCase()));A("Weeks",6048e5),F.lang("en",{ordinal:function(t){var e=t%10,i=1===~~(t%100/10)?"th":1===e?"st":2===e?"nd":3===e?"rd":"th";return t+i}}),P&&(i.exports=F),"undefined"==typeof ender&&(this.moment=F),"function"==typeof t&&t.amd&&t("moment",[],function(){return F})}).call(this)})()},{}]},{},[1])(1)}); \ No newline at end of file +(function(t){if("function"==typeof bootstrap)bootstrap("vis",t);else if("object"==typeof exports)module.exports=t();else if("function"==typeof define&&define.amd)define(t);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeVis=t}else"undefined"!=typeof window?window.vis=t():global.vis=t()})(function(){var t;return function(t,e,i){function s(i,o){if(!e[i]){if(!t[i]){var r="function"==typeof require&&require;if(!o&&r)return r(i,!0);if(n)return n(i,!0);throw Error("Cannot find module '"+i+"'")}var a=e[i]={exports:{}};t[i][0].call(a.exports,function(e){var n=t[i][1][e];return s(n?n:e)},a,a.exports)}return e[i].exports}for(var n="function"==typeof require&&require,o=0;i.length>o;o++)s(i[o]);return s}({1:[function(e,i,s){(function(){function n(){this.subscriptions=[]}function o(t){if(this.id=D.randomUUID(),this.options=t||{},this.data={},this.fieldId=this.options.fieldId||"id",this.convert={},this.options.convert)for(var e in this.options.convert)if(this.options.convert.hasOwnProperty(e)){var i=this.options.convert[e];this.convert[e]="Date"==i||"ISODate"==i||"ASPDate"==i?"Date":i}this.subscribers={},this.internalIds={}}function r(t,e){this.id=D.randomUUID(),this.data=null,this.ids={},this.options=e||{},this.fieldId="id",this.subscribers={};var i=this;this.listener=function(){i._onEvent.apply(i,arguments)},this.setData(t)}function a(t,e){this.parent=t,this.options=e||{},this.defaultOptions={order:function(t,e){if(t instanceof y){if(e instanceof y){var i=t.data.end-t.data.start,s=e.data.end-e.data.start;return i-s||t.data.start-e.data.start}return-1}return e instanceof y?1:t.data.start-e.data.start},margin:{item:10}},this.ordered=[]}function h(t){this.id=D.randomUUID(),this.start=0,this.end=0,this.options={min:null,max:null,zoomMin:null,zoomMax:null},this.listeners=[],this.setOptions(t)}function d(){this.id=D.randomUUID(),this.components={},this.repaintTimer=void 0,this.reflowTimer=void 0}function l(){this.id=null,this.parent=null,this.depends=null,this.controller=null,this.options=null,this.frame=null,this.top=0,this.left=0,this.width=0,this.height=0}function p(t,e,i){this.id=D.randomUUID(),this.parent=t,this.depends=e,this.options=i||{}}function c(t,e){this.id=D.randomUUID(),this.container=t,this.options=e||{},this.defaultOptions={autoResize:!0},this.listeners={}}function u(t,e,i){this.id=D.randomUUID(),this.parent=t,this.depends=e,this.dom={majorLines:[],majorTexts:[],minorLines:[],minorTexts:[],redundant:{majorLines:[],majorTexts:[],minorLines:[],minorTexts:[]}},this.props={range:{start:0,end:0,minimumStep:0},lineTop:0},this.options=i||{},this.defaultOptions={orientation:"bottom",showMinorLabels:!0,showMajorLabels:!0},this.conversion=null,this.range=null}function f(t,e,i){this.id=D.randomUUID(),this.parent=t,this.depends=e,this.options=i||{},this.defaultOptions={type:"box",align:"center",orientation:"bottom",margin:{axis:20,item:10},padding:5},this.dom={};var s=this;this.itemsData=null,this.range=null,this.listeners={add:function(t,e,i){i!=s.id&&s._onAdd(e.items)},update:function(t,e,i){i!=s.id&&s._onUpdate(e.items)},remove:function(t,e,i){i!=s.id&&s._onRemove(e.items)}},this.items={},this.queue={},this.stack=new a(this,Object.create(this.options)),this.conversion=null}function m(t,e,i,s){this.parent=t,this.data=e,this.dom=null,this.options=i||{},this.defaultOptions=s||{},this.selected=!1,this.visible=!1,this.top=0,this.left=0,this.width=0,this.height=0}function g(t,e,i,s){this.props={dot:{left:0,top:0,width:0,height:0},line:{top:0,left:0,width:0,height:0}},m.call(this,t,e,i,s)}function v(t,e,i,s){this.props={dot:{top:0,width:0,height:0},content:{height:0,marginLeft:0}},m.call(this,t,e,i,s)}function y(t,e,i,s){this.props={content:{left:0,width:0}},m.call(this,t,e,i,s)}function b(t,e,i){this.id=D.randomUUID(),this.parent=t,this.groupId=e,this.itemsData=null,this.itemset=null,this.options=i||{},this.options.top=0,this.props={label:{width:0,height:0}},this.top=0,this.left=0,this.width=0,this.height=0}function w(t,e,i){this.id=D.randomUUID(),this.parent=t,this.depends=e,this.options=i||{},this.range=null,this.itemsData=null,this.groupsData=null,this.groups={},this.dom={},this.props={labels:{width:0}},this.queue={};var s=this;this.listeners={add:function(t,e){s._onAdd(e.items)},update:function(t,e){s._onUpdate(e.items)},remove:function(t,e){s._onRemove(e.items)}}}function _(t,e,i){var s=this;if(this.options=D.extend({orientation:"bottom",min:null,max:null,zoomMin:10,zoomMax:31536e10,showMinorLabels:!0,showMajorLabels:!0,autoResize:!1},i),this.controller=new d,!t)throw Error("No container element provided");var n=Object.create(this.options);n.height=function(){return s.options.height?s.options.height:s.timeaxis.height+s.content.height},this.rootPanel=new c(t,n),this.controller.add(this.rootPanel);var o=Object.create(this.options);o.left=function(){return s.labelPanel.width},o.width=function(){return s.rootPanel.width-s.labelPanel.width},o.top=null,o.height=null,this.itemPanel=new p(this.rootPanel,[],o),this.controller.add(this.itemPanel);var r=Object.create(this.options);r.top=null,r.left=null,r.height=null,r.width=function(){return s.content&&"function"==typeof s.content.getLabelsWidth?s.content.getLabelsWidth():0},this.labelPanel=new p(this.rootPanel,[],r),this.controller.add(this.labelPanel);var a=E().hours(0).minutes(0).seconds(0).milliseconds(0);this.range=new h({start:a.clone().add("days",-3).valueOf(),end:a.clone().add("days",4).valueOf()}),this.range.subscribe(this.rootPanel,"move","horizontal"),this.range.subscribe(this.rootPanel,"zoom","horizontal"),this.range.on("rangechange",function(){var t=!0;s.controller.requestReflow(t)}),this.range.on("rangechanged",function(){var t=!0;s.controller.requestReflow(t)});var l=Object.create(n);l.range=this.range,l.left=null,l.top=null,l.width="100%",l.height=null,this.timeaxis=new u(this.itemPanel,[],l),this.timeaxis.setRange(this.range),this.controller.add(this.timeaxis),this.setGroups(null),this.itemsData=null,this.groupsData=null,e&&this.setItems(e)}function x(t,e,i,s){this.selected=!1,this.edges=[],this.group=s.nodes.group,this.fontSize=s.nodes.fontSize,this.fontFace=s.nodes.fontFace,this.fontColor=s.nodes.fontColor,this.color=s.nodes.color,this.id=void 0,this.shape=s.nodes.shape,this.image=s.nodes.image,this.x=0,this.y=0,this.xFixed=!1,this.yFixed=!1,this.radius=s.nodes.radius,this.radiusFixed=!1,this.radiusMin=s.nodes.radiusMin,this.radiusMax=s.nodes.radiusMax,this.imagelist=e,this.grouplist=i,this.setProperties(t,s),this.mass=50,this.fx=0,this.fy=0,this.vx=0,this.vy=0,this.minForce=s.minForce,this.damping=.9}function T(t,e,i){if(!e)throw"No graph provided";this.graph=e,this.widthMin=i.edges.widthMin,this.widthMax=i.edges.widthMax,this.id=void 0,this.fromId=void 0,this.toId=void 0,this.style=i.edges.style,this.title=void 0,this.width=i.edges.width,this.value=void 0,this.length=i.edges.length,this.from=null,this.to=null,this.connected=!1,this.dash=D.extend({},i.edges.dash),this.stiffness=void 0,this.color=i.edges.color,this.widthFixed=!1,this.lengthFixed=!1,this.setProperties(t,i)}function S(t,e,i,s){this.container=t?t:document.body,this.x=0,this.y=0,this.padding=5,void 0!==e&&void 0!==i&&this.setPosition(e,i),void 0!==s&&this.setText(s),this.frame=document.createElement("div");var n=this.frame.style;n.position="absolute",n.visibility="hidden",n.border="1px solid #666",n.color="black",n.padding=this.padding+"px",n.backgroundColor="#FFFFC6",n.borderRadius="3px",n.MozBorderRadius="3px",n.WebkitBorderRadius="3px",n.boxShadow="3px 3px 10px rgba(128, 128, 128, 0.5)",n.whiteSpace="nowrap",this.container.appendChild(this.frame)}function M(t,e,i){this.containerElement=t,this.width="100%",this.height="100%",this.refreshRate=50,this.stabilize=!0,this.selectable=!0,this.constants={nodes:{radiusMin:5,radiusMax:20,radius:5,distance:100,shape:"ellipse",image:void 0,widthMin:16,widthMax:64,fontColor:"black",fontSize:14,fontFace:"arial",color:{border:"#2B7CE9",background:"#97C2FC",highlight:{border:"#2B7CE9",background:"#D2E5FF"}},borderColor:"#2B7CE9",backgroundColor:"#97C2FC",highlightColor:"#D2E5FF",group:void 0},edges:{widthMin:1,widthMax:15,width:1,style:"line",color:"#343434",fontColor:"#343434",fontSize:14,fontFace:"arial",length:100,dash:{length:10,gap:5,altLength:void 0}},minForce:.05,minVelocity:.02,maxIterations:1e3};var s=this;this.nodes={},this.edges={},this.nodesData=null,this.edgesData=null;var n=this;this.nodesListeners={add:function(t,e){n._addNodes(e.items),n.start()},update:function(t,e){n._updateNodes(e.items),n.start()},remove:function(t,e){n._removeNodes(e.items),n.start()}},this.edgesListeners={add:function(t,e){n._addEdges(e.items),n.start()},update:function(t,e){n._updateEdges(e.items),n.start()},remove:function(t,e){n._removeEdges(e.items),n.start()}},this.groups=new Groups,this.images=new Images,this.images.setOnloadCallback(function(){s._redraw()}),this.moving=!1,this.selection=[],this.timer=void 0,this._create(),this.setOptions(i),this.setData(e)}var E=e("moment"),D={};D.isNumber=function(t){return t instanceof Number||"number"==typeof t},D.isString=function(t){return t instanceof String||"string"==typeof t},D.isDate=function(t){if(t instanceof Date)return!0;if(D.isString(t)){var e=C.exec(t);if(e)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},D.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},D.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},D.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var s=arguments[e];for(var n in s)s.hasOwnProperty(n)&&void 0!==s[n]&&(t[n]=s[n])}return t},D.convert=function(t,e){var i;if(void 0===t)return void 0;if(null===t)return null;if(!e)return t;if("string"!=typeof e&&!(e instanceof String))throw Error("Type must be a string");switch(e){case"boolean":case"Boolean":return Boolean(t);case"number":case"Number":return Number(t.valueOf());case"string":case"String":return t+"";case"Date":if(D.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(E.isMoment(t))return new Date(t.valueOf());if(D.isString(t))return i=C.exec(t),i?new Date(Number(i[1])):E(t).toDate();throw Error("Cannot convert object of type "+D.getType(t)+" to type Date");case"Moment":if(D.isNumber(t))return E(t);if(t instanceof Date)return E(t.valueOf());if(E.isMoment(t))return E.clone();if(D.isString(t))return i=C.exec(t),i?E(Number(i[1])):E(t);throw Error("Cannot convert object of type "+D.getType(t)+" to type Date");case"ISODate":if(D.isNumber(t))return new Date(t);if(t instanceof Date)return t.toISOString();if(E.isMoment(t))return t.toDate().toISOString();if(D.isString(t))return i=C.exec(t),i?new Date(Number(i[1])).toISOString():new Date(t).toISOString();throw Error("Cannot convert object of type "+D.getType(t)+" to type ISODate");case"ASPDate":if(D.isNumber(t))return"/Date("+t+")/";if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(D.isString(t)){i=C.exec(t);var s;return s=i?new Date(Number(i[1])).valueOf():new Date(t).valueOf(),"/Date("+s+")/"}throw Error("Cannot convert object of type "+D.getType(t)+" to type ASPDate");default:throw Error("Cannot convert object of type "+D.getType(t)+' to type "'+e+'"')}};var C=/^\/?Date\((\-?\d+)/i;if(D.getType=function(t){var e=typeof t;return"object"==e?null==t?"null":t instanceof Boolean?"Boolean":t instanceof Number?"Number":t instanceof String?"String":t instanceof Array?"Array":t instanceof Date?"Date":"Object":"number"==e?"Number":"boolean"==e?"Boolean":"string"==e?"String":e},D.getAbsoluteLeft=function(t){for(var e=document.documentElement,i=document.body,s=t.offsetLeft,n=t.offsetParent;null!=n&&n!=i&&n!=e;)s+=n.offsetLeft,s-=n.scrollLeft,n=n.offsetParent;return s},D.getAbsoluteTop=function(t){for(var e=document.documentElement,i=document.body,s=t.offsetTop,n=t.offsetParent;null!=n&&n!=i&&n!=e;)s+=n.offsetTop,s-=n.scrollTop,n=n.offsetParent;return s},D.getPageY=function(t){if("pageY"in t)return t.pageY;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientY:t.clientY;var i=document.documentElement,s=document.body;return e+(i&&i.scrollTop||s&&s.scrollTop||0)-(i&&i.clientTop||s&&s.clientTop||0)},D.getPageX=function(t){if("pageY"in t)return t.pageX;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientX:t.clientX;var i=document.documentElement,s=document.body;return e+(i&&i.scrollLeft||s&&s.scrollLeft||0)-(i&&i.clientLeft||s&&s.clientLeft||0)},D.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},D.removeClassName=function(t,e){var i=t.className.split(" "),s=i.indexOf(e);-1!=s&&(i.splice(s,1),t.className=i.join(" "))},D.forEach=function(t,e){var i,s;if(t instanceof Array)for(i=0,s=t.length;s>i;i++)e(t[i],i,t);else for(i in t)t.hasOwnProperty(i)&&e(t[i],i,t)},D.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},D.addEventListener=function(t,e,i,s){t.addEventListener?(void 0===s&&(s=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.addEventListener(e,i,s)):t.attachEvent("on"+e,i)},D.removeEventListener=function(t,e,i,s){t.removeEventListener?(void 0===s&&(s=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.removeEventListener(e,i,s)):t.detachEvent("on"+e,i)},D.getTarget=function(t){t||(t=window.event);var e;return t.target?e=t.target:t.srcElement&&(e=t.srcElement),void 0!=e.nodeType&&3==e.nodeType&&(e=e.parentNode),e},D.stopPropagation=function(t){t||(t=window.event),t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},D.preventDefault=function(t){t||(t=window.event),t.preventDefault?t.preventDefault():t.returnValue=!1},D.option={},D.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},D.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},D.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?t+"":e||null},D.option.asSize=function(t,e){return"function"==typeof t&&(t=t()),D.isString(t)?t:D.isNumber(t)?t+"px":e||null},D.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null},D.loadCss=function(t){if("undefined"!=typeof document){var e=document.createElement("style");e.type="text/css",e.styleSheet?e.styleSheet.cssText=t:e.appendChild(document.createTextNode(t)),document.getElementsByTagName("head")[0].appendChild(e)}},!Array.prototype.indexOf){Array.prototype.indexOf=function(t){for(var e=0;this.length>e;e++)if(this[e]==t)return e;return-1};try{console.log("Warning: Ancient browser detected. Please update your browser")}catch(L){}}Array.prototype.forEach||(Array.prototype.forEach=function(t,e){for(var i=0,s=this.length;s>i;++i)t.call(e||this,this[i],i,this)}),Array.prototype.map||(Array.prototype.map=function(t,e){var i,s,n;if(null==this)throw new TypeError(" this is null or not defined");var o=Object(this),r=o.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(e&&(i=e),s=Array(r),n=0;r>n;){var a,h;n in o&&(a=o[n],h=t.call(i,a,n,o),s[n]=h),n++}return s}),Array.prototype.filter||(Array.prototype.filter=function(t){"use strict";if(null==this)throw new TypeError;var e=Object(this),i=e.length>>>0;if("function"!=typeof t)throw new TypeError;for(var s=[],n=arguments[1],o=0;i>o;o++)if(o in e){var r=e[o];t.call(n,r,o,e)&&s.push(r)}return s}),Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,e=!{toString:null}.propertyIsEnumerable("toString"),i=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],s=i.length;return function(n){if("object"!=typeof n&&"function"!=typeof n||null===n)throw new TypeError("Object.keys called on non-object");var o=[];for(var r in n)t.call(n,r)&&o.push(r);if(e)for(var a=0;s>a;a++)t.call(n,i[a])&&o.push(i[a]);return o}}()),Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,s=function(){},n=function(){return i.apply(this instanceof s&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return s.prototype=this.prototype,n.prototype=new s,n}),Object.create||(Object.create=function(t){function e(){}if(arguments.length>1)throw Error("Object.create implementation only accepts the first parameter.");return e.prototype=t,new e});var O={listeners:[],indexOf:function(t){for(var e=this.listeners,i=0,s=this.listeners.length;s>i;i++){var n=e[i];if(n&&n.object==t)return i}return-1},addListener:function(t,e,i){var s=this.indexOf(t),n=this.listeners[s];n||(n={object:t,events:{}},this.listeners.push(n));var o=n.events[e];o||(o=[],n.events[e]=o),-1==o.indexOf(i)&&o.push(i)},removeListener:function(t,e,i){var s=this.indexOf(t),n=this.listeners[s];if(n){var o=n.events[e];o&&(s=o.indexOf(i),-1!=s&&o.splice(s,1),0==o.length&&delete n.events[e]);var r=0,a=n.events;for(var h in a)a.hasOwnProperty(h)&&r++;0==r&&delete this.listeners[s]}},removeAllListeners:function(){this.listeners=[]},trigger:function(t,e,i){var s=this.indexOf(t),n=this.listeners[s];if(n){var o=n.events[e];if(o)for(var r=0,a=o.length;a>r;r++)o[r](i)}}};n.prototype.on=function(t,e,i){var s=t instanceof RegExp?t:RegExp(t.replace("*","\\w+")),n={id:D.randomUUID(),event:t,regexp:s,callback:"function"==typeof e?e:null,target:i};return this.subscriptions.push(n),n.id},n.prototype.off=function(t){for(var e=0;this.subscriptions.length>e;){var i=this.subscriptions[e],s=!0;if(t instanceof Object)for(var n in t)t.hasOwnProperty(n)&&t[n]!==i[n]&&(s=!1);else s=i.id==t;s?this.subscriptions.splice(e,1):e++}},n.prototype.emit=function(t,e,i){for(var s=0;this.subscriptions.length>s;s++){var n=this.subscriptions[s];n.regexp.test(t)&&n.callback&&n.callback(t,e,i)}},o.prototype.subscribe=function(t,e){var i=this.subscribers[t];i||(i=[],this.subscribers[t]=i),i.push({callback:e})},o.prototype.unsubscribe=function(t,e){var i=this.subscribers[t];i&&(this.subscribers[t]=i.filter(function(t){return t.callback!=e}))},o.prototype._trigger=function(t,e,i){if("*"==t)throw Error("Cannot trigger event *");var s=[];t in this.subscribers&&(s=s.concat(this.subscribers[t])),"*"in this.subscribers&&(s=s.concat(this.subscribers["*"]));for(var n=0;s.length>n;n++){var o=s[n];o.callback&&o.callback(t,e,i||null)}},o.prototype.add=function(t,e){var i,s=[],n=this;if(t instanceof Array)for(var o=0,r=t.length;r>o;o++)i=n._addItem(t[o]),s.push(i);else if(D.isDataTable(t))for(var a=this._getColumnNames(t),h=0,d=t.getNumberOfRows();d>h;h++){for(var l={},p=0,c=a.length;c>p;p++){var u=a[p];l[u]=t.getValue(h,p)}i=n._addItem(l),s.push(i)}else{if(!(t instanceof Object))throw Error("Unknown dataType");i=n._addItem(t),s.push(i)}return s.length&&this._trigger("add",{items:s},e),s},o.prototype.update=function(t,e){var i=[],s=[],n=this,o=n.fieldId,r=function(t){var e=t[o];n.data[e]?(e=n._updateItem(t),s.push(e)):(e=n._addItem(t),i.push(e))};if(t instanceof Array)for(var a=0,h=t.length;h>a;a++)r(t[a]);else if(D.isDataTable(t))for(var d=this._getColumnNames(t),l=0,p=t.getNumberOfRows();p>l;l++){for(var c={},u=0,f=d.length;f>u;u++){var m=d[u];c[m]=t.getValue(l,u)}r(c)}else{if(!(t instanceof Object))throw Error("Unknown dataType");r(t)}return i.length&&this._trigger("add",{items:i},e),s.length&&this._trigger("update",{items:s},e),i.concat(s)},o.prototype.get=function(){var t,e,i,s,n=this,o=D.getType(arguments[0]);"String"==o||"Number"==o?(t=arguments[0],i=arguments[1],s=arguments[2]):"Array"==o?(e=arguments[0],i=arguments[1],s=arguments[2]):(i=arguments[0],s=arguments[1]);var r;if(i&&i.type){if(r="DataTable"==i.type?"DataTable":"Array",s&&r!=D.getType(s))throw Error('Type of parameter "data" ('+D.getType(s)+") "+"does not correspond with specified options.type ("+i.type+")");if("DataTable"==r&&!D.isDataTable(s))throw Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else r=s?"DataTable"==D.getType(s)?"DataTable":"Array":"Array";var a,h,d,l,p=i&&i.convert||this.options.convert,c=i&&i.filter,u=[];if(void 0!=t)a=n._getItem(t,p),c&&!c(a)&&(a=null);else if(void 0!=e)for(d=0,l=e.length;l>d;d++)a=n._getItem(e[d],p),(!c||c(a))&&u.push(a);else for(h in this.data)this.data.hasOwnProperty(h)&&(a=n._getItem(h,p),(!c||c(a))&&u.push(a));if(i&&i.order&&void 0==t&&this._sort(u,i.order),i&&i.fields){var f=i.fields;if(void 0!=t)a=this._filterFields(a,f);else for(d=0,l=u.length;l>d;d++)u[d]=this._filterFields(u[d],f)}if("DataTable"==r){var m=this._getColumnNames(s);if(void 0!=t)n._appendRow(s,m,a);else for(d=0,l=u.length;l>d;d++)n._appendRow(s,m,u[d]);return s}if(void 0!=t)return a;if(s){for(d=0,l=u.length;l>d;d++)s.push(u[d]);return s}return u},o.prototype.getIds=function(t){var e,i,s,n,o,r=this.data,a=t&&t.filter,h=t&&t.order,d=t&&t.convert||this.options.convert,l=[];if(a)if(h){o=[];for(s in r)r.hasOwnProperty(s)&&(n=this._getItem(s,d),a(n)&&o.push(n));for(this._sort(o,h),e=0,i=o.length;i>e;e++)l[e]=o[e][this.fieldId]}else for(s in r)r.hasOwnProperty(s)&&(n=this._getItem(s,d),a(n)&&l.push(n[this.fieldId]));else if(h){o=[];for(s in r)r.hasOwnProperty(s)&&o.push(r[s]);for(this._sort(o,h),e=0,i=o.length;i>e;e++)l[e]=o[e][this.fieldId]}else for(s in r)r.hasOwnProperty(s)&&(n=r[s],l.push(n[this.fieldId]));return l},o.prototype.forEach=function(t,e){var i,s,n=e&&e.filter,o=e&&e.convert||this.options.convert,r=this.data;if(e&&e.order)for(var a=this.get(e),h=0,d=a.length;d>h;h++)i=a[h],s=i[this.fieldId],t(i,s);else for(s in r)r.hasOwnProperty(s)&&(i=this._getItem(s,o),(!n||n(i))&&t(i,s))},o.prototype.map=function(t,e){var i,s=e&&e.filter,n=e&&e.convert||this.options.convert,o=[],r=this.data;for(var a in r)r.hasOwnProperty(a)&&(i=this._getItem(a,n),(!s||s(i))&&o.push(t(i,a)));return e&&e.order&&this._sort(o,e.order),o},o.prototype._filterFields=function(t,e){var i={};for(var s in t)t.hasOwnProperty(s)&&-1!=e.indexOf(s)&&(i[s]=t[s]);return i},o.prototype._sort=function(t,e){if(D.isString(e)){var i=e;t.sort(function(t,e){var s=t[i],n=e[i];return s>n?1:n>s?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},o.prototype.remove=function(t,e){var i,s,n,o=[];if(t instanceof Array)for(i=0,s=t.length;s>i;i++)n=this._remove(t[i]),null!=n&&o.push(n);else n=this._remove(t),null!=n&&o.push(n);return o.length&&this._trigger("remove",{items:o},e),o},o.prototype._remove=function(t){if(D.isNumber(t)||D.isString(t)){if(this.data[t])return delete this.data[t],delete this.internalIds[t],t}else if(t instanceof Object){var e=t[this.fieldId];if(e&&this.data[e])return delete this.data[e],delete this.internalIds[e],e}return null},o.prototype.clear=function(t){var e=Object.keys(this.data);return this.data={},this.internalIds={},this._trigger("remove",{items:e},t),e},o.prototype.max=function(t){var e=this.data,i=null,s=null;for(var n in e)if(e.hasOwnProperty(n)){var o=e[n],r=o[t];null!=r&&(!i||r>s)&&(i=o,s=r)}return i},o.prototype.min=function(t){var e=this.data,i=null,s=null;for(var n in e)if(e.hasOwnProperty(n)){var o=e[n],r=o[t];null!=r&&(!i||s>r)&&(i=o,s=r)}return i},o.prototype.distinct=function(t){var e=this.data,i=[],s=this.options.convert[t],n=0;for(var o in e)if(e.hasOwnProperty(o)){for(var r=e[o],a=D.convert(r[t],s),h=!1,d=0;n>d;d++)if(i[d]==a){h=!0;break}h||(i[n]=a,n++)}return i},o.prototype._addItem=function(t){var e=t[this.fieldId];if(void 0!=e){if(this.data[e])throw Error("Cannot add item: item with id "+e+" already exists")}else e=D.randomUUID(),t[this.fieldId]=e,this.internalIds[e]=t;var i={};for(var s in t)if(t.hasOwnProperty(s)){var n=this.convert[s];i[s]=D.convert(t[s],n)}return this.data[e]=i,e},o.prototype._getItem=function(t,e){var i,s,n=this.data[t];if(!n)return null;var o={},r=this.fieldId,a=this.internalIds;if(e)for(i in n)n.hasOwnProperty(i)&&(s=n[i],i==r&&s in a||(o[i]=D.convert(s,e[i])));else for(i in n)n.hasOwnProperty(i)&&(s=n[i],i==r&&s in a||(o[i]=s));return o},o.prototype._updateItem=function(t){var e=t[this.fieldId];if(void 0==e)throw Error("Cannot update item: item has no id (item: "+JSON.stringify(t)+")");var i=this.data[e];if(!i)throw Error("Cannot update item: no item with id "+e+" found");for(var s in t)if(t.hasOwnProperty(s)){var n=this.convert[s];i[s]=D.convert(t[s],n)}return e},o.prototype._getColumnNames=function(t){for(var e=[],i=0,s=t.getNumberOfColumns();s>i;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},o.prototype._appendRow=function(t,e,i){for(var s=t.addRow(),n=0,o=e.length;o>n;n++){var r=e[n];t.setValue(s,n,i[r])}},r.prototype.setData=function(t){var e,i,s;if(this.data){this.data.unsubscribe&&this.data.unsubscribe("*",this.listener),e=[];for(var n in this.ids)this.ids.hasOwnProperty(n)&&e.push(n);this.ids={},this._trigger("remove",{items:e})}if(this.data=t,this.data){for(this.fieldId=this.options.fieldId||this.data&&this.data.options&&this.data.options.fieldId||"id",e=this.data.getIds({filter:this.options&&this.options.filter}),i=0,s=e.length;s>i;i++)n=e[i],this.ids[n]=!0;this._trigger("add",{items:e}),this.data.subscribe&&this.data.subscribe("*",this.listener)}},r.prototype.get=function(){var t,e,i,s=this,n=D.getType(arguments[0]);"String"==n||"Number"==n||"Array"==n?(t=arguments[0],e=arguments[1],i=arguments[2]):(e=arguments[0],i=arguments[1]);var o=D.extend({},this.options,e);this.options.filter&&e&&e.filter&&(o.filter=function(t){return s.options.filter(t)&&e.filter(t)});var r=[];return void 0!=t&&r.push(t),r.push(o),r.push(i),this.data&&this.data.get.apply(this.data,r)},r.prototype.getIds=function(t){var e;if(this.data){var i,s=this.options.filter;i=t&&t.filter?s?function(e){return s(e)&&t.filter(e)}:t.filter:s,e=this.data.getIds({filter:i,order:t&&t.order})}else e=[];return e},r.prototype._onEvent=function(t,e,i){var s,n,o,r,a=e&&e.items,h=this.data,d=[],l=[],p=[];if(a&&h){switch(t){case"add":for(s=0,n=a.length;n>s;s++)o=a[s],r=this.get(o),r&&(this.ids[o]=!0,d.push(o));break;case"update":for(s=0,n=a.length;n>s;s++)o=a[s],r=this.get(o),r?this.ids[o]?l.push(o):(this.ids[o]=!0,d.push(o)):this.ids[o]&&(delete this.ids[o],p.push(o));break;case"remove":for(s=0,n=a.length;n>s;s++)o=a[s],this.ids[o]&&(delete this.ids[o],p.push(o))}d.length&&this._trigger("add",{items:d},i),l.length&&this._trigger("update",{items:l},i),p.length&&this._trigger("remove",{items:p},i)}},r.prototype.subscribe=o.prototype.subscribe,r.prototype.unsubscribe=o.prototype.unsubscribe,r.prototype._trigger=o.prototype._trigger,TimeStep=function(t,e,i){this.current=new Date,this._start=new Date,this._end=new Date,this.autoScale=!0,this.scale=TimeStep.SCALE.DAY,this.step=1,this.setRange(t,e,i)},TimeStep.SCALE={MILLISECOND:1,SECOND:2,MINUTE:3,HOUR:4,DAY:5,WEEKDAY:6,MONTH:7,YEAR:8},TimeStep.prototype.setRange=function(t,e,i){t instanceof Date&&e instanceof Date&&(this._start=void 0!=t?new Date(t.valueOf()):new Date,this._end=void 0!=e?new Date(e.valueOf()):new Date,this.autoScale&&this.setMinimumStep(i))},TimeStep.prototype.first=function(){this.current=new Date(this._start.valueOf()),this.roundToMinor()},TimeStep.prototype.roundToMinor=function(){switch(this.scale){case TimeStep.SCALE.YEAR:this.current.setFullYear(this.step*Math.floor(this.current.getFullYear()/this.step)),this.current.setMonth(0);case TimeStep.SCALE.MONTH:this.current.setDate(1);case TimeStep.SCALE.DAY:case TimeStep.SCALE.WEEKDAY:this.current.setHours(0);case TimeStep.SCALE.HOUR:this.current.setMinutes(0);case TimeStep.SCALE.MINUTE:this.current.setSeconds(0);case TimeStep.SCALE.SECOND:this.current.setMilliseconds(0)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.setMilliseconds(this.current.getMilliseconds()-this.current.getMilliseconds()%this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()-this.current.getSeconds()%this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()-this.current.getMinutes()%this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()-this.current.getHours()%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()-1-(this.current.getDate()-1)%this.step+1);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()-this.current.getMonth()%this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()-this.current.getFullYear()%this.step);break;default:}},TimeStep.prototype.hasNext=function(){return this.current.valueOf()<=this._end.valueOf()},TimeStep.prototype.next=function(){var t=this.current.valueOf();if(6>this.current.getMonth())switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current=new Date(this.current.valueOf()+1e3*this.step);break;case TimeStep.SCALE.MINUTE:this.current=new Date(this.current.valueOf()+60*1e3*this.step);break;case TimeStep.SCALE.HOUR:this.current=new Date(this.current.valueOf()+60*60*1e3*this.step);var e=this.current.getHours();this.current.setHours(e-e%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step);break;default:}else switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()+this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()+this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()+this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step);break;default:}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.getMilliseconds()0&&(this.step=e),this.autoScale=!1},TimeStep.prototype.setAutoScale=function(t){this.autoScale=t},TimeStep.prototype.setMinimumStep=function(t){if(void 0!=t){var e=31104e6,i=2592e6,s=864e5,n=36e5,o=6e4,r=1e3,a=1;1e3*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1e3),500*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=500),100*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=100),50*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=50),10*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=10),5*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=5),e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1),3*i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=3),i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=1),5*s>t&&(this.scale=TimeStep.SCALE.DAY,this.step=5),2*s>t&&(this.scale=TimeStep.SCALE.DAY,this.step=2),s>t&&(this.scale=TimeStep.SCALE.DAY,this.step=1),s/2>t&&(this.scale=TimeStep.SCALE.WEEKDAY,this.step=1),4*n>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=4),n>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=1),15*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=15),10*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=10),5*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=5),o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=1),15*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=15),10*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=10),5*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=5),r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=1),200*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=200),100*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=100),50*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=50),10*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=10),5*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=5),a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=1) +}},TimeStep.prototype.snap=function(t){if(this.scale==TimeStep.SCALE.YEAR){var e=t.getFullYear()+Math.round(t.getMonth()/12);t.setFullYear(Math.round(e/this.step)*this.step),t.setMonth(0),t.setDate(0),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MONTH)t.getDate()>15?(t.setDate(1),t.setMonth(t.getMonth()+1)):t.setDate(1),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0);else if(this.scale==TimeStep.SCALE.DAY||this.scale==TimeStep.SCALE.WEEKDAY){switch(this.step){case 5:case 2:t.setHours(24*Math.round(t.getHours()/24));break;default:t.setHours(12*Math.round(t.getHours()/12))}t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.HOUR){switch(this.step){case 4:t.setMinutes(60*Math.round(t.getMinutes()/60));break;default:t.setMinutes(30*Math.round(t.getMinutes()/30))}t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MINUTE){switch(this.step){case 15:case 10:t.setMinutes(5*Math.round(t.getMinutes()/5)),t.setSeconds(0);break;case 5:t.setSeconds(60*Math.round(t.getSeconds()/60));break;default:t.setSeconds(30*Math.round(t.getSeconds()/30))}t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.SECOND)switch(this.step){case 15:case 10:t.setSeconds(5*Math.round(t.getSeconds()/5)),t.setMilliseconds(0);break;case 5:t.setMilliseconds(1e3*Math.round(t.getMilliseconds()/1e3));break;default:t.setMilliseconds(500*Math.round(t.getMilliseconds()/500))}else if(this.scale==TimeStep.SCALE.MILLISECOND){var i=this.step>5?this.step/2:1;t.setMilliseconds(Math.round(t.getMilliseconds()/i)*i)}},TimeStep.prototype.isMajor=function(){switch(this.scale){case TimeStep.SCALE.MILLISECOND:return 0==this.current.getMilliseconds();case TimeStep.SCALE.SECOND:return 0==this.current.getSeconds();case TimeStep.SCALE.MINUTE:return 0==this.current.getHours()&&0==this.current.getMinutes();case TimeStep.SCALE.HOUR:return 0==this.current.getHours();case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return 1==this.current.getDate();case TimeStep.SCALE.MONTH:return 0==this.current.getMonth();case TimeStep.SCALE.YEAR:return!1;default:return!1}},TimeStep.prototype.getLabelMinor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return E(t).format("SSS");case TimeStep.SCALE.SECOND:return E(t).format("s");case TimeStep.SCALE.MINUTE:return E(t).format("HH:mm");case TimeStep.SCALE.HOUR:return E(t).format("HH:mm");case TimeStep.SCALE.WEEKDAY:return E(t).format("ddd D");case TimeStep.SCALE.DAY:return E(t).format("D");case TimeStep.SCALE.MONTH:return E(t).format("MMM");case TimeStep.SCALE.YEAR:return E(t).format("YYYY");default:return""}},TimeStep.prototype.getLabelMajor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return E(t).format("HH:mm:ss");case TimeStep.SCALE.SECOND:return E(t).format("D MMMM HH:mm");case TimeStep.SCALE.MINUTE:case TimeStep.SCALE.HOUR:return E(t).format("ddd D MMMM");case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return E(t).format("MMMM YYYY");case TimeStep.SCALE.MONTH:return E(t).format("YYYY");case TimeStep.SCALE.YEAR:return"";default:return""}},a.prototype.setOptions=function(t){D.extend(this.options,t)},a.prototype.update=function(){this._order(),this._stack()},a.prototype._order=function(){var t=this.parent.items;if(!t)throw Error("Cannot stack items: parent does not contain items");var e=[],i=0;D.forEach(t,function(t){t.visible&&(e[i]=t,i++)});var s=this.options.order||this.defaultOptions.order;if("function"!=typeof s)throw Error("Option order must be a function");e.sort(s),this.ordered=e},a.prototype._stack=function(){var t,e,i,s=this.ordered,n=this.options,o=n.orientation||this.defaultOptions.orientation,r="top"==o;for(i=n.margin&&void 0!==n.margin.item?n.margin.item:this.defaultOptions.margin.item,t=0,e=s.length;e>t;t++){var a=s[t],h=null;do h=this.checkOverlap(s,t,0,t-1,i),null!=h&&(a.top=r?h.top+h.height+i:h.top-a.height-i);while(h)}},a.prototype.checkOverlap=function(t,e,i,s,n){for(var o=this.collision,r=t[e],a=s;a>=i;a--){var h=t[a];if(o(r,h,n)&&a!=e)return h}return null},a.prototype.collision=function(t,e,i){return t.left-ie.left&&t.top-ie.top},h.prototype.setOptions=function(t){D.extend(this.options,t),(null!=t.start||null!=t.end)&&this.setRange(t.start,t.end)},h.prototype.subscribe=function(t,e,i){var s,n=this;if("horizontal"!=i&&"vertical"!=i)throw new TypeError('Unknown direction "'+i+'". '+'Choose "horizontal" or "vertical".');if("move"==e)s={component:t,event:e,direction:i,callback:function(t){n._onMouseDown(t,s)},params:{}},t.on("mousedown",s.callback),n.listeners.push(s);else{if("zoom"!=e)throw new TypeError('Unknown event "'+e+'". '+'Choose "move" or "zoom".');s={component:t,event:e,direction:i,callback:function(t){n._onMouseWheel(t,s)},params:{}},t.on("mousewheel",s.callback),n.listeners.push(s)}},h.prototype.on=function(t,e){O.addListener(this,t,e)},h.prototype._trigger=function(t){O.trigger(this,t,{start:this.start,end:this.end})},h.prototype.setRange=function(t,e){var i=this._applyRange(t,e);i&&(this._trigger("rangechange"),this._trigger("rangechanged"))},h.prototype._applyRange=function(t,e){var i,s=null!=t?D.convert(t,"Number"):this.start,n=null!=e?D.convert(e,"Number"):this.end;if(isNaN(s))throw Error('Invalid start "'+t+'"');if(isNaN(n))throw Error('Invalid end "'+e+'"');if(s>n&&(n=s),null!=this.options.min){var o=this.options.min.valueOf();o>s&&(i=o-s,s+=i,n+=i)}if(null!=this.options.max){var r=this.options.max.valueOf();n>r&&(i=n-r,s-=i,n-=i)}if(null!=this.options.zoomMin){var a=this.options.zoomMin.valueOf();0>a&&(a=0),a>n-s&&(this.end-this.start>a?(i=a-(n-s),s-=i/2,n+=i/2):(s=this.start,n=this.end))}if(null!=this.options.zoomMax){var h=this.options.zoomMax.valueOf();0>h&&(h=0),n-s>h&&(h>this.end-this.start?(i=n-s-h,s+=i/2,n-=i/2):(s=this.start,n=this.end))}var d=this.start!=s||this.end!=n;return this.start=s,this.end=n,d},h.prototype.getRange=function(){return{start:this.start,end:this.end}},h.prototype.conversion=function(t){return this.start,this.end,h.conversion(this.start,this.end,t)},h.conversion=function(t,e,i){return 0!=i&&0!=e-t?{offset:t,factor:i/(e-t)}:{offset:0,factor:1}},h.prototype._onMouseDown=function(t,e){t=t||window.event;var i=e.params,s=t.which?1==t.which:1==t.button;if(s){i.mouseX=D.getPageX(t),i.mouseY=D.getPageY(t),i.previousLeft=0,i.previousOffset=0,i.moved=!1,i.start=this.start,i.end=this.end;var n=e.component.frame;n&&(n.style.cursor="move");var o=this;i.onMouseMove||(i.onMouseMove=function(t){o._onMouseMove(t,e)},D.addEventListener(document,"mousemove",i.onMouseMove)),i.onMouseUp||(i.onMouseUp=function(t){o._onMouseUp(t,e)},D.addEventListener(document,"mouseup",i.onMouseUp)),D.preventDefault(t)}},h.prototype._onMouseMove=function(t,e){t=t||window.event;var i=e.params,s=D.getPageX(t),n=D.getPageY(t);void 0==i.mouseX&&(i.mouseX=s),void 0==i.mouseY&&(i.mouseY=n);var o=s-i.mouseX,r=n-i.mouseY,a="horizontal"==e.direction?o:r;Math.abs(a)>=1&&(i.moved=!0);var h=i.end-i.start,d="horizontal"==e.direction?e.component.width:e.component.height,l=-a/d*h;this._applyRange(i.start+l,i.end+l),this._trigger("rangechange"),D.preventDefault(t)},h.prototype._onMouseUp=function(t,e){t=t||window.event;var i=e.params;e.component.frame&&(e.component.frame.style.cursor="auto"),i.onMouseMove&&(D.removeEventListener(document,"mousemove",i.onMouseMove),i.onMouseMove=null),i.onMouseUp&&(D.removeEventListener(document,"mouseup",i.onMouseUp),i.onMouseUp=null),i.moved&&this._trigger("rangechanged")},h.prototype._onMouseWheel=function(t,e){t=t||window.event;var i=0;if(t.wheelDelta?i=t.wheelDelta/120:t.detail&&(i=-t.detail/3),i){var s=this,n=function(){var n=i/5,o=null,r=e.component.frame;if(r){var a,h;if("horizontal"==e.direction){a=e.component.width,h=s.conversion(a);var d=D.getAbsoluteLeft(r),l=D.getPageX(t);o=(l-d)/h.factor+h.offset}else{a=e.component.height,h=s.conversion(a);var p=D.getAbsoluteTop(r),c=D.getPageY(t);o=(p+a-c-p)/h.factor+h.offset}}s.zoom(n,o)};n()}D.preventDefault(t)},h.prototype.zoom=function(t,e){null==e&&(e=(this.start+this.end)/2),t>=1&&(t=.9),-1>=t&&(t=-.9),0>t&&(t/=1+t);var i=this.start-e,s=this.end-e,n=this.start-i*t,o=this.end-s*t;this.setRange(n,o)},h.prototype.move=function(t){var e=this.end-this.start,i=this.start+e*t,s=this.end+e*t;this.start=i,this.end=s},d.prototype.add=function(t){if(void 0==t.id)throw Error("Component has no field id");if(!(t instanceof l||t instanceof d))throw new TypeError("Component must be an instance of prototype Component or Controller");t.controller=this,this.components[t.id]=t},d.prototype.remove=function(t){var e;for(e in this.components)if(this.components.hasOwnProperty(e)&&(e==t||this.components[e]==t))break;e&&delete this.components[e]},d.prototype.requestReflow=function(t){if(t)this.reflow();else if(!this.reflowTimer){var e=this;this.reflowTimer=setTimeout(function(){e.reflowTimer=void 0,e.reflow()},0)}},d.prototype.requestRepaint=function(t){if(t)this.repaint();else if(!this.repaintTimer){var e=this;this.repaintTimer=setTimeout(function(){e.repaintTimer=void 0,e.repaint()},0)}},d.prototype.repaint=function(){function t(s,n){n in i||(s.depends&&s.depends.forEach(function(e){t(e,e.id)}),s.parent&&t(s.parent,s.parent.id),e=s.repaint()||e,i[n]=!0)}var e=!1;this.repaintTimer&&(clearTimeout(this.repaintTimer),this.repaintTimer=void 0);var i={};D.forEach(this.components,t),e&&this.reflow()},d.prototype.reflow=function(){function t(s,n){n in i||(s.depends&&s.depends.forEach(function(e){t(e,e.id)}),s.parent&&t(s.parent,s.parent.id),e=s.reflow()||e,i[n]=!0)}var e=!1;this.reflowTimer&&(clearTimeout(this.reflowTimer),this.reflowTimer=void 0);var i={};D.forEach(this.components,t),e&&this.repaint()},l.prototype.setOptions=function(t){t&&(D.extend(this.options,t),this.controller&&(this.requestRepaint(),this.requestReflow()))},l.prototype.getOption=function(t){var e;return this.options&&(e=this.options[t]),void 0===e&&this.defaultOptions&&(e=this.defaultOptions[t]),e},l.prototype.getContainer=function(){return null},l.prototype.getFrame=function(){return this.frame},l.prototype.repaint=function(){return!1},l.prototype.reflow=function(){return!1},l.prototype.hide=function(){return this.frame&&this.frame.parentNode?(this.frame.parentNode.removeChild(this.frame),!0):!1},l.prototype.show=function(){return this.frame&&this.frame.parentNode?!1:this.repaint()},l.prototype.requestRepaint=function(){if(!this.controller)throw Error("Cannot request a repaint: no controller configured");this.controller.requestRepaint()},l.prototype.requestReflow=function(){if(!this.controller)throw Error("Cannot request a reflow: no controller configured");this.controller.requestReflow()},p.prototype=new l,p.prototype.setOptions=l.prototype.setOptions,p.prototype.getContainer=function(){return this.frame},p.prototype.repaint=function(){var t=0,e=D.updateProperty,i=D.option.asSize,s=this.options,n=this.frame;if(!n){n=document.createElement("div"),n.className="panel";var o=s.className;o&&("function"==typeof o?D.addClassName(n,o()+""):D.addClassName(n,o+"")),this.frame=n,t+=1}if(!n.parentNode){if(!this.parent)throw Error("Cannot repaint panel: no parent attached");var r=this.parent.getContainer();if(!r)throw Error("Cannot repaint panel: parent has no container element");r.appendChild(n),t+=1}return t+=e(n.style,"top",i(s.top,"0px")),t+=e(n.style,"left",i(s.left,"0px")),t+=e(n.style,"width",i(s.width,"100%")),t+=e(n.style,"height",i(s.height,"100%")),t>0},p.prototype.reflow=function(){var t=0,e=D.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},c.prototype=new p,c.prototype.setOptions=l.prototype.setOptions,c.prototype.repaint=function(){var t=0,e=D.updateProperty,i=D.option.asSize,s=this.options,n=this.frame;if(!n){n=document.createElement("div"),n.className="vis timeline rootpanel";var o=s.className;o&&D.addClassName(n,D.option.asString(o)),this.frame=n,t+=1}if(!n.parentNode){if(!this.container)throw Error("Cannot repaint root panel: no container attached");this.container.appendChild(n),t+=1}return t+=e(n.style,"top",i(s.top,"0px")),t+=e(n.style,"left",i(s.left,"0px")),t+=e(n.style,"width",i(s.width,"100%")),t+=e(n.style,"height",i(s.height,"100%")),this._updateEventEmitters(),this._updateWatch(),t>0},c.prototype.reflow=function(){var t=0,e=D.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},c.prototype._updateWatch=function(){var t=this.getOption("autoResize");t?this._watch():this._unwatch()},c.prototype._watch=function(){var t=this;this._unwatch();var e=function(){var e=t.getOption("autoResize");return e?(t.frame&&(t.frame.clientWidth!=t.width||t.frame.clientHeight!=t.height)&&t.requestReflow(),void 0):(t._unwatch(),void 0)};D.addEventListener(window,"resize",e),this.watchTimer=setInterval(e,1e3)},c.prototype._unwatch=function(){this.watchTimer&&(clearInterval(this.watchTimer),this.watchTimer=void 0)},c.prototype.on=function(t,e){var i=this.listeners[t];i||(i=[],this.listeners[t]=i),i.push(e),this._updateEventEmitters()},c.prototype._updateEventEmitters=function(){if(this.listeners){var t=this;D.forEach(this.listeners,function(e,i){if(t.emitters||(t.emitters={}),!(i in t.emitters)){var s=t.frame;if(s){var n=function(t){e.forEach(function(e){e(t)})};t.emitters[i]=n,D.addEventListener(s,i,n)}}})}},u.prototype=new l,u.prototype.setOptions=l.prototype.setOptions,u.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},u.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.factor+e.offset)},u.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.factor},u.prototype.repaint=function(){var t=0,e=D.updateProperty,i=D.option.asSize,s=this.options,n=this.getOption("orientation"),o=this.props,r=this.step,a=this.frame;if(a||(a=document.createElement("div"),this.frame=a,t+=1),a.className="axis "+n,!a.parentNode){if(!this.parent)throw Error("Cannot repaint time axis: no parent attached");var h=this.parent.getContainer();if(!h)throw Error("Cannot repaint time axis: parent has no container element");h.appendChild(a),t+=1}var d=a.parentNode;if(d){var l=a.nextSibling;d.removeChild(a);var p="bottom"==n&&this.props.parentHeight&&this.height?this.props.parentHeight-this.height+"px":"0px";if(t+=e(a.style,"top",i(s.top,p)),t+=e(a.style,"left",i(s.left,"0px")),t+=e(a.style,"width",i(s.width,"100%")),t+=e(a.style,"height",i(s.height,this.height+"px")),this._repaintMeasureChars(),this.step){this._repaintStart(),r.first();for(var c=void 0,u=0;r.hasNext()&&1e3>u;){u++;var f=r.getCurrent(),m=this.toScreen(f),g=r.isMajor();this.getOption("showMinorLabels")&&this._repaintMinorText(m,r.getLabelMinor()),g&&this.getOption("showMajorLabels")?(m>0&&(void 0==c&&(c=m),this._repaintMajorText(m,r.getLabelMajor())),this._repaintMajorLine(m)):this._repaintMinorLine(m),r.next()}if(this.getOption("showMajorLabels")){var v=this.toTime(0),y=r.getLabelMajor(v),b=y.length*(o.majorCharWidth||10)+10;(void 0==c||c>b)&&this._repaintMajorText(0,y)}this._repaintEnd()}this._repaintLine(),l?d.insertBefore(a,l):d.appendChild(a)}return t>0},u.prototype._repaintStart=function(){var t=this.dom,e=t.redundant;e.majorLines=t.majorLines,e.majorTexts=t.majorTexts,e.minorLines=t.minorLines,e.minorTexts=t.minorTexts,t.majorLines=[],t.majorTexts=[],t.minorLines=[],t.minorTexts=[]},u.prototype._repaintEnd=function(){D.forEach(this.dom.redundant,function(t){for(;t.length;){var e=t.pop();e&&e.parentNode&&e.parentNode.removeChild(e)}})},u.prototype._repaintMinorText=function(t,e){var i=this.dom.redundant.minorTexts.shift();if(!i){var s=document.createTextNode("");i=document.createElement("div"),i.appendChild(s),i.className="text minor",this.frame.appendChild(i)}this.dom.minorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.left=t+"px",i.style.top=this.props.minorLabelTop+"px"},u.prototype._repaintMajorText=function(t,e){var i=this.dom.redundant.majorTexts.shift();if(!i){var s=document.createTextNode(e);i=document.createElement("div"),i.className="text major",i.appendChild(s),this.frame.appendChild(i)}this.dom.majorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.top=this.props.majorLabelTop+"px",i.style.left=t+"px"},u.prototype._repaintMinorLine=function(t){var e=this.dom.redundant.minorLines.shift();e||(e=document.createElement("div"),e.className="grid vertical minor",this.frame.appendChild(e)),this.dom.minorLines.push(e);var i=this.props;e.style.top=i.minorLineTop+"px",e.style.height=i.minorLineHeight+"px",e.style.left=t-i.minorLineWidth/2+"px"},u.prototype._repaintMajorLine=function(t){var e=this.dom.redundant.majorLines.shift();e||(e=document.createElement("DIV"),e.className="grid vertical major",this.frame.appendChild(e)),this.dom.majorLines.push(e);var i=this.props;e.style.top=i.majorLineTop+"px",e.style.left=t-i.majorLineWidth/2+"px",e.style.height=i.majorLineHeight+"px"},u.prototype._repaintLine=function(){var t=this.dom.line,e=this.frame;this.options,this.getOption("showMinorLabels")||this.getOption("showMajorLabels")?(t?(e.removeChild(t),e.appendChild(t)):(t=document.createElement("div"),t.className="grid horizontal major",e.appendChild(t),this.dom.line=t),t.style.top=this.props.lineTop+"px"):t&&axis.parentElement&&(e.removeChild(axis.line),delete this.dom.line)},u.prototype._repaintMeasureChars=function(){var t,e=this.dom;if(!e.measureCharMinor){t=document.createTextNode("0");var i=document.createElement("DIV");i.className="text minor measure",i.appendChild(t),this.frame.appendChild(i),e.measureCharMinor=i}if(!e.measureCharMajor){t=document.createTextNode("0");var s=document.createElement("DIV");s.className="text major measure",s.appendChild(t),this.frame.appendChild(s),e.measureCharMajor=s}},u.prototype.reflow=function(){var t=0,e=D.updateProperty,i=this.frame,s=this.range;if(!s)throw Error("Cannot repaint time axis: no range configured");if(i){t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft);var n=this.props,o=this.getOption("showMinorLabels"),r=this.getOption("showMajorLabels"),a=this.dom.measureCharMinor,h=this.dom.measureCharMajor;a&&(n.minorCharHeight=a.clientHeight,n.minorCharWidth=a.clientWidth),h&&(n.majorCharHeight=h.clientHeight,n.majorCharWidth=h.clientWidth);var d=i.parentNode?i.parentNode.offsetHeight:0;switch(d!=n.parentHeight&&(n.parentHeight=d,t+=1),this.getOption("orientation")){case"bottom":n.minorLabelHeight=o?n.minorCharHeight:0,n.majorLabelHeight=r?n.majorCharHeight:0,n.minorLabelTop=0,n.majorLabelTop=n.minorLabelTop+n.minorLabelHeight,n.minorLineTop=-this.top,n.minorLineHeight=Math.max(this.top+n.majorLabelHeight,0),n.minorLineWidth=1,n.majorLineTop=-this.top,n.majorLineHeight=Math.max(this.top+n.minorLabelHeight+n.majorLabelHeight,0),n.majorLineWidth=1,n.lineTop=0;break;case"top":n.minorLabelHeight=o?n.minorCharHeight:0,n.majorLabelHeight=r?n.majorCharHeight:0,n.majorLabelTop=0,n.minorLabelTop=n.majorLabelTop+n.majorLabelHeight,n.minorLineTop=n.minorLabelTop,n.minorLineHeight=Math.max(d-n.majorLabelHeight-this.top),n.minorLineWidth=1,n.majorLineTop=0,n.majorLineHeight=Math.max(d-this.top),n.majorLineWidth=1,n.lineTop=n.majorLabelHeight+n.minorLabelHeight;break;default:throw Error('Unkown orientation "'+this.getOption("orientation")+'"')}var l=n.minorLabelHeight+n.majorLabelHeight;t+=e(this,"width",i.offsetWidth),t+=e(this,"height",l),this._updateConversion();var p=D.convert(s.start,"Date"),c=D.convert(s.end,"Date"),u=this.toTime(5*(n.minorCharWidth||10))-this.toTime(0);this.step=new TimeStep(p,c,u),t+=e(n.range,"start",p.valueOf()),t+=e(n.range,"end",c.valueOf()),t+=e(n.range,"minimumStep",u.valueOf())}return t>0},u.prototype._updateConversion=function(){var t=this.range;if(!t)throw Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},f.prototype=new p,f.types={box:g,range:y,point:v},f.prototype.setOptions=l.prototype.setOptions,f.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},f.prototype.repaint=function(){var t=0,e=D.updateProperty,i=D.option.asSize,s=this.options,n=this.getOption("orientation"),o=this.defaultOptions,r=this.frame;if(!r){r=document.createElement("div"),r.className="itemset";var a=s.className;a&&D.addClassName(r,D.option.asString(a));var h=document.createElement("div");h.className="background",r.appendChild(h),this.dom.background=h;var d=document.createElement("div");d.className="foreground",r.appendChild(d),this.dom.foreground=d;var l=document.createElement("div");l.className="itemset-axis",this.dom.axis=l,this.frame=r,t+=1}if(!this.parent)throw Error("Cannot repaint itemset: no parent attached");var p=this.parent.getContainer();if(!p)throw Error("Cannot repaint itemset: parent has no container element");r.parentNode||(p.appendChild(r),t+=1),this.dom.axis.parentNode||(p.appendChild(this.dom.axis),t+=1),t+=e(r.style,"left",i(s.left,"0px")),t+=e(r.style,"top",i(s.top,"0px")),t+=e(r.style,"width",i(s.width,"100%")),t+=e(r.style,"height",i(s.height,this.height+"px")),t+=e(this.dom.axis.style,"left",i(s.left,"0px")),t+=e(this.dom.axis.style,"width",i(s.width,"100%")),t+="bottom"==n?e(this.dom.axis.style,"top",this.height+this.top+"px"):e(this.dom.axis.style,"top",this.top+"px"),this._updateConversion();var c=this,u=this.queue,m=this.itemsData,g=this.items,v={fields:[m&&m.fieldId||"id","start","end","content","type"]};return Object.keys(u).forEach(function(e){var i=u[e],n=g[e];switch(i){case"add":case"update":var r=m&&m.get(e,v);if(r){var a=r.type||r.start&&r.end&&"range"||s.type||"box",h=f.types[a];if(n&&(h&&n instanceof h?(n.data=r,t++):(t+=n.hide(),n=null)),!n){if(!h)throw new TypeError('Unknown item type "'+a+'"');n=new h(c,r,s,o),t++}n.repaint(),g[e]=n}delete u[e];break;case"remove":n&&(t+=n.hide()),delete g[e],delete u[e];break;default:console.log('Error: unknown action "'+i+'"')}}),D.forEach(this.items,function(e){e.visible?(t+=e.show(),e.reposition()):t+=e.hide()}),t>0},f.prototype.getForeground=function(){return this.dom.foreground},f.prototype.getBackground=function(){return this.dom.background},f.prototype.getAxis=function(){return this.dom.axis},f.prototype.reflow=function(){var t=0,e=this.options,i=e.margin&&e.margin.axis||this.defaultOptions.margin.axis,s=e.margin&&e.margin.item||this.defaultOptions.margin.item,n=D.updateProperty,o=D.option.asNumber,r=D.option.asSize,a=this.frame;if(a){this._updateConversion(),D.forEach(this.items,function(e){t+=e.reflow()}),this.stack.update();var h,d=o(e.maxHeight),l=null!=r(e.height);if(l)h=a.offsetHeight;else{var p=this.stack.ordered;if(p.length){var c=p[0].top,u=p[0].top+p[0].height;D.forEach(p,function(t){c=Math.min(c,t.top),u=Math.max(u,t.top+t.height)}),h=u-c+i+s}else h=i+s}null!=d&&(h=Math.min(h,d)),t+=n(this,"height",h),t+=n(this,"top",a.offsetTop),t+=n(this,"left",a.offsetLeft),t+=n(this,"width",a.offsetWidth)}else t+=1;return t>0},f.prototype.hide=function(){var t=!1;return this.frame&&this.frame.parentNode&&(this.frame.parentNode.removeChild(this.frame),t=!0),this.dom.axis&&this.dom.axis.parentNode&&(this.dom.axis.parentNode.removeChild(this.dom.axis),t=!0),t},f.prototype.setItems=function(t){var e,i=this,s=this.itemsData;if(t){if(!(t instanceof o||t instanceof r))throw new TypeError("Data must be an instance of DataSet");this.itemsData=t}else this.itemsData=null;if(s&&(D.forEach(this.listeners,function(t,e){s.unsubscribe(e,t)}),e=s.getIds(),this._onRemove(e)),this.itemsData){var n=this.id;D.forEach(this.listeners,function(t,e){i.itemsData.subscribe(e,t,n)}),e=this.itemsData.getIds(),this._onAdd(e)}},f.prototype.getItems=function(){return this.itemsData},f.prototype._onUpdate=function(t){this._toQueue("update",t)},f.prototype._onAdd=function(t){this._toQueue("add",t)},f.prototype._onRemove=function(t){this._toQueue("remove",t)},f.prototype._toQueue=function(t,e){var i=this.queue;e.forEach(function(e){i[e]=t}),this.controller&&this.requestRepaint()},f.prototype._updateConversion=function(){var t=this.range;if(!t)throw Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},f.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.factor+e.offset)},f.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.factor},m.prototype.select=function(){this.selected=!0},m.prototype.unselect=function(){this.selected=!1},m.prototype.show=function(){return!1},m.prototype.hide=function(){return!1},m.prototype.repaint=function(){return!1},m.prototype.reflow=function(){return!1},g.prototype=new m(null,null),g.prototype.select=function(){this.selected=!0},g.prototype.unselect=function(){this.selected=!1},g.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw Error("Cannot repaint time axis: parent has no foreground container element");var s=this.parent.getBackground();if(!s)throw Error("Cannot repaint time axis: parent has no background container element");var n=this.parent.getAxis();if(!s)throw Error("Cannot repaint time axis: parent has no axis container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),e.line.parentNode||(s.appendChild(e.line),t=!0),e.dot.parentNode||(n.appendChild(e.dot),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var o=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=o&&(this.className=o,e.box.className="item box"+o,e.line.className="item line"+o,e.dot.className="item dot"+o,t=!0)}return t},g.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},g.prototype.hide=function(){var t=!1,e=this.dom;return e&&(e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),e.line.parentNode&&e.line.parentNode.removeChild(e.line),e.dot.parentNode&&e.dot.parentNode.removeChild(e.dot)),t},g.prototype.reflow=function(){var t,e,i,s,n,o,r,a,h,d,l,p,c=0;if(void 0==this.data.start)throw Error('Property "start" missing in item '+this.data.id);if(l=this.data,p=this.parent&&this.parent.range,l&&p){var u=p.end-p.start;this.visible=l.start>p.start-u&&l.start0},g.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("DIV"),t.content=document.createElement("DIV"),t.content.className="content",t.box.appendChild(t.content),t.line=document.createElement("DIV"),t.line.className="line",t.dot=document.createElement("DIV"),t.dot.className="dot")},g.prototype.reposition=function(){var t=this.dom,e=this.props,i=this.options.orientation||this.defaultOptions.orientation;if(t){var s=t.box,n=t.line,o=t.dot;s.style.left=this.left+"px",s.style.top=this.top+"px",n.style.left=e.line.left+"px","top"==i?(n.style.top="0px",n.style.height=this.top+"px"):(n.style.top=this.top+this.height+"px",n.style.height=Math.max(this.parent.height-this.top-this.height+this.props.dot.height/2,0)+"px"),o.style.left=e.dot.left+"px",o.style.top=e.dot.top+"px"}},v.prototype=new m(null,null),v.prototype.select=function(){this.selected=!0},v.prototype.unselect=function(){this.selected=!1},v.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw Error("Cannot repaint time axis: parent has no foreground container element");if(e.point.parentNode||(i.appendChild(e.point),i.appendChild(e.point),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var s=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=s&&(this.className=s,e.point.className="item point"+s,t=!0)}return t},v.prototype.show=function(){return this.dom&&this.dom.point.parentNode?!1:this.repaint()},v.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.point.parentNode&&(e.point.parentNode.removeChild(e.point),t=!0),t},v.prototype.reflow=function(){var t,e,i,s,n,o,r,a,h,d,l=0;if(void 0==this.data.start)throw Error('Property "start" missing in item '+this.data.id);if(h=this.data,d=this.parent&&this.parent.range,h&&d){var p=d.end-d.start;this.visible=h.start>d.start-p&&h.start0},v.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.point=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.point.appendChild(t.content),t.dot=document.createElement("div"),t.dot.className="dot",t.point.appendChild(t.dot))},v.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.point.style.top=this.top+"px",t.point.style.left=this.left+"px",t.content.style.marginLeft=e.content.marginLeft+"px",t.dot.style.top=e.dot.top+"px")},y.prototype=new m(null,null),y.prototype.select=function(){this.selected=!0},y.prototype.unselect=function(){this.selected=!1},y.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content +}t=!0}var s=this.data.className?""+this.data.className:"";this.className!=s&&(this.className=s,e.box.className="item range"+s,t=!0)}return t},y.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},y.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),t},y.prototype.reflow=function(){var t,e,i,s,n,o,r,a,h,d,l,p,c,u,f,m,g=0;if(void 0==this.data.start)throw Error('Property "start" missing in item '+this.data.id);if(void 0==this.data.end)throw Error('Property "end" missing in item '+this.data.id);return h=this.data,d=this.parent&&this.parent.range,this.visible=h&&d?h.startd.start:!1,this.visible&&(t=this.dom,t?(e=this.props,i=this.options,o=this.parent,r=o.toScreen(this.data.start),a=o.toScreen(this.data.end),l=D.updateProperty,p=t.box,c=o.width,f=i.orientation||this.defaultOptions.orientation,s=i.margin&&i.margin.axis||this.defaultOptions.margin.axis,n=i.padding||this.defaultOptions.padding,g+=l(e.content,"width",t.content.offsetWidth),g+=l(this,"height",p.offsetHeight),-c>r&&(r=-c),a>2*c&&(a=2*c),u=0>r?Math.min(-r,a-r-e.content.width-2*n):0,g+=l(e.content,"left",u),"top"==f?(m=s,g+=l(this,"top",m)):(m=o.height-this.height-s,g+=l(this,"top",m)),g+=l(this,"left",r),g+=l(this,"width",Math.max(a-r,1))):g+=1),g>0},y.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content))},y.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.box.style.top=this.top+"px",t.box.style.left=this.left+"px",t.box.style.width=this.width+"px",t.content.style.left=e.content.left+"px")},b.prototype=new l,b.prototype.setOptions=l.prototype.setOptions,b.prototype.getContainer=function(){return this.parent.getContainer()},b.prototype.setItems=function(t){if(this.itemset&&(this.itemset.hide(),this.itemset.setItems(),this.parent.controller.remove(this.itemset),this.itemset=null),t){var e=this.groupId,i=Object.create(this.options);this.itemset=new f(this,null,i),this.itemset.setRange(this.parent.range),this.view=new r(t,{filter:function(t){return t.group==e}}),this.itemset.setItems(this.view),this.parent.controller.add(this.itemset)}},b.prototype.repaint=function(){return!1},b.prototype.reflow=function(){var t=0,e=D.updateProperty;if(t+=e(this,"top",this.itemset?this.itemset.top:0),t+=e(this,"height",this.itemset?this.itemset.height:0),this.label){var i=this.label.firstChild;t+=e(this.props.label,"width",i.clientWidth),t+=e(this.props.label,"height",i.clientHeight)}else t+=e(this.props.label,"width",0),t+=e(this.props.label,"height",0);return t>0},w.prototype=new p,w.prototype.setOptions=l.prototype.setOptions,w.prototype.setRange=function(){},w.prototype.setItems=function(t){this.itemsData=t;for(var e in this.groups)if(this.groups.hasOwnProperty(e)){var i=this.groups[e];i.setItems(t)}},w.prototype.getItems=function(){return this.itemsData},w.prototype.setRange=function(t){this.range=t},w.prototype.setGroups=function(t){var e,i=this;if(this.groupsData&&(D.forEach(this.listeners,function(t,e){i.groupsData.unsubscribe(e,t)}),e=this.groupsData.getIds(),this._onRemove(e)),t?t instanceof o?this.groupsData=t:(this.groupsData=new o({convert:{start:"Date",end:"Date"}}),this.groupsData.add(t)):this.groupsData=null,this.groupsData){var s=this.id;D.forEach(this.listeners,function(t,e){i.groupsData.subscribe(e,t,s)}),e=this.groupsData.getIds(),this._onAdd(e)}},w.prototype.getGroups=function(){return this.groupsData},w.prototype.repaint=function(){var t,e,i,s,n=0,o=D.updateProperty,r=D.option.asSize,a=D.option.asElement,h=this.options,d=this.dom.frame,l=this.dom.labels;if(!this.parent)throw Error("Cannot repaint groupset: no parent attached");var p=this.parent.getContainer();if(!p)throw Error("Cannot repaint groupset: parent has no container element");if(!d){d=document.createElement("div"),d.className="groupset",this.dom.frame=d;var c=h.className;c&&D.addClassName(d,D.option.asString(c)),n+=1}d.parentNode||(p.appendChild(d),n+=1);var u=a(h.labelContainer);if(!u)throw Error('Cannot repaint groupset: option "labelContainer" not defined');l||(l=document.createElement("div"),l.className="labels",this.dom.labels=l),l.parentNode&&l.parentNode==u||(l.parentNode&&l.parentNode.removeChild(l.parentNode),u.appendChild(l)),n+=o(d.style,"height",r(h.height,this.height+"px")),n+=o(d.style,"top",r(h.top,"0px")),n+=o(d.style,"left",r(h.left,"0px")),n+=o(d.style,"width",r(h.width,"100%")),n+=o(l.style,"top",r(h.top,"0px"));var f=this,m=this.queue,g=this.groups,v=this.groupsData,y=Object.keys(m);if(y.length){y.forEach(function(t){var e=m[t],i=g[t];switch(e){case"add":case"update":if(!i){var s=Object.create(f.options);i=new b(f,t,s),i.setItems(f.itemsData),g[t]=i,f.controller.add(i)}i.data=v.get(t),delete m[t];break;case"remove":i&&(i.setItems(),delete g[t],f.controller.remove(i)),delete m[t];break;default:console.log('Error: unknown action "'+e+'"')}});var w=this.groupsData.getIds({order:this.options.groupsOrder});for(t=0;w.length>t;t++)(function(t,e){var i=0;e&&(i=function(){return e.top+e.height}),t.setOptions({top:i})})(g[w[t]],g[w[t-1]]);for(;l.firstChild;)l.removeChild(l.firstChild);for(t=0;w.length>t;t++)e=w[t],s=this._createLabel(e),l.appendChild(s);n++}for(e in g)g.hasOwnProperty(e)&&(i=g[e],s=i.label,s&&(s.style.top=i.top+"px",s.style.height=i.height+"px"));return n>0},w.prototype._createLabel=function(t){var e=this.groups[t],i=document.createElement("div");i.className="label";var s=document.createElement("div");s.className="inner",i.appendChild(s);var n=e.data&&e.data.content;n instanceof Element?s.appendChild(n):void 0!=n&&(s.innerHTML=n);var o=e.data&&e.data.className;return o&&D.addClassName(i,o),e.label=i,i},w.prototype.getContainer=function(){return this.dom.frame},w.prototype.getLabelsWidth=function(){return this.props.labels.width},w.prototype.reflow=function(){var t,e,i=0,s=this.options,n=D.updateProperty,o=D.option.asNumber,r=D.option.asSize,a=this.dom.frame;if(a){var h,d=o(s.maxHeight),l=null!=r(s.height);if(l)h=a.offsetHeight;else{h=0;for(t in this.groups)this.groups.hasOwnProperty(t)&&(e=this.groups[t],h+=e.height)}null!=d&&(h=Math.min(h,d)),i+=n(this,"height",h),i+=n(this,"top",a.offsetTop),i+=n(this,"left",a.offsetLeft),i+=n(this,"width",a.offsetWidth)}var p=0;for(t in this.groups)if(this.groups.hasOwnProperty(t)){e=this.groups[t];var c=e.props&&e.props.label&&e.props.label.width||0;p=Math.max(p,c)}return i+=n(this.props.labels,"width",p),i>0},w.prototype.hide=function(){return this.dom.frame&&this.dom.frame.parentNode?(this.dom.frame.parentNode.removeChild(this.dom.frame),!0):!1},w.prototype.show=function(){return this.dom.frame&&this.dom.frame.parentNode?!1:this.repaint()},w.prototype._onUpdate=function(t){this._toQueue(t,"update")},w.prototype._onAdd=function(t){this._toQueue(t,"add")},w.prototype._onRemove=function(t){this._toQueue(t,"remove")},w.prototype._toQueue=function(t,e){var i=this.queue;t.forEach(function(t){i[t]=e}),this.controller&&this.requestRepaint()},_.prototype.setOptions=function(t){t&&D.extend(this.options,t),this.controller.reflow(),this.controller.repaint()},_.prototype.setItems=function(t){var e,i=null==this.itemsData;if(t?t instanceof o&&(e=t):e=null,t instanceof o||(e=new o({convert:{start:"Date",end:"Date"}}),e.add(t)),this.itemsData=e,this.content.setItems(e),i&&(void 0==this.options.start||void 0==this.options.end)){var s=this.getItemRange(),n=s.min,r=s.max;if(null!=n&&null!=r){var a=r.valueOf()-n.valueOf();n=new Date(n.valueOf()-.05*a),r=new Date(r.valueOf()+.05*a)}void 0!=this.options.start&&(n=new Date(this.options.start.valueOf())),void 0!=this.options.end&&(r=new Date(this.options.end.valueOf())),(null!=n||null!=r)&&this.range.setRange(n,r)}},_.prototype.setGroups=function(t){var e=this;this.groupsData=t;var i=this.groupsData?w:f;if(!(this.content instanceof i)){this.content&&(this.content.hide(),this.content.setItems&&this.content.setItems(),this.content.setGroups&&this.content.setGroups(),this.controller.remove(this.content));var s=Object.create(this.options);D.extend(s,{top:function(){return"top"==e.options.orientation?e.timeaxis.height:e.itemPanel.height-e.timeaxis.height-e.content.height},left:null,width:"100%",height:function(){return e.options.height?e.itemPanel.height-e.timeaxis.height:null},maxHeight:function(){if(e.options.maxHeight){if(!D.isNumber(e.options.maxHeight))throw new TypeError("Number expected for property maxHeight");return e.options.maxHeight-e.timeaxis.height}return null},labelContainer:function(){return e.labelPanel.getContainer()}}),this.content=new i(this.itemPanel,[this.timeaxis],s),this.content.setRange&&this.content.setRange(this.range),this.content.setItems&&this.content.setItems(this.itemsData),this.content.setGroups&&this.content.setGroups(this.groupsData),this.controller.add(this.content)}},_.prototype.getItemRange=function(){var t=this.itemsData,e=null,i=null;if(t){var s=t.min("start");e=s?s.start.valueOf():null;var n=t.max("start");n&&(i=n.start.valueOf());var o=t.max("end");o&&(i=null==i?o.end.valueOf():Math.max(i,o.end.valueOf()))}return{min:null!=e?new Date(e):null,max:null!=i?new Date(i):null}},function(t){function e(t){return E=t,c()}function i(){D=0,C=E.charAt(0)}function s(){D++,C=E.charAt(D)}function n(){return E.charAt(D+1)}function o(t){return N.test(t)}function r(t,e){if(t||(t={}),e)for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function a(t,e,i){for(var s=e.split("."),n=t;s.length;){var o=s.shift();s.length?(n[o]||(n[o]={}),n=n[o]):n[o]=i}}function h(t,e){for(var i,s,n=null,o=[t],a=t;a.parent;)o.push(a.parent),a=a.parent;if(a.nodes)for(i=0,s=a.nodes.length;s>i;i++)if(e.id===a.nodes[i].id){n=a.nodes[i];break}for(n||(n={id:e.id},t.node&&(n.attr=r(n.attr,t.node))),i=o.length-1;i>=0;i--){var h=o[i];h.nodes||(h.nodes=[]),-1==h.nodes.indexOf(n)&&h.nodes.push(n)}e.attr&&(n.attr=r(n.attr,e.attr))}function d(t,e){if(t.edges||(t.edges=[]),t.edges.push(e),t.edge){var i=r({},t.edge);e.attr=r(i,e.attr)}}function l(t,e,i,s,n){var o={from:e,to:i,type:s};return t.edge&&(o.attr=r({},t.edge)),o.attr=r(o.attr||{},n),o}function p(){for(O=S.NULL,L="";" "==C||" "==C||"\n"==C||"\r"==C;)s();do{var t=!1;if("#"==C){for(var e=D-1;" "==E.charAt(e)||" "==E.charAt(e);)e--;if("\n"==E.charAt(e)||""==E.charAt(e)){for(;""!=C&&"\n"!=C;)s();t=!0}}if("/"==C&&"/"==n()){for(;""!=C&&"\n"!=C;)s();t=!0}if("/"==C&&"*"==n()){for(;""!=C;){if("*"==C&&"/"==n()){s(),s();break}s()}t=!0}for(;" "==C||" "==C||"\n"==C||"\r"==C;)s()}while(t);if(""==C)return O=S.DELIMITER,void 0;var i=C+n();if(M[i])return O=S.DELIMITER,L=i,s(),s(),void 0;if(M[C])return O=S.DELIMITER,L=C,s(),void 0;if(o(C)||"-"==C){for(L+=C,s();o(C);)L+=C,s();return"false"==L?L=!1:"true"==L?L=!0:isNaN(Number(L))||(L=Number(L)),O=S.IDENTIFIER,void 0}if('"'==C){for(s();""!=C&&('"'!=C||'"'==C&&'"'==n());)L+=C,'"'==C&&s(),s();if('"'!=C)throw w('End of string " expected');return s(),O=S.IDENTIFIER,void 0}for(O=S.UNKNOWN;""!=C;)L+=C,s();throw new SyntaxError('Syntax error in part "'+_(L,30)+'"')}function c(){var t={};if(i(),p(),"strict"==L&&(t.strict=!0,p()),("graph"==L||"digraph"==L)&&(t.type=L,p()),O==S.IDENTIFIER&&(t.id=L,p()),"{"!=L)throw w("Angle bracket { expected");if(p(),u(t),"}"!=L)throw w("Angle bracket } expected");if(p(),""!==L)throw w("End of file expected");return p(),delete t.node,delete t.edge,delete t.graph,t}function u(t){for(;""!==L&&"}"!=L;)f(t),";"==L&&p()}function f(t){var e=m(t);if(e)return y(t,e),void 0;var i=g(t);if(!i){if(O!=S.IDENTIFIER)throw w("Identifier expected");var s=L;if(p(),"="==L){if(p(),O!=S.IDENTIFIER)throw w("Identifier expected");t[s]=L,p()}else v(t,s)}}function m(t){var e=null;if("subgraph"==L&&(e={},e.type="subgraph",p(),O==S.IDENTIFIER&&(e.id=L,p())),"{"==L){if(p(),e||(e={}),e.parent=t,e.node=t.node,e.edge=t.edge,e.graph=t.graph,u(e),"}"!=L)throw w("Angle bracket } expected");p(),delete e.node,delete e.edge,delete e.graph,delete e.parent,t.subgraphs||(t.subgraphs=[]),t.subgraphs.push(e)}return e}function g(t){return"node"==L?(p(),t.node=b(),"node"):"edge"==L?(p(),t.edge=b(),"edge"):"graph"==L?(p(),t.graph=b(),"graph"):null}function v(t,e){var i={id:e},s=b();s&&(i.attr=s),h(t,i),y(t,e)}function y(t,e){for(;"->"==L||"--"==L;){var i,s=L;p();var n=m(t);if(n)i=n;else{if(O!=S.IDENTIFIER)throw w("Identifier or subgraph expected");i=L,h(t,{id:i}),p()}var o=b(),r=l(t,e,i,s,o);d(t,r),e=i}}function b(){for(var t=null;"["==L;){for(p(),t={};""!==L&&"]"!=L;){if(O!=S.IDENTIFIER)throw w("Attribute name expected");var e=L;if(p(),"="!=L)throw w("Equal sign = expected");if(p(),O!=S.IDENTIFIER)throw w("Attribute value expected");var i=L;a(t,e,i),p(),","==L&&p()}if("]"!=L)throw w("Bracket ] expected");p()}return t}function w(t){return new SyntaxError(t+', got "'+_(L,30)+'" (char '+D+")")}function _(t,e){return e>=t.length?t:t.substr(0,27)+"..."}function x(t,e,i){t instanceof Array?t.forEach(function(t){e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}):e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}function T(t){function i(t){var e={from:t.from,to:t.to};return r(e,t.attr),e.style="->"==t.type?"arrow":"line",e}var s=e(t),n={nodes:[],edges:[],options:{}};return s.nodes&&s.nodes.forEach(function(t){var e={id:t.id,label:(t.label||t.id)+""};r(e,t.attr),e.image&&(e.shape="image"),n.nodes.push(e)}),s.edges&&s.edges.forEach(function(t){var e,s;e=t.from instanceof Object?t.from.nodes:{id:t.from},s=t.to instanceof Object?t.to.nodes:{id:t.to},t.from instanceof Object&&t.from.edges&&t.from.edges.forEach(function(t){var e=i(t);n.edges.push(e)}),x(e,s,function(e,s){var o=l(n,e.id,s.id,t.type,t.attr),r=i(o);n.edges.push(r)}),t.to instanceof Object&&t.to.edges&&t.to.edges.forEach(function(t){var e=i(t);n.edges.push(e)})}),s.attr&&(n.options=s.attr),n}var S={NULL:0,DELIMITER:1,IDENTIFIER:2,UNKNOWN:3},M={"{":!0,"}":!0,"[":!0,"]":!0,";":!0,"=":!0,",":!0,"->":!0,"--":!0},E="",D=0,C="",L="",O=S.NULL,N=/[a-zA-Z_0-9.:#]/;t.parseDOT=e,t.DOTToGraph=T}(D!==void 0?D:s),"undefined"!=typeof CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.circle=function(t,e,i){this.beginPath(),this.arc(t,e,i,0,2*Math.PI,!1)},CanvasRenderingContext2D.prototype.square=function(t,e,i){this.beginPath(),this.rect(t-i,e-i,2*i,2*i)},CanvasRenderingContext2D.prototype.triangle=function(t,e,i){this.beginPath();var s=2*i,n=s/2,o=Math.sqrt(3)/6*s,r=Math.sqrt(s*s-n*n);this.moveTo(t,e-(r-o)),this.lineTo(t+n,e+o),this.lineTo(t-n,e+o),this.lineTo(t,e-(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.triangleDown=function(t,e,i){this.beginPath();var s=2*i,n=s/2,o=Math.sqrt(3)/6*s,r=Math.sqrt(s*s-n*n);this.moveTo(t,e+(r-o)),this.lineTo(t+n,e-o),this.lineTo(t-n,e-o),this.lineTo(t,e+(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.star=function(t,e,i){this.beginPath();for(var s=0;10>s;s++){var n=0===s%2?1.3*i:.5*i;this.lineTo(t+n*Math.sin(2*s*Math.PI/10),e-n*Math.cos(2*s*Math.PI/10))}this.closePath()},CanvasRenderingContext2D.prototype.roundRect=function(t,e,i,s,n){var o=Math.PI/180;0>i-2*n&&(n=i/2),0>s-2*n&&(n=s/2),this.beginPath(),this.moveTo(t+n,e),this.lineTo(t+i-n,e),this.arc(t+i-n,e+n,n,270*o,360*o,!1),this.lineTo(t+i,e+s-n),this.arc(t+i-n,e+s-n,n,0,90*o,!1),this.lineTo(t+n,e+s),this.arc(t+n,e+s-n,n,90*o,180*o,!1),this.lineTo(t,e+n),this.arc(t+n,e+n,n,180*o,270*o,!1)},CanvasRenderingContext2D.prototype.ellipse=function(t,e,i,s){var n=.5522848,o=i/2*n,r=s/2*n,a=t+i,h=e+s,d=t+i/2,l=e+s/2;this.beginPath(),this.moveTo(t,l),this.bezierCurveTo(t,l-r,d-o,e,d,e),this.bezierCurveTo(d+o,e,a,l-r,a,l),this.bezierCurveTo(a,l+r,d+o,h,d,h),this.bezierCurveTo(d-o,h,t,l+r,t,l)},CanvasRenderingContext2D.prototype.database=function(t,e,i,s){var n=1/3,o=i,r=s*n,a=.5522848,h=o/2*a,d=r/2*a,l=t+o,p=e+r,c=t+o/2,u=e+r/2,f=e+(s-r/2),m=e+s;this.beginPath(),this.moveTo(l,u),this.bezierCurveTo(l,u+d,c+h,p,c,p),this.bezierCurveTo(c-h,p,t,u+d,t,u),this.bezierCurveTo(t,u-d,c-h,e,c,e),this.bezierCurveTo(c+h,e,l,u-d,l,u),this.lineTo(l,f),this.bezierCurveTo(l,f+d,c+h,m,c,m),this.bezierCurveTo(c-h,m,t,f+d,t,f),this.lineTo(t,u)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,s){var n=t-s*Math.cos(i),o=e-s*Math.sin(i),r=t-.9*s*Math.cos(i),a=e-.9*s*Math.sin(i),h=n+s/3*Math.cos(i+.5*Math.PI),d=o+s/3*Math.sin(i+.5*Math.PI),l=n+s/3*Math.cos(i-.5*Math.PI),p=o+s/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,d),this.lineTo(r,a),this.lineTo(l,p),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,s,n){n||(n=[10,5]),0==c&&(c=.001);var o=n.length;this.moveTo(t,e);for(var r=i-t,a=s-e,h=a/r,d=Math.sqrt(r*r+a*a),l=0,p=!0;d>=.1;){var c=n[l++%o];c>d&&(c=d);var u=Math.sqrt(c*c/(1+h*h));0>r&&(u=-u),t+=u,e+=h*u,this[p?"lineTo":"moveTo"](t,e),d-=c,p=!p}}),x.prototype.attachEdge=function(t){-1==this.edges.indexOf(t)&&this.edges.push(t),this._updateMass()},x.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&this.edges.splice(e,1),this._updateMass()},x.prototype._updateMass=function(){this.mass=50+20*this.edges.length},x.prototype.setProperties=function(t,e){if(t){if(void 0!=t.id&&(this.id=t.id),void 0!=t.label&&(this.label=t.label),void 0!=t.title&&(this.title=t.title),void 0!=t.group&&(this.group=t.group),void 0!=t.x&&(this.x=t.x),void 0!=t.y&&(this.y=t.y),void 0!=t.value&&(this.value=t.value),void 0===this.id)throw"Node must have an id";if(this.group){var i=this.grouplist.get(this.group);for(var s in i)i.hasOwnProperty(s)&&(this[s]=i[s])}if(void 0!=t.shape&&(this.shape=t.shape),void 0!=t.image&&(this.image=t.image),void 0!=t.radius&&(this.radius=t.radius),void 0!=t.color&&(this.color=x.parseColor(t.color)),void 0!=t.fontColor&&(this.fontColor=t.fontColor),void 0!=t.fontSize&&(this.fontSize=t.fontSize),void 0!=t.fontFace&&(this.fontFace=t.fontFace),void 0!=this.image){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.image)}switch(this.xFixed=this.xFixed||void 0!=t.x,this.yFixed=this.yFixed||void 0!=t.y,this.radiusFixed=this.radiusFixed||void 0!=t.radius,"image"==this.shape&&(this.radiusMin=e.nodes.widthMin,this.radiusMax=e.nodes.widthMax),this.shape){case"database":this.draw=this._drawDatabase,this.resize=this._resizeDatabase;break;case"box":this.draw=this._drawBox,this.resize=this._resizeBox;break;case"circle":this.draw=this._drawCircle,this.resize=this._resizeCircle;break;case"ellipse":this.draw=this._drawEllipse,this.resize=this._resizeEllipse;break;case"image":this.draw=this._drawImage,this.resize=this._resizeImage;break;case"text":this.draw=this._drawText,this.resize=this._resizeText;break;case"dot":this.draw=this._drawDot,this.resize=this._resizeShape;break;case"square":this.draw=this._drawSquare,this.resize=this._resizeShape;break;case"triangle":this.draw=this._drawTriangle,this.resize=this._resizeShape;break;case"triangleDown":this.draw=this._drawTriangleDown,this.resize=this._resizeShape;break;case"star":this.draw=this._drawStar,this.resize=this._resizeShape;break;default:this.draw=this._drawEllipse,this.resize=this._resizeEllipse}this._reset()}},x.parseColor=function(t){var e;return D.isString(t)?e={border:t,background:t,highlight:{border:t,background:t}}:(e={},e.background=t.background||"white",e.border=t.border||e.background,D.isString(t.highlight)?e.highlight={border:t.highlight,background:t.highlight}:(e.highlight={},e.highlight.background=t.highlight&&t.highlight.background||e.background,e.highlight.border=t.highlight&&t.highlight.border||e.border)),e},x.prototype.select=function(){this.selected=!0,this._reset()},x.prototype.unselect=function(){this.selected=!1,this._reset()},x.prototype._reset=function(){this.width=void 0,this.height=void 0},x.prototype.getTitle=function(){return this.title},x.prototype.distanceToBorder=function(t,e){var i=1;switch(this.width||this.resize(t),this.shape){case"circle":case"dot":return this.radius+i;case"ellipse":var s=this.width/2,n=this.height/2,o=Math.sin(e)*s,r=Math.cos(e)*n;return s*n/Math.sqrt(o*o+r*r);case"box":case"image":case"text":default:return this.width?Math.min(Math.abs(this.width/2/Math.cos(e)),Math.abs(this.height/2/Math.sin(e)))+i:0}},x.prototype._setForce=function(t,e){this.fx=t,this.fy=e},x.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},x.prototype.discreteStep=function(t){if(!this.xFixed){var e=-this.damping*this.vx,i=(this.fx+e)/this.mass;this.vx+=i/t,this.x+=this.vx/t}if(!this.yFixed){var s=-this.damping*this.vy,n=(this.fy+s)/this.mass;this.vy+=n/t,this.y+=this.vy/t}},x.prototype.isFixed=function(){return this.xFixed&&this.yFixed},x.prototype.isMoving=function(t){return Math.abs(this.vx)>t||Math.abs(this.vy)>t||!this.xFixed&&Math.abs(this.fx)>this.minForce||!this.yFixed&&Math.abs(this.fy)>this.minForce},x.prototype.isSelected=function(){return this.selected},x.prototype.getValue=function(){return this.value},x.prototype.getDistance=function(t,e){var i=this.x-t,s=this.y-e;return Math.sqrt(i*i+s*s)},x.prototype.setValueRange=function(t,e){if(!this.radiusFixed&&void 0!==this.value){var i=(this.radiusMax-this.radiusMin)/(e-t);this.radius=(this.value-t)*i+this.radiusMin}},x.prototype.draw=function(){throw"Draw method not initialized for node"},x.prototype.resize=function(){throw"Resize method not initialized for node"},x.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},x.prototype._resizeImage=function(){if(!this.width){var t,e;if(this.value){var i=this.imageObj.height/this.imageObj.width;t=this.radius||this.imageObj.width,e=this.radius*i||this.imageObj.height}else t=this.imageObj.width,e=this.imageObj.height;this.width=t,this.height=e}},x.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e;this.imageObj?(t.drawImage(this.imageObj,this.left,this.top,this.width,this.height),e=this.y+this.height/2):e=this.y,this._label(t,this.label,this.x,e,void 0,"top")},x.prototype._resizeBox=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e}},x.prototype._drawBox=function(t){this._resizeBox(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,t.roundRect(this.left,this.top,this.width,this.height,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},x.prototype._resizeDatabase=function(t){if(!this.width){var e=5,i=this.getTextSize(t),s=i.width+2*e;this.width=s,this.height=s}},x.prototype._drawDatabase=function(t){this._resizeDatabase(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,t.database(this.x-this.width/2,this.y-.5*this.height,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},x.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),s=Math.max(i.width,i.height)+2*e;this.radius=s/2,this.width=s,this.height=s}},x.prototype._drawCircle=function(t){this._resizeCircle(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,t.circle(this.x,this.y,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},x.prototype._resizeEllipse=function(t){if(!this.width){var e=this.getTextSize(t);this.width=1.5*e.width,this.height=2*e.height,this.widthl;l++)t.fillText(r[l],i,d),d+=h}},x.prototype.getTextSize=function(t){if(void 0!=this.label){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace;for(var e=this.label.split("\n"),i=(this.fontSize+4)*e.length,s=0,n=0,o=e.length;o>n;n++)s=Math.max(s,t.measureText(e[n]).width);return{width:s,height:i}}return{width:0,height:0}},T.prototype.setProperties=function(t,e){if(t)switch(void 0!=t.from&&(this.fromId=t.from),void 0!=t.to&&(this.toId=t.to),void 0!=t.id&&(this.id=t.id),void 0!=t.style&&(this.style=t.style),void 0!=t.label&&(this.label=t.label),this.label&&(this.fontSize=e.edges.fontSize,this.fontFace=e.edges.fontFace,this.fontColor=e.edges.fontColor,void 0!=t.fontColor&&(this.fontColor=t.fontColor),void 0!=t.fontSize&&(this.fontSize=t.fontSize),void 0!=t.fontFace&&(this.fontFace=t.fontFace)),void 0!=t.title&&(this.title=t.title),void 0!=t.width&&(this.width=t.width),void 0!=t.value&&(this.value=t.value),void 0!=t.length&&(this.length=t.length),t.dash&&(void 0!=t.dash.length&&(this.dash.length=t.dash.length),void 0!=t.dash.gap&&(this.dash.gap=t.dash.gap),void 0!=t.dash.altLength&&(this.dash.altLength=t.dash.altLength)),void 0!=t.color&&(this.color=t.color),this.connect(),this.widthFixed=this.widthFixed||void 0!=t.width,this.lengthFixed=this.lengthFixed||void 0!=t.length,this.stiffness=1/this.length,this.style){case"line":this.draw=this._drawLine;break;case"arrow":this.draw=this._drawArrow;break;case"arrow-center":this.draw=this._drawArrowCenter;break;case"dash-line":this.draw=this._drawDashLine;break;default:this.draw=this._drawLine}},T.prototype.connect=function(){this.disconnect(),this.from=this.graph.nodes[this.fromId]||null,this.to=this.graph.nodes[this.toId]||null,this.connected=this.from&&this.to,this.connected?(this.from.attachEdge(this),this.to.attachEdge(this)):(this.from&&this.from.detachEdge(this),this.to&&this.to.detachEdge(this))},T.prototype.disconnect=function(){this.from&&(this.from.detachEdge(this),this.from=null),this.to&&(this.to.detachEdge(this),this.to=null),this.connected=!1},T.prototype.getTitle=function(){return this.title},T.prototype.getValue=function(){return this.value},T.prototype.setValueRange=function(t,e){if(!this.widthFixed&&void 0!==this.value){var i=(this.widthMax-this.widthMin)/(e-t);this.width=(this.value-t)*i+this.widthMin}},T.prototype.draw=function(){throw"Method draw not initialized in edge"},T.prototype.isOverlappingWith=function(t){var e=10,i=this.from.x,s=this.from.y,n=this.to.x,o=this.to.y,r=t.left,a=t.top,h=T._dist(i,s,n,o,r,a);return e>h},T.prototype._drawLine=function(t){t.strokeStyle=this.color,t.lineWidth=this._getLineWidth();var e;if(this.from!=this.to)this._line(t),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y));else{var i,s,n=this.length/4,o=this.from;o.width||o.resize(t),o.width>o.height?(i=o.x+o.width/2,s=o.y-n):(i=o.x+n,s=o.y-o.height/2),this._circle(t,i,s,n),e=this._pointOnCircle(i,s,n,.5),this._label(t,this.label,e.x,e.y)}},T.prototype._getLineWidth=function(){return this.from.selected||this.to.selected?Math.min(2*this.width,this.widthMax):this.width},T.prototype._line=function(t){t.beginPath(),t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y),t.stroke()},T.prototype._circle=function(t,e,i,s){t.beginPath(),t.arc(e,i,s,0,2*Math.PI,!1),t.stroke()},T.prototype._label=function(t,e,i,s){if(e){t.font=(this.from.selected||this.to.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle="white";var n=t.measureText(e).width,o=this.fontSize,r=i-n/2,a=s-o/2;t.fillRect(r,a,n,o),t.fillStyle=this.fontColor||"black",t.textAlign="left",t.textBaseline="top",t.fillText(e,r,a)}},T.prototype._drawDashLine=function(t){if(t.strokeStyle=this.color,t.lineWidth=this._getLineWidth(),t.beginPath(),t.lineCap="round",void 0!=this.dash.altLength?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]):void 0!=this.dash.length&&void 0!=this.dash.gap?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap]):(t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y)),t.stroke(),this.label){var e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}},T.prototype._pointOnLine=function(t){return{x:(1-t)*this.from.x+t*this.to.x,y:(1-t)*this.from.y+t*this.to.y}},T.prototype._pointOnCircle=function(t,e,i,s){var n=2*(s-3/8)*Math.PI;return{x:t+i*Math.cos(n),y:e-i*Math.sin(n)}},T.prototype._drawArrowCenter=function(t){var e;if(t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth(),this.from!=this.to){this._line(t);var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),s=10+5*this.width;e=this._pointOnLine(.5),t.arrow(e.x,e.y,i,s),t.fill(),t.stroke(),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y))}else{var n,o,r=this.length/4,a=this.from;a.width||a.resize(t),a.width>a.height?(n=a.x+a.width/2,o=a.y-r):(n=a.x+r,o=a.y-a.height/2),this._circle(t,n,o,r);var i=.2*Math.PI,s=10+5*this.width;e=this._pointOnCircle(n,o,r,.5),t.arrow(e.x,e.y,i,s),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(n,o,r,.5),this._label(t,this.label,e.x,e.y))}},T.prototype._drawArrow=function(t){t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth();var e,i;if(this.from!=this.to){e=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x);var s=this.to.x-this.from.x,n=this.to.y-this.from.y,o=Math.sqrt(s*s+n*n),r=this.from.distanceToBorder(t,e+Math.PI),a=(o-r)/o,h=a*this.from.x+(1-a)*this.to.x,d=a*this.from.y+(1-a)*this.to.y,l=this.to.distanceToBorder(t,e),p=(o-l)/o,c=(1-p)*this.from.x+p*this.to.x,u=(1-p)*this.from.y+p*this.to.y;if(t.beginPath(),t.moveTo(h,d),t.lineTo(c,u),t.stroke(),i=10+5*this.width,t.arrow(c,u,e,i),t.fill(),t.stroke(),this.label){var f=this._pointOnLine(.5);this._label(t,this.label,f.x,f.y)}}else{var m,g,v,y=this.from,b=this.length/4;y.width||y.resize(t),y.width>y.height?(m=y.x+y.width/2,g=y.y-b,v={x:m,y:y.y,angle:.9*Math.PI}):(m=y.x+b,g=y.y-y.height/2,v={x:y.x,y:g,angle:.6*Math.PI}),t.beginPath(),t.arc(m,g,b,0,2*Math.PI,!1),t.stroke(),i=10+5*this.width,t.arrow(v.x,v.y,v.angle,i),t.fill(),t.stroke(),this.label&&(f=this._pointOnCircle(m,g,b,.5),this._label(t,this.label,f.x,f.y))}},T._dist=function(t,e,i,s,n,o){var r=i-t,a=s-e,h=r*r+a*a,d=((n-t)*r+(o-e)*a)/h; +d>1?d=1:0>d&&(d=0);var l=t+d*r,p=e+d*a,c=l-n,u=p-o;return Math.sqrt(c*c+u*u)},S.prototype.setPosition=function(t,e){this.x=parseInt(t),this.y=parseInt(e)},S.prototype.setText=function(t){this.frame.innerHTML=t},S.prototype.show=function(t){if(void 0===t&&(t=!0),t){var e=this.frame.clientHeight,i=this.frame.clientWidth,s=this.frame.parentNode.clientHeight,n=this.frame.parentNode.clientWidth,o=this.y-e;o+e+this.padding>s&&(o=s-e-this.padding),this.padding>o&&(o=this.padding);var r=this.x;r+i+this.padding>n&&(r=n-i-this.padding),this.padding>r&&(r=this.padding),this.frame.style.left=r+"px",this.frame.style.top=o+"px",this.frame.style.visibility="visible"}else this.hide()},S.prototype.hide=function(){this.frame.style.visibility="hidden"},Groups=function(){this.clear(),this.defaultIndex=0},Groups.DEFAULT=[{border:"#2B7CE9",background:"#97C2FC",highlight:{border:"#2B7CE9",background:"#D2E5FF"}},{border:"#FFA500",background:"#FFFF00",highlight:{border:"#FFA500",background:"#FFFFA3"}},{border:"#FA0A10",background:"#FB7E81",highlight:{border:"#FA0A10",background:"#FFAFB1"}},{border:"#41A906",background:"#7BE141",highlight:{border:"#41A906",background:"#A1EC76"}},{border:"#E129F0",background:"#EB7DF4",highlight:{border:"#E129F0",background:"#F0B3F5"}},{border:"#7C29F0",background:"#AD85E4",highlight:{border:"#7C29F0",background:"#D3BDF0"}},{border:"#C37F00",background:"#FFA807",highlight:{border:"#C37F00",background:"#FFCA66"}},{border:"#4220FB",background:"#6E6EFD",highlight:{border:"#4220FB",background:"#9B9BFD"}},{border:"#FD5A77",background:"#FFC0CB",highlight:{border:"#FD5A77",background:"#FFD1D9"}},{border:"#4AD63A",background:"#C2FABC",highlight:{border:"#4AD63A",background:"#E6FFE3"}}],Groups.prototype.clear=function(){this.groups={},this.groups.length=function(){var t=0;for(var e in this)this.hasOwnProperty(e)&&t++;return t}},Groups.prototype.get=function(t){var e=this.groups[t];if(void 0==e){var i=this.defaultIndex%Groups.DEFAULT.length;this.defaultIndex++,e={},e.color=Groups.DEFAULT[i],this.groups[t]=e}return e},Groups.prototype.add=function(t,e){return this.groups[t]=e,e.color&&(e.color=x.parseColor(e.color)),e},Images=function(){this.images={},this.callback=void 0},Images.prototype.setOnloadCallback=function(t){this.callback=t},Images.prototype.load=function(t){var e=this.images[t];if(void 0==e){var i=this;e=new Image,this.images[t]=e,e.onload=function(){i.callback&&i.callback(this)},e.src=t}return e},M.prototype.setData=function(t){if(t&&t.dot&&(t.nodes||t.edges))throw new SyntaxError('Data must contain either parameter "dot" or parameter pair "nodes" and "edges", but not both.');if(this.setOptions(t&&t.options),t&&t.dot){if(t&&t.dot){var e=N.util.DOTToGraph(t.dot);return this.setData(e),void 0}}else this._setNodes(t&&t.nodes),this._setEdges(t&&t.edges);this.stabilize&&this._doStabilize(),this.start()},M.prototype.setOptions=function(t){if(t){if(void 0!=t.width&&(this.width=t.width),void 0!=t.height&&(this.height=t.height),void 0!=t.stabilize&&(this.stabilize=t.stabilize),void 0!=t.selectable&&(this.selectable=t.selectable),t.edges){for(var e in t.edges)t.edges.hasOwnProperty(e)&&(this.constants.edges[e]=t.edges[e]);void 0!=t.edges.length&&t.nodes&&void 0==t.nodes.distance&&(this.constants.edges.length=t.edges.length,this.constants.nodes.distance=1.25*t.edges.length),t.edges.fontColor||(this.constants.edges.fontColor=t.edges.color),t.edges.dash&&(void 0!=t.edges.dash.length&&(this.constants.edges.dash.length=t.edges.dash.length),void 0!=t.edges.dash.gap&&(this.constants.edges.dash.gap=t.edges.dash.gap),void 0!=t.edges.dash.altLength&&(this.constants.edges.dash.altLength=t.edges.dash.altLength))}if(t.nodes){for(e in t.nodes)t.nodes.hasOwnProperty(e)&&(this.constants.nodes[e]=t.nodes[e]);t.nodes.color&&(this.constants.nodes.color=x.parseColor(t.nodes.color))}if(t.groups)for(var i in t.groups)if(t.groups.hasOwnProperty(i)){var s=t.groups[i];this.groups.add(i,s)}}this.setSize(this.width,this.height),this._setTranslation(this.frame.clientWidth/2,this.frame.clientHeight/2),this._setScale(1)},M.prototype._trigger=function(t,e){O.trigger(this,t,e)},M.prototype._create=function(){for(;this.containerElement.hasChildNodes();)this.containerElement.removeChild(this.containerElement.firstChild);if(this.frame=document.createElement("div"),this.frame.className="graph-frame",this.frame.style.position="relative",this.frame.style.overflow="hidden",this.frame.canvas=document.createElement("canvas"),this.frame.canvas.style.position="relative",this.frame.appendChild(this.frame.canvas),!this.frame.canvas.getContext){var t=document.createElement("DIV");t.style.color="red",t.style.fontWeight="bold",t.style.padding="10px",t.innerHTML="Error: your browser does not support HTML canvas",this.frame.canvas.appendChild(t)}var e=this,i=function(t){e._onMouseDown(t)},s=function(t){e._onMouseMoveTitle(t)},n=function(t){e._onMouseWheel(t)},o=function(t){e._onTouchStart(t)};N.util.addEventListener(this.frame.canvas,"mousedown",i),N.util.addEventListener(this.frame.canvas,"mousemove",s),N.util.addEventListener(this.frame.canvas,"mousewheel",n),N.util.addEventListener(this.frame.canvas,"touchstart",o),this.containerElement.appendChild(this.frame)},M.prototype._onMouseDown=function(t){if(t=t||window.event,this.selectable&&(this.leftButtonDown&&this._onMouseUp(t),this.leftButtonDown=t.which?1==t.which:1==t.button,this.leftButtonDown||this.touchDown)){var e=this;this.onmousemove||(this.onmousemove=function(t){e._onMouseMove(t)},N.util.addEventListener(document,"mousemove",e.onmousemove)),this.onmouseup||(this.onmouseup=function(t){e._onMouseUp(t)},N.util.addEventListener(document,"mouseup",e.onmouseup)),N.util.preventDefault(t),this.startMouseX=D.getPageX(t),this.startMouseY=D.getPageY(t),this.startFrameLeft=N.util.getAbsoluteLeft(this.frame.canvas),this.startFrameTop=N.util.getAbsoluteTop(this.frame.canvas),this.startTranslation=this._getTranslation(),this.ctrlKeyDown=t.ctrlKey,this.shiftKeyDown=t.shiftKey;var i={left:this._xToCanvas(this.startMouseX-this.startFrameLeft),top:this._yToCanvas(this.startMouseY-this.startFrameTop),right:this._xToCanvas(this.startMouseX-this.startFrameLeft),bottom:this._yToCanvas(this.startMouseY-this.startFrameTop)},s=this._getNodesOverlappingWith(i);if(this.startClickedObj=s.length>0?s[s.length-1]:void 0,this.startClickedObj){var n=this.nodes[this.startClickedObj];this.startClickedObj.xFixed=n.xFixed,this.startClickedObj.yFixed=n.yFixed,n.xFixed=!0,n.yFixed=!0,this.ctrlKeyDown&&n.isSelected()?this._unselectNodes([this.startClickedObj]):this._selectNodes([this.startClickedObj],this.ctrlKeyDown),this.moving||this._redraw()}else this.shiftKeyDown||(this.moved=!1)}},M.prototype._onMouseMove=function(t){if(t=t||window.event,this.selectable){var e=D.getPageX(t),i=D.getPageY(t);if(this.mouseX=e,this.mouseY=i,this.startClickedObj){var s=this.nodes[this.startClickedObj];this.startClickedObj.xFixed||(s.x=this._xToCanvas(e-this.startFrameLeft)),this.startClickedObj.yFixed||(s.y=this._yToCanvas(i-this.startFrameTop)),this.moving||(this.moving=!0,this.start())}else if(this.shiftKeyDown){void 0==this.frame.selRect&&(this.frame.selRect=document.createElement("DIV"),this.frame.appendChild(this.frame.selRect),this.frame.selRect.style.position="absolute",this.frame.selRect.style.border="1px dashed red");var n=Math.min(this.startMouseX,e)-this.startFrameLeft,o=Math.min(this.startMouseY,i)-this.startFrameTop,r=Math.max(this.startMouseX,e)-this.startFrameLeft,a=Math.max(this.startMouseY,i)-this.startFrameTop;this.frame.selRect.style.left=n+"px",this.frame.selRect.style.top=o+"px",this.frame.selRect.style.width=r-n+"px",this.frame.selRect.style.height=a-o+"px"}else{var h=e-this.startMouseX,d=i-this.startMouseY;this._setTranslation(this.startTranslation.x+h,this.startTranslation.y+d),this._redraw(),this.moved=!0}N.util.preventDefault(t)}},M.prototype._onMouseUp=function(t){if(t=t||window.event,this.selectable){this.onmousemove&&(N.util.removeEventListener(document,"mousemove",this.onmousemove),this.onmousemove=void 0),this.onmouseup&&(N.util.removeEventListener(document,"mouseup",this.onmouseup),this.onmouseup=void 0),N.util.preventDefault(t);var e=D.getPageX(t)||this.mouseX||0,i=D.getPageY(t)||this.mouseY||0,s=t?t.ctrlKey:window.event.ctrlKey;if(this.startClickedObj){var n=this.nodes[this.startClickedObj];n.xFixed=this.startClickedObj.xFixed,n.yFixed=this.startClickedObj.yFixed}else if(this.shiftKeyDown){var o={left:this._xToCanvas(Math.min(this.startMouseX,e)-this.startFrameLeft),top:this._yToCanvas(Math.min(this.startMouseY,i)-this.startFrameTop),right:this._xToCanvas(Math.max(this.startMouseX,e)-this.startFrameLeft),bottom:this._yToCanvas(Math.max(this.startMouseY,i)-this.startFrameTop)},r=this._getNodesOverlappingWith(o);this._selectNodes(r,s),this.redraw(),this.frame.selRect&&(this.frame.removeChild(this.frame.selRect),this.frame.selRect=void 0)}else this.ctrlKeyDown||this.moved||(this._unselectNodes(),this._redraw());this.leftButtonDown=!1,this.ctrlKeyDown=!1}},M.prototype._onMouseWheel=function(t){t=t||window.event;var e=D.getPageX(t),i=D.getPageY(t),s=0;if(t.wheelDelta?s=t.wheelDelta/120:t.detail&&(s=-t.detail/3),s){var n=s/10;0>s&&(n/=1-n);var o=this._getScale(),r=o*(1+n);.01>r&&(r=.01),r>10&&(r=10);var a=N.util.getAbsoluteLeft(this.frame.canvas),h=N.util.getAbsoluteTop(this.frame.canvas),d=e-a,l=i-h,p=this._getTranslation(),c=r/o,u=(1-c)*d+p.x*c,f=(1-c)*l+p.y*c;this._setScale(r),this._setTranslation(u,f),this._redraw()}N.util.preventDefault(t)},M.prototype._onMouseMoveTitle=function(t){t=t||window.event;var e=D.getPageX(t),i=D.getPageY(t);this.startFrameLeft=this.startFrameLeft||N.util.getAbsoluteLeft(this.frame.canvas),this.startFrameTop=this.startFrameTop||N.util.getAbsoluteTop(this.frame.canvas);var s=e-this.startFrameLeft,n=i-this.startFrameTop;this.popupNode&&this._checkHidePopup(s,n);var o=this,r=function(){o._checkShowPopup(s,n)};this.popupTimer&&clearInterval(this.popupTimer),this.leftButtonDown||(this.popupTimer=setTimeout(r,300))},M.prototype._checkShowPopup=function(t,e){var i,s={left:this._xToCanvas(t),top:this._yToCanvas(e),right:this._xToCanvas(t),bottom:this._yToCanvas(e)},n=this.popupNode;if(void 0==this.popupNode){var o=this.nodes;for(i in o)if(o.hasOwnProperty(i)){var r=o[i];if(void 0!=r.getTitle()&&r.isOverlappingWith(s)){this.popupNode=r;break}}}if(void 0==this.popupNode){var a=this.edges;for(i in a)if(a.hasOwnProperty(i)){var h=a[i];if(h.connected&&void 0!=h.getTitle()&&h.isOverlappingWith(s)){this.popupNode=h;break}}}if(this.popupNode){if(this.popupNode!=n){var d=this;d.popup||(d.popup=new S(d.frame)),d.popup.setPosition(t-3,e-3),d.popup.setText(d.popupNode.getTitle()),d.popup.show()}}else this.popup&&this.popup.hide()},M.prototype._checkHidePopup=function(t,e){var i={left:t,top:e,right:t,bottom:e};this.popupNode&&this.popupNode.isOverlappingWith(i)||(this.popupNode=void 0,this.popup&&this.popup.hide())},M.prototype._onTouchStart=function(t){if(N.util.preventDefault(t),!this.touchDown){this.touchDown=!0;var e=this;this.ontouchmove||(this.ontouchmove=function(t){e._onTouchMove(t)},N.util.addEventListener(document,"touchmove",this.ontouchmove)),this.ontouchend||(this.ontouchend=function(t){e._onTouchEnd(t)},N.util.addEventListener(document,"touchend",this.ontouchend)),this._onMouseDown(t)}},M.prototype._onTouchMove=function(t){N.util.preventDefault(t),this._onMouseMove(t)},M.prototype._onTouchEnd=function(t){N.util.preventDefault(t),this.touchDown=!1,this.ontouchmove&&(N.util.removeEventListener(document,"touchmove",this.ontouchmove),this.ontouchmove=void 0),this.ontouchend&&(N.util.removeEventListener(document,"touchend",this.ontouchend),this.ontouchend=void 0),this._onMouseUp(t)},M.prototype._unselectNodes=function(t,e){var i,s,n,o=!1;if(t)for(i=0,s=t.length;s>i;i++){n=t[i],this.nodes[n].unselect();for(var r=0;this.selection.length>r;)this.selection[r]==n?(this.selection.splice(r,1),o=!0):r++}else if(this.selection&&this.selection.length){for(i=0,s=this.selection.length;s>i;i++)n=this.selection[i],this.nodes[n].unselect(),o=!0;this.selection=[]}return!o||1!=e&&void 0!=e||this._trigger("select"),o},M.prototype._selectNodes=function(t,e){var i,s,n=!1,o=!0;if(t.length!=this.selection.length)o=!1;else for(i=0,s=Math.min(t.length,this.selection.length);s>i;i++)if(t[i]!=this.selection[i]){o=!1;break}if(o)return n;if(void 0==e||0==e){var r=!1;n=this._unselectNodes(void 0,r)}for(i=0,s=t.length;s>i;i++){var a=t[i],h=-1!=this.selection.indexOf(a);h||(this.nodes[a].select(),this.selection.push(a),n=!0)}return n&&this._trigger("select"),n},M.prototype._getNodesOverlappingWith=function(t){var e=this.nodes,i=[];for(var s in e)e.hasOwnProperty(s)&&e[s].isOverlappingWith(t)&&i.push(s);return i},M.prototype.getSelection=function(){return this.selection.concat([])},M.prototype.setSelection=function(t){var e,i,s;if(void 0==t.length)throw"Selection must be an array with ids";for(e=0,i=this.selection.length;i>e;e++)s=this.selection[e],this.nodes[s].unselect();for(this.selection=[],e=0,i=t.length;i>e;e++){s=t[e];var n=this.nodes[s];if(!n)throw new RangeError('Node with id "'+s+'" not found');n.select(),this.selection.push(s)}this.redraw()},M.prototype._updateSelection=function(){for(var t=0;this.selection.length>t;){var e=this.selection[t];this.nodes[e]?t++:this.selection.splice(t,1)}},M.prototype._getConnectionCount=function(t){function e(t){for(var e=[],i=0,s=t.length;s>i;i++)for(var n=t[i],o=n.edges,r=0,a=o.length;a>r;r++){var h=o[r],d=null;h.from==n?d=h.to:h.to==n&&(d=h.from);var l,p;if(d)for(l=0,p=t.length;p>l;l++)if(t[l]==d){d=null;break}if(d)for(l=0,p=e.length;p>l;l++)if(e[l]==d){d=null;break}d&&e.push(d)}return e}void 0==t&&(t=1);var i=[],s=this.nodes;for(var n in s)if(s.hasOwnProperty(n)){for(var o=[s[n]],r=0;t>r;r++)o=o.concat(e(o));i.push(o)}for(var a=[],h=0,d=i.length;d>h;h++)a.push(i[h].length);return a},M.prototype.setSize=function(t,e){this.frame.style.width=t,this.frame.style.height=e,this.frame.canvas.style.width="100%",this.frame.canvas.style.height="100%",this.frame.canvas.width=this.frame.canvas.clientWidth,this.frame.canvas.height=this.frame.canvas.clientHeight},M.prototype._setNodes=function(t){var e=this.nodesData;if(t instanceof o||t instanceof r)this.nodesData=t;else if(t instanceof Array)this.nodesData=new o,this.nodesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.nodesData=new o}if(e&&D.forEach(this.nodesListeners,function(t,i){e.unsubscribe(i,t)}),this.nodes={},this.nodesData){var i=this;D.forEach(this.nodesListeners,function(t,e){i.nodesData.subscribe(e,t)});var s=this.nodesData.getIds();this._addNodes(s)}this._updateSelection()},M.prototype._addNodes=function(t){for(var e,i=0,s=t.length;s>i;i++){e=t[i];var n=this.nodesData.get(e),o=new x(n,this.images,this.groups,this.constants);if(this.nodes[e]=o,!o.isFixed()){var r=2*this.constants.edges.length,a=t.length,h=2*Math.PI*(i/a);o.x=r*Math.cos(h),o.y=r*Math.sin(h),this.moving=!0}}this._reconnectEdges(),this._updateValueRange(this.nodes)},M.prototype._updateNodes=function(t){for(var e=this.nodes,i=this.nodesData,s=0,n=t.length;n>s;s++){var o=t[s],r=e[o],a=i.get(o);r?r.setProperties(a,this.constants):(r=new x(properties,this.images,this.groups,this.constants),e[o]=r,r.isFixed()||(this.moving=!0))}this._reconnectEdges(),this._updateValueRange(e)},M.prototype._removeNodes=function(t){for(var e=this.nodes,i=0,s=t.length;s>i;i++){var n=t[i];delete e[n]}this._reconnectEdges(),this._updateSelection(),this._updateValueRange(e)},M.prototype._setEdges=function(t){var e=this.edgesData;if(t instanceof o||t instanceof r)this.edgesData=t;else if(t instanceof Array)this.edgesData=new o,this.edgesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.edgesData=new o}if(e&&D.forEach(this.edgesListeners,function(t,i){e.unsubscribe(i,t)}),this.edges={},this.edgesData){var i=this;D.forEach(this.edgesListeners,function(t,e){i.edgesData.subscribe(e,t)});var s=this.edgesData.getIds();this._addEdges(s)}this._reconnectEdges()},M.prototype._addEdges=function(t){for(var e=this.edges,i=this.edgesData,s=0,n=t.length;n>s;s++){var o=t[s],r=e[o];r&&r.disconnect();var a=i.get(o);e[o]=new T(a,this,this.constants)}this.moving=!0,this._updateValueRange(e)},M.prototype._updateEdges=function(t){for(var e=this.edges,i=this.edgesData,s=0,n=t.length;n>s;s++){var o=t[s],r=i.get(o),a=e[o];a?(a.disconnect(),a.setProperties(r,this.constants),a.connect()):(a=new T(r,this,this.constants),this.edges[o]=a)}this.moving=!0,this._updateValueRange(e)},M.prototype._removeEdges=function(t){for(var e=this.edges,i=0,s=t.length;s>i;i++){var n=t[i],o=e[n];o&&(o.disconnect(),delete e[n])}this.moving=!0,this._updateValueRange(e)},M.prototype._reconnectEdges=function(){var t,e=this.nodes,i=this.edges;for(t in e)e.hasOwnProperty(t)&&(e[t].edges=[]);for(t in i)if(i.hasOwnProperty(t)){var s=i[t];s.from=null,s.to=null,s.connect()}},M.prototype._updateValueRange=function(t){var e,i=void 0,s=void 0;for(e in t)if(t.hasOwnProperty(e)){var n=t[e].getValue();void 0!==n&&(i=void 0===i?n:Math.min(n,i),s=void 0===s?n:Math.max(n,s))}if(void 0!==i&&void 0!==s)for(e in t)t.hasOwnProperty(e)&&t[e].setValueRange(i,s)},M.prototype.redraw=function(){this.setSize(this.width,this.height),this._redraw()},M.prototype._redraw=function(){var t=this.frame.canvas.getContext("2d"),e=this.frame.canvas.width,i=this.frame.canvas.height;t.clearRect(0,0,e,i),t.save(),t.translate(this.translation.x,this.translation.y),t.scale(this.scale,this.scale),this._drawEdges(t),this._drawNodes(t),t.restore()},M.prototype._setTranslation=function(t,e){void 0===this.translation&&(this.translation={x:0,y:0}),void 0!==t&&(this.translation.x=t),void 0!==e&&(this.translation.y=e)},M.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},M.prototype._setScale=function(t){this.scale=t},M.prototype._getScale=function(){return this.scale},M.prototype._xToCanvas=function(t){return(t-this.translation.x)/this.scale},M.prototype._canvasToX=function(t){return t*this.scale+this.translation.x},M.prototype._yToCanvas=function(t){return(t-this.translation.y)/this.scale},M.prototype._canvasToY=function(t){return t*this.scale+this.translation.y},M.prototype._drawNodes=function(t){var e=this.nodes,i=[];for(var s in e)e.hasOwnProperty(s)&&(e[s].isSelected()?i.push(s):e[s].draw(t));for(var n=0,o=i.length;o>n;n++)e[i[n]].draw(t)},M.prototype._drawEdges=function(t){var e=this.edges;for(var i in e)if(e.hasOwnProperty(i)){var s=e[i];s.connected&&e[i].draw(t)}},M.prototype._doStabilize=function(){new Date;for(var t=0,e=this.constants.minVelocity,i=!1;!i&&this.constants.maxIterations>t;)this._calculateForces(),this._discreteStepNodes(),i=!this._isMoving(e),t++;new Date},M.prototype._calculateForces=function(){var t,e,i,s,n,o,r,a,h,d,l,p=this.nodes,c=this.edges,u=.01,f=this.frame.canvas.clientWidth/2,m=this.frame.canvas.clientHeight/2;for(t in p)if(p.hasOwnProperty(t)){var g=p[t];e=f-g.x,i=m-g.y,s=Math.atan2(i,e),o=Math.cos(s)*u,r=Math.sin(s)*u,g._setForce(o,r)}var v=this.constants.nodes.distance,y=10;for(var b in p)if(p.hasOwnProperty(b)){var w=p[b];for(var _ in p)if(p.hasOwnProperty(_)){var x=p[_];e=x.x-w.x,i=x.y-w.y,n=Math.sqrt(e*e+i*i),s=Math.atan2(i,e),a=1/(1+Math.exp((n/v-1)*y)),o=Math.cos(s)*a,r=Math.sin(s)*a,w._addForce(-o,-r),x._addForce(o,r)}}for(t in c)if(c.hasOwnProperty(t)){var T=c[t];T.connected&&(e=T.to.x-T.from.x,i=T.to.y-T.from.y,l=T.length,d=Math.sqrt(e*e+i*i),s=Math.atan2(i,e),h=T.stiffness*(l-d),o=Math.cos(s)*h,r=Math.sin(s)*h,T.from._addForce(-o,-r),T.to._addForce(o,r))}},M.prototype._isMoving=function(t){var e=this.nodes;for(var i in e)if(e.hasOwnProperty(i)&&e[i].isMoving(t))return!0;return!1},M.prototype._discreteStepNodes=function(){var t=this.refreshRate/1e3,e=this.nodes;for(var i in e)e.hasOwnProperty(i)&&e[i].discreteStep(t)},M.prototype.start=function(){if(this.moving){this._calculateForces(),this._discreteStepNodes();var t=this.constants.minVelocity;this.moving=this._isMoving(t)}if(this.moving){if(!this.timer){var e=this;this.timer=window.setTimeout(function(){e.timer=void 0,e.start(),e._redraw()},this.refreshRate)}}else this._redraw()},M.prototype.stop=function(){this.timer&&(window.clearInterval(this.timer),this.timer=void 0)};var N={util:D,events:O,Controller:d,DataSet:o,DataView:r,Range:h,Stack:a,TimeStep:TimeStep,EventBus:n,components:{items:{Item:m,ItemBox:g,ItemPoint:v,ItemRange:y},Component:l,Panel:p,RootPanel:c,ItemSet:f,TimeAxis:u},graph:{Node:x,Edge:T,Popup:S,Groups:Groups,Images:Images},Timeline:_,Graph:M};s!==void 0&&(s=N),i!==void 0&&i.exports!==void 0&&(i.exports=N),"function"==typeof t&&t(function(){return N}),"undefined"!=typeof window&&(window.vis=N),D.loadCss("/* vis.js stylesheet */\n.vis.timeline {\n}\n\n\n.vis.timeline.rootpanel {\n position: relative;\n overflow: hidden;\n\n border: 1px solid #bfbfbf;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n\n.vis.timeline .panel {\n position: absolute;\n overflow: hidden;\n}\n\n\n.vis.timeline .groupset {\n position: absolute;\n padding: 0;\n margin: 0;\n}\n\n.vis.timeline .labels {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n\n padding: 0;\n margin: 0;\n\n border-right: 1px solid #bfbfbf;\n box-sizing: border-box;\n -moz-box-sizing: border-box;\n}\n\n.vis.timeline .labels .label {\n position: absolute;\n left: 0;\n top: 0;\n width: 100%;\n border-bottom: 1px solid #bfbfbf;\n color: #4d4d4d;\n}\n\n.vis.timeline .labels .label .inner {\n display: inline-block;\n padding: 5px;\n}\n\n\n.vis.timeline .itemset {\n position: absolute;\n padding: 0;\n margin: 0;\n overflow: hidden;\n}\n\n.vis.timeline .background {\n}\n\n.vis.timeline .foreground {\n}\n\n.vis.timeline .itemset-axis {\n position: absolute;\n}\n\n.vis.timeline .groupset .itemset-axis {\n border-top: 1px solid #bfbfbf;\n}\n\n/* TODO: with orientation=='bottom', this will more or less overlap with timeline axis\n.vis.timeline .groupset .itemset-axis:last-child {\n border-top: none;\n}\n*/\n\n\n.vis.timeline .item {\n position: absolute;\n color: #1A1A1A;\n border-color: #97B0F8;\n background-color: #D5DDF6;\n display: inline-block;\n}\n\n.vis.timeline .item.selected {\n border-color: #FFC200;\n background-color: #FFF785;\n z-index: 999;\n}\n\n.vis.timeline .item.cluster {\n /* TODO: use another color or pattern? */\n background: #97B0F8 url('img/cluster_bg.png');\n color: white;\n}\n.vis.timeline .item.cluster.point {\n border-color: #D5DDF6;\n}\n\n.vis.timeline .item.box {\n text-align: center;\n border-style: solid;\n border-width: 1px;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.point {\n background: none;\n}\n\n.vis.timeline .dot {\n border: 5px solid #97B0F8;\n position: absolute;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.range {\n overflow: hidden;\n border-style: solid;\n border-width: 1px;\n border-radius: 2px;\n -moz-border-radius: 2px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.range .drag-left {\n cursor: w-resize;\n z-index: 1000;\n}\n\n.vis.timeline .item.range .drag-right {\n cursor: e-resize;\n z-index: 1000;\n}\n\n.vis.timeline .item.range .content {\n position: relative;\n display: inline-block;\n}\n\n.vis.timeline .item.line {\n position: absolute;\n width: 0;\n border-left-width: 1px;\n border-left-style: solid;\n}\n\n.vis.timeline .item .content {\n margin: 5px;\n white-space: nowrap;\n overflow: hidden;\n}\n\n.vis.timeline .axis {\n position: relative;\n}\n\n.vis.timeline .axis .text {\n position: absolute;\n color: #4d4d4d;\n padding: 3px;\n white-space: nowrap;\n}\n\n.vis.timeline .axis .text.measure {\n position: absolute;\n padding-left: 0;\n padding-right: 0;\n margin-left: 0;\n margin-right: 0;\n visibility: hidden;\n}\n\n.vis.timeline .axis .grid.vertical {\n position: absolute;\n width: 0;\n border-right: 1px solid;\n}\n\n.vis.timeline .axis .grid.horizontal {\n position: absolute;\n left: 0;\n width: 100%;\n height: 0;\n border-bottom: 1px solid;\n}\n\n.vis.timeline .axis .grid.minor {\n border-color: #e5e5e5;\n}\n\n.vis.timeline .axis .grid.major {\n border-color: #bfbfbf;\n}\n\n")})()},{moment:2}],2:[function(e,i){(function(){(function(s){function n(t,e){return function(i){return p(t.call(this,i),e)}}function o(t){return function(e){return this.lang().ordinal(t.call(this,e))}}function r(){}function a(t){d(this,t)}function h(t){var e=this._data={},i=t.years||t.year||t.y||0,s=t.months||t.month||t.M||0,n=t.weeks||t.week||t.w||0,o=t.days||t.day||t.d||0,r=t.hours||t.hour||t.h||0,a=t.minutes||t.minute||t.m||0,h=t.seconds||t.second||t.s||0,d=t.milliseconds||t.millisecond||t.ms||0;this._milliseconds=d+1e3*h+6e4*a+36e5*r,this._days=o+7*n,this._months=s+12*i,e.milliseconds=d%1e3,h+=l(d/1e3),e.seconds=h%60,a+=l(h/60),e.minutes=a%60,r+=l(a/60),e.hours=r%24,o+=l(r/24),o+=7*n,e.days=o%30,s+=l(o/30),e.months=s%12,i+=l(s/12),e.years=i}function d(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function l(t){return 0>t?Math.ceil(t):Math.floor(t)}function p(t,e){for(var i=t+"";e>i.length;)i="0"+i;return i}function c(t,e,i){var s,n=e._milliseconds,o=e._days,r=e._months;n&&t._d.setTime(+t+n*i),o&&t.date(t.date()+o*i),r&&(s=t.date(),t.date(1).month(t.month()+r*i).date(Math.min(s,t.daysInMonth())))}function u(t){return"[object Array]"===Object.prototype.toString.call(t)}function f(t,e){var i,s=Math.min(t.length,e.length),n=Math.abs(t.length-e.length),o=0;for(i=0;s>i;i++)~~t[i]!==~~e[i]&&o++;return o+n}function m(t,e){return e.abbr=t,z[t]||(z[t]=new r),z[t].set(e),z[t]}function g(t){return t?(!z[t]&&H&&e("./lang/"+t),z[t]):I.fn._lang}function v(t){return t.match(/\[.*\]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function y(t){var e,i,s=t.match(j);for(e=0,i=s.length;i>e;e++)s[e]=ae[s[e]]?ae[s[e]]:v(s[e]);return function(n){var o="";for(e=0;i>e;e++)o+="function"==typeof s[e].call?s[e].call(n,t):s[e];return o}}function b(t,e){function i(e){return t.lang().longDateFormat(e)||e}for(var s=5;s--&&U.test(e);)e=e.replace(U,i);return ne[e]||(ne[e]=y(e)),ne[e](t)}function w(t){switch(t){case"DDDD":return q;case"YYYY":return V;case"YYYYY":return X;case"S":case"SS":case"SSS":case"DDD":return B;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":case"a":case"A":return K;case"X":return J;case"Z":case"ZZ":return G;case"T":return Z;case"MM":case"DD":case"YY":case"HH":case"hh":case"mm":case"ss":case"M":case"D":case"d":case"H":case"h":case"m":case"s":return W;default:return RegExp(t.replace("\\",""))}}function _(t,e,i){var s,n=i._a;switch(t){case"M":case"MM":n[1]=null==e?0:~~e-1;break;case"MMM":case"MMMM":s=g(i._l).monthsParse(e),null!=s?n[1]=s:i._isValid=!1;break;case"D":case"DD":case"DDD":case"DDDD":null!=e&&(n[2]=~~e);break;case"YY":n[0]=~~e+(~~e>68?1900:2e3);break;case"YYYY":case"YYYYY":n[0]=~~e;break;case"a":case"A":i._isPm="pm"===(e+"").toLowerCase();break;case"H":case"HH":case"h":case"hh":n[3]=~~e;break;case"m":case"mm":n[4]=~~e;break;case"s":case"ss":n[5]=~~e;break;case"S":case"SS":case"SSS":n[6]=~~(1e3*("0."+e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,s=(e+"").match(ee),s&&s[1]&&(i._tzh=~~s[1]),s&&s[2]&&(i._tzm=~~s[2]),s&&"+"===s[0]&&(i._tzh=-i._tzh,i._tzm=-i._tzm)}null==e&&(i._isValid=!1)}function x(t){var e,i,s=[];if(!t._d){for(e=0;7>e;e++)t._a[e]=s[e]=null==t._a[e]?2===e?1:0:t._a[e];s[3]+=t._tzh||0,s[4]+=t._tzm||0,i=new Date(0),t._useUTC?(i.setUTCFullYear(s[0],s[1],s[2]),i.setUTCHours(s[3],s[4],s[5],s[6])):(i.setFullYear(s[0],s[1],s[2]),i.setHours(s[3],s[4],s[5],s[6])),t._d=i}}function T(t){var e,i,s=t._f.match(j),n=t._i;for(t._a=[],e=0;s.length>e;e++)i=(w(s[e]).exec(n)||[])[0],i&&(n=n.slice(n.indexOf(i)+i.length)),ae[s[e]]&&_(s[e],i,t);t._isPm&&12>t._a[3]&&(t._a[3]+=12),t._isPm===!1&&12===t._a[3]&&(t._a[3]=0),x(t)}function S(t){for(var e,i,s,n,o=99;t._f.length;){if(e=d({},t),e._f=t._f.pop(),T(e),i=new a(e),i.isValid()){s=i;break}n=f(e._a,i.toArray()),o>n&&(o=n,s=i)}d(t,s)}function M(t){var e,i=t._i;if(Q.exec(i)){for(t._f="YYYY-MM-DDT",e=0;4>e;e++)if(te[e][1].exec(i)){t._f+=te[e][0];break}G.exec(i)&&(t._f+=" Z"),T(t)}else t._d=new Date(i)}function E(t){var e=t._i,i=R.exec(e);e===s?t._d=new Date:i?t._d=new Date(+i[1]):"string"==typeof e?M(t):u(e)?(t._a=e.slice(0),x(t)):t._d=e instanceof Date?new Date(+e):new Date(e)}function D(t,e,i,s,n){return n.relativeTime(e||1,!!i,t,s)}function C(t,e,i){var s=Y(Math.abs(t)/1e3),n=Y(s/60),o=Y(n/60),r=Y(o/24),a=Y(r/365),h=45>s&&["s",s]||1===n&&["m"]||45>n&&["mm",n]||1===o&&["h"]||22>o&&["hh",o]||1===r&&["d"]||25>=r&&["dd",r]||45>=r&&["M"]||345>r&&["MM",Y(r/30)]||1===a&&["y"]||["yy",a];return h[2]=e,h[3]=t>0,h[4]=i,D.apply({},h)}function L(t,e,i){var s=i-e,n=i-t.day();return n>s&&(n-=7),s-7>n&&(n+=7),Math.ceil(I(t).add("d",n).dayOfYear()/7)}function O(t){var e=t._i,i=t._f;return null===e||""===e?null:("string"==typeof e&&(t._i=e=g().preparse(e)),I.isMoment(e)?(t=d({},e),t._d=new Date(+e._d)):i?u(i)?S(t):T(t):E(t),new a(t))}function N(t,e){I.fn[t]=I.fn[t+"s"]=function(t){var i=this._isUTC?"UTC":"";return null!=t?(this._d["set"+i+e](t),this):this._d["get"+i+e]()}}function A(t){I.duration.fn[t]=function(){return this._data[t]}}function k(t,e){I.duration.fn["as"+t]=function(){return+this/e}}for(var I,F,P="2.0.0",Y=Math.round,z={},H=i!==s&&i.exports,R=/^\/?Date\((\-?\d+)/i,j=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYY|YYYY|YY|a|A|hh?|HH?|mm?|ss?|SS?S?|X|zz?|ZZ?|.)/g,U=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,W=/\d\d?/,B=/\d{1,3}/,q=/\d{3}/,V=/\d{1,4}/,X=/[+\-]?\d{1,6}/,K=/[0-9]*[a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF]+\s*?[\u0600-\u06FF]+/i,G=/Z|[\+\-]\d\d:?\d\d/i,Z=/T/i,J=/[\+\-]?\d+(\.\d{1,3})?/,Q=/^\s*\d{4}-\d\d-\d\d((T| )(\d\d(:\d\d(:\d\d(\.\d\d?\d?)?)?)?)?([\+\-]\d\d:?\d\d)?)?/,$="YYYY-MM-DDTHH:mm:ssZ",te=[["HH:mm:ss.S",/(T| )\d\d:\d\d:\d\d\.\d{1,3}/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],ee=/([\+\-]|\d\d)/gi,ie="Month|Date|Hours|Minutes|Seconds|Milliseconds".split("|"),se={Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6},ne={},oe="DDD w W M D d".split(" "),re="M D H h m s w W".split(" "),ae={M:function(){return this.month()+1},MMM:function(t){return this.lang().monthsShort(this,t)},MMMM:function(t){return this.lang().months(this,t)},D:function(){return this.date()},DDD:function(){return this.dayOfYear()},d:function(){return this.day()},dd:function(t){return this.lang().weekdaysMin(this,t)},ddd:function(t){return this.lang().weekdaysShort(this,t)},dddd:function(t){return this.lang().weekdays(this,t)},w:function(){return this.week()},W:function(){return this.isoWeek()},YY:function(){return p(this.year()%100,2)},YYYY:function(){return p(this.year(),4)},YYYYY:function(){return p(this.year(),5)},a:function(){return this.lang().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.lang().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return~~(this.milliseconds()/100)},SS:function(){return p(~~(this.milliseconds()/10),2)},SSS:function(){return p(this.milliseconds(),3)},Z:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(~~(t/60),2)+":"+p(~~t%60,2)},ZZ:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(~~(10*t/6),4)},X:function(){return this.unix()}};oe.length;)F=oe.pop(),ae[F+"o"]=o(ae[F]);for(;re.length;)F=re.pop(),ae[F+F]=n(ae[F],2);for(ae.DDDD=n(ae.DDD,3),r.prototype={set:function(t){var e,i;for(i in t)e=t[i],"function"==typeof e?this[i]=e:this["_"+i]=e +},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(t){return this._months[t.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(t){return this._monthsShort[t.month()]},monthsParse:function(t){var e,i,s;for(this._monthsParse||(this._monthsParse=[]),e=0;12>e;e++)if(this._monthsParse[e]||(i=I([2e3,e]),s="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[e]=RegExp(s.replace(".",""),"i")),this._monthsParse[e].test(t))return e},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(t){return this._weekdays[t.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(t){return this._weekdaysShort[t.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(t){return this._weekdaysMin[t.day()]},_longDateFormat:{LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D YYYY",LLL:"MMMM D YYYY LT",LLLL:"dddd, MMMM D YYYY LT"},longDateFormat:function(t){var e=this._longDateFormat[t];return!e&&this._longDateFormat[t.toUpperCase()]&&(e=this._longDateFormat[t.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t]=e),e},meridiem:function(t,e,i){return t>11?i?"pm":"PM":i?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[last] dddd [at] LT",sameElse:"L"},calendar:function(t,e){var i=this._calendar[t];return"function"==typeof i?i.apply(e):i},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(t,e,i,s){var n=this._relativeTime[i];return"function"==typeof n?n(t,e,i,s):n.replace(/%d/i,t)},pastFuture:function(t,e){var i=this._relativeTime[t>0?"future":"past"];return"function"==typeof i?i(e):i.replace(/%s/i,e)},ordinal:function(t){return this._ordinal.replace("%d",t)},_ordinal:"%d",preparse:function(t){return t},postformat:function(t){return t},week:function(t){return L(t,this._week.dow,this._week.doy)},_week:{dow:0,doy:6}},I=function(t,e,i){return O({_i:t,_f:e,_l:i,_isUTC:!1})},I.utc=function(t,e,i){return O({_useUTC:!0,_isUTC:!0,_l:i,_i:t,_f:e})},I.unix=function(t){return I(1e3*t)},I.duration=function(t,e){var i,s=I.isDuration(t),n="number"==typeof t,o=s?t._data:n?{}:t;return n&&(e?o[e]=t:o.milliseconds=t),i=new h(o),s&&t.hasOwnProperty("_lang")&&(i._lang=t._lang),i},I.version=P,I.defaultFormat=$,I.lang=function(t,e){return t?(e?m(t,e):z[t]||g(t),I.duration.fn._lang=I.fn._lang=g(t),s):I.fn._lang._abbr},I.langData=function(t){return t&&t._lang&&t._lang._abbr&&(t=t._lang._abbr),g(t)},I.isMoment=function(t){return t instanceof a},I.isDuration=function(t){return t instanceof h},I.fn=a.prototype={clone:function(){return I(this)},valueOf:function(){return+this._d},unix:function(){return Math.floor(+this._d/1e3)},toString:function(){return this.format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._d},toJSON:function(){return I.utc(this).format("YYYY-MM-DD[T]HH:mm:ss.SSS[Z]")},toArray:function(){var t=this;return[t.year(),t.month(),t.date(),t.hours(),t.minutes(),t.seconds(),t.milliseconds()]},isValid:function(){return null==this._isValid&&(this._isValid=this._a?!f(this._a,(this._isUTC?I.utc(this._a):I(this._a)).toArray()):!isNaN(this._d.getTime())),!!this._isValid},utc:function(){return this._isUTC=!0,this},local:function(){return this._isUTC=!1,this},format:function(t){var e=b(this,t||I.defaultFormat);return this.lang().postformat(e)},add:function(t,e){var i;return i="string"==typeof t?I.duration(+e,t):I.duration(t,e),c(this,i,1),this},subtract:function(t,e){var i;return i="string"==typeof t?I.duration(+e,t):I.duration(t,e),c(this,i,-1),this},diff:function(t,e,i){var s,n,o=this._isUTC?I(t).utc():I(t).local(),r=6e4*(this.zone()-o.zone());return e&&(e=e.replace(/s$/,"")),"year"===e||"month"===e?(s=432e5*(this.daysInMonth()+o.daysInMonth()),n=12*(this.year()-o.year())+(this.month()-o.month()),n+=(this-I(this).startOf("month")-(o-I(o).startOf("month")))/s,"year"===e&&(n/=12)):(s=this-o-r,n="second"===e?s/1e3:"minute"===e?s/6e4:"hour"===e?s/36e5:"day"===e?s/864e5:"week"===e?s/6048e5:s),i?n:l(n)},from:function(t,e){return I.duration(this.diff(t)).lang(this.lang()._abbr).humanize(!e)},fromNow:function(t){return this.from(I(),t)},calendar:function(){var t=this.diff(I().startOf("day"),"days",!0),e=-6>t?"sameElse":-1>t?"lastWeek":0>t?"lastDay":1>t?"sameDay":2>t?"nextDay":7>t?"nextWeek":"sameElse";return this.format(this.lang().calendar(e,this))},isLeapYear:function(){var t=this.year();return 0===t%4&&0!==t%100||0===t%400},isDST:function(){return this.zone()+I(t).startOf(e)},isBefore:function(t,e){return e=e!==s?e:"millisecond",+this.clone().startOf(e)<+I(t).startOf(e)},isSame:function(t,e){return e=e!==s?e:"millisecond",+this.clone().startOf(e)===+I(t).startOf(e)},zone:function(){return this._isUTC?0:this._d.getTimezoneOffset()},daysInMonth:function(){return I.utc([this.year(),this.month()+1,0]).date()},dayOfYear:function(t){var e=Y((I(this).startOf("day")-I(this).startOf("year"))/864e5)+1;return null==t?e:this.add("d",t-e)},isoWeek:function(t){var e=L(this,1,4);return null==t?e:this.add("d",7*(t-e))},week:function(t){var e=this.lang().week(this);return null==t?e:this.add("d",7*(t-e))},lang:function(t){return t===s?this._lang:(this._lang=g(t),this)}},F=0;ie.length>F;F++)N(ie[F].toLowerCase().replace(/s$/,""),ie[F]);N("year","FullYear"),I.fn.days=I.fn.day,I.fn.weeks=I.fn.week,I.fn.isoWeeks=I.fn.isoWeek,I.duration.fn=h.prototype={weeks:function(){return l(this.days()/7)},valueOf:function(){return this._milliseconds+864e5*this._days+2592e6*this._months},humanize:function(t){var e=+this,i=C(e,!t,this.lang());return t&&(i=this.lang().pastFuture(e,i)),this.lang().postformat(i)},lang:I.fn.lang};for(F in se)se.hasOwnProperty(F)&&(k(F,se[F]),A(F.toLowerCase()));k("Weeks",6048e5),I.lang("en",{ordinal:function(t){var e=t%10,i=1===~~(t%100/10)?"th":1===e?"st":2===e?"nd":3===e?"rd":"th";return t+i}}),H&&(i.exports=I),"undefined"==typeof ender&&(this.moment=I),"function"==typeof t&&t.amd&&t("moment",[],function(){return I})}).call(this)})()},{}]},{},[1])(1)}); \ No newline at end of file From 65e763c7a284d7bdf6efb14073f7a854e726868b Mon Sep 17 00:00:00 2001 From: josdejong Date: Thu, 20 Jun 2013 16:02:07 +0200 Subject: [PATCH 17/52] Examples upated --- examples/graph/02_random_nodes.html | 2 +- examples/graph/07_selections.html | 19 +- .../graph/15_dot_language_playground.html | 11 +- examples/graph/16_dynamic_data.html | 265 ++++++++++++++++++ examples/graph/graphviz/graphviz_gallery.html | 2 - examples/timeline/02_dataset.html | 8 +- examples/timeline/03_much_data.html | 2 +- examples/timeline/05_groups.html | 7 +- img/gallery/graph/16_dynamic_data.png | Bin 0 -> 17832 bytes index.html | 6 + 10 files changed, 291 insertions(+), 31 deletions(-) create mode 100644 examples/graph/16_dynamic_data.html create mode 100644 img/gallery/graph/16_dynamic_data.png diff --git a/examples/graph/02_random_nodes.html b/examples/graph/02_random_nodes.html index a3de91a5..b048a69d 100755 --- a/examples/graph/02_random_nodes.html +++ b/examples/graph/02_random_nodes.html @@ -88,7 +88,7 @@ // add event listeners vis.events.addListener(graph, 'select', function(params) { document.getElementById('selection').innerHTML = - 'Selection: ' + JSON.stringify(graph.getSelection()); + 'Selection: ' + graph.getSelection(); }); } diff --git a/examples/graph/07_selections.html b/examples/graph/07_selections.html index 25c761e2..421c3794 100644 --- a/examples/graph/07_selections.html +++ b/examples/graph/07_selections.html @@ -52,24 +52,13 @@ // add event listener function onSelect() { - var selection = graph.getSelection(); - - var info = 'selection: '; - selection.forEach(function (s) { - info += s.row + ' '; - }); - - document.getElementById('info').innerHTML += info + '
'; + document.getElementById('info').innerHTML += + 'selection: ' + graph.getSelection().join(', ') + '
'; } vis.events.addListener(graph, 'select', onSelect); - // set initial selection (row based, zero-based) - var selection = [ - {'row': 2}, - {'row': 3}, - {'row': 4} - ]; - graph.setSelection(selection); + // set initial selection (id's of some nodes) + graph.setSelection([3, 4, 5]); diff --git a/examples/graph/15_dot_language_playground.html b/examples/graph/15_dot_language_playground.html index a6e96c86..bf757cd8 100644 --- a/examples/graph/15_dot_language_playground.html +++ b/examples/graph/15_dot_language_playground.html @@ -48,7 +48,7 @@ } - + @@ -140,8 +140,7 @@ digraph { A -> A[label=0.5]; B -> B[label=1.2] -> C[label=0.7] -- A; B -> D; - D -> B; - D -> C; + D -> {B; C} D -> E[label=0.2]; F -> F; A [ @@ -199,11 +198,5 @@ digraph G { } - - diff --git a/examples/graph/16_dynamic_data.html b/examples/graph/16_dynamic_data.html new file mode 100644 index 00000000..b4ccb596 --- /dev/null +++ b/examples/graph/16_dynamic_data.html @@ -0,0 +1,265 @@ + + + + Graph | DataSet + + + + + + + + + + + +

+ This example demonstrates dynamically adding, updating and removing nodes + and edges using a DataSet. +

+ +

Adjust

+
+ + + + + +
+

Node

+ + + + + + + + + + + + + + + + +
Action + + + +
+
+

Edge

+ + + + + + + + + + + + + + + + + + + + + +
Action + + + +
+
+ +

View

+ + + + + + + + + + + + + +
+

Nodes

+

+        
+

Edges

+

+        
+

Graph

+
+
+ + + diff --git a/examples/graph/graphviz/graphviz_gallery.html b/examples/graph/graphviz/graphviz_gallery.html index c5d96ed2..3260187d 100644 --- a/examples/graph/graphviz/graphviz_gallery.html +++ b/examples/graph/graphviz/graphviz_gallery.html @@ -57,9 +57,7 @@ -

diff --git a/examples/timeline/02_dataset.html b/examples/timeline/02_dataset.html index 81c1d0dd..c1987abd 100644 --- a/examples/timeline/02_dataset.html +++ b/examples/timeline/02_dataset.html @@ -7,12 +7,15 @@ body, html { font-family: arial, sans-serif; font-size: 11pt; + height: 100%; + margin: 0; + padding: 0; } #visualization { box-sizing: border-box; width: 100%; - height: 300px; + height: 100%; } @@ -26,7 +29,7 @@ // create a dataset with items var items = new vis.DataSet({ - fieldTypes: { + convert: { start: 'Date', end: 'Date' } @@ -44,6 +47,7 @@ var options = { start: now.clone().add('days', -3), end: now.clone().add('days', 7), + orientation: 'top', height: '100%' }; diff --git a/examples/timeline/03_much_data.html b/examples/timeline/03_much_data.html index 36221ad7..5d778975 100644 --- a/examples/timeline/03_much_data.html +++ b/examples/timeline/03_much_data.html @@ -27,7 +27,7 @@ // create a dataset with items var now = moment().minutes(0).seconds(0).milliseconds(0); var items = new vis.DataSet({ - fieldTypes: { + convert: { start: 'Date', end: 'Date' } diff --git a/examples/timeline/05_groups.html b/examples/timeline/05_groups.html index 42ae2d1c..880a7326 100644 --- a/examples/timeline/05_groups.html +++ b/examples/timeline/05_groups.html @@ -19,6 +19,11 @@ +

+ This example demonstrate using groups. Note that a DataSet is used for both + items and groups, allowing to dynamically add, update or remove both items + and groups via the DataSet. +

+ + + + + + +
+ + + + \ No newline at end of file diff --git a/examples/graph/index.html b/examples/graph/index.html index 04691215..0fd44cfb 100644 --- a/examples/graph/index.html +++ b/examples/graph/index.html @@ -2,7 +2,7 @@ - vis.js | examples + vis.js | graph examples @@ -10,7 +10,7 @@ diff --git a/img/external-link-icons/external-link-icon.png b/img/external-link-icons/external-link-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..29b21e958aeca356111da513eb69923f5fd23479 GIT binary patch literal 194 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 literal 0 HcmV?d00001 diff --git a/index.html b/index.html index 479b818a..167ebbeb 100644 --- a/index.html +++ b/index.html @@ -28,22 +28,31 @@
  • Install
  • Example
  • Gallery
  • -
  • Docs
  • +
  • + + Docs + + +
  • License
  • -

    vis.js

    +

    + vis.js
    + a visual interaction system +

    Vis.js is a dynamic, browser based visualization library. The library is designed to be easy to use, to handle large amounts - of dynamic data, and to enable manipulation of the data. + of dynamic data, and to enable manipulation of and interaction with the data. The library consists of the components DataSet, Timeline, and Graph.

    - The vis.js library is developed by Almende B.V. + The vis.js library is developed by Almende B.V, + as part of the CHAP.

    @@ -270,6 +279,12 @@ bower install vis
    dynamic data
    +
    From 6300445ca700054661f895d50f24e2f6eda5c945 Mon Sep 17 00:00:00 2001 From: josdejong Date: Fri, 20 Sep 2013 12:22:13 +0200 Subject: [PATCH 20/52] Updated to v0.2.0 --- docs/css/style.css | 14 +- docs/graph.html | 6 +- docs/img/vis_overview.odg | Bin 30379 -> 32645 bytes docs/img/vis_overview.png | Bin 65183 -> 49562 bytes docs/index.html | 7 + examples/graph/17_network_info.html | 57 +- examples/timeline/02_dataset.html | 3 + examples/timeline/03_much_data.html | 3 + examples/timeline/05_groups.html | 3 + examples/timeline/index.html | 4 +- img/gallery/graph/17_network_info.png | Bin 101101 -> 61961 bytes index.html | 8 +- vis.js | 22659 +++++++++++++----------- vis.min.js | 14 +- 14 files changed, 12308 insertions(+), 10470 deletions(-) diff --git a/docs/css/style.css b/docs/css/style.css index e8db5f80..14ba2183 100644 --- a/docs/css/style.css +++ b/docs/css/style.css @@ -22,18 +22,12 @@ body, td, th { } h1 { - font-size: 220%; + font-size: 180%; font-weight: bold; padding: 0; margin: 1em 0 1em 0; } -h1 .subtitle { - color: lightgray; - font-size: 11pt; - text-transform: uppercase; -} - h2 { padding-top: 20px; padding-bottom: 10px; @@ -45,13 +39,19 @@ h3 { font-size: 140%; } +a > img { + border: none; +} + a { color: #2B7CE9; text-decoration: none; } + a:visited { color: #2E60A4; } + a:hover { color: red; text-decoration: underline; diff --git a/docs/graph.html b/docs/graph.html index 0ccc5e4e..f196a732 100644 --- a/docs/graph.html +++ b/docs/graph.html @@ -831,10 +831,8 @@ var options = { selectable Boolean true - If true, nodes in the graph can be selected by clicking them, or - by keeping the Shift key down and dragging a selection area around them. - When the Ctrl key is down, the new selection is appended to the - previous selection. If not, the new selection replaces the previous selection. + If true, nodes in the graph can be selected by clicking them. + Long press can be used to select multiple nodes. diff --git a/docs/img/vis_overview.odg b/docs/img/vis_overview.odg index 27ef9772606aa8d9e7d6f5638d7d09d2395b720d..7659955f2fb858c383c3b5b082a352ee45b32523 100644 GIT binary patch delta 16806 zcma*PbyywCmOi|3g1ZNIC%A{;9v}pV;O?%Cy95vJ?(P=c-QC@tAYXFM%-nPD%uaAw(|1o)x%fp(si_qqMciN+cI9FHu|CO4tekr~ zET)Z&jZs>2)U1z#LX`P!|B!3_%U<0P`9004Wo8;{8WdO^1fcN)!)% zkT+4Q%VqW^>3xoStPF@alugh^SReW$D#Nkdc$i&1(tA8?%l74?D7Fscf;i8hv&zVp zwpz|C0j1qvr(}EB=WRp=lxi8OFEleWkTtG@(ZU`OGtTCFYwvOAnj2Lws{@)`l- z9Is#IBmUSWNcRgz-E{b%TDjq7{asmt+N-VgHad4%v8(eAuY$(_t^x6!EyDx8^#kj? z882!1pz*K5DC%nr)+yI&p^W<#4@uJcKk9)N)WnLcPZ2HA^|cvy`=?0y_9%IHDkuuf=~|=rZLN!>*DHtj zf=XDtWXf>%7dZaf&-5_x3(nx`yFZAoAhE;^x{@sc?)$An<=1+KyiKO3SEBH zy`H*~0M#H{yo~a`{KVVq*%FtX_BY90kpAOy6!IF@sKHUBvJGrxiicD9{33unJPIR8 zG83M{0wp~E6koyb!MfTFC1g{aBdq5oC^!_Kq)S(|x%JR2%MwZm9kf3h;l53oC>#Cd ztHxH^+s0%bI;U0M<1)_35B80buvu|8t2EIG&# z2yQVoZr_+plEL^kDT4jebG(2}U;8)~;IYK&ha=yxO_&dTj7Wb`)Uw;03gc0$h}7EB_v; zpX6&p}#U$>DgSs+%jt~a|wBNTXc5~JSMn*~os(FXM&mLVw>%qaugYzy^6WZb=&xMY_mIiZOr#fW=hG_R z$pki@0i@2Y;H%l28<8p1ESRG0tzm1s+E*i7xW}B$SMt42Od--VGcxY;N*?4P>NR~P zRC8t=u5H=e%JF|HdhC7sI)n9LXRm)2aj15|LC_H0Skf*SSOM_gmI5SC97na+EUyV6 zr~}u_v@XHCEXbM|!M#8F#PWhfz0W|Qpj9x8N!!&dD%^<(hf)odg2*#eTV&oE9*{%0 z=ys5!g{a90=-#Q`v?u1@o5xAL#7kGYN z(|nFE>%enY@1@{VR5hKeui;Lgi#5D-W^mE{{E*}_yaqj=%r*z|SPplU=#D*@CH( zS&O+qUJ9m*rce?EJ42(?rMj8i;ST6b-cE?tVqn#!cR>2GfzHlNHYw+!gUWCh*ZB<7 zgqvHwQrWAHzfOQkZf(lYNcXwKJUVKf#O~=tWa@hx@;yOX-Cb8<(_ZzJ>j?rCVZn4> zAkjk85*}diTcCIS((-_P>6!sZO0QKWo$?<0jr9a*I^l$^}K!av$^gt z?+x0Tzl8Y>2y^I#Bb+k|c27+gFDWlyhYozK@Y*1z*G~ONj*7$P6^;+t3{U1OSY&d^ z7oVxWUFdYiHP|Huh26`ClUR_t?6l`E7N+rL(SRu`h=d&KG{qH|-?NXmP?FPRG2LW#@e3XC|d zUs|T>xm|rq{L)VIx6)=}9zY?JdCrSa?ddw^mxUoz66-!zqRKf;C0BHF`JMd?4hRVF zPB{hfWNL;zr8W=xTpR&%j=a&Cw}xuJQblo!OxYZ|SOj-^mE)#Il+ ziAXJ`n%ix8*9_5G^boCCXu+v2FPHqy^s#re!gj*um?QRE1-z5HAI7|8=y+8>%>v9B zp7Wx)a?kAkc%wgdx7F+Qoq=M!m$jnM()9ffVQQs*R#NP%-#uY@yg6`}$ippb03>#S-;?b=1%$zGZHUhcRS1Z_dN!Ugn4KQRs%3pJ<1agpt+a4O;mo12l^x zNmjIBd9C4%W#_0o3IUH+$_1}=6BH$Yya&6SdNCVfQmtdt&qW}BL=gHYE;pXl&c5aj z7#*L`!up`mfbQN!-FjM+&`LSOHs|@P14FW?rHYmx^9zC2K5`8DblS$ADQW!cJ&Jro z`wyn*=nQr-+V^TGar)Uw*OA%!r5CL69OK18~Brj;@oOt z&AASpdgrLLq))*6?)9Dz7`v*iS#^5f^4_Ls z_{vA;MDjP>X*u+nJ|b1Qt(%Qcl+b3UN5oPCg;E&EA6qK!-x2b!^?fWWD0G| z0|NQ|7=G55P)eeUQt0K^ox#<5)dO*BEHB-VGa844doMUfWjUH|a)r)aR*tR2;Y#76l`t7Heqc;JdRpDZ9qw*BDyQJWL zlyBZw^zQkXVy%XQnW@!5eEEIFWB;4p+qW?U#5sMry2QH@cf&Fo`wymC6S-oKoRjF8nR=PlrrWA+>T#zVi-PupqqKcM2MN3SlUjJ)ZbTof; zXV8KA@8c$)6pJ}UDvZm&UHAQj>|L%EQ( zHp5Gb&(*urlVd`=5Vtl%d`yJ+heHu8ceu90RzADwwIt9ZZ>)WK^|L8qBx&2!;cUo8!Y@k5X?lIC|=+K_h#ju z?zi$q&?cmVHEOwV28TSx5~`xl-ru0fwaXFqFahaeA_mn<Z4NYzY4W^+3#D!WqF&sBmQN@scX~6(bs@2Mg-$K{3m- zHt%ERUTS)y%{>()s#4XRX5DCA2SPogXZ5&w2N}tnqDQ&U=YzHFTg6^$@ut?!xV1(v z$s{{w`5~=ub>I&^jfd$u?rarI$!)*lR>k5^y>tQVK@2<0_{Y%xp^femx1ciP{0VmP zbG{mv@AUa44Qr##+a*^B)(7SV}ghSpDR#^ zQA_~C!FTci?UH0Wf=$@eI!8D2nXMaPSu>t4200{sndBpHz}QBAev7O#LHr8k{NiVn z9bR9Pi<(c~9}8tPIfmsvSr!(YTafX|791R99V;3fzV7t^i4{xe?L9xz6lEHAhv$9^ z=NuQGYLK7{&9n#zK)|B3E|r?k8?j4V1Ox2{ljQQ(ag1ePM8j5KU;SA+gv}{Q2Ra$c z5xi+3%iJy5_~TUwdEy<#B6~T_+mx@16hSIxTY*_36^%-M+9Meqm-{D$jix-1R@`)o zcQSCKFo9(?8(1I9pYir;^T>B9JBnN^t4=C&7M-=tFQI&n)^>&z>=mQv*d!-YRDjNg zBao$cG>-d=>0(^5?L1%CXA-P$bK zk%lI+SdxbQkj#KH=j4eQKUA(eOyuz`Q`+Z3!9EodydA{#yaor|RXnBJQ((@s$16_G zbD)8g#pX`vh?w6(C~Iy75gvL*^RYyZA2a!|b||uEO!(L3_*f-2h-fwQ!Cn6{h?|}o>ESU()}Kal0F)Yb?v6zDVE)n z4^>-ifo6--&hO|lZj_luzc{{26{2P=LStoibjTE3tU8T{ZkIWZ+WiWgzj|KEQLQ@_ zl9q>+(0#NSs`uF!k3KJ39(&#h#w&w_GZn08Y3b8L{F+*S@hv#H zFQPj#YcqWW9SmX6;BtgZrvT~;yGDm29t}`a&TxhJ+sit#O?$_kcc)rhOZsD{H8{5X zo;<_yxxwC!e;=bdrsok*l!Pp>vVPm%xi!z@Ko@Tx>O2~512pK%6=f~2pmmwKa7ERi z{Zg+LmKx7D2;F9P5v2B(Q)!#6GPngIV{q@Ccus?LDkrt_iPDpU#2z40uLjhGZ5$z&`jKr~X|2*3!I-ewXck`52eWJdK-#iv*$(Oda+eVfARbq08#98R(2Q0;iwA36` zb8fYaf|%9aH0PpQPHu6#*g3Lm7y~`a^Xk)T9(|b?4*h$kBwK^|hAL?S=7l3#o`hsO zMm8xaQO%!Sdc^HOaWz3f9))b@AXaZb;EYp2g25ll1J|~pn|q#o(8E_cR_hoIhDB}x zkK60+R&96+0zabYTSq2UC<|}7G=iPVWX%qB#O1D2cnf}qPFZQJr>FNrDM?$o6pF!X zHujxZAIE{-DAUbSCJEw{`-iuRmKzmM-&?M|+&v9$XH!`K{1-ltq0&H{QNU{xzzUer zeWX>4ERP@=hi$6yzF`sIwA~NwWJS!OuHF?4*%Kxg=)qPyz4{8bh|(W9B2wDW+~6sD z?J_+0G3a5Uv(e&%tnp^o;ri;=>gj@q6uuYLxIK<#F}VbZypY?}N>00C?L_CKO+Y`e z<#Hhz%VQN7goU0TG7TB}{NWhcf%E{H){7jQb~$1$HkMLV-OKjcoIrH3d6azN*mre} zxYsdd%l_n;l(mGkTma~!SVMEV&S;>DExvJ&g_}xmr@G(h(S;jLy&-D7w<*)C>6jUG z{TWPB?7^ahB3L7{9RU>T9_B?T!pz<{mFD#O$AkkoYGRI zWcT~~e}?|LJsjyKD#M!}Hk|)y>}-9iey70gl@sBRc#Z%#GLGNa5Qc{vk{Hr z&JmxAvT5x*Tb-2v-109aVSlxKKh+p~POLNdD2i0_RrQ_NIBq~G$2f8O9I6RaYRvZ5 z_Bhr&!xDFCd5U4ikMwq~)LSaj$XT^aA%nh#JeT46lyuE$WWme*eXq(5cm2J!of-ZL zP7#26^e%mna#-34PyZ;7v)r@?5c^I#7qfQ|v*fVnZuDgu7=jV;8xt{t^e0|A8vy$>@Ry2c#^r z*>JXUu2<^Tv1;xZG9Pdn7=y@KV{L|T5xvwH)Y>I(r6lo!7zvtyx)5?U6FX^@l;3|n zRo-acy7XoDJYb_ITe^vYOFkZ^ik9| zyJy4nswHb8>4l!>b+BXOnNyBaz38_XlFC=)3y8VplgRT;$&()RokptBqLi5u370mB zyU){qp5jVlqHsK9@@lW@)$TpwUouJCyUDXB${A6{8?Q8}WGc^3BNmwLALG?MC{5qw zlOY1%BK5GSjt&(T0)U8O)c_oBqJPo zcWqtb@E~?ceydWoWhZ-Sk9lWx;!d$kRDcasD?XW`V-(!4R9&^++B19n z@H0cZH@UlP*C|a&(<E~!pJL+J8JM`a zCc^1HqI`pD?%P#P+m$wPeCe+(?t3Y_54xCv3&)$R5e2uq_umG+54tmyls{#tsR-5p z=XPHTPdN<6n-ZPB4rx~$_7~>dn@bK1!mM#GXMS+>3}2Y$tx8R|ucMJTH|j2B88}Zj zHsvZmp1*Bq2Xzpvq6CxQXgfW0Fdpv(L_2D__g9rjL3mmEvz;MjU@;w$sp3poRprYuKKM>uX!TvOBg_Q!e{&lD-n8q-;Rx-@ z+gMXT9U8FR+FOs|hlr6KiKB>PFh-yW4wfMwKrd!aPB;<`8GP%_GmFI6WAi#X5b$t) zVwm{tFY$HJ;>kN?Xf^3;m|ep93l%6NO&rWrpRmE%`j_Q3RkcU5jm?RCcu7y%Pu2FH zgNJO!oJga(dCn~?JMP%bKmXjls`SBLyS~tRbQ-`6zbhN@_(gd+vS%`U>%|NnGyrP8 z_IGv2s5Zje-RaV2A)CEIuOQ&+GaKQ$myZno#Yh=YGQ&0z-9t=Kh7Ab|mC1{2Q!Lkl zU1g*>|Kme}(g=42&I6P6cllx0djc>O!~>Ln-9Ce2n(N_45(X~CWhkwo@Ky@o(eJI> z#L4Q=pG>=fXPld#aW7rDD4-0#CZh`@kd=_x%6)Ir={pfErJ68-y|zPkQyuqEQQTq5 zkHnioFGP+VN_HND1HlfjUGOr{jjesM%Qvg}ZcRQ5S|B~)8}oq!ZKA_fkoou_WsV^; zx9MW2@E+p}gL`-Kwc^+9E=N=V^t%&cyipviyZL$q!^| zWY)j#{I|B$oiPufF8xs&+*Tw)Hk$0;Dg%H5yw6Ud#aghm{tlL(LK7Mj|D|1jV($N^ zQ`~rrWV`#-r$GW^Gn?1J%M9~?lrsC{A8PEM-TlAC50Kh~mcU!3NrhtD0m7B2vk4M^ z&Iw~NauY8J-#!FyQuVpCbnIP=_dINjOCAlgM5bQjax}k?R(0PyyPH~n^2{H)Ult!> zT5}g1kg2w+i`oCRvU1P=F!mYu2)N9Z?p|3blz_uI{fc)bKk%(+>>Lqvk!!eGbw!D! z?s|E?7T-om_IR(;G5!3B0NBY2)K8BVsPJSLrD6G+Bh9+^=B1{oEu&w#P?8~V|H*3%ADF-W4B#P# z^%I9ry?xqmA&@Kn{C<w?1un+15|42-#Vi*Y{Do;Si*Aa-K!dy&Uwc zJAJ{Mwfq!x`%MXS0O#_ahvJ3+xP`|~%?W=T)^Y4E-Bt_KKro0V=aKVVnX74UPO_#U zr@w;e+JJRINbBpA-d5B8`by8T>?WwTxjvh-@^)|5#*iZbknCEQ=H`bqWie|1l(c<| zQpt-E8f<@6l_2`3>7!cf2tr(?4ej>NRLu z4nm$P=t364QgT|vAKR)>b^C=PX~Wl%a;1E>&bvegSq2(+;}o#pi_NVh zFAmJmJ0<%!-3O?wrP4zH&*{0p*foQ=Or}SpQt-&xhTf=sUQ|jm#<%G+lGT(unnl7e zvEMWlQYQ7a-0wx0KQ?OR`doM3fo*4nvi+s+_f8Nn|1~$eIiByJHg}i6XV%E}9|Z<# ze>|8?le8$!6#OQ@zf>Kv?tJE8(4qbm^DLzU@#UED$OeEs{jn}X>Nv2BOeszvHS8Eo~Rll}iO*8~5r$sTQ0%M|kcmJ`D7sasWa zJLIf}&e=kmfzXHffQ=R%FHJomO^hV6vW|^&Za%tiF-^acXrIatZce3?j97`b@MGcb+|e&k25yn|9V~ zW9H`C>mA23P+*oN4RSawW9}5-aDF{l`+BHmyey4%*K4S)?nHVNE5p)6jgEWD+dlG(Y(_0#+OcxPyx{5go;b2XMNrW_xG^SPU?B^+pK*v)gKbl#z_2yo5jK5<< zyn1$t#xp^DXn_yym!;TiATczM*sn7<1>t^=Z*Xb>#JSU?koQT^%LTY~lk$GwnP%R=PFieVQMa?7XZWh!3E;W6C26dfK|7Pm-4-f_hJ=x+q8#xbIe z%oX*pe>9-l*eelRN(&%o!I41TFA%`eU>WtcX_ z=<+8(i4K9`aFX(JZErI^?M$2ZnWcBa%Z{l$Hc^zof^}kp_M_PVPczd|*sn*M;dyzp zB7EZ;-EQtYQ$wb0!EgQ|A_MX)RP`LpOIv?98B3T zv$i|g?5n=Q-^_xoisD29fGiJ&!^mp_(prc2F2U!rUrZOrBl#iG%%Q5%nJV`>57RFJ z&SkN`P1PSu^*0mze_Ew~a=l$z&Mq>H7t%jPoe#c2J{SKlehdT?4t{Sf%MkRrD(_ys%;{cfJLOy&MyK^tA1Xyds8bOw z_IK48F$1R(gb}yBl&iLzend|%F)aF}nJWSbkw9UR9TYE;0(5Q7^>$@Gu}};fpeGEH z>pOOUaxNqJvT5(?WbbziPs0#YwG~=>k`+CU<6p0NfTQFheF-L9fQ5@Q?~LJhX=>t6 ze&b{-X*JU33RmGq``M-9=VJwN?YQq{RGH}6_zH?2PoCaRP0olt7*&`#^cDK!Ipi;y z+QA{Y_kTj_BY$nHKdLT0u zw?6=DSYl5f=rz5@8VgUUFGK?sjXFJv7Dna%CNZsc9-Sfm%!y;O~dwol*;3dUD@NAy~>8Ceck z)4hZp5Iue0j~8G{?z1^j0kwlNT8NrK@#v04G<9ekAYsD9Z?oF?(Mq&QTqbKezgdqX3~tJ2;G$7q z!a;?1=ggTmHNvE402}?5@`2ikTepRqI^}wSBUq1(vmu!fy?A*1M=nSPA3rCMiesYT z4ON&VK-ymSvAiPBvB(*}mnD>1^UfCo?{&J7NX!kDxWS0K^;g`F7CG=^g|q1CUG3|v zT29dxz5yZiK6>WeLPZ6{{~|-ATy?xO>m(@w2NTdyi;Mma53u`v#=$8gD~l3*yUGOv ztYND?lzN!B)B5z|KLvsn-Khrf2-UEetR}@=DFx_ISLj!ago>*}c@U;dM-INr@CgdY zJqH-3dTCPDB;SfrK|Q2kV9S zx4F~;Sw(!IfiD*RcvbRa^2z&a6$+hVX!K6O<6Ew;NU(IT_Uus_^hCsDJc;gWx4{&x zwUJt~gifD_;ux7_3W8dsKSR%vMz9_+_77S)=%J~>Palc|9ypTA6@~9WI_qK~aw(cR z1rdO`QI%0T416O+n7)k-QLGXi$ovr9Cr4##N>hml3s^{9cUC*=s;vd6 zKC-jg1p-UjS-)r)So&;Vl=FFW?*Ar$nGMRv!v@&~VyV!?2G zD8_w8%A9Jr;-li6miBlJy=7cG?z1j4oUvS%5uXC2v*fz8OLXT{e2iR%Hlfi%IeVY7 z>m?V15juF`8a!!)lCzxF$XmR-(v~cq0S2AZVvTz7z7lPwajK@QcVdiQniB225E`sn z6~O3_veK+uTh^t;Ob~w!2SL=AGV>W|WVcZqB(vcsrM3xntnD9yTQ^;F1m)|8F65Xp zu6O~N)?iJ~U+@@6ZUzMuWHx-vr7y{L*bIEX3gp3z-L-gc#Z z1K_C{vuBR#XA%g>Q5&&``C;zCiK*L~-C-e25p6@a4#YUVXeE5x=_3rq0ywV(&j3Zr ztJTwU?cVk%O|EM_XUw0}N-JDL0|g?rISzgH);pMyMl2EvJYgSUr`7hxwjjj<=49g1 ztD0S;k}dtZj$~A4#x{gGz9bFJIdplrjQ&2qV_rZ|&adt%%x)$^R`!yB=#2`Q?S?ck zDZoSq3l&%&7^astO0Hi7EM_9|`dqSbrw_mAHyQe^Dl)2VdP};NLqkZ=NwW*H*M8#g z$HiF^przxWQ4g>WhDm`o$n-Ju)s+&FaHe4i!X!VMd8pGyFq(Ip)HQN`ckwNqWs^sl z-kM99UVa8qsQ#qWIlGN2>E!gKB~*orKpi{2ENQ5h8h1sOk>RKxu+`*)oy#H4zz`2=)h`kGt9>&JL8|#gK_GPW)LkuXfY1 z*756rQ5Tk0w^m10NFmv$uv!K$`x`TyNWEX}Z);uj(GXu4M(Kltx<{_=j~*^Mu&W># zFvT#nC6lB8p$7OIpef)0++Dkb+B7l`)mbbxq*~18I!!Z7?xiR73?;Vd$&*$_A{?p> zF0fo7X(|n+_^S^*)6l|Ef62f$mkq?vAV@utnvb0`Ms;Xrs8C&*Hmrs(mc8E-XmzDj z#l=)oM<7q#ynk+XS8g2yhw=jrJ@3!A@{8i@e4O8E#I7;$fDB2{2Q2InTDeeela{k z4250T4&*l;c0Fu3m2CYbh=tfNJ9|tD5)NN3Vdi)f2nkQFR~d|KF4Azc7!2gxp2s(T z(ub0wx2FV6As}j|Q5ypse`oR{v!t2Zu3J3;ABH95=epWSd?G&hGp^p03|bbg;WVC- zp@MJt;++Q(lmTSEtv4S@Ug_xV<^s_!H^yf@>`Z$7@b;cK1~}LWUvIpRg3IyhN;!@3 zBYb19^-UPPYHAxUIrJpz^zWiQP;z^;y=21AC%H>vdVzPA3<^25=#(ij2P<=4>o;FwPM2V@fd^hsb{BsIH}8kV+>dQaZV*19DE#4!zUvo9o-c`JrDP)fysG8 zKAl8yqVhr+yw|bV)vjG8!`W}^kbost?|@eKBxH0)t&3I!b(Mj_=qU>$>I1@*jD)&3 zGbCqqRw50Ko1Q=*Gg|q67cEnC=O%P;XQ(93OB-+&2*j9K0|V@zVX;1kpl@VbXw38= z;*z3G+gN2ld}O<+sIvWxK#|slq`r)?sf*HJgJT&%#xaMKypbBz?OvQWwL5Mb zzP~`%l1rg5|Gnj`bZvkLZ_T$7g84?8F^+~5Ut)Czhqv3vr42DgpkBMY`>H32TUskG z&J&0hN4eB@TJvQg?xsV6lcvYJ!Xrb8D=V>!g9;}WVvzoq&;%`bpFCR<$v zS~%_|(-SyF89F|m_`qtGF5J%^7ee10Oo`yd><_&N@GM?z z+L1Dwv^z4b&i3aC;rJ8CsMN*2WA3OS%o~T4_Jz#B?(5YK-`d_sRLPH0>tItfxdM1O zzh?HDF0wq6F<@VoPKDxR=N$oi%>GGVu269FQXL|3u3MEl(*B z({$EvDd9#!v~|mkcXt3YciTQjFaaoE7na+lv4JttU_7zpH%KW5ogLK>xFIux?6Z~D z7Hl5cUw738c#;ATW<8>@s^v|x2E%G64h*n9DE|^wAK*?3D8)9-xI8?${`7LQV}Mny zQ<#ySKJkfZT7Ft~89m9wK`l~!V60$TeIFv;wU6(vepmE$XXlj8$=_c8p5mO~0EDw$SrEiB-={h)X&87-zlarA}B5SAK!)_{k*4UNH?Iy~Wq zEnEDnrY$UMt0CMC$&O%uE)JkIMKNu2^W1hIz)MV>x<-S%8obzBmF8wtFH0<#3Y#tJ zs#k3x_S1`bqfLa)D^W$u-1m#;(NsrX2Wvf>#p~=hn=j_I5PoExpF8aWg#5cs{CxzC z1clck!doS69qOEB{l4>5J71zs2kRCb4PXRG+Isei_w*n2^kZGJm^}a|L_!HXEO#49 zjb)4;SE`g8gR~zc{lk(U?*lzr#EPD<3^vF{u0DS<46BUMWI69$L1iJDWhP1kx0hz` zBi-wDMBdBc|B*s)-7%G7q0&PX)Tku9;u@;p1>VCD>4JE|kI*Deg76u#0`ibJcvbQ{ zSk;2!si}UwLHKMHmpKJMhbT?{$#zxP|B{e&;p$XyQ`0St9E^qO#WI<${ry8E&*l3N zq|Q=q&@~N#w{A(~s|51LE8umw|CduOk;M{S}_ zHm<{~Bq4e(<}*J}i79HrSLO$9E6n<}%(ez(vA zC8QMlaDfWJ=Tkhlbgr9lX=ztbRNKx4v90b922^;GoH>Gz|>)m(zGT zF+t@oi+S)U&)$8Ywasl6?3D6z0pl9Wa`kc5MpQ7+G08d!lZ0~AMz-}(bdJCA6p6Kuoj^8Lymj~zxAN7>b`11dujiiJ+L8+4 z^+?9Wf}{d~HAZ*L=Ml+{Ce#Tq=&OXyz2xNJiglzf<`=9y2F_F%pB}MX(|&2unY8+9 zA_=VMY!;SfLENM|*(blKZ)-8MR11>iVehO3160D~qR(%nXU|nPo?yD^VUjq3Lto!1 z`2SQ^eH>r)xahool%P%1(;pFhBP}^Qkq9*{-jf4tiYyCtyIYMmBOqXBQ0_A4m zU#1E9&Xa2=fhD20rIXNF;nY~d4-~g7hZZSX`TYxdxlJ}$nH#PQ(N^{))3%i&@Rt zz>X{b=-qxpAmZ}n(RzzHgzV}3bAMzd)z8fOS!G#OdQbI?Dw%$EaVuG5zi;cCf(3xJ z>vN&rx*sfsK{kL;2@wkLRo<8=(Upt8_cgjsSi-f}huMJ<05WFk!_*_Q%ngqN375{+ zD*5kb>U9g9M)6Nl)8FlRDqVj8f7~C=&+FdV2p~|F{lB|E z|KsxjfB8LdzmN6~t`>&&e|(-*4V|cE4m6-cUYGiyZ8FC2+~~BAW(nSxZUQohvT5Eo zfjaCR1sr*u_P+GWwr7V|43gwamc?K+`ngpzK5;M?>()rrbr5Sw>%$?Veyj#5`R?OV ziY$cnr>o$8w)OHhh48~y+ilTEvpWk8Fp2-#>2Z)oHJsZg`0GMR2PB@ z!J|KFThfj3bdt`sk;rD%lc}~!Uh4>lNO&MLorgnl05O_sr{-zmw)W1D!}GBd?^26Z z0|c`;4OY&}2(z=6Az_qryz9x3k!l{qzWa6uSoY)bsCAi6h{cI^asz}ixe3dX%<$=u z{TRM-oj0OWjuj3h{JH?|N=qzo!YhP{isbGP!~c`s3}s)9$fT3=+6N+9f9Z(~*^YHjuIE9prjHR#w~u6o&k`UVx9cAnCZg%0z7u0Ybs>7Q+*CHY_m zQxc3_U%EqZxPSKog|#ryq?nK!g|?|^tM;u7KjK|O=?_erJKFkeV1!H=5BPAd?H*$k zaHk<1WG6ErhJrwWj}&A^&mg+b(@2sT-hbgn`F&|7*S|YHY>#Eqr>sI}k3k*PURIhp zHn$4@C*;Lu0A$ItZVjH3<$QEq9y#n89m_gNjcX5XkZ-xjy97|UQI*(hM&rg+|2+z; z-BrQ~WydwbzEhPx;Ik{P5hLs^M2Y=-`-;M6Odr7&Jt51=c@4=Y+>h_D13s7|>@TBP z>xS$Yk@!-71$TJ7D7Tg#h~lci^b{4?dP|6P=1SE0Qk@XzUL@gEYA$Qd?!;9)#qOuv zcI6}WEBTJQj3yqJeN)H!*O%$Mpy-y04+YWh*$OvtIEr)+*@5D${F{l=z?)-@irX={ z&+}G?VvVvAJTyJ3J!_A)=eeI;kd4{uLu!U1dGS){b6LOFXg)sIbUuF>9Hcavz+`lZ z*l<`QuR!AWRh_;6hM)N!8g>VLD|v}3^>ZH{d~&?l^zMhym>x(GAN|#C5(!ARAT^h~ zdmC8%^0;==+erXNGA^G06>>Ensdp=RYe93{gy7i30Sh&bOA@2`7;ll{%sr$|lGEoE zBFJ2w6FLtp%?2?sq6;xf&8U_Jm&{Br#BKEp>9vWZ#QMVgTE^R(&bIiNw7SYw(A1u; zoCgfjg;j)KqfpJ$aar2Wqg;|j1t@`WdVFx>6aChO1>RISzv8*Gs;@)P-gYqS@+?Kf; z;@N6kb0D{8Xxw)LrpD}hj?sm#8Vt*OpA@nI={!yg9{L~y427bNT@KON6}o-b@sn+1 zlbA)r0)m?RvxnyU~i%huf8D;P2 zvGa+eruG?~F}p_KE^i!6caJL3OE6A0x{02u?*lkqzF9!?6~25?@-zNQh`^15VP{XE zfW;0d>=HQ!lcqj$?Hcc5vAg+B5VqTI^Lt$q4E7 zVF31kjy?#XVqgE>r1||ok_}E-2GS208!P;r_1xXS{$KqwH#eh2#R>D@DaPxM^l7@- z2R4`=H%sxGbr;t;S(*dP^6K&iUp-h)%MO3BUxk|+++(S(mx=!ridQo2P!iXsAG0&C zoH}8#z&#vo%u?W!e-f{iBjv{N#*gj}Uhde#k;W7SBu28G# zrDM!YIdIAtw7TWMF~P*)pMK3>VR%CL^jxYJgGO*HeZFm+!1Pfks|hw}1HpKkg@=jR zES!)+nV(Q%m9X8anKQL_U)WjRbhjnIYLfLe6V8|K>8l8{qhrwLak6f+C5=ORYEUnfrJ$nG z2HA(70m}y5`G_sMDUDoGQM3135*V9X~&?4EMsW@92fksHcVeD{X6IDHG6y z8zuPcduG@@Wv1!dp3*3IfQ3oYt%y6n-asS>F6Sm0RlIC`Un2@{aBaJd+7|E)Au0`h zKz9ySPsql}H%E$^M;f2;Z2}2i%CJs$hFI|fktyOHLJsIiwat?5RmuouUf&X-l zb#Y)I{?FJt!M|GmoqPKuOpNsRllh<5?Bj?B&g~LgWsMa};fV6DuB`u*5&mDb3tVE; z94Y^<`A2%yC6>sBAok7izXpWpga?l98cXBE{?~vKl^DfYz<#UO?>F}QPY(W(%v@u= MoT#AJ-2RmPe~NGhApigX delta 14515 zcmZ{r1yo#1^6&=_?(PH&?(UEf+}+*X^&$yDf({nk-8Hy71PJaB+}-U<_U+q!`#Q_~_Kfgkh9z&og%0NM5fk1CSAn$}Ru~-y2^gmaDuJ4P<1R&6#4<1<9 zhcNaF1^@y2oi5)%{{G%EGGGIN2n?hoL{&Z0j#uDxF)c{p&RQ6{S5@AqC^;%Zn-yt_ zD2kSQ_J0XkVV|W}<|St*UAZfo@6}a1<+YLCyOi znSwGYc=vTi;d{cC!gqs{rV%iI$VbX-kRd@av(g}4 zUERS-D3CKHCFNjLLpzLR0~$zBe1zM>5)vX$6a@OYh$5o)GbJE0_@#xKz4ta|tqFW; zo8jbf{*5zu-mP}TxQ8Ykk-y2P%KDj@joL?|QYk;1Xz%*RX z%)@xN_LXb@6HkTT%9&|&LaS7-Nd&^LsKV%F&m-|M3|+P4F}9s#qk9De+b=pAun#)A zcgUC*6|XnGTRXX%70}}y@wLzzhlH(;i$fE^l_lgLk*GzjZ;o~}q;0K9t8d|=ij(v1> zL;GVU)d<z!6K%8dXSrKT>)AoM1!yBXmUQHmN?&wNArnZOwQ7%4s4_7AE_=hpR>v zW)7CG<~#!P?ncwg9Wb*hjVTkPQu2 zdsRc?=XwKcjU5ccL634k&?V#u*M0fB{4A;***`X+2(R@0Fm}zFUC>{PkSbx1I^j<& z$q7qPy>aFmG>=BKI9if_q#V{NFZWTU0$M2OEh9SgU;3^)v>DS2{mt*?lCH@UWqH+M zAV6ERass~N?|g#`3yO}+HP;W0hTOZD@}rpm((v{{&eV3>@U!K9Fii6m!ixSqZX7Q; zdjX7goqv=QZ!kzPDk1{$z6GKdN|M%_8#E9GZux~b)ww9|qG;gPFE=nb)m`1Db6Mg% zRcXG?RB)67)LPp~!eQD7|1dP>6ho)p(tyWz)g@Q^EjD;L(u2}F)@oU`lJvB=3}=C} zySqDEg*0mY@%O)g@70$qKbn3X&^0#|f3SZp`B8IrZf&d5JoYcGlYvAE%y*38MKaSBJW zsd%I@qecF0X~CSdq_EmNbZ7rn`1R?#f%xr}k+D^<7 zzG$W4r+RYS>AIHIgGyO=yrjWfUh**M3}Q67t`5KAXD*R>)xX?-cX=y$n70ft8e>~n z@u;pn4GgW3MPuXfs%u{CZDs6%dCgrqzM0P?q~}my%c8IF$MY|zKOXnnFjz?$#U?VW zQbiB4=)4?XHiU)ny}s&dbl7em+uC+M1rpp+Ja}uC*eZ2O zugyq7*E44}znt>Yl9k?Q$gzsu!n5~gTG35uFM*<6d|%X8#!2l;_IaG-c^d3&P)HAz zK`GO@%&j#3Yf7Al7P@|4Xp7->>l=ZyywR^V;xtR7s~OI38KG`j)EEI-Kc!zi*1G+( z!aSOFUMu;RFkd%%b+hwH%IT>f`;@wMFe^BD6y0{bXBVFd=KYlVN_WN7#K&@ENeoPP z`7AWAW*sox>NOeK^iy2V_0gCZ#Co-Qa#Z-48X5)H%hsm&&h=CHD3j zGQPo!K}&@ywvfkD@_pwl&)JxQU-uCF`!mGfEt$K&4!-S>{<7S@yhqJHaPZ7L*RjUa ztiAX_w{}d&mtSY`U1ER=pz8MUXyG#$TcgUs+he#@iK0-lCbZ>$A>LZLBN^ zb4ZfP06wWa8#gE^oz!qvp7-7Q|9_H91_0N(YL+n!g$f^_nyKdFvfkSQUx7g=< z#-M-TmyTzYRew~NcD8@4k5zHkXfWIYU?KlVacQ`K(c8sFv9a#vN42tqpA`A7Adupp z;-J$SXloqmiV__M=q>-a10X8vUseBrufLb3#0SFSEt1@}kq=_Zu?NvQm$hx$aJ@%> zb@<#20SbWrKg{-5x4PmDP|?wxL1-9bp`q$?B9bL3be3GXd!++!b<1tHB+bsiG7Db2-Mz%GX=}%xZxS`}>&Lmb5wyT7ej2oEe2;Q$hS`*!hX zusXI#BnD*X`sIT`m9>jIc1WK|GF1q^Ouu&mLm&VG^^x;~7I^{9HDvEgXMDW=o~oB{ z<~Lc9)1V2PVZOQ>Oga_@!k$qqEi@65VhB9PA9u$mF`tbJ!Ub`l(Ik~Ylmpy|d~V|s zNIsH3`alx_UqREvD++cF_(qXi-2)sUMfXU7LE(@hVjB>aHw)@A#gEr1a@FZ-MODrq zOF*m|!czB9r?nPSyW+W5V(HswJbhvPNoRD>mUtk7UBS zWuG>nir2zHBCJqwxRnZx5}#oHxQ~Sqz}v4@!nlooPyjQd^Kbbpqr&y` zfJ-sh6QdIC5wqkQcl?RfMdl@o3VwfZ!524+H~_S$``A|wZM3QBC9elEo%4r`g~+a2 zDG&K|Hl=X9_>_FpocBr@y_H)Dj2=6s1Tg27T4ArW#!|GtmZ`GkH~hNa*o(0KKt~nQ zc8!N*!fo)QI_E&T*$mj^=e9TRAhevFrI%?v^q67{_->o8+pp=gMH(OhzL;fS|7yg> zoE|Ibr9~&>{&IJ|85THIs1V`6X?GWg?$U%iFVvtiJt-KOO9JtWkRqEMa4*MRi(1=R zV|o7}b7E%X5LVoe?~G%`e&)0o>nF6eAQZ=bhRE{}OPu)-JN zG+8Xu?*J3f$td`RgZ#sonl&l!Wt9-IA4kT6Z=*+W&4r!(k%iepog;JaH~~f7m!6=p(#{-A%$C zB3EX#ZymqW$2`Da`DiLHRc-NsWAmImm)BJ`=5?LKE>s8D2rR!%M#h97gL(&%mCDoN zGH%eMc*55g6L{{34aJ{+Wzi=aoT7a$YmA>}XK6v{IpLa9<90TT>lpa;BqEI(P0puE zqbsMDLHaqEl2K9`2VKqi_okw`fTkc!jB7`RRTTdz1gh8& zI)(Gt&+-OdL)~g<+BkRg1XXQ0;_`>!bv8cAbAqN-UX;k1H(J z1pcM2^bkZm1gf=YT+iktwr2K>_(%gt+(W7wzJLGjy2X9GZX95p1rPlnHTPdF_YV`} zj}`>}GGm-CitShEMYReK4`!LQ3uCKccw9oJHGbPA_CPy#oB?Z@WUFO5)c;s0|5c*z z1VL&;{Dq{wU#`uQOr3d2j@SX?3NC9`xq)Kxx3b~JjYq(sYUK{=vc=6fkKgl79};`V zhCX|+fE*C7&#g5~a)Pu}`sg-#wOal>YBbb3)g4ZWfgsH`Rm<_^-lju9ya&&fPi9FmA}S0zp9-=dH@C3Ei&@6z_9G(oX@QJs zD3ur>wQ;zlp=usIF8oq;RJ%x=xw>~;nKXWp&JJ*SV6u+Rp&N1~2c%*p-5>lYrbC8U zGs+u!{w}6&6?G05+ddA)P-bw(mvX}Y<}^_1Dv{rhDMUCBi4t9ZZQM4UT*Wez+WB@8Fc$BrgFSLzKsa7y$K4dcn8(`ieKBWZ_)WKb#O7TS#QcjZRcf|L9a} z8;ClXiLQ7~=N7H)IQ?!|j#)~A9mQ2asPB4~5EkhvYUHnc5nyGrqp6PD)(p;8dPg_z zHHs}?T~lpwJ5%_a{!C`pyR1fDKad;eX)-qd8^40y3)}9Vv%Uen*9WCkJnGIRq#A4S z;=|=kO*`UP7+VIojYahMjF;k9Nne#;1GLJt#n8n`7%RJ#$!6rfH4eu^uG-zgUv3W) z`J(4?w_D|T=<)q60!TD!D8~!~#82*nTdYT}80j+;QkOP40!2P*%+Q8MkCSwn|hTukrqbi&Yfz(Wj>Zd)P9owxh&|`$5Vdt#MGr8-yj+AdGM2H`4qfaV!)RBC|* zaQnY;FtB*9EIWNzW%sszQ9B^h4GP82J@hA(Vv6To`{izGh*kKov$Nw+LhPr{(VL{W zD?<7OGLN*?}SRQLSvmzB9j6aJvZQ>Zj^75?$w*xOfuKn5YWu$&0;Tjk+EB z3I41GUu41RKss1oPwzc9H=tHHMAT5qU$J{)Q*hOsARFVqF(9YFIVuoLja-lzwdLM04RxktP?J49ZUNCA_x*QLnDfX_}0}+Hnddg{a|e)M2)~-NaAK zV1oXFvdEaHB7diwmZUxo-z@^rQfu@LJqfZ$dq%hLyyQ22>MA&3^L`04B&`I0fE9l?1MU&g#WNL2=xB{ z4xk_v78QOY0{O?2`49g8Ka%mk?jLP^fDWhw+pGZedRMmNXt6%9I{0O|%AVlKaA<4={ zebh=eSe(l0>y_+=SEDsni;NFoY?le{0O!>~vt|7!8qN)%_f2Aj^4fXs$UTfwT$4V; z_8Oq`i`V74Ux7$%=#dJvSJnVUR$|06`ZBD?{W?BI=<#!H#ItBeXqAVbx1J{;%%+7= z@anyM?-!j0Ls)iy)?t3x=0{e^U zI^*|z{#@Fg)ISuBej@u>ER>~>KiH=VMVz1b_%TcEc*9x>dv*6pm5~N8Srx+f)*-C8 z@YWe!b)KI!lb1R$qa-~MRnwnCu;v?h_AK){zl-3}g^?5s%u%|cjqz;zqR<6`r~U2o z9u(aNi9Ev5668aH0&?C7fb^_}0gs1v=Vez{N6A*q{O+4bgx}7xG+yxo1MT)XyaYYD zC9M%=1OLOd>V;fUl6c4z5r^5T0(WCZ2gzDV8&8~%kl)Ba4rKbw+bye&`5Rj6Q>bjB zpw-a<$%|E4F{Dr$NYfxtD}FUR8iZD2l4;^U%_(E~d17Qh* z@Z`5EFHW~?>y%c2K?B_f)HkL6t#3d6_H?JvnO)wX!;7_N)ZzQwD47B#ton_k#k~GXrAdKK-VxGse*a8dhJhj9ZUot3 ztI3E%Gf;+FZ5sC&5kM03#2E0AmUc*X{3p>)K@ zmA8z^t*K10y(x^oevje9N9Xqgq={o1M%s^Z1_wRugthPTRZUlZu%l;|w;z9zJ_}<| z{)h?+-hA%5AXm_MziU}k#j`4k_>3GnC3gnw&ra=nmY5Ha-oLX~RlNg!dz{|td&y8c zDbj!5TU_%Z55i6IU$`NvWJ|yMh7zS#cSBjTV#~LZThZfzGiY4UQ_$l2(03vTcF}DhU)06?pUW^~uWx;n+>9Lkqnm{}$u7CS3eW6RM3ot)b$t zvacpY(Y44=Ktg97&PSn3au0p=`CxyE^_oma4F7N~5#wq|cmFw%`?t6P^8S{2|6|Ud z!PZ#3Q?o354RH_?Bc=TFOqUr&+7{|a(9}#GwRBXi(!=0G?6Iz0*jo@MY<}BVucI|p z_5`8b>kOa&CPM7oH-E=z{y)y^e~U`xf6-()To(Nt7fcqR6%}X#A2ACmMdW`x-p8-< z0;yt|%hJBT!&D%t_wo`IVunHg8|8`~4x31Z{vF+_y`#{ALgr#*Wmjcm;p1TE<75Zx zQ;R`!%5kuP^QoC2xWLoYxez>HPZ~DpKXEZ|1q~6ft*z&9z=P(uW}uYqH$M}Ok#(%E zI6~)JUne5<2FsH@43Q~{ctIZOcCHdLD+w_>U%s~a=Y`^QuaJd6#wd}(_ZN%(U$q*8 zJULs`VBtA7i66Bf?I1E9)bQQ-G3R^b;`oRY z`!C)|&hRi2re{{4T3p<%?4&a$k5uEY_g3!Xe{$#cz#o2oAA-wqOwsrP@TauA$sERx z8e5#c&KpyC0#|}WPl{PK=7ZHL%e~iber6m4C{SH3>=)WhL}1<}+Y|YZ*lY=QPqsY; z&TURR5A+exu06?oOS&j?uHe{D+Zxcpjg}+5V~<`x(9S1}_<}og^v!)#$^^VH(PN8E zBa)Kln#9u-j2bs;Lt(~oFO#&5?`XC{y@+1S$PMoJS)Yg{YQ4&yKg*PRviZ-#=;NRR za7@{?<1oQ@E8#nXAhS{xh7i$_1$HnZwK%y7Jk;CDoiLq{G@P|N6I6fccOe0$bV2tl z@V;QBn$ut0XBGiX6y6cH@MjDJHNI`fI#(pgT_}d^5}w|a8*5w?XS98|-}jv!Anhhi zFN_Zu1nDxfU2&#*ggT&lyJ8M`K&8<@4mY~iRyiM3ZM*N!v-4x6=m6LcOcWxWBz>iW zc6MH(d*ph$+Ht&Uti=s?x=A~s5p~~yA?B;K4cbD2kL3(CX=Kj3(U)riYFSk!Mj`sGxR)uc9#DJ__|_c zrV914<%-fkzbdceM2lsMr(@|({&G8zp_yZ;!Nt)H4+)OK*`VY=7qvqfL`re>tNKVz z{fNgKb4$iWP!^*j;gT=DD0KD$MgNHwam6SYI|3IsMJ##9!_5SUdY~!Vo$N^!-weR zc0_!%`20boFP}af&}UF}L7YUIJdu`}r2XL27Eo>_mka(Bbi5bFB!wQk_wLOheE!MX zuvj>n>AB>H7QaA~M(*;EI|!oisTS!&M4ls7uhO(~@~ zBXEPEKejV&eT@-?%T+WYB$4Ck@)41ytTs+CR0G>SZiY6GoZGYWv4)j>-shlrdqs_L zTKshj+CvEknOAw=O_GS*o4cIEwbzgwY3dsMS-DzxG>a{kt`JjA8-WPGg#3chYLMJ+ ztVaCi`}leQ(N!iFoAf!OKGw%}{?D?r0B&yvDt4-v;JdfxNS>GNr_EMWbF^_tq=u9? zD;atGSY2YXaS80ch)g!dgk>m85=)ld9D~x?GS#F^?C55rDs5&~Q1~^sil)p6CCC}b zQltogf%MDr08Rgj0k0jv+lbhswnl7iH=^mr_?+~Ncc0CAcjDHc%hZ5N;%=QX>xB=^ zDxT@umJ26*Qg^juO4fm^B0l$M5C5%E&Te@wiBnlGuu#U1%{rlMY3Fum@5P9XO`>si z*u(X7#+@|-!{uc8*WA9$YBJ6#=aQXw)JdCcgqj1}K|EgwO@A)nL*az8NyF@bE5{m} zEGV;^u8mfA_|WrR@t5<7FF>f zTv#fr2v*DFYb)|Pw^h98Q7>eTU2yjVCd%3Luw$)jf9Vph!i9v(NO}{F=>pOE zjjtuXY$%z*tg>1q26W>o34+!zx%Ix2K`gbwjnz?00;p~pqxPES!(KPB`ibdYtwAlHbm+cw*okz?X{soUu z-^!@MNFLy={t0_^$~g7cQxc(@mRjE^3s-6+(C*|ah8x0}E{`m4haIKeZv0;52eu@v zG*!77s4hUPO~WtnpO@J?t{2z6OER4EQtLMP;iSrqSyM2+k~$85ypYP~*E zClRAK-{Lrr%bZ%8XKN`>HACv>8RyRSz;l$)r{k5Sbc0FTBi*l!P-+rRtlr;(bP{Pk z0d*y85a>s`dP^L7;zTmbskujl;q($zH+!@`SOrQEJVOs6P(mXh6y)-6BaNcH0km+? zw&F25J8UEZ*TQRUex!^_I48;HR_4gNX4pIYro%{ux#gf%D0#vi&pLXR)!>QjQG8hR zTcmIVvC>(Qp*spt?L6a$5jvSKDtNhEKp7&zKwDW>l!*vmuxU;?>!NSAd&!j3K-vi} zwZe6w1P@pjF$zJmpv!a76|$n4Ue|SUcJ@=*h332{D6|14Cpoq|K4Of|Vow$8>rd*j zy35;iSdN(*j8>GK2rPD~W}Pg{24W9B93@KmoAK{SdO0<&B|@7k&xR~1{Rix-K$bVP zm4R_7bE;hEN51??luxDMEaQm9jyRXKT}o%0b?1%!guC#$^D?M8Lk}pafVt$QNFd z+2%xi(T~y+miaw85 zdg{tC%L?x(G*pb#rwzq@?Oa>5Ex{*99rayPV45u<*rPO)l^rB z`KcD-GHU{x)^5FU86ILrh0NH^fast)Vk=1-ZpQbXHYsX%zeMQm{98bpbv{81;-L-S z3{d8C0E(y_ahPI0gtK(d__2dQY(0v|mXYJU>QA&|P1K39FMOo{tY#qRBB+{-Ic>9X zjkF9G2k!!=Zp2D*3#O}eH1*k(VzGf7KWANc5+1fG^=bDf>o}hT?owI)5$62zo8(6V^MXY z{YcRA-aq%{wBywZmp0wBaTHv!YO42UuE0AZ*p0yicV8>Vd5kRGtv1X=C-G{b7DS@m zgoNnoN%1nOvgCWfp`Zz6oSM&0v{uAppK-cJlD{G71H8c#8Z5zx1TQK#oHWVd)>#D( znmBT@&9vziVwGXALRY73T`Uz#irvpwCpGrD=< zXL{}Ci_i!b9$imdsP^>noJ8wL9y)alQBKP(1!myNPEfR0c&#*-W*B#~nun=8Mm)-* zY!`R#APQg}geP>p)Ue)Vjrf0Xqwnxmmn87P_27_oalRe z=3^5`^M&Sp541y(K~OE@O6qWc*F!HsFEB#bJ95x7LfSc!NHhwIj2*HV*H+FMviPQz z%w0c!RGpTO5V|KY6*sNJHX=RZMmcOlDP2cZz#VzT49btXn ze4;oxgG81OCacG2M07?2w0w!MW10m@Zh>6?7FeuFVp;DWG|gOZ(Y*5Q&@S9U8Nia~ z?5h00^Y&w!e9Tu%SH0s)*4pPT7-hJlc3Z%;QP|hb^oHuukZeJw#n0ajD?r|6tj5ox zxT#{KLxGy~m_Vw1Xdyx?X%owG>Qbb3bgD>;`c4gbX>eo+bAyyfT&5(}=lz9i5J~mB z<;u9X+@FuQw(beL$-Zm)&*K-iDgk;LO>(|4Lh}qbM@F*lWEddXVM)`Ng-SQ+0!&P( zkfq-Jt#sN^LaL8nF~8C}2A7Xz3-lKHm(NqIEmLy=7ENJ(d?Ln~OeSdB^#}J|@(TUr zbr7O2pVQ-kYW&=HJAtkRND4!%f?T@d-9k@>jmnk0E^A(?g$ffL8m&I>5&`<7jJl3o zat@vRjmU@mVqZJL3Tq;8%}xINvcV(l-Ki39i-LTM9K-hav|8qYjhW;tC(&C+G0FSQ zefTz^_mYG6&yI@&`P7ffCn$j9Fi*M4*EJ27qbHSk@}jR#bkasb-I#PDiCVlAhXeBe@+WHStQIfD&6l zu%{byY4fdY*+7$(^S7nd<_ZG`Yh7>ldJmONNAB(Y27Yhu?d$svPS?$xS_@-tro8eU zE&j2QWuYtn>~#Z54EcHiVFrvBbw+eG|EH6SMwE`?SNWS-#twTCx zi~93~AL|W={Ofd>e%3Au=<-AUp5sNG^qLz3t{MLX<7LH`UT(|0$!s9UZ{0-&~0)jrFl)<%h!2=F6J@ z5RQ}{t&a0n9`m;okZ5lSMk&f+cZs_GlWS7#0wa3dh4JR+%g)qTiXC`Hcf!-?+setv z+o_R`wsk9MlNxzX-R(TZk0nrVongB_>+1aKFO{g?(NqSSm>lJ|wEJxI<8sioTb6BV z6ZBY_Q|auJ^{n2XOsg7=ErI)%_W23THTcjyh1E1KAqy%zhYJzbq(YRVj5CrnC*Lxj z;4uo>x5^efA3r`m`?nj6HqGB}Sl3@5*Q@c^-w#W(^d$5O8A&)$KRc2V_{spirj}LRG=?^10!&!TwXnf6TgI8Vb$5s+Vs zK5Mj-QQ?-rP^M?N8YLCU;eQ)m@Eo3)4soN2GmXKX*1C%kBJ-SNqp2^|RQ~qH^Lz$;TsJP0)~@6!Z+`=-2t?+Yo*E80YMe zPOn#>rPAu-9N}P*+mOq!?N*zubqQlWvw@`@`D~vgh562!c6#J(EgDf-KyTeF%WL;3 zmp%)kxe|*Gv^z1I3`sWu!nHOIOr}7Gf2L{>KuO!h=3?-Wg0nSFdv}Rl2JWrR`!pQ4 z0d=5hF6gaS028M6wkrXti|7`eRr$!Z8({~~=#oq0uPYiSh^$sFcFbnR8spP6L6i_v z)~$YcV6C-z7vd>k+nU~K_Q9lbqdZgTT_^Xa97jE=dvDaz(4>YkETaA0lV>WN`N1aT z#Jp&X4QVGW<8nf|H;rY<3HUeG4K;MeYWM)#>8fYkPX3LK%ok_b33W6iDngVm)(nim z`(3{8mgH9! z2@s{mO{pAEQpOGzUN#oBtK!y?dVm)J!V>e@Y>;qU5Kaxlu*}IrXw@NI?>AQ_5@Sf6 zCTSnSeLG((%ugN3g-cD}zC%@xeNvqZS+zQHw9F@jE%iQzs=q-#R+&|_W+&(tUPUP` zkU@RxVPGmx&u^_b!fLNP!e*%|GqzW)#kfD$sK1-umSw;EGtx0N##Q-a)yLKmU~^UK z^BKtxOJhunbmChMR;`Z~WEM>~_otATDl{~yS)v->*Xx5W->0^EU*Q?6tp(c!+~ASL zjECAB#5hXh+b~*cXv=Ao^2n=TqEX4aqJAMm-y`nclRn)*YtVh?_nsh!HI7b>m;6oh z2vK++XHQsD|0Lz) z)M5QFJ&JMNTr9CO85h%D?a=!Ad@Ec|%FDd3J47mzI>38Q%+uK--o8EBLYcoP(AfI0 z+B?8&!oG>(yd=p$}<&TxLe@p9%>;PtSxil!|zCD7I^`6<(+f*ca`k;OPy*XDAFNMEJ!h`l+!;!ok2K#g{f_pBf4?y4w>*fBvk8z=GPBzfk6jbL zWqOlKN$g1H&%dQ2j^tM57PyP#EyTXQv4l#g?o&cWzVz*OJ*^PG&Uo^Lf*}1XM7ui{ z2Wll#I&6LJ1G`HO>5uU++xc{2Oh1SeE;RwlG&iQ^{5XOn{}}WMTul^w{qX^k30M9Y z_6-&-VPcl(^<}OP9n!!EqXLRT@&0|PiXLMnxs1N;%oph(o0v(Xi%l(V_nw*#2V+;b z8EG4tsh(}~MV+Zen=P2R!57A=CLM)O!E}W`{d1#Qb@jIf7xT{E*%CY-iyK~EedZ+R z)4-GuE#x%v##*4`zvjsqiGJ&yyouMG0lji+;B668;MA(^r(*%IPz@e44XpeUAlk>( z>F&JOpJls2^>b2U9eN{wm4Ca>K4OtoIjQ@>#PP$1>sKbkudul^Qfdlt${k-EQcf5x zhPEdJ6}9ipvvp9u3Ks>DMR(v#rWtC54TNeme$-#2{4gL#!4Vkj+_uAVfc z$D}CW$-lAd+ov^uB^WHq*ykD<<6zVNAwHEoONWTS<0RVR5Rd;o^sCeUjb@bDrv5$k zJB1pP=O&(?%$82hxC#Oa(QEEvz^EqaT4IDmQjbw4Pc!EpK$;}x0te0l=BnyolMVMM zPNKcv%MDhm_Ftl|G)4!2^?!m7P8Oc6Cm|R7mpsKz$&$NG2B4kOI71ZC($Y7IF2m%1 zhKvX|^aLprmPVI*oK+ruQP5l6@6JNR*jQ z#SU42^9u6+oE-xjdT{&|Bs26N0~7fnA^r1Y8F<2j_pe%HPp-di4n4`hkA4XM+w4!@ zbWg1RwwUq6_&f9O7#z8m%D+l#J-wVE{;E6iW<&Ykb8BEGA0G8TMgIx*{SNs3Uid!} zDIo}CXXa}3hp7~0ARw_oSfD=+)<3=e>3T)_M;{Pqg%sTCL-5zMi#`O9j?`c|CT52J zJHS7|?vGpczX?wptmKO?@Mo5P{+oXo@4som?4QK<_uzjY(*vLQ5>L>sZK*l(NH31q}Xy-pI{~v*V4zK_K diff --git a/docs/img/vis_overview.png b/docs/img/vis_overview.png index 5eef9e0d726fddbd762d66f886f44cd962c62101..ea53362dde056ff701afa980594f3706e1793cb5 100644 GIT binary patch literal 49562 zcmb@uWmH_v)-Bu(1Shxzg1b8eZ`|D>xD(vn-CcvbyIX?0yC%33+~Ibf^PYRoz2lDW z*Y|@lx_4FA?yjme*POG~CR{;I90?v59smF!NlJ()0RWKTmymI=5C8zsC7=!w{0`1e zLemid_}KsV5135*5f1?PDI+N&sN%MIng#O}T@r7Q5{^g}Lv*G{0v)46u`X{Jv(AtQ zL1UU{$|dERcg#I|uVKB+j0f|1#S_T0{1MaWLMpyKLZ^_Le#?p@NZ~^e&hYhnFcS|? z$4aOBU3$880eP|%+%P_U5CBM%4+tMH3=;knE|Q=s=!K<_B7LVr7jJM}e~KPr@L-W* z@@eq9NrCxf8A`M88P@5Xv^}<%46gIbvbf>GIG^1`{fZg?q|IAI-ASpiM1obk(up9V z(Sc6zTk4e_JD-@MSEq=O5I^}iGt&%b(&H}s^Np>53*sCVbu)F1HS}eQ6N;VAd^DV zF^5kh?fAUT8r-k|qt?~l z*uBRSx*{>pGv|tIL@9p+>d%ssfWoP%J+#u*u5_hF5#Vb>(l}efW1{UfNku2;Oz7n^ zo}(`9hGS_lC&waY3X{16)|(&4sjs&~hR%&w}PUovLl z1pPUFa?j-@5WcpJzEL3HPDz{A-Lpl;%>t1u*WiBJ}d3|v_BI&;k%Pxy6AYXn(u&| z^1k{~XvjC39wFISs2E8Mf{ok%a9HyR9igkzKyxQv;60_R>FU0>rA9X;8{ob7iB0Rs z7;bt%x%=2o?PCWHL=b=&M9u|rVHQS2zaP`SG`)Om+2v(vpo}P|QPA7E#F&66r%RL(_K^Ym;C&a|ig+ePxwzr|*o*2{^SN(R~tbKUv9=^!ULH3It zm<}2bo1*g@oZQAdV+)6+LuayK<4ZX#9{#al5Q`7`g5idMQylF0So?b4ijKpRuiV3m zKGPq%gt{j~Z{pZdTd4;J8^_E2T>u@8Sbi0{I~k@_^TWB`M6Y#VSnS6>rpOv`x(vR@ zgB9sfRVG>Qx~|tBNI{1wjh35qq@W~P_3H5)0bgnXV!Cmx+SA9Ipi{c#Q}TM%qwsRX zn|neHLl@@mXwoG`BcXsVTY0_qDdEF~1`w%bzmY_j0-IF?us!%I@pW`jN$ch83h}J- zbID~TKvQu>Q_UTpE90B0^JVkLBH*;OWE?9Vs~4bW)!Q?svB#8UBb=E|dt3|FkRtin@OOj_Jf{CHmg|zC2c> zxr(4ObFv1WjYNM2=`V=;RVjkkqKY2(2WM7zyuX>kb9*%Y&|BEhiPAv?ulNl+8Cn0y3Es`S{b{u- zZNH%yi2-UZB0p+EMg|G_ZVR=5upn2iw4T@?n_@vmaAmI{YVLTGXNg4uIs!)G>^;nf zJx>ylR413@@H#!JlDstisUa5!gzdDe{Md~!iX{=D$~CM498#RWzasGy68TZ*vbw{Y z7l?pQ^|N9>LkRf05o!CuyAFuf-Eht8vtqEDiupl6K+KbIm;MV8pz1$JcxS&>P-y2D zPc^D1YSAs3t+FEa)t?Su8ksJ7zZBk=H4g@uBBD=XN>e8ze`bt=$#P4im_0b(&6~-) zEbred`i!vHe;Bu(ZLwwX^Yfl$8k<4`pzP{6MmSXN={W};0m0`oph_vYuDRLS*?OzN z%*u=QFNO`;D`Mr2>g;`*7hBQ-Gk#8A*VSdp;XJ2m;RE_ z@bu^pDn%Y=hVj&eC62V=yNw!FSw?={8WRV&f)>1}htu!EKCec%FX>%{L~=%547alDwyh-<_?q)lCGxr5V1!iH zi%tB`FJCzB3gQ(td3Zv7UZ2`p*;K!M*t2&Qj~6zIf4BP)h(ZJf3shPHlua$*ANxJ& zZusj|7JiVRNhX0;K!GR>0OY}s%^pqQ5;e86D9F0jJs~FkY9^h$=gIhJripj3iK^ae zCYs4QKCy>%9Nm*g)ppL$v*q|J+b0KCzAb;alW>H4;cR@9PuCLCDKVN%WH^nJVm23w zTGIO`pF?5~(f%#}J)Ly7&!fZS1#+^Z2!zsTe&R-9TWEB>BFrNk$9Fu>@SY!i^E*^0 z@nxlJ$*iRVplsmmcMtklc$ykO*}^qq-CxA}yWhRTd-;Adb*y0j_DF*HsiGq0E`w!G zb_xMgYWLc73aO0s=uuzE6gvVDO&pn5arqK>d5Z$sz3NngLI05m``lcC47#J8|-*<5Sp+0w! zl*e!jW&@qZ>$X)Q5kMu1`GMz_>K)@8$LOwGUa^WYHd{SKPAr9G05dnAdr(8=Dyp`ji%T3dQXIB z@YWZQXp`VTix4=@;|8H6W~@fCL4GXk+VzxDUVa!xpljhrED4sa+DG+MV7Y5Q(VUYJ zgVJNH;$H-s1DHgA{2jtRs4>+hE{{`3)S`Y-sJto(ZWSZA;caUB&9x z&IQpQ*12jB9}ex}rLf3EB5x*?vUJzBIK8!|>BGVw^^L#EJ@TUVv61h77~`j920FN{ z@k%>w7qot`HVK?i7Rpeqz4a)`dg?^c*0=f^Q-{muQ@S$MkQ#SW5p(33$zfeCC-7pc zU4Vv?JB0bBta2dIADv^P&k(ELV)Olyj$Fx5^C4Ql?|njIY%(ml^V+ZxK6R)xZ#*_x z<7r<&yXIbVFn8$-asm>QtxL6;-G;evwU|7aQx3@qlz2PZY#46S;Qhb@a9?|@H_2Id za09n6aBtTFDb?JDCk%P6wjryJpMRw8M_E`PE8y4urb!u_~CP11S zXZ;K`B6cS}XRqQet>B9_s8ST<#-V?pGT7AFF2T6sFxIR;x;KblCr*zk2M23$@+#k(d&X*-- z%qn1ni+s=%kq*?F<>wbiPdcxbmy^4?UUPnXIXW~~YmQ`QU^v@YfBN>#EUKl;zM!TZ zrt|@f)&7T@-mu=u4_b)ouDhcAHRr?f8>t1a9g*n;!Ky{L?$e85t;8uIZ1%MA^K-Pu z>^VCMzxgWSiF@AaJl$u zaK{7y`p*&*t$q~=gx!^JvEJPSMVL)C-?iQE)D=@m6LK9JXCxOfja)xgG=fx?U#GP8 zoPyhY7OxMcD%7eXw#t%J43Jx#AKYu_j8dHS(;S1KkYCe}y0i9|^js1d?b>@x&hSx9 zg|4>TDBC`ATeq@rE10Ji$lmOv-*t=xrmJB23vg#J`idM3>ZN;i$4p63wmr-mUTA!A zQA^P&5R1-0sn0R_K$dNBRDj-26=m{`XJsgS$~=xx%*mPh?$RCT=Ldj-A|e8STfalle68qy z@CaTe_<{n$gq~I0BS*ezh_KMNf`tWv$kA1GT~*=NK#JPj>7J(Rhl6@@H?B)kzI^k( zckTPh)KlNh_({q9P5O9vG&aI%C$HFOE8lS?~#w0~hw$ZE&JMPSJ*g)-^IoVHt0PYL` z1UiOW1?l;Dm=be%h^VIurCIx6DYl$ZuQO`3p3Pvu??2zWSsZMq<97JqFKKZ9!g zVYbwW`f66Q9&|>Hx>n!xxR^8*DU;|9qXgjJ8O#1evd z2UAx8Sj!#kSvsIe!pGP!l%kYaw&)<6|($aQwORX07h^_DS$=&9-3s-qlR(jrx|iY=F1}+9J+1R7Nh!tJF-C zyAn6Ry8YVi^*9)fCji~O$4*vKUk(}nbl&Ov>y%@$%VgnDdibdRScq4aUnK+L@260C)vmpTm*ia(JvZl@~%934iW#l8iLoUerQd8V=4~< ziH5Arw8K%`OKUx_B~eR~NmRV{hGi1RSqRajqShoV^&#=|&s)n&c*bK%%GTX_4OvSI zv(bR(v-`Z|QN-)&xq9dU_%@E=`0beTnbS*Kj4X%EI!Rv&ZTD(4oGhN*hXCm;_>*}m z^5LfhhT^p9A>8TyKq%`5qK1GB=3@ks-@uzTbV$*3H$ogsFk4JGTfz z$$}3_Syv`BKIqDdEzi9~xwEmjo1sPF5E)yuZ_W^!9Pls~CKO4GNe* z|Mr{nFCeLa*eo>;JWQW5{;(t5XZHF7%E4$}M!8g@cd&)W(Qly(Tl(we52UNkXn#2R zRE|KbISBNDf{IFl4ojF11qCL#cc$ROx%srHZYR|rv$l>%_QC>q7zh*;KfihZg`biI zXHH5a-eCidGYUb_Qzrsa&qciBTfGBwtY!CcnsgF|1@#A6%)PFP@lg zO}&wI+~a~kT*7Ce-O_iH+naM|q51S3G1?WDjQkq4gs@cVA@|jIdTkTc3(_XHD*ZfV z!yeYWw6r&R8`Ll%Ryn!-(UN8#tOON zT^-8pAeAjAF*EIQ8B0UETdY>Dwg)1^prKUsKN9k>pePvp$`Kjtf&7aj zpw|zDiuYdrHK#iNGt2+L3&5)jtV-`-%pq2q;!`12&CF%z1EhHb1uJSD zv8Pn33Ok%HR7(8UMzYGh_LBuH`A{P{o&!T$7{1j^O&A zH>#zNb6kgv6YtA#aH6%%@R)S(FOIaUAW`J(Ngxn2VcU%x##e8s&S+?S{EB^fbECsG z^dmkE2D}9fQx0J~TKjz41sch0kISva{@jPzuc3iKei1!m6g4Fe9eZcE_p-jm;y-B^ z`S`l}`}+fYxOK`wdyiES2sdn2&D*Th+970v=v{S&*U<@~5t5Lw5+>`K3i5YEAHRi@ zMa5Z`$P+$pO}7Wp(f60bdkAZutu`UdydS8(ZPaI?hs%x0S0nPamx>jCmE;!C z=C>$80+xjp${X2^xSTM>M$21-ji%Pr{!vJJY8JBcNs#bSl7Y_pGDdlNH!{xRji#D5 zI&JaYhu>|B$&=;OD71_Pn;+Q0~`JS#WjeCaz8@! z${G;8cS--lG`jQr3YDny0lz>1h<}0<;OF;)69dJU6bM)uS@IY891dOD`=bR*L26hk zHq+Z|>u9(6H~CmSVjmTs1Wj<6Kx7w}KtbaTsgdrE7?d_wsvGi! z)11uD^@h5g_qH)P{NIx2Ft^32F(GE_@f|0My7AoEYavQ-l*j znh~9OT#miufgO@*IP9`*6C4SLU#1#Wfr@y$l8VoXDXd zXwt2Tb~c~GY`l9+-cCy5q;Bp%v%Cy1BC%LlpHpozl=5XcmJHKlLVs>;C>%*FqVGX| zkZ^3j!6(vt>&wn&@aeaQC%)h162m{2F{vz0ki92KgtIS`Vj%OGr=ir{8g#$naKEVW z4plqKi52flF$UJ96Bf8D-*ub*{G9OkGeZk2+cm{5{8&KeB{Z%e=;3UIIx|r$%7dV@ zHi2l$Vp6yZzfz zb;Jl=-}`PIkwD9X93N(ZpNhNhO4VVIQZ1jm6>+jOf#da?rIU?MGmI(@2oHR3@Lm3M zBR^dD!{5i*&rySjwXtW7y!>tlKh`5md@5yT(9zMA8%!r)kO^Q5Or`YgYs6W-v66QR;#iDOw$VIdUo`0NEAR7IgK=P!bZC3bz*YulO`>}wL z`oN_v|_8lwJt_eUCM6Jk0KwnO4V{HIxhDOnUL1(HEhgj2Z%H@u(XHL-INA*~zd7DG#PWTxij z7~}L=rnjat4Y+gRpE;n4TdcB2&`gf>*lk2K{p%3a%h(8p+^6;|f@Db3a~_p;|IpTO zKR|gi%HJwZMpLX_#O!`m%It>gstVd%TSb`_)Ab9ZftN_i0Vg|U6cj*_9OzWg^@Zb~ zr1&3c16G1)Bt)wG;>-f~d}V8QR8-S^dYZ%UT}I^cpy1YY>)V%4NEz*4I$WlM&J^3# zD=M#=MIDtShV2^~Y~}ayy05fi#Z(M9AsB=Bd=z8^aGJ$QS3wtB-9PV=a?cb=fr`HS z=;{!1WqooXXVeA|#}|CfQ?)Z}#AxBQe8)X}mXt*3bEB3flgrs?E6@<+2!D6-|7@js zzaCSWmyjHO`*Xb_eFSzb&@onSLThko@4vwktj%C0UfrL5$!S^Q$|lk4bw{+R@;d^c z$S5CvcD-i4=Y^vtn*P}ymjCGIx9fEG5Q81MtyT513josvq>MHU5*Uc5!9!U71usQ^ z`7M^nceTu!wUg&7Od2dUa8t^BB*$>JvJCF%ftvxp?7NYuK!%B!X zAqS4}aVylC6b6wc!sj4&)6by`#EKzEY>N6Occ{!tXu+c%8E4vOYJ|abiLy#0en@%+ z#IhK4M9-nIZsdGp-OU1(&gVjB(B&fDN;szB)vu6wnjWg5<4w6j0DVxSu@xvTMksO% zk=rcEoFc=kmUu9I-*+jc(P@yM|Gd~YxS(rrD8z4N8GNKgn*J@&?UJt8or-mr-ME)Q zVm#Xd^8wRC2sEJSXre5=n|I~aTY4}prJOQcQ8^WEP`xf;FsnkM@R&#$#f6)*C+4b% zC@`=|YHaIv6=b^bFoJ%t`P$iE|A@6JO2#NJ=a_?SzWl^_ElykXq~2_;3k$^5?x4J< zk<25AsEyKXBSz=9(!siJm1)b!>5(L&S+*~cz=TX$ASsMZZdQKU&0qVDXZ>hoF0<8y z5NhpgXBW22^l+M$Y?n)du8`ci<@g$uRO#OAZ;N>(7zk~>)?C$l&syf!7_Hn!*I|ni z=CM;9$~lfx8^v*$JjB>wm}Zx9`@OAf4%)_z3vB0R%vV5>W>`|0AmVOf8vuxT_{ z{B&zF1kK7G$>LR}-D2}Ku)y=4R6J%n2uM1Y5q{haran0jL5316K0oRM(<%GrDCH4b zNc!4t0=GZ+$_Q65QKPQ2L{8;>GL{-Xak{wlkoPn|ea+N3Z_g-We&*#BwgV-48mI_k zqH$;C$JPkz-Ea0WB$YWCtVrkFYy@_U>iXrCcKE5 zC$D>jKvMUyD4xk@^h$9F4C1M_!fw_2s)LR=({=JNt*F~sP6KF1yma@0#MPj~-`F$y zzz;Ww>CVn%$*2NcwNJLB-zk>7ElA=U11Nop*-&mnzx^}Z{( zcSTd$evpB*Ce_}-9n(Ii>zz_vy9BGRnl*^Ln6m7%9Qx+6-?3ViJHdjW4?DMS1jSv* z)CZmGd%A7!iq0`HxG_^jZ4jgR1Q8h(q2e2Z2eV&*q8H~Dix;`t!p{>u-0AHTB<)Dq z)&x2e-gAkhJd%~bZYSpg{jLnHbsyMUj#?o#qG1#{yA54Y%J{g zx?b)u5JlnV;psJsz`xN=Apt6B>HsMKP2@KLu(W6t8Pbjj@Q)$&FOU?1b=X;~(k?4o zpA(Xik*TbzLPdcs)nD)S_8f@7WMej){0s{VLBo`to!#lz?sODj4gv-DFDzgR`uV|+ zEY}&y%F3d`z=jn}-v>`*uvg?pf)D)(kkF=Q3cmQlfT8s-6#om2o@rw z_x@aHjl=Q_+%Cuo76I4eew>v^$T3n-8%Sy`a)*J{8mWB^L3{+H1qrbr$9k58dXJJG zO__;yjr}qBCvJ}8O{+Pi$QpRx+_Gl3FiN^o@B@i*ziQg0>{Zk*FXQkJNgM<}7go{w zn9I{3iFtwBRU#+mus9r#l(D0wO(pi#i)T&^K8^YPa)0>~*H6C}|Qdyx)j zhUjd0M#2*{7f>rvu8hPELorKLnc>@Wlj-$i3#PNCi&pC^S^NXBA&LUU8~E~(L5 zi30&5vh)j=s&lLLhgcX}xsTP$_H)OS)CCok1Bvxvm{3WOUA}j}&_{koHlBegB!d7! z!z;2<-42J467=c`TK=nMgn}T5D{sq=tLby~J9+l!Ke4=y9b__e%>`AY;bdRSPOXCw zAVz_EVzCBKg(4(`UuV+r(xr?^h`xM>{hz7+OYi|G3O;tO>Kkqbt&Ei_ce4mD1#;;u z1K>rw9|Xq+84=O1x7TMB6etxp-7b${BJhg(FY0;qPE8?GKmjq+BoirQ)0q7AJDFfh z?b6cIiDCbxg8v$sU~vHf#C*~W$emAob&6B-fd~50ApTFf1^lNU5D3nzO{gf7!T#$% z+L*w7k}!bGQL-uz&W;sYbdlmT{=HwO&C0XmsMIJZ&M$3$(|seCzM+@L+AtbGbj&nq z7!Oz_A|f~%>G<6w(^$$MfQ-D`;Bo4m%n+|qyvZ2k>G5l7#S{n|COlo&jF~fw&PZn5 z@sXH^mu4aD$3gh;i8VrC?=6mEvnBu{APY){vLrxQTT1|>@12xlqeg&9 z#dJbV&idHya&`_D{@Hv8(Gl>mdtr|c@p#|rtTc^CNsWYsNki%?)h3GN@Jqy^kA*;b z12YBW51+Rpv2DA$LhsJ`a@A{qqmK&}OT{%WmBbVjbG!bK9d{R7zjtp`TC`EJ&#(L(5BA1qN2yOr+pH zm$IP|=D3`#t}IrqVV{(I7r5BU6{IyXLWNRUMS%^9#%qz6$W^;>e|Z3cPm@oVYRtt5 zx4NG7^tK?!QmmI27QW4wBCUdoKI3Pxd|UjS3r9m?qT6kp!{7D3JJR*%&#$yJeAXA9$e{7p>lGbEK71{ z0mKuw0-_Ec%#v`@N+o$aWpsxXqLClBEFr;x*5BnJLh~`{?C^5E@&6;@kucH|oXmRl zQ&Fa|HU1Ux8jtpzq*>VKiOtmyd30z}!_Sjur3aF$L^4czAg1d!kl5ukUxbM^boDAM`xYRjG&pfXNbC%~t7YX=$QZ zk7mJ$j*i#t-#+dYv}TDoWWQzpdUw&xgpXMN5o^IGBZ@NJ0>W+hlYKY8`b3>4o%PI+ z_X)eY?y2mzq?X!aV@@PCBiafTJ-AZD>-JdH|MRdav@hyxB=(2pV`%};h!NT2+=zYL z9IC}dJTOo|;w^Z|468i0ULN)IC;tejE{TkSpub`-xkTc5LvyXy`;|2`nyyJfOr-i} z*>p8|fJ`>U=l$*MK%<=4xx0`(%@$g*ijzz7EqyLkfSS9dfxPMmMj}dFgoLN#^sl{$ zW?_j=xrgK?)v?qX(5QNx1Ven1-R-*m-tkenk`_A*K2dHZ+c{eZvbU{GOLmkW7$Mg4 z?#)&LuQvih{J{3XKk4OQr{~+w z(9agzEzdu{e(nq*8yN`<4h#$qco#l~gqR>9MMp)Aa(|gG1;^mosvNuJGA-lb(UG8D zX>a#lZ28A8UzTUEiTS3XAkMq{JDilkSYp; z007u=003wx0Dy@I06>HV0Q5oNDm*r#I*q84F#zBLi9okM778F&#Q7&fY|T*}qvr{+Rp*i(0j}PU)Q8@@(0&7Q+A;bEc7B!nV0G^P#U> z&%J)dZ^bj!%}n#U;?=wKd3=r2vwi4v(O3Qp=VXj&_vV4F?MrlKEF+@z!ljMS9v}83 zPv-1|oDmMftla>2sxoORf%VhIckjs1gSrWx1Go43MR{Y(p8Z@s@ozTs@dzg+9#fB; z46@7fMpv7AJ0HkW3_iEz`>yG}(Eq6|nC%^56u&w2c~LVybIA_noH`h?X)sMA8(J9( z3Az8?K9c|F3iQM(V1@%Hh%i{0eeU>A_t;);ioY|G#-A8-hZb~^C>TD*eskoCp8xI` z-pMmKPq1Kgf$q`;4Cfn4V>OZsm8+n}W4%}~xwinG&ka9hAT~Iv4_F>~m#G?J z8m}y|k}H@k3}R8EM{2i1Fk3=D8oKqI?5bEDDU6ynS-yzv!Y&>R*5+no?Mdl}mUDOc zoodPOe$7un@(nnWdS@~9a_9H;qnUT3#A*jR*1k*;vA8XR`HuD(4TPOi1y@ zvRmG^i=Vg#oU8Q?bV(c!UEB&HzG6p>u{-eH-y=g}6Ik$@6Ld^R@<1o`sW%#E-fgW2 z)2CgU(D1zBp)6-m3x^00tT&f&8S!0B1@=u0hs2p!7PDTdUHw{^UOfv9siPBvhy10DheBLIP*;&eLF=+M=AxWk!)JCK&Xq0@napXn zTB}@NZGGiywFo2^Reijwxo>lvK+K{UvJElWidx)Rtle3pqCnE|+9k}F7{+1qoXcGq z?ULxTeskSBdaE?#DS7ua@bK7@uKV(Om<+>U%0)&{+;|sChd>U@Rf1IdR7@bg@) z@)xoc+L0uZ@5@UQ^4rxvUJ82sy#@e}4DP3ZjuZ0pJ^%>(WBtYJ!Or4Uwi7ENEza^ zMo*<^?ybJlaIEqq@Xc1_R(Q5onsl7>gxY?)_R=ottrBGSdU>c*DQ_q9VVq#iO`;ks z9~sei+4$*r^}TTkv2Q)XST-1U=`A^yAroy-qY2hzh2@BK`KMmfW_h5z*B&mQUB4)i z)H}nxX;Vu&wk5kTZCOOfiGbHFmo~WtRxAfLT~|9*jS^9rG|0rc%^@7o=swM4%hu|G zmo>$tX1WsF^C{v$)yQ_Lyi!qIJ1XCnOt-e-eV&$ye%R=T(uIA#UH7;VF z)}PIK__$wvV=z698195|;)5o-aD9Nu9frVvRbn&tgO=y zB-)&6W_)EnEiS2A^_dJ~)iBu=br#INa$YH83w?paJs;-8NBmMFMJiTQO3p5Hx8PJh zPf`f|PF|soMKMTLTwelLm)eFbib3*Cl5fHSiS*ksO~AFJ)ILF2x?3HLK!sAQwH5Md zAQO>nzRZLL9Z#7n{r>24)Hng_y{v2gv$~X63P{AYx+8UpzPrbEx*@{p!XUBL`|vCe zZu}0m0-o%}di5-G^Z=P1VLn2?C zNS7;3NRD#mRPJ&;86sgdQ|Qwd;+n2fXk&gE8>cuLX>#(f__!K-YW9{-SvF5u?kz0K zx8h{4;f7K1RgqHXDUNa`z8O)D1n(2QFGfK50WonS4N6uFU?KlIkMClGvp6M5FE~`p z|2x>g@iQP?#tR{9N8UL4hs#CK#Q$xkV5i)hQuVG2g%Gn}JlV61W+xC!!NN#H9oroC zpLp8xTevp+6F!xLRs;3j!R5>^jfg)C8Bs!X9d_LO&&AdYGE~q55kC`AGDkLMr|&Z~ zl0`qvr9ZF?cHmO3yb#URoo74n;cwjjy7QU$ zFB|!b4S&P^|NKNojBCr{Y$F^0gn*im{FeSe_RfGJGYy>y`>2p*p16;>%R*dm-8 zZmLnBr_p^W@cDSP9sqmP*@@*8!O>xYr5DhB1TM)JWx31Vn(3pVO(g6$WVWda049Gg zo;XNNSqjDL;unXSebK}q-Vahq(Nr=8n@&k|$PfVN8|!JwD5o!5DoHo|eQH;5O=S`* zk%mHHvJ{l{-dlWyF9uZ5033zM!-4gpMN-y;n*FTPB4G)gw%||R{G?PFs*nJwR3Kc~ z{83Po+UyC5t}Pnz5^Nn=e^h39WDE{?x0nR&I%XYEh$wx}K^25On_BSG0xwRHGUKYk zCV2wJd*}cfnp_yBy@!csj}ojCq+bYboS;M8tM*dVQEdQyc7g;+Y?8F}xJSNpZldW5 zpV%1DeIPF*oIzN#8k-2D9|f*L^pf*vp{b3xLWf&ojfryNNW>>hv9f8$bGJCZLdk}lQW!vz8e}=Pb=-ASqgPfc{EDfN()GJVz@H6@o1Chpj!H+v zR?e|B)Zc@6($NqJIdoO~?IQfdvllE@PwgwZ?z-(n-k0GjGZRh2U46dDnaxSjk~Y7Y zeV(tV-KppRx;N)LDVe$vkb zPOpN9g#R(uL%hNh-)gW;2{UrG16=Va=3;P|_+jx%Uha)QOox5s3GA~v%pE*e2NgwmqA?~>G1thnrmD3xwF{V|8 zW+9iB097OOwAfw5e585M99Wmqb960e<+aXx%5(-;E^b$#yH(v3AhgAn*fusthsWh0 zm)V}96k|6;M%zUHH*gErJGnT1e?HCPqHG>C9)(>?DO+^-pR;L9OmJ3IRveV(x}LJ zKPOO(E=Y|Zo-9xg>)?||>4z9#pl@p1@>^<$ufjP;{Rg(8gK8y%?uu4df+1lAGu`prjb zD0;tT?5r|YgcTC@D6FQX6nF~D4TXsme%%N{Zn=FNnQx6H>8p=u6AnRCbRm>#vDqkv zxjZkhz118J4L!F+lCFYita$IQ7uaJH=M-908R>1ku6zN2{diGKty-=N9d2m2y>QvQ%8cqO~x0JLA-HYv>7iZ za}RUJO4O2(xTu`3p%1Y52~s!oiB7a7<|oRD3CR^Co-}cQRRAckLm$(bRv9mWyr>%H ztWd;*Wt+*{gkfN#Xfwk;Q^D0?rxoZi(!#QTIBlctk-=fU4eL(tDZfu3PccgxvN#gb zJo1%!m8*h?XXL{i5CEOj<(Paf5)|#raj3FJ*DzJreN*(OV7;^`XFc!bAZAa1lS7K3 zUrdA&Zi#p4opO~(QYu<%lZ|I?Cte~K=@U>P0*MN8FgK$&N>1$a!`3bJqu!lv0EhQ$ zkr(rZ`rLV3fuSb=P_*usbY#8~*^QCdqf6kz^~CF=2qv0aevh)?gP~*!*(WZ${#*5T z%#+X*)FVM*Fwv|h!8oL|=w=_%Y}xv%bOe51sZKOIc;OyMBzB^UkUMWV-edhyzVqMrrgvDG=WSbS z?T^b$mLT+uWdTeTCeBBUTNWSHUvriwEGZEkEk;8YMwTG=B%r$;DN})Pqwlo<6H#s+ zbmN;=t~TjV^HPq_7jB|qpGn(~Cc0y>j3wSOc^9@#)_iZ9Po4~u2{|l82a~A*_qJQP zq|j_l2o!7^EqS&rKgWgx#fPddRE$f4s@x@ypLDl|iiFi#ojZ3uy)}t~bQq<$qDidJhrHye4^#H#9w(2$D|&DXy%$FhK# zfWpkR*?s%LcGZ2>In)O*Jy2p#{J51JL`e8=mhdnBQ~D)Nf-KDKs31F?KR_WvVb3Q5 zY+?X(nEvB&{FjLMg3D?1JtbwZWWbQwo0Ey@i!VVz0(d|wpMZb>x2?aXs7|LFb1#HG zxUMb=pT`A!Pyi1p1Ols<(vR};Q>qneGch=4Ud~6eAAmscBp%0T#1im*#ODrD01p#K ziWM14pgMEL3-%U0E`>z5#=y@Dt%36omc`co@s;QhVh zJ;gl+L=v9=&Jp9F;myaur+hHKz=W+_1EMK>wH8x}IAx zccrawt74l{O06SQb!j71OVi@@&5oZ+xEeJRf9PsA+U?i<=wRzO>7-?VB>{h`#u`}U zjl${Tq4{`DNG~J7K%d*EJC25)6Y1-m{dyn1Qcn@DVa1vUsV(ORg1|v}zzy0nzb?s1 zv#;iSpS@Vo0tJ1CHSDl8?I;;w$e8uE^%E&KS@-S5bw5D(JO5N24J)A};v}EqBjrE6 zc0T->;*uW6^?~{;-oVXp-!s%Mmga0ttN7=N{0A-<`h2%M?1#vk+imJKzMg##VkeuG zJxTe9!==dS`z^6sV7c_wBfKBk{{s`zpAR-uRo5qd{%9jAKC|BI4EOe$5rtJ+_hzma z;q3t!v0`ddg8 z;MwSO!+ew*%NO*K`iQFCRc>ipL0M>_o!A;9TS)wDZUFrFN7OuTx!#H@lB%oKSMmknW zX3D9_+Jou@iQvh?(t+>lRkkfve66NM$vPQu35S|v-o^Hy<&oz=uYT>SNtJb-fK9sB zE=jh5qV|99wf{(9P`F64JigUR{oX(%w)ECL1b7dhhYc8FdZK`N`VVH4Q4Ie0w6w#6 zgV5iSFe8z+RZ%6UJq76Wm z2K>!S3&_pg9papZfB@toK>r_d0KByS#KV6}nSZWfQ~`h2Wdi&H5(u|IU~@oWwp~9b z=d8}+EzxkcbLpyrmKQ}9;0KRLrMb_~@%vP?-Rn4%hbMM}>z=pBS=Gk!|F8@xiQ@6r zc&5DU&idEIvP>Iu8s2XzH~a0eJY6t!#$MfJxhrG1vBnpd#vIGqusM;Ne#(CUAcl!& znyjQQxwO<8kO+)5-0^*;@^&5XyelQ}%&9#=k~rlW{Qk+2+bPcK`~{hSjwh+18Y{89 zDV_D8da2SBb zRfzUh3l|;j{Rv9LjoiTZ0tpyW;;g=Un}*Ky^l(>N?nZ8RhfqT}|JhjvTEZ}7X0$RN zm0v10Y6Aq1n&2m}AxCrfrdL`*Cnq;~G8-QIKNng2qbxNM@M8=S>M#@t{|%Op1{p|* zh?C%A*s2!Fo+JksD|Qgz;x1OCWD+4@e>dpF~URvBiHM?@9tc$I|7^b9laS0xo8qo}o7S zroAyZxVgGIIa%GFoa}6GHQr!mKuj#(+bbj_oHH%r;NVcDb!)j~qfsJfgb+!GoHBj1 z;z;G~UD5i}52W@Ko*p;OCF|SP*xSb)d~1LHroGPv5l$BIw)SPz;P&=QaIw4&5-Vy^ z*nrx~qK+seVU>lAjj*1L&1=Kdwzj;eT#?k`%|fFE9PCF#*xetsItB%2v(Kp1#D)i0 z;RKb~&~- zoRc5_vXtq2bZ~*ZD>Dm=$L;X~=i^OoZZ3(fB`OIE3rq2PR1|Iv&lq%#&0_1ARrr=w zkKXYV_x0#{xt7WUtKqV!gN^rLHe4*+qiaaX;<#*Ya&*IZFwkFVEOW=Z-3GN-+muj+)yGAB;NlpfND7Bn%O^)FU?CF=vC4suM){r&xN-$|?E&})1% zoh|Ql*>J6sb)!fTG;_xDmoC>9v1-UdFT%JJyoB}rzatB;mRqcahxV3z6~l+uV{Be! zVOpPyz?QdrGO#e{lM_%1-F8q$sS7v_;t-G|`_$(ZG1`KU=Nadoa4oQver-9E@O_Qe#(EE{KV^sFj0}x8lHi9QsBY#$uQ}(c(SX(6 zJG1RrEg@MIt||_k68~Xx|IS>){gYXqF@#%7Z4KfUPfDo__}VR#Fwjtb?MAk?!g^jF zuTNFlEl-F9FI}11zIh574&5TFm*6LGtTcJ-a+ikVb)DMfbE?6nokH)QI|3m+uE}=K z``>$Gf}FOxJ>JjlWfmsizVUqf=81;~^X=pqlO_#wXt2{08z1YAj4jDCIQT=4557)I zb*s;7$mC@7@qAf&TczD{E$}9o0f&l3>O>hv`tZJ7rvus>HNXA&s6vI=(IJ0P4T4}4 z>VFvN-|YQwbN&Bj4*$08{qos!XFY6D0l5#uv9`G%pa39j@IUJSkMQrA01TLcl*%v^ z0f4`)|84sH?;igzn()6!d+V?`zHD8%@enj|WGmV*1yFk`( zi7!a83eVRK6wKW5M%&OKt}6p4O{!*%tT@?}#?i&}hVoVBj{p&6hHTiO?3(!M(tO!` z=q~S!**rP%%A8VzlcCgGza4M&q%kleB5!?7u1~+csk|j>rCIiJm!FS6_u0q)cAau& zdH!MfAP(wwaTZosE3~Rw(Y5o{$96_#t<pSf>&~8=YI{>kn|ztHuq3-pVL@WZ{zh z+ zU^20<^X#A`yLYav=entCM>Wzkdz+ON-b0lisEqUHuO zawak`d96K&8(2*8E?abg|rZ4&L_C-3cuTK=~O0W((C-Rc5)eDvc{Y`S=kpEIpPcZ~S77+TQLg zE7k3CX*9z>UXE8(Ei07XF5-zsk}2bmU}V{Ss=!&<=)8nXr;T2IOj98sK0KeShEYGB z^J7l@EQnRyV>0n)7{=8q*hkZGb1R#oG>sm97d6;IfU?M1GMhMRaA&QAem`CpOtKqM?c1E)#vL*YGg-N&g73-mq)$b522fHBzCMtSrB^qdEc?-x7#<5 z#P(7d_ekcg@m{kB;3jzPl!rrjgxp^7GiPQD(VIB6*G_V+W0KI7DxkiHgDZeXpti~o zG$6YQ7AC)p;R&D+FCN-M{JD z_L@NTwf$y^{<_f`MPrasJ`y;@W_Z~DRsYVdNqp%^nIWwjfBP>vr(^;-+C=>_1vPXx{oBICdUdRQv16l?rtX&S_bIqY60q#09RTc8>Z!H|& zSXEOyW+R3sP~5?zSC7r-W8DG-{J#j7m&agwO=S>xj+x84J)$%&D=Sby(AUO2wj`_Y z$^qDnywJsar*j0$sZR}F#*@m6JK0hstI|otOx348~G@RusqM0xTNt?F8 z&-9zGtDGn#L5-~KRN+GM;+pkR3vba+{ailVMvCSDA$?qMf3vHSdWL-+g4qrx^4xLr zJdlJsn|(8(d+Xf}jyOAbO;+uH(%{O50+D4fJK1&V_;r5YF}`{dnr5#QGtvFkd!^;{ zA(LfwUoW%sZgm>yTGiWiGDcMV6Pd zP<-b6z}d=r#Yx+fJ+5_f?O?6>VC|5WT!Hr1?HK1)&d;s0$Ar`vLEq8% z(~Plle2QAjsV#H07~z|I-|DCDDxy5|Y|(efs!uix&_Y^}jvc^n6u=?Vj;_8c%J3z% z7CpUy`zNdVUu|Z^YA|QdOVEA-bHut<uy#icjy@T|l}n=ajLEV07$ z)1?O1=@H5+lZ>WNBNMXv$|t#4FF*KX7_MqaZ;CfpY#;#W;SVG5FWmBW9(f;#>= zhEGf1`$^3D%lX`%0w1z6eLqOmF}Pd$?G*p|5pqn&^=$oMk^kXQGfm~>m--yIE>JkS zR{v)PEssizJgcLO7STYXh9iixU|PKh!!q4!VeV$sdGMU+z{YnmlPA5`KzS@CG;Dqy z}o#k0iTMEdc0GCh%hD)?E@-69`AS~6K1LH6^j)vXZd&yp?E$sn*d zYwn-FoOX-yvEfOPNn4V!7qU=Oo6uNVTKcHatNrf4N9*y$03quLDc)`QF2>6zr!;lA z1TOM*D|7!0d^`;hR?Or-On&0hiwhgj9aFfx$Y|yhpzhF3?k2x4;=1e@JBC3I*2w&oOm2%C1F2_PbtnD5rl^mjPaCJ-fAZlgVPN z5f+_x<&Cpq@u+@NnP`1?8+o&-CsR_%7{Pbhv2b_?M}feGlP`5G66;{9cY40rjNIGG z-RkY6@TvFI8RoJ0h9MNr9(_9Dvi5zVKl8DrN>xgIQ`mrY`|@c(x_(+|RPdBnrsiOX z&1~V`f%d`G>f21_)#aX;UR*<08t1oIn{MAB4)=9=`TG3v2p4xYzA0a~ z%jZwCSzM!Lb4v@13`sb{`YkGS#R!9QQSJug$EQEx-`c(HmgD(B0<|{ly+E+N<-7HJ zO(BwpTu$YcfAFG)Xh*NIHFj&v-YG!zFr1STL-MnipoMl+Vok@fUh%f&9lA$a_wZvq zhbw7&T~EN(%t&|k>panbjotS7uLO$zFxv3|#-b@btEqOZped_f)ZeTTX|4H?Zf4!} zDuMVX^?+9GAe2l~6+sdPt1s_gCiV~WJL`F5+PiITAxXJ&QfdWtiM(Rx&%fzW4sZ)C zgF14!UOjtu$HRHO)++Y{%Upu^Lm?7XP)>ruOt|psI!84Co51?~#_aj^j^Cc3EuZ_H zx2pGI2%cK6C)FK|TF|JY1Hu^uQ+Mq~e2u7cwMf{=9%B*YGO?J;akv8qGbx-?u99s=1BuNq>N1iCpY@Uml_GPo4Ku)Ge1r7z49>V z+A=Wox?61#q`gBia_(rVjiN3$9!@$UuFB3|JcxVQv?nj_niUAP@pPVelXmsEp;c6M z9IAq*O3%NTLo#c{8u%RjruA#T9Vg|OJ$#g{*-FJqNt(4>THdeP(`tk0+AKqev+%*^ zvN%^`%zeIQrZcF#0!kKiu5^)@r4zFL<+`_ZmQ|XXPgfw9U!2pjhRCKcjtDhQZP|lE zYmWKeg0Rj1XXEi$6_*YFY_W9yGcx&9sT)P#QGJNdaAWh;t*wVm$h)VIt?_6?Qu!H- zNQ+fBp%Jx-JXgMRR$;9?Z_=H?_>l~{gTm5DXfR`ImzHgx#SeS$3=xxdD8~|12HDCJ zBy3oj`IUm7UdikTl;3Mko3HFiOO$zTYIt8mI;Y`vit7D|^;>{mQ-EH&jnCezlEL>X z_X)Wvf^dH$r~y40ioGeW=QO8=@)x7|e^tc)*=zc*`u%UZZx&ccP~J*d2g0N_ia*@q zQQP4}(LxMx=~dc1_q3?QfcR*Fku)}z^P~50sZLbPJZ0((gF;t>qsGCvDP_0I(Q1r# zlkUc$g9qt%reSgFg{lD;P=!%xh>t}k~D4*px1 zhu3exM+UKm^@(=6y7c#d0zC?F)&jS2?PO{Ggn{gmH0N)@OR*6DEmoxDF;BmUbu{H)_xfjN`rj}F z_wYeu85Ip{0YD-rY-zqID)eXY@R3yiFZcEDE@&_u72@ALR^DtNz$ITaAct4y)i zHboNFaHB?)jj^jk7FO?s&W%0jYEA=Bl9pw_OJu71gL6tEUttOS zv$CcP4zXbWW{9rgs<d#+*h+BSyik_Cs-}!7KG*i~EKU|wRg*zY#X^&o zd~YBS7-F-Cx+nj-Bm(E_M=vDDm-gpU9L+cZT4MQTbdaCPZ>f43o=K#lhG;0Ea$F&F zw`tDn6QPD`xYHN)eypp}W@LOFEh!5p0b)jto`!i&o^GKVEHmj4Q<*oag<&g8rEIEb zNuN`OFQCsNf#53al%nbnmYpVW=+d0{g}wyIMIuvqS*bRW#?mbH>x`I8fu2dwjrcos z=hPB57ha-8GHkw}!q_U80tJI;DMB<_Tp#NQ{0`&^X%kCtQg2ZUO*eCd)SwXah95q`US3%)Jv7GR`{+I7q6w7qu{UjLJFgN z5j0d0K03dPH!_N{_On&O0dM3n_lxP$>*RfuuAEn&wNLxXNQ)z@fbcQ!K9RG3szLxX z%L&qKU3X|lE=hm0U4rf1$9DxU$BkpkG?N=2kQD9(ho+hY(^OuT!wv>j8G$UgxQPRX z=C7HqXUo>-b(6)J2?Px;MO#XKdiIVhx;HU&XyYIiO@nmmL49d5e6hUAJk%}vO@ktu z>}r=ohE|9S8{t_!mRfMX=qh+Yvy7lh>t#r+Taq|?@$N!@<>on>}Vqp+=XFEwM9qRSC{ z+3n<>XFrWgM9Q8jzRDG)pw;4HSu{F3IjKP@^Xuk?GJH0pemno8GPX|i8y5dhk&Ir8 zg56jv_4BQ3gCy%V@d)20g>SPYx6mX=&lqBUjLY&(M8Bl)5nlUM@iKN1QtVOAhaTq= zvUhBWMdG%3GZX!_-d(k0r2Q!zUQvyPShq#0fV*hRN z9P(O@sHkuLnJ)&DjC4rlw1`VJy{Zu-*c(41Djt4i54Rjg8HE(0h+Z}y2|VaQOyVC} z-@RNoeDw)@*K!tjkw90)W}0uNS?@83--y)WoezGur7x7+A^3%U)V%w%d=`;x9;wrk zQ{B(0j&P5J4xf{Q82Xp+8nV5VI*%Me{aMZ5*2b3^NV81tHEuVzZB3C{s;Gj}Cm=u? z0-e%o#8kD&R_><9?eZIKn)u_Z>rVgm(JMxqY~ylyd|tg3n*s?=jVy67=<=XfM&g9q z`=5>TL1(O%t_Yvz3=(XtJw(>oRy%dDz~L{X ztUk|e_kCUO8;Z1a%-g6-|0_kY*RbZ#mhTGB4-uHzwWUn)a0)99X%!lJOkihwdjPCt zi;j)W;j#=*O-<#U%4|F|0u48yWZgZIUqx^HWHzSSekFu+ka@}RnfIh1>h*`g`Q%pf z*T)Zx4N1A@pWj&Lq0)g56|nqP6(X8H*+w@~6QcU>L4{PfOGC~T5=4XYNMxb0-P}D> zlQ-~R=sINj+XiWYIbdAQfIP(iqC=(XUBVZgwA^fM30)hH{-V&DiHgPT8xhO3o&e>+ z+)>!xO!>jy-qCV;qrX2?S0iR>IDtrgB=P_nJ%&f4fnvlDFB zMWTM4ZAe#W6m0(X;Klj!W?g!L3)_c{MT=se&*G`Lw2X10!~;Eq&=j2w+N6o zrQZ!F66Tl0y;44hZqp0+uO55q^xj~@Rap3xQCQ>uDo8r}q+k0Py=oURe)Q!Ery)+a-Rc@dn*~-}BPGbo5 zNCJx^%TT9L_+4;41*V-gj#O!x|J~ZhtdVP5%zOdY)$Ort4&ye75(WhxH5mA}v{8W2 z85hN^u27b&f~8=3c2wrKNKlmv$d~ZRZYbpG$nDyi+dbD#L16HE-vnFnAzF@hGPa|S za0yYLg@V(r;#F+DQz6tU$H&lHl9u5%WAva}(bV zq~U|0QHHi+swK1G|1~;kiv)GgOx|RygD>K_(NXNdBbMRxMJn6I^7onX?cB_GdOlRH zkD@#@)UNz8gT(#B79BH|NLw8moqk$&YAuum~h_3npWnNNHpoL6i;UPfChxQGP<0pL+3a_yosVkpPUYRTY z@!FaO0ltC&j&VlgK+#iRZ#&p_3hr)Dt~Auu|9W1|o+I}Z8zZexQq;M~oI8Q#o;)1S z8dXy@3B0CSSyx$M0j5C!klx~b>(g}5QhtTWt<{;ucIGSVjuD<5S;p5#&1#GGWPI9= zj43u0=L;|U$JVRBxUU+^vTAY%-`rh&mgWXkNrHwwYs)WfUewt-C-dMa^A=}ts`WEZ znGog8vlhPP6OizFE@3bfd4Su&H@o9so$>vfStmWU(l?um0%ACwVi0ZbtGPS&M_0|y zp$AB!CF?s&ckaDE!k?u1;456<7)L&AlMsH4GfR?=xO>cFS7X@$V<|tEBZIH#fn(HG z)lH6BF`W{HOC%I^P2hmsZ0)s30{Ng+4HS#grlHy6c&2#oknmP_AINyso- z$Yxon$)}p-(023eov!=Rk;p-UD=WMPeo5cP^vdUsUuUvxFA{p7MoYYB89QOjh|eT6 zR<*Q4*FUH;qDX)~oD+~Tb|Zn`>Dxtf8WoT5YwXvQp>JTy5k%wXy z+pI@R>wMj3VBrHXVH@YwPrO;YC0}7BVF=B$u9Oizh%byCuOLlfwCR`Od<8 z?vWp>_=;tUNp87W`F{#QpcWaH&)o9B_FO-*b_=J6|iP#hsWx!=o9v>!f!%9nAE7h&VM> z_(kdO84w75a)K^N49gUCi2@jJIhs+hx+B=ztN=N^LqxDr8_1U56=?BHNUEg`8f)9@XwuL3Oi3vPwW5?+_T}R%1V0$1%+#6 ze0=;AR7#Mf-~u!VT3l@D{or`E(a(qr3|h0v=h6>oK*{u$uahu%M9N#fTFz!DP(09p z1^tNQ&n0tzyM&UEJmIy=2|f;vmWyk|pb!;ElJ4y`dQZi_JoEqD8i=}?j84@72_iQ) z>#JK(P0AASiPM1N7h`i>3mczPX+>RD$NBsUu7Ch76&FJ9$@alT0Uv_nKuS9YQ93+s z;2Ee??tTj|aD?;okZ$0f*LO0li1+RE%CPi{Xg^J@w)9q&n;v>oOQpJ>xy~peW}dFy+I?qhCgbtjCwscTOJ&Pmh#qDlBT_PE?V?TO*=};K zZ(dRAeYd>nA!|LkL4U=`<=5p<{DNEwBO2QELZsMbN7`?&X|3 z3T728UAI5!>J376Dsg9fR10ioT{G~9QGtFqEX`4-jDXE=KY+sN&AdTkw@bl?^!k@^ z22k}S*EbGCIboySWS-Nx?FOQvl;uod`cn z2nhUmoqow2y@3=hBXpkw<@m@~+gIyD&mn@i==n}4h>qvYN}fHRJuFVxacAIT|DqiA7)2Pn`i7w|hp3_RTUf@2--|*$62$p!G#auQuFlqvW&cf2p z167cSp4jRVSm*vp#J_guB9X^LXCbvuD(26(^JyYtPpCA9ED31w0xQgS{0CFLbrerb z^4HwI8|7b8$vf+Qy=~W~d#no`eUASE*Pbq^d50)Lh-g}E6+Y9mgI2B`NF{<7qPdpL zgK%gV(8)mL+_}aeC>-|Ekb%(q#N4&Q(E=Zz_**mSFPAm^Z58r zLj?pVrGGsv_^`W}`kGFhFn?ljKo$h=ui5nK)vMEYU3`vn1*3ql;cN{?bW~JHK@c#m zA?X}u(?NTnl$@NJs;X#sIAAo1{~CxJIm{GrB{wt&D!aAvcia1uuo>Ejfc@85Xu%(& z2FxiA$Dl%d!v=c6O0~J^Gto{}*Nc-)sHh zufNVTv_Klv{XQaioizl25upd{1PJc04IYU51-Acm_@93Mmw*1}LkT)miFd$j!zp-q zz%n8*%>FL>GZtcj+Zeif5Da#%_UUs<$XCSRe2QS4y1269gd@fi9yGrmVd!`J%`&~Y z5F`rB0$#YEa8??~|4SW4u<)+EKbRA8QT+$OKrO0oS zlPO2d6I)G#dz?pnt@-84!);{LoXI`TS%rm2Qxxp)noCaGKdh~4eh!D100E>a4BKFQ z>DZiKRG8_Uao5L5&P{+#lb23l#pt=Vhb1SE^Oai;>w>kua0YTyGLuGfiIv*KTThlw4 z1n1DV(kEo)3`Dwvr^_M&+#6|5$X@S%dTrMbg!=1?W~g9fh}}|1;SK12LdhTyB?QD- zzn~iw3%VZgm_eOTy<~9{;7N|4>J*P5gc3|~;9_84Kvi!QlkUt~oUgm&=NFb#du})d zuXU)W4n01)^x@mG115jCak@S6hGFC4Jh_;jOhRAPYp8cZMkP^51&78w^!Zo)P*P#f zf%bHkNn z&rSYldVdZYFew{3Q(__cmlNW~6M>B4Z|%mn&=5a}%zSddz&L=Ep;bW+JhqN4o@^Wu5B&}{4^I=2d8e|fs_5+>+)?-Yy_~!}$`pWS3UV^Cvcf|{ zt)M!Znv$7+W^nT3!;P?zkPQS%z+oE84NTx$q<=vyGyfITSpUZ*?o1OqZDFCIDN9Sb z-GkCd$br9a&$NMbS2;Q=QeWqP{KzONL6mx_s2FvLm>GnNyGIo|qFeq{Rq4j_q=hH@ zG&?spH3_gKRgzD$v$K2x0+rf>=s=xId2CNfA<@+A?CXaMF(<3t0T*OP0jvnrR8k5pDi1kDk5bt z^8xf}+zc9ccV^j>tXlu)iajucxCC(2V|XU$v%)SWh5((KB@Ctq zZa_C#sl7uZKmIyy;;ThN8oP=7%`4%j?Hw=@+_QqBr7j<{*#`~3>)+{VX>}F)YFNa8 zYGy1w`xQYh<{$s%jZUVzjHcCS224JlR1ySVu?r+Y3c5aI5{EXi=s9h?Wxi<|+N-g> zK8$i+^!(BNKuVCcA)o<7JV!l-rb(M#St&)6Nk&rlnFfk8Vu;`0;eT_o1Kwa*=e_Y> z%RnS1cA$&%?~p86PTygAGJu`ly)#x(k#TbJbaJxt^t3WI_O!BkCnY74Xo{33@w}5j zWwE}luCUy;ptQ8OxVXGl6)eQ(uv=a2Xkfrs+BvK#RzdxdMHy?!VU1?uF`x~6=Zg1i zZ-U1^-%qBA&$ac{TRO#rY>3Agxt-|lPx0iXFfz~MhHKTluuh6+S%&JUVL5S_1fI4o zrf~?o%y65Q!#it3fn3d*>)81pgH}}cU{qoh^oC5^nfD3Tb!2*?R}SSg0aWqZEq1@H zVn2HqP?%kxLLMK{69kRLjx;Iyp95&n;z(uaJ;ZFcLT3_j9nXz-=9}-A>4jGRY)m>T zMD;lU$lbo!XnrVvTD?qkT3Dj4exH`aiWeC4w)KAlvY8I7%<{#F?=~}zh0F@%BJ~co z{CnoDDe7BRXZ*X$r`o4QVPrb2fMK2t$EIOSieuhzACbxQ5_mhacF8v#eVc^d$S<&$DlR?C^*kvoi*FLo|H3)5YKSTByZs2LTx3`)2gzfzufwcVvb=junR6Pj9Tj2M%Bk3H2aU=|Q&w~co4tzxNDl7MZ3~pz;Q~;1k|9`{p-=l5GcUrGs-!R|< zo?&EhF-@Xq$S#9yQJzSz`r3U<+!1Wmy*cx}1=UQsT$k>2eGCXuWA(f*_xw_uW{Tn= z50hIHyBsawc!76(_N((jHIWELySA1a!(!Xv&x;8v5L`;N6uATeKEAF?0z)y))Xy&= z($dl+r)Tm?4#dWF@KnS{%W1a)8gF0Dc?yX~YGSl90j7Z1Urbz3&}X&Fhl*QJeoFPz z#m)%qderAbR%T`4+9z2_t1Ao((})`bcx5QtsV||wesnHE(qAVJMJZ&M#@CZ zhfQJ%Z7?-;quz1aNAKLH;$FmA>vlLtgAn_@mYR-f#qq_S8kTbjom#Srw<+#>hmwwO z_FUgh!akgA%31edUd{&si3??Xv(fGncWuAnf&&8;J$8+ErHeKXve=PB#`AMo0}RJ6 zN?R?{SN1;*yB%pI*pPYGn05XhKODFlqy|aq(q(R^m&hmm-k=>f92F7f*lo}}slOuG zV*K&jH_+qCT|ZkS@!Q(k6GL}mNQksgf3A}bGF6t+sGf3uo?^@^zrKg-F|_m(Ij-!| zot%nOVEtF4H1g|pWaMo4i^|7A=N$^-Y}Xy6b^bjsyUi+C6T$e6k#-(S8d+4JR`JQ} z6ff+@@+e}Ty(3Of*UdgbmU32M!SjM&!GrB(%>JxEQ!@cXHc4EMgJ2GIXRh`)eQTeY z$QfA~NhIs55WPz`+BBZMSjV%~f)^1VBJ`D9!O*Q;`6$_NPu>vOo$Qi=KNZ491&1g8 zqS>Fm>i_VOD80B#*eVyCoPh$=%_zhb46AxjS?(=NlZ0CDesngq&RoeTf zq_en(8-X1l9{h~6zyq4LIgTdP!TEjv#d*$PlL#$9wqff?Dnb}=wbpd>4CYiECoR)R z_TKV&d_P`S1&{dZc-9ac`Yg^83y82b;3DO$+Y4@x2KC*f$29gddfl#-rSlNLJ*xsz zg8D~&s4BMHUVz|H4JCw?MAbB0?VKg_s^V+N{F$;5jF;~tjh{dJ4)Z>AeBZR*w#RVn zd>qyI2TioEo)AlX_jTB5qZsTWhT%&y~UIe5L$d1I`5FQYPRc)+UoN~Gtf;K)=4e^U+oiD&Wz9Ksc0t_Oudz_6os&_8$R{ z4+Nrwg9r8!@QA=Z7!ip2`KJQGW*L9#A(o#24@eBoFRwYrIQ&y0*a77)xqmONgUk&- z-|7lw)}LE@yZ7iJ9jCu07bWHG>CkejI>*vd7eVggT%9IrxiP!m8p2Vk+v!WMIOmuEya-(Xx;x<8LZeD`fl4OGsgHUr`o zT4GEjXt%a9)2kA=P$w9ttF0_nsdMq+Q#$hPu=_){CZCbxSf1uZ8dia3WreT@o|x<*9n>Do;!J1nLP7%9$GxQ_UeYG zg{a+ScXHcCU0WYl_D*z|5?EGLt+J>0T^zgunip@KlVv~bi;+K@~&Q<}PIXdv~|RXI}bvi3D= z8zu0KwZ)0-&rMsb`=5Mvt%ZL5J6Jc(?AhjE(-#9IHVWVG5g>hC3 z)%J9CLMuO9lBV7~M0jQeJUqf)sB)kS1`Lj{Pwa_R)|-Ae2|970u-xlYRG+_bGr2QP z+J#OoY_Im92nWruQlbn$Tb^9I;G#3?+;#+C*7uuZEO#GUH4WYDn%#Y33n*(2_%xK5 z9kl)VQQpZmFMy{IHC>VR?B@05e)k#1)z$D5De>J&(5DrH5Y7E4v}Bk~D!?y}deqb~ zh zB9@v6>*@N{Pj~YYrtAYx%1z73fi=>!?sRqy?`NZOmBA1KRLpB;hqqa3XA8pZ z))@SWv^~owQ{eH`+n>_EjK~eIclsThNVZMCMszPZvbSFcX5i?~$NWcs$n?71V~11=m&)szI*Go84jf!%3cquRGoF-9cexZE&$aUL5qvCu zuuhmS6{}k+X;1R3|2&y_v?oG$G*+hzZt_;9HOrkFb~0Suk|#Iz@|c5?&3c?@>^1p? zus#%WeJ565hR)STIX%Ukez=L#-#O;nv?gN0+UcwvHWu_A@mjinsW1_2zJIgYdMDGw zC9pfIB*OPjzcZNT5&b-mxOmy;Xv&#v<|Fn2@bYCW*GP@Jic5&OpX)&fA9+AFIZ=oGVq)P=_{(kPnt`BN z3X9Zsta$55^XBBLHG{qQ%J1J83qvc+DFAh@lZhC~$VbXkdZso}?&(?qUgOF{FsR+} z;Y}ht)%---^J!#2awk;A)5G{C+kj_5jV!zUBDkocMiQAu&G_C7LGXcAKl-k2Qb}0} zf5eOgIeRQA{ZZpAFnReVNO+jOL%1R8tnasW)QRfej`M-QkP_8R9*w!AtNhE+t`ohY zs2Bz|!MNc&gFYPO10!y#C^3Q7F~&8S1sljN=jcknYN*%PK9{M`m!;^_dro2-k^~mWY}yU*FVDLyjdZ_Y7ITgCd9vwHe|69GxV|sOU+ocZZHTepeOk}n zf_Ey50N|8d&=ho*=j53UL8CzNSen2GHl$dqx6TZC@5CE+v8+Wl8sErVk32n^98Q0F zxx?`C^>>-FVsw}dIsFsN(%9<# ze&iuHxnryH2dMo!sO%qbOY!Vo7ZB##@E*W$fqe?EQ2>bcFX-)m4fp=3!2ciI2nb4@ z`dh8sD_Gx&td2LqD#U~D5h}$0oyYtOtuk7+A@@u>*E6h3r6Bw}@b!O?oQjYz*gICh zGJn13Ge@!Y50IMzPv`Gvwfb&C+Le1VVcshX0=}>_VsG+)t^6N=RN}^fWba}7_oHq z`H@YH_&kZE^?l4u?hL)QH!Z)~T@K@vmTlmgw1(~6Y)}oBYDNzaWpt_YUvi}=SuHR62@7M||m#TLs$w<*YA_3XtQStm)7ihfp$ zQ3qzekmXyn+^(y5B`j!*SAW*y4uTX86Y_kGHAK8@f;1^e=obI{Fkoo0jew`_{`%Q! zyMM2EdY)Vf4t_C#Cy8_8qX?l$;2?*6Qa|UO=+Nr*pzjW?M_JE<;&zANAO8!lU^><@3$56Eq_8 zHtDjieliqAQk;I^3Bn+P7EFkvIi;iIkXwCYK7b$qvrD%LA>@FS;4 za}Wt7eHoJfaDEpR+-5$|VOREAMeY}eY4!|fQzK*M)%E=Y#hN$;c1U8+Ji)@S1G;9z zZj05>7u@0#*%j!6?Dy{<*w9Z8<;rP>b1_90k4o}dNW+T~FAkd$oL8LX?b=!ljt+Ulc?HDs|wv^$gek+@W3Fc3M-syOU7SEi6(!%q1}VD zItcQ2E&Qnd(6GSKzba_oYCES z;UlAo3jWg(;H?8SXNClf$)A|Mtr{yLEWZbHiTND|seV_=QQgdWfA8z2F!SQ|%#X43 zm2RFNwDLzUR`Zt+ud{Wchf_hQ$Knb20#%uoJIS=iQEPtpP@e}mLlvidr989rX6}Y7 zrydm8GR)?c^aJ%8x8WM))qBAVI}_;O~E zOgtUP%y&3YHdH*nteV!Nps0}e@#OW4c;*+!8_$FHvUN5}=*(Nc7Q&!AFNg#i=zooUyu72`?tG;m7;Sf;)#Q5E2o07sAV;d^iV zA3&@t%h_VguUmQlV;RLZj0be@`&MG>@zW63a9rjikI#zvG`179 z*ZTP9sV-JLsVx|6&PHH^+j^t=)-vXPyNPPyBmal(*@juuCHloonVA@k%7qGD+Z(rR zQ#G5M{lRR{ld0|EFQTxTN9X(PY!^0#MgA50#g&g%t!0%a(uv7w)UlP-uODc&omT9Q?)EJmRmdgb@#{JowhEvXLNo z$)3Vx%m{JR^ZCLKc5Q(+6}Gp|c>5|nOc}=KULS)x3#ivHnfcXL>>)@q(WH!E?tg%W zpF4Ba@Wi|S9+cSxq7ZKV#fA%Uoa+G~qlx)HSnq!#rTz|o{y|nTSFQy~_ z*DI8dAjvQS(%Yh8&EuhKl9$!>n%}1*zv$AS z{|nFnfTF4q5M5Sgb)=IJ6Q!r4*A70y@s>f@$0~sRG5?K?U@==XEVTZ3J3ta34jxh0 z;Cg%~=MxRFMiA()JEx|4?0BgCc!BX3OadmF!!Yzhkl`>A`R}(!8d|x_!TnESwGb)9 zOUjPdD@@x)0E@_$}cJN_nTKv6g%%ajfF~4shWPAIcEGD?{Fo7!VWBt8p z{?U;C#QOcCM}e;VA8Eq>LLYuyYBZ5I6Pdf2eS{yWtBzvU?ZPi=p`_C4c#v+`l@E+WCx>l;s>;~*4h z43-i1zaCHGJ@F!+04Fyp78;vXR#`16t%ckAf}E@o=3gu*<7f`w68$x}kQS%i(vdi` zEAaen|EguGi{M{lus~v%xvD!nR;&kHz1%>&D8%j}y=%|B@*lFzg>KxS0b9l}1ocdm z?87B+P00w{UsVem3i?^;iIUB{`1fj@Q@mqd`BE0$O8N)KeIyLgaFUCbJC}UiOnq+g ze%U^6RwYRTJw?~+TMJEbCUs79$NrZSEh$MAN`F%O=-*T;aL_M6S^ z;_ja+i`YH64`Z?17Ieogn?*DYRWqcp) za)w!M2?B7Jl$61Am(3-ir?(qs#V#E__gxdN7mn19X)Iu3 zVUp4cY#AmX{AixctvA@Z?tyj^R~D;d&GRgm{cy}k%?j1#p? zqV(%{;MD+8;3W^a&%*Kf-V&c?tM@jqPZ5=!Lj1-DeS)=pE7_ltiy7YPi{5*+sANB4 zdVwz9i*4Tg5meNlbw5GP zj@bx~0Gu4spNi>TNP6F~c!%H8Tq;)uD^lK`;bc;Z$NZK?UFn3VXN${U=arhWCSeEC z4XWca%CD$|B*yF)oE!(pCy9duKK zEX0tojc7vIrjgJ8f+<=h@p-;z<>n2&PxuG@4$4tkb#Zzz5_jOO05U{mvxRrJsHtQ= z_U|oNhLX3lesvN$7`}0P>%8|jaBglehI6+7XE*a>(_S{~?6x>K2635DYXa~n3O`fN zvogC(>1tq?ZQ=-~PgxXlgJC)AGx6qrIA|og5$2?m9_{7K+QQ1Cf)3lSbXTBEOFmN< zF@Iie5B1k@B2!~!T&RC{;=;+O@be7-Thh5E`9X7K;|DLP{JByok1H>Z;GY8e2>Yzx zTMP@i&TaqfcaMjkUuo-nL-vUMKeUSizW8JO&+e>X6l8|wh55eB&ajS&!Ym`5U{f6_ za(U^8OJ)knAKydI>BdZFvuGw2ys_gEDj`C&22^QL#j4BN_rnkUL33WVxjg-jb-O05xK*z+o|cPN;8h@r%PK16bTYdzIGbk@6Xy@i^=B9mlve?Pxomoc8(_I^PoYw zejc-3U|nc(Y0(vEJOfUVaGbbfY0kdC6$a|;_{3WwH=K{EtTcI^GB%%rhBah{rhAAuS7hiN?rzLOsuz7HP{&vU^6VQkEb{b(L<5MgMQi z>8z6HaM2?jx-#Oea^7zw;wHW^meq20@hRcE^x0i@74l0l%Q@r-1B%dAO;q>9r*2X- z!WrNA^AH7N`6s6nWx;5w+Oq1ONfb_R#D0H2TR2)nMMhGlLc^3?e6VA)+`F6DZ9b#{ zZ51+yz=%g(&dkZGe`g>*pgD~s?sN8kZ)vt3`1KXxUi;(x={Kmj+>2}z$i2qQEtY`Y zhs)gK{$NY9o|G-GU>s8eZNd)F?>q!+eZ+^=b*l|3g=P1hT4$^ACinR|bXbHaY z8#H;ZZp?B%>>u?TfUThl!CElZ1Vt9Oxoau(pXTnpeHTtds%3_s-L3ytK}d|f7;?Krkk&h=Xi=~K-Qn597bO-kx9ssr#si6aW@dClHIGjG@f74 zNZ(tD_~X&~B^^5*Ll(%_jq##W(RnEr-C&?Yu!F7v|q6(;O@w) zLrn22|x>P>Id6MQ_ zVYIihys_SV=W3_yi7XNKf7rmaE|Y>P1J$2A#Gwld>L@8#fPjr(!~683;3bmxc8^UL zdZPZ4{uJ+zw!MUrN~-ku9Bm`Td{{G~TG5soKNPUvrVRtAsMcEtX1cpA4i*|^p$VCD zbsWZ3-zj_M*=VT*yf&GO`qG~z91bAk#(xi0uMAPcTwPtQjuez(4?4ym$$;|J`mBC_ zvYn2zE7MkBIa4fK|3OVerO8hs1NyutOuCe4qpH!oeSw19z@-*6x zS8kpWaUzl|?Pn_lgiOqp3J7ky_nc2la@8C*noN(~qfO=&Om{uEBNX!7E~Cs|a=$1W zOj|3B`BFu$`1~0F2ETq^I}3Tg)nS~gE%C96s?xmCitir$hrOhNDpe`kYCZzE|d zc`Zs)UB+j6^~x6&9@Z^_TEwc{rMB}nTh~_|-tR{TF=!{!Ky7}fJ2N&F_E`J!*&JJg z2GuGhLkFu|t*HY%lTqB;OF4s5fj+m|x?CvJ*7J=J0h)>r+oL-~%XQj*=YQw9KX;{S z^?9#cDPd8Cd`^6QAmn{NlAR-$6EsFFZihDh4F>VL-oxKADm`m8pyN#P(q|Po-oGMF zfrZ<0Zi*4Lde+sMpF%&t7T>Phfd$O(HFgY9oZ%)9Hd&ggZ`MV~!KmU@52e4n_J(jm zP*8t*jzLVT)Eua&k4!dutwrip&^?|_c)D6|DG&orPkYk`I^9s9p`ii7uvFGIQ)gcX zD!i>x>h~cbb)S`@%@kFU{zOmzqJ*ygxtc83>sVa~v>o9NcY|IeF#a9~^hab3i%htec$rrc(myWc3p zP0*N}pNcm3dCzPTqshXl?G~GYvrV}#3g*zh|5V)ovr`!o>D!*E>R<*-QyORj`V3UZt{;ExyAY_c}YE*4et2xPh*T<>6%4M zOlPe}GhWFsP05Gq#LNYne8t%NZfg@$Q(8(XaHOqVLXbLlj#hukuF*)@6T84mG?c)k z%YFle1d!n47v|?rH8`81xu3^rMF~dj-x@FSXcI?o)nd8~jzdVgRDTd36_ah+R6Gm& zY987Ipl5&qGLY`?3_3py_|FPA_dO|5VLF?yOg` z(Pv_{tDDaZ98B(hF+V&_l+GT?Ez*cOb0>E5t>=-oc@LpE)N+0ka=x-kP2LYAUTbe3 z_ruUMrvoGOyQToxgL&=M-HG|$YU4%srt}AV>V>($(g&;ZX_2&?cz!JMXk>kg^Nx_S zC)!}+1=fg(aVk&K{5@1cx!J|+ZPZW$dDYQjC36?)i2NcqsZoZsPU#4<9*CNJlxk*> z3{sEBXjUZMI3Lq^+_?nuPK+L&SJ4|2(&kpOk~m9_Rhhy^ykBMV1{R)g;3jop z_)4Jdc6oqE8yzR+^8OI9`c-ngWw|1CYd1GIEg2_IE%Z0|!C%gf61OsKa?BCuv^8&D zR&EMoRxrzIwiRnUO!^x>YWA-@?1r}sb8o523C?`B`^PFs+JYDm3SxrTXT^pv*b$R|6SR`yr0KyC09l zmayomouDV}NO`AGXGyC7N-D)hO!-*Vlu125m_yJ1Cs;cnu{`XE*7Fgv$0rp{^G{u& zFUB%slzZ~bv+T(`Z(OGmHLb48HvJJu8sb5Hk7GOIq)|F6!qm{NxwHK;^^4MNpS&_p zmE!5VuxtWChTP71p%b(ff$=g)(hG#0UA3ya#t#e0?1#&OxYgKds1_f-biLt-+9OY3V zXESkYXTbrWR-MEo3_}b}M#;`ljJtju{N?FYz3I(DvPbTrH+^H_5k}^g7$1=94+hzq zNw3`4=#tWrFUM~2*YTApb3cyit|HdwdFY5&ZJ3S@)4nk?aAyb-I|PxzFU(O2Pik?y zdNlpnD|mIzv(ue#$skDCQZ|>N^EKiI0XWT=q(6+`NUAM@np5Y^U&~<82!%H_-o$$- z-|iNl$ylByn7G23i}Z(5blzP5UtlD*a9Iqhv`eQE8Yf#9NfYy1h&mlri2Menc{U+~fb$SAAZ}S- zi3R4!dAJ3L?bqe$yp+HQNgbfSA0P_8{WMExZ|m?M!ok?+`u~= zjY<8IM9+a!(Pa2SJSptwVo6H@$GD5LFjMQOXs<8T%4r-51F>vRzmU*G@-6wyj3stj zoc~^2d@mOOilALl9>!pRzL`G{27#7W7>Q{;W)UG(UxUA{Ja&54__3)~=^Dly$W#t} z2zLyKqq$`VTDY`-W`!Hbi@AO?Bi8MLPpkVv{pNjaI9$WCFy9S0ee`6~p5LDtN=Cyv zIe40_DwxXOWcm=%tki+k6+~+ToMpoX@;ObI)P^=AhidH5JCt;No?PM4@>|RyCnd#} zFeh0c{6&sDq&l&Bao5S=74xA_fY&wPuu+aZ`?WWhjxSra8w=#cZ?y1gbkpwfhq7ZB z(N3e@&dTXccz3rWjsbGXyT43phqwJh>>Qq2)8ef-eewby^2iXlSg^HJbKV$WQ~ z;}IJJms`8Sz}kt{r>`3VaH@P4z7Y^!>q=*%M`k$5WEpsEfI*rsh$+x^(LYZU7^2U$ zfb@TjWF!h?kk#67Iqazecam)!J#JBo-u+b|KU|WLQDkTHTfV0`u6%7k-{`a>Zl|7W zO(&-V&*#AN1E1^4*rG&I4K|!sJ!l_#jSrQRwHAX`%qQUx3A4wLEJCoNRcnKX(?2&R zQmRu2+rQ)Kw>+2;3#NXzFmhziR{>uQ1xEY*Q$rFjqxo;pE5{sXAUrLUL%Y`cet$j9 zRm^RKez1hJgI?aP<4)oCh=!9n;i{dW1CjDxblaj*8UAbmmA6D@|t0!Eh-p z563GGLA83{o~d)D325^>_dOvEN9W;%ec>nPR(94r$p%3q1 z9a?F`1|zAr(@$fpv^fvBa-8d@)eE*~e0m0#Sg`5FG1aPz$0s!sTigZU;nPPlvXFNp zW#dym+q3n~^;QCf3C#A-fWbt%tP>6i-SSxW0SO4i%svLqKHgG(%s2p#5dFt<_=V^v z@Ca3)(;ecP3$GO3<)xp+Z_d7_OG-$>K&$7Zz^{MV9uQ~$ujlaSZuoSe)j+6RG=qE%+6@3o`IPauW|uEKVYXB7BGi{!+y(z_qzF!$&H^QX^Rz7#R2<@O8q* zYa}+VwiwJlMFDyXKh@LI105!m%*5I(E$9<LbS8l&e;%Wo`?~kCyB{_zUt4h%h)ts~#U66b&+Lda>X)IeeDfFA~w^i|_Z5rJFQ8Z~GlN zrnN@GiMAgwrnJ$4#X%T3N67MO${~F<|8FG2X&`bH>lB~|I4$sMk(gO~&T zjf@nitHODX7*Wl{dvo@|4-5>bHIvoc)RWvJ+!HH>0QWwnebzV4?a;S#pz2zBc;rvg zxD|Ie+i7O2eET_i5fPP`yG~7vCia6RHJWb4z6;CTTlnsdqMYs;Z(bB9Q>6sdx>;)> z3iP4mVLWZ!Lole7jo_5hs`Z9BM>*^lA$CaVqv@@jE{0ZsD|(xg>g)#-3}M^QiuAm? zpg=eaWLjxoKs~LTW=ol=&96It#u6q5Y`QXPj+C*Rl@FUu$Gk|FDZO^!+t5(F2A!Am z(ZkYLrhQ}`L@ZqPB37kd+s$Eb0a;k;N!1DJyeg!$uNxk@kvK$LUo6gVj@8|Xuytf` zw=cPG@mo33qD!6%!vhmXN=jj?R#y=o-i2NDa=IjO21=WQ>MTV%C_5lwYCv7ElLuF(>7yk6t>*;s9 z&xcS2c(az*-tt@4R*rjDqD!1DP0n|8MI)E(yp8pT)8>2m#%#>R;3%Xx9Ss7(X1zSE zrl{N7w#=B9JD)pz5|WC0zXNT}1vhCo+tcVpRS*dMa{Oj{6#gZl#!ATkE*qWewv_mB z7g8xozu6_c_S(m+6SzA(AJ8@8J+i#|YA)>a95r zW0botGNE|XU;R}qy8>f(y9f2~gm|p9q}1Faao`e4v=r^r_z;TsIvR?!()XmeYXRfPNYp&59314C<@OaG^w->UMm2 z@p-X&Ov$Ul5FJ)K6fmaDGV3&2Zts2i$YWQR@Xd=9}-@&Z6pKaflT8mcVc#le)n&QiASUryOF3Y-aukJ~;91sJr8C9t)GlAngzCMAOTu41f5HVeE_91Ms|tnIQFgV`*=p>X z(O|y8Iye`aulM*)1K#eSFD9@oRCfWMeOk2~MPDIn-&S*Ero^J21Q2~}bLDqV1%d+` ze&eP7{qe!~>={dF>73sEXTKrx9$??Oit4=60R~G+L^La|6{W1X=^Kyn7cb%b21NvF zn)PW1>?UvF=~PJz3KT$+{M`tc1TXyj0xiE{TGLI_?V|f~Wq;i);$76#LVCM#G@QmF z8}({|YnE*jbKHh~e#6x-XV^{0W%ZkV#hsynU3v0H+fTEPEQh`cyQR1F)C21U;+>_MMf{+_Ou4um%MJBu zXbox}PnXCuKx!)Y=Hk3$x-l{AF(k*0`Z!`VpWF0e;YdB%$wqN}x%mOt%pUL1K-=&^ zVKWU=<4=DOzf$eaRjTfu#jU7cD5S!mfi7t-zVbaTjg=o<{*ioF9HjG6iX)udo8Q+L zgqEx1FaNz4fE22YwgrK7Zqs6a>*6v)o!PYCOwflze_F_2)nA=drtgMN<~W?|-1Y?Z z@9X;48>vQ}u)DJzd}#S;(_h$ViTOgC1Cq(hwB(OS1%9bb@`3LDdeu(cm74<%jhLzJ z75t?9HO!#5Yi4Yol}N^Pw>aI%Oe4&{^68;6KNsBA;Zb)zO@jO^(S4CT$3H>CbTO%U zby-k<;iz*c)YviMgS5TE6>ewCxmE8kRY9#e=CL;w!+FnTG_hgz*}}%bT!^K$asuVVkNd`3sI&}R{ zV%Hf(v!7Z%=|@~#9LN3N z-w4FSY4DT;22yaa^5jG8{8c;yBV#xmVgulTvHp~Sg|8hh1q(}C(hR*uG2m=2%(?zg z98UU#zVO#jMa$MJ1o+sh4ofXSB%PVDadbT^AK!IejA>7#gt+)eZS7GLII)6WK$PoM zMbzHPN|ojCI|4Wo`d^?0FfJUo0YdO!EYhc9#LU|ZFTj$g)%zOHeF^_0ip>wu{^Z|w z``>4UFUOO|X8&T=|L&d%B>U^?l3-38&wTRaFGTI5SD?}-VDd^aIMr}EfP=QIO1&sh zb=-r-ADP;S31ej{5pNDkQ!DG<_j$c_*BB8QL;*Bbr+boj>*ybbE9bDzaDP)#eKQ@} z;U+@6Tl?^Bt556YC-Jsyf2q0VNXM66k$rsZ5Uy z86?7O#JA4B|EuFpy*6PQr_CykubYWPSwJ(>Rq^n-7u!={7rc`d&v`c;&J2X|p%bmq zUoyi5v1;UrP8f}pZIcc|Lll^*Jm@IAZ7=3>#Bf#$4OR~W0I))lk7wRr_Nk32KeYkp z@A9oJR6k&#B)Xtp-pg-Vrst{cT~G7QB8otPN=5YNbhB+-rD-l9Nu>5cM~L3cdrF4w zSMB2?GJY;&QObVzQ_eWG$i}(=OaoZ3f^@WG!ts3DpBF2+Z!}R%ERsmj%?Wyc%9i}) z=<>|vg5VE>JTGkbs497Sin&*jGP|>5b!Rrxr?DK75bsuy_ovs=P!(9Ne$Y-^mHbtF zO6>sM=>6XAK8Mm&ioeX81E%f$#g!nB+KIoT2f8E{gA?|R2L($B1fo0ZqO-szl0Ipr z<*;z|*{s~G?jffB_S}cps(AaOx;22iTP(tsH-)46-$5+DyH?!Q>?drB`{b!!*=e9e zWd_Ek)|^fkG2>v#be~$sRwXoD`Ag&*a~O?-p|)tKinu1XA2!~nW3cfQs139{B;*Z- zS0%EP+5;!&nX-Y+Mp_$5ed+NDIxFP!M=c>G9jL>n9R!E1M$7}(wceJ@XA;H zO?30x=VhUHt*KgyA84p!tsoeJ3jS#~jUnJn`6eESwk@<-`;T=KGcWPXEaRbCv<+^Y z3?+4$ro*;Y#bOhpXm~(I7VlS_wk58d>uNzJ>t%Zs_}M)fqZfkB>_?{boD(%uh$`#N z@-*Ib_pvaUOjyn3YXp{TTS}m~16*0I3EQ7Hzu#W#MQbgw>ut^im4%29N@~W3pjfmG z*14xz-m~xLmR!`P$|y|deGc5u5IPlI{Kv`)&$r!FsVye9u8(2f4Yz!8@M<-F_~Utt zyM4S-V9mXzy!IpeADi&>6KT-5Z;?d2>;a8oVSnVP_(6L=tE#fQ9x>m^&QzJLsVNpN zE(~nGu&@A>+mjZ0l(tgB!k_S+**Q?|`O?bD_JNeN7yI*4|1iyn0omIT{QBbjoXN?d zFNR9s!-r0DD_Xc5pzm5-^qVf%zv6Fq;e+VZJ1Ag11%#Ti2=HL*_8B0pGFMJKf<~`i zzy<92`u?k&e^_SD(c>5v=H?QQrroC%@_GupsZwn>e|T@&PXOfyi!L}ms)H%bVSzlD zIC(ZbCHnk$je0}7Fa+=0%k9PH3kq^_tSSNj+pXH9Uavo(2%E% zjV$ozkf*F{m1tJ)TP0c9fnHD0{2`6fJBIlF&d!3BAE~KvjQ29K*gai6xw*M}F_g~1 zu~i>{wAJs~=!~tb?5wP;jEpE_`#Pl%5X4MPDHuvrVX&#|YxYPUKqX{WWoNGprSg)z z^Jk%_XQ!s#xxf1!{Q9A;hEc7lCce?j8YN71Vfe^A}9MGEb8J=N>Xx(gPomOqrZP(pnYMXy}LVKlgUy}4#hwM z*rH!OwCwD#tx;28o7%k3tCC!Zi2AjP)${ZkLn9;CyE4ZMRXD&~R4-qCTOs9|*u_($ z=cq7Yyk_?N7m`yUeB!&HvMK82IAZr!q~)wi*peLdXA(*KV75i=1?dOim6Gq zR0P3%p^5-plRYFPPV>+d6bs$sORM?T*xBtt?m$I6RbH;2AP;lyyHl8-o;&n1{a^_<}bk zE+jsX`o|lWg zy*|#)ujLh(I*rbTsoqpG2V2?LIGC8I%7f*Ku-^%WM@2-0gocKOG-e2hhcHnHCeRw& zn444N6EQI85)w+;?pAGVfL4?t{&EKJHT*>*rmNdCT3N-@;@sC0HBKVre|coQkRx@B zgmip-?7Wi0bAJI{=@oNkXJX>Kf#G=r2eS?|rO)be=ojr{8J;?CB2D?_^Jf*sTA-w; z$#Ql5aDc;CGUlVPGFDYJlm;A0la=v-fq{USg`B;Z&fMIB#*4PzHk|J9y?H~*yxg?~ zWQyG(eAS|fnTDX~X#5>n0>Tu00*i?6Q6?eL(L5%lW%jE1;XLYVIHG{Yu)@Y*@bNfn zyDNSuC7k6^ceb6hHA@8JHd#4Y zYc-KhP?M)t)KU0m02Cu{QPaV*Pq|SC! zwqph=`dRY9Jpiu8y-a#f%DD)>NNzjuN7W50Z%oDdbB|P?@38)E*<{&8)cCPcWLPYA z4M)z(Gn53~p!47X=%|fahBu01n$Dh2ao57Nmw#(cITgpmbYfd&`dS!ALCCh$T>Hf* z!^O=+0yb7!WBqc?dJ&IAw?p=ah1+!7ViMw&%)ETMSnCaKZR5DiypLVpn3#x*A*^n=S<1^4`5!{vtwy=@s53)=M#i$!V$F(-N= z!xIw|P$;y$ePtE;0F=P?_7Zq-PX~i_lG)AY>K&nZa(LtzzyzPPx`{Pnl9S)!;%=nu z$A*cA@`p8nbl=>AsVHH@n|B|Iiq>yh%<12y>Tx@4G+q7{Y32jF&}aerp|A$1(^lxT zaFrOnWx8k{ygVOxGjG+V4nDrfy1Ki*XD^yUM;Uh4wN#(-s+WydQY&#IelbVI;5+rRClO)6Hf7Tni+Ov& zEm6b=tEz`($iZBI{{q+D(EtyStC!DfhZ6XclalZ;F)@jVN>8F`9T$oKLwG!2fsoVY zOcig28|r&n)T*IV>r`>KxTaQ=<-duQ!Wn1YO>(ludR%YDN#gemFPn8LPNFvHT5fQl{?5b3goPtp-nv zxUWA|8ANYzU+_yBn}p;+=JvU~dY){2W+o{XR_w}gN=4ky*hHKaXx?r-N3TCGz$M2d zn|G_rR_mu<%`};DYE7#QekJ!$Yrq_*fZTV#q+~GavM%=IWPjV7)hIe}4H+Q%FkZQW zHsck^I*6gmYJ?%_r-|tq_9tzb4GpJ~E9*THx_o1J8 z+|RT2MkI2G-@o{6yqBHj(_G%L52Vla8xHk$^h?_skdjJdZv7FDMBuCa)wVzLyIJlB z1<#YU+0E$WZ5gGN0|S9p*XoCFDB4ida#o|eaxz727O4<0kor>!9GWyAAkg=dYluKA zU-D~d2AkFSY-edmT+b}A`K-0UIBE0gUWL$*+ttIYsnXG=^MV+x>{mL zXfFY4=C4{oL%mCGy&m0`|9xw~{4-`43){7CSFu6)K}t4y#6hk7^iX*o?ni4 zzt^7vPRQ?CN)adT>{@({(hQ*8bp|cw#Rlg*ainUS$zs5aX?9oyD}X035k-3egMc)3YeD%+dDft+Or>Z=V#{U6Paue z*VMCI*2h*x@)aol6a04c_GT&)<2ie-#)O2(jE+{qF|YG+Wu;=Fo0IP!uztvO$iCmvNQMUFPdktvge|rD^=|%(&!V|z9 z_P;RXzw&YZx3}?Mbtj>J(zouSgZ1ReZ2>Za;}JY_0xbwmz`vdGzx|t!&5jJOgpA5( V>_4#~vI3+(k&#doFBdiX@*f7Yf4cwx literal 65183 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 YVJ3Yjw2b?wtEx%9LMS65+Lo$8% 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 + +

    Install

    diff --git a/examples/graph/17_network_info.html b/examples/graph/17_network_info.html index ebec84f8..62cd9eef 100644 --- a/examples/graph/17_network_info.html +++ b/examples/graph/17_network_info.html @@ -24,16 +24,14 @@ var edges = null; var graph = null; - var DIR = 'img/refresh-cl/', - SWITCH = DIR + 'Network-Pipe-icon.png', - COMPUTER = DIR + 'Hardware-My-Computer-3-icon.png', - PRINTER = DIR + 'Hardware-Printer-Blue-icon.png', - LENGTH_MAIN = 350, + var LENGTH_MAIN = 350, LENGTH_SERVER = 150, LENGTH_SUB = 50, + WIDTH_SCALE = 2, GREEN = 'green', - RED = '#FA0A10', + RED = '#C5000B', ORANGE = 'orange', + //GRAY = '#666666', GRAY = 'gray', BLACK = '#2B1B17'; @@ -48,13 +46,13 @@ nodes.push({id: 1, label: '192.168.0.1', group: 'switch', value: 10}); nodes.push({id: 2, label: '192.168.0.2', group: 'switch', value: 8}); nodes.push({id: 3, label: '192.168.0.3', group: 'switch', value: 6}); - edges.push({from: 1, to: 2, length: LENGTH_MAIN, width: 6, label: '0.71 mbps'}); - edges.push({from: 1, to: 3, length: LENGTH_MAIN, width: 4, label: '0.55 mbps'}); + edges.push({from: 1, to: 2, length: LENGTH_MAIN, width: WIDTH_SCALE * 6, label: '0.71 mbps'}); + edges.push({from: 1, to: 3, length: LENGTH_MAIN, width: WIDTH_SCALE * 4, label: '0.55 mbps'}); // group around 2 for (var i = 100; i <= 104; i++) { var value = 1; - var width = 1; + var width = WIDTH_SCALE * 2; var color = GRAY; var label = null; @@ -71,37 +69,38 @@ edges.push({from: 2, to: i, length: LENGTH_SUB, color: color, fontColor: color, width: width, label: label}); } nodes.push({id: 201, label: '192.168.0.201', group: 'desktop', value: 1}); - edges.push({from: 2, to: 201, length: LENGTH_SUB, color: GRAY}); + edges.push({from: 2, to: 201, length: LENGTH_SUB, color: GRAY, width: WIDTH_SCALE}); // group around 3 nodes.push({id: 202, label: '192.168.0.202', group: 'desktop', value: 4}); - edges.push({from: 3, to: 202, length: LENGTH_SUB, color: GRAY, width: 2}); + edges.push({from: 3, to: 202, length: LENGTH_SUB, color: GRAY, width: WIDTH_SCALE * 2}); for (var i = 230; i <= 231; i++ ) { nodes.push({id: i, label: '192.168.0.' + i, group: 'mobile', value: 2}); - edges.push({from: 3, to: i, length: LENGTH_SUB, color: GRAY, fontColor: GRAY, width: 1}); + edges.push({from: 3, to: i, length: LENGTH_SUB, color: GRAY, fontColor: GRAY, width: WIDTH_SCALE}); } // group around 1 nodes.push({id: 10, label: '192.168.0.10', group: 'server', value: 10}); - edges.push({from: 1, to: 10, length: LENGTH_SERVER, color: GRAY, width: 6, label: '0.92 mbps'}); + edges.push({from: 1, to: 10, length: LENGTH_SERVER, color: GRAY, width: WIDTH_SCALE * 6, label: '0.92 mbps'}); nodes.push({id: 11, label: '192.168.0.11', group: 'server', value: 7}); - edges.push({from: 1, to: 11, length: LENGTH_SERVER, color: GRAY, width: 3, label: '0.68 mbps'}); + edges.push({from: 1, to: 11, length: LENGTH_SERVER, color: GRAY, width: WIDTH_SCALE * 3, label: '0.68 mbps'}); nodes.push({id: 12, label: '192.168.0.12', group: 'server', value: 3}); - edges.push({from: 1, to: 12, length: LENGTH_SERVER, color: GRAY, label: '0.3 mbps'}); + edges.push({from: 1, to: 12, length: LENGTH_SERVER, color: GRAY, width: WIDTH_SCALE, label: '0.3 mbps'}); nodes.push({id: 204, label: 'Internet', group: 'internet', value: 10}); - edges.push({from: 1, to: 204, length: 200, width: 3, label: '0.63 mbps'}); + edges.push({from: 1, to: 204, length: 200, width: WIDTH_SCALE * 3, label: '0.63 mbps'}); // legend var mygraph = document.getElementById('mygraph'); var x = - mygraph.clientWidth / 2 + 50; - var y = - mygraph.clientHeight / 2 + 20; - nodes.push({id: 1000, x: x, y: y + 0, label: 'Internet', group: 'internet'}); - nodes.push({id: 1001, x: x, y: y + 50, label: 'Switch', group: 'switch'}); - nodes.push({id: 1002, x: x, y: y + 100, label: 'Server', group: 'server'}); - nodes.push({id: 1003, x: x, y: y + 150, label: 'Computer', group: 'desktop'}); - nodes.push({id: 1004, x: x, y: y + 200, label: 'Smartphone', group: 'mobile'}); + var y = - mygraph.clientHeight / 2 + 50; + var step = 70; + nodes.push({id: 1000, x: x, y: y, label: 'Internet', group: 'internet', value: 1}); + nodes.push({id: 1001, x: x, y: y + step, label: 'Switch', group: 'switch', value: 1}); + nodes.push({id: 1002, x: x, y: y + 2 * step, label: 'Server', group: 'server', value: 1}); + nodes.push({id: 1003, x: x, y: y + 3 * step, label: 'Computer', group: 'desktop', value: 1}); + nodes.push({id: 1004, x: x, y: y + 4 * step, label: 'Smartphone', group: 'mobile', value: 1}); // create a graph var container = document.getElementById('mygraph'); @@ -112,8 +111,8 @@ var options = { stabilize: false, // stabilize positions before displaying nodes: { - widthMin: 24, - maxWidth: 64, + radiusMin: 16, + radiusMax: 32, fontColor: BLACK }, edges: { @@ -122,23 +121,23 @@ groups: { 'switch': { shape: 'triangle', - color: vis.graph.Groups.DEFAULT[1] // yellow + color: '#FF9900' // orange }, desktop: { shape: 'dot', - color: vis.graph.Groups.DEFAULT[0] // blue + color: "#2B7CE9" // blue }, mobile: { shape: 'dot', - color: vis.graph.Groups.DEFAULT[4] // purple + color: "#5A1E5C" // purple }, server: { shape: 'square', - color: vis.graph.Groups.DEFAULT[2] // red + color: "#C5000B" // red }, internet: { shape: 'square', - color: vis.graph.Groups.DEFAULT[3] // green + color: "#109618" // green } } }; diff --git a/examples/timeline/02_dataset.html b/examples/timeline/02_dataset.html index c1987abd..ad74d2d5 100644 --- a/examples/timeline/02_dataset.html +++ b/examples/timeline/02_dataset.html @@ -19,6 +19,9 @@ } + + + diff --git a/examples/timeline/03_much_data.html b/examples/timeline/03_much_data.html index 5d778975..db94f807 100644 --- a/examples/timeline/03_much_data.html +++ b/examples/timeline/03_much_data.html @@ -10,6 +10,9 @@ } + + + diff --git a/examples/timeline/05_groups.html b/examples/timeline/05_groups.html index 880a7326..17b85200 100644 --- a/examples/timeline/05_groups.html +++ b/examples/timeline/05_groups.html @@ -16,6 +16,9 @@ } + + + diff --git a/examples/timeline/index.html b/examples/timeline/index.html index faa6b2c4..937d5dab 100644 --- a/examples/timeline/index.html +++ b/examples/timeline/index.html @@ -2,7 +2,7 @@ - vis.js | examples + vis.js | timeline examples @@ -10,7 +10,7 @@
    -

    vis.js examples

    +

    vis.js timeline examples

    01_basic.html

    02_dataset.html

    diff --git a/img/gallery/graph/17_network_info.png b/img/gallery/graph/17_network_info.png index 1d0ee70b7a2712b0dc94310a190db25657e7bcf3..aabff0e6358655728a0019d167b3cb78c103b020 100644 GIT binary patch literal 61961 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 literal 101101 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 diff --git a/index.html b/index.html index 167ebbeb..65261521 100644 --- a/index.html +++ b/index.html @@ -76,19 +76,19 @@ bower install vis Development - (version 0.1.0) + (version 0.2.0) - 384 kB, uncompressed with comments + 441 kB, uncompressed with comments Production - (version 0.1.0) + (version 0.2.0) - 34 kB, minified and gzipped + 39 kB, minified and gzipped diff --git a/vis.js b/vis.js index b4a4d086..eeb9980b 100644 --- a/vis.js +++ b/vis.js @@ -4,8 +4,8 @@ * * A dynamic, browser-based visualization library. * - * @version 0.1.0 - * @date 2013-06-20 + * @version 0.2.0 + * @date 2013-09-20 * * @license * Copyright (C) 2011-2013 Almende B.V, http://almende.com @@ -23,5698 +23,7018 @@ * the License. */ (function(e){if("function"==typeof bootstrap)bootstrap("vis",e);else if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeVis=e}else"undefined"!=typeof window?window.vis=e():global.vis=e()})(function(){var define,ses,bootstrap,module,exports; -return (function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require=="function"&&require;for(var s=0;s; + * Licensed under the MIT license */ -/** - * utility functions - */ -var util = {}; +(function(window, undefined) { + 'use strict'; /** - * Test whether given object is a number - * @param {*} object - * @return {Boolean} isNumber + * Hammer + * use this to create instances + * @param {HTMLElement} element + * @param {Object} options + * @returns {Hammer.Instance} + * @constructor */ -util.isNumber = function isNumber(object) { - return (object instanceof Number || typeof object == 'number'); +var Hammer = function(element, options) { + return new Hammer.Instance(element, options || {}); }; -/** - * Test whether given object is a string - * @param {*} object - * @return {Boolean} isString - */ -util.isString = function isString(object) { - return (object instanceof String || typeof object == 'string'); +// default settings +Hammer.defaults = { + // add styles and attributes to the element to prevent the browser from doing + // its native behavior. this doesnt prevent the scrolling, but cancels + // the contextmenu, tap highlighting etc + // set to false to disable this + stop_browser_behavior: { + // this also triggers onselectstart=false for IE + userSelect: 'none', + // this makes the element blocking in IE10 >, you could experiment with the value + // see for more options this issue; https://github.com/EightMedia/hammer.js/issues/241 + touchAction: 'none', + touchCallout: 'none', + contentZooming: 'none', + userDrag: 'none', + tapHighlightColor: 'rgba(0,0,0,0)' + } + + // more settings are defined per gesture at gestures.js }; +// detect touchevents +Hammer.HAS_POINTEREVENTS = navigator.pointerEnabled || navigator.msPointerEnabled; +Hammer.HAS_TOUCHEVENTS = ('ontouchstart' in window); + +// dont use mouseevents on mobile devices +Hammer.MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i; +Hammer.NO_MOUSEEVENTS = Hammer.HAS_TOUCHEVENTS && navigator.userAgent.match(Hammer.MOBILE_REGEX); + +// eventtypes per touchevent (start, move, end) +// are filled by Hammer.event.determineEventTypes on setup +Hammer.EVENT_TYPES = {}; + +// direction defines +Hammer.DIRECTION_DOWN = 'down'; +Hammer.DIRECTION_LEFT = 'left'; +Hammer.DIRECTION_UP = 'up'; +Hammer.DIRECTION_RIGHT = 'right'; + +// pointer type +Hammer.POINTER_MOUSE = 'mouse'; +Hammer.POINTER_TOUCH = 'touch'; +Hammer.POINTER_PEN = 'pen'; + +// touch event defines +Hammer.EVENT_START = 'start'; +Hammer.EVENT_MOVE = 'move'; +Hammer.EVENT_END = 'end'; + +// hammer document where the base events are added at +Hammer.DOCUMENT = document; + +// plugins namespace +Hammer.plugins = {}; + +// if the window events are set... +Hammer.READY = false; + /** - * Test whether given object is a Date, or a String containing a Date - * @param {Date | String} object - * @return {Boolean} isDate + * setup events to detect gestures on the document */ -util.isDate = function isDate(object) { - if (object instanceof Date) { - return true; +function setup() { + if(Hammer.READY) { + return; } - else if (util.isString(object)) { - // test whether this string contains a date - var match = ASPDateRegex.exec(object); - if (match) { - return true; - } - else if (!isNaN(Date.parse(object))) { - return true; + + // find what eventtypes we add listeners to + Hammer.event.determineEventTypes(); + + // Register all gestures inside Hammer.gestures + for(var name in Hammer.gestures) { + if(Hammer.gestures.hasOwnProperty(name)) { + Hammer.detection.register(Hammer.gestures[name]); } } - return false; -}; + // Add touch events on the document + Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_MOVE, Hammer.detection.detect); + Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_END, Hammer.detection.detect); + + // Hammer is ready...! + Hammer.READY = true; +} /** - * Test whether given object is an instance of google.visualization.DataTable - * @param {*} object - * @return {Boolean} isDataTable + * create new hammer instance + * all methods should return the instance itself, so it is chainable. + * @param {HTMLElement} element + * @param {Object} [options={}] + * @returns {Hammer.Instance} + * @constructor */ -util.isDataTable = function isDataTable(object) { - return (typeof (google) !== 'undefined') && - (google.visualization) && - (google.visualization.DataTable) && - (object instanceof google.visualization.DataTable); +Hammer.Instance = function(element, options) { + var self = this; + + // setup HammerJS window events and register all gestures + // this also sets up the default options + setup(); + + this.element = element; + + // start/stop detection option + this.enabled = true; + + // merge options + this.options = Hammer.utils.extend( + Hammer.utils.extend({}, Hammer.defaults), + options || {}); + + // add some css to the element to prevent the browser from doing its native behavoir + if(this.options.stop_browser_behavior) { + Hammer.utils.stopDefaultBrowserBehavior(this.element, this.options.stop_browser_behavior); + } + + // start detection on touchstart + Hammer.event.onTouch(element, Hammer.EVENT_START, function(ev) { + if(self.enabled) { + Hammer.detection.startDetect(self, ev); + } + }); + + // return instance + return this; +}; + + +Hammer.Instance.prototype = { + /** + * bind events to the instance + * @param {String} gesture + * @param {Function} handler + * @returns {Hammer.Instance} + */ + on: function onEvent(gesture, handler){ + var gestures = gesture.split(' '); + for(var t=0; t 0 && eventType == Hammer.EVENT_END) { + eventType = Hammer.EVENT_MOVE; } - else { - return moment(object); // parse string + // no touches, force the end event + else if(!count_touches) { + eventType = Hammer.EVENT_END; } - } - else { - throw new Error( - 'Cannot convert object of type ' + util.getType(object) + - ' to type Date'); - } - case 'ISODate': - if (util.isNumber(object)) { - return new Date(object); - } - else if (object instanceof Date) { - return object.toISOString(); - } - else if (moment.isMoment(object)) { - return object.toDate().toISOString(); - } - else if (util.isString(object)) { - match = ASPDateRegex.exec(object); - if (match) { - // object is an ASP date - return new Date(Number(match[1])).toISOString(); // parse number + // because touchend has no touches, and we often want to use these in our gestures, + // we send the last move event as our eventData in touchend + if(!count_touches && last_move_event !== null) { + ev = last_move_event; } + // store the last move event else { - return new Date(object).toISOString(); // parse string + last_move_event = ev; } - } - else { - throw new Error( - 'Cannot convert object of type ' + util.getType(object) + - ' to type ISODate'); - } - case 'ASPDate': - if (util.isNumber(object)) { - return '/Date(' + object + ')/'; - } - else if (object instanceof Date) { - return '/Date(' + object.valueOf() + ')/'; - } - else if (util.isString(object)) { - match = ASPDateRegex.exec(object); - var value; - if (match) { - // object is an ASP date - value = new Date(Number(match[1])).valueOf(); // parse number - } - else { - value = new Date(object).valueOf(); // parse string + // trigger the handler + handler.call(Hammer.detection, self.collectEventData(element, eventType, ev)); + + // remove pointerevent from list + if(Hammer.HAS_POINTEREVENTS && eventType == Hammer.EVENT_END) { + count_touches = Hammer.PointerEvent.updatePointer(eventType, ev); } - return '/Date(' + value + ')/'; - } - else { - throw new Error( - 'Cannot convert object of type ' + util.getType(object) + - ' to type ASPDate'); } - default: - throw new Error('Cannot convert object of type ' + util.getType(object) + - ' to type "' + type + '"'); - } -}; + //debug(sourceEventType +" "+ eventType); -// parse ASP.Net Date pattern, -// for example '/Date(1198908717056)/' or '/Date(1198908717056-0700)/' -// code from http://momentjs.com/ -var ASPDateRegex = /^\/?Date\((\-?\d+)/i; + // on the end we reset everything + if(!count_touches) { + last_move_event = null; + enable_detect = false; + touch_triggered = false; + Hammer.PointerEvent.reset(); + } + }); + }, -/** - * Get the type of an object, for example util.getType([]) returns 'Array' - * @param {*} object - * @return {String} type - */ -util.getType = function getType(object) { - var type = typeof object; - if (type == 'object') { - if (object == null) { - return 'null'; - } - if (object instanceof Boolean) { - return 'Boolean'; + /** + * we have different events for each device/browser + * determine what we need and set them in the Hammer.EVENT_TYPES constant + */ + determineEventTypes: function determineEventTypes() { + // determine the eventtype we want to set + var types; + + // pointerEvents magic + if(Hammer.HAS_POINTEREVENTS) { + types = Hammer.PointerEvent.getEvents(); + } + // on Android, iOS, blackberry, windows mobile we dont want any mouseevents + else if(Hammer.NO_MOUSEEVENTS) { + types = [ + 'touchstart', + 'touchmove', + 'touchend touchcancel']; + } + // for non pointer events browsers and mixed browsers, + // like chrome on windows8 touch laptop + else { + types = [ + 'touchstart mousedown', + 'touchmove mousemove', + 'touchend touchcancel mouseup']; } - if (object instanceof Number) { - return 'Number'; + + Hammer.EVENT_TYPES[Hammer.EVENT_START] = types[0]; + Hammer.EVENT_TYPES[Hammer.EVENT_MOVE] = types[1]; + Hammer.EVENT_TYPES[Hammer.EVENT_END] = types[2]; + }, + + + /** + * create touchlist depending on the event + * @param {Object} ev + * @param {String} eventType used by the fakemultitouch plugin + */ + getTouchList: function getTouchList(ev/*, eventType*/) { + // get the fake pointerEvent touchlist + if(Hammer.HAS_POINTEREVENTS) { + return Hammer.PointerEvent.getTouchList(); } - if (object instanceof String) { - return 'String'; + // get the touchlist + else if(ev.touches) { + return ev.touches; } - if (object instanceof Array) { - return 'Array'; + // make fake touchlist from mouse position + else { + return [{ + identifier: 1, + pageX: ev.pageX, + pageY: ev.pageY, + target: ev.target + }]; } - if (object instanceof Date) { - return 'Date'; + }, + + + /** + * collect event data for Hammer js + * @param {HTMLElement} element + * @param {String} eventType like Hammer.EVENT_MOVE + * @param {Object} eventData + */ + collectEventData: function collectEventData(element, eventType, ev) { + var touches = this.getTouchList(ev, eventType); + + // find out pointerType + var pointerType = Hammer.POINTER_TOUCH; + if(ev.type.match(/mouse/) || Hammer.PointerEvent.matchType(Hammer.POINTER_MOUSE, ev)) { + pointerType = Hammer.POINTER_MOUSE; } - return 'Object'; - } - else if (type == 'number') { - return 'Number'; - } - else if (type == 'boolean') { - return 'Boolean'; - } - else if (type == 'string') { - return 'String'; - } - return type; -}; + return { + center : Hammer.utils.getCenter(touches), + timeStamp : new Date().getTime(), + target : ev.target, + touches : touches, + eventType : eventType, + pointerType : pointerType, + srcEvent : ev, -/** - * Retrieve the absolute left value of a DOM element - * @param {Element} elem A dom element, for example a div - * @return {number} left The absolute left position of this element - * in the browser page. - */ -util.getAbsoluteLeft = function getAbsoluteLeft (elem) { - var doc = document.documentElement; - var body = document.body; + /** + * prevent the browser default actions + * mostly used to disable scrolling of the browser + */ + preventDefault: function() { + if(this.srcEvent.preventManipulation) { + this.srcEvent.preventManipulation(); + } - var left = elem.offsetLeft; - var e = elem.offsetParent; - while (e != null && e != body && e != doc) { - left += e.offsetLeft; - left -= e.scrollLeft; - e = e.offsetParent; - } - return left; -}; + if(this.srcEvent.preventDefault) { + this.srcEvent.preventDefault(); + } + }, -/** - * Retrieve the absolute top value of a DOM element - * @param {Element} elem A dom element, for example a div - * @return {number} top The absolute top position of this element - * in the browser page. - */ -util.getAbsoluteTop = function getAbsoluteTop (elem) { - var doc = document.documentElement; - var body = document.body; + /** + * stop bubbling the event up to its parents + */ + stopPropagation: function() { + this.srcEvent.stopPropagation(); + }, - var top = elem.offsetTop; - var e = elem.offsetParent; - while (e != null && e != body && e != doc) { - top += e.offsetTop; - top -= e.scrollTop; - e = e.offsetParent; + /** + * immediately stop gesture detection + * might be useful after a swipe was detected + * @return {*} + */ + stopDetect: function() { + return Hammer.detection.stopDetect(); + } + }; } - return top; }; -/** - * Get the absolute, vertical mouse position from an event. - * @param {Event} event - * @return {Number} pageY - */ -util.getPageY = function getPageY (event) { - if ('pageY' in event) { - return event.pageY; - } - else { - var clientY; - if (('targetTouches' in event) && event.targetTouches.length) { - clientY = event.targetTouches[0].clientY; +Hammer.PointerEvent = { + /** + * holds all pointers + * @type {Object} + */ + pointers: {}, + + /** + * get a list of pointers + * @returns {Array} touchlist + */ + getTouchList: function() { + var self = this; + var touchlist = []; + + // we can use forEach since pointerEvents only is in IE10 + Object.keys(self.pointers).sort().forEach(function(id) { + touchlist.push(self.pointers[id]); + }); + return touchlist; + }, + + /** + * update the position of a pointer + * @param {String} type Hammer.EVENT_END + * @param {Object} pointerEvent + */ + updatePointer: function(type, pointerEvent) { + if(type == Hammer.EVENT_END) { + this.pointers = {}; } else { - clientY = event.clientY; + pointerEvent.identifier = pointerEvent.pointerId; + this.pointers[pointerEvent.pointerId] = pointerEvent; } - var doc = document.documentElement; - var body = document.body; - return clientY + - ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - - ( doc && doc.clientTop || body && body.clientTop || 0 ); - } -}; + return Object.keys(this.pointers).length; + }, -/** - * Get the absolute, horizontal mouse position from an event. - * @param {Event} event - * @return {Number} pageX - */ -util.getPageX = function getPageX (event) { - if ('pageY' in event) { - return event.pageX; - } - else { - var clientX; - if (('targetTouches' in event) && event.targetTouches.length) { - clientX = event.targetTouches[0].clientX; - } - else { - clientX = event.clientX; + /** + * check if ev matches pointertype + * @param {String} pointerType Hammer.POINTER_MOUSE + * @param {PointerEvent} ev + */ + matchType: function(pointerType, ev) { + if(!ev.pointerType) { + return false; } - var doc = document.documentElement; - var body = document.body; - return clientX + - ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); - } -}; + var types = {}; + types[Hammer.POINTER_MOUSE] = (ev.pointerType == ev.MSPOINTER_TYPE_MOUSE || ev.pointerType == Hammer.POINTER_MOUSE); + types[Hammer.POINTER_TOUCH] = (ev.pointerType == ev.MSPOINTER_TYPE_TOUCH || ev.pointerType == Hammer.POINTER_TOUCH); + types[Hammer.POINTER_PEN] = (ev.pointerType == ev.MSPOINTER_TYPE_PEN || ev.pointerType == Hammer.POINTER_PEN); + return types[pointerType]; + }, -/** - * add a className to the given elements style - * @param {Element} elem - * @param {String} className - */ -util.addClassName = function addClassName(elem, className) { - var classes = elem.className.split(' '); - if (classes.indexOf(className) == -1) { - classes.push(className); // add the class to the array - elem.className = classes.join(' '); - } -}; -/** - * add a className to the given elements style - * @param {Element} elem - * @param {String} className - */ -util.removeClassName = function removeClassname(elem, className) { - var classes = elem.className.split(' '); - var index = classes.indexOf(className); - if (index != -1) { - classes.splice(index, 1); // remove the class from the array - elem.className = classes.join(' '); + /** + * get events + */ + getEvents: function() { + return [ + 'pointerdown MSPointerDown', + 'pointermove MSPointerMove', + 'pointerup pointercancel MSPointerUp MSPointerCancel' + ]; + }, + + /** + * reset the list + */ + reset: function() { + this.pointers = {}; } }; -/** - * For each method for both arrays and objects. - * In case of an array, the built-in Array.forEach() is applied. - * In case of an Object, the method loops over all properties of the object. - * @param {Object | Array} object An Object or Array - * @param {function} callback Callback method, called for each item in - * the object or array with three parameters: - * callback(value, index, object) - */ -util.forEach = function forEach (object, callback) { - var i, - len; - if (object instanceof Array) { - // array - for (i = 0, len = object.length; i < len; i++) { - callback(object[i], i, object); - } - } - else { - // object - for (i in object) { - if (object.hasOwnProperty(i)) { - callback(object[i], i, object); + +Hammer.utils = { + /** + * extend method, + * also used for cloning when dest is an empty object + * @param {Object} dest + * @param {Object} src + * @parm {Boolean} merge do a merge + * @returns {Object} dest + */ + extend: function extend(dest, src, merge) { + for (var key in src) { + if(dest[key] !== undefined && merge) { + continue; + } + dest[key] = src[key]; + } + return dest; + }, + + + /** + * find if a node is in the given parent + * used for event delegation tricks + * @param {HTMLElement} node + * @param {HTMLElement} parent + * @returns {boolean} has_parent + */ + hasParent: function(node, parent) { + while(node){ + if(node == parent) { + return true; } + node = node.parentNode; } - } -}; - -/** - * Update a property in an object - * @param {Object} object - * @param {String} key - * @param {*} value - * @return {Boolean} changed - */ -util.updateProperty = function updateProp (object, key, value) { - if (object[key] !== value) { - object[key] = value; - return true; - } - else { return false; - } -}; + }, -/** - * Add and event listener. Works for all browsers - * @param {Element} element An html element - * @param {string} action The action, for example "click", - * without the prefix "on" - * @param {function} listener The callback function to be executed - * @param {boolean} [useCapture] - */ -util.addEventListener = function addEventListener(element, action, listener, useCapture) { - if (element.addEventListener) { - if (useCapture === undefined) - useCapture = false; - if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) { - action = "DOMMouseScroll"; // For Firefox + /** + * get the center of all the touches + * @param {Array} touches + * @returns {Object} center + */ + getCenter: function getCenter(touches) { + var valuesX = [], valuesY = []; + + for(var t= 0,len=touches.length; t= 0) { - action = "DOMMouseScroll"; // For Firefox - } + /** + * calculate the velocity between two points + * @param {Number} delta_time + * @param {Number} delta_x + * @param {Number} delta_y + * @returns {Object} velocity + */ + getVelocity: function getVelocity(delta_time, delta_x, delta_y) { + return { + x: Math.abs(delta_x / delta_time) || 0, + y: Math.abs(delta_y / delta_time) || 0 + }; + }, - element.removeEventListener(action, listener, useCapture); - } else { - // IE browsers - element.detachEvent("on" + action, listener); - } -}; + /** + * calculate the angle between two coordinates + * @param {Touch} touch1 + * @param {Touch} touch2 + * @returns {Number} angle + */ + getAngle: function getAngle(touch1, touch2) { + var y = touch2.pageY - touch1.pageY, + x = touch2.pageX - touch1.pageX; + return Math.atan2(y, x) * 180 / Math.PI; + }, -/** - * Get HTML element which is the target of the event - * @param {Event} event - * @return {Element} target element - */ -util.getTarget = function getTarget(event) { - // code from http://www.quirksmode.org/js/events_properties.html - if (!event) { - event = window.event; - } - var target; + /** + * angle to direction define + * @param {Touch} touch1 + * @param {Touch} touch2 + * @returns {String} direction constant, like Hammer.DIRECTION_LEFT + */ + getDirection: function getDirection(touch1, touch2) { + var x = Math.abs(touch1.pageX - touch2.pageX), + y = Math.abs(touch1.pageY - touch2.pageY); - if (event.target) { - target = event.target; - } - else if (event.srcElement) { - target = event.srcElement; - } + if(x >= y) { + return touch1.pageX - touch2.pageX > 0 ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT; + } + else { + return touch1.pageY - touch2.pageY > 0 ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN; + } + }, - if (target.nodeType != undefined && target.nodeType == 3) { - // defeat Safari bug - target = target.parentNode; - } - return target; -}; + /** + * calculate the distance between two touches + * @param {Touch} touch1 + * @param {Touch} touch2 + * @returns {Number} distance + */ + getDistance: function getDistance(touch1, touch2) { + var x = touch2.pageX - touch1.pageX, + y = touch2.pageY - touch1.pageY; + return Math.sqrt((x*x) + (y*y)); + }, -/** - * Stop event propagation - */ -util.stopPropagation = function stopPropagation(event) { - if (!event) - event = window.event; - if (event.stopPropagation) { - event.stopPropagation(); // non-IE browsers - } - else { - event.cancelBubble = true; // IE browsers - } -}; + /** + * calculate the scale factor between two touchLists (fingers) + * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out + * @param {Array} start + * @param {Array} end + * @returns {Number} scale + */ + getScale: function getScale(start, end) { + // need two fingers... + if(start.length >= 2 && end.length >= 2) { + return this.getDistance(end[0], end[1]) / + this.getDistance(start[0], start[1]); + } + return 1; + }, -/** - * Cancels the event if it is cancelable, without stopping further propagation of the event. - */ -util.preventDefault = function preventDefault (event) { - if (!event) - event = window.event; + /** + * calculate the rotation degrees between two touchLists (fingers) + * @param {Array} start + * @param {Array} end + * @returns {Number} rotation + */ + getRotation: function getRotation(start, end) { + // need two fingers + if(start.length >= 2 && end.length >= 2) { + return this.getAngle(end[1], end[0]) - + this.getAngle(start[1], start[0]); + } + return 0; + }, - if (event.preventDefault) { - event.preventDefault(); // non-IE browsers - } - else { - event.returnValue = false; // IE browsers - } -}; + /** + * boolean if the direction is vertical + * @param {String} direction + * @returns {Boolean} is_vertical + */ + isVertical: function isVertical(direction) { + return (direction == Hammer.DIRECTION_UP || direction == Hammer.DIRECTION_DOWN); + }, -util.option = {}; -/** - * Convert a value into a boolean - * @param {Boolean | function | undefined} value - * @param {Boolean} [defaultValue] - * @returns {Boolean} bool - */ -util.option.asBoolean = function (value, defaultValue) { - if (typeof value == 'function') { - value = value(); - } + /** + * stop browser default behavior with css props + * @param {HtmlElement} element + * @param {Object} css_props + */ + stopDefaultBrowserBehavior: function stopDefaultBrowserBehavior(element, css_props) { + var prop, + vendors = ['webkit','khtml','moz','ms','o','']; - if (value != null) { - return (value != false); - } + if(!css_props || !element.style) { + return; + } - return defaultValue || null; -}; + // with css properties for modern browsers + for(var i = 0; i < vendors.length; i++) { + for(var p in css_props) { + if(css_props.hasOwnProperty(p)) { + prop = p; -/** - * Convert a value into a number - * @param {Boolean | function | undefined} value - * @param {Number} [defaultValue] - * @returns {Number} number - */ -util.option.asNumber = function (value, defaultValue) { - if (typeof value == 'function') { - value = value(); - } + // vender prefix at the property + if(vendors[i]) { + prop = vendors[i] + prop.substring(0, 1).toUpperCase() + prop.substring(1); + } - if (value != null) { - return Number(value) || defaultValue || null; - } + // set the style + element.style[prop] = css_props[p]; + } + } + } - return defaultValue || null; + // also the disable onselectstart + if(css_props.userSelect == 'none') { + element.onselectstart = function() { + return false; + }; + } + } }; -/** - * Convert a value into a string - * @param {String | function | undefined} value - * @param {String} [defaultValue] - * @returns {String} str - */ -util.option.asString = function (value, defaultValue) { - if (typeof value == 'function') { - value = value(); - } +Hammer.detection = { + // contains all registred Hammer.gestures in the correct order + gestures: [], - if (value != null) { - return String(value); - } + // data of the current Hammer.gesture detection session + current: null, - return defaultValue || null; -}; + // the previous Hammer.gesture session data + // is a full clone of the previous gesture.current object + previous: null, -/** - * Convert a size or location into a string with pixels or a percentage - * @param {String | Number | function | undefined} value - * @param {String} [defaultValue] - * @returns {String} size - */ -util.option.asSize = function (value, defaultValue) { - if (typeof value == 'function') { - value = value(); - } + // when this becomes true, no gestures are fired + stopped: false, - if (util.isString(value)) { - return value; - } - else if (util.isNumber(value)) { - return value + 'px'; - } - else { - return defaultValue || null; - } -}; -/** - * Convert a value into a DOM element - * @param {HTMLElement | function | undefined} value - * @param {HTMLElement} [defaultValue] - * @returns {HTMLElement | null} dom - */ -util.option.asElement = function (value, defaultValue) { - if (typeof value == 'function') { - value = value(); - } + /** + * start Hammer.gesture detection + * @param {Hammer.Instance} inst + * @param {Object} eventData + */ + startDetect: function startDetect(inst, eventData) { + // already busy with a Hammer.gesture detection on an element + if(this.current) { + return; + } - return value || defaultValue || null; -}; + this.stopped = false; -/** - * load css from text - * @param {String} css Text containing css - */ -util.loadCss = function (css) { - if (typeof document === 'undefined') { - return; - } + this.current = { + inst : inst, // reference to HammerInstance we're working for + startEvent : Hammer.utils.extend({}, eventData), // start eventData for distances, timing etc + lastEvent : false, // last eventData + name : '' // current gesture we're in/detected, can be 'tap', 'hold' etc + }; - // get the script location, and built the css file name from the js file name - // http://stackoverflow.com/a/2161748/1262753 - // var scripts = document.getElementsByTagName('script'); - // var jsFile = scripts[scripts.length-1].src.split('?')[0]; - // var cssFile = jsFile.substring(0, jsFile.length - 2) + 'css'; + this.detect(eventData); + }, - // inject css - // http://stackoverflow.com/questions/524696/how-to-create-a-style-tag-with-javascript - var style = document.createElement('style'); - style.type = 'text/css'; - if (style.styleSheet){ - style.styleSheet.cssText = css; - } else { - style.appendChild(document.createTextNode(css)); - } - document.getElementsByTagName('head')[0].appendChild(style); -}; + /** + * Hammer.gesture detection + * @param {Object} eventData + * @param {Object} eventData + */ + detect: function detect(eventData) { + if(!this.current || this.stopped) { + return; + } + // extend event data with calculations about scale, distance etc + eventData = this.extendEventData(eventData); -// Internet Explorer 8 and older does not support Array.indexOf, so we define -// it here in that case. -// http://soledadpenades.com/2007/05/17/arrayindexof-in-internet-explorer/ -if(!Array.prototype.indexOf) { - Array.prototype.indexOf = function(obj){ - for(var i = 0; i < this.length; i++){ - if(this[i] == obj){ - return i; + // instance options + var inst_options = this.current.inst.options; + + // call Hammer.gesture handlers + for(var g=0,len=this.gestures.length; g>> 0; + // stopped! + this.stopped = true; + }, - // 4. If IsCallable(callback) is false, throw a TypeError exception. - // See: http://es5.github.com/#x9.11 - if (typeof callback !== "function") { - throw new TypeError(callback + " is not a function"); - } - // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. - if (thisArg) { - T = thisArg; + /** + * extend eventData for Hammer.gestures + * @param {Object} ev + * @returns {Object} ev + */ + extendEventData: function extendEventData(ev) { + var startEv = this.current.startEvent; + + // if the touches change, set the new touches over the startEvent touches + // this because touchevents don't have all the touches on touchstart, or the + // user must place his fingers at the EXACT same time on the screen, which is not realistic + // but, sometimes it happens that both fingers are touching at the EXACT same time + if(startEv && (ev.touches.length != startEv.touches.length || ev.touches === startEv.touches)) { + // extend 1 level deep to get the touchlist with the touch objects + startEv.touches = []; + for(var i=0,len=ev.touches.length; i>> 0; - if (typeof fun != "function") { - throw new TypeError(); - } + // add Hammer.gesture to the list + this.gestures.push(gesture); - var res = []; - var thisp = arguments[1]; - for (var i = 0; i < len; i++) { - if (i in t) { - var val = t[i]; // in case fun mutates this - if (fun.call(thisp, val, i, t)) - res.push(val); + // sort the list by index + this.gestures.sort(function(a, b) { + if (a.index < b.index) { + return -1; } - } - - return res; - }; -} + if (a.index > b.index) { + return 1; + } + return 0; + }); + return this.gestures; + } +}; -// Internet Explorer 8 and older does not support Object.keys, so we define it -// here in that case. -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys -if (!Object.keys) { - Object.keys = (function () { - var hasOwnProperty = Object.prototype.hasOwnProperty, - hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), - dontEnums = [ - 'toString', - 'toLocaleString', - 'valueOf', - 'hasOwnProperty', - 'isPrototypeOf', - 'propertyIsEnumerable', - 'constructor' - ], - dontEnumsLength = dontEnums.length; - return function (obj) { - if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) { - throw new TypeError('Object.keys called on non-object'); - } +Hammer.gestures = Hammer.gestures || {}; - var result = []; +/** + * Custom gestures + * ============================== + * + * Gesture object + * -------------------- + * The object structure of a gesture: + * + * { name: 'mygesture', + * index: 1337, + * defaults: { + * mygesture_option: true + * } + * handler: function(type, ev, inst) { + * // trigger gesture event + * inst.trigger(this.name, ev); + * } + * } + + * @param {String} name + * this should be the name of the gesture, lowercase + * it is also being used to disable/enable the gesture per instance config. + * + * @param {Number} [index=1000] + * the index of the gesture, where it is going to be in the stack of gestures detection + * like when you build an gesture that depends on the drag gesture, it is a good + * idea to place it after the index of the drag gesture. + * + * @param {Object} [defaults={}] + * the default settings of the gesture. these are added to the instance settings, + * and can be overruled per instance. you can also add the name of the gesture, + * but this is also added by default (and set to true). + * + * @param {Function} handler + * this handles the gesture detection of your custom gesture and receives the + * following arguments: + * + * @param {Object} eventData + * event data containing the following properties: + * timeStamp {Number} time the event occurred + * target {HTMLElement} target element + * touches {Array} touches (fingers, pointers, mouse) on the screen + * pointerType {String} kind of pointer that was used. matches Hammer.POINTER_MOUSE|TOUCH + * center {Object} center position of the touches. contains pageX and pageY + * deltaTime {Number} the total time of the touches in the screen + * deltaX {Number} the delta on x axis we haved moved + * deltaY {Number} the delta on y axis we haved moved + * velocityX {Number} the velocity on the x + * velocityY {Number} the velocity on y + * angle {Number} the angle we are moving + * direction {String} the direction we are moving. matches Hammer.DIRECTION_UP|DOWN|LEFT|RIGHT + * distance {Number} the distance we haved moved + * scale {Number} scaling of the touches, needs 2 touches + * rotation {Number} rotation of the touches, needs 2 touches * + * eventType {String} matches Hammer.EVENT_START|MOVE|END + * srcEvent {Object} the source event, like TouchStart or MouseDown * + * startEvent {Object} contains the same properties as above, + * but from the first touch. this is used to calculate + * distances, deltaTime, scaling etc + * + * @param {Hammer.Instance} inst + * the instance we are doing the detection for. you can get the options from + * the inst.options object and trigger the gesture event by calling inst.trigger + * + * + * Handle gestures + * -------------------- + * inside the handler you can get/set Hammer.detection.current. This is the current + * detection session. It has the following properties + * @param {String} name + * contains the name of the gesture we have detected. it has not a real function, + * only to check in other gestures if something is detected. + * like in the drag gesture we set it to 'drag' and in the swipe gesture we can + * check if the current gesture is 'drag' by accessing Hammer.detection.current.name + * + * @readonly + * @param {Hammer.Instance} inst + * the instance we do the detection for + * + * @readonly + * @param {Object} startEvent + * contains the properties of the first gesture detection in this session. + * Used for calculations about timing, distance, etc. + * + * @readonly + * @param {Object} lastEvent + * contains all the properties of the last gesture detect in this session. + * + * after the gesture detection session has been completed (user has released the screen) + * the Hammer.detection.current object is copied into Hammer.detection.previous, + * this is usefull for gestures like doubletap, where you need to know if the + * previous gesture was a tap + * + * options that have been set by the instance can be received by calling inst.options + * + * You can trigger a gesture event by calling inst.trigger("mygesture", event). + * The first param is the name of your gesture, the second the event argument + * + * + * Register gestures + * -------------------- + * When an gesture is added to the Hammer.gestures object, it is auto registered + * at the setup of the first Hammer instance. You can also call Hammer.detection.register + * manually and pass your gesture object as a param + * + */ - for (var prop in obj) { - if (hasOwnProperty.call(obj, prop)) result.push(prop); - } +/** + * Hold + * Touch stays at the same place for x time + * @events hold + */ +Hammer.gestures.Hold = { + name: 'hold', + index: 10, + defaults: { + hold_timeout : 500, + hold_threshold : 1 + }, + timer: null, + handler: function holdGesture(ev, inst) { + switch(ev.eventType) { + case Hammer.EVENT_START: + // clear any running timers + clearTimeout(this.timer); + + // set the gesture so we can check in the timeout if it still is + Hammer.detection.current.name = this.name; + + // set timer and if after the timeout it still is hold, + // we trigger the hold event + this.timer = setTimeout(function() { + if(Hammer.detection.current.name == 'hold') { + inst.trigger('hold', ev); + } + }, inst.options.hold_timeout); + break; - if (hasDontEnumBug) { - for (var i=0; i < dontEnumsLength; i++) { - if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]); + // when you move or end we clear the timer + case Hammer.EVENT_MOVE: + if(ev.distance > inst.options.hold_threshold) { + clearTimeout(this.timer); } - } - return result; - } - })() -} - -// Internet Explorer 8 and older does not support Array.isArray, -// so we define it here in that case. -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/isArray -if(!Array.isArray) { - Array.isArray = function (vArg) { - return Object.prototype.toString.call(vArg) === "[object Array]"; - }; -} + break; -// Internet Explorer 8 and older does not support Function.bind, -// so we define it here in that case. -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind -if (!Function.prototype.bind) { - Function.prototype.bind = function (oThis) { - if (typeof this !== "function") { - // closest thing possible to the ECMAScript 5 internal IsCallable function - throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); + case Hammer.EVENT_END: + clearTimeout(this.timer); + break; } + } +}; - var aArgs = Array.prototype.slice.call(arguments, 1), - fToBind = this, - fNOP = function () {}, - fBound = function () { - return fToBind.apply(this instanceof fNOP && oThis - ? this - : oThis, - aArgs.concat(Array.prototype.slice.call(arguments))); - }; - fNOP.prototype = this.prototype; - fBound.prototype = new fNOP(); +/** + * Tap/DoubleTap + * Quick touch at a place or double at the same place + * @events tap, doubletap + */ +Hammer.gestures.Tap = { + name: 'tap', + index: 100, + defaults: { + tap_max_touchtime : 250, + tap_max_distance : 10, + tap_always : true, + doubletap_distance : 20, + doubletap_interval : 300 + }, + handler: function tapGesture(ev, inst) { + if(ev.eventType == Hammer.EVENT_END) { + // previous gesture, for the double tap since these are two different gesture detections + var prev = Hammer.detection.previous, + did_doubletap = false; - return fBound; - }; -} + // when the touchtime is higher then the max touch time + // or when the moving distance is too much + if(ev.deltaTime > inst.options.tap_max_touchtime || + ev.distance > inst.options.tap_max_distance) { + return; + } -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create -if (!Object.create) { - Object.create = function (o) { - if (arguments.length > 1) { - throw new Error('Object.create implementation only accepts the first parameter.'); + // check if double tap + if(prev && prev.name == 'tap' && + (ev.timeStamp - prev.lastEvent.timeStamp) < inst.options.doubletap_interval && + ev.distance < inst.options.doubletap_distance) { + inst.trigger('doubletap', ev); + did_doubletap = true; + } + + // do a single tap + if(!did_doubletap || inst.options.tap_always) { + Hammer.detection.current.name = 'tap'; + inst.trigger(Hammer.detection.current.name, ev); + } } - function F() {} - F.prototype = o; - return new F(); - }; -} + } +}; + /** - * Event listener (singleton) + * Swipe + * triggers swipe events when the end velocity is above the threshold + * @events swipe, swipeleft, swiperight, swipeup, swipedown */ -// TODO: replace usage of the event listener for the EventBus -var events = { - 'listeners': [], +Hammer.gestures.Swipe = { + name: 'swipe', + index: 40, + defaults: { + // set 0 for unlimited, but this can conflict with transform + swipe_max_touches : 1, + swipe_velocity : 0.7 + }, + handler: function swipeGesture(ev, inst) { + if(ev.eventType == Hammer.EVENT_END) { + // max touches + if(inst.options.swipe_max_touches > 0 && + ev.touches.length > inst.options.swipe_max_touches) { + return; + } + + // when the distance we moved is too small we skip this gesture + // or we can be already in dragging + if(ev.velocityX > inst.options.swipe_velocity || + ev.velocityY > inst.options.swipe_velocity) { + // trigger swipe events + inst.trigger(this.name, ev); + inst.trigger(this.name + ev.direction, ev); + } + } + } +}; + + +/** + * Drag + * Move with x fingers (default 1) around on the page. Blocking the scrolling when + * moving left and right is a good practice. When all the drag events are blocking + * you disable scrolling on that area. + * @events drag, drapleft, dragright, dragup, dragdown + */ +Hammer.gestures.Drag = { + name: 'drag', + index: 50, + defaults: { + drag_min_distance : 10, + // set 0 for unlimited, but this can conflict with transform + drag_max_touches : 1, + // prevent default browser behavior when dragging occurs + // be careful with it, it makes the element a blocking element + // when you are using the drag gesture, it is a good practice to set this true + drag_block_horizontal : false, + drag_block_vertical : false, + // drag_lock_to_axis keeps the drag gesture on the axis that it started on, + // It disallows vertical directions if the initial direction was horizontal, and vice versa. + drag_lock_to_axis : false, + // drag lock only kicks in when distance > drag_lock_min_distance + // This way, locking occurs only when the distance has become large enough to reliably determine the direction + drag_lock_min_distance : 25 + }, + triggered: false, + handler: function dragGesture(ev, inst) { + // current gesture isnt drag, but dragged is true + // this means an other gesture is busy. now call dragend + if(Hammer.detection.current.name != this.name && this.triggered) { + inst.trigger(this.name +'end', ev); + this.triggered = false; + return; + } - /** - * Find a single listener by its object - * @param {Object} object - * @return {Number} index -1 when not found - */ - 'indexOf': function (object) { - var listeners = this.listeners; - for (var i = 0, iMax = this.listeners.length; i < iMax; i++) { - var listener = listeners[i]; - if (listener && listener.object == object) { - return i; - } + // max touches + if(inst.options.drag_max_touches > 0 && + ev.touches.length > inst.options.drag_max_touches) { + return; } - return -1; - }, - /** - * Add an event listener - * @param {Object} object - * @param {String} event The name of an event, for example 'select' - * @param {function} callback The callback method, called when the - * event takes place - */ - 'addListener': function (object, event, callback) { - var index = this.indexOf(object); - var listener = this.listeners[index]; - if (!listener) { - listener = { - 'object': object, - 'events': {} - }; - this.listeners.push(listener); - } + switch(ev.eventType) { + case Hammer.EVENT_START: + this.triggered = false; + break; - var callbacks = listener.events[event]; - if (!callbacks) { - callbacks = []; - listener.events[event] = callbacks; - } + case Hammer.EVENT_MOVE: + // when the distance we moved is too small we skip this gesture + // or we can be already in dragging + if(ev.distance < inst.options.drag_min_distance && + Hammer.detection.current.name != this.name) { + return; + } - // add the callback if it does not yet exist - if (callbacks.indexOf(callback) == -1) { - callbacks.push(callback); - } - }, + // we are dragging! + Hammer.detection.current.name = this.name; - /** - * Remove an event listener - * @param {Object} object - * @param {String} event The name of an event, for example 'select' - * @param {function} callback The registered callback method - */ - 'removeListener': function (object, event, callback) { - var index = this.indexOf(object); - var listener = this.listeners[index]; - if (listener) { - var callbacks = listener.events[event]; - if (callbacks) { - index = callbacks.indexOf(callback); - if (index != -1) { - callbacks.splice(index, 1); + // lock drag to axis? + if(Hammer.detection.current.lastEvent.drag_locked_to_axis || (inst.options.drag_lock_to_axis && inst.options.drag_lock_min_distance<=ev.distance)) { + ev.drag_locked_to_axis = true; } - - // remove the array when empty - if (callbacks.length == 0) { - delete listener.events[event]; + var last_direction = Hammer.detection.current.lastEvent.direction; + if(ev.drag_locked_to_axis && last_direction !== ev.direction) { + // keep direction on the axis that the drag gesture started on + if(Hammer.utils.isVertical(last_direction)) { + ev.direction = (ev.deltaY < 0) ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN; + } + else { + ev.direction = (ev.deltaX < 0) ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT; + } } - } - // count the number of registered events. remove listener when empty - var count = 0; - var events = listener.events; - for (var e in events) { - if (events.hasOwnProperty(e)) { - count++; + // first time, trigger dragstart event + if(!this.triggered) { + inst.trigger(this.name +'start', ev); + this.triggered = true; } - } - if (count == 0) { - delete this.listeners[index]; - } - } - }, - /** - * Remove all registered event listeners - */ - 'removeAllListeners': function () { - this.listeners = []; - }, + // trigger normal event + inst.trigger(this.name, ev); - /** - * Trigger an event. All registered event handlers will be called - * @param {Object} object - * @param {String} event - * @param {Object} properties (optional) - */ - 'trigger': function (object, event, properties) { - var index = this.indexOf(object); - var listener = this.listeners[index]; - if (listener) { - var callbacks = listener.events[event]; - if (callbacks) { - for (var i = 0, iMax = callbacks.length; i < iMax; i++) { - callbacks[i](properties); + // direction event, like dragdown + inst.trigger(this.name + ev.direction, ev); + + // block the browser events + if( (inst.options.drag_block_vertical && Hammer.utils.isVertical(ev.direction)) || + (inst.options.drag_block_horizontal && !Hammer.utils.isVertical(ev.direction))) { + ev.preventDefault(); } - } + break; + + case Hammer.EVENT_END: + // trigger dragend + if(this.triggered) { + inst.trigger(this.name +'end', ev); + } + + this.triggered = false; + break; } } }; -/** - * An event bus can be used to emit events, and to subscribe to events - * @constructor EventBus - */ -function EventBus() { - this.subscriptions = []; -} /** - * Subscribe to an event - * @param {String | RegExp} event The event can be a regular expression, or - * a string with wildcards, like 'server.*'. - * @param {function} callback. Callback are called with three parameters: - * {String} event, {*} [data], {*} [source] - * @param {*} [target] - * @returns {String} id A subscription id + * Transform + * User want to scale or rotate with 2 fingers + * @events transform, pinch, pinchin, pinchout, rotate */ -EventBus.prototype.on = function (event, callback, target) { - var regexp = (event instanceof RegExp) ? - event : - new RegExp(event.replace('*', '\\w+')); +Hammer.gestures.Transform = { + name: 'transform', + index: 45, + defaults: { + // factor, no scale is 1, zoomin is to 0 and zoomout until higher then 1 + transform_min_scale : 0.01, + // rotation in degrees + transform_min_rotation : 1, + // prevent default browser behavior when two touches are on the screen + // but it makes the element a blocking element + // when you are using the transform gesture, it is a good practice to set this true + transform_always_block : false + }, + triggered: false, + handler: function transformGesture(ev, inst) { + // current gesture isnt drag, but dragged is true + // this means an other gesture is busy. now call dragend + if(Hammer.detection.current.name != this.name && this.triggered) { + inst.trigger(this.name +'end', ev); + this.triggered = false; + return; + } - var subscription = { - id: util.randomUUID(), - event: event, - regexp: regexp, - callback: (typeof callback === 'function') ? callback : null, - target: target - }; + // atleast multitouch + if(ev.touches.length < 2) { + return; + } - this.subscriptions.push(subscription); + // prevent default when two fingers are on the screen + if(inst.options.transform_always_block) { + ev.preventDefault(); + } - return subscription.id; + switch(ev.eventType) { + case Hammer.EVENT_START: + this.triggered = false; + break; + + case Hammer.EVENT_MOVE: + var scale_threshold = Math.abs(1-ev.scale); + var rotation_threshold = Math.abs(ev.rotation); + + // when the distance we moved is too small we skip this gesture + // or we can be already in dragging + if(scale_threshold < inst.options.transform_min_scale && + rotation_threshold < inst.options.transform_min_rotation) { + return; + } + + // we are transforming! + Hammer.detection.current.name = this.name; + + // first time, trigger dragstart event + if(!this.triggered) { + inst.trigger(this.name +'start', ev); + this.triggered = true; + } + + inst.trigger(this.name, ev); // basic transform event + + // trigger rotate event + if(rotation_threshold > inst.options.transform_min_rotation) { + inst.trigger('rotate', ev); + } + + // trigger pinch event + if(scale_threshold > inst.options.transform_min_scale) { + inst.trigger('pinch', ev); + inst.trigger('pinch'+ ((ev.scale < 1) ? 'in' : 'out'), ev); + } + break; + + case Hammer.EVENT_END: + // trigger dragend + if(this.triggered) { + inst.trigger(this.name +'end', ev); + } + + this.triggered = false; + break; + } + } }; + /** - * Unsubscribe from an event - * @param {String | Object} filter Filter for subscriptions to be removed - * Filter can be a string containing a - * subscription id, or an object containing - * one or more of the fields id, event, - * callback, and target. + * Touch + * Called as first, tells the user has touched the screen + * @events touch */ -EventBus.prototype.off = function (filter) { - var i = 0; - while (i < this.subscriptions.length) { - var subscription = this.subscriptions[i]; +Hammer.gestures.Touch = { + name: 'touch', + index: -Infinity, + defaults: { + // call preventDefault at touchstart, and makes the element blocking by + // disabling the scrolling of the page, but it improves gestures like + // transforming and dragging. + // be careful with using this, it can be very annoying for users to be stuck + // on the page + prevent_default: false, - var match = true; - if (filter instanceof Object) { - // filter is an object. All fields must match - for (var prop in filter) { - if (filter.hasOwnProperty(prop)) { - if (filter[prop] !== subscription[prop]) { - match = false; - } - } - } - } - else { - // filter is a string, filter on id - match = (subscription.id == filter); + // disable mouse events, so only touch (or pen!) input triggers events + prevent_mouseevents: false + }, + handler: function touchGesture(ev, inst) { + if(inst.options.prevent_mouseevents && ev.pointerType == Hammer.POINTER_MOUSE) { + ev.stopDetect(); + return; } - if (match) { - this.subscriptions.splice(i, 1); + if(inst.options.prevent_default) { + ev.preventDefault(); } - else { - i++; + + if(ev.eventType == Hammer.EVENT_START) { + inst.trigger(this.name, ev); } } }; + /** - * Emit an event - * @param {String} event - * @param {*} [data] - * @param {*} [source] + * Release + * Called as last, tells the user has released the screen + * @events release */ -EventBus.prototype.emit = function (event, data, source) { - for (var i =0; i < this.subscriptions.length; i++) { - var subscription = this.subscriptions[i]; - if (subscription.regexp.test(event)) { - if (subscription.callback) { - subscription.callback(event, data, source); - } +Hammer.gestures.Release = { + name: 'release', + index: Infinity, + handler: function releaseGesture(ev, inst) { + if(ev.eventType == Hammer.EVENT_END) { + inst.trigger(this.name, ev); } } }; -/** - * DataSet - * - * Usage: - * var dataSet = new DataSet({ - * fieldId: '_id', - * convert: { - * // ... - * } - * }); - * - * dataSet.add(item); - * dataSet.add(data); - * dataSet.update(item); - * dataSet.update(data); - * dataSet.remove(id); - * dataSet.remove(ids); - * var data = dataSet.get(); - * var data = dataSet.get(id); - * var data = dataSet.get(ids); - * var data = dataSet.get(ids, options, data); - * dataSet.clear(); - * - * A data set can: - * - add/remove/update data - * - gives triggers upon changes in the data - * - can import/export data in various data formats - * - * @param {Object} [options] Available options: - * {String} fieldId Field name of the id in the - * items, 'id' by default. - * {Object. ["10", "00"] or "-1530" > ["-15", "30"] + parseTimezoneChunker = /([\+\-]|\d\d)/gi, + + // getter and setter names + proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'), + unitMillisecondFactors = { + 'Milliseconds' : 1, + 'Seconds' : 1e3, + 'Minutes' : 6e4, + 'Hours' : 36e5, + 'Days' : 864e5, + 'Months' : 2592e6, + 'Years' : 31536e6 + }, + + unitAliases = { + ms : 'millisecond', + s : 'second', + m : 'minute', + h : 'hour', + d : 'day', + w : 'week', + W : 'isoweek', + M : 'month', + y : 'year' + }, + + // format function strings + formatFunctions = {}, + + // tokens to ordinalize and pad + ordinalizeTokens = 'DDD w W M D d'.split(' '), + paddedTokens = 'M D H h m s w W'.split(' '), + + formatTokenFunctions = { + M : function () { + return this.month() + 1; + }, + MMM : function (format) { + return this.lang().monthsShort(this, format); + }, + MMMM : function (format) { + return this.lang().months(this, format); + }, + D : function () { + return this.date(); + }, + DDD : function () { + return this.dayOfYear(); + }, + d : function () { + return this.day(); + }, + dd : function (format) { + return this.lang().weekdaysMin(this, format); + }, + ddd : function (format) { + return this.lang().weekdaysShort(this, format); + }, + dddd : function (format) { + return this.lang().weekdays(this, format); + }, + w : function () { + return this.week(); + }, + W : function () { + return this.isoWeek(); + }, + YY : function () { + return leftZeroFill(this.year() % 100, 2); + }, + YYYY : function () { + return leftZeroFill(this.year(), 4); + }, + YYYYY : function () { + return leftZeroFill(this.year(), 5); + }, + gg : function () { + return leftZeroFill(this.weekYear() % 100, 2); + }, + gggg : function () { + return this.weekYear(); + }, + ggggg : function () { + return leftZeroFill(this.weekYear(), 5); + }, + GG : function () { + return leftZeroFill(this.isoWeekYear() % 100, 2); + }, + GGGG : function () { + return this.isoWeekYear(); + }, + GGGGG : function () { + return leftZeroFill(this.isoWeekYear(), 5); + }, + e : function () { + return this.weekday(); + }, + E : function () { + return this.isoWeekday(); + }, + a : function () { + return this.lang().meridiem(this.hours(), this.minutes(), true); + }, + A : function () { + return this.lang().meridiem(this.hours(), this.minutes(), false); + }, + H : function () { + return this.hours(); + }, + h : function () { + return this.hours() % 12 || 12; + }, + m : function () { + return this.minutes(); + }, + s : function () { + return this.seconds(); + }, + S : function () { + return ~~(this.milliseconds() / 100); + }, + SS : function () { + return leftZeroFill(~~(this.milliseconds() / 10), 2); + }, + SSS : function () { + return leftZeroFill(this.milliseconds(), 3); + }, + Z : function () { + var a = -this.zone(), + b = "+"; + if (a < 0) { + a = -a; + b = "-"; + } + return b + leftZeroFill(~~(a / 60), 2) + ":" + leftZeroFill(~~a % 60, 2); + }, + ZZ : function () { + var a = -this.zone(), + b = "+"; + if (a < 0) { + a = -a; + b = "-"; + } + return b + leftZeroFill(~~(10 * a / 6), 4); + }, + z : function () { + return this.zoneAbbr(); + }, + zz : function () { + return this.zoneName(); + }, + X : function () { + return this.unix(); + } + }; + + function padToken(func, count) { + return function (a) { + return leftZeroFill(func.call(this, a), count); + }; + } + function ordinalizeToken(func, period) { + return function (a) { + return this.lang().ordinal(func.call(this, a), period); + }; + } + + while (ordinalizeTokens.length) { + i = ordinalizeTokens.pop(); + formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i); + } + while (paddedTokens.length) { + i = paddedTokens.pop(); + formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2); + } + formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3); + + + /************************************ + Constructors + ************************************/ + + function Language() { + + } + + // Moment prototype object + function Moment(config) { + extend(this, config); + } + + // Duration Constructor + function Duration(duration) { + var years = duration.years || duration.year || duration.y || 0, + months = duration.months || duration.month || duration.M || 0, + weeks = duration.weeks || duration.week || duration.w || 0, + days = duration.days || duration.day || duration.d || 0, + hours = duration.hours || duration.hour || duration.h || 0, + minutes = duration.minutes || duration.minute || duration.m || 0, + seconds = duration.seconds || duration.second || duration.s || 0, + milliseconds = duration.milliseconds || duration.millisecond || duration.ms || 0; + + // store reference to input for deterministic cloning + this._input = duration; + + // representation for dateAddRemove + this._milliseconds = +milliseconds + + seconds * 1e3 + // 1000 + minutes * 6e4 + // 1000 * 60 + hours * 36e5; // 1000 * 60 * 60 + // Because of dateAddRemove treats 24 hours as different from a + // day when working around DST, we need to store them separately + this._days = +days + + weeks * 7; + // It is impossible translate months into days without knowing + // which months you are are talking about, so we have to store + // it separately. + this._months = +months + + years * 12; + + this._data = {}; + + this._bubble(); + } + + + /************************************ + Helpers + ************************************/ + + + function extend(a, b) { + for (var i in b) { + if (b.hasOwnProperty(i)) { + a[i] = b[i]; + } + } + return a; + } + + function absRound(number) { + if (number < 0) { + return Math.ceil(number); + } else { + return Math.floor(number); + } + } + + // left zero fill a number + // see http://jsperf.com/left-zero-filling for performance comparison + function leftZeroFill(number, targetLength) { + var output = number + ''; + while (output.length < targetLength) { + output = '0' + output; + } + return output; + } + + // helper function for _.addTime and _.subtractTime + function addOrSubtractDurationFromMoment(mom, duration, isAdding, ignoreUpdateOffset) { + var milliseconds = duration._milliseconds, + days = duration._days, + months = duration._months, + minutes, + hours; + + if (milliseconds) { + mom._d.setTime(+mom._d + milliseconds * isAdding); + } + // store the minutes and hours so we can restore them + if (days || months) { + minutes = mom.minute(); + hours = mom.hour(); + } + if (days) { + mom.date(mom.date() + days * isAdding); + } + if (months) { + mom.month(mom.month() + months * isAdding); + } + if (milliseconds && !ignoreUpdateOffset) { + moment.updateOffset(mom); + } + // restore the minutes and hours after possibly changing dst + if (days || months) { + mom.minute(minutes); + mom.hour(hours); + } + } + + // check if is an array + function isArray(input) { + return Object.prototype.toString.call(input) === '[object Array]'; + } + + // compare two arrays, return the number of differences + function compareArrays(array1, array2) { + var len = Math.min(array1.length, array2.length), + lengthDiff = Math.abs(array1.length - array2.length), + diffs = 0, + i; + for (i = 0; i < len; i++) { + if (~~array1[i] !== ~~array2[i]) { + diffs++; + } + } + return diffs + lengthDiff; + } + + function normalizeUnits(units) { + return units ? unitAliases[units] || units.toLowerCase().replace(/(.)s$/, '$1') : units; + } + + + /************************************ + Languages + ************************************/ + + + extend(Language.prototype, { + + set : function (config) { + var prop, i; + for (i in config) { + prop = config[i]; + if (typeof prop === 'function') { + this[i] = prop; + } else { + this['_' + i] = prop; + } + } + }, + + _months : "January_February_March_April_May_June_July_August_September_October_November_December".split("_"), + months : function (m) { + return this._months[m.month()]; + }, + + _monthsShort : "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"), + monthsShort : function (m) { + return this._monthsShort[m.month()]; + }, + + monthsParse : function (monthName) { + var i, mom, regex; + + if (!this._monthsParse) { + this._monthsParse = []; + } + + for (i = 0; i < 12; i++) { + // make the regex if we don't have it already + if (!this._monthsParse[i]) { + mom = moment.utc([2000, i]); + regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); + this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (this._monthsParse[i].test(monthName)) { + return i; + } + } + }, + + _weekdays : "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), + weekdays : function (m) { + return this._weekdays[m.day()]; + }, + + _weekdaysShort : "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"), + weekdaysShort : function (m) { + return this._weekdaysShort[m.day()]; + }, + + _weekdaysMin : "Su_Mo_Tu_We_Th_Fr_Sa".split("_"), + weekdaysMin : function (m) { + return this._weekdaysMin[m.day()]; + }, + + weekdaysParse : function (weekdayName) { + var i, mom, regex; + + if (!this._weekdaysParse) { + this._weekdaysParse = []; + } + + for (i = 0; i < 7; i++) { + // make the regex if we don't have it already + if (!this._weekdaysParse[i]) { + mom = moment([2000, 1]).day(i); + regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); + this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (this._weekdaysParse[i].test(weekdayName)) { + return i; + } + } + }, + + _longDateFormat : { + LT : "h:mm A", + L : "MM/DD/YYYY", + LL : "MMMM D YYYY", + LLL : "MMMM D YYYY LT", + LLLL : "dddd, MMMM D YYYY LT" + }, + longDateFormat : function (key) { + var output = this._longDateFormat[key]; + if (!output && this._longDateFormat[key.toUpperCase()]) { + output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) { + return val.slice(1); + }); + this._longDateFormat[key] = output; + } + return output; + }, + + isPM : function (input) { + // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays + // Using charAt should be more compatible. + return ((input + '').toLowerCase().charAt(0) === 'p'); + }, + + _meridiemParse : /[ap]\.?m?\.?/i, + meridiem : function (hours, minutes, isLower) { + if (hours > 11) { + return isLower ? 'pm' : 'PM'; + } else { + return isLower ? 'am' : 'AM'; + } + }, + + _calendar : { + sameDay : '[Today at] LT', + nextDay : '[Tomorrow at] LT', + nextWeek : 'dddd [at] LT', + lastDay : '[Yesterday at] LT', + lastWeek : '[Last] dddd [at] LT', + sameElse : 'L' + }, + calendar : function (key, mom) { + var output = this._calendar[key]; + return typeof output === 'function' ? output.apply(mom) : output; + }, + + _relativeTime : { + future : "in %s", + past : "%s ago", + s : "a few seconds", + m : "a minute", + mm : "%d minutes", + h : "an hour", + hh : "%d hours", + d : "a day", + dd : "%d days", + M : "a month", + MM : "%d months", + y : "a year", + yy : "%d years" + }, + relativeTime : function (number, withoutSuffix, string, isFuture) { + var output = this._relativeTime[string]; + return (typeof output === 'function') ? + output(number, withoutSuffix, string, isFuture) : + output.replace(/%d/i, number); + }, + pastFuture : function (diff, output) { + var format = this._relativeTime[diff > 0 ? 'future' : 'past']; + return typeof format === 'function' ? format(output) : format.replace(/%s/i, output); + }, + + ordinal : function (number) { + return this._ordinal.replace("%d", number); + }, + _ordinal : "%d", + + preparse : function (string) { + return string; + }, + + postformat : function (string) { + return string; + }, + + week : function (mom) { + return weekOfYear(mom, this._week.dow, this._week.doy).week; + }, + _week : { + dow : 0, // Sunday is the first day of the week. + doy : 6 // The week that contains Jan 1st is the first week of the year. + } + }); + + // Loads a language definition into the `languages` cache. The function + // takes a key and optionally values. If not in the browser and no values + // are provided, it will load the language file module. As a convenience, + // this function also returns the language values. + function loadLang(key, values) { + values.abbr = key; + if (!languages[key]) { + languages[key] = new Language(); + } + languages[key].set(values); + return languages[key]; + } + + // Remove a language from the `languages` cache. Mostly useful in tests. + function unloadLang(key) { + delete languages[key]; + } + + // Determines which language definition to use and returns it. + // + // With no parameters, it will return the global language. If you + // pass in a language key, such as 'en', it will return the + // definition for 'en', so long as 'en' has already been loaded using + // moment.lang. + function getLangDefinition(key) { + if (!key) { + return moment.fn._lang; + } + if (!languages[key] && hasModule) { + try { + require('./lang/' + key); + } catch (e) { + // call with no params to set to default + return moment.fn._lang; + } + } + return languages[key] || moment.fn._lang; + } + + + /************************************ + Formatting + ************************************/ + + + function removeFormattingTokens(input) { + if (input.match(/\[.*\]/)) { + return input.replace(/^\[|\]$/g, ""); + } + return input.replace(/\\/g, ""); + } + + function makeFormatFunction(format) { + var array = format.match(formattingTokens), i, length; + + for (i = 0, length = array.length; i < length; i++) { + if (formatTokenFunctions[array[i]]) { + array[i] = formatTokenFunctions[array[i]]; + } else { + array[i] = removeFormattingTokens(array[i]); + } + } + + return function (mom) { + var output = ""; + for (i = 0; i < length; i++) { + output += array[i] instanceof Function ? array[i].call(mom, format) : array[i]; + } + return output; + }; + } + + // format date using native date object + function formatMoment(m, format) { + + format = expandFormat(format, m.lang()); + + if (!formatFunctions[format]) { + formatFunctions[format] = makeFormatFunction(format); + } + + return formatFunctions[format](m); + } + + function expandFormat(format, lang) { + var i = 5; + + function replaceLongDateFormatTokens(input) { + return lang.longDateFormat(input) || input; + } + + while (i-- && (localFormattingTokens.lastIndex = 0, + localFormattingTokens.test(format))) { + format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); + } + + return format; + } + + + /************************************ + Parsing + ************************************/ + + + // get the regex to find the next token + function getParseRegexForToken(token, config) { + switch (token) { + case 'DDDD': + return parseTokenThreeDigits; + case 'YYYY': + return parseTokenFourDigits; + case 'YYYYY': + return parseTokenSixDigits; + case 'S': + case 'SS': + case 'SSS': + case 'DDD': + return parseTokenOneToThreeDigits; + case 'MMM': + case 'MMMM': + case 'dd': + case 'ddd': + case 'dddd': + return parseTokenWord; + case 'a': + case 'A': + return getLangDefinition(config._l)._meridiemParse; + case 'X': + return parseTokenTimestampMs; + case 'Z': + case 'ZZ': + return parseTokenTimezone; + case 'T': + return parseTokenT; + case 'MM': + case 'DD': + case 'YY': + case 'HH': + case 'hh': + case 'mm': + case 'ss': + case 'M': + case 'D': + case 'd': + case 'H': + case 'h': + case 'm': + case 's': + return parseTokenOneOrTwoDigits; + default : + return new RegExp(token.replace('\\', '')); + } } - subscribers.push({ - callback: callback - }); -}; + function timezoneMinutesFromString(string) { + var tzchunk = (parseTokenTimezone.exec(string) || [])[0], + parts = (tzchunk + '').match(parseTimezoneChunker) || ['-', 0, 0], + minutes = +(parts[1] * 60) + ~~parts[2]; -/** - * Unsubscribe from an event, remove an event listener - * @param {String} event - * @param {function} callback - */ -DataSet.prototype.unsubscribe = function (event, callback) { - var subscribers = this.subscribers[event]; - if (subscribers) { - this.subscribers[event] = subscribers.filter(function (listener) { - return (listener.callback != callback); - }); + return parts[0] === '+' ? -minutes : minutes; } -}; -/** - * Trigger an event - * @param {String} event - * @param {Object | null} params - * @param {String} [senderId] Optional id of the sender. - * @private - */ -DataSet.prototype._trigger = function (event, params, senderId) { - if (event == '*') { - throw new Error('Cannot trigger event *'); + // function to convert string input to date + function addTimeToArrayFromToken(token, input, config) { + var a, datePartArray = config._a; + + switch (token) { + // MONTH + case 'M' : // fall through to MM + case 'MM' : + if (input != null) { + datePartArray[1] = ~~input - 1; + } + break; + case 'MMM' : // fall through to MMMM + case 'MMMM' : + a = getLangDefinition(config._l).monthsParse(input); + // if we didn't find a month name, mark the date as invalid. + if (a != null) { + datePartArray[1] = a; + } else { + config._isValid = false; + } + break; + // DAY OF MONTH + case 'D' : // fall through to DD + case 'DD' : + if (input != null) { + datePartArray[2] = ~~input; + } + break; + // DAY OF YEAR + case 'DDD' : // fall through to DDDD + case 'DDDD' : + if (input != null) { + datePartArray[1] = 0; + datePartArray[2] = ~~input; + } + break; + // YEAR + case 'YY' : + datePartArray[0] = ~~input + (~~input > 68 ? 1900 : 2000); + break; + case 'YYYY' : + case 'YYYYY' : + datePartArray[0] = ~~input; + break; + // AM / PM + case 'a' : // fall through to A + case 'A' : + config._isPm = getLangDefinition(config._l).isPM(input); + break; + // 24 HOUR + case 'H' : // fall through to hh + case 'HH' : // fall through to hh + case 'h' : // fall through to hh + case 'hh' : + datePartArray[3] = ~~input; + break; + // MINUTE + case 'm' : // fall through to mm + case 'mm' : + datePartArray[4] = ~~input; + break; + // SECOND + case 's' : // fall through to ss + case 'ss' : + datePartArray[5] = ~~input; + break; + // MILLISECOND + case 'S' : + case 'SS' : + case 'SSS' : + datePartArray[6] = ~~ (('0.' + input) * 1000); + break; + // UNIX TIMESTAMP WITH MS + case 'X': + config._d = new Date(parseFloat(input) * 1000); + break; + // TIMEZONE + case 'Z' : // fall through to ZZ + case 'ZZ' : + config._useUTC = true; + config._tzm = timezoneMinutesFromString(input); + break; + } + + // if the input is null, the date is not valid + if (input == null) { + config._isValid = false; + } } - var subscribers = []; - if (event in this.subscribers) { - subscribers = subscribers.concat(this.subscribers[event]); + // convert an array to a date. + // the array should mirror the parameters below + // note: all values past the year are optional and will default to the lowest possible value. + // [year, month, day , hour, minute, second, millisecond] + function dateFromArray(config) { + var i, date, input = [], currentDate; + + if (config._d) { + return; + } + + // Default to current date. + // * if no year, month, day of month are given, default to today + // * if day of month is given, default month and year + // * if month is given, default only year + // * if year is given, don't default anything + currentDate = currentDateArray(config); + for (i = 0; i < 3 && config._a[i] == null; ++i) { + config._a[i] = input[i] = currentDate[i]; + } + + // Zero out whatever was not defaulted, including time + for (; i < 7; i++) { + config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; + } + + // add the offsets to the time to be parsed so that we can have a clean array for checking isValid + input[3] += ~~((config._tzm || 0) / 60); + input[4] += ~~((config._tzm || 0) % 60); + + date = new Date(0); + + if (config._useUTC) { + date.setUTCFullYear(input[0], input[1], input[2]); + date.setUTCHours(input[3], input[4], input[5], input[6]); + } else { + date.setFullYear(input[0], input[1], input[2]); + date.setHours(input[3], input[4], input[5], input[6]); + } + + config._d = date; } - if ('*' in this.subscribers) { - subscribers = subscribers.concat(this.subscribers['*']); + + function dateFromObject(config) { + var o = config._i; + + if (config._d) { + return; + } + + config._a = [ + o.years || o.year || o.y, + o.months || o.month || o.M, + o.days || o.day || o.d, + o.hours || o.hour || o.h, + o.minutes || o.minute || o.m, + o.seconds || o.second || o.s, + o.milliseconds || o.millisecond || o.ms + ]; + + dateFromArray(config); } - for (var i = 0; i < subscribers.length; i++) { - var subscriber = subscribers[i]; - if (subscriber.callback) { - subscriber.callback(event, params, senderId || null); + function currentDateArray(config) { + var now = new Date(); + if (config._useUTC) { + return [ + now.getUTCFullYear(), + now.getUTCMonth(), + now.getUTCDate() + ]; + } else { + return [now.getFullYear(), now.getMonth(), now.getDate()]; } } -}; -/** - * Add data. - * Adding an item will fail when there already is an item with the same id. - * @param {Object | Array | DataTable} data - * @param {String} [senderId] Optional sender id - * @return {Array} addedIds Array with the ids of the added items - */ -DataSet.prototype.add = function (data, senderId) { - var addedIds = [], - id, - me = this; + // date from string and format string + function makeDateFromStringAndFormat(config) { + // This array is used to make a Date, either with `new Date` or `Date.UTC` + var lang = getLangDefinition(config._l), + string = '' + config._i, + i, parsedInput, tokens; - if (data instanceof Array) { - // Array - for (var i = 0, len = data.length; i < len; i++) { - id = me._addItem(data[i]); - addedIds.push(id); + tokens = expandFormat(config._f, lang).match(formattingTokens); + + config._a = []; + + for (i = 0; i < tokens.length; i++) { + parsedInput = (getParseRegexForToken(tokens[i], config).exec(string) || [])[0]; + if (parsedInput) { + string = string.slice(string.indexOf(parsedInput) + parsedInput.length); + } + // don't parse if its not a known token + if (formatTokenFunctions[tokens[i]]) { + addTimeToArrayFromToken(tokens[i], parsedInput, config); + } + } + + // add remaining unparsed input to the string + if (string) { + config._il = string; + } + + // handle am pm + if (config._isPm && config._a[3] < 12) { + config._a[3] += 12; + } + // if is 12 am, change hours to 0 + if (config._isPm === false && config._a[3] === 12) { + config._a[3] = 0; } + // return + dateFromArray(config); } - else if (util.isDataTable(data)) { - // Google DataTable - var columns = this._getColumnNames(data); - for (var row = 0, rows = data.getNumberOfRows(); row < rows; row++) { - var item = {}; - for (var col = 0, cols = columns.length; col < cols; col++) { - var field = columns[col]; - item[field] = data.getValue(row, col); + + // date from string and array of format strings + function makeDateFromStringAndArray(config) { + var tempConfig, + tempMoment, + bestMoment, + + scoreToBeat = 99, + i, + currentScore; + + for (i = 0; i < config._f.length; i++) { + tempConfig = extend({}, config); + tempConfig._f = config._f[i]; + makeDateFromStringAndFormat(tempConfig); + tempMoment = new Moment(tempConfig); + + currentScore = compareArrays(tempConfig._a, tempMoment.toArray()); + + // if there is any input that was not parsed + // add a penalty for that format + if (tempMoment._il) { + currentScore += tempMoment._il.length; } - id = me._addItem(item); - addedIds.push(id); + if (currentScore < scoreToBeat) { + scoreToBeat = currentScore; + bestMoment = tempMoment; + } } - } - else if (data instanceof Object) { - // Single item - id = me._addItem(data); - addedIds.push(id); - } - else { - throw new Error('Unknown dataType'); - } - if (addedIds.length) { - this._trigger('add', {items: addedIds}, senderId); + extend(config, bestMoment); } - return addedIds; -}; - -/** - * Update existing items. When an item does not exist, it will be created - * @param {Object | Array | DataTable} data - * @param {String} [senderId] Optional sender id - * @return {Array} updatedIds The ids of the added or updated items - */ -DataSet.prototype.update = function (data, senderId) { - var addedIds = [], - updatedIds = [], - me = this, - fieldId = me.fieldId; - - var addOrUpdate = function (item) { - var id = item[fieldId]; - if (me.data[id]) { - // update item - id = me._updateItem(item); - updatedIds.push(id); - } - else { - // add new item - id = me._addItem(item); - addedIds.push(id); - } - }; + // date from iso format + function makeDateFromString(config) { + var i, + string = config._i, + match = isoRegex.exec(string); - if (data instanceof Array) { - // Array - for (var i = 0, len = data.length; i < len; i++) { - addOrUpdate(data[i]); + if (match) { + // match[2] should be "T" or undefined + config._f = 'YYYY-MM-DD' + (match[2] || " "); + for (i = 0; i < 4; i++) { + if (isoTimes[i][1].exec(string)) { + config._f += isoTimes[i][0]; + break; + } + } + if (parseTokenTimezone.exec(string)) { + config._f += " Z"; + } + makeDateFromStringAndFormat(config); + } else { + config._d = new Date(string); } } - else if (util.isDataTable(data)) { - // Google DataTable - var columns = this._getColumnNames(data); - for (var row = 0, rows = data.getNumberOfRows(); row < rows; row++) { - var item = {}; - for (var col = 0, cols = columns.length; col < cols; col++) { - var field = columns[col]; - item[field] = data.getValue(row, col); - } - addOrUpdate(item); + function makeDateFromInput(config) { + var input = config._i, + matched = aspNetJsonRegex.exec(input); + + if (input === undefined) { + config._d = new Date(); + } else if (matched) { + config._d = new Date(+matched[1]); + } else if (typeof input === 'string') { + makeDateFromString(config); + } else if (isArray(input)) { + config._a = input.slice(0); + dateFromArray(config); + } else if (input instanceof Date) { + config._d = new Date(+input); + } else if (typeof(input) === 'object') { + dateFromObject(config); + } else { + config._d = new Date(input); } } - else if (data instanceof Object) { - // Single item - addOrUpdate(data); - } - else { - throw new Error('Unknown dataType'); - } - if (addedIds.length) { - this._trigger('add', {items: addedIds}, senderId); - } - if (updatedIds.length) { - this._trigger('update', {items: updatedIds}, senderId); - } - return addedIds.concat(updatedIds); -}; + /************************************ + Relative Time + ************************************/ -/** - * Get a data item or multiple items. - * - * Usage: - * - * get() - * get(options: Object) - * get(options: Object, data: Array | DataTable) - * - * get(id: Number | String) - * get(id: Number | String, options: Object) - * get(id: Number | String, options: Object, data: Array | DataTable) - * - * get(ids: Number[] | String[]) - * get(ids: Number[] | String[], options: Object) - * get(ids: Number[] | String[], options: Object, data: Array | DataTable) - * - * Where: - * - * {Number | String} id The id of an item - * {Number[] | String{}} ids An array with ids of items - * {Object} options An Object with options. Available options: - * {String} [type] Type of data to be returned. Can - * be 'DataTable' or 'Array' (default) - * {Object.} [convert] - * {String[]} [fields] field names to be returned - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * {Array | DataTable} [data] If provided, items will be appended to this - * array or table. Required in case of Google - * DataTable. - * - * @throws Error - */ -DataSet.prototype.get = function (args) { - var me = this; - // parse the arguments - var id, ids, options, data; - var firstType = util.getType(arguments[0]); - if (firstType == 'String' || firstType == 'Number') { - // get(id [, options] [, data]) - id = arguments[0]; - options = arguments[1]; - data = arguments[2]; - } - else if (firstType == 'Array') { - // get(ids [, options] [, data]) - ids = arguments[0]; - options = arguments[1]; - data = arguments[2]; + // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize + function substituteTimeAgo(string, number, withoutSuffix, isFuture, lang) { + return lang.relativeTime(number || 1, !!withoutSuffix, string, isFuture); } - else { - // get([, options] [, data]) - options = arguments[0]; - data = arguments[1]; + + function relativeTime(milliseconds, withoutSuffix, lang) { + var seconds = round(Math.abs(milliseconds) / 1000), + minutes = round(seconds / 60), + hours = round(minutes / 60), + days = round(hours / 24), + years = round(days / 365), + args = seconds < 45 && ['s', seconds] || + minutes === 1 && ['m'] || + minutes < 45 && ['mm', minutes] || + hours === 1 && ['h'] || + hours < 22 && ['hh', hours] || + days === 1 && ['d'] || + days <= 25 && ['dd', days] || + days <= 45 && ['M'] || + days < 345 && ['MM', round(days / 30)] || + years === 1 && ['y'] || ['yy', years]; + args[2] = withoutSuffix; + args[3] = milliseconds > 0; + args[4] = lang; + return substituteTimeAgo.apply({}, args); } - // determine the return type - var type; - if (options && options.type) { - type = (options.type == 'DataTable') ? 'DataTable' : 'Array'; - if (data && (type != util.getType(data))) { - throw new Error('Type of parameter "data" (' + util.getType(data) + ') ' + - 'does not correspond with specified options.type (' + options.type + ')'); + /************************************ + Week of Year + ************************************/ + + + // firstDayOfWeek 0 = sun, 6 = sat + // the day of the week that starts the week + // (usually sunday or monday) + // firstDayOfWeekOfYear 0 = sun, 6 = sat + // the first week is the week that contains the first + // of this day of the week + // (eg. ISO weeks use thursday (4)) + function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { + var end = firstDayOfWeekOfYear - firstDayOfWeek, + daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(), + adjustedMoment; + + + if (daysToDayOfWeek > end) { + daysToDayOfWeek -= 7; } - if (type == 'DataTable' && !util.isDataTable(data)) { - throw new Error('Parameter "data" must be a DataTable ' + - 'when options.type is "DataTable"'); + + if (daysToDayOfWeek < end - 7) { + daysToDayOfWeek += 7; } - } - else if (data) { - type = (util.getType(data) == 'DataTable') ? 'DataTable' : 'Array'; - } - else { - type = 'Array'; + + adjustedMoment = moment(mom).add('d', daysToDayOfWeek); + return { + week: Math.ceil(adjustedMoment.dayOfYear() / 7), + year: adjustedMoment.year() + }; } - // build options - var convert = options && options.convert || this.options.convert; - var filter = options && options.filter; - var items = [], item, itemId, i, len; - // convert items - if (id != undefined) { - // return a single item - item = me._getItem(id, convert); - if (filter && !filter(item)) { - item = null; - } - } - else if (ids != undefined) { - // return a subset of items - for (i = 0, len = ids.length; i < len; i++) { - item = me._getItem(ids[i], convert); - if (!filter || filter(item)) { - items.push(item); - } + /************************************ + Top Level Functions + ************************************/ + + function makeMoment(config) { + var input = config._i, + format = config._f; + + if (input === null || input === '') { + return null; } - } - else { - // return all items - for (itemId in this.data) { - if (this.data.hasOwnProperty(itemId)) { - item = me._getItem(itemId, convert); - if (!filter || filter(item)) { - items.push(item); - } + + if (typeof input === 'string') { + config._i = input = getLangDefinition().preparse(input); + } + + if (moment.isMoment(input)) { + config = extend({}, input); + config._d = new Date(+input._d); + } else if (format) { + if (isArray(format)) { + makeDateFromStringAndArray(config); + } else { + makeDateFromStringAndFormat(config); } + } else { + makeDateFromInput(config); } - } - // order the results - if (options && options.order && id == undefined) { - this._sort(items, options.order); + return new Moment(config); } - // filter fields of the items - if (options && options.fields) { - var fields = options.fields; - if (id != undefined) { - item = this._filterFields(item, fields); - } - else { - for (i = 0, len = items.length; i < len; i++) { - items[i] = this._filterFields(items[i], fields); + moment = function (input, format, lang) { + return makeMoment({ + _i : input, + _f : format, + _l : lang, + _isUTC : false + }); + }; + + // creating with utc + moment.utc = function (input, format, lang) { + return makeMoment({ + _useUTC : true, + _isUTC : true, + _l : lang, + _i : input, + _f : format + }).utc(); + }; + + // creating with unix timestamp (in seconds) + moment.unix = function (input) { + return moment(input * 1000); + }; + + // duration + moment.duration = function (input, key) { + var isDuration = moment.isDuration(input), + isNumber = (typeof input === 'number'), + duration = (isDuration ? input._input : (isNumber ? {} : input)), + matched = aspNetTimeSpanJsonRegex.exec(input), + sign, + ret; + + if (isNumber) { + if (key) { + duration[key] = input; + } else { + duration.milliseconds = input; } + } else if (matched) { + sign = (matched[1] === "-") ? -1 : 1; + duration = { + y: 0, + d: ~~matched[2] * sign, + h: ~~matched[3] * sign, + m: ~~matched[4] * sign, + s: ~~matched[5] * sign, + ms: ~~matched[6] * sign + }; } - } - // return the results - if (type == 'DataTable') { - var columns = this._getColumnNames(data); - if (id != undefined) { - // append a single item to the data table - me._appendRow(data, columns, item); + ret = new Duration(duration); + + if (isDuration && input.hasOwnProperty('_lang')) { + ret._lang = input._lang; } - else { - // copy the items to the provided data table - for (i = 0, len = items.length; i < len; i++) { - me._appendRow(data, columns, items[i]); - } + + return ret; + }; + + // version number + moment.version = VERSION; + + // default format + moment.defaultFormat = isoFormat; + + // This function will be called whenever a moment is mutated. + // It is intended to keep the offset in sync with the timezone. + moment.updateOffset = function () {}; + + // This function will load languages and then set the global language. If + // no arguments are passed in, it will simply return the current global + // language key. + moment.lang = function (key, values) { + if (!key) { + return moment.fn._lang._abbr; } - return data; - } - else { - // return an array - if (id != undefined) { - // a single item - return item; + key = key.toLowerCase(); + key = key.replace('_', '-'); + if (values) { + loadLang(key, values); + } else if (values === null) { + unloadLang(key); + key = 'en'; + } else if (!languages[key]) { + getLangDefinition(key); } - else { - // multiple items - if (data) { - // copy the items to the provided array - for (i = 0, len = items.length; i < len; i++) { - data.push(items[i]); - } - return data; - } - else { - // just return our array - return items; - } + moment.duration.fn._lang = moment.fn._lang = getLangDefinition(key); + }; + + // returns language data + moment.langData = function (key) { + if (key && key._lang && key._lang._abbr) { + key = key._lang._abbr; } - } -}; + return getLangDefinition(key); + }; -/** - * Get ids of all items or from a filtered set of items. - * @param {Object} [options] An Object with options. Available options: - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * @return {Array} ids - */ -DataSet.prototype.getIds = function (options) { - var data = this.data, - filter = options && options.filter, - order = options && options.order, - convert = options && options.convert || this.options.convert, - i, - len, - id, - item, - items, - ids = []; + // compare moment object + moment.isMoment = function (obj) { + return obj instanceof Moment; + }; - if (filter) { - // get filtered items - if (order) { - // create ordered list - items = []; - for (id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, convert); - if (filter(item)) { - items.push(item); - } - } - } + // for typechecking Duration objects + moment.isDuration = function (obj) { + return obj instanceof Duration; + }; - this._sort(items, order); - for (i = 0, len = items.length; i < len; i++) { - ids[i] = items[i][this.fieldId]; - } - } - else { - // create unordered list - for (id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, convert); - if (filter(item)) { - ids.push(item[this.fieldId]); - } + /************************************ + Moment Prototype + ************************************/ + + + extend(moment.fn = Moment.prototype, { + + clone : function () { + return moment(this); + }, + + valueOf : function () { + return +this._d + ((this._offset || 0) * 60000); + }, + + unix : function () { + return Math.floor(+this / 1000); + }, + + toString : function () { + return this.format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ"); + }, + + toDate : function () { + return this._offset ? new Date(+this) : this._d; + }, + + toISOString : function () { + return formatMoment(moment(this).utc(), 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); + }, + + toArray : function () { + var m = this; + return [ + m.year(), + m.month(), + m.date(), + m.hours(), + m.minutes(), + m.seconds(), + m.milliseconds() + ]; + }, + + isValid : function () { + if (this._isValid == null) { + if (this._a) { + this._isValid = !compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()); + } else { + this._isValid = !isNaN(this._d.getTime()); } } - } - } - else { - // get all items - if (order) { - // create an ordered list - items = []; - for (id in data) { - if (data.hasOwnProperty(id)) { - items.push(data[id]); - } + return !!this._isValid; + }, + + invalidAt: function () { + var i, arr1 = this._a, arr2 = (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray(); + for (i = 6; i >= 0 && arr1[i] === arr2[i]; --i) { + // empty loop body } + return i; + }, - this._sort(items, order); + utc : function () { + return this.zone(0); + }, - for (i = 0, len = items.length; i < len; i++) { - ids[i] = items[i][this.fieldId]; - } - } - else { - // create unordered list - for (id in data) { - if (data.hasOwnProperty(id)) { - item = data[id]; - ids.push(item[this.fieldId]); - } + local : function () { + this.zone(0); + this._isUTC = false; + return this; + }, + + format : function (inputString) { + var output = formatMoment(this, inputString || moment.defaultFormat); + return this.lang().postformat(output); + }, + + add : function (input, val) { + var dur; + // switch args to support add('s', 1) and add(1, 's') + if (typeof input === 'string') { + dur = moment.duration(+val, input); + } else { + dur = moment.duration(input, val); } - } - } + addOrSubtractDurationFromMoment(this, dur, 1); + return this; + }, - return ids; -}; + subtract : function (input, val) { + var dur; + // switch args to support subtract('s', 1) and subtract(1, 's') + if (typeof input === 'string') { + dur = moment.duration(+val, input); + } else { + dur = moment.duration(input, val); + } + addOrSubtractDurationFromMoment(this, dur, -1); + return this; + }, -/** - * Execute a callback function for every item in the dataset. - * The order of the items is not determined. - * @param {function} callback - * @param {Object} [options] Available options: - * {Object.} [convert] - * {String[]} [fields] filter fields - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - */ -DataSet.prototype.forEach = function (callback, options) { - var filter = options && options.filter, - convert = options && options.convert || this.options.convert, - data = this.data, - item, - id; + diff : function (input, units, asFloat) { + var that = this._isUTC ? moment(input).zone(this._offset || 0) : moment(input).local(), + zoneDiff = (this.zone() - that.zone()) * 6e4, + diff, output; - if (options && options.order) { - // execute forEach on ordered list - var items = this.get(options); + units = normalizeUnits(units); - for (var i = 0, len = items.length; i < len; i++) { - item = items[i]; - id = item[this.fieldId]; - callback(item, id); - } - } - else { - // unordered - for (id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, convert); - if (!filter || filter(item)) { - callback(item, id); + if (units === 'year' || units === 'month') { + // average number of days in the months in the given dates + diff = (this.daysInMonth() + that.daysInMonth()) * 432e5; // 24 * 60 * 60 * 1000 / 2 + // difference in months + output = ((this.year() - that.year()) * 12) + (this.month() - that.month()); + // adjust by taking difference in days, average number of days + // and dst in the given months. + output += ((this - moment(this).startOf('month')) - + (that - moment(that).startOf('month'))) / diff; + // same as above but with zones, to negate all dst + output -= ((this.zone() - moment(this).startOf('month').zone()) - + (that.zone() - moment(that).startOf('month').zone())) * 6e4 / diff; + if (units === 'year') { + output = output / 12; } + } else { + diff = (this - that); + output = units === 'second' ? diff / 1e3 : // 1000 + units === 'minute' ? diff / 6e4 : // 1000 * 60 + units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60 + units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst + units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst + diff; } - } - } -}; + return asFloat ? output : absRound(output); + }, -/** - * Map every item in the dataset. - * @param {function} callback - * @param {Object} [options] Available options: - * {Object.} [convert] - * {String[]} [fields] filter fields - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * @return {Object[]} mappedItems - */ -DataSet.prototype.map = function (callback, options) { - var filter = options && options.filter, - convert = options && options.convert || this.options.convert, - mappedItems = [], - data = this.data, - item; + from : function (time, withoutSuffix) { + return moment.duration(this.diff(time)).lang(this.lang()._abbr).humanize(!withoutSuffix); + }, - // convert and filter items - for (var id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, convert); - if (!filter || filter(item)) { - mappedItems.push(callback(item, id)); - } - } - } + fromNow : function (withoutSuffix) { + return this.from(moment(), withoutSuffix); + }, - // order items - if (options && options.order) { - this._sort(mappedItems, options.order); - } + calendar : function () { + var diff = this.diff(moment().zone(this.zone()).startOf('day'), 'days', true), + format = diff < -6 ? 'sameElse' : + diff < -1 ? 'lastWeek' : + diff < 0 ? 'lastDay' : + diff < 1 ? 'sameDay' : + diff < 2 ? 'nextDay' : + diff < 7 ? 'nextWeek' : 'sameElse'; + return this.format(this.lang().calendar(format, this)); + }, - return mappedItems; -}; + isLeapYear : function () { + var year = this.year(); + return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; + }, -/** - * Filter the fields of an item - * @param {Object} item - * @param {String[]} fields Field names - * @return {Object} filteredItem - * @private - */ -DataSet.prototype._filterFields = function (item, fields) { - var filteredItem = {}; + isDST : function () { + return (this.zone() < this.clone().month(0).zone() || + this.zone() < this.clone().month(5).zone()); + }, - for (var field in item) { - if (item.hasOwnProperty(field) && (fields.indexOf(field) != -1)) { - filteredItem[field] = item[field]; - } - } + day : function (input) { + var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); + if (input != null) { + if (typeof input === 'string') { + input = this.lang().weekdaysParse(input); + if (typeof input !== 'number') { + return this; + } + } + return this.add({ d : input - day }); + } else { + return day; + } + }, - return filteredItem; -}; + month : function (input) { + var utc = this._isUTC ? 'UTC' : '', + dayOfMonth; -/** - * Sort the provided array with items - * @param {Object[]} items - * @param {String | function} order A field name or custom sort function. - * @private - */ -DataSet.prototype._sort = function (items, order) { - if (util.isString(order)) { - // order by provided field name - var name = order; // field name - items.sort(function (a, b) { - var av = a[name]; - var bv = b[name]; - return (av > bv) ? 1 : ((av < bv) ? -1 : 0); - }); - } - else if (typeof order === 'function') { - // order by sort function - items.sort(order); - } - // TODO: extend order by an Object {field:String, direction:String} - // where direction can be 'asc' or 'desc' - else { - throw new TypeError('Order must be a function or a string'); - } -}; + if (input != null) { + if (typeof input === 'string') { + input = this.lang().monthsParse(input); + if (typeof input !== 'number') { + return this; + } + } -/** - * Remove an object by pointer or by id - * @param {String | Number | Object | Array} id Object or id, or an array with - * objects or ids to be removed - * @param {String} [senderId] Optional sender id - * @return {Array} removedIds - */ -DataSet.prototype.remove = function (id, senderId) { - var removedIds = [], - i, len, removedId; + dayOfMonth = this.date(); + this.date(1); + this._d['set' + utc + 'Month'](input); + this.date(Math.min(dayOfMonth, this.daysInMonth())); - if (id instanceof Array) { - for (i = 0, len = id.length; i < len; i++) { - removedId = this._remove(id[i]); - if (removedId != null) { - removedIds.push(removedId); + moment.updateOffset(this); + return this; + } else { + return this._d['get' + utc + 'Month'](); + } + }, + + startOf: function (units) { + units = normalizeUnits(units); + // the following switch intentionally omits break keywords + // to utilize falling through the cases. + switch (units) { + case 'year': + this.month(0); + /* falls through */ + case 'month': + this.date(1); + /* falls through */ + case 'week': + case 'isoweek': + case 'day': + this.hours(0); + /* falls through */ + case 'hour': + this.minutes(0); + /* falls through */ + case 'minute': + this.seconds(0); + /* falls through */ + case 'second': + this.milliseconds(0); + /* falls through */ } - } - } - else { - removedId = this._remove(id); - if (removedId != null) { - removedIds.push(removedId); - } - } - if (removedIds.length) { - this._trigger('remove', {items: removedIds}, senderId); - } + // weeks are a special case + if (units === 'week') { + this.weekday(0); + } else if (units === 'isoweek') { + this.isoWeekday(1); + } - return removedIds; -}; + return this; + }, -/** - * Remove an item by its id - * @param {Number | String | Object} id id or item - * @returns {Number | String | null} id - * @private - */ -DataSet.prototype._remove = function (id) { - if (util.isNumber(id) || util.isString(id)) { - if (this.data[id]) { - delete this.data[id]; - delete this.internalIds[id]; - return id; - } - } - else if (id instanceof Object) { - var itemId = id[this.fieldId]; - if (itemId && this.data[itemId]) { - delete this.data[itemId]; - delete this.internalIds[itemId]; - return itemId; - } - } - return null; -}; + endOf: function (units) { + units = normalizeUnits(units); + return this.startOf(units).add((units === 'isoweek' ? 'week' : units), 1).subtract('ms', 1); + }, -/** - * Clear the data - * @param {String} [senderId] Optional sender id - * @return {Array} removedIds The ids of all removed items - */ -DataSet.prototype.clear = function (senderId) { - var ids = Object.keys(this.data); + isAfter: function (input, units) { + units = typeof units !== 'undefined' ? units : 'millisecond'; + return +this.clone().startOf(units) > +moment(input).startOf(units); + }, - this.data = {}; - this.internalIds = {}; + isBefore: function (input, units) { + units = typeof units !== 'undefined' ? units : 'millisecond'; + return +this.clone().startOf(units) < +moment(input).startOf(units); + }, - this._trigger('remove', {items: ids}, senderId); + isSame: function (input, units) { + units = typeof units !== 'undefined' ? units : 'millisecond'; + return +this.clone().startOf(units) === +moment(input).startOf(units); + }, - return ids; -}; + min: function (other) { + other = moment.apply(null, arguments); + return other < this ? this : other; + }, -/** - * Find the item with maximum value of a specified field - * @param {String} field - * @return {Object | null} item Item containing max value, or null if no items - */ -DataSet.prototype.max = function (field) { - var data = this.data, - max = null, - maxField = null; + max: function (other) { + other = moment.apply(null, arguments); + return other > this ? this : other; + }, - for (var id in data) { - if (data.hasOwnProperty(id)) { - var item = data[id]; - var itemField = item[field]; - if (itemField != null && (!max || itemField > maxField)) { - max = item; - maxField = itemField; + zone : function (input) { + var offset = this._offset || 0; + if (input != null) { + if (typeof input === "string") { + input = timezoneMinutesFromString(input); + } + if (Math.abs(input) < 16) { + input = input * 60; + } + this._offset = input; + this._isUTC = true; + if (offset !== input) { + addOrSubtractDurationFromMoment(this, moment.duration(offset - input, 'm'), 1, true); + } + } else { + return this._isUTC ? offset : this._d.getTimezoneOffset(); } - } - } + return this; + }, - return max; -}; + zoneAbbr : function () { + return this._isUTC ? "UTC" : ""; + }, -/** - * Find the item with minimum value of a specified field - * @param {String} field - * @return {Object | null} item Item containing max value, or null if no items - */ -DataSet.prototype.min = function (field) { - var data = this.data, - min = null, - minField = null; + zoneName : function () { + return this._isUTC ? "Coordinated Universal Time" : ""; + }, - for (var id in data) { - if (data.hasOwnProperty(id)) { - var item = data[id]; - var itemField = item[field]; - if (itemField != null && (!min || itemField < minField)) { - min = item; - minField = itemField; + hasAlignedHourOffset : function (input) { + if (!input) { + input = 0; + } + else { + input = moment(input).zone(); } - } - } - return min; -}; + return (this.zone() - input) % 60 === 0; + }, -/** - * Find all distinct values of a specified field - * @param {String} field - * @return {Array} values Array containing all distinct values. If the data - * items do not contain the specified field, an array - * containing a single value undefined is returned. - * The returned array is unordered. - */ -DataSet.prototype.distinct = function (field) { - var data = this.data, - values = [], - fieldType = this.options.convert[field], - count = 0; + daysInMonth : function () { + return moment.utc([this.year(), this.month() + 1, 0]).date(); + }, - for (var prop in data) { - if (data.hasOwnProperty(prop)) { - var item = data[prop]; - var value = util.convert(item[field], fieldType); - var exists = false; - for (var i = 0; i < count; i++) { - if (values[i] == value) { - exists = true; - break; - } - } - if (!exists) { - values[count] = value; - count++; - } - } - } + dayOfYear : function (input) { + var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1; + return input == null ? dayOfYear : this.add("d", (input - dayOfYear)); + }, - return values; -}; + weekYear : function (input) { + var year = weekOfYear(this, this.lang()._week.dow, this.lang()._week.doy).year; + return input == null ? year : this.add("y", (input - year)); + }, -/** - * Add a single item. Will fail when an item with the same id already exists. - * @param {Object} item - * @return {String} id - * @private - */ -DataSet.prototype._addItem = function (item) { - var id = item[this.fieldId]; + isoWeekYear : function (input) { + var year = weekOfYear(this, 1, 4).year; + return input == null ? year : this.add("y", (input - year)); + }, - if (id != undefined) { - // check whether this id is already taken - if (this.data[id]) { - // item already exists - throw new Error('Cannot add item: item with id ' + id + ' already exists'); - } - } - else { - // generate an id - id = util.randomUUID(); - item[this.fieldId] = id; - this.internalIds[id] = item; - } + week : function (input) { + var week = this.lang().week(this); + return input == null ? week : this.add("d", (input - week) * 7); + }, - var d = {}; - for (var field in item) { - if (item.hasOwnProperty(field)) { - var fieldType = this.convert[field]; // type may be undefined - d[field] = util.convert(item[field], fieldType); - } - } - this.data[id] = d; + isoWeek : function (input) { + var week = weekOfYear(this, 1, 4).week; + return input == null ? week : this.add("d", (input - week) * 7); + }, - return id; -}; + weekday : function (input) { + var weekday = (this._d.getDay() + 7 - this.lang()._week.dow) % 7; + return input == null ? weekday : this.add("d", input - weekday); + }, -/** - * Get an item. Fields can be converted to a specific type - * @param {String} id - * @param {Object.} [convert] field types to convert - * @return {Object | null} item - * @private - */ -DataSet.prototype._getItem = function (id, convert) { - var field, value; + isoWeekday : function (input) { + // behaves the same as moment#day except + // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) + // as a setter, sunday should belong to the previous week. + return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7); + }, - // get the item from the dataset - var raw = this.data[id]; - if (!raw) { - return null; - } + get : function (units) { + units = normalizeUnits(units); + return this[units.toLowerCase()](); + }, - // convert the items field types - var converted = {}, - fieldId = this.fieldId, - internalIds = this.internalIds; - if (convert) { - for (field in raw) { - if (raw.hasOwnProperty(field)) { - value = raw[field]; - // output all fields, except internal ids - if ((field != fieldId) || !(value in internalIds)) { - converted[field] = util.convert(value, convert[field]); - } + set : function (units, value) { + units = normalizeUnits(units); + this[units.toLowerCase()](value); + }, + + // If passed a language key, it will set the language for this + // instance. Otherwise, it will return the language configuration + // variables for this instance. + lang : function (key) { + if (key === undefined) { + return this._lang; + } else { + this._lang = getLangDefinition(key); + return this; } } - } - else { - // no field types specified, no converting needed - for (field in raw) { - if (raw.hasOwnProperty(field)) { - value = raw[field]; - // output all fields, except internal ids - if ((field != fieldId) || !(value in internalIds)) { - converted[field] = value; - } + }); + + // helper for adding shortcuts + function makeGetterAndSetter(name, key) { + moment.fn[name] = moment.fn[name + 's'] = function (input) { + var utc = this._isUTC ? 'UTC' : ''; + if (input != null) { + this._d['set' + utc + key](input); + moment.updateOffset(this); + return this; + } else { + return this._d['get' + utc + key](); } - } + }; } - return converted; -}; - -/** - * Update a single item: merge with existing item. - * Will fail when the item has no id, or when there does not exist an item - * with the same id. - * @param {Object} item - * @return {String} id - * @private - */ -DataSet.prototype._updateItem = function (item) { - var id = item[this.fieldId]; - if (id == undefined) { - throw new Error('Cannot update item: item has no id (item: ' + JSON.stringify(item) + ')'); - } - var d = this.data[id]; - if (!d) { - // item doesn't exist - throw new Error('Cannot update item: no item with id ' + id + ' found'); + // loop through and add shortcuts (Month, Date, Hours, Minutes, Seconds, Milliseconds) + for (i = 0; i < proxyGettersAndSetters.length; i ++) { + makeGetterAndSetter(proxyGettersAndSetters[i].toLowerCase().replace(/s$/, ''), proxyGettersAndSetters[i]); } - // merge with current item - for (var field in item) { - if (item.hasOwnProperty(field)) { - var fieldType = this.convert[field]; // type may be undefined - d[field] = util.convert(item[field], fieldType); - } - } + // add shortcut for year (uses different syntax than the getter/setter 'year' == 'FullYear') + makeGetterAndSetter('year', 'FullYear'); - return id; -}; + // add plural methods + moment.fn.days = moment.fn.day; + moment.fn.months = moment.fn.month; + moment.fn.weeks = moment.fn.week; + moment.fn.isoWeeks = moment.fn.isoWeek; -/** - * Get an array with the column names of a Google DataTable - * @param {DataTable} dataTable - * @return {String[]} columnNames - * @private - */ -DataSet.prototype._getColumnNames = function (dataTable) { - var columns = []; - for (var col = 0, cols = dataTable.getNumberOfColumns(); col < cols; col++) { - columns[col] = dataTable.getColumnId(col) || dataTable.getColumnLabel(col); - } - return columns; -}; + // add aliased format methods + moment.fn.toJSON = moment.fn.toISOString; -/** - * Append an item as a row to the dataTable - * @param dataTable - * @param columns - * @param item - * @private - */ -DataSet.prototype._appendRow = function (dataTable, columns, item) { - var row = dataTable.addRow(); + /************************************ + Duration Prototype + ************************************/ - for (var col = 0, cols = columns.length; col < cols; col++) { - var field = columns[col]; - dataTable.setValue(row, col, item[field]); - } -}; -/** - * DataView - * - * a dataview offers a filtered view on a dataset or an other dataview. - * - * @param {DataSet | DataView} data - * @param {Object} [options] Available options: see method get - * - * @constructor DataView - */ -function DataView (data, options) { - this.id = util.randomUUID(); + extend(moment.duration.fn = Duration.prototype, { - this.data = null; - this.ids = {}; // ids of the items currently in memory (just contains a boolean true) - this.options = options || {}; - this.fieldId = 'id'; // name of the field containing id - this.subscribers = {}; // event subscribers + _bubble : function () { + var milliseconds = this._milliseconds, + days = this._days, + months = this._months, + data = this._data, + seconds, minutes, hours, years; - var me = this; - this.listener = function () { - me._onEvent.apply(me, arguments); - }; + // The following code bubbles up values, see the tests for + // examples of what that means. + data.milliseconds = milliseconds % 1000; - this.setData(data); -} + seconds = absRound(milliseconds / 1000); + data.seconds = seconds % 60; -/** - * Set a data source for the view - * @param {DataSet | DataView} data - */ -DataView.prototype.setData = function (data) { - var ids, dataItems, i, len; + minutes = absRound(seconds / 60); + data.minutes = minutes % 60; - if (this.data) { - // unsubscribe from current dataset - if (this.data.unsubscribe) { - this.data.unsubscribe('*', this.listener); - } + hours = absRound(minutes / 60); + data.hours = hours % 24; - // trigger a remove of all items in memory - ids = []; - for (var id in this.ids) { - if (this.ids.hasOwnProperty(id)) { - ids.push(id); + days += absRound(hours / 24); + data.days = days % 30; + + months += absRound(days / 30); + data.months = months % 12; + + years = absRound(months / 12); + data.years = years; + }, + + weeks : function () { + return absRound(this.days() / 7); + }, + + valueOf : function () { + return this._milliseconds + + this._days * 864e5 + + (this._months % 12) * 2592e6 + + ~~(this._months / 12) * 31536e6; + }, + + humanize : function (withSuffix) { + var difference = +this, + output = relativeTime(difference, !withSuffix, this.lang()); + + if (withSuffix) { + output = this.lang().pastFuture(difference, output); } - } - this.ids = {}; - this._trigger('remove', {items: ids}); - } - this.data = data; + return this.lang().postformat(output); + }, - if (this.data) { - // update fieldId - this.fieldId = this.options.fieldId || - (this.data && this.data.options && this.data.options.fieldId) || - 'id'; + add : function (input, val) { + // supports only 2.0-style add(1, 's') or add(moment) + var dur = moment.duration(input, val); - // trigger an add of all added items - ids = this.data.getIds({filter: this.options && this.options.filter}); - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - this.ids[id] = true; - } - this._trigger('add', {items: ids}); + this._milliseconds += dur._milliseconds; + this._days += dur._days; + this._months += dur._months; - // subscribe to new dataset - if (this.data.subscribe) { - this.data.subscribe('*', this.listener); - } - } -}; + this._bubble(); -/** - * Get data from the data view - * - * Usage: - * - * get() - * get(options: Object) - * get(options: Object, data: Array | DataTable) - * - * get(id: Number) - * get(id: Number, options: Object) - * get(id: Number, options: Object, data: Array | DataTable) - * - * get(ids: Number[]) - * get(ids: Number[], options: Object) - * get(ids: Number[], options: Object, data: Array | DataTable) - * - * Where: - * - * {Number | String} id The id of an item - * {Number[] | String{}} ids An array with ids of items - * {Object} options An Object with options. Available options: - * {String} [type] Type of data to be returned. Can - * be 'DataTable' or 'Array' (default) - * {Object.} [convert] - * {String[]} [fields] field names to be returned - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * {Array | DataTable} [data] If provided, items will be appended to this - * array or table. Required in case of Google - * DataTable. - * @param args - */ -DataView.prototype.get = function (args) { - var me = this; + return this; + }, - // parse the arguments - var ids, options, data; - var firstType = util.getType(arguments[0]); - if (firstType == 'String' || firstType == 'Number' || firstType == 'Array') { - // get(id(s) [, options] [, data]) - ids = arguments[0]; // can be a single id or an array with ids - options = arguments[1]; - data = arguments[2]; + subtract : function (input, val) { + var dur = moment.duration(input, val); + + this._milliseconds -= dur._milliseconds; + this._days -= dur._days; + this._months -= dur._months; + + this._bubble(); + + return this; + }, + + get : function (units) { + units = normalizeUnits(units); + return this[units.toLowerCase() + 's'](); + }, + + as : function (units) { + units = normalizeUnits(units); + return this['as' + units.charAt(0).toUpperCase() + units.slice(1) + 's'](); + }, + + lang : moment.fn.lang + }); + + function makeDurationGetter(name) { + moment.duration.fn[name] = function () { + return this._data[name]; + }; } - else { - // get([, options] [, data]) - options = arguments[0]; - data = arguments[1]; + + function makeDurationAsGetter(name, factor) { + moment.duration.fn['as' + name] = function () { + return +this / factor; + }; + } + + for (i in unitMillisecondFactors) { + if (unitMillisecondFactors.hasOwnProperty(i)) { + makeDurationAsGetter(i, unitMillisecondFactors[i]); + makeDurationGetter(i.toLowerCase()); + } } - // extend the options with the default options and provided options - var viewOptions = util.extend({}, this.options, options); + makeDurationAsGetter('Weeks', 6048e5); + moment.duration.fn.asMonths = function () { + return (+this - this.years() * 31536e6) / 2592e6 + this.years() * 12; + }; + + + /************************************ + Default Lang + ************************************/ + + + // Set default language, other languages will inherit from English. + moment.lang('en', { + ordinal : function (number) { + var b = number % 10, + output = (~~ (number % 100 / 10) === 1) ? 'th' : + (b === 1) ? 'st' : + (b === 2) ? 'nd' : + (b === 3) ? 'rd' : 'th'; + return number + output; + } + }); + + /* EMBED_LANGUAGES */ - // create a combined filter method when needed - if (this.options.filter && options && options.filter) { - viewOptions.filter = function (item) { - return me.options.filter(item) && options.filter(item); - } - } + /************************************ + Exposing Moment + ************************************/ - // build up the call to the linked data set - var getArguments = []; - if (ids != undefined) { - getArguments.push(ids); - } - getArguments.push(viewOptions); - getArguments.push(data); - return this.data && this.data.get.apply(this.data, getArguments); -}; + // CommonJS module is defined + if (hasModule) { + module.exports = moment; + } + /*global ender:false */ + if (typeof ender === 'undefined') { + // here, `this` means `window` in the browser, or `global` on the server + // add `moment` as a global object via a string identifier, + // for Closure Compiler "advanced" mode + this['moment'] = moment; + } + /*global define:false */ + if (typeof define === "function" && define.amd) { + define("moment", [], function () { + return moment; + }); + } +}).call(this); +},{}],3:[function(require,module,exports){ /** - * Get ids of all items or from a filtered set of items. - * @param {Object} [options] An Object with options. Available options: - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * @return {Array} ids + * vis.js module imports */ -DataView.prototype.getIds = function (options) { - var ids; - if (this.data) { - var defaultFilter = this.options.filter; - var filter; +// Try to load dependencies from the global window object. +// If not available there, load via require. +var moment = (typeof window !== 'undefined') && window['moment'] || require('moment'); +var Hammer = (typeof window !== 'undefined') && window['Hammer'] || require('hammerjs'); - if (options && options.filter) { - if (defaultFilter) { - filter = function (item) { - return defaultFilter(item) && options.filter(item); - } - } - else { - filter = options.filter; + +// Internet Explorer 8 and older does not support Array.indexOf, so we define +// it here in that case. +// http://soledadpenades.com/2007/05/17/arrayindexof-in-internet-explorer/ +if(!Array.prototype.indexOf) { + Array.prototype.indexOf = function(obj){ + for(var i = 0; i < this.length; i++){ + if(this[i] == obj){ + return i; } } - else { - filter = defaultFilter; - } + return -1; + }; - ids = this.data.getIds({ - filter: filter, - order: options && options.order - }); + try { + console.log("Warning: Ancient browser detected. Please update your browser"); } - else { - ids = []; + catch (err) { } +} - return ids; -}; - -/** - * Event listener. Will propagate all events from the connected data set to - * the subscribers of the DataView, but will filter the items and only trigger - * when there are changes in the filtered data set. - * @param {String} event - * @param {Object | null} params - * @param {String} senderId - * @private - */ -DataView.prototype._onEvent = function (event, params, senderId) { - var i, len, id, item, - ids = params && params.items, - data = this.data, - added = [], - updated = [], - removed = []; - - if (ids && data) { - switch (event) { - case 'add': - // filter the ids of the added items - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - item = this.get(id); - if (item) { - this.ids[id] = true; - added.push(id); - } - } +// Internet Explorer 8 and older does not support Array.forEach, so we define +// it here in that case. +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach +if (!Array.prototype.forEach) { + Array.prototype.forEach = function(fn, scope) { + for(var i = 0, len = this.length; i < len; ++i) { + fn.call(scope || this, this[i], i, this); + } + } +} - break; +// Internet Explorer 8 and older does not support Array.map, so we define it +// here in that case. +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/map +// Production steps of ECMA-262, Edition 5, 15.4.4.19 +// Reference: http://es5.github.com/#x15.4.4.19 +if (!Array.prototype.map) { + Array.prototype.map = function(callback, thisArg) { - case 'update': - // determine the event from the views viewpoint: an updated - // item can be added, updated, or removed from this view. - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - item = this.get(id); + var T, A, k; - if (item) { - if (this.ids[id]) { - updated.push(id); - } - else { - this.ids[id] = true; - added.push(id); - } - } - else { - if (this.ids[id]) { - delete this.ids[id]; - removed.push(id); - } - else { - // nothing interesting for me :-( - } - } - } + if (this == null) { + throw new TypeError(" this is null or not defined"); + } - break; + // 1. Let O be the result of calling ToObject passing the |this| value as the argument. + var O = Object(this); - case 'remove': - // filter the ids of the removed items - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - if (this.ids[id]) { - delete this.ids[id]; - removed.push(id); - } - } + // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length". + // 3. Let len be ToUint32(lenValue). + var len = O.length >>> 0; - break; + // 4. If IsCallable(callback) is false, throw a TypeError exception. + // See: http://es5.github.com/#x9.11 + if (typeof callback !== "function") { + throw new TypeError(callback + " is not a function"); } - if (added.length) { - this._trigger('add', {items: added}, senderId); - } - if (updated.length) { - this._trigger('update', {items: updated}, senderId); - } - if (removed.length) { - this._trigger('remove', {items: removed}, senderId); + // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. + if (thisArg) { + T = thisArg; } - } -}; -// copy subscription functionality from DataSet -DataView.prototype.subscribe = DataSet.prototype.subscribe; -DataView.prototype.unsubscribe = DataSet.prototype.unsubscribe; -DataView.prototype._trigger = DataSet.prototype._trigger; + // 6. Let A be a new array created as if by the expression new Array(len) where Array is + // the standard built-in constructor with that name and len is the value of len. + A = new Array(len); -/** - * @constructor TimeStep - * The class TimeStep is an iterator for dates. You provide a start date and an - * end date. The class itself determines the best scale (step size) based on the - * provided start Date, end Date, and minimumStep. - * - * If minimumStep is provided, the step size is chosen as close as possible - * to the minimumStep but larger than minimumStep. If minimumStep is not - * provided, the scale is set to 1 DAY. - * The minimumStep should correspond with the onscreen size of about 6 characters - * - * Alternatively, you can set a scale by hand. - * After creation, you can initialize the class by executing first(). Then you - * can iterate from the start date to the end date via next(). You can check if - * the end date is reached with the function hasNext(). After each step, you can - * retrieve the current date via getCurrent(). - * The TimeStep has scales ranging from milliseconds, seconds, minutes, hours, - * days, to years. - * - * Version: 1.2 - * - * @param {Date} [start] The start date, for example new Date(2010, 9, 21) - * or new Date(2010, 9, 21, 23, 45, 00) - * @param {Date} [end] The end date - * @param {Number} [minimumStep] Optional. Minimum step size in milliseconds - */ -TimeStep = function(start, end, minimumStep) { - // variables - this.current = new Date(); - this._start = new Date(); - this._end = new Date(); + // 7. Let k be 0 + k = 0; + + // 8. Repeat, while k < len + while(k < len) { + + var kValue, mappedValue; + + // a. Let Pk be ToString(k). + // This is implicit for LHS operands of the in operator + // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk. + // This step can be combined with c + // c. If kPresent is true, then + if (k in O) { + + // i. Let kValue be the result of calling the Get internal method of O with argument Pk. + kValue = O[ k ]; + + // ii. Let mappedValue be the result of calling the Call internal method of callback + // with T as the this value and argument list containing kValue, k, and O. + mappedValue = callback.call(T, kValue, k, O); + + // iii. Call the DefineOwnProperty internal method of A with arguments + // Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true}, + // and false. - this.autoScale = true; - this.scale = TimeStep.SCALE.DAY; - this.step = 1; + // In browsers that support Object.defineProperty, use the following: + // Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true }); - // initialize the range - this.setRange(start, end, minimumStep); -}; + // For best browser support, use the following: + A[ k ] = mappedValue; + } + // d. Increase k by 1. + k++; + } -/// enum scale -TimeStep.SCALE = { - MILLISECOND: 1, - SECOND: 2, - MINUTE: 3, - HOUR: 4, - DAY: 5, - WEEKDAY: 6, - MONTH: 7, - YEAR: 8 -}; + // 9. return A + return A; + }; +} +// Internet Explorer 8 and older does not support Array.filter, so we define it +// here in that case. +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/filter +if (!Array.prototype.filter) { + Array.prototype.filter = function(fun /*, thisp */) { + "use strict"; -/** - * Set a new range - * If minimumStep is provided, the step size is chosen as close as possible - * to the minimumStep but larger than minimumStep. If minimumStep is not - * provided, the scale is set to 1 DAY. - * The minimumStep should correspond with the onscreen size of about 6 characters - * @param {Date} [start] The start date and time. - * @param {Date} [end] The end date and time. - * @param {int} [minimumStep] Optional. Minimum step size in milliseconds - */ -TimeStep.prototype.setRange = function(start, end, minimumStep) { - if (!(start instanceof Date) || !(end instanceof Date)) { - //throw "No legal start or end date in method setRange"; - return; - } + if (this == null) { + throw new TypeError(); + } - this._start = (start != undefined) ? new Date(start.valueOf()) : new Date(); - this._end = (end != undefined) ? new Date(end.valueOf()) : new Date(); + var t = Object(this); + var len = t.length >>> 0; + if (typeof fun != "function") { + throw new TypeError(); + } - if (this.autoScale) { - this.setMinimumStep(minimumStep); - } -}; + var res = []; + var thisp = arguments[1]; + for (var i = 0; i < len; i++) { + if (i in t) { + var val = t[i]; // in case fun mutates this + if (fun.call(thisp, val, i, t)) + res.push(val); + } + } -/** - * Set the range iterator to the start date. - */ -TimeStep.prototype.first = function() { - this.current = new Date(this._start.valueOf()); - this.roundToMinor(); -}; + return res; + }; +} -/** - * Round the current date to the first minor date value - * This must be executed once when the current date is set to start Date - */ -TimeStep.prototype.roundToMinor = function() { - // round to floor - // IMPORTANT: we have no breaks in this switch! (this is no bug) - //noinspection FallthroughInSwitchStatementJS - switch (this.scale) { - case TimeStep.SCALE.YEAR: - this.current.setFullYear(this.step * Math.floor(this.current.getFullYear() / this.step)); - this.current.setMonth(0); - case TimeStep.SCALE.MONTH: this.current.setDate(1); - case TimeStep.SCALE.DAY: // intentional fall through - case TimeStep.SCALE.WEEKDAY: this.current.setHours(0); - case TimeStep.SCALE.HOUR: this.current.setMinutes(0); - case TimeStep.SCALE.MINUTE: this.current.setSeconds(0); - case TimeStep.SCALE.SECOND: this.current.setMilliseconds(0); - //case TimeStep.SCALE.MILLISECOND: // nothing to do for milliseconds - } - if (this.step != 1) { - // round down to the first minor value that is a multiple of the current step size - switch (this.scale) { - case TimeStep.SCALE.MILLISECOND: this.current.setMilliseconds(this.current.getMilliseconds() - this.current.getMilliseconds() % this.step); break; - case TimeStep.SCALE.SECOND: this.current.setSeconds(this.current.getSeconds() - this.current.getSeconds() % this.step); break; - case TimeStep.SCALE.MINUTE: this.current.setMinutes(this.current.getMinutes() - this.current.getMinutes() % this.step); break; - case TimeStep.SCALE.HOUR: this.current.setHours(this.current.getHours() - this.current.getHours() % this.step); break; - case TimeStep.SCALE.WEEKDAY: // intentional fall through - case TimeStep.SCALE.DAY: this.current.setDate((this.current.getDate()-1) - (this.current.getDate()-1) % this.step + 1); break; - case TimeStep.SCALE.MONTH: this.current.setMonth(this.current.getMonth() - this.current.getMonth() % this.step); break; - case TimeStep.SCALE.YEAR: this.current.setFullYear(this.current.getFullYear() - this.current.getFullYear() % this.step); break; - default: break; - } - } -}; +// Internet Explorer 8 and older does not support Object.keys, so we define it +// here in that case. +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys +if (!Object.keys) { + Object.keys = (function () { + var hasOwnProperty = Object.prototype.hasOwnProperty, + hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), + dontEnums = [ + 'toString', + 'toLocaleString', + 'valueOf', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'constructor' + ], + dontEnumsLength = dontEnums.length; -/** - * Check if the there is a next step - * @return {boolean} true if the current date has not passed the end date - */ -TimeStep.prototype.hasNext = function () { - return (this.current.valueOf() <= this._end.valueOf()); -}; + return function (obj) { + if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) { + throw new TypeError('Object.keys called on non-object'); + } -/** - * Do the next step - */ -TimeStep.prototype.next = function() { - var prev = this.current.valueOf(); + var result = []; - // Two cases, needed to prevent issues with switching daylight savings - // (end of March and end of October) - if (this.current.getMonth() < 6) { - switch (this.scale) { - case TimeStep.SCALE.MILLISECOND: + for (var prop in obj) { + if (hasOwnProperty.call(obj, prop)) result.push(prop); + } - this.current = new Date(this.current.valueOf() + this.step); break; - case TimeStep.SCALE.SECOND: this.current = new Date(this.current.valueOf() + this.step * 1000); break; - case TimeStep.SCALE.MINUTE: this.current = new Date(this.current.valueOf() + this.step * 1000 * 60); break; - case TimeStep.SCALE.HOUR: - this.current = new Date(this.current.valueOf() + this.step * 1000 * 60 * 60); - // in case of skipping an hour for daylight savings, adjust the hour again (else you get: 0h 5h 9h ... instead of 0h 4h 8h ...) - var h = this.current.getHours(); - this.current.setHours(h - (h % this.step)); - break; - case TimeStep.SCALE.WEEKDAY: // intentional fall through - case TimeStep.SCALE.DAY: this.current.setDate(this.current.getDate() + this.step); break; - case TimeStep.SCALE.MONTH: this.current.setMonth(this.current.getMonth() + this.step); break; - case TimeStep.SCALE.YEAR: this.current.setFullYear(this.current.getFullYear() + this.step); break; - default: break; + if (hasDontEnumBug) { + for (var i=0; i < dontEnumsLength; i++) { + if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]); + } + } + return result; } - } - else { - switch (this.scale) { - case TimeStep.SCALE.MILLISECOND: this.current = new Date(this.current.valueOf() + this.step); break; - case TimeStep.SCALE.SECOND: this.current.setSeconds(this.current.getSeconds() + this.step); break; - case TimeStep.SCALE.MINUTE: this.current.setMinutes(this.current.getMinutes() + this.step); break; - case TimeStep.SCALE.HOUR: this.current.setHours(this.current.getHours() + this.step); break; - case TimeStep.SCALE.WEEKDAY: // intentional fall through - case TimeStep.SCALE.DAY: this.current.setDate(this.current.getDate() + this.step); break; - case TimeStep.SCALE.MONTH: this.current.setMonth(this.current.getMonth() + this.step); break; - case TimeStep.SCALE.YEAR: this.current.setFullYear(this.current.getFullYear() + this.step); break; - default: break; + })() +} + +// Internet Explorer 8 and older does not support Array.isArray, +// so we define it here in that case. +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/isArray +if(!Array.isArray) { + Array.isArray = function (vArg) { + return Object.prototype.toString.call(vArg) === "[object Array]"; + }; +} + +// Internet Explorer 8 and older does not support Function.bind, +// so we define it here in that case. +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind +if (!Function.prototype.bind) { + Function.prototype.bind = function (oThis) { + if (typeof this !== "function") { + // closest thing possible to the ECMAScript 5 internal IsCallable function + throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); } - } - if (this.step != 1) { - // round down to the correct major value - switch (this.scale) { - case TimeStep.SCALE.MILLISECOND: if(this.current.getMilliseconds() < this.step) this.current.setMilliseconds(0); break; - case TimeStep.SCALE.SECOND: if(this.current.getSeconds() < this.step) this.current.setSeconds(0); break; - case TimeStep.SCALE.MINUTE: if(this.current.getMinutes() < this.step) this.current.setMinutes(0); break; - case TimeStep.SCALE.HOUR: if(this.current.getHours() < this.step) this.current.setHours(0); break; - case TimeStep.SCALE.WEEKDAY: // intentional fall through - case TimeStep.SCALE.DAY: if(this.current.getDate() < this.step+1) this.current.setDate(1); break; - case TimeStep.SCALE.MONTH: if(this.current.getMonth() < this.step) this.current.setMonth(0); break; - case TimeStep.SCALE.YEAR: break; // nothing to do for year - default: break; + var aArgs = Array.prototype.slice.call(arguments, 1), + fToBind = this, + fNOP = function () {}, + fBound = function () { + return fToBind.apply(this instanceof fNOP && oThis + ? this + : oThis, + aArgs.concat(Array.prototype.slice.call(arguments))); + }; + + fNOP.prototype = this.prototype; + fBound.prototype = new fNOP(); + + return fBound; + }; +} + +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create +if (!Object.create) { + Object.create = function (o) { + if (arguments.length > 1) { + throw new Error('Object.create implementation only accepts the first parameter.'); + } + function F() {} + F.prototype = o; + return new F(); + }; +} + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind +if (!Function.prototype.bind) { + Function.prototype.bind = function (oThis) { + if (typeof this !== "function") { + // closest thing possible to the ECMAScript 5 internal IsCallable function + throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); } - } - // safety mechanism: if current time is still unchanged, move to the end - if (this.current.valueOf() == prev) { - this.current = new Date(this._end.valueOf()); - } -}; + var aArgs = Array.prototype.slice.call(arguments, 1), + fToBind = this, + fNOP = function () {}, + fBound = function () { + return fToBind.apply(this instanceof fNOP && oThis + ? this + : oThis, + aArgs.concat(Array.prototype.slice.call(arguments))); + }; + + fNOP.prototype = this.prototype; + fBound.prototype = new fNOP(); + return fBound; + }; +} /** - * Get the current datetime - * @return {Date} current The current date + * utility functions */ -TimeStep.prototype.getCurrent = function() { - return this.current; -}; +var util = {}; /** - * Set a custom scale. Autoscaling will be disabled. - * For example setScale(SCALE.MINUTES, 5) will result - * in minor steps of 5 minutes, and major steps of an hour. - * - * @param {TimeStep.SCALE} newScale - * A scale. Choose from SCALE.MILLISECOND, - * SCALE.SECOND, SCALE.MINUTE, SCALE.HOUR, - * SCALE.WEEKDAY, SCALE.DAY, SCALE.MONTH, - * SCALE.YEAR. - * @param {Number} newStep A step size, by default 1. Choose for - * example 1, 2, 5, or 10. + * Test whether given object is a number + * @param {*} object + * @return {Boolean} isNumber */ -TimeStep.prototype.setScale = function(newScale, newStep) { - this.scale = newScale; - - if (newStep > 0) { - this.step = newStep; - } - - this.autoScale = false; +util.isNumber = function isNumber(object) { + return (object instanceof Number || typeof object == 'number'); }; /** - * Enable or disable autoscaling - * @param {boolean} enable If true, autoascaling is set true + * Test whether given object is a string + * @param {*} object + * @return {Boolean} isString */ -TimeStep.prototype.setAutoScale = function (enable) { - this.autoScale = enable; +util.isString = function isString(object) { + return (object instanceof String || typeof object == 'string'); }; - /** - * Automatically determine the scale that bests fits the provided minimum step - * @param {Number} [minimumStep] The minimum step size in milliseconds + * Test whether given object is a Date, or a String containing a Date + * @param {Date | String} object + * @return {Boolean} isDate */ -TimeStep.prototype.setMinimumStep = function(minimumStep) { - if (minimumStep == undefined) { - return; +util.isDate = function isDate(object) { + if (object instanceof Date) { + return true; + } + else if (util.isString(object)) { + // test whether this string contains a date + var match = ASPDateRegex.exec(object); + if (match) { + return true; + } + else if (!isNaN(Date.parse(object))) { + return true; + } } - var stepYear = (1000 * 60 * 60 * 24 * 30 * 12); - var stepMonth = (1000 * 60 * 60 * 24 * 30); - var stepDay = (1000 * 60 * 60 * 24); - var stepHour = (1000 * 60 * 60); - var stepMinute = (1000 * 60); - var stepSecond = (1000); - var stepMillisecond= (1); - - // find the smallest step that is larger than the provided minimumStep - if (stepYear*1000 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 1000;} - if (stepYear*500 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 500;} - if (stepYear*100 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 100;} - if (stepYear*50 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 50;} - if (stepYear*10 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 10;} - if (stepYear*5 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 5;} - if (stepYear > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 1;} - if (stepMonth*3 > minimumStep) {this.scale = TimeStep.SCALE.MONTH; this.step = 3;} - if (stepMonth > minimumStep) {this.scale = TimeStep.SCALE.MONTH; this.step = 1;} - if (stepDay*5 > minimumStep) {this.scale = TimeStep.SCALE.DAY; this.step = 5;} - if (stepDay*2 > minimumStep) {this.scale = TimeStep.SCALE.DAY; this.step = 2;} - if (stepDay > minimumStep) {this.scale = TimeStep.SCALE.DAY; this.step = 1;} - if (stepDay/2 > minimumStep) {this.scale = TimeStep.SCALE.WEEKDAY; this.step = 1;} - if (stepHour*4 > minimumStep) {this.scale = TimeStep.SCALE.HOUR; this.step = 4;} - if (stepHour > minimumStep) {this.scale = TimeStep.SCALE.HOUR; this.step = 1;} - if (stepMinute*15 > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 15;} - if (stepMinute*10 > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 10;} - if (stepMinute*5 > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 5;} - if (stepMinute > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 1;} - if (stepSecond*15 > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 15;} - if (stepSecond*10 > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 10;} - if (stepSecond*5 > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 5;} - if (stepSecond > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 1;} - if (stepMillisecond*200 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 200;} - if (stepMillisecond*100 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 100;} - if (stepMillisecond*50 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 50;} - if (stepMillisecond*10 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 10;} - if (stepMillisecond*5 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 5;} - if (stepMillisecond > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 1;} + return false; }; /** - * Snap a date to a rounded value. The snap intervals are dependent on the - * current scale and step. - * @param {Date} date the date to be snapped + * Test whether given object is an instance of google.visualization.DataTable + * @param {*} object + * @return {Boolean} isDataTable */ -TimeStep.prototype.snap = function(date) { - if (this.scale == TimeStep.SCALE.YEAR) { - var year = date.getFullYear() + Math.round(date.getMonth() / 12); - date.setFullYear(Math.round(year / this.step) * this.step); - date.setMonth(0); - date.setDate(0); - date.setHours(0); - date.setMinutes(0); - date.setSeconds(0); - date.setMilliseconds(0); - } - else if (this.scale == TimeStep.SCALE.MONTH) { - if (date.getDate() > 15) { - date.setDate(1); - date.setMonth(date.getMonth() + 1); - // important: first set Date to 1, after that change the month. - } - else { - date.setDate(1); - } - - date.setHours(0); - date.setMinutes(0); - date.setSeconds(0); - date.setMilliseconds(0); - } - else if (this.scale == TimeStep.SCALE.DAY || - this.scale == TimeStep.SCALE.WEEKDAY) { - //noinspection FallthroughInSwitchStatementJS - switch (this.step) { - case 5: - case 2: - date.setHours(Math.round(date.getHours() / 24) * 24); break; - default: - date.setHours(Math.round(date.getHours() / 12) * 12); break; - } - date.setMinutes(0); - date.setSeconds(0); - date.setMilliseconds(0); - } - else if (this.scale == TimeStep.SCALE.HOUR) { - switch (this.step) { - case 4: - date.setMinutes(Math.round(date.getMinutes() / 60) * 60); break; - default: - date.setMinutes(Math.round(date.getMinutes() / 30) * 30); break; - } - date.setSeconds(0); - date.setMilliseconds(0); - } else if (this.scale == TimeStep.SCALE.MINUTE) { - //noinspection FallthroughInSwitchStatementJS - switch (this.step) { - case 15: - case 10: - date.setMinutes(Math.round(date.getMinutes() / 5) * 5); - date.setSeconds(0); - break; - case 5: - date.setSeconds(Math.round(date.getSeconds() / 60) * 60); break; - default: - date.setSeconds(Math.round(date.getSeconds() / 30) * 30); break; - } - date.setMilliseconds(0); - } - else if (this.scale == TimeStep.SCALE.SECOND) { - //noinspection FallthroughInSwitchStatementJS - switch (this.step) { - case 15: - case 10: - date.setSeconds(Math.round(date.getSeconds() / 5) * 5); - date.setMilliseconds(0); - break; - case 5: - date.setMilliseconds(Math.round(date.getMilliseconds() / 1000) * 1000); break; - default: - date.setMilliseconds(Math.round(date.getMilliseconds() / 500) * 500); break; - } - } - else if (this.scale == TimeStep.SCALE.MILLISECOND) { - var step = this.step > 5 ? this.step / 2 : 1; - date.setMilliseconds(Math.round(date.getMilliseconds() / step) * step); - } +util.isDataTable = function isDataTable(object) { + return (typeof (google) !== 'undefined') && + (google.visualization) && + (google.visualization.DataTable) && + (object instanceof google.visualization.DataTable); }; /** - * Check if the current value is a major value (for example when the step - * is DAY, a major value is each first day of the MONTH) - * @return {boolean} true if current date is major, else false. + * Create a semi UUID + * source: http://stackoverflow.com/a/105074/1262753 + * @return {String} uuid */ -TimeStep.prototype.isMajor = function() { - switch (this.scale) { - case TimeStep.SCALE.MILLISECOND: - return (this.current.getMilliseconds() == 0); - case TimeStep.SCALE.SECOND: - return (this.current.getSeconds() == 0); - case TimeStep.SCALE.MINUTE: - return (this.current.getHours() == 0) && (this.current.getMinutes() == 0); - // Note: this is no bug. Major label is equal for both minute and hour scale - case TimeStep.SCALE.HOUR: - return (this.current.getHours() == 0); - case TimeStep.SCALE.WEEKDAY: // intentional fall through - case TimeStep.SCALE.DAY: - return (this.current.getDate() == 1); - case TimeStep.SCALE.MONTH: - return (this.current.getMonth() == 0); - case TimeStep.SCALE.YEAR: - return false; - default: - return false; - } +util.randomUUID = function randomUUID () { + var S4 = function () { + return Math.floor( + Math.random() * 0x10000 /* 65536 */ + ).toString(16); + }; + + return ( + S4() + S4() + '-' + + S4() + '-' + + S4() + '-' + + S4() + '-' + + S4() + S4() + S4() + ); }; - /** - * Returns formatted text for the minor axislabel, depending on the current - * date and the scale. For example when scale is MINUTE, the current time is - * formatted as "hh:mm". - * @param {Date} [date] custom date. if not provided, current date is taken + * Extend object a with the properties of object b or a series of objects + * Only properties with defined values are copied + * @param {Object} a + * @param {... Object} b + * @return {Object} a */ -TimeStep.prototype.getLabelMinor = function(date) { - if (date == undefined) { - date = this.current; +util.extend = function (a, b) { + for (var i = 1, len = arguments.length; i < len; i++) { + var other = arguments[i]; + for (var prop in other) { + if (other.hasOwnProperty(prop) && other[prop] !== undefined) { + a[prop] = other[prop]; + } + } } - switch (this.scale) { - case TimeStep.SCALE.MILLISECOND: return moment(date).format('SSS'); - case TimeStep.SCALE.SECOND: return moment(date).format('s'); - case TimeStep.SCALE.MINUTE: return moment(date).format('HH:mm'); - case TimeStep.SCALE.HOUR: return moment(date).format('HH:mm'); - case TimeStep.SCALE.WEEKDAY: return moment(date).format('ddd D'); - case TimeStep.SCALE.DAY: return moment(date).format('D'); - case TimeStep.SCALE.MONTH: return moment(date).format('MMM'); - case TimeStep.SCALE.YEAR: return moment(date).format('YYYY'); - default: return ''; - } + return a; }; - /** - * Returns formatted text for the major axis label, depending on the current - * date and the scale. For example when scale is MINUTE, the major scale is - * hours, and the hour will be formatted as "hh". - * @param {Date} [date] custom date. if not provided, current date is taken + * Convert an object to another type + * @param {Boolean | Number | String | Date | Moment | Null | undefined} object + * @param {String | undefined} type Name of the type. Available types: + * 'Boolean', 'Number', 'String', + * 'Date', 'Moment', ISODate', 'ASPDate'. + * @return {*} object + * @throws Error */ -TimeStep.prototype.getLabelMajor = function(date) { - if (date == undefined) { - date = this.current; +util.convert = function convert(object, type) { + var match; + + if (object === undefined) { + return undefined; + } + if (object === null) { + return null; } - //noinspection FallthroughInSwitchStatementJS - switch (this.scale) { - case TimeStep.SCALE.MILLISECOND:return moment(date).format('HH:mm:ss'); - case TimeStep.SCALE.SECOND: return moment(date).format('D MMMM HH:mm'); - case TimeStep.SCALE.MINUTE: - case TimeStep.SCALE.HOUR: return moment(date).format('ddd D MMMM'); - case TimeStep.SCALE.WEEKDAY: - case TimeStep.SCALE.DAY: return moment(date).format('MMMM YYYY'); - case TimeStep.SCALE.MONTH: return moment(date).format('YYYY'); - case TimeStep.SCALE.YEAR: return ''; - default: return ''; + if (!type) { + return object; + } + if (!(typeof type === 'string') && !(type instanceof String)) { + throw new Error('Type must be a string'); } -}; -/** - * @constructor Stack - * Stacks items on top of each other. - * @param {ItemSet} parent - * @param {Object} [options] - */ -function Stack (parent, options) { - this.parent = parent; + //noinspection FallthroughInSwitchStatementJS + switch (type) { + case 'boolean': + case 'Boolean': + return Boolean(object); - this.options = options || {}; - this.defaultOptions = { - order: function (a, b) { - //return (b.width - a.width) || (a.left - b.left); // TODO: cleanup - // Order: ranges over non-ranges, ranged ordered by width, and - // lastly ordered by start. - if (a instanceof ItemRange) { - if (b instanceof ItemRange) { - var aInt = (a.data.end - a.data.start); - var bInt = (b.data.end - b.data.start); - return (aInt - bInt) || (a.data.start - b.data.start); + case 'number': + case 'Number': + return Number(object.valueOf()); + + case 'string': + case 'String': + return String(object); + + case 'Date': + if (util.isNumber(object)) { + return new Date(object); + } + if (object instanceof Date) { + return new Date(object.valueOf()); + } + else if (moment.isMoment(object)) { + return new Date(object.valueOf()); + } + if (util.isString(object)) { + match = ASPDateRegex.exec(object); + if (match) { + // object is an ASP date + return new Date(Number(match[1])); // parse number } else { - return -1; + return moment(object).toDate(); // parse string } } else { - if (b instanceof ItemRange) { - return 1; + throw new Error( + 'Cannot convert object of type ' + util.getType(object) + + ' to type Date'); + } + + case 'Moment': + if (util.isNumber(object)) { + return moment(object); + } + if (object instanceof Date) { + return moment(object.valueOf()); + } + else if (moment.isMoment(object)) { + return moment.clone(); + } + if (util.isString(object)) { + match = ASPDateRegex.exec(object); + if (match) { + // object is an ASP date + return moment(Number(match[1])); // parse number } else { - return (a.data.start - b.data.start); + return moment(object); // parse string } } - }, - margin: { - item: 10 + else { + throw new Error( + 'Cannot convert object of type ' + util.getType(object) + + ' to type Date'); + } + + case 'ISODate': + if (util.isNumber(object)) { + return new Date(object); + } + else if (object instanceof Date) { + return object.toISOString(); + } + else if (moment.isMoment(object)) { + return object.toDate().toISOString(); + } + else if (util.isString(object)) { + match = ASPDateRegex.exec(object); + if (match) { + // object is an ASP date + return new Date(Number(match[1])).toISOString(); // parse number + } + else { + return new Date(object).toISOString(); // parse string + } + } + else { + throw new Error( + 'Cannot convert object of type ' + util.getType(object) + + ' to type ISODate'); + } + + case 'ASPDate': + if (util.isNumber(object)) { + return '/Date(' + object + ')/'; + } + else if (object instanceof Date) { + return '/Date(' + object.valueOf() + ')/'; + } + else if (util.isString(object)) { + match = ASPDateRegex.exec(object); + var value; + if (match) { + // object is an ASP date + value = new Date(Number(match[1])).valueOf(); // parse number + } + else { + value = new Date(object).valueOf(); // parse string + } + return '/Date(' + value + ')/'; + } + else { + throw new Error( + 'Cannot convert object of type ' + util.getType(object) + + ' to type ASPDate'); + } + + default: + throw new Error('Cannot convert object of type ' + util.getType(object) + + ' to type "' + type + '"'); + } +}; + +// parse ASP.Net Date pattern, +// for example '/Date(1198908717056)/' or '/Date(1198908717056-0700)/' +// code from http://momentjs.com/ +var ASPDateRegex = /^\/?Date\((\-?\d+)/i; + +/** + * Get the type of an object, for example util.getType([]) returns 'Array' + * @param {*} object + * @return {String} type + */ +util.getType = function getType(object) { + var type = typeof object; + + if (type == 'object') { + if (object == null) { + return 'null'; } - }; + if (object instanceof Boolean) { + return 'Boolean'; + } + if (object instanceof Number) { + return 'Number'; + } + if (object instanceof String) { + return 'String'; + } + if (object instanceof Array) { + return 'Array'; + } + if (object instanceof Date) { + return 'Date'; + } + return 'Object'; + } + else if (type == 'number') { + return 'Number'; + } + else if (type == 'boolean') { + return 'Boolean'; + } + else if (type == 'string') { + return 'String'; + } - this.ordered = []; // ordered items -} + return type; +}; /** - * Set options for the stack - * @param {Object} options Available options: - * {ItemSet} parent - * {Number} margin - * {function} order Stacking order + * Retrieve the absolute left value of a DOM element + * @param {Element} elem A dom element, for example a div + * @return {number} left The absolute left position of this element + * in the browser page. */ -Stack.prototype.setOptions = function setOptions (options) { - util.extend(this.options, options); +util.getAbsoluteLeft = function getAbsoluteLeft (elem) { + var doc = document.documentElement; + var body = document.body; - // TODO: register on data changes at the connected parent itemset, and update the changed part only and immediately + var left = elem.offsetLeft; + var e = elem.offsetParent; + while (e != null && e != body && e != doc) { + left += e.offsetLeft; + left -= e.scrollLeft; + e = e.offsetParent; + } + return left; }; /** - * Stack the items such that they don't overlap. The items will have a minimal - * distance equal to options.margin.item. + * Retrieve the absolute top value of a DOM element + * @param {Element} elem A dom element, for example a div + * @return {number} top The absolute top position of this element + * in the browser page. */ -Stack.prototype.update = function update() { - this._order(); - this._stack(); +util.getAbsoluteTop = function getAbsoluteTop (elem) { + var doc = document.documentElement; + var body = document.body; + + var top = elem.offsetTop; + var e = elem.offsetParent; + while (e != null && e != body && e != doc) { + top += e.offsetTop; + top -= e.scrollTop; + e = e.offsetParent; + } + return top; }; /** - * Order the items. The items are ordered by width first, and by left position - * second. - * If a custom order function has been provided via the options, then this will - * be used. - * @private + * Get the absolute, vertical mouse position from an event. + * @param {Event} event + * @return {Number} pageY */ -Stack.prototype._order = function _order () { - var items = this.parent.items; - if (!items) { - throw new Error('Cannot stack items: parent does not contain items'); +util.getPageY = function getPageY (event) { + if ('pageY' in event) { + return event.pageY; } - - // TODO: store the sorted items, to have less work later on - var ordered = []; - var index = 0; - // items is a map (no array) - util.forEach(items, function (item) { - if (item.visible) { - ordered[index] = item; - index++; + else { + var clientY; + if (('targetTouches' in event) && event.targetTouches.length) { + clientY = event.targetTouches[0].clientY; + } + else { + clientY = event.clientY; } - }); - //if a customer stack order function exists, use it. - var order = this.options.order || this.defaultOptions.order; - if (!(typeof order === 'function')) { - throw new Error('Option order must be a function'); + var doc = document.documentElement; + var body = document.body; + return clientY + + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - + ( doc && doc.clientTop || body && body.clientTop || 0 ); } - - ordered.sort(order); - - this.ordered = ordered; }; /** - * Adjust vertical positions of the events such that they don't overlap each - * other. - * @private + * Get the absolute, horizontal mouse position from an event. + * @param {Event} event + * @return {Number} pageX */ -Stack.prototype._stack = function _stack () { - var i, - iMax, - ordered = this.ordered, - options = this.options, - orientation = options.orientation || this.defaultOptions.orientation, - axisOnTop = (orientation == 'top'), - margin; - - if (options.margin && options.margin.item !== undefined) { - margin = options.margin.item; +util.getPageX = function getPageX (event) { + if ('pageY' in event) { + return event.pageX; } else { - margin = this.defaultOptions.margin.item - } + var clientX; + if (('targetTouches' in event) && event.targetTouches.length) { + clientX = event.targetTouches[0].clientX; + } + else { + clientX = event.clientX; + } - // calculate new, non-overlapping positions - for (i = 0, iMax = ordered.length; i < iMax; i++) { - var item = ordered[i]; - var collidingItem = null; - do { - // TODO: optimize checking for overlap. when there is a gap without items, - // you only need to check for items from the next item on, not from zero - collidingItem = this.checkOverlap(ordered, i, 0, i - 1, margin); - if (collidingItem != null) { - // There is a collision. Reposition the event above the colliding element - if (axisOnTop) { - item.top = collidingItem.top + collidingItem.height + margin; - } - else { - item.top = collidingItem.top - item.height - margin; - } - } - } while (collidingItem); + var doc = document.documentElement; + var body = document.body; + return clientX + + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - + ( doc && doc.clientLeft || body && body.clientLeft || 0 ); } }; /** - * Check if the destiny position of given item overlaps with any - * of the other items from index itemStart to itemEnd. - * @param {Array} items Array with items - * @param {int} itemIndex Number of the item to be checked for overlap - * @param {int} itemStart First item to be checked. - * @param {int} itemEnd Last item to be checked. - * @return {Object | null} colliding item, or undefined when no collisions - * @param {Number} margin A minimum required margin. - * If margin is provided, the two items will be - * marked colliding when they overlap or - * when the margin between the two is smaller than - * the requested margin. + * add a className to the given elements style + * @param {Element} elem + * @param {String} className */ -Stack.prototype.checkOverlap = function checkOverlap (items, itemIndex, - itemStart, itemEnd, margin) { - var collision = this.collision; - - // we loop from end to start, as we suppose that the chance of a - // collision is larger for items at the end, so check these first. - var a = items[itemIndex]; - for (var i = itemEnd; i >= itemStart; i--) { - var b = items[i]; - if (collision(a, b, margin)) { - if (i != itemIndex) { - return b; - } - } +util.addClassName = function addClassName(elem, className) { + var classes = elem.className.split(' '); + if (classes.indexOf(className) == -1) { + classes.push(className); // add the class to the array + elem.className = classes.join(' '); } +}; - return null; +/** + * add a className to the given elements style + * @param {Element} elem + * @param {String} className + */ +util.removeClassName = function removeClassname(elem, className) { + var classes = elem.className.split(' '); + var index = classes.indexOf(className); + if (index != -1) { + classes.splice(index, 1); // remove the class from the array + elem.className = classes.join(' '); + } }; /** - * Test if the two provided items collide - * The items must have parameters left, width, top, and height. - * @param {Component} a The first item - * @param {Component} b The second item - * @param {Number} margin A minimum required margin. - * If margin is provided, the two items will be - * marked colliding when they overlap or - * when the margin between the two is smaller than - * the requested margin. - * @return {boolean} true if a and b collide, else false + * For each method for both arrays and objects. + * In case of an array, the built-in Array.forEach() is applied. + * In case of an Object, the method loops over all properties of the object. + * @param {Object | Array} object An Object or Array + * @param {function} callback Callback method, called for each item in + * the object or array with three parameters: + * callback(value, index, object) */ -Stack.prototype.collision = function collision (a, b, margin) { - return ((a.left - margin) < (b.left + b.width) && - (a.left + a.width + margin) > b.left && - (a.top - margin) < (b.top + b.height) && - (a.top + a.height + margin) > b.top); +util.forEach = function forEach (object, callback) { + var i, + len; + if (object instanceof Array) { + // array + for (i = 0, len = object.length; i < len; i++) { + callback(object[i], i, object); + } + } + else { + // object + for (i in object) { + if (object.hasOwnProperty(i)) { + callback(object[i], i, object); + } + } + } }; /** - * @constructor Range - * A Range controls a numeric range with a start and end value. - * The Range adjusts the range based on mouse events or programmatic changes, - * and triggers events when the range is changing or has been changed. - * @param {Object} [options] See description at Range.setOptions - * @extends Controller + * Update a property in an object + * @param {Object} object + * @param {String} key + * @param {*} value + * @return {Boolean} changed */ -function Range(options) { - this.id = util.randomUUID(); - this.start = 0; // Number - this.end = 0; // Number +util.updateProperty = function updateProp (object, key, value) { + if (object[key] !== value) { + object[key] = value; + return true; + } + else { + return false; + } +}; - this.options = { - min: null, - max: null, - zoomMin: null, - zoomMax: null - }; +/** + * Add and event listener. Works for all browsers + * @param {Element} element An html element + * @param {string} action The action, for example "click", + * without the prefix "on" + * @param {function} listener The callback function to be executed + * @param {boolean} [useCapture] + */ +util.addEventListener = function addEventListener(element, action, listener, useCapture) { + if (element.addEventListener) { + if (useCapture === undefined) + useCapture = false; - this.listeners = []; + if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) { + action = "DOMMouseScroll"; // For Firefox + } - this.setOptions(options); -} + element.addEventListener(action, listener, useCapture); + } else { + element.attachEvent("on" + action, listener); // IE browsers + } +}; /** - * Set options for the range controller - * @param {Object} options Available options: - * {Number} start Set start value of the range - * {Number} end Set end value of the range - * {Number} min Minimum value for start - * {Number} max Maximum value for end - * {Number} zoomMin Set a minimum value for - * (end - start). - * {Number} zoomMax Set a maximum value for - * (end - start). + * Remove an event listener from an element + * @param {Element} element An html dom element + * @param {string} action The name of the event, for example "mousedown" + * @param {function} listener The listener function + * @param {boolean} [useCapture] */ -Range.prototype.setOptions = function (options) { - util.extend(this.options, options); +util.removeEventListener = function removeEventListener(element, action, listener, useCapture) { + if (element.removeEventListener) { + // non-IE browsers + if (useCapture === undefined) + useCapture = false; - if (options.start != null || options.end != null) { - this.setRange(options.start, options.end); + if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) { + action = "DOMMouseScroll"; // For Firefox + } + + element.removeEventListener(action, listener, useCapture); + } else { + // IE browsers + element.detachEvent("on" + action, listener); } }; + /** - * Add listeners for mouse and touch events to the component - * @param {Component} component - * @param {String} event Available events: 'move', 'zoom' - * @param {String} direction Available directions: 'horizontal', 'vertical' + * Get HTML element which is the target of the event + * @param {Event} event + * @return {Element} target element */ -Range.prototype.subscribe = function (component, event, direction) { - var me = this; - var listener; - - if (direction != 'horizontal' && direction != 'vertical') { - throw new TypeError('Unknown direction "' + direction + '". ' + - 'Choose "horizontal" or "vertical".'); +util.getTarget = function getTarget(event) { + // code from http://www.quirksmode.org/js/events_properties.html + if (!event) { + event = window.event; } - //noinspection FallthroughInSwitchStatementJS - if (event == 'move') { - listener = { - component: component, - event: event, - direction: direction, - callback: function (event) { - me._onMouseDown(event, listener); - }, - params: {} - }; + var target; - component.on('mousedown', listener.callback); - me.listeners.push(listener); + if (event.target) { + target = event.target; } - else if (event == 'zoom') { - listener = { - component: component, - event: event, - direction: direction, - callback: function (event) { - me._onMouseWheel(event, listener); - }, - params: {} - }; - - component.on('mousewheel', listener.callback); - me.listeners.push(listener); + else if (event.srcElement) { + target = event.srcElement; } - else { - throw new TypeError('Unknown event "' + event + '". ' + - 'Choose "move" or "zoom".'); + + if (target.nodeType != undefined && target.nodeType == 3) { + // defeat Safari bug + target = target.parentNode; } -}; -/** - * Event handler - * @param {String} event name of the event, for example 'click', 'mousemove' - * @param {function} callback callback handler, invoked with the raw HTML Event - * as parameter. - */ -Range.prototype.on = function (event, callback) { - events.addListener(this, event, callback); + return target; }; /** - * Trigger an event - * @param {String} event name of the event, available events: 'rangechange', - * 'rangechanged' - * @private + * Stop event propagation */ -Range.prototype._trigger = function (event) { - events.trigger(this, event, { - start: this.start, - end: this.end - }); -}; +util.stopPropagation = function stopPropagation(event) { + if (!event) + event = window.event; -/** - * Set a new start and end range - * @param {Number} start - * @param {Number} end - */ -Range.prototype.setRange = function(start, end) { - var changed = this._applyRange(start, end); - if (changed) { - this._trigger('rangechange'); - this._trigger('rangechanged'); + if (event.stopPropagation) { + event.stopPropagation(); // non-IE browsers + } + else { + event.cancelBubble = true; // IE browsers } }; + /** - * Set a new start and end range. This method is the same as setRange, but - * does not trigger a range change and range changed event, and it returns - * true when the range is changed - * @param {Number} start - * @param {Number} end - * @return {Boolean} changed - * @private + * Cancels the event if it is cancelable, without stopping further propagation of the event. */ -Range.prototype._applyRange = function(start, end) { - var newStart = (start != null) ? util.convert(start, 'Number') : this.start; - var newEnd = (end != null) ? util.convert(end, 'Number') : this.end; - var diff; - - // check for valid number - if (isNaN(newStart)) { - throw new Error('Invalid start "' + start + '"'); - } - if (isNaN(newEnd)) { - throw new Error('Invalid end "' + end + '"'); - } +util.preventDefault = function preventDefault (event) { + if (!event) + event = window.event; - // prevent start < end - if (newEnd < newStart) { - newEnd = newStart; + if (event.preventDefault) { + event.preventDefault(); // non-IE browsers } - - // prevent start < min - if (this.options.min != null) { - var min = this.options.min.valueOf(); - if (newStart < min) { - diff = (min - newStart); - newStart += diff; - newEnd += diff; - } + else { + event.returnValue = false; // IE browsers } +}; - // prevent end > max - if (this.options.max != null) { - var max = this.options.max.valueOf(); - if (newEnd > max) { - diff = (newEnd - max); - newStart -= diff; - newEnd -= diff; - } - } - // prevent (end-start) > zoomMin - if (this.options.zoomMin != null) { - var zoomMin = this.options.zoomMin.valueOf(); - if (zoomMin < 0) { - zoomMin = 0; - } - if ((newEnd - newStart) < zoomMin) { - if ((this.end - this.start) > zoomMin) { - // zoom to the minimum - diff = (zoomMin - (newEnd - newStart)); - newStart -= diff / 2; - newEnd += diff / 2; - } - else { - // ingore this action, we are already zoomed to the minimum - newStart = this.start; - newEnd = this.end; - } - } - } +util.option = {}; - // prevent (end-start) > zoomMin - if (this.options.zoomMax != null) { - var zoomMax = this.options.zoomMax.valueOf(); - if (zoomMax < 0) { - zoomMax = 0; - } - if ((newEnd - newStart) > zoomMax) { - if ((this.end - this.start) < zoomMax) { - // zoom to the maximum - diff = ((newEnd - newStart) - zoomMax); - newStart += diff / 2; - newEnd -= diff / 2; - } - else { - // ingore this action, we are already zoomed to the maximum - newStart = this.start; - newEnd = this.end; - } - } +/** + * Convert a value into a boolean + * @param {Boolean | function | undefined} value + * @param {Boolean} [defaultValue] + * @returns {Boolean} bool + */ +util.option.asBoolean = function (value, defaultValue) { + if (typeof value == 'function') { + value = value(); } - var changed = (this.start != newStart || this.end != newEnd); - - this.start = newStart; - this.end = newEnd; + if (value != null) { + return (value != false); + } - return changed; + return defaultValue || null; }; /** - * Retrieve the current range. - * @return {Object} An object with start and end properties + * Convert a value into a number + * @param {Boolean | function | undefined} value + * @param {Number} [defaultValue] + * @returns {Number} number */ -Range.prototype.getRange = function() { - return { - start: this.start, - end: this.end - }; +util.option.asNumber = function (value, defaultValue) { + if (typeof value == 'function') { + value = value(); + } + + if (value != null) { + return Number(value) || defaultValue || null; + } + + return defaultValue || null; }; /** - * Calculate the conversion offset and factor for current range, based on - * the provided width - * @param {Number} width - * @returns {{offset: number, factor: number}} conversion + * Convert a value into a string + * @param {String | function | undefined} value + * @param {String} [defaultValue] + * @returns {String} str */ -Range.prototype.conversion = function (width) { - var start = this.start; - var end = this.end; +util.option.asString = function (value, defaultValue) { + if (typeof value == 'function') { + value = value(); + } - return Range.conversion(this.start, this.end, width); + if (value != null) { + return String(value); + } + + return defaultValue || null; }; /** - * Static method to calculate the conversion offset and factor for a range, - * based on the provided start, end, and width - * @param {Number} start - * @param {Number} end - * @param {Number} width - * @returns {{offset: number, factor: number}} conversion + * Convert a size or location into a string with pixels or a percentage + * @param {String | Number | function | undefined} value + * @param {String} [defaultValue] + * @returns {String} size */ -Range.conversion = function (start, end, width) { - if (width != 0 && (end - start != 0)) { - return { - offset: start, - factor: width / (end - start) - } +util.option.asSize = function (value, defaultValue) { + if (typeof value == 'function') { + value = value(); + } + + if (util.isString(value)) { + return value; + } + else if (util.isNumber(value)) { + return value + 'px'; } else { - return { - offset: 0, - factor: 1 - }; + return defaultValue || null; } }; /** - * Start moving horizontally or vertically - * @param {Event} event - * @param {Object} listener Listener containing the component and params - * @private + * Convert a value into a DOM element + * @param {HTMLElement | function | undefined} value + * @param {HTMLElement} [defaultValue] + * @returns {HTMLElement | null} dom */ -Range.prototype._onMouseDown = function(event, listener) { - event = event || window.event; - var params = listener.params; +util.option.asElement = function (value, defaultValue) { + if (typeof value == 'function') { + value = value(); + } - // only react on left mouse button down - var leftButtonDown = event.which ? (event.which == 1) : (event.button == 1); - if (!leftButtonDown) { + return value || defaultValue || null; +}; + +/** + * load css from text + * @param {String} css Text containing css + */ +util.loadCss = function (css) { + if (typeof document === 'undefined') { return; } - // get mouse position - params.mouseX = util.getPageX(event); - params.mouseY = util.getPageY(event); - params.previousLeft = 0; - params.previousOffset = 0; - - params.moved = false; - params.start = this.start; - params.end = this.end; + // get the script location, and built the css file name from the js file name + // http://stackoverflow.com/a/2161748/1262753 + // var scripts = document.getElementsByTagName('script'); + // var jsFile = scripts[scripts.length-1].src.split('?')[0]; + // var cssFile = jsFile.substring(0, jsFile.length - 2) + 'css'; - var frame = listener.component.frame; - if (frame) { - frame.style.cursor = 'move'; + // inject css + // http://stackoverflow.com/questions/524696/how-to-create-a-style-tag-with-javascript + var style = document.createElement('style'); + style.type = 'text/css'; + if (style.styleSheet){ + style.styleSheet.cssText = css; + } else { + style.appendChild(document.createTextNode(css)); } - // add event listeners to handle moving the contents - // we store the function onmousemove and onmouseup in the timeaxis, - // so we can remove the eventlisteners lateron in the function onmouseup - var me = this; - if (!params.onMouseMove) { - params.onMouseMove = function (event) { - me._onMouseMove(event, listener); - }; - util.addEventListener(document, "mousemove", params.onMouseMove); - } - if (!params.onMouseUp) { - params.onMouseUp = function (event) { - me._onMouseUp(event, listener); - }; - util.addEventListener(document, "mouseup", params.onMouseUp); + document.getElementsByTagName('head')[0].appendChild(style); +}; + +/** + * Event listener (singleton) + */ +// TODO: replace usage of the event listener for the EventBus +var events = { + 'listeners': [], + + /** + * Find a single listener by its object + * @param {Object} object + * @return {Number} index -1 when not found + */ + 'indexOf': function (object) { + var listeners = this.listeners; + for (var i = 0, iMax = this.listeners.length; i < iMax; i++) { + var listener = listeners[i]; + if (listener && listener.object == object) { + return i; + } + } + return -1; + }, + + /** + * Add an event listener + * @param {Object} object + * @param {String} event The name of an event, for example 'select' + * @param {function} callback The callback method, called when the + * event takes place + */ + 'addListener': function (object, event, callback) { + var index = this.indexOf(object); + var listener = this.listeners[index]; + if (!listener) { + listener = { + 'object': object, + 'events': {} + }; + this.listeners.push(listener); + } + + var callbacks = listener.events[event]; + if (!callbacks) { + callbacks = []; + listener.events[event] = callbacks; + } + + // add the callback if it does not yet exist + if (callbacks.indexOf(callback) == -1) { + callbacks.push(callback); + } + }, + + /** + * Remove an event listener + * @param {Object} object + * @param {String} event The name of an event, for example 'select' + * @param {function} callback The registered callback method + */ + 'removeListener': function (object, event, callback) { + var index = this.indexOf(object); + var listener = this.listeners[index]; + if (listener) { + var callbacks = listener.events[event]; + if (callbacks) { + index = callbacks.indexOf(callback); + if (index != -1) { + callbacks.splice(index, 1); + } + + // remove the array when empty + if (callbacks.length == 0) { + delete listener.events[event]; + } + } + + // count the number of registered events. remove listener when empty + var count = 0; + var events = listener.events; + for (var e in events) { + if (events.hasOwnProperty(e)) { + count++; + } + } + if (count == 0) { + delete this.listeners[index]; + } + } + }, + + /** + * Remove all registered event listeners + */ + 'removeAllListeners': function () { + this.listeners = []; + }, + + /** + * Trigger an event. All registered event handlers will be called + * @param {Object} object + * @param {String} event + * @param {Object} properties (optional) + */ + 'trigger': function (object, event, properties) { + var index = this.indexOf(object); + var listener = this.listeners[index]; + if (listener) { + var callbacks = listener.events[event]; + if (callbacks) { + for (var i = 0, iMax = callbacks.length; i < iMax; i++) { + callbacks[i](properties); + } + } + } } - - util.preventDefault(event); }; /** - * Perform moving operating. - * This function activated from within the funcion TimeAxis._onMouseDown(). - * @param {Event} event - * @param {Object} listener - * @private + * An event bus can be used to emit events, and to subscribe to events + * @constructor EventBus */ -Range.prototype._onMouseMove = function (event, listener) { - event = event || window.event; - - var params = listener.params; - - // calculate change in mouse position - var mouseX = util.getPageX(event); - var mouseY = util.getPageY(event); - - if (params.mouseX == undefined) { - params.mouseX = mouseX; - } - if (params.mouseY == undefined) { - params.mouseY = mouseY; - } - - var diffX = mouseX - params.mouseX; - var diffY = mouseY - params.mouseY; - var diff = (listener.direction == 'horizontal') ? diffX : diffY; +function EventBus() { + this.subscriptions = []; +} - // if mouse movement is big enough, register it as a "moved" event - if (Math.abs(diff) >= 1) { - params.moved = true; - } +/** + * Subscribe to an event + * @param {String | RegExp} event The event can be a regular expression, or + * a string with wildcards, like 'server.*'. + * @param {function} callback. Callback are called with three parameters: + * {String} event, {*} [data], {*} [source] + * @param {*} [target] + * @returns {String} id A subscription id + */ +EventBus.prototype.on = function (event, callback, target) { + var regexp = (event instanceof RegExp) ? + event : + new RegExp(event.replace('*', '\\w+')); - var interval = (params.end - params.start); - var width = (listener.direction == 'horizontal') ? - listener.component.width : listener.component.height; - var diffRange = -diff / width * interval; - this._applyRange(params.start + diffRange, params.end + diffRange); + var subscription = { + id: util.randomUUID(), + event: event, + regexp: regexp, + callback: (typeof callback === 'function') ? callback : null, + target: target + }; - // fire a rangechange event - this._trigger('rangechange'); + this.subscriptions.push(subscription); - util.preventDefault(event); + return subscription.id; }; /** - * Stop moving operating. - * This function activated from within the function Range._onMouseDown(). - * @param {event} event - * @param {Object} listener - * @private + * Unsubscribe from an event + * @param {String | Object} filter Filter for subscriptions to be removed + * Filter can be a string containing a + * subscription id, or an object containing + * one or more of the fields id, event, + * callback, and target. */ -Range.prototype._onMouseUp = function (event, listener) { - event = event || window.event; - - var params = listener.params; +EventBus.prototype.off = function (filter) { + var i = 0; + while (i < this.subscriptions.length) { + var subscription = this.subscriptions[i]; - if (listener.component.frame) { - listener.component.frame.style.cursor = 'auto'; - } + var match = true; + if (filter instanceof Object) { + // filter is an object. All fields must match + for (var prop in filter) { + if (filter.hasOwnProperty(prop)) { + if (filter[prop] !== subscription[prop]) { + match = false; + } + } + } + } + else { + // filter is a string, filter on id + match = (subscription.id == filter); + } - // remove event listeners here, important for Safari - if (params.onMouseMove) { - util.removeEventListener(document, "mousemove", params.onMouseMove); - params.onMouseMove = null; - } - if (params.onMouseUp) { - util.removeEventListener(document, "mouseup", params.onMouseUp); - params.onMouseUp = null; + if (match) { + this.subscriptions.splice(i, 1); + } + else { + i++; + } } - //util.preventDefault(event); +}; - if (params.moved) { - // fire a rangechanged event - this._trigger('rangechanged'); +/** + * Emit an event + * @param {String} event + * @param {*} [data] + * @param {*} [source] + */ +EventBus.prototype.emit = function (event, data, source) { + for (var i =0; i < this.subscriptions.length; i++) { + var subscription = this.subscriptions[i]; + if (subscription.regexp.test(event)) { + if (subscription.callback) { + subscription.callback(event, data, source); + } + } } }; /** - * Event handler for mouse wheel event, used to zoom - * Code from http://adomas.org/javascript-mouse-wheel/ - * @param {Event} event - * @param {Object} listener - * @private + * DataSet + * + * Usage: + * var dataSet = new DataSet({ + * fieldId: '_id', + * convert: { + * // ... + * } + * }); + * + * dataSet.add(item); + * dataSet.add(data); + * dataSet.update(item); + * dataSet.update(data); + * dataSet.remove(id); + * dataSet.remove(ids); + * var data = dataSet.get(); + * var data = dataSet.get(id); + * var data = dataSet.get(ids); + * var data = dataSet.get(ids, options, data); + * dataSet.clear(); + * + * A data set can: + * - add/remove/update data + * - gives triggers upon changes in the data + * - can import/export data in various data formats + * + * @param {Object} [options] Available options: + * {String} fieldId Field name of the id in the + * items, 'id' by default. + * {Object.=end ) - if (zoomFactor >= 1) { - zoomFactor = 0.9; + var subscribers = []; + if (event in this.subscribers) { + subscribers = subscribers.concat(this.subscribers[event]); } - if (zoomFactor <= -1) { - zoomFactor = -0.9; + if ('*' in this.subscribers) { + subscribers = subscribers.concat(this.subscribers['*']); } - // adjust a negative factor such that zooming in with 0.1 equals zooming - // out with a factor -0.1 - if (zoomFactor < 0) { - zoomFactor = zoomFactor / (1 + zoomFactor); + for (var i = 0; i < subscribers.length; i++) { + var subscriber = subscribers[i]; + if (subscriber.callback) { + subscriber.callback(event, params, senderId || null); + } } +}; - // zoom start and end relative to the zoomAround value - var startDiff = (this.start - zoomAround); - var endDiff = (this.end - zoomAround); +/** + * Add data. + * Adding an item will fail when there already is an item with the same id. + * @param {Object | Array | DataTable} data + * @param {String} [senderId] Optional sender id + * @return {Array} addedIds Array with the ids of the added items + */ +DataSet.prototype.add = function (data, senderId) { + var addedIds = [], + id, + me = this; - // calculate new start and end - var newStart = this.start - startDiff * zoomFactor; - var newEnd = this.end - endDiff * zoomFactor; + if (data instanceof Array) { + // Array + for (var i = 0, len = data.length; i < len; i++) { + id = me._addItem(data[i]); + addedIds.push(id); + } + } + else if (util.isDataTable(data)) { + // Google DataTable + var columns = this._getColumnNames(data); + for (var row = 0, rows = data.getNumberOfRows(); row < rows; row++) { + var item = {}; + for (var col = 0, cols = columns.length; col < cols; col++) { + var field = columns[col]; + item[field] = data.getValue(row, col); + } - this.setRange(newStart, newEnd); + id = me._addItem(item); + addedIds.push(id); + } + } + else if (data instanceof Object) { + // Single item + id = me._addItem(data); + addedIds.push(id); + } + else { + throw new Error('Unknown dataType'); + } + + if (addedIds.length) { + this._trigger('add', {items: addedIds}, senderId); + } + + return addedIds; }; /** - * Move the range with a given factor to the left or right. Start and end - * value will be adjusted. For example, try moveFactor = 0.1 or -0.1 - * @param {Number} moveFactor Moving amount. Positive value will move right, - * negative value will move left + * Update existing items. When an item does not exist, it will be created + * @param {Object | Array | DataTable} data + * @param {String} [senderId] Optional sender id + * @return {Array} updatedIds The ids of the added or updated items */ -Range.prototype.move = function(moveFactor) { - // zoom start Date and end Date relative to the zoomAroundDate - var diff = (this.end - this.start); +DataSet.prototype.update = function (data, senderId) { + var addedIds = [], + updatedIds = [], + me = this, + fieldId = me.fieldId; - // apply new values - var newStart = this.start + diff * moveFactor; - var newEnd = this.end + diff * moveFactor; + var addOrUpdate = function (item) { + var id = item[fieldId]; + if (me.data[id]) { + // update item + id = me._updateItem(item); + updatedIds.push(id); + } + else { + // add new item + id = me._addItem(item); + addedIds.push(id); + } + }; - // TODO: reckon with min and max range + if (data instanceof Array) { + // Array + for (var i = 0, len = data.length; i < len; i++) { + addOrUpdate(data[i]); + } + } + else if (util.isDataTable(data)) { + // Google DataTable + var columns = this._getColumnNames(data); + for (var row = 0, rows = data.getNumberOfRows(); row < rows; row++) { + var item = {}; + for (var col = 0, cols = columns.length; col < cols; col++) { + var field = columns[col]; + item[field] = data.getValue(row, col); + } - this.start = newStart; - this.end = newEnd; + addOrUpdate(item); + } + } + else if (data instanceof Object) { + // Single item + addOrUpdate(data); + } + else { + throw new Error('Unknown dataType'); + } + + if (addedIds.length) { + this._trigger('add', {items: addedIds}, senderId); + } + if (updatedIds.length) { + this._trigger('update', {items: updatedIds}, senderId); + } + + return addedIds.concat(updatedIds); }; /** - * @constructor Controller + * Get a data item or multiple items. * - * A Controller controls the reflows and repaints of all visual components + * Usage: + * + * get() + * get(options: Object) + * get(options: Object, data: Array | DataTable) + * + * get(id: Number | String) + * get(id: Number | String, options: Object) + * get(id: Number | String, options: Object, data: Array | DataTable) + * + * get(ids: Number[] | String[]) + * get(ids: Number[] | String[], options: Object) + * get(ids: Number[] | String[], options: Object, data: Array | DataTable) + * + * Where: + * + * {Number | String} id The id of an item + * {Number[] | String{}} ids An array with ids of items + * {Object} options An Object with options. Available options: + * {String} [type] Type of data to be returned. Can + * be 'DataTable' or 'Array' (default) + * {Object.} [convert] + * {String[]} [fields] field names to be returned + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * {Array | DataTable} [data] If provided, items will be appended to this + * array or table. Required in case of Google + * DataTable. + * + * @throws Error */ -function Controller () { - this.id = util.randomUUID(); - this.components = {}; +DataSet.prototype.get = function (args) { + var me = this; - this.repaintTimer = undefined; - this.reflowTimer = undefined; -} + // parse the arguments + var id, ids, options, data; + var firstType = util.getType(arguments[0]); + if (firstType == 'String' || firstType == 'Number') { + // get(id [, options] [, data]) + id = arguments[0]; + options = arguments[1]; + data = arguments[2]; + } + else if (firstType == 'Array') { + // get(ids [, options] [, data]) + ids = arguments[0]; + options = arguments[1]; + data = arguments[2]; + } + else { + // get([, options] [, data]) + options = arguments[0]; + data = arguments[1]; + } -/** - * Add a component to the controller - * @param {Component} component - */ -Controller.prototype.add = function add(component) { - // validate the component - if (component.id == undefined) { - throw new Error('Component has no field id'); + // determine the return type + var type; + if (options && options.type) { + type = (options.type == 'DataTable') ? 'DataTable' : 'Array'; + + if (data && (type != util.getType(data))) { + throw new Error('Type of parameter "data" (' + util.getType(data) + ') ' + + 'does not correspond with specified options.type (' + options.type + ')'); + } + if (type == 'DataTable' && !util.isDataTable(data)) { + throw new Error('Parameter "data" must be a DataTable ' + + 'when options.type is "DataTable"'); + } } - if (!(component instanceof Component) && !(component instanceof Controller)) { - throw new TypeError('Component must be an instance of ' + - 'prototype Component or Controller'); + else if (data) { + type = (util.getType(data) == 'DataTable') ? 'DataTable' : 'Array'; + } + else { + type = 'Array'; } - // add the component - component.controller = this; - this.components[component.id] = component; -}; + // build options + var convert = options && options.convert || this.options.convert; + var filter = options && options.filter; + var items = [], item, itemId, i, len; -/** - * Remove a component from the controller - * @param {Component | String} component - */ -Controller.prototype.remove = function remove(component) { - var id; - for (id in this.components) { - if (this.components.hasOwnProperty(id)) { - if (id == component || this.components[id] == component) { - break; + // convert items + if (id != undefined) { + // return a single item + item = me._getItem(id, convert); + if (filter && !filter(item)) { + item = null; + } + } + else if (ids != undefined) { + // return a subset of items + for (i = 0, len = ids.length; i < len; i++) { + item = me._getItem(ids[i], convert); + if (!filter || filter(item)) { + items.push(item); } } } - - if (id) { - delete this.components[id]; + else { + // return all items + for (itemId in this.data) { + if (this.data.hasOwnProperty(itemId)) { + item = me._getItem(itemId, convert); + if (!filter || filter(item)) { + items.push(item); + } + } + } } -}; -/** - * Request a reflow. The controller will schedule a reflow - * @param {Boolean} [force] If true, an immediate reflow is forced. Default - * is false. - */ -Controller.prototype.requestReflow = function requestReflow(force) { - if (force) { - this.reflow(); + // order the results + if (options && options.order && id == undefined) { + this._sort(items, options.order); } - else { - if (!this.reflowTimer) { - var me = this; - this.reflowTimer = setTimeout(function () { - me.reflowTimer = undefined; - me.reflow(); - }, 0); + + // filter fields of the items + if (options && options.fields) { + var fields = options.fields; + if (id != undefined) { + item = this._filterFields(item, fields); + } + else { + for (i = 0, len = items.length; i < len; i++) { + items[i] = this._filterFields(items[i], fields); + } } } -}; -/** - * Request a repaint. The controller will schedule a repaint - * @param {Boolean} [force] If true, an immediate repaint is forced. Default - * is false. - */ -Controller.prototype.requestRepaint = function requestRepaint(force) { - if (force) { - this.repaint(); + // return the results + if (type == 'DataTable') { + var columns = this._getColumnNames(data); + if (id != undefined) { + // append a single item to the data table + me._appendRow(data, columns, item); + } + else { + // copy the items to the provided data table + for (i = 0, len = items.length; i < len; i++) { + me._appendRow(data, columns, items[i]); + } + } + return data; } else { - if (!this.repaintTimer) { - var me = this; - this.repaintTimer = setTimeout(function () { - me.repaintTimer = undefined; - me.repaint(); - }, 0); + // return an array + if (id != undefined) { + // a single item + return item; + } + else { + // multiple items + if (data) { + // copy the items to the provided array + for (i = 0, len = items.length; i < len; i++) { + data.push(items[i]); + } + return data; + } + else { + // just return our array + return items; + } } } }; /** - * Repaint all components + * Get ids of all items or from a filtered set of items. + * @param {Object} [options] An Object with options. Available options: + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * @return {Array} ids */ -Controller.prototype.repaint = function repaint() { - var changed = false; +DataSet.prototype.getIds = function (options) { + var data = this.data, + filter = options && options.filter, + order = options && options.order, + convert = options && options.convert || this.options.convert, + i, + len, + id, + item, + items, + ids = []; - // cancel any running repaint request - if (this.repaintTimer) { - clearTimeout(this.repaintTimer); - this.repaintTimer = undefined; + if (filter) { + // get filtered items + if (order) { + // create ordered list + items = []; + for (id in data) { + if (data.hasOwnProperty(id)) { + item = this._getItem(id, convert); + if (filter(item)) { + items.push(item); + } + } + } + + this._sort(items, order); + + for (i = 0, len = items.length; i < len; i++) { + ids[i] = items[i][this.fieldId]; + } + } + else { + // create unordered list + for (id in data) { + if (data.hasOwnProperty(id)) { + item = this._getItem(id, convert); + if (filter(item)) { + ids.push(item[this.fieldId]); + } + } + } + } } + else { + // get all items + if (order) { + // create an ordered list + items = []; + for (id in data) { + if (data.hasOwnProperty(id)) { + items.push(data[id]); + } + } - var done = {}; + this._sort(items, order); - function repaint(component, id) { - if (!(id in done)) { - // first repaint the components on which this component is dependent - if (component.depends) { - component.depends.forEach(function (dep) { - repaint(dep, dep.id); - }); + for (i = 0, len = items.length; i < len; i++) { + ids[i] = items[i][this.fieldId]; } - if (component.parent) { - repaint(component.parent, component.parent.id); + } + else { + // create unordered list + for (id in data) { + if (data.hasOwnProperty(id)) { + item = data[id]; + ids.push(item[this.fieldId]); + } } + } + } - // repaint the component itself and mark as done - changed = component.repaint() || changed; - done[id] = true; + return ids; +}; + +/** + * Execute a callback function for every item in the dataset. + * The order of the items is not determined. + * @param {function} callback + * @param {Object} [options] Available options: + * {Object.} [convert] + * {String[]} [fields] filter fields + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + */ +DataSet.prototype.forEach = function (callback, options) { + var filter = options && options.filter, + convert = options && options.convert || this.options.convert, + data = this.data, + item, + id; + + if (options && options.order) { + // execute forEach on ordered list + var items = this.get(options); + + for (var i = 0, len = items.length; i < len; i++) { + item = items[i]; + id = item[this.fieldId]; + callback(item, id); } } - - util.forEach(this.components, repaint); - - // immediately reflow when needed - if (changed) { - this.reflow(); + else { + // unordered + for (id in data) { + if (data.hasOwnProperty(id)) { + item = this._getItem(id, convert); + if (!filter || filter(item)) { + callback(item, id); + } + } + } } - // TODO: limit the number of nested reflows/repaints, prevent loop }; /** - * Reflow all components + * Map every item in the dataset. + * @param {function} callback + * @param {Object} [options] Available options: + * {Object.} [convert] + * {String[]} [fields] filter fields + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * @return {Object[]} mappedItems */ -Controller.prototype.reflow = function reflow() { - var resized = false; - - // cancel any running repaint request - if (this.reflowTimer) { - clearTimeout(this.reflowTimer); - this.reflowTimer = undefined; - } - - var done = {}; +DataSet.prototype.map = function (callback, options) { + var filter = options && options.filter, + convert = options && options.convert || this.options.convert, + mappedItems = [], + data = this.data, + item; - function reflow(component, id) { - if (!(id in done)) { - // first reflow the components on which this component is dependent - if (component.depends) { - component.depends.forEach(function (dep) { - reflow(dep, dep.id); - }); - } - if (component.parent) { - reflow(component.parent, component.parent.id); + // convert and filter items + for (var id in data) { + if (data.hasOwnProperty(id)) { + item = this._getItem(id, convert); + if (!filter || filter(item)) { + mappedItems.push(callback(item, id)); } - - // reflow the component itself and mark as done - resized = component.reflow() || resized; - done[id] = true; } } - util.forEach(this.components, reflow); - - // immediately repaint when needed - if (resized) { - this.repaint(); + // order items + if (options && options.order) { + this._sort(mappedItems, options.order); } - // TODO: limit the number of nested reflows/repaints, prevent loop -}; - -/** - * Prototype for visual components - */ -function Component () { - this.id = null; - this.parent = null; - this.depends = null; - this.controller = null; - this.options = null; - this.frame = null; // main DOM element - this.top = 0; - this.left = 0; - this.width = 0; - this.height = 0; -} + return mappedItems; +}; /** - * Set parameters for the frame. Parameters will be merged in current parameter - * set. - * @param {Object} options Available parameters: - * {String | function} [className] - * {EventBus} [eventBus] - * {String | Number | function} [left] - * {String | Number | function} [top] - * {String | Number | function} [width] - * {String | Number | function} [height] + * Filter the fields of an item + * @param {Object} item + * @param {String[]} fields Field names + * @return {Object} filteredItem + * @private */ -Component.prototype.setOptions = function setOptions(options) { - if (options) { - util.extend(this.options, options); +DataSet.prototype._filterFields = function (item, fields) { + var filteredItem = {}; - if (this.controller) { - this.requestRepaint(); - this.requestReflow(); + for (var field in item) { + if (item.hasOwnProperty(field) && (fields.indexOf(field) != -1)) { + filteredItem[field] = item[field]; } } + + return filteredItem; }; /** - * Get an option value by name - * The function will first check this.options object, and else will check - * this.defaultOptions. - * @param {String} name - * @return {*} value + * Sort the provided array with items + * @param {Object[]} items + * @param {String | function} order A field name or custom sort function. + * @private */ -Component.prototype.getOption = function getOption(name) { - var value; - if (this.options) { - value = this.options[name]; +DataSet.prototype._sort = function (items, order) { + if (util.isString(order)) { + // order by provided field name + var name = order; // field name + items.sort(function (a, b) { + var av = a[name]; + var bv = b[name]; + return (av > bv) ? 1 : ((av < bv) ? -1 : 0); + }); } - if (value === undefined && this.defaultOptions) { - value = this.defaultOptions[name]; + else if (typeof order === 'function') { + // order by sort function + items.sort(order); + } + // TODO: extend order by an Object {field:String, direction:String} + // where direction can be 'asc' or 'desc' + else { + throw new TypeError('Order must be a function or a string'); } - return value; }; /** - * Get the container element of the component, which can be used by a child to - * add its own widgets. Not all components do have a container for childs, in - * that case null is returned. - * @returns {HTMLElement | null} container + * Remove an object by pointer or by id + * @param {String | Number | Object | Array} id Object or id, or an array with + * objects or ids to be removed + * @param {String} [senderId] Optional sender id + * @return {Array} removedIds */ -// TODO: get rid of the getContainer and getFrame methods, provide these via the options -Component.prototype.getContainer = function getContainer() { - // should be implemented by the component - return null; +DataSet.prototype.remove = function (id, senderId) { + var removedIds = [], + i, len, removedId; + + if (id instanceof Array) { + for (i = 0, len = id.length; i < len; i++) { + removedId = this._remove(id[i]); + if (removedId != null) { + removedIds.push(removedId); + } + } + } + else { + removedId = this._remove(id); + if (removedId != null) { + removedIds.push(removedId); + } + } + + if (removedIds.length) { + this._trigger('remove', {items: removedIds}, senderId); + } + + return removedIds; }; /** - * Get the frame element of the component, the outer HTML DOM element. - * @returns {HTMLElement | null} frame + * Remove an item by its id + * @param {Number | String | Object} id id or item + * @returns {Number | String | null} id + * @private */ -Component.prototype.getFrame = function getFrame() { - return this.frame; +DataSet.prototype._remove = function (id) { + if (util.isNumber(id) || util.isString(id)) { + if (this.data[id]) { + delete this.data[id]; + delete this.internalIds[id]; + return id; + } + } + else if (id instanceof Object) { + var itemId = id[this.fieldId]; + if (itemId && this.data[itemId]) { + delete this.data[itemId]; + delete this.internalIds[itemId]; + return itemId; + } + } + return null; }; /** - * Repaint the component - * @return {Boolean} changed + * Clear the data + * @param {String} [senderId] Optional sender id + * @return {Array} removedIds The ids of all removed items */ -Component.prototype.repaint = function repaint() { - // should be implemented by the component - return false; +DataSet.prototype.clear = function (senderId) { + var ids = Object.keys(this.data); + + this.data = {}; + this.internalIds = {}; + + this._trigger('remove', {items: ids}, senderId); + + return ids; }; /** - * Reflow the component - * @return {Boolean} resized + * Find the item with maximum value of a specified field + * @param {String} field + * @return {Object | null} item Item containing max value, or null if no items */ -Component.prototype.reflow = function reflow() { - // should be implemented by the component - return false; +DataSet.prototype.max = function (field) { + var data = this.data, + max = null, + maxField = null; + + for (var id in data) { + if (data.hasOwnProperty(id)) { + var item = data[id]; + var itemField = item[field]; + if (itemField != null && (!max || itemField > maxField)) { + max = item; + maxField = itemField; + } + } + } + + return max; }; /** - * Hide the component from the DOM - * @return {Boolean} changed + * Find the item with minimum value of a specified field + * @param {String} field + * @return {Object | null} item Item containing max value, or null if no items */ -Component.prototype.hide = function hide() { - if (this.frame && this.frame.parentNode) { - this.frame.parentNode.removeChild(this.frame); - return true; - } - else { - return false; +DataSet.prototype.min = function (field) { + var data = this.data, + min = null, + minField = null; + + for (var id in data) { + if (data.hasOwnProperty(id)) { + var item = data[id]; + var itemField = item[field]; + if (itemField != null && (!min || itemField < minField)) { + min = item; + minField = itemField; + } + } } + + return min; }; /** - * Show the component in the DOM (when not already visible). - * A repaint will be executed when the component is not visible - * @return {Boolean} changed + * Find all distinct values of a specified field + * @param {String} field + * @return {Array} values Array containing all distinct values. If the data + * items do not contain the specified field, an array + * containing a single value undefined is returned. + * The returned array is unordered. */ -Component.prototype.show = function show() { - if (!this.frame || !this.frame.parentNode) { - return this.repaint(); - } - else { - return false; +DataSet.prototype.distinct = function (field) { + var data = this.data, + values = [], + fieldType = this.options.convert[field], + count = 0; + + for (var prop in data) { + if (data.hasOwnProperty(prop)) { + var item = data[prop]; + var value = util.convert(item[field], fieldType); + var exists = false; + for (var i = 0; i < count; i++) { + if (values[i] == value) { + exists = true; + break; + } + } + if (!exists) { + values[count] = value; + count++; + } + } } + + return values; }; /** - * Request a repaint. The controller will schedule a repaint + * Add a single item. Will fail when an item with the same id already exists. + * @param {Object} item + * @return {String} id + * @private */ -Component.prototype.requestRepaint = function requestRepaint() { - if (this.controller) { - this.controller.requestRepaint(); +DataSet.prototype._addItem = function (item) { + var id = item[this.fieldId]; + + if (id != undefined) { + // check whether this id is already taken + if (this.data[id]) { + // item already exists + throw new Error('Cannot add item: item with id ' + id + ' already exists'); + } } else { - throw new Error('Cannot request a repaint: no controller configured'); - // TODO: just do a repaint when no parent is configured? + // generate an id + id = util.randomUUID(); + item[this.fieldId] = id; + this.internalIds[id] = item; + } + + var d = {}; + for (var field in item) { + if (item.hasOwnProperty(field)) { + var fieldType = this.convert[field]; // type may be undefined + d[field] = util.convert(item[field], fieldType); + } } + this.data[id] = d; + + return id; }; /** - * Request a reflow. The controller will schedule a reflow + * Get an item. Fields can be converted to a specific type + * @param {String} id + * @param {Object.} [convert] field types to convert + * @return {Object | null} item + * @private */ -Component.prototype.requestReflow = function requestReflow() { - if (this.controller) { - this.controller.requestReflow(); +DataSet.prototype._getItem = function (id, convert) { + var field, value; + + // get the item from the dataset + var raw = this.data[id]; + if (!raw) { + return null; + } + + // convert the items field types + var converted = {}, + fieldId = this.fieldId, + internalIds = this.internalIds; + if (convert) { + for (field in raw) { + if (raw.hasOwnProperty(field)) { + value = raw[field]; + // output all fields, except internal ids + if ((field != fieldId) || !(value in internalIds)) { + converted[field] = util.convert(value, convert[field]); + } + } + } } else { - throw new Error('Cannot request a reflow: no controller configured'); - // TODO: just do a reflow when no parent is configured? + // no field types specified, no converting needed + for (field in raw) { + if (raw.hasOwnProperty(field)) { + value = raw[field]; + // output all fields, except internal ids + if ((field != fieldId) || !(value in internalIds)) { + converted[field] = value; + } + } + } } + + return converted; }; /** - * A panel can contain components - * @param {Component} [parent] - * @param {Component[]} [depends] Components on which this components depends - * (except for the parent) - * @param {Object} [options] Available parameters: - * {String | Number | function} [left] - * {String | Number | function} [top] - * {String | Number | function} [width] - * {String | Number | function} [height] - * {String | function} [className] - * @constructor Panel - * @extends Component + * Update a single item: merge with existing item. + * Will fail when the item has no id, or when there does not exist an item + * with the same id. + * @param {Object} item + * @return {String} id + * @private */ -function Panel(parent, depends, options) { - this.id = util.randomUUID(); - this.parent = parent; - this.depends = depends; - - this.options = options || {}; -} - -Panel.prototype = new Component(); +DataSet.prototype._updateItem = function (item) { + var id = item[this.fieldId]; + if (id == undefined) { + throw new Error('Cannot update item: item has no id (item: ' + JSON.stringify(item) + ')'); + } + var d = this.data[id]; + if (!d) { + // item doesn't exist + throw new Error('Cannot update item: no item with id ' + id + ' found'); + } -/** - * Set options. Will extend the current options. - * @param {Object} [options] Available parameters: - * {String | function} [className] - * {String | Number | function} [left] - * {String | Number | function} [top] - * {String | Number | function} [width] - * {String | Number | function} [height] - */ -Panel.prototype.setOptions = Component.prototype.setOptions; + // merge with current item + for (var field in item) { + if (item.hasOwnProperty(field)) { + var fieldType = this.convert[field]; // type may be undefined + d[field] = util.convert(item[field], fieldType); + } + } -/** - * Get the container element of the panel, which can be used by a child to - * add its own widgets. - * @returns {HTMLElement} container - */ -Panel.prototype.getContainer = function () { - return this.frame; + return id; }; /** - * Repaint the component - * @return {Boolean} changed + * Get an array with the column names of a Google DataTable + * @param {DataTable} dataTable + * @return {String[]} columnNames + * @private */ -Panel.prototype.repaint = function () { - var changed = 0, - update = util.updateProperty, - asSize = util.option.asSize, - options = this.options, - frame = this.frame; - if (!frame) { - frame = document.createElement('div'); - frame.className = 'panel'; - - var className = options.className; - if (className) { - if (typeof className == 'function') { - util.addClassName(frame, String(className())); - } - else { - util.addClassName(frame, String(className)); - } - } - - this.frame = frame; - changed += 1; - } - if (!frame.parentNode) { - if (!this.parent) { - throw new Error('Cannot repaint panel: no parent attached'); - } - var parentContainer = this.parent.getContainer(); - if (!parentContainer) { - throw new Error('Cannot repaint panel: parent has no container element'); - } - parentContainer.appendChild(frame); - changed += 1; +DataSet.prototype._getColumnNames = function (dataTable) { + var columns = []; + for (var col = 0, cols = dataTable.getNumberOfColumns(); col < cols; col++) { + columns[col] = dataTable.getColumnId(col) || dataTable.getColumnLabel(col); } - - changed += update(frame.style, 'top', asSize(options.top, '0px')); - changed += update(frame.style, 'left', asSize(options.left, '0px')); - changed += update(frame.style, 'width', asSize(options.width, '100%')); - changed += update(frame.style, 'height', asSize(options.height, '100%')); - - return (changed > 0); + return columns; }; /** - * Reflow the component - * @return {Boolean} resized + * Append an item as a row to the dataTable + * @param dataTable + * @param columns + * @param item + * @private */ -Panel.prototype.reflow = function () { - var changed = 0, - update = util.updateProperty, - frame = this.frame; +DataSet.prototype._appendRow = function (dataTable, columns, item) { + var row = dataTable.addRow(); - if (frame) { - changed += update(this, 'top', frame.offsetTop); - changed += update(this, 'left', frame.offsetLeft); - changed += update(this, 'width', frame.offsetWidth); - changed += update(this, 'height', frame.offsetHeight); - } - else { - changed += 1; + for (var col = 0, cols = columns.length; col < cols; col++) { + var field = columns[col]; + dataTable.setValue(row, col, item[field]); } - - return (changed > 0); }; /** - * A root panel can hold components. The root panel must be initialized with - * a DOM element as container. - * @param {HTMLElement} container - * @param {Object} [options] Available parameters: see RootPanel.setOptions. - * @constructor RootPanel - * @extends Panel + * DataView + * + * a dataview offers a filtered view on a dataset or an other dataview. + * + * @param {DataSet | DataView} data + * @param {Object} [options] Available options: see method get + * + * @constructor DataView */ -function RootPanel(container, options) { +function DataView (data, options) { this.id = util.randomUUID(); - this.container = container; + this.data = null; + this.ids = {}; // ids of the items currently in memory (just contains a boolean true) this.options = options || {}; - this.defaultOptions = { - autoResize: true + this.fieldId = 'id'; // name of the field containing id + this.subscribers = {}; // event subscribers + + var me = this; + this.listener = function () { + me._onEvent.apply(me, arguments); }; - this.listeners = {}; // event listeners + this.setData(data); } -RootPanel.prototype = new Panel(); - -/** - * Set options. Will extend the current options. - * @param {Object} [options] Available parameters: - * {String | function} [className] - * {String | Number | function} [left] - * {String | Number | function} [top] - * {String | Number | function} [width] - * {String | Number | function} [height] - * {Boolean | function} [autoResize] - */ -RootPanel.prototype.setOptions = Component.prototype.setOptions; - /** - * Repaint the component - * @return {Boolean} changed + * Set a data source for the view + * @param {DataSet | DataView} data */ -RootPanel.prototype.repaint = function () { - var changed = 0, - update = util.updateProperty, - asSize = util.option.asSize, - options = this.options, - frame = this.frame; - - if (!frame) { - frame = document.createElement('div'); - frame.className = 'vis timeline rootpanel'; +DataView.prototype.setData = function (data) { + var ids, dataItems, i, len; - var className = options.className; - if (className) { - util.addClassName(frame, util.option.asString(className)); + if (this.data) { + // unsubscribe from current dataset + if (this.data.unsubscribe) { + this.data.unsubscribe('*', this.listener); } - this.frame = frame; - - changed += 1; - } - if (!frame.parentNode) { - if (!this.container) { - throw new Error('Cannot repaint root panel: no container attached'); + // trigger a remove of all items in memory + ids = []; + for (var id in this.ids) { + if (this.ids.hasOwnProperty(id)) { + ids.push(id); + } } - this.container.appendChild(frame); - changed += 1; + this.ids = {}; + this._trigger('remove', {items: ids}); } - changed += update(frame.style, 'top', asSize(options.top, '0px')); - changed += update(frame.style, 'left', asSize(options.left, '0px')); - changed += update(frame.style, 'width', asSize(options.width, '100%')); - changed += update(frame.style, 'height', asSize(options.height, '100%')); + this.data = data; - this._updateEventEmitters(); - this._updateWatch(); + if (this.data) { + // update fieldId + this.fieldId = this.options.fieldId || + (this.data && this.data.options && this.data.options.fieldId) || + 'id'; - return (changed > 0); + // trigger an add of all added items + ids = this.data.getIds({filter: this.options && this.options.filter}); + for (i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + this.ids[id] = true; + } + this._trigger('add', {items: ids}); + + // subscribe to new dataset + if (this.data.subscribe) { + this.data.subscribe('*', this.listener); + } + } }; /** - * Reflow the component - * @return {Boolean} resized + * Get data from the data view + * + * Usage: + * + * get() + * get(options: Object) + * get(options: Object, data: Array | DataTable) + * + * get(id: Number) + * get(id: Number, options: Object) + * get(id: Number, options: Object, data: Array | DataTable) + * + * get(ids: Number[]) + * get(ids: Number[], options: Object) + * get(ids: Number[], options: Object, data: Array | DataTable) + * + * Where: + * + * {Number | String} id The id of an item + * {Number[] | String{}} ids An array with ids of items + * {Object} options An Object with options. Available options: + * {String} [type] Type of data to be returned. Can + * be 'DataTable' or 'Array' (default) + * {Object.} [convert] + * {String[]} [fields] field names to be returned + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * {Array | DataTable} [data] If provided, items will be appended to this + * array or table. Required in case of Google + * DataTable. + * @param args */ -RootPanel.prototype.reflow = function () { - var changed = 0, - update = util.updateProperty, - frame = this.frame; +DataView.prototype.get = function (args) { + var me = this; - if (frame) { - changed += update(this, 'top', frame.offsetTop); - changed += update(this, 'left', frame.offsetLeft); - changed += update(this, 'width', frame.offsetWidth); - changed += update(this, 'height', frame.offsetHeight); + // parse the arguments + var ids, options, data; + var firstType = util.getType(arguments[0]); + if (firstType == 'String' || firstType == 'Number' || firstType == 'Array') { + // get(id(s) [, options] [, data]) + ids = arguments[0]; // can be a single id or an array with ids + options = arguments[1]; + data = arguments[2]; } else { - changed += 1; + // get([, options] [, data]) + options = arguments[0]; + data = arguments[1]; } - return (changed > 0); + // extend the options with the default options and provided options + var viewOptions = util.extend({}, this.options, options); + + // create a combined filter method when needed + if (this.options.filter && options && options.filter) { + viewOptions.filter = function (item) { + return me.options.filter(item) && options.filter(item); + } + } + + // build up the call to the linked data set + var getArguments = []; + if (ids != undefined) { + getArguments.push(ids); + } + getArguments.push(viewOptions); + getArguments.push(data); + + return this.data && this.data.get.apply(this.data, getArguments); }; /** - * Update watching for resize, depending on the current option - * @private + * Get ids of all items or from a filtered set of items. + * @param {Object} [options] An Object with options. Available options: + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * @return {Array} ids */ -RootPanel.prototype._updateWatch = function () { - var autoResize = this.getOption('autoResize'); - if (autoResize) { - this._watch(); +DataView.prototype.getIds = function (options) { + var ids; + + if (this.data) { + var defaultFilter = this.options.filter; + var filter; + + if (options && options.filter) { + if (defaultFilter) { + filter = function (item) { + return defaultFilter(item) && options.filter(item); + } + } + else { + filter = options.filter; + } + } + else { + filter = defaultFilter; + } + + ids = this.data.getIds({ + filter: filter, + order: options && options.order + }); } else { - this._unwatch(); + ids = []; } + + return ids; }; /** - * Watch for changes in the size of the frame. On resize, the Panel will - * automatically redraw itself. + * Event listener. Will propagate all events from the connected data set to + * the subscribers of the DataView, but will filter the items and only trigger + * when there are changes in the filtered data set. + * @param {String} event + * @param {Object | null} params + * @param {String} senderId * @private */ -RootPanel.prototype._watch = function () { - var me = this; +DataView.prototype._onEvent = function (event, params, senderId) { + var i, len, id, item, + ids = params && params.items, + data = this.data, + added = [], + updated = [], + removed = []; - this._unwatch(); + if (ids && data) { + switch (event) { + case 'add': + // filter the ids of the added items + for (i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + item = this.get(id); + if (item) { + this.ids[id] = true; + added.push(id); + } + } - var checkSize = function () { - var autoResize = me.getOption('autoResize'); - if (!autoResize) { - // stop watching when the option autoResize is changed to false - me._unwatch(); - return; - } + break; - if (me.frame) { - // check whether the frame is resized - if ((me.frame.clientWidth != me.width) || - (me.frame.clientHeight != me.height)) { - me.requestReflow(); - } - } - }; + case 'update': + // determine the event from the views viewpoint: an updated + // item can be added, updated, or removed from this view. + for (i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + item = this.get(id); - // TODO: automatically cleanup the event listener when the frame is deleted - util.addEventListener(window, 'resize', checkSize); + if (item) { + if (this.ids[id]) { + updated.push(id); + } + else { + this.ids[id] = true; + added.push(id); + } + } + else { + if (this.ids[id]) { + delete this.ids[id]; + removed.push(id); + } + else { + // nothing interesting for me :-( + } + } + } - this.watchTimer = setInterval(checkSize, 1000); -}; + break; -/** - * Stop watching for a resize of the frame. - * @private - */ -RootPanel.prototype._unwatch = function () { - if (this.watchTimer) { - clearInterval(this.watchTimer); - this.watchTimer = undefined; - } + case 'remove': + // filter the ids of the removed items + for (i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + if (this.ids[id]) { + delete this.ids[id]; + removed.push(id); + } + } - // TODO: remove event listener on window.resize -}; + break; + } -/** - * Event handler - * @param {String} event name of the event, for example 'click', 'mousemove' - * @param {function} callback callback handler, invoked with the raw HTML Event - * as parameter. - */ -RootPanel.prototype.on = function (event, callback) { - // register the listener at this component - var arr = this.listeners[event]; - if (!arr) { - arr = []; - this.listeners[event] = arr; + if (added.length) { + this._trigger('add', {items: added}, senderId); + } + if (updated.length) { + this._trigger('update', {items: updated}, senderId); + } + if (removed.length) { + this._trigger('remove', {items: removed}, senderId); + } } - arr.push(callback); - - this._updateEventEmitters(); }; +// copy subscription functionality from DataSet +DataView.prototype.subscribe = DataSet.prototype.subscribe; +DataView.prototype.unsubscribe = DataSet.prototype.unsubscribe; +DataView.prototype._trigger = DataSet.prototype._trigger; + /** - * Update the event listeners for all event emitters - * @private + * @constructor TimeStep + * The class TimeStep is an iterator for dates. You provide a start date and an + * end date. The class itself determines the best scale (step size) based on the + * provided start Date, end Date, and minimumStep. + * + * If minimumStep is provided, the step size is chosen as close as possible + * to the minimumStep but larger than minimumStep. If minimumStep is not + * provided, the scale is set to 1 DAY. + * The minimumStep should correspond with the onscreen size of about 6 characters + * + * Alternatively, you can set a scale by hand. + * After creation, you can initialize the class by executing first(). Then you + * can iterate from the start date to the end date via next(). You can check if + * the end date is reached with the function hasNext(). After each step, you can + * retrieve the current date via getCurrent(). + * The TimeStep has scales ranging from milliseconds, seconds, minutes, hours, + * days, to years. + * + * Version: 1.2 + * + * @param {Date} [start] The start date, for example new Date(2010, 9, 21) + * or new Date(2010, 9, 21, 23, 45, 00) + * @param {Date} [end] The end date + * @param {Number} [minimumStep] Optional. Minimum step size in milliseconds */ -RootPanel.prototype._updateEventEmitters = function () { - if (this.listeners) { - var me = this; - util.forEach(this.listeners, function (listeners, event) { - if (!me.emitters) { - me.emitters = {}; - } - if (!(event in me.emitters)) { - // create event - var frame = me.frame; - if (frame) { - //console.log('Created a listener for event ' + event + ' on component ' + me.id); // TODO: cleanup logging - var callback = function(event) { - listeners.forEach(function (listener) { - // TODO: filter on event target! - listener(event); - }); - }; - me.emitters[event] = callback; - util.addEventListener(frame, event, callback); - } - } - }); +TimeStep = function(start, end, minimumStep) { + // variables + this.current = new Date(); + this._start = new Date(); + this._end = new Date(); - // TODO: be able to delete event listeners - // TODO: be able to move event listeners to a parent when available - } -}; + this.autoScale = true; + this.scale = TimeStep.SCALE.DAY; + this.step = 1; -/** - * A horizontal time axis - * @param {Component} parent - * @param {Component[]} [depends] Components on which this components depends - * (except for the parent) - * @param {Object} [options] See TimeAxis.setOptions for the available - * options. - * @constructor TimeAxis - * @extends Component - */ -function TimeAxis (parent, depends, options) { - this.id = util.randomUUID(); - this.parent = parent; - this.depends = depends; + // initialize the range + this.setRange(start, end, minimumStep); +}; - this.dom = { - majorLines: [], - majorTexts: [], - minorLines: [], - minorTexts: [], - redundant: { - majorLines: [], - majorTexts: [], - minorLines: [], - minorTexts: [] - } - }; - this.props = { - range: { - start: 0, - end: 0, - minimumStep: 0 - }, - lineTop: 0 - }; +/// enum scale +TimeStep.SCALE = { + MILLISECOND: 1, + SECOND: 2, + MINUTE: 3, + HOUR: 4, + DAY: 5, + WEEKDAY: 6, + MONTH: 7, + YEAR: 8 +}; - this.options = options || {}; - this.defaultOptions = { - orientation: 'bottom', // supported: 'top', 'bottom' - // TODO: implement timeaxis orientations 'left' and 'right' - showMinorLabels: true, - showMajorLabels: true - }; - this.conversion = null; - this.range = null; -} +/** + * Set a new range + * If minimumStep is provided, the step size is chosen as close as possible + * to the minimumStep but larger than minimumStep. If minimumStep is not + * provided, the scale is set to 1 DAY. + * The minimumStep should correspond with the onscreen size of about 6 characters + * @param {Date} [start] The start date and time. + * @param {Date} [end] The end date and time. + * @param {int} [minimumStep] Optional. Minimum step size in milliseconds + */ +TimeStep.prototype.setRange = function(start, end, minimumStep) { + if (!(start instanceof Date) || !(end instanceof Date)) { + //throw "No legal start or end date in method setRange"; + return; + } -TimeAxis.prototype = new Component(); + this._start = (start != undefined) ? new Date(start.valueOf()) : new Date(); + this._end = (end != undefined) ? new Date(end.valueOf()) : new Date(); -// TODO: comment options -TimeAxis.prototype.setOptions = Component.prototype.setOptions; + if (this.autoScale) { + this.setMinimumStep(minimumStep); + } +}; /** - * Set a range (start and end) - * @param {Range | Object} range A Range or an object containing start and end. + * Set the range iterator to the start date. */ -TimeAxis.prototype.setRange = function (range) { - if (!(range instanceof Range) && (!range || !range.start || !range.end)) { - throw new TypeError('Range must be an instance of Range, ' + - 'or an object containing start and end.'); - } - this.range = range; +TimeStep.prototype.first = function() { + this.current = new Date(this._start.valueOf()); + this.roundToMinor(); }; /** - * Convert a position on screen (pixels) to a datetime - * @param {int} x Position on the screen in pixels - * @return {Date} time The datetime the corresponds with given position x + * Round the current date to the first minor date value + * This must be executed once when the current date is set to start Date */ -TimeAxis.prototype.toTime = function(x) { - var conversion = this.conversion; - return new Date(x / conversion.factor + conversion.offset); +TimeStep.prototype.roundToMinor = function() { + // round to floor + // IMPORTANT: we have no breaks in this switch! (this is no bug) + //noinspection FallthroughInSwitchStatementJS + switch (this.scale) { + case TimeStep.SCALE.YEAR: + this.current.setFullYear(this.step * Math.floor(this.current.getFullYear() / this.step)); + this.current.setMonth(0); + case TimeStep.SCALE.MONTH: this.current.setDate(1); + case TimeStep.SCALE.DAY: // intentional fall through + case TimeStep.SCALE.WEEKDAY: this.current.setHours(0); + case TimeStep.SCALE.HOUR: this.current.setMinutes(0); + case TimeStep.SCALE.MINUTE: this.current.setSeconds(0); + case TimeStep.SCALE.SECOND: this.current.setMilliseconds(0); + //case TimeStep.SCALE.MILLISECOND: // nothing to do for milliseconds + } + + if (this.step != 1) { + // round down to the first minor value that is a multiple of the current step size + switch (this.scale) { + case TimeStep.SCALE.MILLISECOND: this.current.setMilliseconds(this.current.getMilliseconds() - this.current.getMilliseconds() % this.step); break; + case TimeStep.SCALE.SECOND: this.current.setSeconds(this.current.getSeconds() - this.current.getSeconds() % this.step); break; + case TimeStep.SCALE.MINUTE: this.current.setMinutes(this.current.getMinutes() - this.current.getMinutes() % this.step); break; + case TimeStep.SCALE.HOUR: this.current.setHours(this.current.getHours() - this.current.getHours() % this.step); break; + case TimeStep.SCALE.WEEKDAY: // intentional fall through + case TimeStep.SCALE.DAY: this.current.setDate((this.current.getDate()-1) - (this.current.getDate()-1) % this.step + 1); break; + case TimeStep.SCALE.MONTH: this.current.setMonth(this.current.getMonth() - this.current.getMonth() % this.step); break; + case TimeStep.SCALE.YEAR: this.current.setFullYear(this.current.getFullYear() - this.current.getFullYear() % this.step); break; + default: break; + } + } }; /** - * Convert a datetime (Date object) into a position on the screen - * @param {Date} time A date - * @return {int} x The position on the screen in pixels which corresponds - * with the given date. - * @private + * Check if the there is a next step + * @return {boolean} true if the current date has not passed the end date */ -TimeAxis.prototype.toScreen = function(time) { - var conversion = this.conversion; - return (time.valueOf() - conversion.offset) * conversion.factor; +TimeStep.prototype.hasNext = function () { + return (this.current.valueOf() <= this._end.valueOf()); }; /** - * Repaint the component - * @return {Boolean} changed + * Do the next step */ -TimeAxis.prototype.repaint = function () { - var changed = 0, - update = util.updateProperty, - asSize = util.option.asSize, - options = this.options, - orientation = this.getOption('orientation'), - props = this.props, - step = this.step; +TimeStep.prototype.next = function() { + var prev = this.current.valueOf(); - var frame = this.frame; - if (!frame) { - frame = document.createElement('div'); - this.frame = frame; - changed += 1; - } - frame.className = 'axis ' + orientation; - // TODO: custom className? + // Two cases, needed to prevent issues with switching daylight savings + // (end of March and end of October) + if (this.current.getMonth() < 6) { + switch (this.scale) { + case TimeStep.SCALE.MILLISECOND: - if (!frame.parentNode) { - if (!this.parent) { - throw new Error('Cannot repaint time axis: no parent attached'); + this.current = new Date(this.current.valueOf() + this.step); break; + case TimeStep.SCALE.SECOND: this.current = new Date(this.current.valueOf() + this.step * 1000); break; + case TimeStep.SCALE.MINUTE: this.current = new Date(this.current.valueOf() + this.step * 1000 * 60); break; + case TimeStep.SCALE.HOUR: + this.current = new Date(this.current.valueOf() + this.step * 1000 * 60 * 60); + // in case of skipping an hour for daylight savings, adjust the hour again (else you get: 0h 5h 9h ... instead of 0h 4h 8h ...) + var h = this.current.getHours(); + this.current.setHours(h - (h % this.step)); + break; + case TimeStep.SCALE.WEEKDAY: // intentional fall through + case TimeStep.SCALE.DAY: this.current.setDate(this.current.getDate() + this.step); break; + case TimeStep.SCALE.MONTH: this.current.setMonth(this.current.getMonth() + this.step); break; + case TimeStep.SCALE.YEAR: this.current.setFullYear(this.current.getFullYear() + this.step); break; + default: break; } - var parentContainer = this.parent.getContainer(); - if (!parentContainer) { - throw new Error('Cannot repaint time axis: parent has no container element'); + } + else { + switch (this.scale) { + case TimeStep.SCALE.MILLISECOND: this.current = new Date(this.current.valueOf() + this.step); break; + case TimeStep.SCALE.SECOND: this.current.setSeconds(this.current.getSeconds() + this.step); break; + case TimeStep.SCALE.MINUTE: this.current.setMinutes(this.current.getMinutes() + this.step); break; + case TimeStep.SCALE.HOUR: this.current.setHours(this.current.getHours() + this.step); break; + case TimeStep.SCALE.WEEKDAY: // intentional fall through + case TimeStep.SCALE.DAY: this.current.setDate(this.current.getDate() + this.step); break; + case TimeStep.SCALE.MONTH: this.current.setMonth(this.current.getMonth() + this.step); break; + case TimeStep.SCALE.YEAR: this.current.setFullYear(this.current.getFullYear() + this.step); break; + default: break; } - parentContainer.appendChild(frame); - - changed += 1; } - var parent = frame.parentNode; - if (parent) { - var beforeChild = frame.nextSibling; - parent.removeChild(frame); // take frame offline while updating (is almost twice as fast) - - var defaultTop = (orientation == 'bottom' && this.props.parentHeight && this.height) ? - (this.props.parentHeight - this.height) + 'px' : - '0px'; - changed += update(frame.style, 'top', asSize(options.top, defaultTop)); - changed += update(frame.style, 'left', asSize(options.left, '0px')); - changed += update(frame.style, 'width', asSize(options.width, '100%')); - changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); - - // get characters width and height - this._repaintMeasureChars(); - - if (this.step) { - this._repaintStart(); - - step.first(); - var xFirstMajorLabel = undefined; - var max = 0; - while (step.hasNext() && max < 1000) { - max++; - var cur = step.getCurrent(), - x = this.toScreen(cur), - isMajor = step.isMajor(); - - // TODO: lines must have a width, such that we can create css backgrounds - - if (this.getOption('showMinorLabels')) { - this._repaintMinorText(x, step.getLabelMinor()); - } - - if (isMajor && this.getOption('showMajorLabels')) { - if (x > 0) { - if (xFirstMajorLabel == undefined) { - xFirstMajorLabel = x; - } - this._repaintMajorText(x, step.getLabelMajor()); - } - this._repaintMajorLine(x); - } - else { - this._repaintMinorLine(x); - } - - step.next(); - } - - // create a major label on the left when needed - if (this.getOption('showMajorLabels')) { - var leftTime = this.toTime(0), - leftText = step.getLabelMajor(leftTime), - widthText = leftText.length * (props.majorCharWidth || 10) + 10; // upper bound estimation - - if (xFirstMajorLabel == undefined || widthText < xFirstMajorLabel) { - this._repaintMajorText(0, leftText); - } - } - - this._repaintEnd(); + if (this.step != 1) { + // round down to the correct major value + switch (this.scale) { + case TimeStep.SCALE.MILLISECOND: if(this.current.getMilliseconds() < this.step) this.current.setMilliseconds(0); break; + case TimeStep.SCALE.SECOND: if(this.current.getSeconds() < this.step) this.current.setSeconds(0); break; + case TimeStep.SCALE.MINUTE: if(this.current.getMinutes() < this.step) this.current.setMinutes(0); break; + case TimeStep.SCALE.HOUR: if(this.current.getHours() < this.step) this.current.setHours(0); break; + case TimeStep.SCALE.WEEKDAY: // intentional fall through + case TimeStep.SCALE.DAY: if(this.current.getDate() < this.step+1) this.current.setDate(1); break; + case TimeStep.SCALE.MONTH: if(this.current.getMonth() < this.step) this.current.setMonth(0); break; + case TimeStep.SCALE.YEAR: break; // nothing to do for year + default: break; } + } - this._repaintLine(); - - // put frame online again - if (beforeChild) { - parent.insertBefore(frame, beforeChild); - } - else { - parent.appendChild(frame) - } + // safety mechanism: if current time is still unchanged, move to the end + if (this.current.valueOf() == prev) { + this.current = new Date(this._end.valueOf()); } +}; - return (changed > 0); + +/** + * Get the current datetime + * @return {Date} current The current date + */ +TimeStep.prototype.getCurrent = function() { + return this.current; }; /** - * Start a repaint. Move all DOM elements to a redundant list, where they - * can be picked for re-use, or can be cleaned up in the end - * @private + * Set a custom scale. Autoscaling will be disabled. + * For example setScale(SCALE.MINUTES, 5) will result + * in minor steps of 5 minutes, and major steps of an hour. + * + * @param {TimeStep.SCALE} newScale + * A scale. Choose from SCALE.MILLISECOND, + * SCALE.SECOND, SCALE.MINUTE, SCALE.HOUR, + * SCALE.WEEKDAY, SCALE.DAY, SCALE.MONTH, + * SCALE.YEAR. + * @param {Number} newStep A step size, by default 1. Choose for + * example 1, 2, 5, or 10. */ -TimeAxis.prototype._repaintStart = function () { - var dom = this.dom, - redundant = dom.redundant; +TimeStep.prototype.setScale = function(newScale, newStep) { + this.scale = newScale; - redundant.majorLines = dom.majorLines; - redundant.majorTexts = dom.majorTexts; - redundant.minorLines = dom.minorLines; - redundant.minorTexts = dom.minorTexts; + if (newStep > 0) { + this.step = newStep; + } - dom.majorLines = []; - dom.majorTexts = []; - dom.minorLines = []; - dom.minorTexts = []; + this.autoScale = false; }; /** - * End a repaint. Cleanup leftover DOM elements in the redundant list - * @private + * Enable or disable autoscaling + * @param {boolean} enable If true, autoascaling is set true */ -TimeAxis.prototype._repaintEnd = function () { - util.forEach(this.dom.redundant, function (arr) { - while (arr.length) { - var elem = arr.pop(); - if (elem && elem.parentNode) { - elem.parentNode.removeChild(elem); - } - } - }); +TimeStep.prototype.setAutoScale = function (enable) { + this.autoScale = enable; }; /** - * Create a minor label for the axis at position x - * @param {Number} x - * @param {String} text - * @private + * Automatically determine the scale that bests fits the provided minimum step + * @param {Number} [minimumStep] The minimum step size in milliseconds */ -TimeAxis.prototype._repaintMinorText = function (x, text) { - // reuse redundant label - var label = this.dom.redundant.minorTexts.shift(); - - if (!label) { - // create new label - var content = document.createTextNode(''); - label = document.createElement('div'); - label.appendChild(content); - label.className = 'text minor'; - this.frame.appendChild(label); +TimeStep.prototype.setMinimumStep = function(minimumStep) { + if (minimumStep == undefined) { + return; } - this.dom.minorTexts.push(label); - label.childNodes[0].nodeValue = text; - label.style.left = x + 'px'; - label.style.top = this.props.minorLabelTop + 'px'; - //label.title = title; // TODO: this is a heavy operation + var stepYear = (1000 * 60 * 60 * 24 * 30 * 12); + var stepMonth = (1000 * 60 * 60 * 24 * 30); + var stepDay = (1000 * 60 * 60 * 24); + var stepHour = (1000 * 60 * 60); + var stepMinute = (1000 * 60); + var stepSecond = (1000); + var stepMillisecond= (1); + + // find the smallest step that is larger than the provided minimumStep + if (stepYear*1000 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 1000;} + if (stepYear*500 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 500;} + if (stepYear*100 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 100;} + if (stepYear*50 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 50;} + if (stepYear*10 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 10;} + if (stepYear*5 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 5;} + if (stepYear > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 1;} + if (stepMonth*3 > minimumStep) {this.scale = TimeStep.SCALE.MONTH; this.step = 3;} + if (stepMonth > minimumStep) {this.scale = TimeStep.SCALE.MONTH; this.step = 1;} + if (stepDay*5 > minimumStep) {this.scale = TimeStep.SCALE.DAY; this.step = 5;} + if (stepDay*2 > minimumStep) {this.scale = TimeStep.SCALE.DAY; this.step = 2;} + if (stepDay > minimumStep) {this.scale = TimeStep.SCALE.DAY; this.step = 1;} + if (stepDay/2 > minimumStep) {this.scale = TimeStep.SCALE.WEEKDAY; this.step = 1;} + if (stepHour*4 > minimumStep) {this.scale = TimeStep.SCALE.HOUR; this.step = 4;} + if (stepHour > minimumStep) {this.scale = TimeStep.SCALE.HOUR; this.step = 1;} + if (stepMinute*15 > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 15;} + if (stepMinute*10 > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 10;} + if (stepMinute*5 > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 5;} + if (stepMinute > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 1;} + if (stepSecond*15 > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 15;} + if (stepSecond*10 > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 10;} + if (stepSecond*5 > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 5;} + if (stepSecond > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 1;} + if (stepMillisecond*200 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 200;} + if (stepMillisecond*100 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 100;} + if (stepMillisecond*50 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 50;} + if (stepMillisecond*10 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 10;} + if (stepMillisecond*5 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 5;} + if (stepMillisecond > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 1;} }; /** - * Create a Major label for the axis at position x - * @param {Number} x - * @param {String} text - * @private + * Snap a date to a rounded value. The snap intervals are dependent on the + * current scale and step. + * @param {Date} date the date to be snapped */ -TimeAxis.prototype._repaintMajorText = function (x, text) { - // reuse redundant label - var label = this.dom.redundant.majorTexts.shift(); - - if (!label) { - // create label - var content = document.createTextNode(text); - label = document.createElement('div'); - label.className = 'text major'; - label.appendChild(content); - this.frame.appendChild(label); +TimeStep.prototype.snap = function(date) { + if (this.scale == TimeStep.SCALE.YEAR) { + var year = date.getFullYear() + Math.round(date.getMonth() / 12); + date.setFullYear(Math.round(year / this.step) * this.step); + date.setMonth(0); + date.setDate(0); + date.setHours(0); + date.setMinutes(0); + date.setSeconds(0); + date.setMilliseconds(0); } - this.dom.majorTexts.push(label); + else if (this.scale == TimeStep.SCALE.MONTH) { + if (date.getDate() > 15) { + date.setDate(1); + date.setMonth(date.getMonth() + 1); + // important: first set Date to 1, after that change the month. + } + else { + date.setDate(1); + } - label.childNodes[0].nodeValue = text; - label.style.top = this.props.majorLabelTop + 'px'; - label.style.left = x + 'px'; - //label.title = title; // TODO: this is a heavy operation + date.setHours(0); + date.setMinutes(0); + date.setSeconds(0); + date.setMilliseconds(0); + } + else if (this.scale == TimeStep.SCALE.DAY || + this.scale == TimeStep.SCALE.WEEKDAY) { + //noinspection FallthroughInSwitchStatementJS + switch (this.step) { + case 5: + case 2: + date.setHours(Math.round(date.getHours() / 24) * 24); break; + default: + date.setHours(Math.round(date.getHours() / 12) * 12); break; + } + date.setMinutes(0); + date.setSeconds(0); + date.setMilliseconds(0); + } + else if (this.scale == TimeStep.SCALE.HOUR) { + switch (this.step) { + case 4: + date.setMinutes(Math.round(date.getMinutes() / 60) * 60); break; + default: + date.setMinutes(Math.round(date.getMinutes() / 30) * 30); break; + } + date.setSeconds(0); + date.setMilliseconds(0); + } else if (this.scale == TimeStep.SCALE.MINUTE) { + //noinspection FallthroughInSwitchStatementJS + switch (this.step) { + case 15: + case 10: + date.setMinutes(Math.round(date.getMinutes() / 5) * 5); + date.setSeconds(0); + break; + case 5: + date.setSeconds(Math.round(date.getSeconds() / 60) * 60); break; + default: + date.setSeconds(Math.round(date.getSeconds() / 30) * 30); break; + } + date.setMilliseconds(0); + } + else if (this.scale == TimeStep.SCALE.SECOND) { + //noinspection FallthroughInSwitchStatementJS + switch (this.step) { + case 15: + case 10: + date.setSeconds(Math.round(date.getSeconds() / 5) * 5); + date.setMilliseconds(0); + break; + case 5: + date.setMilliseconds(Math.round(date.getMilliseconds() / 1000) * 1000); break; + default: + date.setMilliseconds(Math.round(date.getMilliseconds() / 500) * 500); break; + } + } + else if (this.scale == TimeStep.SCALE.MILLISECOND) { + var step = this.step > 5 ? this.step / 2 : 1; + date.setMilliseconds(Math.round(date.getMilliseconds() / step) * step); + } }; /** - * Create a minor line for the axis at position x - * @param {Number} x - * @private + * Check if the current value is a major value (for example when the step + * is DAY, a major value is each first day of the MONTH) + * @return {boolean} true if current date is major, else false. */ -TimeAxis.prototype._repaintMinorLine = function (x) { - // reuse redundant line - var line = this.dom.redundant.minorLines.shift(); - - if (!line) { - // create vertical line - line = document.createElement('div'); - line.className = 'grid vertical minor'; - this.frame.appendChild(line); +TimeStep.prototype.isMajor = function() { + switch (this.scale) { + case TimeStep.SCALE.MILLISECOND: + return (this.current.getMilliseconds() == 0); + case TimeStep.SCALE.SECOND: + return (this.current.getSeconds() == 0); + case TimeStep.SCALE.MINUTE: + return (this.current.getHours() == 0) && (this.current.getMinutes() == 0); + // Note: this is no bug. Major label is equal for both minute and hour scale + case TimeStep.SCALE.HOUR: + return (this.current.getHours() == 0); + case TimeStep.SCALE.WEEKDAY: // intentional fall through + case TimeStep.SCALE.DAY: + return (this.current.getDate() == 1); + case TimeStep.SCALE.MONTH: + return (this.current.getMonth() == 0); + case TimeStep.SCALE.YEAR: + return false; + default: + return false; } - this.dom.minorLines.push(line); - - var props = this.props; - line.style.top = props.minorLineTop + 'px'; - line.style.height = props.minorLineHeight + 'px'; - line.style.left = (x - props.minorLineWidth / 2) + 'px'; }; + /** - * Create a Major line for the axis at position x - * @param {Number} x - * @private + * Returns formatted text for the minor axislabel, depending on the current + * date and the scale. For example when scale is MINUTE, the current time is + * formatted as "hh:mm". + * @param {Date} [date] custom date. if not provided, current date is taken */ -TimeAxis.prototype._repaintMajorLine = function (x) { - // reuse redundant line - var line = this.dom.redundant.majorLines.shift(); - - if (!line) { - // create vertical line - line = document.createElement('DIV'); - line.className = 'grid vertical major'; - this.frame.appendChild(line); +TimeStep.prototype.getLabelMinor = function(date) { + if (date == undefined) { + date = this.current; } - this.dom.majorLines.push(line); - var props = this.props; - line.style.top = props.majorLineTop + 'px'; - line.style.left = (x - props.majorLineWidth / 2) + 'px'; - line.style.height = props.majorLineHeight + 'px'; + switch (this.scale) { + case TimeStep.SCALE.MILLISECOND: return moment(date).format('SSS'); + case TimeStep.SCALE.SECOND: return moment(date).format('s'); + case TimeStep.SCALE.MINUTE: return moment(date).format('HH:mm'); + case TimeStep.SCALE.HOUR: return moment(date).format('HH:mm'); + case TimeStep.SCALE.WEEKDAY: return moment(date).format('ddd D'); + case TimeStep.SCALE.DAY: return moment(date).format('D'); + case TimeStep.SCALE.MONTH: return moment(date).format('MMM'); + case TimeStep.SCALE.YEAR: return moment(date).format('YYYY'); + default: return ''; + } }; /** - * Repaint the horizontal line for the axis - * @private + * Returns formatted text for the major axis label, depending on the current + * date and the scale. For example when scale is MINUTE, the major scale is + * hours, and the hour will be formatted as "hh". + * @param {Date} [date] custom date. if not provided, current date is taken */ -TimeAxis.prototype._repaintLine = function() { - var line = this.dom.line, - frame = this.frame, - options = this.options; - - // line before all axis elements - if (this.getOption('showMinorLabels') || this.getOption('showMajorLabels')) { - if (line) { - // put this line at the end of all childs - frame.removeChild(line); - frame.appendChild(line); - } - else { - // create the axis line - line = document.createElement('div'); - line.className = 'grid horizontal major'; - frame.appendChild(line); - this.dom.line = line; - } - - line.style.top = this.props.lineTop + 'px'; +TimeStep.prototype.getLabelMajor = function(date) { + if (date == undefined) { + date = this.current; } - else { - if (line && axis.parentElement) { - frame.removeChild(axis.line); - delete this.dom.line; - } + + //noinspection FallthroughInSwitchStatementJS + switch (this.scale) { + case TimeStep.SCALE.MILLISECOND:return moment(date).format('HH:mm:ss'); + case TimeStep.SCALE.SECOND: return moment(date).format('D MMMM HH:mm'); + case TimeStep.SCALE.MINUTE: + case TimeStep.SCALE.HOUR: return moment(date).format('ddd D MMMM'); + case TimeStep.SCALE.WEEKDAY: + case TimeStep.SCALE.DAY: return moment(date).format('MMMM YYYY'); + case TimeStep.SCALE.MONTH: return moment(date).format('YYYY'); + case TimeStep.SCALE.YEAR: return ''; + default: return ''; } }; /** - * Create characters used to determine the size of text on the axis - * @private + * @constructor Stack + * Stacks items on top of each other. + * @param {ItemSet} parent + * @param {Object} [options] */ -TimeAxis.prototype._repaintMeasureChars = function () { - // calculate the width and height of a single character - // this is used to calculate the step size, and also the positioning of the - // axis - var dom = this.dom, - text; +function Stack (parent, options) { + this.parent = parent; - if (!dom.measureCharMinor) { - text = document.createTextNode('0'); - var measureCharMinor = document.createElement('DIV'); - measureCharMinor.className = 'text minor measure'; - measureCharMinor.appendChild(text); - this.frame.appendChild(measureCharMinor); + this.options = options || {}; + this.defaultOptions = { + order: function (a, b) { + //return (b.width - a.width) || (a.left - b.left); // TODO: cleanup + // Order: ranges over non-ranges, ranged ordered by width, and + // lastly ordered by start. + if (a instanceof ItemRange) { + if (b instanceof ItemRange) { + var aInt = (a.data.end - a.data.start); + var bInt = (b.data.end - b.data.start); + return (aInt - bInt) || (a.data.start - b.data.start); + } + else { + return -1; + } + } + else { + if (b instanceof ItemRange) { + return 1; + } + else { + return (a.data.start - b.data.start); + } + } + }, + margin: { + item: 10 + } + }; - dom.measureCharMinor = measureCharMinor; - } + this.ordered = []; // ordered items +} - if (!dom.measureCharMajor) { - text = document.createTextNode('0'); - var measureCharMajor = document.createElement('DIV'); - measureCharMajor.className = 'text major measure'; - measureCharMajor.appendChild(text); - this.frame.appendChild(measureCharMajor); +/** + * Set options for the stack + * @param {Object} options Available options: + * {ItemSet} parent + * {Number} margin + * {function} order Stacking order + */ +Stack.prototype.setOptions = function setOptions (options) { + util.extend(this.options, options); - dom.measureCharMajor = measureCharMajor; - } + // TODO: register on data changes at the connected parent itemset, and update the changed part only and immediately }; /** - * Reflow the component - * @return {Boolean} resized + * Stack the items such that they don't overlap. The items will have a minimal + * distance equal to options.margin.item. */ -TimeAxis.prototype.reflow = function () { - var changed = 0, - update = util.updateProperty, - frame = this.frame, - range = this.range; +Stack.prototype.update = function update() { + this._order(); + this._stack(); +}; - if (!range) { - throw new Error('Cannot repaint time axis: no range configured'); +/** + * Order the items. The items are ordered by width first, and by left position + * second. + * If a custom order function has been provided via the options, then this will + * be used. + * @private + */ +Stack.prototype._order = function _order () { + var items = this.parent.items; + if (!items) { + throw new Error('Cannot stack items: parent does not contain items'); } - if (frame) { - changed += update(this, 'top', frame.offsetTop); - changed += update(this, 'left', frame.offsetLeft); - - // calculate size of a character - var props = this.props, - showMinorLabels = this.getOption('showMinorLabels'), - showMajorLabels = this.getOption('showMajorLabels'), - measureCharMinor = this.dom.measureCharMinor, - measureCharMajor = this.dom.measureCharMajor; - if (measureCharMinor) { - props.minorCharHeight = measureCharMinor.clientHeight; - props.minorCharWidth = measureCharMinor.clientWidth; - } - if (measureCharMajor) { - props.majorCharHeight = measureCharMajor.clientHeight; - props.majorCharWidth = measureCharMajor.clientWidth; - } - - var parentHeight = frame.parentNode ? frame.parentNode.offsetHeight : 0; - if (parentHeight != props.parentHeight) { - props.parentHeight = parentHeight; - changed += 1; + // TODO: store the sorted items, to have less work later on + var ordered = []; + var index = 0; + // items is a map (no array) + util.forEach(items, function (item) { + if (item.visible) { + ordered[index] = item; + index++; } - switch (this.getOption('orientation')) { - case 'bottom': - props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; - props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; - - props.minorLabelTop = 0; - props.majorLabelTop = props.minorLabelTop + props.minorLabelHeight; - - props.minorLineTop = -this.top; - props.minorLineHeight = Math.max(this.top + props.majorLabelHeight, 0); - props.minorLineWidth = 1; // TODO: really calculate width - - props.majorLineTop = -this.top; - props.majorLineHeight = Math.max(this.top + props.minorLabelHeight + props.majorLabelHeight, 0); - props.majorLineWidth = 1; // TODO: really calculate width - - props.lineTop = 0; + }); - break; + //if a customer stack order function exists, use it. + var order = this.options.order || this.defaultOptions.order; + if (!(typeof order === 'function')) { + throw new Error('Option order must be a function'); + } - case 'top': - props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; - props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; + ordered.sort(order); - props.majorLabelTop = 0; - props.minorLabelTop = props.majorLabelTop + props.majorLabelHeight; + this.ordered = ordered; +}; - props.minorLineTop = props.minorLabelTop; - props.minorLineHeight = Math.max(parentHeight - props.majorLabelHeight - this.top); - props.minorLineWidth = 1; // TODO: really calculate width +/** + * Adjust vertical positions of the events such that they don't overlap each + * other. + * @private + */ +Stack.prototype._stack = function _stack () { + var i, + iMax, + ordered = this.ordered, + options = this.options, + orientation = options.orientation || this.defaultOptions.orientation, + axisOnTop = (orientation == 'top'), + margin; - props.majorLineTop = 0; - props.majorLineHeight = Math.max(parentHeight - this.top); - props.majorLineWidth = 1; // TODO: really calculate width + if (options.margin && options.margin.item !== undefined) { + margin = options.margin.item; + } + else { + margin = this.defaultOptions.margin.item + } - props.lineTop = props.majorLabelHeight + props.minorLabelHeight; + // calculate new, non-overlapping positions + for (i = 0, iMax = ordered.length; i < iMax; i++) { + var item = ordered[i]; + var collidingItem = null; + do { + // TODO: optimize checking for overlap. when there is a gap without items, + // you only need to check for items from the next item on, not from zero + collidingItem = this.checkOverlap(ordered, i, 0, i - 1, margin); + if (collidingItem != null) { + // There is a collision. Reposition the event above the colliding element + if (axisOnTop) { + item.top = collidingItem.top + collidingItem.height + margin; + } + else { + item.top = collidingItem.top - item.height - margin; + } + } + } while (collidingItem); + } +}; - break; +/** + * Check if the destiny position of given item overlaps with any + * of the other items from index itemStart to itemEnd. + * @param {Array} items Array with items + * @param {int} itemIndex Number of the item to be checked for overlap + * @param {int} itemStart First item to be checked. + * @param {int} itemEnd Last item to be checked. + * @return {Object | null} colliding item, or undefined when no collisions + * @param {Number} margin A minimum required margin. + * If margin is provided, the two items will be + * marked colliding when they overlap or + * when the margin between the two is smaller than + * the requested margin. + */ +Stack.prototype.checkOverlap = function checkOverlap (items, itemIndex, + itemStart, itemEnd, margin) { + var collision = this.collision; - default: - throw new Error('Unkown orientation "' + this.getOption('orientation') + '"'); + // we loop from end to start, as we suppose that the chance of a + // collision is larger for items at the end, so check these first. + var a = items[itemIndex]; + for (var i = itemEnd; i >= itemStart; i--) { + var b = items[i]; + if (collision(a, b, margin)) { + if (i != itemIndex) { + return b; + } } - - var height = props.minorLabelHeight + props.majorLabelHeight; - changed += update(this, 'width', frame.offsetWidth); - changed += update(this, 'height', height); - - // calculate range and step - this._updateConversion(); - - var start = util.convert(range.start, 'Date'), - end = util.convert(range.end, 'Date'), - minimumStep = this.toTime((props.minorCharWidth || 10) * 5) - this.toTime(0); - this.step = new TimeStep(start, end, minimumStep); - changed += update(props.range, 'start', start.valueOf()); - changed += update(props.range, 'end', end.valueOf()); - changed += update(props.range, 'minimumStep', minimumStep.valueOf()); } - return (changed > 0); + return null; }; /** - * Calculate the factor and offset to convert a position on screen to the - * corresponding date and vice versa. - * After the method _updateConversion is executed once, the methods toTime - * and toScreen can be used. - * @private + * Test if the two provided items collide + * The items must have parameters left, width, top, and height. + * @param {Component} a The first item + * @param {Component} b The second item + * @param {Number} margin A minimum required margin. + * If margin is provided, the two items will be + * marked colliding when they overlap or + * when the margin between the two is smaller than + * the requested margin. + * @return {boolean} true if a and b collide, else false */ -TimeAxis.prototype._updateConversion = function() { - var range = this.range; - if (!range) { - throw new Error('No range configured'); - } - - if (range.conversion) { - this.conversion = range.conversion(this.width); - } - else { - this.conversion = Range.conversion(range.start, range.end, this.width); - } +Stack.prototype.collision = function collision (a, b, margin) { + return ((a.left - margin) < (b.left + b.width) && + (a.left + a.width + margin) > b.left && + (a.top - margin) < (b.top + b.height) && + (a.top + a.height + margin) > b.top); }; /** - * An ItemSet holds a set of items and ranges which can be displayed in a - * range. The width is determined by the parent of the ItemSet, and the height - * is determined by the size of the items. - * @param {Component} parent - * @param {Component[]} [depends] Components on which this components depends - * (except for the parent) - * @param {Object} [options] See ItemSet.setOptions for the available - * options. - * @constructor ItemSet - * @extends Panel + * @constructor Range + * A Range controls a numeric range with a start and end value. + * The Range adjusts the range based on mouse events or programmatic changes, + * and triggers events when the range is changing or has been changed. + * @param {Object} [options] See description at Range.setOptions + * @extends Controller */ -// TODO: improve performance by replacing all Array.forEach with a for loop -function ItemSet(parent, depends, options) { +function Range(options) { this.id = util.randomUUID(); - this.parent = parent; - this.depends = depends; + this.start = 0; // Number + this.end = 0; // Number - // one options object is shared by this itemset and all its items - this.options = options || {}; - this.defaultOptions = { - type: 'box', - align: 'center', - orientation: 'bottom', - margin: { - axis: 20, - item: 10 - }, - padding: 5 + // this.options = options || {}; // TODO: fix range options + this.options = { + min: null, + max: null, + zoomMin: null, + zoomMax: null }; - this.dom = {}; + this.listeners = []; - var me = this; - this.itemsData = null; // DataSet - this.range = null; // Range or Object {start: number, end: number} + this.setOptions(options); +} - this.listeners = { - 'add': function (event, params, senderId) { - if (senderId != me.id) { - me._onAdd(params.items); - } - }, - 'update': function (event, params, senderId) { - if (senderId != me.id) { - me._onUpdate(params.items); - } - }, - 'remove': function (event, params, senderId) { - if (senderId != me.id) { - me._onRemove(params.items); - } - } - }; +/** + * Set options for the range controller + * @param {Object} options Available options: + * {Number} start Set start value of the range + * {Number} end Set end value of the range + * {Number} min Minimum value for start + * {Number} max Maximum value for end + * {Number} zoomMin Set a minimum value for + * (end - start). + * {Number} zoomMax Set a maximum value for + * (end - start). + */ +Range.prototype.setOptions = function (options) { + util.extend(this.options, options); - this.items = {}; // object with an Item for every data item - this.queue = {}; // queue with id/actions: 'add', 'update', 'delete' - this.stack = new Stack(this, Object.create(this.options)); - this.conversion = null; + if (options.start != null || options.end != null) { + this.setRange(options.start, options.end); + } +}; - // TODO: ItemSet should also attach event listeners for rangechange and rangechanged, like timeaxis -} +/** + * Add listeners for mouse and touch events to the component + * @param {Component} component + * @param {String} event Available events: 'move', 'zoom' + * @param {String} direction Available directions: 'horizontal', 'vertical' + */ +Range.prototype.subscribe = function (component, event, direction) { + var me = this; + var listener; -ItemSet.prototype = new Panel(); + if (direction != 'horizontal' && direction != 'vertical') { + throw new TypeError('Unknown direction "' + direction + '". ' + + 'Choose "horizontal" or "vertical".'); + } -// available item types will be registered here -ItemSet.types = { - box: ItemBox, - range: ItemRange, - point: ItemPoint + //noinspection FallthroughInSwitchStatementJS + if (event == 'move') { + listener = { + component: component, + event: event, + direction: direction, + callback: function (event) { + me._onMouseDown(event, listener); + }, + params: {} + }; + + component.on('mousedown', listener.callback); + me.listeners.push(listener); + } + else if (event == 'zoom') { + listener = { + component: component, + event: event, + direction: direction, + callback: function (event) { + me._onMouseWheel(event, listener); + }, + params: {} + }; + + component.on('mousewheel', listener.callback); + me.listeners.push(listener); + } + else { + throw new TypeError('Unknown event "' + event + '". ' + + 'Choose "move" or "zoom".'); + } }; /** - * Set options for the ItemSet. Existing options will be extended/overwritten. - * @param {Object} [options] The following options are available: - * {String | function} [className] - * class name for the itemset - * {String} [type] - * Default type for the items. Choose from 'box' - * (default), 'point', or 'range'. The default - * Style can be overwritten by individual items. - * {String} align - * Alignment for the items, only applicable for - * ItemBox. Choose 'center' (default), 'left', or - * 'right'. - * {String} orientation - * Orientation of the item set. Choose 'top' or - * 'bottom' (default). - * {Number} margin.axis - * Margin between the axis and the items in pixels. - * Default is 20. - * {Number} margin.item - * Margin between items in pixels. Default is 10. - * {Number} padding - * Padding of the contents of an item in pixels. - * Must correspond with the items css. Default is 5. + * Event handler + * @param {String} event name of the event, for example 'click', 'mousemove' + * @param {function} callback callback handler, invoked with the raw HTML Event + * as parameter. */ -ItemSet.prototype.setOptions = Component.prototype.setOptions; +Range.prototype.on = function (event, callback) { + events.addListener(this, event, callback); +}; /** - * Set range (start and end). - * @param {Range | Object} range A Range or an object containing start and end. + * Trigger an event + * @param {String} event name of the event, available events: 'rangechange', + * 'rangechanged' + * @private */ -ItemSet.prototype.setRange = function setRange(range) { - if (!(range instanceof Range) && (!range || !range.start || !range.end)) { - throw new TypeError('Range must be an instance of Range, ' + - 'or an object containing start and end.'); +Range.prototype._trigger = function (event) { + events.trigger(this, event, { + start: this.start, + end: this.end + }); +}; + +/** + * Set a new start and end range + * @param {Number} start + * @param {Number} end + */ +Range.prototype.setRange = function(start, end) { + var changed = this._applyRange(start, end); + if (changed) { + this._trigger('rangechange'); + this._trigger('rangechanged'); } - this.range = range; }; /** - * Repaint the component + * Set a new start and end range. This method is the same as setRange, but + * does not trigger a range change and range changed event, and it returns + * true when the range is changed + * @param {Number} start + * @param {Number} end * @return {Boolean} changed + * @private */ -ItemSet.prototype.repaint = function repaint() { - var changed = 0, - update = util.updateProperty, - asSize = util.option.asSize, - options = this.options, - orientation = this.getOption('orientation'), - defaultOptions = this.defaultOptions, - frame = this.frame; - - if (!frame) { - frame = document.createElement('div'); - frame.className = 'itemset'; - - var className = options.className; - if (className) { - util.addClassName(frame, util.option.asString(className)); - } - - // create background panel - var background = document.createElement('div'); - background.className = 'background'; - frame.appendChild(background); - this.dom.background = background; - - // create foreground panel - var foreground = document.createElement('div'); - foreground.className = 'foreground'; - frame.appendChild(foreground); - this.dom.foreground = foreground; - - // create axis panel - var axis = document.createElement('div'); - axis.className = 'itemset-axis'; - //frame.appendChild(axis); - this.dom.axis = axis; - - this.frame = frame; - changed += 1; - } +Range.prototype._applyRange = function(start, end) { + var newStart = (start != null) ? util.convert(start, 'Number') : this.start; + var newEnd = (end != null) ? util.convert(end, 'Number') : this.end; + var diff; - if (!this.parent) { - throw new Error('Cannot repaint itemset: no parent attached'); - } - var parentContainer = this.parent.getContainer(); - if (!parentContainer) { - throw new Error('Cannot repaint itemset: parent has no container element'); - } - if (!frame.parentNode) { - parentContainer.appendChild(frame); - changed += 1; + // check for valid number + if (isNaN(newStart)) { + throw new Error('Invalid start "' + start + '"'); } - if (!this.dom.axis.parentNode) { - parentContainer.appendChild(this.dom.axis); - changed += 1; + if (isNaN(newEnd)) { + throw new Error('Invalid end "' + end + '"'); } - // reposition frame - changed += update(frame.style, 'left', asSize(options.left, '0px')); - changed += update(frame.style, 'top', asSize(options.top, '0px')); - changed += update(frame.style, 'width', asSize(options.width, '100%')); - changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); - - // reposition axis - changed += update(this.dom.axis.style, 'left', asSize(options.left, '0px')); - changed += update(this.dom.axis.style, 'width', asSize(options.width, '100%')); - if (orientation == 'bottom') { - changed += update(this.dom.axis.style, 'top', (this.height + this.top) + 'px'); - } - else { // orientation == 'top' - changed += update(this.dom.axis.style, 'top', this.top + 'px'); + // prevent start < end + if (newEnd < newStart) { + newEnd = newStart; } - this._updateConversion(); - - var me = this, - queue = this.queue, - itemsData = this.itemsData, - items = this.items, - dataOptions = { - fields: [(itemsData && itemsData.fieldId || 'id'), 'start', 'end', 'content', 'type'] - }; - // TODO: copy options from the itemset itself? - - // show/hide added/changed/removed items - Object.keys(queue).forEach(function (id) { - //var entry = queue[id]; - var action = queue[id]; - var item = items[id]; - //var item = entry.item; - //noinspection FallthroughInSwitchStatementJS - switch (action) { - case 'add': - case 'update': - var itemData = itemsData && itemsData.get(id, dataOptions); - - if (itemData) { - var type = itemData.type || - (itemData.start && itemData.end && 'range') || - options.type || - 'box'; - var constructor = ItemSet.types[type]; - - // TODO: how to handle items with invalid data? hide them and give a warning? or throw an error? - if (item) { - // update item - if (!constructor || !(item instanceof constructor)) { - // item type has changed, hide and delete the item - changed += item.hide(); - item = null; - } - else { - item.data = itemData; // TODO: create a method item.setData ? - changed++; - } - } - - if (!item) { - // create item - if (constructor) { - item = new constructor(me, itemData, options, defaultOptions); - changed++; - } - else { - throw new TypeError('Unknown item type "' + type + '"'); - } - } - - // force a repaint (not only a reposition) - item.repaint(); - - items[id] = item; - } - - // update queue - delete queue[id]; - break; - - case 'remove': - if (item) { - // remove DOM of the item - changed += item.hide(); - } + // prevent start < min + if (this.options.min != null) { + var min = this.options.min.valueOf(); + if (newStart < min) { + diff = (min - newStart); + newStart += diff; + newEnd += diff; + } + } - // update lists - delete items[id]; - delete queue[id]; - break; + // prevent end > max + if (this.options.max != null) { + var max = this.options.max.valueOf(); + if (newEnd > max) { + diff = (newEnd - max); + newStart -= diff; + newEnd -= diff; + } + } - default: - console.log('Error: unknown action "' + action + '"'); + // prevent (end-start) > zoomMin + if (this.options.zoomMin != null) { + var zoomMin = this.options.zoomMin.valueOf(); + if (zoomMin < 0) { + zoomMin = 0; } - }); + if ((newEnd - newStart) < zoomMin) { + if ((this.end - this.start) > zoomMin) { + // zoom to the minimum + diff = (zoomMin - (newEnd - newStart)); + newStart -= diff / 2; + newEnd += diff / 2; + } + else { + // ingore this action, we are already zoomed to the minimum + newStart = this.start; + newEnd = this.end; + } + } + } - // reposition all items. Show items only when in the visible area - util.forEach(this.items, function (item) { - if (item.visible) { - changed += item.show(); - item.reposition(); + // prevent (end-start) > zoomMin + if (this.options.zoomMax != null) { + var zoomMax = this.options.zoomMax.valueOf(); + if (zoomMax < 0) { + zoomMax = 0; } - else { - changed += item.hide(); + if ((newEnd - newStart) > zoomMax) { + if ((this.end - this.start) < zoomMax) { + // zoom to the maximum + diff = ((newEnd - newStart) - zoomMax); + newStart += diff / 2; + newEnd -= diff / 2; + } + else { + // ingore this action, we are already zoomed to the maximum + newStart = this.start; + newEnd = this.end; + } } - }); + } - return (changed > 0); -}; + var changed = (this.start != newStart || this.end != newEnd); -/** - * Get the foreground container element - * @return {HTMLElement} foreground - */ -ItemSet.prototype.getForeground = function getForeground() { - return this.dom.foreground; + this.start = newStart; + this.end = newEnd; + + return changed; }; /** - * Get the background container element - * @return {HTMLElement} background + * Retrieve the current range. + * @return {Object} An object with start and end properties */ -ItemSet.prototype.getBackground = function getBackground() { - return this.dom.background; +Range.prototype.getRange = function() { + return { + start: this.start, + end: this.end + }; }; /** - * Get the axis container element - * @return {HTMLElement} axis + * Calculate the conversion offset and factor for current range, based on + * the provided width + * @param {Number} width + * @returns {{offset: number, factor: number}} conversion */ -ItemSet.prototype.getAxis = function getAxis() { - return this.dom.axis; +Range.prototype.conversion = function (width) { + var start = this.start; + var end = this.end; + + return Range.conversion(this.start, this.end, width); }; /** - * Reflow the component - * @return {Boolean} resized + * Static method to calculate the conversion offset and factor for a range, + * based on the provided start, end, and width + * @param {Number} start + * @param {Number} end + * @param {Number} width + * @returns {{offset: number, factor: number}} conversion */ -ItemSet.prototype.reflow = function reflow () { - var changed = 0, - options = this.options, - marginAxis = options.margin && options.margin.axis || this.defaultOptions.margin.axis, - marginItem = options.margin && options.margin.item || this.defaultOptions.margin.item, - update = util.updateProperty, - asNumber = util.option.asNumber, - asSize = util.option.asSize, - frame = this.frame; - - if (frame) { - this._updateConversion(); - - util.forEach(this.items, function (item) { - changed += item.reflow(); - }); - - // TODO: stack.update should be triggered via an event, in stack itself - // TODO: only update the stack when there are changed items - this.stack.update(); - - var maxHeight = asNumber(options.maxHeight); - var fixedHeight = (asSize(options.height) != null); - var height; - if (fixedHeight) { - height = frame.offsetHeight; - } - else { - // height is not specified, determine the height from the height and positioned items - var visibleItems = this.stack.ordered; // TODO: not so nice way to get the filtered items - if (visibleItems.length) { - var min = visibleItems[0].top; - var max = visibleItems[0].top + visibleItems[0].height; - util.forEach(visibleItems, function (item) { - min = Math.min(min, item.top); - max = Math.max(max, (item.top + item.height)); - }); - height = (max - min) + marginAxis + marginItem; - } - else { - height = marginAxis + marginItem; - } - } - if (maxHeight != null) { - height = Math.min(height, maxHeight); +Range.conversion = function (start, end, width) { + if (width != 0 && (end - start != 0)) { + return { + offset: start, + factor: width / (end - start) } - changed += update(this, 'height', height); - - // calculate height from items - changed += update(this, 'top', frame.offsetTop); - changed += update(this, 'left', frame.offsetLeft); - changed += update(this, 'width', frame.offsetWidth); } else { - changed += 1; + return { + offset: 0, + factor: 1 + }; } - - return (changed > 0); }; /** - * Hide this component from the DOM - * @return {Boolean} changed + * Start moving horizontally or vertically + * @param {Event} event + * @param {Object} listener Listener containing the component and params + * @private */ -ItemSet.prototype.hide = function hide() { - var changed = false; +Range.prototype._onMouseDown = function(event, listener) { + event = event || window.event; + var params = listener.params; - // remove the DOM - if (this.frame && this.frame.parentNode) { - this.frame.parentNode.removeChild(this.frame); - changed = true; - } - if (this.dom.axis && this.dom.axis.parentNode) { - this.dom.axis.parentNode.removeChild(this.dom.axis); - changed = true; + // only react on left mouse button down + var leftButtonDown = event.which ? (event.which == 1) : (event.button == 1); + if (!leftButtonDown) { + return; } - return changed; -}; + // get mouse position + params.mouseX = util.getPageX(event); + params.mouseY = util.getPageY(event); + params.previousLeft = 0; + params.previousOffset = 0; -/** - * Set items - * @param {vis.DataSet | null} items - */ -ItemSet.prototype.setItems = function setItems(items) { - var me = this, - ids, - oldItemsData = this.itemsData; + params.moved = false; + params.start = this.start; + params.end = this.end; - // replace the dataset - if (!items) { - this.itemsData = null; - } - else if (items instanceof DataSet || items instanceof DataView) { - this.itemsData = items; - } - else { - throw new TypeError('Data must be an instance of DataSet'); + var frame = listener.component.frame; + if (frame) { + frame.style.cursor = 'move'; } - if (oldItemsData) { - // unsubscribe from old dataset - util.forEach(this.listeners, function (callback, event) { - oldItemsData.unsubscribe(event, callback); - }); - - // remove all drawn items - ids = oldItemsData.getIds(); - this._onRemove(ids); + // add event listeners to handle moving the contents + // we store the function onmousemove and onmouseup in the timeaxis, + // so we can remove the eventlisteners lateron in the function onmouseup + var me = this; + if (!params.onMouseMove) { + params.onMouseMove = function (event) { + me._onMouseMove(event, listener); + }; + util.addEventListener(document, "mousemove", params.onMouseMove); } - - if (this.itemsData) { - // subscribe to new dataset - var id = this.id; - util.forEach(this.listeners, function (callback, event) { - me.itemsData.subscribe(event, callback, id); - }); - - // draw all new items - ids = this.itemsData.getIds(); - this._onAdd(ids); + if (!params.onMouseUp) { + params.onMouseUp = function (event) { + me._onMouseUp(event, listener); + }; + util.addEventListener(document, "mouseup", params.onMouseUp); } -}; -/** - * Get the current items items - * @returns {vis.DataSet | null} - */ -ItemSet.prototype.getItems = function getItems() { - return this.itemsData; + util.preventDefault(event); }; /** - * Handle updated items - * @param {Number[]} ids + * Perform moving operating. + * This function activated from within the funcion TimeAxis._onMouseDown(). + * @param {Event} event + * @param {Object} listener * @private */ -ItemSet.prototype._onUpdate = function _onUpdate(ids) { - this._toQueue('update', ids); -}; +Range.prototype._onMouseMove = function (event, listener) { + event = event || window.event; -/** - * Handle changed items - * @param {Number[]} ids - * @private - */ -ItemSet.prototype._onAdd = function _onAdd(ids) { - this._toQueue('add', ids); -}; + var params = listener.params; -/** - * Handle removed items - * @param {Number[]} ids - * @private - */ -ItemSet.prototype._onRemove = function _onRemove(ids) { - this._toQueue('remove', ids); -}; + // calculate change in mouse position + var mouseX = util.getPageX(event); + var mouseY = util.getPageY(event); -/** - * Put items in the queue to be added/updated/remove - * @param {String} action can be 'add', 'update', 'remove' - * @param {Number[]} ids - */ -ItemSet.prototype._toQueue = function _toQueue(action, ids) { - var queue = this.queue; - ids.forEach(function (id) { - queue[id] = action; - }); + if (params.mouseX == undefined) { + params.mouseX = mouseX; + } + if (params.mouseY == undefined) { + params.mouseY = mouseY; + } - if (this.controller) { - //this.requestReflow(); - this.requestRepaint(); + var diffX = mouseX - params.mouseX; + var diffY = mouseY - params.mouseY; + var diff = (listener.direction == 'horizontal') ? diffX : diffY; + + // if mouse movement is big enough, register it as a "moved" event + if (Math.abs(diff) >= 1) { + params.moved = true; } + + var interval = (params.end - params.start); + var width = (listener.direction == 'horizontal') ? + listener.component.width : listener.component.height; + var diffRange = -diff / width * interval; + this._applyRange(params.start + diffRange, params.end + diffRange); + + // fire a rangechange event + this._trigger('rangechange'); + + util.preventDefault(event); }; /** - * Calculate the factor and offset to convert a position on screen to the - * corresponding date and vice versa. - * After the method _updateConversion is executed once, the methods toTime - * and toScreen can be used. + * Stop moving operating. + * This function activated from within the function Range._onMouseDown(). + * @param {event} event + * @param {Object} listener * @private */ -ItemSet.prototype._updateConversion = function _updateConversion() { - var range = this.range; - if (!range) { - throw new Error('No range configured'); +Range.prototype._onMouseUp = function (event, listener) { + event = event || window.event; + + var params = listener.params; + + if (listener.component.frame) { + listener.component.frame.style.cursor = 'auto'; } - if (range.conversion) { - this.conversion = range.conversion(this.width); + // remove event listeners here, important for Safari + if (params.onMouseMove) { + util.removeEventListener(document, "mousemove", params.onMouseMove); + params.onMouseMove = null; } - else { - this.conversion = Range.conversion(range.start, range.end, this.width); + if (params.onMouseUp) { + util.removeEventListener(document, "mouseup", params.onMouseUp); + params.onMouseUp = null; } -}; + //util.preventDefault(event); -/** - * Convert a position on screen (pixels) to a datetime - * Before this method can be used, the method _updateConversion must be - * executed once. - * @param {int} x Position on the screen in pixels - * @return {Date} time The datetime the corresponds with given position x - */ -ItemSet.prototype.toTime = function toTime(x) { - var conversion = this.conversion; - return new Date(x / conversion.factor + conversion.offset); + if (params.moved) { + // fire a rangechanged event + this._trigger('rangechanged'); + } }; /** - * Convert a datetime (Date object) into a position on the screen - * Before this method can be used, the method _updateConversion must be - * executed once. - * @param {Date} time A date - * @return {int} x The position on the screen in pixels which corresponds - * with the given date. + * Event handler for mouse wheel event, used to zoom + * Code from http://adomas.org/javascript-mouse-wheel/ + * @param {Event} event + * @param {Object} listener + * @private */ -ItemSet.prototype.toScreen = function toScreen(time) { - var conversion = this.conversion; - return (time.valueOf() - conversion.offset) * conversion.factor; -}; +Range.prototype._onMouseWheel = function(event, listener) { + event = event || window.event; -/** - * @constructor Item - * @param {ItemSet} parent - * @param {Object} data Object containing (optional) parameters type, - * start, end, content, group, className. - * @param {Object} [options] Options to set initial property values - * @param {Object} [defaultOptions] default options - * // TODO: describe available options - */ -function Item (parent, data, options, defaultOptions) { - this.parent = parent; - this.data = data; - this.dom = null; - this.options = options || {}; - this.defaultOptions = defaultOptions || {}; + // retrieve delta + var delta = 0; + if (event.wheelDelta) { /* IE/Opera. */ + delta = event.wheelDelta / 120; + } else if (event.detail) { /* Mozilla case. */ + // In Mozilla, sign of delta is different than in IE. + // Also, delta is multiple of 3. + delta = -event.detail / 3; + } - this.selected = false; - this.visible = false; - this.top = 0; - this.left = 0; - this.width = 0; - this.height = 0; -} + // If delta is nonzero, handle it. + // Basically, delta is now positive if wheel was scrolled up, + // and negative, if wheel was scrolled down. + if (delta) { + var me = this; + var zoom = function () { + // perform the zoom action. Delta is normally 1 or -1 + var zoomFactor = delta / 5.0; + var zoomAround = null; + var frame = listener.component.frame; + if (frame) { + var size, conversion; + if (listener.direction == 'horizontal') { + size = listener.component.width; + conversion = me.conversion(size); + var frameLeft = util.getAbsoluteLeft(frame); + var mouseX = util.getPageX(event); + zoomAround = (mouseX - frameLeft) / conversion.factor + conversion.offset; + } + else { + size = listener.component.height; + conversion = me.conversion(size); + var frameTop = util.getAbsoluteTop(frame); + var mouseY = util.getPageY(event); + zoomAround = ((frameTop + size - mouseY) - frameTop) / conversion.factor + conversion.offset; + } + } -/** - * Select current item - */ -Item.prototype.select = function select() { - this.selected = true; -}; + me.zoom(zoomFactor, zoomAround); + }; -/** - * Unselect current item - */ -Item.prototype.unselect = function unselect() { - this.selected = false; -}; + zoom(); + } -/** - * Show the Item in the DOM (when not already visible) - * @return {Boolean} changed - */ -Item.prototype.show = function show() { - return false; + // Prevent default actions caused by mouse wheel. + // That might be ugly, but we handle scrolls somehow + // anyway, so don't bother here... + util.preventDefault(event); }; -/** - * Hide the Item from the DOM (when visible) - * @return {Boolean} changed - */ -Item.prototype.hide = function hide() { - return false; -}; /** - * Repaint the item - * @return {Boolean} changed + * Zoom the range the given zoomfactor in or out. Start and end date will + * be adjusted, and the timeline will be redrawn. You can optionally give a + * date around which to zoom. + * For example, try zoomfactor = 0.1 or -0.1 + * @param {Number} zoomFactor Zooming amount. Positive value will zoom in, + * negative value will zoom out + * @param {Number} zoomAround Value around which will be zoomed. Optional */ -Item.prototype.repaint = function repaint() { - // should be implemented by the item - return false; -}; +Range.prototype.zoom = function(zoomFactor, zoomAround) { + // if zoomAroundDate is not provided, take it half between start Date and end Date + if (zoomAround == null) { + zoomAround = (this.start + this.end) / 2; + } -/** - * Reflow the item - * @return {Boolean} resized - */ -Item.prototype.reflow = function reflow() { - // should be implemented by the item - return false; + // prevent zoom factor larger than 1 or smaller than -1 (larger than 1 will + // result in a start>=end ) + if (zoomFactor >= 1) { + zoomFactor = 0.9; + } + if (zoomFactor <= -1) { + zoomFactor = -0.9; + } + + // adjust a negative factor such that zooming in with 0.1 equals zooming + // out with a factor -0.1 + if (zoomFactor < 0) { + zoomFactor = zoomFactor / (1 + zoomFactor); + } + + // zoom start and end relative to the zoomAround value + var startDiff = (this.start - zoomAround); + var endDiff = (this.end - zoomAround); + + // calculate new start and end + var newStart = this.start - startDiff * zoomFactor; + var newEnd = this.end - endDiff * zoomFactor; + + this.setRange(newStart, newEnd); }; /** - * @constructor ItemBox - * @extends Item - * @param {ItemSet} parent - * @param {Object} data Object containing parameters start - * content, className. - * @param {Object} [options] Options to set initial property values - * @param {Object} [defaultOptions] default options - * // TODO: describe available options + * Move the range with a given factor to the left or right. Start and end + * value will be adjusted. For example, try moveFactor = 0.1 or -0.1 + * @param {Number} moveFactor Moving amount. Positive value will move right, + * negative value will move left */ -function ItemBox (parent, data, options, defaultOptions) { - this.props = { - dot: { - left: 0, - top: 0, - width: 0, - height: 0 - }, - line: { - top: 0, - left: 0, - width: 0, - height: 0 - } - }; +Range.prototype.move = function(moveFactor) { + // zoom start Date and end Date relative to the zoomAroundDate + var diff = (this.end - this.start); - Item.call(this, parent, data, options, defaultOptions); -} + // apply new values + var newStart = this.start + diff * moveFactor; + var newEnd = this.end + diff * moveFactor; -ItemBox.prototype = new Item (null, null); + // TODO: reckon with min and max range + + this.start = newStart; + this.end = newEnd; +}; /** - * Select the item - * @override + * Move the range to a new center point + * @param {Number} moveTo New center point of the range */ -ItemBox.prototype.select = function select() { - this.selected = true; - // TODO: select and unselect -}; +Range.prototype.moveTo = function(moveTo) { + var center = (this.start + this.end) / 2; + + var diff = center - moveTo; + + // calculate new start and end + var newStart = this.start - diff; + var newEnd = this.end - diff; + + this.setRange(newStart, newEnd); +} /** - * Unselect the item - * @override + * @constructor Controller + * + * A Controller controls the reflows and repaints of all visual components */ -ItemBox.prototype.unselect = function unselect() { - this.selected = false; - // TODO: select and unselect -}; +function Controller () { + this.id = util.randomUUID(); + this.components = {}; + + this.repaintTimer = undefined; + this.reflowTimer = undefined; +} /** - * Repaint the item - * @return {Boolean} changed + * Add a component to the controller + * @param {Component} component */ -ItemBox.prototype.repaint = function repaint() { - // TODO: make an efficient repaint - var changed = false; - var dom = this.dom; - - if (!dom) { - this._create(); - dom = this.dom; - changed = true; +Controller.prototype.add = function add(component) { + // validate the component + if (component.id == undefined) { + throw new Error('Component has no field id'); + } + if (!(component instanceof Component) && !(component instanceof Controller)) { + throw new TypeError('Component must be an instance of ' + + 'prototype Component or Controller'); } - if (dom) { - if (!this.parent) { - throw new Error('Cannot repaint item: no parent attached'); - } - var foreground = this.parent.getForeground(); - if (!foreground) { - throw new Error('Cannot repaint time axis: ' + - 'parent has no foreground container element'); - } - var background = this.parent.getBackground(); - if (!background) { - throw new Error('Cannot repaint time axis: ' + - 'parent has no background container element'); - } - var axis = this.parent.getAxis(); - if (!background) { - throw new Error('Cannot repaint time axis: ' + - 'parent has no axis container element'); - } - - if (!dom.box.parentNode) { - foreground.appendChild(dom.box); - changed = true; - } - if (!dom.line.parentNode) { - background.appendChild(dom.line); - changed = true; - } - if (!dom.dot.parentNode) { - axis.appendChild(dom.dot); - changed = true; - } + // add the component + component.controller = this; + this.components[component.id] = component; +}; - // update contents - if (this.data.content != this.content) { - this.content = this.data.content; - if (this.content instanceof Element) { - dom.content.innerHTML = ''; - dom.content.appendChild(this.content); - } - else if (this.data.content != undefined) { - dom.content.innerHTML = this.content; - } - else { - throw new Error('Property "content" missing in item ' + this.data.id); +/** + * Remove a component from the controller + * @param {Component | String} component + */ +Controller.prototype.remove = function remove(component) { + var id; + for (id in this.components) { + if (this.components.hasOwnProperty(id)) { + if (id == component || this.components[id] == component) { + break; } - changed = true; - } - - // update class - var className = (this.data.className? ' ' + this.data.className : '') + - (this.selected ? ' selected' : ''); - if (this.className != className) { - this.className = className; - dom.box.className = 'item box' + className; - dom.line.className = 'item line' + className; - dom.dot.className = 'item dot' + className; - changed = true; } } - return changed; + if (id) { + delete this.components[id]; + } }; /** - * Show the item in the DOM (when not already visible). The items DOM will - * be created when needed. - * @return {Boolean} changed + * Request a reflow. The controller will schedule a reflow + * @param {Boolean} [force] If true, an immediate reflow is forced. Default + * is false. */ -ItemBox.prototype.show = function show() { - if (!this.dom || !this.dom.box.parentNode) { - return this.repaint(); +Controller.prototype.requestReflow = function requestReflow(force) { + if (force) { + this.reflow(); } else { - return false; + if (!this.reflowTimer) { + var me = this; + this.reflowTimer = setTimeout(function () { + me.reflowTimer = undefined; + me.reflow(); + }, 0); + } } }; /** - * Hide the item from the DOM (when visible) - * @return {Boolean} changed + * Request a repaint. The controller will schedule a repaint + * @param {Boolean} [force] If true, an immediate repaint is forced. Default + * is false. */ -ItemBox.prototype.hide = function hide() { - var changed = false, - dom = this.dom; - if (dom) { - if (dom.box.parentNode) { - dom.box.parentNode.removeChild(dom.box); - changed = true; - } - if (dom.line.parentNode) { - dom.line.parentNode.removeChild(dom.line); - } - if (dom.dot.parentNode) { - dom.dot.parentNode.removeChild(dom.dot); +Controller.prototype.requestRepaint = function requestRepaint(force) { + if (force) { + this.repaint(); + } + else { + if (!this.repaintTimer) { + var me = this; + this.repaintTimer = setTimeout(function () { + me.repaintTimer = undefined; + me.repaint(); + }, 0); } } - return changed; }; /** - * Reflow the item: calculate its actual size and position from the DOM - * @return {boolean} resized returns true if the axis is resized - * @override + * Repaint all components */ -ItemBox.prototype.reflow = function reflow() { - var changed = 0, - update, - dom, - props, - options, - margin, - start, - align, - orientation, - top, - left, - data, - range; - - if (this.data.start == undefined) { - throw new Error('Property "start" missing in item ' + this.data.id); - } +Controller.prototype.repaint = function repaint() { + var changed = false; - data = this.data; - range = this.parent && this.parent.range; - if (data && range) { - // TODO: account for the width of the item - var interval = (range.end - range.start); - this.visible = (data.start > range.start - interval) && (data.start < range.end + interval); - } - else { - this.visible = false; + // cancel any running repaint request + if (this.repaintTimer) { + clearTimeout(this.repaintTimer); + this.repaintTimer = undefined; } - if (this.visible) { - dom = this.dom; - if (dom) { - update = util.updateProperty; - props = this.props; - options = this.options; - start = this.parent.toScreen(this.data.start); - align = options.align || this.defaultOptions.align; - margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; - orientation = options.orientation || this.defaultOptions.orientation; - - changed += update(props.dot, 'height', dom.dot.offsetHeight); - changed += update(props.dot, 'width', dom.dot.offsetWidth); - changed += update(props.line, 'width', dom.line.offsetWidth); - changed += update(props.line, 'height', dom.line.offsetHeight); - changed += update(props.line, 'top', dom.line.offsetTop); - changed += update(this, 'width', dom.box.offsetWidth); - changed += update(this, 'height', dom.box.offsetHeight); - if (align == 'right') { - left = start - this.width; - } - else if (align == 'left') { - left = start; - } - else { - // default or 'center' - left = start - this.width / 2; - } - changed += update(this, 'left', left); - - changed += update(props.line, 'left', start - props.line.width / 2); - changed += update(props.dot, 'left', start - props.dot.width / 2); - changed += update(props.dot, 'top', -props.dot.height / 2); - if (orientation == 'top') { - top = margin; + var done = {}; - changed += update(this, 'top', top); + function repaint(component, id) { + if (!(id in done)) { + // first repaint the components on which this component is dependent + if (component.depends) { + component.depends.forEach(function (dep) { + repaint(dep, dep.id); + }); } - else { - // default or 'bottom' - var parentHeight = this.parent.height; - top = parentHeight - this.height - margin; - - changed += update(this, 'top', top); + if (component.parent) { + repaint(component.parent, component.parent.id); } - } - else { - changed += 1; + + // repaint the component itself and mark as done + changed = component.repaint() || changed; + done[id] = true; } } - return (changed > 0); + util.forEach(this.components, repaint); + + // immediately reflow when needed + if (changed) { + this.reflow(); + } + // TODO: limit the number of nested reflows/repaints, prevent loop }; /** - * Create an items DOM - * @private + * Reflow all components */ -ItemBox.prototype._create = function _create() { - var dom = this.dom; - if (!dom) { - this.dom = dom = {}; +Controller.prototype.reflow = function reflow() { + var resized = false; - // create the box - dom.box = document.createElement('DIV'); - // className is updated in repaint() + // cancel any running repaint request + if (this.reflowTimer) { + clearTimeout(this.reflowTimer); + this.reflowTimer = undefined; + } - // contents box (inside the background box). used for making margins - dom.content = document.createElement('DIV'); - dom.content.className = 'content'; - dom.box.appendChild(dom.content); + var done = {}; - // line to axis - dom.line = document.createElement('DIV'); - dom.line.className = 'line'; + function reflow(component, id) { + if (!(id in done)) { + // first reflow the components on which this component is dependent + if (component.depends) { + component.depends.forEach(function (dep) { + reflow(dep, dep.id); + }); + } + if (component.parent) { + reflow(component.parent, component.parent.id); + } - // dot on axis - dom.dot = document.createElement('DIV'); - dom.dot.className = 'dot'; + // reflow the component itself and mark as done + resized = component.reflow() || resized; + done[id] = true; + } + } + + util.forEach(this.components, reflow); + + // immediately repaint when needed + if (resized) { + this.repaint(); } + // TODO: limit the number of nested reflows/repaints, prevent loop }; /** - * Reposition the item, recalculate its left, top, and width, using the current - * range and size of the items itemset - * @override + * Prototype for visual components */ -ItemBox.prototype.reposition = function reposition() { - var dom = this.dom, - props = this.props, - orientation = this.options.orientation || this.defaultOptions.orientation; +function Component () { + this.id = null; + this.parent = null; + this.depends = null; + this.controller = null; + this.options = null; - if (dom) { - var box = dom.box, - line = dom.line, - dot = dom.dot; + this.frame = null; // main DOM element + this.top = 0; + this.left = 0; + this.width = 0; + this.height = 0; +} - box.style.left = this.left + 'px'; - box.style.top = this.top + 'px'; +/** + * Set parameters for the frame. Parameters will be merged in current parameter + * set. + * @param {Object} options Available parameters: + * {String | function} [className] + * {EventBus} [eventBus] + * {String | Number | function} [left] + * {String | Number | function} [top] + * {String | Number | function} [width] + * {String | Number | function} [height] + */ +Component.prototype.setOptions = function setOptions(options) { + if (options) { + util.extend(this.options, options); - line.style.left = props.line.left + 'px'; - if (orientation == 'top') { - line.style.top = 0 + 'px'; - line.style.height = this.top + 'px'; - } - else { - // orientation 'bottom' - line.style.top = (this.top + this.height) + 'px'; - line.style.height = Math.max(this.parent.height - this.top - this.height + - this.props.dot.height / 2, 0) + 'px'; + if (this.controller) { + this.requestRepaint(); + this.requestReflow(); } - - dot.style.left = props.dot.left + 'px'; - dot.style.top = props.dot.top + 'px'; } }; /** - * @constructor ItemPoint - * @extends Item - * @param {ItemSet} parent - * @param {Object} data Object containing parameters start - * content, className. - * @param {Object} [options] Options to set initial property values - * @param {Object} [defaultOptions] default options - * // TODO: describe available options + * Get an option value by name + * The function will first check this.options object, and else will check + * this.defaultOptions. + * @param {String} name + * @return {*} value */ -function ItemPoint (parent, data, options, defaultOptions) { - this.props = { - dot: { - top: 0, - width: 0, - height: 0 - }, - content: { - height: 0, - marginLeft: 0 - } - }; - - Item.call(this, parent, data, options, defaultOptions); -} - -ItemPoint.prototype = new Item (null, null); +Component.prototype.getOption = function getOption(name) { + var value; + if (this.options) { + value = this.options[name]; + } + if (value === undefined && this.defaultOptions) { + value = this.defaultOptions[name]; + } + return value; +}; /** - * Select the item - * @override + * Get the container element of the component, which can be used by a child to + * add its own widgets. Not all components do have a container for childs, in + * that case null is returned. + * @returns {HTMLElement | null} container */ -ItemPoint.prototype.select = function select() { - this.selected = true; - // TODO: select and unselect +// TODO: get rid of the getContainer and getFrame methods, provide these via the options +Component.prototype.getContainer = function getContainer() { + // should be implemented by the component + return null; }; /** - * Unselect the item - * @override + * Get the frame element of the component, the outer HTML DOM element. + * @returns {HTMLElement | null} frame */ -ItemPoint.prototype.unselect = function unselect() { - this.selected = false; - // TODO: select and unselect +Component.prototype.getFrame = function getFrame() { + return this.frame; }; /** - * Repaint the item + * Repaint the component * @return {Boolean} changed */ -ItemPoint.prototype.repaint = function repaint() { - // TODO: make an efficient repaint - var changed = false; - var dom = this.dom; - - if (!dom) { - this._create(); - dom = this.dom; - changed = true; - } - - if (dom) { - if (!this.parent) { - throw new Error('Cannot repaint item: no parent attached'); - } - var foreground = this.parent.getForeground(); - if (!foreground) { - throw new Error('Cannot repaint time axis: ' + - 'parent has no foreground container element'); - } - - if (!dom.point.parentNode) { - foreground.appendChild(dom.point); - foreground.appendChild(dom.point); - changed = true; - } - - // update contents - if (this.data.content != this.content) { - this.content = this.data.content; - if (this.content instanceof Element) { - dom.content.innerHTML = ''; - dom.content.appendChild(this.content); - } - else if (this.data.content != undefined) { - dom.content.innerHTML = this.content; - } - else { - throw new Error('Property "content" missing in item ' + this.data.id); - } - changed = true; - } - - // update class - var className = (this.data.className? ' ' + this.data.className : '') + - (this.selected ? ' selected' : ''); - if (this.className != className) { - this.className = className; - dom.point.className = 'item point' + className; - changed = true; - } - } +Component.prototype.repaint = function repaint() { + // should be implemented by the component + return false; +}; - return changed; +/** + * Reflow the component + * @return {Boolean} resized + */ +Component.prototype.reflow = function reflow() { + // should be implemented by the component + return false; }; /** - * Show the item in the DOM (when not already visible). The items DOM will - * be created when needed. + * Hide the component from the DOM * @return {Boolean} changed */ -ItemPoint.prototype.show = function show() { - if (!this.dom || !this.dom.point.parentNode) { - return this.repaint(); +Component.prototype.hide = function hide() { + if (this.frame && this.frame.parentNode) { + this.frame.parentNode.removeChild(this.frame); + return true; } else { return false; @@ -5722,7121 +7042,7626 @@ ItemPoint.prototype.show = function show() { }; /** - * Hide the item from the DOM (when visible) + * Show the component in the DOM (when not already visible). + * A repaint will be executed when the component is not visible * @return {Boolean} changed */ -ItemPoint.prototype.hide = function hide() { - var changed = false, - dom = this.dom; - if (dom) { - if (dom.point.parentNode) { - dom.point.parentNode.removeChild(dom.point); - changed = true; - } +Component.prototype.show = function show() { + if (!this.frame || !this.frame.parentNode) { + return this.repaint(); + } + else { + return false; } - return changed; }; /** - * Reflow the item: calculate its actual size from the DOM - * @return {boolean} resized returns true if the axis is resized - * @override + * Request a repaint. The controller will schedule a repaint */ -ItemPoint.prototype.reflow = function reflow() { - var changed = 0, - update, - dom, - props, - options, - margin, - orientation, - start, - top, - data, - range; - - if (this.data.start == undefined) { - throw new Error('Property "start" missing in item ' + this.data.id); - } - - data = this.data; - range = this.parent && this.parent.range; - if (data && range) { - // TODO: account for the width of the item - var interval = (range.end - range.start); - this.visible = (data.start > range.start - interval) && (data.start < range.end); +Component.prototype.requestRepaint = function requestRepaint() { + if (this.controller) { + this.controller.requestRepaint(); } else { - this.visible = false; - } - - if (this.visible) { - dom = this.dom; - if (dom) { - update = util.updateProperty; - props = this.props; - options = this.options; - orientation = options.orientation || this.defaultOptions.orientation; - margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; - start = this.parent.toScreen(this.data.start); - - changed += update(this, 'width', dom.point.offsetWidth); - changed += update(this, 'height', dom.point.offsetHeight); - changed += update(props.dot, 'width', dom.dot.offsetWidth); - changed += update(props.dot, 'height', dom.dot.offsetHeight); - changed += update(props.content, 'height', dom.content.offsetHeight); - - if (orientation == 'top') { - top = margin; - } - else { - // default or 'bottom' - var parentHeight = this.parent.height; - top = Math.max(parentHeight - this.height - margin, 0); - } - changed += update(this, 'top', top); - changed += update(this, 'left', start - props.dot.width / 2); - changed += update(props.content, 'marginLeft', 1.5 * props.dot.width); - //changed += update(props.content, 'marginRight', 0.5 * props.dot.width); // TODO - - changed += update(props.dot, 'top', (this.height - props.dot.height) / 2); - } - else { - changed += 1; - } + throw new Error('Cannot request a repaint: no controller configured'); + // TODO: just do a repaint when no parent is configured? } - - return (changed > 0); }; /** - * Create an items DOM - * @private + * Request a reflow. The controller will schedule a reflow */ -ItemPoint.prototype._create = function _create() { - var dom = this.dom; - if (!dom) { - this.dom = dom = {}; - - // background box - dom.point = document.createElement('div'); - // className is updated in repaint() - - // contents box, right from the dot - dom.content = document.createElement('div'); - dom.content.className = 'content'; - dom.point.appendChild(dom.content); - - // dot at start - dom.dot = document.createElement('div'); - dom.dot.className = 'dot'; - dom.point.appendChild(dom.dot); +Component.prototype.requestReflow = function requestReflow() { + if (this.controller) { + this.controller.requestReflow(); } -}; - -/** - * Reposition the item, recalculate its left, top, and width, using the current - * range and size of the items itemset - * @override - */ -ItemPoint.prototype.reposition = function reposition() { - var dom = this.dom, - props = this.props; - - if (dom) { - dom.point.style.top = this.top + 'px'; - dom.point.style.left = this.left + 'px'; - - dom.content.style.marginLeft = props.content.marginLeft + 'px'; - //dom.content.style.marginRight = props.content.marginRight + 'px'; // TODO - - dom.dot.style.top = props.dot.top + 'px'; + else { + throw new Error('Cannot request a reflow: no controller configured'); + // TODO: just do a reflow when no parent is configured? } }; /** - * @constructor ItemRange - * @extends Item - * @param {ItemSet} parent - * @param {Object} data Object containing parameters start, end - * content, className. - * @param {Object} [options] Options to set initial property values - * @param {Object} [defaultOptions] default options - * // TODO: describe available options + * A panel can contain components + * @param {Component} [parent] + * @param {Component[]} [depends] Components on which this components depends + * (except for the parent) + * @param {Object} [options] Available parameters: + * {String | Number | function} [left] + * {String | Number | function} [top] + * {String | Number | function} [width] + * {String | Number | function} [height] + * {String | function} [className] + * @constructor Panel + * @extends Component */ -function ItemRange (parent, data, options, defaultOptions) { - this.props = { - content: { - left: 0, - width: 0 - } - }; +function Panel(parent, depends, options) { + this.id = util.randomUUID(); + this.parent = parent; + this.depends = depends; - Item.call(this, parent, data, options, defaultOptions); + this.options = options || {}; } -ItemRange.prototype = new Item (null, null); +Panel.prototype = new Component(); /** - * Select the item - * @override + * Set options. Will extend the current options. + * @param {Object} [options] Available parameters: + * {String | function} [className] + * {String | Number | function} [left] + * {String | Number | function} [top] + * {String | Number | function} [width] + * {String | Number | function} [height] */ -ItemRange.prototype.select = function select() { - this.selected = true; - // TODO: select and unselect -}; +Panel.prototype.setOptions = Component.prototype.setOptions; /** - * Unselect the item - * @override + * Get the container element of the panel, which can be used by a child to + * add its own widgets. + * @returns {HTMLElement} container */ -ItemRange.prototype.unselect = function unselect() { - this.selected = false; - // TODO: select and unselect +Panel.prototype.getContainer = function () { + return this.frame; }; /** - * Repaint the item + * Repaint the component * @return {Boolean} changed */ -ItemRange.prototype.repaint = function repaint() { - // TODO: make an efficient repaint - var changed = false; - var dom = this.dom; - - if (!dom) { - this._create(); - dom = this.dom; - changed = true; - } - - if (dom) { - if (!this.parent) { - throw new Error('Cannot repaint item: no parent attached'); - } - var foreground = this.parent.getForeground(); - if (!foreground) { - throw new Error('Cannot repaint time axis: ' + - 'parent has no foreground container element'); - } - - if (!dom.box.parentNode) { - foreground.appendChild(dom.box); - changed = true; - } +Panel.prototype.repaint = function () { + var changed = 0, + update = util.updateProperty, + asSize = util.option.asSize, + options = this.options, + frame = this.frame; + if (!frame) { + frame = document.createElement('div'); + frame.className = 'panel'; - // update content - if (this.data.content != this.content) { - this.content = this.data.content; - if (this.content instanceof Element) { - dom.content.innerHTML = ''; - dom.content.appendChild(this.content); - } - else if (this.data.content != undefined) { - dom.content.innerHTML = this.content; + var className = options.className; + if (className) { + if (typeof className == 'function') { + util.addClassName(frame, String(className())); } else { - throw new Error('Property "content" missing in item ' + this.data.id); + util.addClassName(frame, String(className)); } - changed = true; } - // update class - var className = this.data.className ? ('' + this.data.className) : ''; - if (this.className != className) { - this.className = className; - dom.box.className = 'item range' + className; - changed = true; + this.frame = frame; + changed += 1; + } + if (!frame.parentNode) { + if (!this.parent) { + throw new Error('Cannot repaint panel: no parent attached'); + } + var parentContainer = this.parent.getContainer(); + if (!parentContainer) { + throw new Error('Cannot repaint panel: parent has no container element'); } + parentContainer.appendChild(frame); + changed += 1; } - return changed; + changed += update(frame.style, 'top', asSize(options.top, '0px')); + changed += update(frame.style, 'left', asSize(options.left, '0px')); + changed += update(frame.style, 'width', asSize(options.width, '100%')); + changed += update(frame.style, 'height', asSize(options.height, '100%')); + + return (changed > 0); }; /** - * Show the item in the DOM (when not already visible). The items DOM will - * be created when needed. - * @return {Boolean} changed + * Reflow the component + * @return {Boolean} resized */ -ItemRange.prototype.show = function show() { - if (!this.dom || !this.dom.box.parentNode) { - return this.repaint(); +Panel.prototype.reflow = function () { + var changed = 0, + update = util.updateProperty, + frame = this.frame; + + if (frame) { + changed += update(this, 'top', frame.offsetTop); + changed += update(this, 'left', frame.offsetLeft); + changed += update(this, 'width', frame.offsetWidth); + changed += update(this, 'height', frame.offsetHeight); } else { - return false; + changed += 1; } + + return (changed > 0); }; /** - * Hide the item from the DOM (when visible) + * A root panel can hold components. The root panel must be initialized with + * a DOM element as container. + * @param {HTMLElement} container + * @param {Object} [options] Available parameters: see RootPanel.setOptions. + * @constructor RootPanel + * @extends Panel + */ +function RootPanel(container, options) { + this.id = util.randomUUID(); + this.container = container; + + this.options = options || {}; + this.defaultOptions = { + autoResize: true + }; + + this.listeners = {}; // event listeners +} + +RootPanel.prototype = new Panel(); + +/** + * Set options. Will extend the current options. + * @param {Object} [options] Available parameters: + * {String | function} [className] + * {String | Number | function} [left] + * {String | Number | function} [top] + * {String | Number | function} [width] + * {String | Number | function} [height] + * {Boolean | function} [autoResize] + */ +RootPanel.prototype.setOptions = Component.prototype.setOptions; + +/** + * Repaint the component * @return {Boolean} changed */ -ItemRange.prototype.hide = function hide() { - var changed = false, - dom = this.dom; - if (dom) { - if (dom.box.parentNode) { - dom.box.parentNode.removeChild(dom.box); - changed = true; +RootPanel.prototype.repaint = function () { + var changed = 0, + update = util.updateProperty, + asSize = util.option.asSize, + options = this.options, + frame = this.frame; + + if (!frame) { + frame = document.createElement('div'); + frame.className = 'vis timeline rootpanel'; + + var className = options.className; + if (className) { + util.addClassName(frame, util.option.asString(className)); } + + this.frame = frame; + + changed += 1; } - return changed; + if (!frame.parentNode) { + if (!this.container) { + throw new Error('Cannot repaint root panel: no container attached'); + } + this.container.appendChild(frame); + changed += 1; + } + + changed += update(frame.style, 'top', asSize(options.top, '0px')); + changed += update(frame.style, 'left', asSize(options.left, '0px')); + changed += update(frame.style, 'width', asSize(options.width, '100%')); + changed += update(frame.style, 'height', asSize(options.height, '100%')); + + this._updateEventEmitters(); + this._updateWatch(); + + return (changed > 0); }; /** - * Reflow the item: calculate its actual size from the DOM - * @return {boolean} resized returns true if the axis is resized - * @override + * Reflow the component + * @return {Boolean} resized */ -ItemRange.prototype.reflow = function reflow() { +RootPanel.prototype.reflow = function () { var changed = 0, - dom, - props, - options, - margin, - padding, - parent, - start, - end, - data, - range, - update, - box, - parentWidth, - contentLeft, - orientation, - top; + update = util.updateProperty, + frame = this.frame; - if (this.data.start == undefined) { - throw new Error('Property "start" missing in item ' + this.data.id); + if (frame) { + changed += update(this, 'top', frame.offsetTop); + changed += update(this, 'left', frame.offsetLeft); + changed += update(this, 'width', frame.offsetWidth); + changed += update(this, 'height', frame.offsetHeight); } - if (this.data.end == undefined) { - throw new Error('Property "end" missing in item ' + this.data.id); + else { + changed += 1; } - data = this.data; - range = this.parent && this.parent.range; - if (data && range) { - // TODO: account for the width of the item. Take some margin - this.visible = (data.start < range.end) && (data.end > range.start); + return (changed > 0); +}; + +/** + * Update watching for resize, depending on the current option + * @private + */ +RootPanel.prototype._updateWatch = function () { + var autoResize = this.getOption('autoResize'); + if (autoResize) { + this._watch(); } else { - this.visible = false; + this._unwatch(); } +}; - if (this.visible) { - dom = this.dom; - if (dom) { - props = this.props; - options = this.options; - parent = this.parent; - start = parent.toScreen(this.data.start); - end = parent.toScreen(this.data.end); - update = util.updateProperty; - box = dom.box; - parentWidth = parent.width; - orientation = options.orientation || this.defaultOptions.orientation; - margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; - padding = options.padding || this.defaultOptions.padding; - - changed += update(props.content, 'width', dom.content.offsetWidth); - - changed += update(this, 'height', box.offsetHeight); +/** + * Watch for changes in the size of the frame. On resize, the Panel will + * automatically redraw itself. + * @private + */ +RootPanel.prototype._watch = function () { + var me = this; - // limit the width of the this, as browsers cannot draw very wide divs - if (start < -parentWidth) { - start = -parentWidth; - } - if (end > 2 * parentWidth) { - end = 2 * parentWidth; - } + this._unwatch(); - // when range exceeds left of the window, position the contents at the left of the visible area - if (start < 0) { - contentLeft = Math.min(-start, - (end - start - props.content.width - 2 * padding)); - // TODO: remove the need for options.padding. it's terrible. - } - else { - contentLeft = 0; - } - changed += update(props.content, 'left', contentLeft); + var checkSize = function () { + var autoResize = me.getOption('autoResize'); + if (!autoResize) { + // stop watching when the option autoResize is changed to false + me._unwatch(); + return; + } - if (orientation == 'top') { - top = margin; - changed += update(this, 'top', top); - } - else { - // default or 'bottom' - top = parent.height - this.height - margin; - changed += update(this, 'top', top); + if (me.frame) { + // check whether the frame is resized + if ((me.frame.clientWidth != me.width) || + (me.frame.clientHeight != me.height)) { + me.requestReflow(); } - - changed += update(this, 'left', start); - changed += update(this, 'width', Math.max(end - start, 1)); // TODO: reckon with border width; - } - else { - changed += 1; } - } + }; + + // TODO: automatically cleanup the event listener when the frame is deleted + util.addEventListener(window, 'resize', checkSize); - return (changed > 0); + this.watchTimer = setInterval(checkSize, 1000); }; /** - * Create an items DOM + * Stop watching for a resize of the frame. * @private */ -ItemRange.prototype._create = function _create() { - var dom = this.dom; - if (!dom) { - this.dom = dom = {}; - // background box - dom.box = document.createElement('div'); - // className is updated in repaint() - - // contents box - dom.content = document.createElement('div'); - dom.content.className = 'content'; - dom.box.appendChild(dom.content); +RootPanel.prototype._unwatch = function () { + if (this.watchTimer) { + clearInterval(this.watchTimer); + this.watchTimer = undefined; } + + // TODO: remove event listener on window.resize }; /** - * Reposition the item, recalculate its left, top, and width, using the current - * range and size of the items itemset - * @override + * Event handler + * @param {String} event name of the event, for example 'click', 'mousemove' + * @param {function} callback callback handler, invoked with the raw HTML Event + * as parameter. */ -ItemRange.prototype.reposition = function reposition() { - var dom = this.dom, - props = this.props; +RootPanel.prototype.on = function (event, callback) { + // register the listener at this component + var arr = this.listeners[event]; + if (!arr) { + arr = []; + this.listeners[event] = arr; + } + arr.push(callback); - if (dom) { - dom.box.style.top = this.top + 'px'; - dom.box.style.left = this.left + 'px'; - dom.box.style.width = this.width + 'px'; + this._updateEventEmitters(); +}; - dom.content.style.left = props.content.left + 'px'; +/** + * Update the event listeners for all event emitters + * @private + */ +RootPanel.prototype._updateEventEmitters = function () { + if (this.listeners) { + var me = this; + util.forEach(this.listeners, function (listeners, event) { + if (!me.emitters) { + me.emitters = {}; + } + if (!(event in me.emitters)) { + // create event + var frame = me.frame; + if (frame) { + //console.log('Created a listener for event ' + event + ' on component ' + me.id); // TODO: cleanup logging + var callback = function(event) { + listeners.forEach(function (listener) { + // TODO: filter on event target! + listener(event); + }); + }; + me.emitters[event] = callback; + util.addEventListener(frame, event, callback); + } + } + }); + + // TODO: be able to delete event listeners + // TODO: be able to move event listeners to a parent when available } }; /** - * @constructor Group - * @param {GroupSet} parent - * @param {Number | String} groupId - * @param {Object} [options] Options to set initial property values - * // TODO: describe available options + * A horizontal time axis + * @param {Component} parent + * @param {Component[]} [depends] Components on which this components depends + * (except for the parent) + * @param {Object} [options] See TimeAxis.setOptions for the available + * options. + * @constructor TimeAxis * @extends Component */ -function Group (parent, groupId, options) { +function TimeAxis (parent, depends, options) { this.id = util.randomUUID(); this.parent = parent; + this.depends = depends; - this.groupId = groupId; - this.itemsData = null; // DataSet - this.itemset = null; // ItemSet - this.options = options || {}; - this.options.top = 0; - - this.props = { - label: { - width: 0, - height: 0 + this.dom = { + majorLines: [], + majorTexts: [], + minorLines: [], + minorTexts: [], + redundant: { + majorLines: [], + majorTexts: [], + minorLines: [], + minorTexts: [] } }; + this.props = { + range: { + start: 0, + end: 0, + minimumStep: 0 + }, + lineTop: 0 + }; - this.top = 0; - this.left = 0; - this.width = 0; - this.height = 0; + this.options = options || {}; + this.defaultOptions = { + orientation: 'bottom', // supported: 'top', 'bottom' + // TODO: implement timeaxis orientations 'left' and 'right' + showMinorLabels: true, + showMajorLabels: true + }; + + this.conversion = null; + this.range = null; } -Group.prototype = new Component(); +TimeAxis.prototype = new Component(); -// TODO: comment -Group.prototype.setOptions = Component.prototype.setOptions; +// TODO: comment options +TimeAxis.prototype.setOptions = Component.prototype.setOptions; /** - * Get the container element of the panel, which can be used by a child to - * add its own widgets. - * @returns {HTMLElement} container + * Set a range (start and end) + * @param {Range | Object} range A Range or an object containing start and end. */ -Group.prototype.getContainer = function () { - return this.parent.getContainer(); +TimeAxis.prototype.setRange = function (range) { + if (!(range instanceof Range) && (!range || !range.start || !range.end)) { + throw new TypeError('Range must be an instance of Range, ' + + 'or an object containing start and end.'); + } + this.range = range; }; /** - * Set item set for the group. The group will create a view on the itemset, - * filtered by the groups id. - * @param {DataSet | DataView} items + * Convert a position on screen (pixels) to a datetime + * @param {int} x Position on the screen in pixels + * @return {Date} time The datetime the corresponds with given position x */ -Group.prototype.setItems = function setItems(items) { - if (this.itemset) { - // remove current item set - this.itemset.hide(); - this.itemset.setItems(); +TimeAxis.prototype.toTime = function(x) { + var conversion = this.conversion; + return new Date(x / conversion.factor + conversion.offset); +}; - this.parent.controller.remove(this.itemset); - this.itemset = null; +/** + * Convert a datetime (Date object) into a position on the screen + * @param {Date} time A date + * @return {int} x The position on the screen in pixels which corresponds + * with the given date. + * @private + */ +TimeAxis.prototype.toScreen = function(time) { + var conversion = this.conversion; + return (time.valueOf() - conversion.offset) * conversion.factor; +}; + +/** + * Repaint the component + * @return {Boolean} changed + */ +TimeAxis.prototype.repaint = function () { + var changed = 0, + update = util.updateProperty, + asSize = util.option.asSize, + options = this.options, + orientation = this.getOption('orientation'), + props = this.props, + step = this.step; + + var frame = this.frame; + if (!frame) { + frame = document.createElement('div'); + this.frame = frame; + changed += 1; + } + frame.className = 'axis ' + orientation; + // TODO: custom className? + + if (!frame.parentNode) { + if (!this.parent) { + throw new Error('Cannot repaint time axis: no parent attached'); + } + var parentContainer = this.parent.getContainer(); + if (!parentContainer) { + throw new Error('Cannot repaint time axis: parent has no container element'); + } + parentContainer.appendChild(frame); + + changed += 1; } - if (items) { - var groupId = this.groupId; + var parent = frame.parentNode; + if (parent) { + var beforeChild = frame.nextSibling; + parent.removeChild(frame); // take frame offline while updating (is almost twice as fast) + + var defaultTop = (orientation == 'bottom' && this.props.parentHeight && this.height) ? + (this.props.parentHeight - this.height) + 'px' : + '0px'; + changed += update(frame.style, 'top', asSize(options.top, defaultTop)); + changed += update(frame.style, 'left', asSize(options.left, '0px')); + changed += update(frame.style, 'width', asSize(options.width, '100%')); + changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); + + // get characters width and height + this._repaintMeasureChars(); + + if (this.step) { + this._repaintStart(); + + step.first(); + var xFirstMajorLabel = undefined; + var max = 0; + while (step.hasNext() && max < 1000) { + max++; + var cur = step.getCurrent(), + x = this.toScreen(cur), + isMajor = step.isMajor(); + + // TODO: lines must have a width, such that we can create css backgrounds + + if (this.getOption('showMinorLabels')) { + this._repaintMinorText(x, step.getLabelMinor()); + } + + if (isMajor && this.getOption('showMajorLabels')) { + if (x > 0) { + if (xFirstMajorLabel == undefined) { + xFirstMajorLabel = x; + } + this._repaintMajorText(x, step.getLabelMajor()); + } + this._repaintMajorLine(x); + } + else { + this._repaintMinorLine(x); + } + + step.next(); + } - var itemsetOptions = Object.create(this.options); - this.itemset = new ItemSet(this, null, itemsetOptions); - this.itemset.setRange(this.parent.range); + // create a major label on the left when needed + if (this.getOption('showMajorLabels')) { + var leftTime = this.toTime(0), + leftText = step.getLabelMajor(leftTime), + widthText = leftText.length * (props.majorCharWidth || 10) + 10; // upper bound estimation - this.view = new DataView(items, { - filter: function (item) { - return item.group == groupId; + if (xFirstMajorLabel == undefined || widthText < xFirstMajorLabel) { + this._repaintMajorText(0, leftText); + } } - }); - this.itemset.setItems(this.view); - this.parent.controller.add(this.itemset); + this._repaintEnd(); + } + + this._repaintLine(); + + // put frame online again + if (beforeChild) { + parent.insertBefore(frame, beforeChild); + } + else { + parent.appendChild(frame) + } } + + return (changed > 0); }; /** - * Repaint the item - * @return {Boolean} changed + * Start a repaint. Move all DOM elements to a redundant list, where they + * can be picked for re-use, or can be cleaned up in the end + * @private */ -Group.prototype.repaint = function repaint() { - return false; +TimeAxis.prototype._repaintStart = function () { + var dom = this.dom, + redundant = dom.redundant; + + redundant.majorLines = dom.majorLines; + redundant.majorTexts = dom.majorTexts; + redundant.minorLines = dom.minorLines; + redundant.minorTexts = dom.minorTexts; + + dom.majorLines = []; + dom.majorTexts = []; + dom.minorLines = []; + dom.minorTexts = []; }; /** - * Reflow the item - * @return {Boolean} resized + * End a repaint. Cleanup leftover DOM elements in the redundant list + * @private */ -Group.prototype.reflow = function reflow() { - var changed = 0, - update = util.updateProperty; +TimeAxis.prototype._repaintEnd = function () { + util.forEach(this.dom.redundant, function (arr) { + while (arr.length) { + var elem = arr.pop(); + if (elem && elem.parentNode) { + elem.parentNode.removeChild(elem); + } + } + }); +}; - changed += update(this, 'top', this.itemset ? this.itemset.top : 0); - changed += update(this, 'height', this.itemset ? this.itemset.height : 0); - // TODO: reckon with the height of the group label +/** + * Create a minor label for the axis at position x + * @param {Number} x + * @param {String} text + * @private + */ +TimeAxis.prototype._repaintMinorText = function (x, text) { + // reuse redundant label + var label = this.dom.redundant.minorTexts.shift(); - if (this.label) { - var inner = this.label.firstChild; - changed += update(this.props.label, 'width', inner.clientWidth); - changed += update(this.props.label, 'height', inner.clientHeight); - } - else { - changed += update(this.props.label, 'width', 0); - changed += update(this.props.label, 'height', 0); + if (!label) { + // create new label + var content = document.createTextNode(''); + label = document.createElement('div'); + label.appendChild(content); + label.className = 'text minor'; + this.frame.appendChild(label); } + this.dom.minorTexts.push(label); - return (changed > 0); + label.childNodes[0].nodeValue = text; + label.style.left = x + 'px'; + label.style.top = this.props.minorLabelTop + 'px'; + //label.title = title; // TODO: this is a heavy operation }; /** - * An GroupSet holds a set of groups - * @param {Component} parent - * @param {Component[]} [depends] Components on which this components depends - * (except for the parent) - * @param {Object} [options] See GroupSet.setOptions for the available - * options. - * @constructor GroupSet - * @extends Panel + * Create a Major label for the axis at position x + * @param {Number} x + * @param {String} text + * @private */ -function GroupSet(parent, depends, options) { - this.id = util.randomUUID(); - this.parent = parent; - this.depends = depends; - - this.options = options || {}; - - this.range = null; // Range or Object {start: number, end: number} - this.itemsData = null; // DataSet with items - this.groupsData = null; // DataSet with groups - - this.groups = {}; // map with groups +TimeAxis.prototype._repaintMajorText = function (x, text) { + // reuse redundant label + var label = this.dom.redundant.majorTexts.shift(); - this.dom = {}; - this.props = { - labels: { - width: 0 - } - }; + if (!label) { + // create label + var content = document.createTextNode(text); + label = document.createElement('div'); + label.className = 'text major'; + label.appendChild(content); + this.frame.appendChild(label); + } + this.dom.majorTexts.push(label); - // TODO: implement right orientation of the labels + label.childNodes[0].nodeValue = text; + label.style.top = this.props.majorLabelTop + 'px'; + label.style.left = x + 'px'; + //label.title = title; // TODO: this is a heavy operation +}; - // changes in groups are queued key/value map containing id/action - this.queue = {}; +/** + * Create a minor line for the axis at position x + * @param {Number} x + * @private + */ +TimeAxis.prototype._repaintMinorLine = function (x) { + // reuse redundant line + var line = this.dom.redundant.minorLines.shift(); - var me = this; - this.listeners = { - 'add': function (event, params) { - me._onAdd(params.items); - }, - 'update': function (event, params) { - me._onUpdate(params.items); - }, - 'remove': function (event, params) { - me._onRemove(params.items); - } - }; -} + if (!line) { + // create vertical line + line = document.createElement('div'); + line.className = 'grid vertical minor'; + this.frame.appendChild(line); + } + this.dom.minorLines.push(line); -GroupSet.prototype = new Panel(); + var props = this.props; + line.style.top = props.minorLineTop + 'px'; + line.style.height = props.minorLineHeight + 'px'; + line.style.left = (x - props.minorLineWidth / 2) + 'px'; +}; /** - * Set options for the GroupSet. Existing options will be extended/overwritten. - * @param {Object} [options] The following options are available: - * {String | function} groupsOrder - * TODO: describe options + * Create a Major line for the axis at position x + * @param {Number} x + * @private */ -GroupSet.prototype.setOptions = Component.prototype.setOptions; +TimeAxis.prototype._repaintMajorLine = function (x) { + // reuse redundant line + var line = this.dom.redundant.majorLines.shift(); -GroupSet.prototype.setRange = function (range) { - // TODO: implement setRange + if (!line) { + // create vertical line + line = document.createElement('DIV'); + line.className = 'grid vertical major'; + this.frame.appendChild(line); + } + this.dom.majorLines.push(line); + + var props = this.props; + line.style.top = props.majorLineTop + 'px'; + line.style.left = (x - props.majorLineWidth / 2) + 'px'; + line.style.height = props.majorLineHeight + 'px'; }; + /** - * Set items - * @param {vis.DataSet | null} items + * Repaint the horizontal line for the axis + * @private */ -GroupSet.prototype.setItems = function setItems(items) { - this.itemsData = items; +TimeAxis.prototype._repaintLine = function() { + var line = this.dom.line, + frame = this.frame, + options = this.options; - for (var id in this.groups) { - if (this.groups.hasOwnProperty(id)) { - var group = this.groups[id]; - group.setItems(items); + // line before all axis elements + if (this.getOption('showMinorLabels') || this.getOption('showMajorLabels')) { + if (line) { + // put this line at the end of all childs + frame.removeChild(line); + frame.appendChild(line); + } + else { + // create the axis line + line = document.createElement('div'); + line.className = 'grid horizontal major'; + frame.appendChild(line); + this.dom.line = line; + } + + line.style.top = this.props.lineTop + 'px'; + } + else { + if (line && axis.parentElement) { + frame.removeChild(axis.line); + delete this.dom.line; } } }; /** - * Get items - * @return {vis.DataSet | null} items - */ -GroupSet.prototype.getItems = function getItems() { - return this.itemsData; -}; - -/** - * Set range (start and end). - * @param {Range | Object} range A Range or an object containing start and end. - */ -GroupSet.prototype.setRange = function setRange(range) { - this.range = range; -}; - -/** - * Set groups - * @param {vis.DataSet} groups + * Create characters used to determine the size of text on the axis + * @private */ -GroupSet.prototype.setGroups = function setGroups(groups) { - var me = this, - ids; - - // unsubscribe from current dataset - if (this.groupsData) { - util.forEach(this.listeners, function (callback, event) { - me.groupsData.unsubscribe(event, callback); - }); +TimeAxis.prototype._repaintMeasureChars = function () { + // calculate the width and height of a single character + // this is used to calculate the step size, and also the positioning of the + // axis + var dom = this.dom, + text; - // remove all drawn groups - ids = this.groupsData.getIds(); - this._onRemove(ids); - } + if (!dom.measureCharMinor) { + text = document.createTextNode('0'); + var measureCharMinor = document.createElement('DIV'); + measureCharMinor.className = 'text minor measure'; + measureCharMinor.appendChild(text); + this.frame.appendChild(measureCharMinor); - // replace the dataset - if (!groups) { - this.groupsData = null; - } - else if (groups instanceof DataSet) { - this.groupsData = groups; - } - else { - this.groupsData = new DataSet({ - convert: { - start: 'Date', - end: 'Date' - } - }); - this.groupsData.add(groups); + dom.measureCharMinor = measureCharMinor; } - if (this.groupsData) { - // subscribe to new dataset - var id = this.id; - util.forEach(this.listeners, function (callback, event) { - me.groupsData.subscribe(event, callback, id); - }); + if (!dom.measureCharMajor) { + text = document.createTextNode('0'); + var measureCharMajor = document.createElement('DIV'); + measureCharMajor.className = 'text major measure'; + measureCharMajor.appendChild(text); + this.frame.appendChild(measureCharMajor); - // draw all new groups - ids = this.groupsData.getIds(); - this._onAdd(ids); + dom.measureCharMajor = measureCharMajor; } }; /** - * Get groups - * @return {vis.DataSet | null} groups - */ -GroupSet.prototype.getGroups = function getGroups() { - return this.groupsData; -}; - -/** - * Repaint the component - * @return {Boolean} changed + * Reflow the component + * @return {Boolean} resized */ -GroupSet.prototype.repaint = function repaint() { +TimeAxis.prototype.reflow = function () { var changed = 0, - i, id, group, label, update = util.updateProperty, - asSize = util.option.asSize, - asElement = util.option.asElement, - options = this.options, - frame = this.dom.frame, - labels = this.dom.labels; + frame = this.frame, + range = this.range; - // create frame - if (!this.parent) { - throw new Error('Cannot repaint groupset: no parent attached'); - } - var parentContainer = this.parent.getContainer(); - if (!parentContainer) { - throw new Error('Cannot repaint groupset: parent has no container element'); + if (!range) { + throw new Error('Cannot repaint time axis: no range configured'); } - if (!frame) { - frame = document.createElement('div'); - frame.className = 'groupset'; - this.dom.frame = frame; - - var className = options.className; - if (className) { - util.addClassName(frame, util.option.asString(className)); - } - changed += 1; - } - if (!frame.parentNode) { - parentContainer.appendChild(frame); - changed += 1; - } + if (frame) { + changed += update(this, 'top', frame.offsetTop); + changed += update(this, 'left', frame.offsetLeft); - // create labels - var labelContainer = asElement(options.labelContainer); - if (!labelContainer) { - throw new Error('Cannot repaint groupset: option "labelContainer" not defined'); - } - if (!labels) { - labels = document.createElement('div'); - labels.className = 'labels'; - //frame.appendChild(labels); - this.dom.labels = labels; - } - if (!labels.parentNode || labels.parentNode != labelContainer) { - if (labels.parentNode) { - labels.parentNode.removeChild(labels.parentNode); + // calculate size of a character + var props = this.props, + showMinorLabels = this.getOption('showMinorLabels'), + showMajorLabels = this.getOption('showMajorLabels'), + measureCharMinor = this.dom.measureCharMinor, + measureCharMajor = this.dom.measureCharMajor; + if (measureCharMinor) { + props.minorCharHeight = measureCharMinor.clientHeight; + props.minorCharWidth = measureCharMinor.clientWidth; + } + if (measureCharMajor) { + props.majorCharHeight = measureCharMajor.clientHeight; + props.majorCharWidth = measureCharMajor.clientWidth; } - labelContainer.appendChild(labels); - } - - // reposition frame - changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); - changed += update(frame.style, 'top', asSize(options.top, '0px')); - changed += update(frame.style, 'left', asSize(options.left, '0px')); - changed += update(frame.style, 'width', asSize(options.width, '100%')); - - // reposition labels - changed += update(labels.style, 'top', asSize(options.top, '0px')); - var me = this, - queue = this.queue, - groups = this.groups, - groupsData = this.groupsData; + var parentHeight = frame.parentNode ? frame.parentNode.offsetHeight : 0; + if (parentHeight != props.parentHeight) { + props.parentHeight = parentHeight; + changed += 1; + } + switch (this.getOption('orientation')) { + case 'bottom': + props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; + props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; - // show/hide added/changed/removed groups - var ids = Object.keys(queue); - if (ids.length) { - ids.forEach(function (id) { - var action = queue[id]; - var group = groups[id]; + props.minorLabelTop = 0; + props.majorLabelTop = props.minorLabelTop + props.minorLabelHeight; - //noinspection FallthroughInSwitchStatementJS - switch (action) { - case 'add': - case 'update': - if (!group) { - var groupOptions = Object.create(me.options); - group = new Group(me, id, groupOptions); - group.setItems(me.itemsData); // attach items data - groups[id] = group; + props.minorLineTop = -this.top; + props.minorLineHeight = Math.max(this.top + props.majorLabelHeight, 0); + props.minorLineWidth = 1; // TODO: really calculate width - me.controller.add(group); - } + props.majorLineTop = -this.top; + props.majorLineHeight = Math.max(this.top + props.minorLabelHeight + props.majorLabelHeight, 0); + props.majorLineWidth = 1; // TODO: really calculate width - // TODO: update group data - group.data = groupsData.get(id); + props.lineTop = 0; - delete queue[id]; - break; + break; - case 'remove': - if (group) { - group.setItems(); // detach items data - delete groups[id]; + case 'top': + props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; + props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; - me.controller.remove(group); - } + props.majorLabelTop = 0; + props.minorLabelTop = props.majorLabelTop + props.majorLabelHeight; - // update lists - delete queue[id]; - break; + props.minorLineTop = props.minorLabelTop; + props.minorLineHeight = Math.max(parentHeight - props.majorLabelHeight - this.top); + props.minorLineWidth = 1; // TODO: really calculate width - default: - console.log('Error: unknown action "' + action + '"'); - } - }); + props.majorLineTop = 0; + props.majorLineHeight = Math.max(parentHeight - this.top); + props.majorLineWidth = 1; // TODO: really calculate width - // the groupset depends on each of the groups - //this.depends = this.groups; // TODO: gives a circular reference through the parent + props.lineTop = props.majorLabelHeight + props.minorLabelHeight; - // TODO: apply dependencies of the groupset + break; - // update the top positions of the groups in the correct order - var orderedGroups = this.groupsData.getIds({ - order: this.options.groupsOrder - }); - for (i = 0; i < orderedGroups.length; i++) { - (function (group, prevGroup) { - var top = 0; - if (prevGroup) { - top = function () { - // TODO: top must reckon with options.maxHeight - return prevGroup.top + prevGroup.height; - } - } - group.setOptions({ - top: top - }); - })(groups[orderedGroups[i]], groups[orderedGroups[i - 1]]); + default: + throw new Error('Unkown orientation "' + this.getOption('orientation') + '"'); } - // (re)create the labels - while (labels.firstChild) { - labels.removeChild(labels.firstChild); - } - for (i = 0; i < orderedGroups.length; i++) { - id = orderedGroups[i]; - label = this._createLabel(id); - labels.appendChild(label); - } + var height = props.minorLabelHeight + props.majorLabelHeight; + changed += update(this, 'width', frame.offsetWidth); + changed += update(this, 'height', height); - changed++; - } + // calculate range and step + this._updateConversion(); - // reposition the labels - // TODO: labels are not displayed correctly when orientation=='top' - // TODO: width of labelPanel is not immediately updated on a change in groups - for (id in groups) { - if (groups.hasOwnProperty(id)) { - group = groups[id]; - label = group.label; - if (label) { - label.style.top = group.top + 'px'; - label.style.height = group.height + 'px'; - } - } + var start = util.convert(range.start, 'Date'), + end = util.convert(range.end, 'Date'), + minimumStep = this.toTime((props.minorCharWidth || 10) * 5) - this.toTime(0); + this.step = new TimeStep(start, end, minimumStep); + changed += update(props.range, 'start', start.valueOf()); + changed += update(props.range, 'end', end.valueOf()); + changed += update(props.range, 'minimumStep', minimumStep.valueOf()); } return (changed > 0); }; /** - * Create a label for group with given id - * @param {Number} id - * @return {Element} label + * Calculate the factor and offset to convert a position on screen to the + * corresponding date and vice versa. + * After the method _updateConversion is executed once, the methods toTime + * and toScreen can be used. * @private */ -GroupSet.prototype._createLabel = function(id) { - var group = this.groups[id]; - var label = document.createElement('div'); - label.className = 'label'; - var inner = document.createElement('div'); - inner.className = 'inner'; - label.appendChild(inner); +TimeAxis.prototype._updateConversion = function() { + var range = this.range; + if (!range) { + throw new Error('No range configured'); + } - var content = group.data && group.data.content; - if (content instanceof Element) { - inner.appendChild(content); + if (range.conversion) { + this.conversion = range.conversion(this.width); } - else if (content != undefined) { - inner.innerHTML = content; + else { + this.conversion = Range.conversion(range.start, range.end, this.width); } +}; - var className = group.data && group.data.className; - if (className) { - util.addClassName(label, className); - } +/** + * An ItemSet holds a set of items and ranges which can be displayed in a + * range. The width is determined by the parent of the ItemSet, and the height + * is determined by the size of the items. + * @param {Component} parent + * @param {Component[]} [depends] Components on which this components depends + * (except for the parent) + * @param {Object} [options] See ItemSet.setOptions for the available + * options. + * @constructor ItemSet + * @extends Panel + */ +// TODO: improve performance by replacing all Array.forEach with a for loop +function ItemSet(parent, depends, options) { + this.id = util.randomUUID(); + this.parent = parent; + this.depends = depends; - group.label = label; // TODO: not so nice, parking labels in the group this way!!! + // one options object is shared by this itemset and all its items + this.options = options || {}; + this.defaultOptions = { + type: 'box', + align: 'center', + orientation: 'bottom', + margin: { + axis: 20, + item: 10 + }, + padding: 5 + }; - return label; + this.dom = {}; + + var me = this; + this.itemsData = null; // DataSet + this.range = null; // Range or Object {start: number, end: number} + + this.listeners = { + 'add': function (event, params, senderId) { + if (senderId != me.id) { + me._onAdd(params.items); + } + }, + 'update': function (event, params, senderId) { + if (senderId != me.id) { + me._onUpdate(params.items); + } + }, + 'remove': function (event, params, senderId) { + if (senderId != me.id) { + me._onRemove(params.items); + } + } + }; + + this.items = {}; // object with an Item for every data item + this.queue = {}; // queue with id/actions: 'add', 'update', 'delete' + this.stack = new Stack(this, Object.create(this.options)); + this.conversion = null; + + // TODO: ItemSet should also attach event listeners for rangechange and rangechanged, like timeaxis +} + +ItemSet.prototype = new Panel(); + +// available item types will be registered here +ItemSet.types = { + box: ItemBox, + range: ItemRange, + point: ItemPoint }; /** - * Get container element - * @return {HTMLElement} container + * Set options for the ItemSet. Existing options will be extended/overwritten. + * @param {Object} [options] The following options are available: + * {String | function} [className] + * class name for the itemset + * {String} [type] + * Default type for the items. Choose from 'box' + * (default), 'point', or 'range'. The default + * Style can be overwritten by individual items. + * {String} align + * Alignment for the items, only applicable for + * ItemBox. Choose 'center' (default), 'left', or + * 'right'. + * {String} orientation + * Orientation of the item set. Choose 'top' or + * 'bottom' (default). + * {Number} margin.axis + * Margin between the axis and the items in pixels. + * Default is 20. + * {Number} margin.item + * Margin between items in pixels. Default is 10. + * {Number} padding + * Padding of the contents of an item in pixels. + * Must correspond with the items css. Default is 5. */ -GroupSet.prototype.getContainer = function getContainer() { - return this.dom.frame; -}; +ItemSet.prototype.setOptions = Component.prototype.setOptions; /** - * Get the width of the group labels - * @return {Number} width + * Set range (start and end). + * @param {Range | Object} range A Range or an object containing start and end. */ -GroupSet.prototype.getLabelsWidth = function getContainer() { - return this.props.labels.width; +ItemSet.prototype.setRange = function setRange(range) { + if (!(range instanceof Range) && (!range || !range.start || !range.end)) { + throw new TypeError('Range must be an instance of Range, ' + + 'or an object containing start and end.'); + } + this.range = range; }; /** - * Reflow the component - * @return {Boolean} resized + * Repaint the component + * @return {Boolean} changed */ -GroupSet.prototype.reflow = function reflow() { +ItemSet.prototype.repaint = function repaint() { var changed = 0, - id, group, - options = this.options, update = util.updateProperty, - asNumber = util.option.asNumber, asSize = util.option.asSize, - frame = this.dom.frame; + options = this.options, + orientation = this.getOption('orientation'), + defaultOptions = this.defaultOptions, + frame = this.frame; - if (frame) { - var maxHeight = asNumber(options.maxHeight); - var fixedHeight = (asSize(options.height) != null); - var height; - if (fixedHeight) { - height = frame.offsetHeight; - } - else { - // height is not specified, calculate the sum of the height of all groups - height = 0; + if (!frame) { + frame = document.createElement('div'); + frame.className = 'itemset'; - for (id in this.groups) { - if (this.groups.hasOwnProperty(id)) { - group = this.groups[id]; - height += group.height; - } - } - } - if (maxHeight != null) { - height = Math.min(height, maxHeight); + var className = options.className; + if (className) { + util.addClassName(frame, util.option.asString(className)); } - changed += update(this, 'height', height); - changed += update(this, 'top', frame.offsetTop); - changed += update(this, 'left', frame.offsetLeft); - changed += update(this, 'width', frame.offsetWidth); + // create background panel + var background = document.createElement('div'); + background.className = 'background'; + frame.appendChild(background); + this.dom.background = background; + + // create foreground panel + var foreground = document.createElement('div'); + foreground.className = 'foreground'; + frame.appendChild(foreground); + this.dom.foreground = foreground; + + // create axis panel + var axis = document.createElement('div'); + axis.className = 'itemset-axis'; + //frame.appendChild(axis); + this.dom.axis = axis; + + this.frame = frame; + changed += 1; } - // calculate the maximum width of the labels - var width = 0; - for (id in this.groups) { - if (this.groups.hasOwnProperty(id)) { - group = this.groups[id]; - var labelWidth = group.props && group.props.label && group.props.label.width || 0; - width = Math.max(width, labelWidth); - } + if (!this.parent) { + throw new Error('Cannot repaint itemset: no parent attached'); + } + var parentContainer = this.parent.getContainer(); + if (!parentContainer) { + throw new Error('Cannot repaint itemset: parent has no container element'); } - changed += update(this.props.labels, 'width', width); - - return (changed > 0); -}; - -/** - * Hide the component from the DOM - * @return {Boolean} changed - */ -GroupSet.prototype.hide = function hide() { - if (this.dom.frame && this.dom.frame.parentNode) { - this.dom.frame.parentNode.removeChild(this.dom.frame); - return true; + if (!frame.parentNode) { + parentContainer.appendChild(frame); + changed += 1; } - else { - return false; + if (!this.dom.axis.parentNode) { + parentContainer.appendChild(this.dom.axis); + changed += 1; } -}; -/** - * Show the component in the DOM (when not already visible). - * A repaint will be executed when the component is not visible - * @return {Boolean} changed - */ -GroupSet.prototype.show = function show() { - if (!this.dom.frame || !this.dom.frame.parentNode) { - return this.repaint(); + // reposition frame + changed += update(frame.style, 'left', asSize(options.left, '0px')); + changed += update(frame.style, 'top', asSize(options.top, '0px')); + changed += update(frame.style, 'width', asSize(options.width, '100%')); + changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); + + // reposition axis + changed += update(this.dom.axis.style, 'left', asSize(options.left, '0px')); + changed += update(this.dom.axis.style, 'width', asSize(options.width, '100%')); + if (orientation == 'bottom') { + changed += update(this.dom.axis.style, 'top', (this.height + this.top) + 'px'); } - else { - return false; + else { // orientation == 'top' + changed += update(this.dom.axis.style, 'top', this.top + 'px'); } -}; - -/** - * Handle updated groups - * @param {Number[]} ids - * @private - */ -GroupSet.prototype._onUpdate = function _onUpdate(ids) { - this._toQueue(ids, 'update'); -}; -/** - * Handle changed groups - * @param {Number[]} ids - * @private - */ -GroupSet.prototype._onAdd = function _onAdd(ids) { - this._toQueue(ids, 'add'); -}; + this._updateConversion(); -/** - * Handle removed groups - * @param {Number[]} ids - * @private - */ -GroupSet.prototype._onRemove = function _onRemove(ids) { - this._toQueue(ids, 'remove'); -}; + var me = this, + queue = this.queue, + itemsData = this.itemsData, + items = this.items, + dataOptions = { + // TODO: cleanup + // fields: [(itemsData && itemsData.fieldId || 'id'), 'start', 'end', 'content', 'type', 'className'] + }; -/** - * Put groups in the queue to be added/updated/remove - * @param {Number[]} ids - * @param {String} action can be 'add', 'update', 'remove' - */ -GroupSet.prototype._toQueue = function _toQueue(ids, action) { - var queue = this.queue; - ids.forEach(function (id) { - queue[id] = action; - }); + // show/hide added/changed/removed items + Object.keys(queue).forEach(function (id) { + //var entry = queue[id]; + var action = queue[id]; + var item = items[id]; + //var item = entry.item; + //noinspection FallthroughInSwitchStatementJS + switch (action) { + case 'add': + case 'update': + var itemData = itemsData && itemsData.get(id, dataOptions); - if (this.controller) { - //this.requestReflow(); - this.requestRepaint(); - } -}; + if (itemData) { + var type = itemData.type || + (itemData.start && itemData.end && 'range') || + options.type || + 'box'; + var constructor = ItemSet.types[type]; -/** - * Create a timeline visualization - * @param {HTMLElement} container - * @param {vis.DataSet | Array | DataTable} [items] - * @param {Object} [options] See Timeline.setOptions for the available options. - * @constructor - */ -function Timeline (container, items, options) { - var me = this; - this.options = util.extend({ - orientation: 'bottom', - min: null, - max: null, - zoomMin: 10, // milliseconds - zoomMax: 1000 * 60 * 60 * 24 * 365 * 10000, // milliseconds - // moveable: true, // TODO: option moveable - // zoomable: true, // TODO: option zoomable - showMinorLabels: true, - showMajorLabels: true, - autoResize: false - }, options); + // TODO: how to handle items with invalid data? hide them and give a warning? or throw an error? + if (item) { + // update item + if (!constructor || !(item instanceof constructor)) { + // item type has changed, hide and delete the item + changed += item.hide(); + item = null; + } + else { + item.data = itemData; // TODO: create a method item.setData ? + changed++; + } + } - // controller - this.controller = new Controller(); + if (!item) { + // create item + if (constructor) { + item = new constructor(me, itemData, options, defaultOptions); + changed++; + } + else { + throw new TypeError('Unknown item type "' + type + '"'); + } + } - // root panel - if (!container) { - throw new Error('No container element provided'); - } - var rootOptions = Object.create(this.options); - rootOptions.height = function () { - if (me.options.height) { - // fixed height - return me.options.height; - } - else { - // auto height - return me.timeaxis.height + me.content.height; - } - }; - this.rootPanel = new RootPanel(container, rootOptions); - this.controller.add(this.rootPanel); + // force a repaint (not only a reposition) + item.repaint(); - // item panel - var itemOptions = Object.create(this.options); - itemOptions.left = function () { - return me.labelPanel.width; - }; - itemOptions.width = function () { - return me.rootPanel.width - me.labelPanel.width; - }; - itemOptions.top = null; - itemOptions.height = null; - this.itemPanel = new Panel(this.rootPanel, [], itemOptions); - this.controller.add(this.itemPanel); + items[id] = item; + } - // label panel - var labelOptions = Object.create(this.options); - labelOptions.top = null; - labelOptions.left = null; - labelOptions.height = null; - labelOptions.width = function () { - if (me.content && typeof me.content.getLabelsWidth === 'function') { - return me.content.getLabelsWidth(); - } - else { - return 0; - } - }; - this.labelPanel = new Panel(this.rootPanel, [], labelOptions); - this.controller.add(this.labelPanel); + // update queue + delete queue[id]; + break; - // range - var now = moment().hours(0).minutes(0).seconds(0).milliseconds(0); - this.range = new Range({ - start: now.clone().add('days', -3).valueOf(), - end: now.clone().add('days', 4).valueOf() - }); - // TODO: reckon with options moveable and zoomable - this.range.subscribe(this.rootPanel, 'move', 'horizontal'); - this.range.subscribe(this.rootPanel, 'zoom', 'horizontal'); - this.range.on('rangechange', function () { - var force = true; - me.controller.requestReflow(force); - }); - this.range.on('rangechanged', function () { - var force = true; - me.controller.requestReflow(force); - }); + case 'remove': + if (item) { + // remove DOM of the item + changed += item.hide(); + } - // TODO: put the listeners in setOptions, be able to dynamically change with options moveable and zoomable + // update lists + delete items[id]; + delete queue[id]; + break; - // time axis - var timeaxisOptions = Object.create(rootOptions); - timeaxisOptions.range = this.range; - timeaxisOptions.left = null; - timeaxisOptions.top = null; - timeaxisOptions.width = '100%'; - timeaxisOptions.height = null; - this.timeaxis = new TimeAxis(this.itemPanel, [], timeaxisOptions); - this.timeaxis.setRange(this.range); - this.controller.add(this.timeaxis); + default: + console.log('Error: unknown action "' + action + '"'); + } + }); - // create itemset or groupset - this.setGroups(null); + // reposition all items. Show items only when in the visible area + util.forEach(this.items, function (item) { + if (item.visible) { + changed += item.show(); + item.reposition(); + } + else { + changed += item.hide(); + } + }); - this.itemsData = null; // DataSet - this.groupsData = null; // DataSet + return (changed > 0); +}; - // set data - if (items) { - this.setItems(items); - } -} +/** + * Get the foreground container element + * @return {HTMLElement} foreground + */ +ItemSet.prototype.getForeground = function getForeground() { + return this.dom.foreground; +}; /** - * Set options - * @param {Object} options TODO: describe the available options + * Get the background container element + * @return {HTMLElement} background */ -Timeline.prototype.setOptions = function (options) { - if (options) { - util.extend(this.options, options); - } +ItemSet.prototype.getBackground = function getBackground() { + return this.dom.background; +}; - this.controller.reflow(); - this.controller.repaint(); +/** + * Get the axis container element + * @return {HTMLElement} axis + */ +ItemSet.prototype.getAxis = function getAxis() { + return this.dom.axis; }; /** - * Set items - * @param {vis.DataSet | Array | DataTable | null} items + * Reflow the component + * @return {Boolean} resized */ -Timeline.prototype.setItems = function(items) { - var initialLoad = (this.itemsData == null); +ItemSet.prototype.reflow = function reflow () { + var changed = 0, + options = this.options, + marginAxis = options.margin && options.margin.axis || this.defaultOptions.margin.axis, + marginItem = options.margin && options.margin.item || this.defaultOptions.margin.item, + update = util.updateProperty, + asNumber = util.option.asNumber, + asSize = util.option.asSize, + frame = this.frame; - // convert to type DataSet when needed - var newItemSet; - if (!items) { - newItemSet = null; - } - else if (items instanceof DataSet) { - newItemSet = items; - } - if (!(items instanceof DataSet)) { - newItemSet = new DataSet({ - convert: { - start: 'Date', - end: 'Date' - } - }); - newItemSet.add(items); - } + if (frame) { + this._updateConversion(); - // set items - this.itemsData = newItemSet; - this.content.setItems(newItemSet); + util.forEach(this.items, function (item) { + changed += item.reflow(); + }); - if (initialLoad && (this.options.start == undefined || this.options.end == undefined)) { - // apply the data range as range - var dataRange = this.getItemRange(); + // TODO: stack.update should be triggered via an event, in stack itself + // TODO: only update the stack when there are changed items + this.stack.update(); - // add 5% on both sides - var min = dataRange.min; - var max = dataRange.max; - if (min != null && max != null) { - var interval = (max.valueOf() - min.valueOf()); - min = new Date(min.valueOf() - interval * 0.05); - max = new Date(max.valueOf() + interval * 0.05); + var maxHeight = asNumber(options.maxHeight); + var fixedHeight = (asSize(options.height) != null); + var height; + if (fixedHeight) { + height = frame.offsetHeight; } - - // override specified start and/or end date - if (this.options.start != undefined) { - min = new Date(this.options.start.valueOf()); + else { + // height is not specified, determine the height from the height and positioned items + var visibleItems = this.stack.ordered; // TODO: not so nice way to get the filtered items + if (visibleItems.length) { + var min = visibleItems[0].top; + var max = visibleItems[0].top + visibleItems[0].height; + util.forEach(visibleItems, function (item) { + min = Math.min(min, item.top); + max = Math.max(max, (item.top + item.height)); + }); + height = (max - min) + marginAxis + marginItem; + } + else { + height = marginAxis + marginItem; + } } - if (this.options.end != undefined) { - max = new Date(this.options.end.valueOf()); + if (maxHeight != null) { + height = Math.min(height, maxHeight); } + changed += update(this, 'height', height); - // apply range if there is a min or max available - if (min != null || max != null) { - this.range.setRange(min, max); - } + // calculate height from items + changed += update(this, 'top', frame.offsetTop); + changed += update(this, 'left', frame.offsetLeft); + changed += update(this, 'width', frame.offsetWidth); + } + else { + changed += 1; } + + return (changed > 0); }; /** - * Set groups - * @param {vis.DataSet | Array | DataTable} groups + * Hide this component from the DOM + * @return {Boolean} changed */ -Timeline.prototype.setGroups = function(groups) { - var me = this; - this.groupsData = groups; - - // switch content type between ItemSet or GroupSet when needed - var type = this.groupsData ? GroupSet : ItemSet; - if (!(this.content instanceof type)) { - // remove old content set - if (this.content) { - this.content.hide(); - if (this.content.setItems) { - this.content.setItems(); // disconnect from items - } - if (this.content.setGroups) { - this.content.setGroups(); // disconnect from groups - } - this.controller.remove(this.content); - } +ItemSet.prototype.hide = function hide() { + var changed = false; - // create new content set - var options = Object.create(this.options); - util.extend(options, { - top: function () { - if (me.options.orientation == 'top') { - return me.timeaxis.height; - } - else { - return me.itemPanel.height - me.timeaxis.height - me.content.height; - } - }, - left: null, - width: '100%', - height: function () { - if (me.options.height) { - return me.itemPanel.height - me.timeaxis.height; - } - else { - return null; - } - }, - maxHeight: function () { - if (me.options.maxHeight) { - if (!util.isNumber(me.options.maxHeight)) { - throw new TypeError('Number expected for property maxHeight'); - } - return me.options.maxHeight - me.timeaxis.height; - } - else { - return null; - } - }, - labelContainer: function () { - return me.labelPanel.getContainer(); - } - }); - this.content = new type(this.itemPanel, [this.timeaxis], options); - if (this.content.setRange) { - this.content.setRange(this.range); - } - if (this.content.setItems) { - this.content.setItems(this.itemsData); - } - if (this.content.setGroups) { - this.content.setGroups(this.groupsData); - } - this.controller.add(this.content); + // remove the DOM + if (this.frame && this.frame.parentNode) { + this.frame.parentNode.removeChild(this.frame); + changed = true; + } + if (this.dom.axis && this.dom.axis.parentNode) { + this.dom.axis.parentNode.removeChild(this.dom.axis); + changed = true; } + + return changed; }; /** - * Get the data range of the item set. - * @returns {{min: Date, max: Date}} range A range with a start and end Date. - * When no minimum is found, min==null - * When no maximum is found, max==null + * Set items + * @param {vis.DataSet | null} items */ -Timeline.prototype.getItemRange = function getItemRange() { - // calculate min from start filed - var itemsData = this.itemsData, - min = null, - max = null; - - if (itemsData) { - // calculate the minimum value of the field 'start' - var minItem = itemsData.min('start'); - min = minItem ? minItem.start.valueOf() : null; +ItemSet.prototype.setItems = function setItems(items) { + var me = this, + ids, + oldItemsData = this.itemsData; - // calculate maximum value of fields 'start' and 'end' - var maxStartItem = itemsData.max('start'); - if (maxStartItem) { - max = maxStartItem.start.valueOf(); - } - var maxEndItem = itemsData.max('end'); - if (maxEndItem) { - if (max == null) { - max = maxEndItem.end.valueOf(); - } - else { - max = Math.max(max, maxEndItem.end.valueOf()); - } - } + // replace the dataset + if (!items) { + this.itemsData = null; + } + else if (items instanceof DataSet || items instanceof DataView) { + this.itemsData = items; + } + else { + throw new TypeError('Data must be an instance of DataSet'); } - return { - min: (min != null) ? new Date(min) : null, - max: (max != null) ? new Date(max) : null - }; -}; + if (oldItemsData) { + // unsubscribe from old dataset + util.forEach(this.listeners, function (callback, event) { + oldItemsData.unsubscribe(event, callback); + }); -(function(exports) { - /** - * Parse a text source containing data in DOT language into a JSON object. - * The object contains two lists: one with nodes and one with edges. - * - * DOT language reference: http://www.graphviz.org/doc/info/lang.html - * - * @param {String} data Text containing a graph in DOT-notation - * @return {Object} graph An object containing two parameters: - * {Object[]} nodes - * {Object[]} edges - */ - function parseDOT (data) { - dot = data; - return parseGraph(); + // remove all drawn items + ids = oldItemsData.getIds(); + this._onRemove(ids); } - // token types enumeration - var TOKENTYPE = { - NULL : 0, - DELIMITER : 1, - IDENTIFIER: 2, - UNKNOWN : 3 - }; + if (this.itemsData) { + // subscribe to new dataset + var id = this.id; + util.forEach(this.listeners, function (callback, event) { + me.itemsData.subscribe(event, callback, id); + }); - // map with all delimiters - var DELIMITERS = { - '{': true, - '}': true, - '[': true, - ']': true, - ';': true, - '=': true, - ',': true, + // draw all new items + ids = this.itemsData.getIds(); + this._onAdd(ids); + } +}; - '->': true, - '--': true - }; +/** + * Get the current items items + * @returns {vis.DataSet | null} + */ +ItemSet.prototype.getItems = function getItems() { + return this.itemsData; +}; - var dot = ''; // current dot file - var index = 0; // current index in dot file - var c = ''; // current token character in expr - var token = ''; // current token - var tokenType = TOKENTYPE.NULL; // type of the token +/** + * Handle updated items + * @param {Number[]} ids + * @private + */ +ItemSet.prototype._onUpdate = function _onUpdate(ids) { + this._toQueue('update', ids); +}; - /** - * Get the first character from the dot file. - * The character is stored into the char c. If the end of the dot file is - * reached, the function puts an empty string in c. - */ - function first() { - index = 0; - c = dot.charAt(0); - } +/** + * Handle changed items + * @param {Number[]} ids + * @private + */ +ItemSet.prototype._onAdd = function _onAdd(ids) { + this._toQueue('add', ids); +}; - /** - * Get the next character from the dot file. - * The character is stored into the char c. If the end of the dot file is - * reached, the function puts an empty string in c. - */ - function next() { - index++; - c = dot.charAt(index); - } +/** + * Handle removed items + * @param {Number[]} ids + * @private + */ +ItemSet.prototype._onRemove = function _onRemove(ids) { + this._toQueue('remove', ids); +}; - /** - * Preview the next character from the dot file. - * @return {String} cNext - */ - function nextPreview() { - return dot.charAt(index + 1); - } +/** + * Put items in the queue to be added/updated/remove + * @param {String} action can be 'add', 'update', 'remove' + * @param {Number[]} ids + */ +ItemSet.prototype._toQueue = function _toQueue(action, ids) { + var queue = this.queue; + ids.forEach(function (id) { + queue[id] = action; + }); - /** - * Test whether given character is alphabetic or numeric - * @param {String} c - * @return {Boolean} isAlphaNumeric - */ - var regexAlphaNumeric = /[a-zA-Z_0-9.:#]/; - function isAlphaNumeric(c) { - return regexAlphaNumeric.test(c); + if (this.controller) { + //this.requestReflow(); + this.requestRepaint(); } +}; - /** - * Merge all properties of object b into object b - * @param {Object} a - * @param {Object} b - * @return {Object} a - */ - function merge (a, b) { - if (!a) { - a = {}; - } - - if (b) { - for (var name in b) { - if (b.hasOwnProperty(name)) { - a[name] = b[name]; - } - } - } - return a; +/** + * Calculate the factor and offset to convert a position on screen to the + * corresponding date and vice versa. + * After the method _updateConversion is executed once, the methods toTime + * and toScreen can be used. + * @private + */ +ItemSet.prototype._updateConversion = function _updateConversion() { + var range = this.range; + if (!range) { + throw new Error('No range configured'); } - /** - * Set a value in an object, where the provided parameter name can be a - * path with nested parameters. For example: - * - * var obj = {a: 2}; - * setValue(obj, 'b.c', 3); // obj = {a: 2, b: {c: 3}} - * - * @param {Object} obj - * @param {String} path A parameter name or dot-separated parameter path, - * like "color.highlight.border". - * @param {*} value - */ - function setValue(obj, path, value) { - var keys = path.split('.'); - var o = obj; - while (keys.length) { - var key = keys.shift(); - if (keys.length) { - // this isn't the end point - if (!o[key]) { - o[key] = {}; - } - o = o[key]; - } - else { - // this is the end point - o[key] = value; - } - } + if (range.conversion) { + this.conversion = range.conversion(this.width); + } + else { + this.conversion = Range.conversion(range.start, range.end, this.width); } +}; - /** - * Add a node to a graph object. If there is already a node with - * the same id, their attributes will be merged. - * @param {Object} graph - * @param {Object} node - */ - function addNode(graph, node) { - var i, len; - var current = null; +/** + * Convert a position on screen (pixels) to a datetime + * Before this method can be used, the method _updateConversion must be + * executed once. + * @param {int} x Position on the screen in pixels + * @return {Date} time The datetime the corresponds with given position x + */ +ItemSet.prototype.toTime = function toTime(x) { + var conversion = this.conversion; + return new Date(x / conversion.factor + conversion.offset); +}; - // find root graph (in case of subgraph) - var graphs = [graph]; // list with all graphs from current graph to root graph - var root = graph; - while (root.parent) { - graphs.push(root.parent); - root = root.parent; - } +/** + * Convert a datetime (Date object) into a position on the screen + * Before this method can be used, the method _updateConversion must be + * executed once. + * @param {Date} time A date + * @return {int} x The position on the screen in pixels which corresponds + * with the given date. + */ +ItemSet.prototype.toScreen = function toScreen(time) { + var conversion = this.conversion; + return (time.valueOf() - conversion.offset) * conversion.factor; +}; + +/** + * @constructor Item + * @param {ItemSet} parent + * @param {Object} data Object containing (optional) parameters type, + * start, end, content, group, className. + * @param {Object} [options] Options to set initial property values + * @param {Object} [defaultOptions] default options + * // TODO: describe available options + */ +function Item (parent, data, options, defaultOptions) { + this.parent = parent; + this.data = data; + this.dom = null; + this.options = options || {}; + this.defaultOptions = defaultOptions || {}; - // find existing node (at root level) by its id - if (root.nodes) { - for (i = 0, len = root.nodes.length; i < len; i++) { - if (node.id === root.nodes[i].id) { - current = root.nodes[i]; - break; - } - } - } + this.selected = false; + this.visible = false; + this.top = 0; + this.left = 0; + this.width = 0; + this.height = 0; +} - if (!current) { - // this is a new node - current = { - id: node.id - }; - if (graph.node) { - // clone default attributes - current.attr = merge(current.attr, graph.node); - } - } +/** + * Select current item + */ +Item.prototype.select = function select() { + this.selected = true; +}; - // add node to this (sub)graph and all its parent graphs - for (i = graphs.length - 1; i >= 0; i--) { - var g = graphs[i]; +/** + * Unselect current item + */ +Item.prototype.unselect = function unselect() { + this.selected = false; +}; - if (!g.nodes) { - g.nodes = []; - } - if (g.nodes.indexOf(current) == -1) { - g.nodes.push(current); - } - } +/** + * Show the Item in the DOM (when not already visible) + * @return {Boolean} changed + */ +Item.prototype.show = function show() { + return false; +}; - // merge attributes - if (node.attr) { - current.attr = merge(current.attr, node.attr); - } - } +/** + * Hide the Item from the DOM (when visible) + * @return {Boolean} changed + */ +Item.prototype.hide = function hide() { + return false; +}; - /** - * Add an edge to a graph object - * @param {Object} graph - * @param {Object} edge - */ - function addEdge(graph, edge) { - if (!graph.edges) { - graph.edges = []; - } - graph.edges.push(edge); - if (graph.edge) { - var attr = merge({}, graph.edge); // clone default attributes - edge.attr = merge(attr, edge.attr); // merge attributes - } - } +/** + * Repaint the item + * @return {Boolean} changed + */ +Item.prototype.repaint = function repaint() { + // should be implemented by the item + return false; +}; - /** - * Create an edge to a graph object - * @param {Object} graph - * @param {String | Number | Object} from - * @param {String | Number | Object} to - * @param {String} type - * @param {Object | null} attr - * @return {Object} edge - */ - function createEdge(graph, from, to, type, attr) { - var edge = { - from: from, - to: to, - type: type - }; +/** + * Reflow the item + * @return {Boolean} resized + */ +Item.prototype.reflow = function reflow() { + // should be implemented by the item + return false; +}; - if (graph.edge) { - edge.attr = merge({}, graph.edge); // clone default attributes +/** + * @constructor ItemBox + * @extends Item + * @param {ItemSet} parent + * @param {Object} data Object containing parameters start + * content, className. + * @param {Object} [options] Options to set initial property values + * @param {Object} [defaultOptions] default options + * // TODO: describe available options + */ +function ItemBox (parent, data, options, defaultOptions) { + this.props = { + dot: { + left: 0, + top: 0, + width: 0, + height: 0 + }, + line: { + top: 0, + left: 0, + width: 0, + height: 0 } - edge.attr = merge(edge.attr || {}, attr); // merge attributes + }; - return edge; - } + Item.call(this, parent, data, options, defaultOptions); +} - /** - * Get next token in the current dot file. - * The token and token type are available as token and tokenType - */ - function getToken() { - tokenType = TOKENTYPE.NULL; - token = ''; +ItemBox.prototype = new Item (null, null); - // skip over whitespaces - while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter - next(); - } +/** + * Select the item + * @override + */ +ItemBox.prototype.select = function select() { + this.selected = true; + // TODO: select and unselect +}; - do { - var isComment = false; +/** + * Unselect the item + * @override + */ +ItemBox.prototype.unselect = function unselect() { + this.selected = false; + // TODO: select and unselect +}; - // skip comment - if (c == '#') { - // find the previous non-space character - var i = index - 1; - while (dot.charAt(i) == ' ' || dot.charAt(i) == '\t') { - i--; - } - if (dot.charAt(i) == '\n' || dot.charAt(i) == '') { - // the # is at the start of a line, this is indeed a line comment - while (c != '' && c != '\n') { - next(); - } - isComment = true; - } - } - if (c == '/' && nextPreview() == '/') { - // skip line comment - while (c != '' && c != '\n') { - next(); - } - isComment = true; - } - if (c == '/' && nextPreview() == '*') { - // skip block comment - while (c != '') { - if (c == '*' && nextPreview() == '/') { - // end of block comment found. skip these last two characters - next(); - next(); - break; - } - else { - next(); - } - } - isComment = true; - } +/** + * Repaint the item + * @return {Boolean} changed + */ +ItemBox.prototype.repaint = function repaint() { + // TODO: make an efficient repaint + var changed = false; + var dom = this.dom; - // skip over whitespaces - while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter - next(); - } - } - while (isComment); + if (!dom) { + this._create(); + dom = this.dom; + changed = true; + } - // check for end of dot file - if (c == '') { - // token is still empty - tokenType = TOKENTYPE.DELIMITER; - return; + if (dom) { + if (!this.parent) { + throw new Error('Cannot repaint item: no parent attached'); + } + var foreground = this.parent.getForeground(); + if (!foreground) { + throw new Error('Cannot repaint time axis: ' + + 'parent has no foreground container element'); + } + var background = this.parent.getBackground(); + if (!background) { + throw new Error('Cannot repaint time axis: ' + + 'parent has no background container element'); } - - // check for delimiters consisting of 2 characters - var c2 = c + nextPreview(); - if (DELIMITERS[c2]) { - tokenType = TOKENTYPE.DELIMITER; - token = c2; - next(); - next(); - return; + var axis = this.parent.getAxis(); + if (!background) { + throw new Error('Cannot repaint time axis: ' + + 'parent has no axis container element'); } - // check for delimiters consisting of 1 character - if (DELIMITERS[c]) { - tokenType = TOKENTYPE.DELIMITER; - token = c; - next(); - return; + if (!dom.box.parentNode) { + foreground.appendChild(dom.box); + changed = true; } - - // check for an identifier (number or string) - // TODO: more precise parsing of numbers/strings (and the port separator ':') - if (isAlphaNumeric(c) || c == '-') { - token += c; - next(); - - while (isAlphaNumeric(c)) { - token += c; - next(); - } - if (token == 'false') { - token = false; // convert to boolean - } - else if (token == 'true') { - token = true; // convert to boolean - } - else if (!isNaN(Number(token))) { - token = Number(token); // convert to number - } - tokenType = TOKENTYPE.IDENTIFIER; - return; + if (!dom.line.parentNode) { + background.appendChild(dom.line); + changed = true; + } + if (!dom.dot.parentNode) { + axis.appendChild(dom.dot); + changed = true; } - // check for a string enclosed by double quotes - if (c == '"') { - next(); - while (c != '' && (c != '"' || (c == '"' && nextPreview() == '"'))) { - token += c; - if (c == '"') { // skip the escape character - next(); - } - next(); + // update contents + if (this.data.content != this.content) { + this.content = this.data.content; + if (this.content instanceof Element) { + dom.content.innerHTML = ''; + dom.content.appendChild(this.content); } - if (c != '"') { - throw newSyntaxError('End of string " expected'); + else if (this.data.content != undefined) { + dom.content.innerHTML = this.content; } - next(); - tokenType = TOKENTYPE.IDENTIFIER; - return; + else { + throw new Error('Property "content" missing in item ' + this.data.id); + } + changed = true; } - // something unknown is found, wrong characters, a syntax error - tokenType = TOKENTYPE.UNKNOWN; - while (c != '') { - token += c; - next(); + // update class + var className = (this.data.className? ' ' + this.data.className : '') + + (this.selected ? ' selected' : ''); + if (this.className != className) { + this.className = className; + dom.box.className = 'item box' + className; + dom.line.className = 'item line' + className; + dom.dot.className = 'item dot' + className; + changed = true; } - throw new SyntaxError('Syntax error in part "' + chop(token, 30) + '"'); } - /** - * Parse a graph. - * @returns {Object} graph - */ - function parseGraph() { - var graph = {}; - - first(); - getToken(); - - // optional strict keyword - if (token == 'strict') { - graph.strict = true; - getToken(); - } - - // graph or digraph keyword - if (token == 'graph' || token == 'digraph') { - graph.type = token; - getToken(); - } + return changed; +}; - // optional graph id - if (tokenType == TOKENTYPE.IDENTIFIER) { - graph.id = token; - getToken(); - } +/** + * Show the item in the DOM (when not already visible). The items DOM will + * be created when needed. + * @return {Boolean} changed + */ +ItemBox.prototype.show = function show() { + if (!this.dom || !this.dom.box.parentNode) { + return this.repaint(); + } + else { + return false; + } +}; - // open angle bracket - if (token != '{') { - throw newSyntaxError('Angle bracket { expected'); +/** + * Hide the item from the DOM (when visible) + * @return {Boolean} changed + */ +ItemBox.prototype.hide = function hide() { + var changed = false, + dom = this.dom; + if (dom) { + if (dom.box.parentNode) { + dom.box.parentNode.removeChild(dom.box); + changed = true; } - getToken(); - - // statements - parseStatements(graph); - - // close angle bracket - if (token != '}') { - throw newSyntaxError('Angle bracket } expected'); + if (dom.line.parentNode) { + dom.line.parentNode.removeChild(dom.line); } - getToken(); - - // end of file - if (token !== '') { - throw newSyntaxError('End of file expected'); + if (dom.dot.parentNode) { + dom.dot.parentNode.removeChild(dom.dot); } - getToken(); + } + return changed; +}; - // remove temporary default properties - delete graph.node; - delete graph.edge; - delete graph.graph; +/** + * Reflow the item: calculate its actual size and position from the DOM + * @return {boolean} resized returns true if the axis is resized + * @override + */ +ItemBox.prototype.reflow = function reflow() { + var changed = 0, + update, + dom, + props, + options, + margin, + start, + align, + orientation, + top, + left, + data, + range; - return graph; + if (this.data.start == undefined) { + throw new Error('Property "start" missing in item ' + this.data.id); } - /** - * Parse a list with statements. - * @param {Object} graph - */ - function parseStatements (graph) { - while (token !== '' && token != '}') { - parseStatement(graph); - if (token == ';') { - getToken(); - } - } + data = this.data; + range = this.parent && this.parent.range; + if (data && range) { + // TODO: account for the width of the item + var interval = (range.end - range.start); + this.visible = (data.start > range.start - interval) && (data.start < range.end + interval); + } + else { + this.visible = false; } - /** - * Parse a single statement. Can be a an attribute statement, node - * statement, a series of node statements and edge statements, or a - * parameter. - * @param {Object} graph - */ - function parseStatement(graph) { - // parse subgraph - var subgraph = parseSubgraph(graph); - if (subgraph) { - // edge statements - parseEdge(graph, subgraph); + if (this.visible) { + dom = this.dom; + if (dom) { + update = util.updateProperty; + props = this.props; + options = this.options; + start = this.parent.toScreen(this.data.start); + align = options.align || this.defaultOptions.align; + margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; + orientation = options.orientation || this.defaultOptions.orientation; - return; - } + changed += update(props.dot, 'height', dom.dot.offsetHeight); + changed += update(props.dot, 'width', dom.dot.offsetWidth); + changed += update(props.line, 'width', dom.line.offsetWidth); + changed += update(props.line, 'height', dom.line.offsetHeight); + changed += update(props.line, 'top', dom.line.offsetTop); + changed += update(this, 'width', dom.box.offsetWidth); + changed += update(this, 'height', dom.box.offsetHeight); + if (align == 'right') { + left = start - this.width; + } + else if (align == 'left') { + left = start; + } + else { + // default or 'center' + left = start - this.width / 2; + } + changed += update(this, 'left', left); - // parse an attribute statement - var attr = parseAttributeStatement(graph); - if (attr) { - return; - } + changed += update(props.line, 'left', start - props.line.width / 2); + changed += update(props.dot, 'left', start - props.dot.width / 2); + changed += update(props.dot, 'top', -props.dot.height / 2); + if (orientation == 'top') { + top = margin; - // parse node - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Identifier expected'); - } - var id = token; // id can be a string or a number - getToken(); + changed += update(this, 'top', top); + } + else { + // default or 'bottom' + var parentHeight = this.parent.height; + top = parentHeight - this.height - margin; - if (token == '=') { - // id statement - getToken(); - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Identifier expected'); + changed += update(this, 'top', top); } - graph[id] = token; - getToken(); - // TODO: implement comma separated list with "a_list: ID=ID [','] [a_list] " } else { - parseNodeStatement(graph, id); + changed += 1; } } - /** - * Parse a subgraph - * @param {Object} graph parent graph object - * @return {Object | null} subgraph - */ - function parseSubgraph (graph) { - var subgraph = null; - - // optional subgraph keyword - if (token == 'subgraph') { - subgraph = {}; - subgraph.type = 'subgraph'; - getToken(); - - // optional graph id - if (tokenType == TOKENTYPE.IDENTIFIER) { - subgraph.id = token; - getToken(); - } - } - - // open angle bracket - if (token == '{') { - getToken(); - - if (!subgraph) { - subgraph = {}; - } - subgraph.parent = graph; - subgraph.node = graph.node; - subgraph.edge = graph.edge; - subgraph.graph = graph.graph; + return (changed > 0); +}; - // statements - parseStatements(subgraph); +/** + * Create an items DOM + * @private + */ +ItemBox.prototype._create = function _create() { + var dom = this.dom; + if (!dom) { + this.dom = dom = {}; - // close angle bracket - if (token != '}') { - throw newSyntaxError('Angle bracket } expected'); - } - getToken(); + // create the box + dom.box = document.createElement('DIV'); + // className is updated in repaint() - // remove temporary default properties - delete subgraph.node; - delete subgraph.edge; - delete subgraph.graph; - delete subgraph.parent; + // contents box (inside the background box). used for making margins + dom.content = document.createElement('DIV'); + dom.content.className = 'content'; + dom.box.appendChild(dom.content); - // register at the parent graph - if (!graph.subgraphs) { - graph.subgraphs = []; - } - graph.subgraphs.push(subgraph); - } + // line to axis + dom.line = document.createElement('DIV'); + dom.line.className = 'line'; - return subgraph; + // dot on axis + dom.dot = document.createElement('DIV'); + dom.dot.className = 'dot'; } +}; - /** - * parse an attribute statement like "node [shape=circle fontSize=16]". - * Available keywords are 'node', 'edge', 'graph'. - * The previous list with default attributes will be replaced - * @param {Object} graph - * @returns {String | null} keyword Returns the name of the parsed attribute - * (node, edge, graph), or null if nothing - * is parsed. - */ - function parseAttributeStatement (graph) { - // attribute statements - if (token == 'node') { - getToken(); +/** + * Reposition the item, recalculate its left, top, and width, using the current + * range and size of the items itemset + * @override + */ +ItemBox.prototype.reposition = function reposition() { + var dom = this.dom, + props = this.props, + orientation = this.options.orientation || this.defaultOptions.orientation; - // node attributes - graph.node = parseAttributeList(); - return 'node'; - } - else if (token == 'edge') { - getToken(); + if (dom) { + var box = dom.box, + line = dom.line, + dot = dom.dot; - // edge attributes - graph.edge = parseAttributeList(); - return 'edge'; - } - else if (token == 'graph') { - getToken(); + box.style.left = this.left + 'px'; + box.style.top = this.top + 'px'; - // graph attributes - graph.graph = parseAttributeList(); - return 'graph'; + line.style.left = props.line.left + 'px'; + if (orientation == 'top') { + line.style.top = 0 + 'px'; + line.style.height = this.top + 'px'; } - - return null; - } - - /** - * parse a node statement - * @param {Object} graph - * @param {String | Number} id - */ - function parseNodeStatement(graph, id) { - // node statement - var node = { - id: id - }; - var attr = parseAttributeList(); - if (attr) { - node.attr = attr; + else { + // orientation 'bottom' + line.style.top = (this.top + this.height) + 'px'; + line.style.height = Math.max(this.parent.height - this.top - this.height + + this.props.dot.height / 2, 0) + 'px'; } - addNode(graph, node); - // edge statements - parseEdge(graph, id); + dot.style.left = props.dot.left + 'px'; + dot.style.top = props.dot.top + 'px'; } +}; - /** - * Parse an edge or a series of edges - * @param {Object} graph - * @param {String | Number} from Id of the from node - */ - function parseEdge(graph, from) { - while (token == '->' || token == '--') { - var to; - var type = token; - getToken(); +/** + * @constructor ItemPoint + * @extends Item + * @param {ItemSet} parent + * @param {Object} data Object containing parameters start + * content, className. + * @param {Object} [options] Options to set initial property values + * @param {Object} [defaultOptions] default options + * // TODO: describe available options + */ +function ItemPoint (parent, data, options, defaultOptions) { + this.props = { + dot: { + top: 0, + width: 0, + height: 0 + }, + content: { + height: 0, + marginLeft: 0 + } + }; - var subgraph = parseSubgraph(graph); - if (subgraph) { - to = subgraph; - } - else { - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Identifier or subgraph expected'); - } - to = token; - addNode(graph, { - id: to - }); - getToken(); - } + Item.call(this, parent, data, options, defaultOptions); +} - // parse edge attributes - var attr = parseAttributeList(); +ItemPoint.prototype = new Item (null, null); - // create edge - var edge = createEdge(graph, from, to, type, attr); - addEdge(graph, edge); +/** + * Select the item + * @override + */ +ItemPoint.prototype.select = function select() { + this.selected = true; + // TODO: select and unselect +}; - from = to; - } - } +/** + * Unselect the item + * @override + */ +ItemPoint.prototype.unselect = function unselect() { + this.selected = false; + // TODO: select and unselect +}; - /** - * Parse a set with attributes, - * for example [label="1.000", shape=solid] - * @return {Object | null} attr - */ - function parseAttributeList() { - var attr = null; +/** + * Repaint the item + * @return {Boolean} changed + */ +ItemPoint.prototype.repaint = function repaint() { + // TODO: make an efficient repaint + var changed = false; + var dom = this.dom; - while (token == '[') { - getToken(); - attr = {}; - while (token !== '' && token != ']') { - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Attribute name expected'); - } - var name = token; + if (!dom) { + this._create(); + dom = this.dom; + changed = true; + } - getToken(); - if (token != '=') { - throw newSyntaxError('Equal sign = expected'); - } - getToken(); + if (dom) { + if (!this.parent) { + throw new Error('Cannot repaint item: no parent attached'); + } + var foreground = this.parent.getForeground(); + if (!foreground) { + throw new Error('Cannot repaint time axis: ' + + 'parent has no foreground container element'); + } - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Attribute value expected'); - } - var value = token; - setValue(attr, name, value); // name can be a path + if (!dom.point.parentNode) { + foreground.appendChild(dom.point); + foreground.appendChild(dom.point); + changed = true; + } - getToken(); - if (token ==',') { - getToken(); - } + // update contents + if (this.data.content != this.content) { + this.content = this.data.content; + if (this.content instanceof Element) { + dom.content.innerHTML = ''; + dom.content.appendChild(this.content); } - - if (token != ']') { - throw newSyntaxError('Bracket ] expected'); + else if (this.data.content != undefined) { + dom.content.innerHTML = this.content; } - getToken(); + else { + throw new Error('Property "content" missing in item ' + this.data.id); + } + changed = true; } - return attr; + // update class + var className = (this.data.className? ' ' + this.data.className : '') + + (this.selected ? ' selected' : ''); + if (this.className != className) { + this.className = className; + dom.point.className = 'item point' + className; + changed = true; + } } - /** - * Create a syntax error with extra information on current token and index. - * @param {String} message - * @returns {SyntaxError} err - */ - function newSyntaxError(message) { - return new SyntaxError(message + ', got "' + chop(token, 30) + '" (char ' + index + ')'); - } + return changed; +}; - /** - * Chop off text after a maximum length - * @param {String} text - * @param {Number} maxLength - * @returns {String} - */ - function chop (text, maxLength) { - return (text.length <= maxLength) ? text : (text.substr(0, 27) + '...'); +/** + * Show the item in the DOM (when not already visible). The items DOM will + * be created when needed. + * @return {Boolean} changed + */ +ItemPoint.prototype.show = function show() { + if (!this.dom || !this.dom.point.parentNode) { + return this.repaint(); } - - /** - * Execute a function fn for each pair of elements in two arrays - * @param {Array | *} array1 - * @param {Array | *} array2 - * @param {function} fn - */ - function forEach2(array1, array2, fn) { - if (array1 instanceof Array) { - array1.forEach(function (elem1) { - if (array2 instanceof Array) { - array2.forEach(function (elem2) { - fn(elem1, elem2); - }); - } - else { - fn(elem1, array2); - } - }); - } - else { - if (array2 instanceof Array) { - array2.forEach(function (elem2) { - fn(array1, elem2); - }); - } - else { - fn(array1, array2); - } - } + else { + return false; } +}; - /** - * Convert a string containing a graph in DOT language into a map containing - * with nodes and edges in the format of graph. - * @param {String} data Text containing a graph in DOT-notation - * @return {Object} graphData - */ - function DOTToGraph (data) { - // parse the DOT file - var dotData = parseDOT(data); - var graphData = { - nodes: [], - edges: [], - options: {} - }; - - // copy the nodes - if (dotData.nodes) { - dotData.nodes.forEach(function (dotNode) { - var graphNode = { - id: dotNode.id, - label: String(dotNode.label || dotNode.id) - }; - merge(graphNode, dotNode.attr); - if (graphNode.image) { - graphNode.shape = 'image'; - } - graphData.nodes.push(graphNode); - }); +/** + * Hide the item from the DOM (when visible) + * @return {Boolean} changed + */ +ItemPoint.prototype.hide = function hide() { + var changed = false, + dom = this.dom; + if (dom) { + if (dom.point.parentNode) { + dom.point.parentNode.removeChild(dom.point); + changed = true; } + } + return changed; +}; - // copy the edges - if (dotData.edges) { - /** - * Convert an edge in DOT format to an edge with VisGraph format - * @param {Object} dotEdge - * @returns {Object} graphEdge - */ - function convertEdge(dotEdge) { - var graphEdge = { - from: dotEdge.from, - to: dotEdge.to - }; - merge(graphEdge, dotEdge.attr); - graphEdge.style = (dotEdge.type == '->') ? 'arrow' : 'line'; - return graphEdge; - } +/** + * Reflow the item: calculate its actual size from the DOM + * @return {boolean} resized returns true if the axis is resized + * @override + */ +ItemPoint.prototype.reflow = function reflow() { + var changed = 0, + update, + dom, + props, + options, + margin, + orientation, + start, + top, + data, + range; - dotData.edges.forEach(function (dotEdge) { - var from, to; - if (dotEdge.from instanceof Object) { - from = dotEdge.from.nodes; - } - else { - from = { - id: dotEdge.from - } - } + if (this.data.start == undefined) { + throw new Error('Property "start" missing in item ' + this.data.id); + } - if (dotEdge.to instanceof Object) { - to = dotEdge.to.nodes; - } - else { - to = { - id: dotEdge.to - } - } + data = this.data; + range = this.parent && this.parent.range; + if (data && range) { + // TODO: account for the width of the item + var interval = (range.end - range.start); + this.visible = (data.start > range.start - interval) && (data.start < range.end); + } + else { + this.visible = false; + } + + if (this.visible) { + dom = this.dom; + if (dom) { + update = util.updateProperty; + props = this.props; + options = this.options; + orientation = options.orientation || this.defaultOptions.orientation; + margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; + start = this.parent.toScreen(this.data.start); - if (dotEdge.from instanceof Object && dotEdge.from.edges) { - dotEdge.from.edges.forEach(function (subEdge) { - var graphEdge = convertEdge(subEdge); - graphData.edges.push(graphEdge); - }); - } + changed += update(this, 'width', dom.point.offsetWidth); + changed += update(this, 'height', dom.point.offsetHeight); + changed += update(props.dot, 'width', dom.dot.offsetWidth); + changed += update(props.dot, 'height', dom.dot.offsetHeight); + changed += update(props.content, 'height', dom.content.offsetHeight); - forEach2(from, to, function (from, to) { - var subEdge = createEdge(graphData, from.id, to.id, dotEdge.type, dotEdge.attr); - var graphEdge = convertEdge(subEdge); - graphData.edges.push(graphEdge); - }); + if (orientation == 'top') { + top = margin; + } + else { + // default or 'bottom' + var parentHeight = this.parent.height; + top = Math.max(parentHeight - this.height - margin, 0); + } + changed += update(this, 'top', top); + changed += update(this, 'left', start - props.dot.width / 2); + changed += update(props.content, 'marginLeft', 1.5 * props.dot.width); + //changed += update(props.content, 'marginRight', 0.5 * props.dot.width); // TODO - if (dotEdge.to instanceof Object && dotEdge.to.edges) { - dotEdge.to.edges.forEach(function (subEdge) { - var graphEdge = convertEdge(subEdge); - graphData.edges.push(graphEdge); - }); - } - }); + changed += update(props.dot, 'top', (this.height - props.dot.height) / 2); } - - // copy the options - if (dotData.attr) { - graphData.options = dotData.attr; + else { + changed += 1; } - - return graphData; } - // exports - exports.parseDOT = parseDOT; - exports.DOTToGraph = DOTToGraph; - -})(typeof util !== 'undefined' ? util : exports); + return (changed > 0); +}; /** - * Canvas shapes used by the Graph + * Create an items DOM + * @private */ -if (typeof CanvasRenderingContext2D !== 'undefined') { +ItemPoint.prototype._create = function _create() { + var dom = this.dom; + if (!dom) { + this.dom = dom = {}; - /** - * Draw a circle shape - */ - CanvasRenderingContext2D.prototype.circle = function(x, y, r) { - this.beginPath(); - this.arc(x, y, r, 0, 2*Math.PI, false); - }; + // background box + dom.point = document.createElement('div'); + // className is updated in repaint() - /** - * Draw a square shape - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r size, width and height of the square - */ - CanvasRenderingContext2D.prototype.square = function(x, y, r) { - this.beginPath(); - this.rect(x - r, y - r, r * 2, r * 2); - }; + // contents box, right from the dot + dom.content = document.createElement('div'); + dom.content.className = 'content'; + dom.point.appendChild(dom.content); - /** - * Draw a triangle shape - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r radius, half the length of the sides of the triangle - */ - CanvasRenderingContext2D.prototype.triangle = function(x, y, r) { - // http://en.wikipedia.org/wiki/Equilateral_triangle - this.beginPath(); + // dot at start + dom.dot = document.createElement('div'); + dom.dot.className = 'dot'; + dom.point.appendChild(dom.dot); + } +}; - var s = r * 2; - var s2 = s / 2; - var ir = Math.sqrt(3) / 6 * s; // radius of inner circle - var h = Math.sqrt(s * s - s2 * s2); // height +/** + * Reposition the item, recalculate its left, top, and width, using the current + * range and size of the items itemset + * @override + */ +ItemPoint.prototype.reposition = function reposition() { + var dom = this.dom, + props = this.props; - this.moveTo(x, y - (h - ir)); - this.lineTo(x + s2, y + ir); - this.lineTo(x - s2, y + ir); - this.lineTo(x, y - (h - ir)); - this.closePath(); - }; + if (dom) { + dom.point.style.top = this.top + 'px'; + dom.point.style.left = this.left + 'px'; - /** - * Draw a triangle shape in downward orientation - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r radius - */ - CanvasRenderingContext2D.prototype.triangleDown = function(x, y, r) { - // http://en.wikipedia.org/wiki/Equilateral_triangle - this.beginPath(); + dom.content.style.marginLeft = props.content.marginLeft + 'px'; + //dom.content.style.marginRight = props.content.marginRight + 'px'; // TODO - var s = r * 2; - var s2 = s / 2; - var ir = Math.sqrt(3) / 6 * s; // radius of inner circle - var h = Math.sqrt(s * s - s2 * s2); // height + dom.dot.style.top = props.dot.top + 'px'; + } +}; - this.moveTo(x, y + (h - ir)); - this.lineTo(x + s2, y - ir); - this.lineTo(x - s2, y - ir); - this.lineTo(x, y + (h - ir)); - this.closePath(); +/** + * @constructor ItemRange + * @extends Item + * @param {ItemSet} parent + * @param {Object} data Object containing parameters start, end + * content, className. + * @param {Object} [options] Options to set initial property values + * @param {Object} [defaultOptions] default options + * // TODO: describe available options + */ +function ItemRange (parent, data, options, defaultOptions) { + this.props = { + content: { + left: 0, + width: 0 + } }; - /** - * Draw a star shape, a star with 5 points - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r radius, half the length of the sides of the triangle - */ - CanvasRenderingContext2D.prototype.star = function(x, y, r) { - // http://www.html5canvastutorials.com/labs/html5-canvas-star-spinner/ - this.beginPath(); + Item.call(this, parent, data, options, defaultOptions); +} - for (var n = 0; n < 10; n++) { - var radius = (n % 2 === 0) ? r * 1.3 : r * 0.5; - this.lineTo( - x + radius * Math.sin(n * 2 * Math.PI / 10), - y - radius * Math.cos(n * 2 * Math.PI / 10) - ); - } +ItemRange.prototype = new Item (null, null); - this.closePath(); - }; +/** + * Select the item + * @override + */ +ItemRange.prototype.select = function select() { + this.selected = true; + // TODO: select and unselect +}; - /** - * http://stackoverflow.com/questions/1255512/how-to-draw-a-rounded-rectangle-on-html-canvas - */ - CanvasRenderingContext2D.prototype.roundRect = function(x, y, w, h, r) { - var r2d = Math.PI/180; - if( w - ( 2 * r ) < 0 ) { r = ( w / 2 ); } //ensure that the radius isn't too large for x - if( h - ( 2 * r ) < 0 ) { r = ( h / 2 ); } //ensure that the radius isn't too large for y - this.beginPath(); - this.moveTo(x+r,y); - this.lineTo(x+w-r,y); - this.arc(x+w-r,y+r,r,r2d*270,r2d*360,false); - this.lineTo(x+w,y+h-r); - this.arc(x+w-r,y+h-r,r,0,r2d*90,false); - this.lineTo(x+r,y+h); - this.arc(x+r,y+h-r,r,r2d*90,r2d*180,false); - this.lineTo(x,y+r); - this.arc(x+r,y+r,r,r2d*180,r2d*270,false); - }; +/** + * Unselect the item + * @override + */ +ItemRange.prototype.unselect = function unselect() { + this.selected = false; + // TODO: select and unselect +}; - /** - * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - */ - CanvasRenderingContext2D.prototype.ellipse = function(x, y, w, h) { - var kappa = .5522848, - ox = (w / 2) * kappa, // control point offset horizontal - oy = (h / 2) * kappa, // control point offset vertical - xe = x + w, // x-end - ye = y + h, // y-end - xm = x + w / 2, // x-middle - ym = y + h / 2; // y-middle +/** + * Repaint the item + * @return {Boolean} changed + */ +ItemRange.prototype.repaint = function repaint() { + // TODO: make an efficient repaint + var changed = false; + var dom = this.dom; - this.beginPath(); - this.moveTo(x, ym); - this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); - this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); - this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); - this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - }; + if (!dom) { + this._create(); + dom = this.dom; + changed = true; + } + if (dom) { + if (!this.parent) { + throw new Error('Cannot repaint item: no parent attached'); + } + var foreground = this.parent.getForeground(); + if (!foreground) { + throw new Error('Cannot repaint time axis: ' + + 'parent has no foreground container element'); + } + if (!dom.box.parentNode) { + foreground.appendChild(dom.box); + changed = true; + } - /** - * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - */ - CanvasRenderingContext2D.prototype.database = function(x, y, w, h) { - var f = 1/3; - var wEllipse = w; - var hEllipse = h * f; + // update content + if (this.data.content != this.content) { + this.content = this.data.content; + if (this.content instanceof Element) { + dom.content.innerHTML = ''; + dom.content.appendChild(this.content); + } + else if (this.data.content != undefined) { + dom.content.innerHTML = this.content; + } + else { + throw new Error('Property "content" missing in item ' + this.data.id); + } + changed = true; + } - var kappa = .5522848, - ox = (wEllipse / 2) * kappa, // control point offset horizontal - oy = (hEllipse / 2) * kappa, // control point offset vertical - xe = x + wEllipse, // x-end - ye = y + hEllipse, // y-end - xm = x + wEllipse / 2, // x-middle - ym = y + hEllipse / 2, // y-middle - ymb = y + (h - hEllipse/2), // y-midlle, bottom ellipse - yeb = y + h; // y-end, bottom ellipse + // update class + var className = this.data.className ? (' ' + this.data.className) : ''; + if (this.className != className) { + this.className = className; + dom.box.className = 'item range' + className; + changed = true; + } + } - this.beginPath(); - this.moveTo(xe, ym); + return changed; +}; - this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); - this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); +/** + * Show the item in the DOM (when not already visible). The items DOM will + * be created when needed. + * @return {Boolean} changed + */ +ItemRange.prototype.show = function show() { + if (!this.dom || !this.dom.box.parentNode) { + return this.repaint(); + } + else { + return false; + } +}; - this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); - this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); +/** + * Hide the item from the DOM (when visible) + * @return {Boolean} changed + */ +ItemRange.prototype.hide = function hide() { + var changed = false, + dom = this.dom; + if (dom) { + if (dom.box.parentNode) { + dom.box.parentNode.removeChild(dom.box); + changed = true; + } + } + return changed; +}; - this.lineTo(xe, ymb); +/** + * Reflow the item: calculate its actual size from the DOM + * @return {boolean} resized returns true if the axis is resized + * @override + */ +ItemRange.prototype.reflow = function reflow() { + var changed = 0, + dom, + props, + options, + margin, + padding, + parent, + start, + end, + data, + range, + update, + box, + parentWidth, + contentLeft, + orientation, + top; - this.bezierCurveTo(xe, ymb + oy, xm + ox, yeb, xm, yeb); - this.bezierCurveTo(xm - ox, yeb, x, ymb + oy, x, ymb); + if (this.data.start == undefined) { + throw new Error('Property "start" missing in item ' + this.data.id); + } + if (this.data.end == undefined) { + throw new Error('Property "end" missing in item ' + this.data.id); + } - this.lineTo(x, ym); - }; + data = this.data; + range = this.parent && this.parent.range; + if (data && range) { + // TODO: account for the width of the item. Take some margin + this.visible = (data.start < range.end) && (data.end > range.start); + } + else { + this.visible = false; + } + if (this.visible) { + dom = this.dom; + if (dom) { + props = this.props; + options = this.options; + parent = this.parent; + start = parent.toScreen(this.data.start); + end = parent.toScreen(this.data.end); + update = util.updateProperty; + box = dom.box; + parentWidth = parent.width; + orientation = options.orientation || this.defaultOptions.orientation; + margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; + padding = options.padding || this.defaultOptions.padding; - /** - * Draw an arrow point (no line) - */ - CanvasRenderingContext2D.prototype.arrow = function(x, y, angle, length) { - // tail - var xt = x - length * Math.cos(angle); - var yt = y - length * Math.sin(angle); + changed += update(props.content, 'width', dom.content.offsetWidth); - // inner tail - // TODO: allow to customize different shapes - var xi = x - length * 0.9 * Math.cos(angle); - var yi = y - length * 0.9 * Math.sin(angle); + changed += update(this, 'height', box.offsetHeight); - // left - var xl = xt + length / 3 * Math.cos(angle + 0.5 * Math.PI); - var yl = yt + length / 3 * Math.sin(angle + 0.5 * Math.PI); + // limit the width of the this, as browsers cannot draw very wide divs + if (start < -parentWidth) { + start = -parentWidth; + } + if (end > 2 * parentWidth) { + end = 2 * parentWidth; + } - // right - var xr = xt + length / 3 * Math.cos(angle - 0.5 * Math.PI); - var yr = yt + length / 3 * Math.sin(angle - 0.5 * Math.PI); + // when range exceeds left of the window, position the contents at the left of the visible area + if (start < 0) { + contentLeft = Math.min(-start, + (end - start - props.content.width - 2 * padding)); + // TODO: remove the need for options.padding. it's terrible. + } + else { + contentLeft = 0; + } + changed += update(props.content, 'left', contentLeft); - this.beginPath(); - this.moveTo(x, y); - this.lineTo(xl, yl); - this.lineTo(xi, yi); - this.lineTo(xr, yr); - this.closePath(); - }; + if (orientation == 'top') { + top = margin; + changed += update(this, 'top', top); + } + else { + // default or 'bottom' + top = parent.height - this.height - margin; + changed += update(this, 'top', top); + } - /** - * Sets up the dashedLine functionality for drawing - * Original code came from http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas - * @author David Jordan - * @date 2012-08-08 - */ - CanvasRenderingContext2D.prototype.dashedLine = function(x,y,x2,y2,dashArray){ - if (!dashArray) dashArray=[10,5]; - if (dashLength==0) dashLength = 0.001; // Hack for Safari - var dashCount = dashArray.length; - this.moveTo(x, y); - var dx = (x2-x), dy = (y2-y); - var slope = dy/dx; - var distRemaining = Math.sqrt( dx*dx + dy*dy ); - var dashIndex=0, draw=true; - while (distRemaining>=0.1){ - var dashLength = dashArray[dashIndex++%dashCount]; - if (dashLength > distRemaining) dashLength = distRemaining; - var xStep = Math.sqrt( dashLength*dashLength / (1 + slope*slope) ); - if (dx<0) xStep = -xStep; - x += xStep; - y += slope*xStep; - this[draw ? 'lineTo' : 'moveTo'](x,y); - distRemaining -= dashLength; - draw = !draw; + changed += update(this, 'left', start); + changed += update(this, 'width', Math.max(end - start, 1)); // TODO: reckon with border width; } - }; + else { + changed += 1; + } + } - // TODO: add diamond shape -} + return (changed > 0); +}; /** - * @class Node - * A node. A node can be connected to other nodes via one or multiple edges. - * @param {object} properties An object containing properties for the node. All - * properties are optional, except for the id. - * {number} id Id of the node. Required - * {string} label Text label for the node - * {number} x Horizontal position of the node - * {number} y Vertical position of the node - * {string} shape Node shape, available: - * "database", "circle", "ellipse", - * "box", "image", "text", "dot", - * "star", "triangle", "triangleDown", - * "square" - * {string} image An image url - * {string} title An title text, can be HTML - * {anytype} group A group name or number - * @param {Graph.Images} imagelist A list with images. Only needed - * when the node has an image - * @param {Graph.Groups} grouplist A list with groups. Needed for - * retrieving group properties - * @param {Object} constants An object with default values for - * example for the color + * Create an items DOM + * @private + */ +ItemRange.prototype._create = function _create() { + var dom = this.dom; + if (!dom) { + this.dom = dom = {}; + // background box + dom.box = document.createElement('div'); + // className is updated in repaint() + + // contents box + dom.content = document.createElement('div'); + dom.content.className = 'content'; + dom.box.appendChild(dom.content); + } +}; + +/** + * Reposition the item, recalculate its left, top, and width, using the current + * range and size of the items itemset + * @override */ -function Node(properties, imagelist, grouplist, constants) { - this.selected = false; +ItemRange.prototype.reposition = function reposition() { + var dom = this.dom, + props = this.props; - this.edges = []; // all edges connected to this node - this.group = constants.nodes.group; + if (dom) { + dom.box.style.top = this.top + 'px'; + dom.box.style.left = this.left + 'px'; + dom.box.style.width = this.width + 'px'; - this.fontSize = constants.nodes.fontSize; - this.fontFace = constants.nodes.fontFace; - this.fontColor = constants.nodes.fontColor; + dom.content.style.left = props.content.left + 'px'; + } +}; - this.color = constants.nodes.color; +/** + * @constructor Group + * @param {GroupSet} parent + * @param {Number | String} groupId + * @param {Object} [options] Options to set initial property values + * // TODO: describe available options + * @extends Component + */ +function Group (parent, groupId, options) { + this.id = util.randomUUID(); + this.parent = parent; - // set defaults for the properties - this.id = undefined; - this.shape = constants.nodes.shape; - this.image = constants.nodes.image; - this.x = 0; - this.y = 0; - this.xFixed = false; - this.yFixed = false; - this.radius = constants.nodes.radius; - this.radiusFixed = false; - this.radiusMin = constants.nodes.radiusMin; - this.radiusMax = constants.nodes.radiusMax; + this.groupId = groupId; + this.itemset = null; // ItemSet + this.options = options || {}; + this.options.top = 0; - this.imagelist = imagelist; - this.grouplist = grouplist; + this.props = { + label: { + width: 0, + height: 0 + } + }; - this.setProperties(properties, constants); + this.top = 0; + this.left = 0; + this.width = 0; + this.height = 0; +} - // mass, force, velocity - this.mass = 50; // kg (mass is adjusted for the number of connected edges) - this.fx = 0.0; // external force x - this.fy = 0.0; // external force y - this.vx = 0.0; // velocity x - this.vy = 0.0; // velocity y - this.minForce = constants.minForce; - this.damping = 0.9; // damping factor -}; +Group.prototype = new Component(); + +// TODO: comment +Group.prototype.setOptions = Component.prototype.setOptions; /** - * Attach a edge to the node - * @param {Edge} edge + * Get the container element of the panel, which can be used by a child to + * add its own widgets. + * @returns {HTMLElement} container */ -Node.prototype.attachEdge = function(edge) { - if (this.edges.indexOf(edge) == -1) { - this.edges.push(edge); - } - this._updateMass(); +Group.prototype.getContainer = function () { + return this.parent.getContainer(); }; /** - * Detach a edge from the node - * @param {Edge} edge + * Set item set for the group. The group will create a view on the itemset, + * filtered by the groups id. + * @param {DataSet | DataView} items */ -Node.prototype.detachEdge = function(edge) { - var index = this.edges.indexOf(edge); - if (index != -1) { - this.edges.splice(index, 1); +Group.prototype.setItems = function setItems(items) { + if (this.itemset) { + // remove current item set + this.itemset.hide(); + this.itemset.setItems(); + + this.parent.controller.remove(this.itemset); + this.itemset = null; + } + + if (items) { + var groupId = this.groupId; + + var itemsetOptions = Object.create(this.options); + this.itemset = new ItemSet(this, null, itemsetOptions); + this.itemset.setRange(this.parent.range); + + this.view = new DataView(items, { + filter: function (item) { + return item.group == groupId; + } + }); + this.itemset.setItems(this.view); + + this.parent.controller.add(this.itemset); } - this._updateMass(); }; /** - * Update the nodes mass, which is determined by the number of edges connecting - * to it (more edges -> heavier node). - * @private + * Repaint the item + * @return {Boolean} changed */ -Node.prototype._updateMass = function() { - this.mass = 50 + 20 * this.edges.length; // kg +Group.prototype.repaint = function repaint() { + return false; }; /** - * Set or overwrite properties for the node - * @param {Object} properties an object with properties - * @param {Object} constants and object with default, global properties + * Reflow the item + * @return {Boolean} resized */ -Node.prototype.setProperties = function(properties, constants) { - if (!properties) { - return; - } +Group.prototype.reflow = function reflow() { + var changed = 0, + update = util.updateProperty; - // basic properties - if (properties.id != undefined) {this.id = properties.id;} - if (properties.label != undefined) {this.label = properties.label;} - if (properties.title != undefined) {this.title = properties.title;} - if (properties.group != undefined) {this.group = properties.group;} - if (properties.x != undefined) {this.x = properties.x;} - if (properties.y != undefined) {this.y = properties.y;} - if (properties.value != undefined) {this.value = properties.value;} + changed += update(this, 'top', this.itemset ? this.itemset.top : 0); + changed += update(this, 'height', this.itemset ? this.itemset.height : 0); - if (this.id === undefined) { - throw "Node must have an id"; - } + // TODO: reckon with the height of the group label - // copy group properties - if (this.group) { - var groupObj = this.grouplist.get(this.group); - for (var prop in groupObj) { - if (groupObj.hasOwnProperty(prop)) { - this[prop] = groupObj[prop]; - } - } + if (this.label) { + var inner = this.label.firstChild; + changed += update(this.props.label, 'width', inner.clientWidth); + changed += update(this.props.label, 'height', inner.clientHeight); + } + else { + changed += update(this.props.label, 'width', 0); + changed += update(this.props.label, 'height', 0); } - // individual shape properties - if (properties.shape != undefined) {this.shape = properties.shape;} - if (properties.image != undefined) {this.image = properties.image;} - if (properties.radius != undefined) {this.radius = properties.radius;} - if (properties.color != undefined) {this.color = Node.parseColor(properties.color);} + return (changed > 0); +}; - if (properties.fontColor != undefined) {this.fontColor = properties.fontColor;} - if (properties.fontSize != undefined) {this.fontSize = properties.fontSize;} - if (properties.fontFace != undefined) {this.fontFace = properties.fontFace;} +/** + * An GroupSet holds a set of groups + * @param {Component} parent + * @param {Component[]} [depends] Components on which this components depends + * (except for the parent) + * @param {Object} [options] See GroupSet.setOptions for the available + * options. + * @constructor GroupSet + * @extends Panel + */ +function GroupSet(parent, depends, options) { + this.id = util.randomUUID(); + this.parent = parent; + this.depends = depends; + this.options = options || {}; - if (this.image != undefined) { - if (this.imagelist) { - this.imageObj = this.imagelist.load(this.image); - } - else { - throw "No imagelist provided"; + this.range = null; // Range or Object {start: number, end: number} + this.itemsData = null; // DataSet with items + this.groupsData = null; // DataSet with groups + + this.groups = {}; // map with groups + + this.dom = {}; + this.props = { + labels: { + width: 0 } - } + }; - this.xFixed = this.xFixed || (properties.x != undefined); - this.yFixed = this.yFixed || (properties.y != undefined); - this.radiusFixed = this.radiusFixed || (properties.radius != undefined); + // TODO: implement right orientation of the labels - if (this.shape == 'image') { - this.radiusMin = constants.nodes.widthMin; - this.radiusMax = constants.nodes.widthMax; - } + // changes in groups are queued key/value map containing id/action + this.queue = {}; - // choose draw method depending on the shape - switch (this.shape) { - case 'database': this.draw = this._drawDatabase; this.resize = this._resizeDatabase; break; - case 'box': this.draw = this._drawBox; this.resize = this._resizeBox; break; - case 'circle': this.draw = this._drawCircle; this.resize = this._resizeCircle; break; - case 'ellipse': this.draw = this._drawEllipse; this.resize = this._resizeEllipse; break; - // TODO: add diamond shape - case 'image': this.draw = this._drawImage; this.resize = this._resizeImage; break; - case 'text': this.draw = this._drawText; this.resize = this._resizeText; break; - case 'dot': this.draw = this._drawDot; this.resize = this._resizeShape; break; - case 'square': this.draw = this._drawSquare; this.resize = this._resizeShape; break; - case 'triangle': this.draw = this._drawTriangle; this.resize = this._resizeShape; break; - case 'triangleDown': this.draw = this._drawTriangleDown; this.resize = this._resizeShape; break; - case 'star': this.draw = this._drawStar; this.resize = this._resizeShape; break; - default: this.draw = this._drawEllipse; this.resize = this._resizeEllipse; break; - } + var me = this; + this.listeners = { + 'add': function (event, params) { + me._onAdd(params.items); + }, + 'update': function (event, params) { + me._onUpdate(params.items); + }, + 'remove': function (event, params) { + me._onRemove(params.items); + } + }; +} - // reset the size of the node, this can be changed - this._reset(); +GroupSet.prototype = new Panel(); + +/** + * Set options for the GroupSet. Existing options will be extended/overwritten. + * @param {Object} [options] The following options are available: + * {String | function} groupsOrder + * TODO: describe options + */ +GroupSet.prototype.setOptions = Component.prototype.setOptions; + +GroupSet.prototype.setRange = function (range) { + // TODO: implement setRange }; /** - * Parse a color property into an object with border, background, and - * hightlight colors - * @param {Object | String} color - * @return {Object} colorObject + * Set items + * @param {vis.DataSet | null} items */ -Node.parseColor = function(color) { - var c; - if (util.isString(color)) { - c = { - border: color, - background: color, - highlight: { - border: color, - background: color - } - }; - // TODO: automatically generate a nice highlight color - } - else { - c = {}; - c.background = color.background || 'white'; - c.border = color.border || c.background; - if (util.isString(color.highlight)) { - c.highlight = { - border: color.highlight, - background: color.highlight - } - } - else { - c.highlight = {}; - c.highlight.background = color.highlight && color.highlight.background || c.background; - c.highlight.border = color.highlight && color.highlight.border || c.border; +GroupSet.prototype.setItems = function setItems(items) { + this.itemsData = items; + + for (var id in this.groups) { + if (this.groups.hasOwnProperty(id)) { + var group = this.groups[id]; + group.setItems(items); } } - return c; }; /** - * select this node + * Get items + * @return {vis.DataSet | null} items */ -Node.prototype.select = function() { - this.selected = true; - this._reset(); +GroupSet.prototype.getItems = function getItems() { + return this.itemsData; }; /** - * unselect this node + * Set range (start and end). + * @param {Range | Object} range A Range or an object containing start and end. */ -Node.prototype.unselect = function() { - this.selected = false; - this._reset(); +GroupSet.prototype.setRange = function setRange(range) { + this.range = range; }; /** - * Reset the calculated size of the node, forces it to recalculate its size - * @private + * Set groups + * @param {vis.DataSet} groups */ -Node.prototype._reset = function() { - this.width = undefined; - this.height = undefined; +GroupSet.prototype.setGroups = function setGroups(groups) { + var me = this, + ids; + + // unsubscribe from current dataset + if (this.groupsData) { + util.forEach(this.listeners, function (callback, event) { + me.groupsData.unsubscribe(event, callback); + }); + + // remove all drawn groups + ids = this.groupsData.getIds(); + this._onRemove(ids); + } + + // replace the dataset + if (!groups) { + this.groupsData = null; + } + else if (groups instanceof DataSet) { + this.groupsData = groups; + } + else { + this.groupsData = new DataSet({ + convert: { + start: 'Date', + end: 'Date' + } + }); + this.groupsData.add(groups); + } + + if (this.groupsData) { + // subscribe to new dataset + var id = this.id; + util.forEach(this.listeners, function (callback, event) { + me.groupsData.subscribe(event, callback, id); + }); + + // draw all new groups + ids = this.groupsData.getIds(); + this._onAdd(ids); + } }; /** - * get the title of this node. - * @return {string} title The title of the node, or undefined when no title - * has been set. + * Get groups + * @return {vis.DataSet | null} groups */ -Node.prototype.getTitle = function() { - return this.title; +GroupSet.prototype.getGroups = function getGroups() { + return this.groupsData; }; /** - * Calculate the distance to the border of the Node - * @param {CanvasRenderingContext2D} ctx - * @param {Number} angle Angle in radians - * @returns {number} distance Distance to the border in pixels + * Repaint the component + * @return {Boolean} changed */ -Node.prototype.distanceToBorder = function (ctx, angle) { - var borderWidth = 1; +GroupSet.prototype.repaint = function repaint() { + var changed = 0, + i, id, group, label, + update = util.updateProperty, + asSize = util.option.asSize, + asElement = util.option.asElement, + options = this.options, + frame = this.dom.frame, + labels = this.dom.labels; - if (!this.width) { - this.resize(ctx); + // create frame + if (!this.parent) { + throw new Error('Cannot repaint groupset: no parent attached'); + } + var parentContainer = this.parent.getContainer(); + if (!parentContainer) { + throw new Error('Cannot repaint groupset: parent has no container element'); } + if (!frame) { + frame = document.createElement('div'); + frame.className = 'groupset'; + this.dom.frame = frame; - //noinspection FallthroughInSwitchStatementJS - switch (this.shape) { - case 'circle': - case 'dot': - return this.radius + borderWidth; + var className = options.className; + if (className) { + util.addClassName(frame, util.option.asString(className)); + } - case 'ellipse': - var a = this.width / 2; - var b = this.height / 2; - var w = (Math.sin(angle) * a); - var h = (Math.cos(angle) * b); - return a * b / Math.sqrt(w * w + h * h); + changed += 1; + } + if (!frame.parentNode) { + parentContainer.appendChild(frame); + changed += 1; + } - // TODO: implement distanceToBorder for database - // TODO: implement distanceToBorder for triangle - // TODO: implement distanceToBorder for triangleDown + // create labels + var labelContainer = asElement(options.labelContainer); + if (!labelContainer) { + throw new Error('Cannot repaint groupset: option "labelContainer" not defined'); + } + if (!labels) { + labels = document.createElement('div'); + labels.className = 'labels'; + //frame.appendChild(labels); + this.dom.labels = labels; + } + if (!labels.parentNode || labels.parentNode != labelContainer) { + if (labels.parentNode) { + labels.parentNode.removeChild(labels.parentNode); + } + labelContainer.appendChild(labels); + } + + // reposition frame + changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); + changed += update(frame.style, 'top', asSize(options.top, '0px')); + changed += update(frame.style, 'left', asSize(options.left, '0px')); + changed += update(frame.style, 'width', asSize(options.width, '100%')); + + // reposition labels + changed += update(labels.style, 'top', asSize(options.top, '0px')); + + var me = this, + queue = this.queue, + groups = this.groups, + groupsData = this.groupsData; + + // show/hide added/changed/removed groups + var ids = Object.keys(queue); + if (ids.length) { + ids.forEach(function (id) { + var action = queue[id]; + var group = groups[id]; + + //noinspection FallthroughInSwitchStatementJS + switch (action) { + case 'add': + case 'update': + if (!group) { + var groupOptions = Object.create(me.options); + group = new Group(me, id, groupOptions); + group.setItems(me.itemsData); // attach items data + groups[id] = group; + + me.controller.add(group); + } + + // TODO: update group data + group.data = groupsData.get(id); + + delete queue[id]; + break; + + case 'remove': + if (group) { + group.setItems(); // detach items data + delete groups[id]; + + me.controller.remove(group); + } + + // update lists + delete queue[id]; + break; - case 'box': - case 'image': - case 'text': - default: - if (this.width) { - return Math.min( - Math.abs(this.width / 2 / Math.cos(angle)), - Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth; - // TODO: reckon with border radius too in case of box - } - else { - return 0; + default: + console.log('Error: unknown action "' + action + '"'); } + }); - } + // the groupset depends on each of the groups + //this.depends = this.groups; // TODO: gives a circular reference through the parent - // TODO: implement calculation of distance to border for all shapes -}; + // TODO: apply dependencies of the groupset -/** - * Set forces acting on the node - * @param {number} fx Force in horizontal direction - * @param {number} fy Force in vertical direction - */ -Node.prototype._setForce = function(fx, fy) { - this.fx = fx; - this.fy = fy; -}; + // update the top positions of the groups in the correct order + var orderedGroups = this.groupsData.getIds({ + order: this.options.groupsOrder + }); + for (i = 0; i < orderedGroups.length; i++) { + (function (group, prevGroup) { + var top = 0; + if (prevGroup) { + top = function () { + // TODO: top must reckon with options.maxHeight + return prevGroup.top + prevGroup.height; + } + } + group.setOptions({ + top: top + }); + })(groups[orderedGroups[i]], groups[orderedGroups[i - 1]]); + } -/** - * Add forces acting on the node - * @param {number} fx Force in horizontal direction - * @param {number} fy Force in vertical direction - * @private - */ -Node.prototype._addForce = function(fx, fy) { - this.fx += fx; - this.fy += fy; -}; + // (re)create the labels + while (labels.firstChild) { + labels.removeChild(labels.firstChild); + } + for (i = 0; i < orderedGroups.length; i++) { + id = orderedGroups[i]; + label = this._createLabel(id); + labels.appendChild(label); + } -/** - * Perform one discrete step for the node - * @param {number} interval Time interval in seconds - */ -Node.prototype.discreteStep = function(interval) { - if (!this.xFixed) { - var dx = -this.damping * this.vx; // damping force - var ax = (this.fx + dx) / this.mass; // acceleration - this.vx += ax / interval; // velocity - this.x += this.vx / interval; // position + changed++; } - if (!this.yFixed) { - var dy = -this.damping * this.vy; // damping force - var ay = (this.fy + dy) / this.mass; // acceleration - this.vy += ay / interval; // velocity - this.y += this.vy / interval; // position + // reposition the labels + // TODO: labels are not displayed correctly when orientation=='top' + // TODO: width of labelPanel is not immediately updated on a change in groups + for (id in groups) { + if (groups.hasOwnProperty(id)) { + group = groups[id]; + label = group.label; + if (label) { + label.style.top = group.top + 'px'; + label.style.height = group.height + 'px'; + } + } } -}; - - -/** - * Check if this node has a fixed x and y position - * @return {boolean} true if fixed, false if not - */ -Node.prototype.isFixed = function() { - return (this.xFixed && this.yFixed); -}; -/** - * Check if this node is moving - * @param {number} vmin the minimum velocity considered as "moving" - * @return {boolean} true if moving, false if it has no velocity - */ -// TODO: replace this method with calculating the kinetic energy -Node.prototype.isMoving = function(vmin) { - return (Math.abs(this.vx) > vmin || Math.abs(this.vy) > vmin || - (!this.xFixed && Math.abs(this.fx) > this.minForce) || - (!this.yFixed && Math.abs(this.fy) > this.minForce)); + return (changed > 0); }; /** - * check if this node is selecte - * @return {boolean} selected True if node is selected, else false + * Create a label for group with given id + * @param {Number} id + * @return {Element} label + * @private */ -Node.prototype.isSelected = function() { - return this.selected; -}; +GroupSet.prototype._createLabel = function(id) { + var group = this.groups[id]; + var label = document.createElement('div'); + label.className = 'label'; + var inner = document.createElement('div'); + inner.className = 'inner'; + label.appendChild(inner); -/** - * Retrieve the value of the node. Can be undefined - * @return {Number} value - */ -Node.prototype.getValue = function() { - return this.value; -}; + var content = group.data && group.data.content; + if (content instanceof Element) { + inner.appendChild(content); + } + else if (content != undefined) { + inner.innerHTML = content; + } -/** - * Calculate the distance from the nodes location to the given location (x,y) - * @param {Number} x - * @param {Number} y - * @return {Number} value - */ -Node.prototype.getDistance = function(x, y) { - var dx = this.x - x, - dy = this.y - y; - return Math.sqrt(dx * dx + dy * dy); -}; + var className = group.data && group.data.className; + if (className) { + util.addClassName(label, className); + } + group.label = label; // TODO: not so nice, parking labels in the group this way!!! -/** - * Adjust the value range of the node. The node will adjust it's radius - * based on its value. - * @param {Number} min - * @param {Number} max - */ -Node.prototype.setValueRange = function(min, max) { - if (!this.radiusFixed && this.value !== undefined) { - var scale = (this.radiusMax - this.radiusMin) / (max - min); - this.radius = (this.value - min) * scale + this.radiusMin; - } + return label; }; /** - * Draw this node in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx + * Get container element + * @return {HTMLElement} container */ -Node.prototype.draw = function(ctx) { - throw "Draw method not initialized for node"; +GroupSet.prototype.getContainer = function getContainer() { + return this.dom.frame; }; /** - * Recalculate the size of this node in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx + * Get the width of the group labels + * @return {Number} width */ -Node.prototype.resize = function(ctx) { - throw "Resize method not initialized for node"; +GroupSet.prototype.getLabelsWidth = function getContainer() { + return this.props.labels.width; }; /** - * Check if this object is overlapping with the provided object - * @param {Object} obj an object with parameters left, top, right, bottom - * @return {boolean} True if location is located on node + * Reflow the component + * @return {Boolean} resized */ -Node.prototype.isOverlappingWith = function(obj) { - return (this.left < obj.right && - this.left + this.width > obj.left && - this.top < obj.bottom && - this.top + this.height > obj.top); -}; +GroupSet.prototype.reflow = function reflow() { + var changed = 0, + id, group, + options = this.options, + update = util.updateProperty, + asNumber = util.option.asNumber, + asSize = util.option.asSize, + frame = this.dom.frame; -Node.prototype._resizeImage = function (ctx) { - // TODO: pre calculate the image size - if (!this.width) { // undefined or 0 - var width, height; - if (this.value) { - var scale = this.imageObj.height / this.imageObj.width; - width = this.radius || this.imageObj.width; - height = this.radius * scale || this.imageObj.height; + if (frame) { + var maxHeight = asNumber(options.maxHeight); + var fixedHeight = (asSize(options.height) != null); + var height; + if (fixedHeight) { + height = frame.offsetHeight; } else { - width = this.imageObj.width; - height = this.imageObj.height; + // height is not specified, calculate the sum of the height of all groups + height = 0; + + for (id in this.groups) { + if (this.groups.hasOwnProperty(id)) { + group = this.groups[id]; + height += group.height; + } + } } - this.width = width; - this.height = height; + if (maxHeight != null) { + height = Math.min(height, maxHeight); + } + changed += update(this, 'height', height); + + changed += update(this, 'top', frame.offsetTop); + changed += update(this, 'left', frame.offsetLeft); + changed += update(this, 'width', frame.offsetWidth); } -}; -Node.prototype._drawImage = function (ctx) { - this._resizeImage(ctx); + // calculate the maximum width of the labels + var width = 0; + for (id in this.groups) { + if (this.groups.hasOwnProperty(id)) { + group = this.groups[id]; + var labelWidth = group.props && group.props.label && group.props.label.width || 0; + width = Math.max(width, labelWidth); + } + } + changed += update(this.props.labels, 'width', width); - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; + return (changed > 0); +}; - var yLabel; - if (this.imageObj) { - ctx.drawImage(this.imageObj, this.left, this.top, this.width, this.height); - yLabel = this.y + this.height / 2; +/** + * Hide the component from the DOM + * @return {Boolean} changed + */ +GroupSet.prototype.hide = function hide() { + if (this.dom.frame && this.dom.frame.parentNode) { + this.dom.frame.parentNode.removeChild(this.dom.frame); + return true; } else { - // image still loading... just draw the label for now - yLabel = this.y; + return false; } - - this._label(ctx, this.label, this.x, yLabel, undefined, "top"); }; - -Node.prototype._resizeBox = function (ctx) { - if (!this.width) { - var margin = 5; - var textSize = this.getTextSize(ctx); - this.width = textSize.width + 2 * margin; - this.height = textSize.height + 2 * margin; +/** + * Show the component in the DOM (when not already visible). + * A repaint will be executed when the component is not visible + * @return {Boolean} changed + */ +GroupSet.prototype.show = function show() { + if (!this.dom.frame || !this.dom.frame.parentNode) { + return this.repaint(); + } + else { + return false; } }; -Node.prototype._drawBox = function (ctx) { - this._resizeBox(ctx); - - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; - ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; - ctx.lineWidth = this.selected ? 2.0 : 1.0; - ctx.roundRect(this.left, this.top, this.width, this.height, this.radius); - ctx.fill(); - ctx.stroke(); - - this._label(ctx, this.label, this.x, this.y); +/** + * Handle updated groups + * @param {Number[]} ids + * @private + */ +GroupSet.prototype._onUpdate = function _onUpdate(ids) { + this._toQueue(ids, 'update'); }; - -Node.prototype._resizeDatabase = function (ctx) { - if (!this.width) { - var margin = 5; - var textSize = this.getTextSize(ctx); - var size = textSize.width + 2 * margin; - this.width = size; - this.height = size; - } +/** + * Handle changed groups + * @param {Number[]} ids + * @private + */ +GroupSet.prototype._onAdd = function _onAdd(ids) { + this._toQueue(ids, 'add'); }; -Node.prototype._drawDatabase = function (ctx) { - this._resizeDatabase(ctx); - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; - ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; - ctx.lineWidth = this.selected ? 2.0 : 1.0; - ctx.database(this.x - this.width/2, this.y - this.height*0.5, this.width, this.height); - ctx.fill(); - ctx.stroke(); - - this._label(ctx, this.label, this.x, this.y); +/** + * Handle removed groups + * @param {Number[]} ids + * @private + */ +GroupSet.prototype._onRemove = function _onRemove(ids) { + this._toQueue(ids, 'remove'); }; +/** + * Put groups in the queue to be added/updated/remove + * @param {Number[]} ids + * @param {String} action can be 'add', 'update', 'remove' + */ +GroupSet.prototype._toQueue = function _toQueue(ids, action) { + var queue = this.queue; + ids.forEach(function (id) { + queue[id] = action; + }); -Node.prototype._resizeCircle = function (ctx) { - if (!this.width) { - var margin = 5; - var textSize = this.getTextSize(ctx); - var diameter = Math.max(textSize.width, textSize.height) + 2 * margin; - this.radius = diameter / 2; - - this.width = diameter; - this.height = diameter; + if (this.controller) { + //this.requestReflow(); + this.requestRepaint(); } }; -Node.prototype._drawCircle = function (ctx) { - this._resizeCircle(ctx); - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; - ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; - ctx.lineWidth = this.selected ? 2.0 : 1.0; - ctx.circle(this.x, this.y, this.radius); - ctx.fill(); - ctx.stroke(); - - this._label(ctx, this.label, this.x, this.y); -}; +/** + * Create a timeline visualization + * @param {HTMLElement} container + * @param {vis.DataSet | Array | DataTable} [items] + * @param {Object} [options] See Timeline.setOptions for the available options. + * @constructor + */ +function Timeline (container, items, options) { + var me = this; + this.options = util.extend({ + orientation: 'bottom', + min: null, + max: null, + zoomMin: 10, // milliseconds + zoomMax: 1000 * 60 * 60 * 24 * 365 * 10000, // milliseconds + // moveable: true, // TODO: option moveable + // zoomable: true, // TODO: option zoomable + showMinorLabels: true, + showMajorLabels: true, + autoResize: false + }, options); -Node.prototype._resizeEllipse = function (ctx) { - if (!this.width) { - var textSize = this.getTextSize(ctx); + // controller + this.controller = new Controller(); - this.width = textSize.width * 1.5; - this.height = textSize.height * 2; - if (this.width < this.height) { - this.width = this.height; - } + // root panel + if (!container) { + throw new Error('No container element provided'); } -}; - -Node.prototype._drawEllipse = function (ctx) { - this._resizeEllipse(ctx); - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; + var rootOptions = Object.create(this.options); + rootOptions.height = function () { + if (me.options.height) { + // fixed height + return me.options.height; + } + else { + // auto height + return me.timeaxis.height + me.content.height; + } + }; + this.rootPanel = new RootPanel(container, rootOptions); + this.controller.add(this.rootPanel); - ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; - ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; - ctx.lineWidth = this.selected ? 2.0 : 1.0; - ctx.ellipse(this.left, this.top, this.width, this.height); - ctx.fill(); - ctx.stroke(); + // item panel + var itemOptions = Object.create(this.options); + itemOptions.left = function () { + return me.labelPanel.width; + }; + itemOptions.width = function () { + return me.rootPanel.width - me.labelPanel.width; + }; + itemOptions.top = null; + itemOptions.height = null; + this.itemPanel = new Panel(this.rootPanel, [], itemOptions); + this.controller.add(this.itemPanel); - this._label(ctx, this.label, this.x, this.y); -}; + // label panel + var labelOptions = Object.create(this.options); + labelOptions.top = null; + labelOptions.left = null; + labelOptions.height = null; + labelOptions.width = function () { + if (me.content && typeof me.content.getLabelsWidth === 'function') { + return me.content.getLabelsWidth(); + } + else { + return 0; + } + }; + this.labelPanel = new Panel(this.rootPanel, [], labelOptions); + this.controller.add(this.labelPanel); -Node.prototype._drawDot = function (ctx) { - this._drawShape(ctx, 'circle'); -}; + // range + var now = moment().hours(0).minutes(0).seconds(0).milliseconds(0); + this.range = new Range({ + start: now.clone().add('days', -3).valueOf(), + end: now.clone().add('days', 4).valueOf() + }); + /* TODO: fix range options + var rangeOptions = Object.create(this.options); + this.range = new Range(rangeOptions); + this.range.setRange( + now.clone().add('days', -3).valueOf(), + now.clone().add('days', 4).valueOf() + ); + */ + // TODO: reckon with options moveable and zoomable + this.range.subscribe(this.rootPanel, 'move', 'horizontal'); + this.range.subscribe(this.rootPanel, 'zoom', 'horizontal'); + this.range.on('rangechange', function () { + var force = true; + me.controller.requestReflow(force); + }); + this.range.on('rangechanged', function () { + var force = true; + me.controller.requestReflow(force); + }); -Node.prototype._drawTriangle = function (ctx) { - this._drawShape(ctx, 'triangle'); -}; + // TODO: put the listeners in setOptions, be able to dynamically change with options moveable and zoomable -Node.prototype._drawTriangleDown = function (ctx) { - this._drawShape(ctx, 'triangleDown'); -}; + // time axis + var timeaxisOptions = Object.create(rootOptions); + timeaxisOptions.range = this.range; + timeaxisOptions.left = null; + timeaxisOptions.top = null; + timeaxisOptions.width = '100%'; + timeaxisOptions.height = null; + this.timeaxis = new TimeAxis(this.itemPanel, [], timeaxisOptions); + this.timeaxis.setRange(this.range); + this.controller.add(this.timeaxis); -Node.prototype._drawSquare = function (ctx) { - this._drawShape(ctx, 'square'); -}; + // create itemset or groupset + this.setGroups(null); -Node.prototype._drawStar = function (ctx) { - this._drawShape(ctx, 'star'); -}; + this.itemsData = null; // DataSet + this.groupsData = null; // DataSet -Node.prototype._resizeShape = function (ctx) { - if (!this.width) { - var size = 2 * this.radius; - this.width = size; - this.height = size; + // set data + if (items) { + this.setItems(items); } -}; +} -Node.prototype._drawShape = function (ctx, shape) { - this._resizeShape(ctx); +/** + * Set options + * @param {Object} options TODO: describe the available options + */ +Timeline.prototype.setOptions = function (options) { + if (options) { + util.extend(this.options, options); + } - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; + // TODO: apply range min,max - ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; - ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; - ctx.lineWidth = this.selected ? 2.0 : 1.0; + this.controller.reflow(); + this.controller.repaint(); +}; - ctx[shape](this.x, this.y, this.radius); - ctx.fill(); - ctx.stroke(); +/** + * Set items + * @param {vis.DataSet | Array | DataTable | null} items + */ +Timeline.prototype.setItems = function(items) { + var initialLoad = (this.itemsData == null); - if (this.label) { - this._label(ctx, this.label, this.x, this.y + this.height / 2, undefined, 'top'); + // convert to type DataSet when needed + var newItemSet; + if (!items) { + newItemSet = null; } -}; - -Node.prototype._resizeText = function (ctx) { - if (!this.width) { - var margin = 5; - var textSize = this.getTextSize(ctx); - this.width = textSize.width + 2 * margin; - this.height = textSize.height + 2 * margin; + else if (items instanceof DataSet) { + newItemSet = items; + } + if (!(items instanceof DataSet)) { + newItemSet = new DataSet({ + convert: { + start: 'Date', + end: 'Date' + } + }); + newItemSet.add(items); } -}; - -Node.prototype._drawText = function (ctx) { - this._resizeText(ctx); - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - this._label(ctx, this.label, this.x, this.y); -}; + // set items + this.itemsData = newItemSet; + this.content.setItems(newItemSet); + if (initialLoad && (this.options.start == undefined || this.options.end == undefined)) { + // apply the data range as range + var dataRange = this.getItemRange(); -Node.prototype._label = function (ctx, text, x, y, align, baseline) { - if (text) { - ctx.font = (this.selected ? "bold " : "") + this.fontSize + "px " + this.fontFace; - ctx.fillStyle = this.fontColor || "black"; - ctx.textAlign = align || "center"; - ctx.textBaseline = baseline || "middle"; + // add 5% on both sides + var min = dataRange.min; + var max = dataRange.max; + if (min != null && max != null) { + var interval = (max.valueOf() - min.valueOf()); + if (interval <= 0) { + // prevent an empty interval + interval = 24 * 60 * 60 * 1000; // 1 day + } + min = new Date(min.valueOf() - interval * 0.05); + max = new Date(max.valueOf() + interval * 0.05); + } - var lines = text.split('\n'), - lineCount = lines.length, - fontSize = (this.fontSize + 4), - yLine = y + (1 - lineCount) / 2 * fontSize; + // override specified start and/or end date + if (this.options.start != undefined) { + min = new Date(this.options.start.valueOf()); + } + if (this.options.end != undefined) { + max = new Date(this.options.end.valueOf()); + } - for (var i = 0; i < lineCount; i++) { - ctx.fillText(lines[i], x, yLine); - yLine += fontSize; + // apply range if there is a min or max available + if (min != null || max != null) { + this.range.setRange(min, max); } } }; +/** + * Set groups + * @param {vis.DataSet | Array | DataTable} groups + */ +Timeline.prototype.setGroups = function(groups) { + var me = this; + this.groupsData = groups; -Node.prototype.getTextSize = function(ctx) { - if (this.label != undefined) { - ctx.font = (this.selected ? "bold " : "") + this.fontSize + "px " + this.fontFace; - - var lines = this.label.split('\n'), - height = (this.fontSize + 4) * lines.length, - width = 0; - - for (var i = 0, iMax = lines.length; i < iMax; i++) { - width = Math.max(width, ctx.measureText(lines[i]).width); + // switch content type between ItemSet or GroupSet when needed + var type = this.groupsData ? GroupSet : ItemSet; + if (!(this.content instanceof type)) { + // remove old content set + if (this.content) { + this.content.hide(); + if (this.content.setItems) { + this.content.setItems(); // disconnect from items + } + if (this.content.setGroups) { + this.content.setGroups(); // disconnect from groups + } + this.controller.remove(this.content); } - return {"width": width, "height": height}; - } - else { - return {"width": 0, "height": 0}; + // create new content set + var options = Object.create(this.options); + util.extend(options, { + top: function () { + if (me.options.orientation == 'top') { + return me.timeaxis.height; + } + else { + return me.itemPanel.height - me.timeaxis.height - me.content.height; + } + }, + left: null, + width: '100%', + height: function () { + if (me.options.height) { + return me.itemPanel.height - me.timeaxis.height; + } + else { + return null; + } + }, + maxHeight: function () { + if (me.options.maxHeight) { + if (!util.isNumber(me.options.maxHeight)) { + throw new TypeError('Number expected for property maxHeight'); + } + return me.options.maxHeight - me.timeaxis.height; + } + else { + return null; + } + }, + labelContainer: function () { + return me.labelPanel.getContainer(); + } + }); + this.content = new type(this.itemPanel, [this.timeaxis], options); + if (this.content.setRange) { + this.content.setRange(this.range); + } + if (this.content.setItems) { + this.content.setItems(this.itemsData); + } + if (this.content.setGroups) { + this.content.setGroups(this.groupsData); + } + this.controller.add(this.content); } }; /** - * @class Edge - * - * A edge connects two nodes - * @param {Object} properties Object with properties. Must contain - * At least properties from and to. - * Available properties: from (number), - * to (number), label (string, color (string), - * width (number), style (string), - * length (number), title (string) - * @param {Graph} graph A graph object, used to find and edge to - * nodes. - * @param {Object} constants An object with default values for - * example for the color + * Get the data range of the item set. + * @returns {{min: Date, max: Date}} range A range with a start and end Date. + * When no minimum is found, min==null + * When no maximum is found, max==null */ -function Edge (properties, graph, constants) { - if (!graph) { - throw "No graph provided"; +Timeline.prototype.getItemRange = function getItemRange() { + // calculate min from start filed + var itemsData = this.itemsData, + min = null, + max = null; + + if (itemsData) { + // calculate the minimum value of the field 'start' + var minItem = itemsData.min('start'); + min = minItem ? minItem.start.valueOf() : null; + + // calculate maximum value of fields 'start' and 'end' + var maxStartItem = itemsData.max('start'); + if (maxStartItem) { + max = maxStartItem.start.valueOf(); + } + var maxEndItem = itemsData.max('end'); + if (maxEndItem) { + if (max == null) { + max = maxEndItem.end.valueOf(); + } + else { + max = Math.max(max, maxEndItem.end.valueOf()); + } + } + } + + return { + min: (min != null) ? new Date(min) : null, + max: (max != null) ? new Date(max) : null + }; +}; + +(function(exports) { + /** + * Parse a text source containing data in DOT language into a JSON object. + * The object contains two lists: one with nodes and one with edges. + * + * DOT language reference: http://www.graphviz.org/doc/info/lang.html + * + * @param {String} data Text containing a graph in DOT-notation + * @return {Object} graph An object containing two parameters: + * {Object[]} nodes + * {Object[]} edges + */ + function parseDOT (data) { + dot = data; + return parseGraph(); } - this.graph = graph; - // initialize constants - this.widthMin = constants.edges.widthMin; - this.widthMax = constants.edges.widthMax; + // token types enumeration + var TOKENTYPE = { + NULL : 0, + DELIMITER : 1, + IDENTIFIER: 2, + UNKNOWN : 3 + }; - // initialize variables - this.id = undefined; - this.fromId = undefined; - this.toId = undefined; - this.style = constants.edges.style; - this.title = undefined; - this.width = constants.edges.width; - this.value = undefined; - this.length = constants.edges.length; + // map with all delimiters + var DELIMITERS = { + '{': true, + '}': true, + '[': true, + ']': true, + ';': true, + '=': true, + ',': true, - this.from = null; // a node - this.to = null; // a node - this.connected = false; + '->': true, + '--': true + }; - // Added to support dashed lines - // David Jordan - // 2012-08-08 - this.dash = util.extend({}, constants.edges.dash); // contains properties length, gap, altLength + var dot = ''; // current dot file + var index = 0; // current index in dot file + var c = ''; // current token character in expr + var token = ''; // current token + var tokenType = TOKENTYPE.NULL; // type of the token - this.stiffness = undefined; // depends on the length of the edge - this.color = constants.edges.color; - this.widthFixed = false; - this.lengthFixed = false; + /** + * Get the first character from the dot file. + * The character is stored into the char c. If the end of the dot file is + * reached, the function puts an empty string in c. + */ + function first() { + index = 0; + c = dot.charAt(0); + } - this.setProperties(properties, constants); -} + /** + * Get the next character from the dot file. + * The character is stored into the char c. If the end of the dot file is + * reached, the function puts an empty string in c. + */ + function next() { + index++; + c = dot.charAt(index); + } -/** - * Set or overwrite properties for the edge - * @param {Object} properties an object with properties - * @param {Object} constants and object with default, global properties - */ -Edge.prototype.setProperties = function(properties, constants) { - if (!properties) { - return; + /** + * Preview the next character from the dot file. + * @return {String} cNext + */ + function nextPreview() { + return dot.charAt(index + 1); } - if (properties.from != undefined) {this.fromId = properties.from;} - if (properties.to != undefined) {this.toId = properties.to;} + /** + * Test whether given character is alphabetic or numeric + * @param {String} c + * @return {Boolean} isAlphaNumeric + */ + var regexAlphaNumeric = /[a-zA-Z_0-9.:#]/; + function isAlphaNumeric(c) { + return regexAlphaNumeric.test(c); + } - if (properties.id != undefined) {this.id = properties.id;} - if (properties.style != undefined) {this.style = properties.style;} - if (properties.label != undefined) {this.label = properties.label;} - if (this.label) { - this.fontSize = constants.edges.fontSize; - this.fontFace = constants.edges.fontFace; - this.fontColor = constants.edges.fontColor; - if (properties.fontColor != undefined) {this.fontColor = properties.fontColor;} - if (properties.fontSize != undefined) {this.fontSize = properties.fontSize;} - if (properties.fontFace != undefined) {this.fontFace = properties.fontFace;} + /** + * Merge all properties of object b into object b + * @param {Object} a + * @param {Object} b + * @return {Object} a + */ + function merge (a, b) { + if (!a) { + a = {}; + } + + if (b) { + for (var name in b) { + if (b.hasOwnProperty(name)) { + a[name] = b[name]; + } + } + } + return a; } - if (properties.title != undefined) {this.title = properties.title;} - if (properties.width != undefined) {this.width = properties.width;} - if (properties.value != undefined) {this.value = properties.value;} - if (properties.length != undefined) {this.length = properties.length;} - // Added to support dashed lines - // David Jordan - // 2012-08-08 - if (properties.dash) { - if (properties.dash.length != undefined) {this.dash.length = properties.dash.length;} - if (properties.dash.gap != undefined) {this.dash.gap = properties.dash.gap;} - if (properties.dash.altLength != undefined) {this.dash.altLength = properties.dash.altLength;} + /** + * Set a value in an object, where the provided parameter name can be a + * path with nested parameters. For example: + * + * var obj = {a: 2}; + * setValue(obj, 'b.c', 3); // obj = {a: 2, b: {c: 3}} + * + * @param {Object} obj + * @param {String} path A parameter name or dot-separated parameter path, + * like "color.highlight.border". + * @param {*} value + */ + function setValue(obj, path, value) { + var keys = path.split('.'); + var o = obj; + while (keys.length) { + var key = keys.shift(); + if (keys.length) { + // this isn't the end point + if (!o[key]) { + o[key] = {}; + } + o = o[key]; + } + else { + // this is the end point + o[key] = value; + } + } } - - if (properties.color != undefined) {this.color = properties.color;} - // A node is connected when it has a from and to node. - this.connect(); + /** + * Add a node to a graph object. If there is already a node with + * the same id, their attributes will be merged. + * @param {Object} graph + * @param {Object} node + */ + function addNode(graph, node) { + var i, len; + var current = null; - this.widthFixed = this.widthFixed || (properties.width != undefined); - this.lengthFixed = this.lengthFixed || (properties.length != undefined); - this.stiffness = 1 / this.length; + // find root graph (in case of subgraph) + var graphs = [graph]; // list with all graphs from current graph to root graph + var root = graph; + while (root.parent) { + graphs.push(root.parent); + root = root.parent; + } - // set draw method based on style - switch (this.style) { - case 'line': this.draw = this._drawLine; break; - case 'arrow': this.draw = this._drawArrow; break; - case 'arrow-center': this.draw = this._drawArrowCenter; break; - case 'dash-line': this.draw = this._drawDashLine; break; - default: this.draw = this._drawLine; break; - } -}; + // find existing node (at root level) by its id + if (root.nodes) { + for (i = 0, len = root.nodes.length; i < len; i++) { + if (node.id === root.nodes[i].id) { + current = root.nodes[i]; + break; + } + } + } -/** - * Connect an edge to its nodes - */ -Edge.prototype.connect = function () { - this.disconnect(); + if (!current) { + // this is a new node + current = { + id: node.id + }; + if (graph.node) { + // clone default attributes + current.attr = merge(current.attr, graph.node); + } + } - this.from = this.graph.nodes[this.fromId] || null; - this.to = this.graph.nodes[this.toId] || null; - this.connected = (this.from && this.to); + // add node to this (sub)graph and all its parent graphs + for (i = graphs.length - 1; i >= 0; i--) { + var g = graphs[i]; - if (this.connected) { - this.from.attachEdge(this); - this.to.attachEdge(this); - } - else { - if (this.from) { - this.from.detachEdge(this); + if (!g.nodes) { + g.nodes = []; + } + if (g.nodes.indexOf(current) == -1) { + g.nodes.push(current); + } } - if (this.to) { - this.to.detachEdge(this); + + // merge attributes + if (node.attr) { + current.attr = merge(current.attr, node.attr); } } -}; -/** - * Disconnect an edge from its nodes - */ -Edge.prototype.disconnect = function () { - if (this.from) { - this.from.detachEdge(this); - this.from = null; - } - if (this.to) { - this.to.detachEdge(this); - this.to = null; + /** + * Add an edge to a graph object + * @param {Object} graph + * @param {Object} edge + */ + function addEdge(graph, edge) { + if (!graph.edges) { + graph.edges = []; + } + graph.edges.push(edge); + if (graph.edge) { + var attr = merge({}, graph.edge); // clone default attributes + edge.attr = merge(attr, edge.attr); // merge attributes + } } - this.connected = false; -}; - -/** - * get the title of this edge. - * @return {string} title The title of the edge, or undefined when no title - * has been set. - */ -Edge.prototype.getTitle = function() { - return this.title; -}; - + /** + * Create an edge to a graph object + * @param {Object} graph + * @param {String | Number | Object} from + * @param {String | Number | Object} to + * @param {String} type + * @param {Object | null} attr + * @return {Object} edge + */ + function createEdge(graph, from, to, type, attr) { + var edge = { + from: from, + to: to, + type: type + }; -/** - * Retrieve the value of the edge. Can be undefined - * @return {Number} value - */ -Edge.prototype.getValue = function() { - return this.value; -}; + if (graph.edge) { + edge.attr = merge({}, graph.edge); // clone default attributes + } + edge.attr = merge(edge.attr || {}, attr); // merge attributes -/** - * Adjust the value range of the edge. The edge will adjust it's width - * based on its value. - * @param {Number} min - * @param {Number} max - */ -Edge.prototype.setValueRange = function(min, max) { - if (!this.widthFixed && this.value !== undefined) { - var factor = (this.widthMax - this.widthMin) / (max - min); - this.width = (this.value - min) * factor + this.widthMin; + return edge; } -}; -/** - * Redraw a edge - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - */ -Edge.prototype.draw = function(ctx) { - throw "Method draw not initialized in edge"; -}; + /** + * Get next token in the current dot file. + * The token and token type are available as token and tokenType + */ + function getToken() { + tokenType = TOKENTYPE.NULL; + token = ''; -/** - * Check if this object is overlapping with the provided object - * @param {Object} obj an object with parameters left, top - * @return {boolean} True if location is located on the edge - */ -Edge.prototype.isOverlappingWith = function(obj) { - var distMax = 10; + // skip over whitespaces + while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter + next(); + } - var xFrom = this.from.x; - var yFrom = this.from.y; - var xTo = this.to.x; - var yTo = this.to.y; - var xObj = obj.left; - var yObj = obj.top; + do { + var isComment = false; + // skip comment + if (c == '#') { + // find the previous non-space character + var i = index - 1; + while (dot.charAt(i) == ' ' || dot.charAt(i) == '\t') { + i--; + } + if (dot.charAt(i) == '\n' || dot.charAt(i) == '') { + // the # is at the start of a line, this is indeed a line comment + while (c != '' && c != '\n') { + next(); + } + isComment = true; + } + } + if (c == '/' && nextPreview() == '/') { + // skip line comment + while (c != '' && c != '\n') { + next(); + } + isComment = true; + } + if (c == '/' && nextPreview() == '*') { + // skip block comment + while (c != '') { + if (c == '*' && nextPreview() == '/') { + // end of block comment found. skip these last two characters + next(); + next(); + break; + } + else { + next(); + } + } + isComment = true; + } - var dist = Edge._dist(xFrom, yFrom, xTo, yTo, xObj, yObj); + // skip over whitespaces + while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter + next(); + } + } + while (isComment); - return (dist < distMax); -}; + // check for end of dot file + if (c == '') { + // token is still empty + tokenType = TOKENTYPE.DELIMITER; + return; + } + // check for delimiters consisting of 2 characters + var c2 = c + nextPreview(); + if (DELIMITERS[c2]) { + tokenType = TOKENTYPE.DELIMITER; + token = c2; + next(); + next(); + return; + } -/** - * Redraw a edge as a line - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Edge.prototype._drawLine = function(ctx) { - // set style - ctx.strokeStyle = this.color; - ctx.lineWidth = this._getLineWidth(); + // check for delimiters consisting of 1 character + if (DELIMITERS[c]) { + tokenType = TOKENTYPE.DELIMITER; + token = c; + next(); + return; + } - var point; - if (this.from != this.to) { - // draw line - this._line(ctx); + // check for an identifier (number or string) + // TODO: more precise parsing of numbers/strings (and the port separator ':') + if (isAlphaNumeric(c) || c == '-') { + token += c; + next(); - // draw label - if (this.label) { - point = this._pointOnLine(0.5); - this._label(ctx, this.label, point.x, point.y); - } - } - else { - var x, y; - var radius = this.length / 4; - var node = this.from; - if (!node.width) { - node.resize(ctx); + while (isAlphaNumeric(c)) { + token += c; + next(); + } + if (token == 'false') { + token = false; // convert to boolean + } + else if (token == 'true') { + token = true; // convert to boolean + } + else if (!isNaN(Number(token))) { + token = Number(token); // convert to number + } + tokenType = TOKENTYPE.IDENTIFIER; + return; } - if (node.width > node.height) { - x = node.x + node.width / 2; - y = node.y - radius; + + // check for a string enclosed by double quotes + if (c == '"') { + next(); + while (c != '' && (c != '"' || (c == '"' && nextPreview() == '"'))) { + token += c; + if (c == '"') { // skip the escape character + next(); + } + next(); + } + if (c != '"') { + throw newSyntaxError('End of string " expected'); + } + next(); + tokenType = TOKENTYPE.IDENTIFIER; + return; } - else { - x = node.x + radius; - y = node.y - node.height / 2; + + // something unknown is found, wrong characters, a syntax error + tokenType = TOKENTYPE.UNKNOWN; + while (c != '') { + token += c; + next(); } - this._circle(ctx, x, y, radius); - point = this._pointOnCircle(x, y, radius, 0.5); - this._label(ctx, this.label, point.x, point.y); + throw new SyntaxError('Syntax error in part "' + chop(token, 30) + '"'); } -}; -/** - * Get the line width of the edge. Depends on width and whether one of the - * connected nodes is selected. - * @return {Number} width - * @private - */ -Edge.prototype._getLineWidth = function() { - if (this.from.selected || this.to.selected) { - return Math.min(this.width * 2, this.widthMax); - } - else { - return this.width; - } -}; + /** + * Parse a graph. + * @returns {Object} graph + */ + function parseGraph() { + var graph = {}; -/** - * Draw a line between two nodes - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Edge.prototype._line = function (ctx) { - // draw a straight line - ctx.beginPath(); - ctx.moveTo(this.from.x, this.from.y); - ctx.lineTo(this.to.x, this.to.y); - ctx.stroke(); -}; + first(); + getToken(); -/** - * Draw a line from a node to itself, a circle - * @param {CanvasRenderingContext2D} ctx - * @param {Number} x - * @param {Number} y - * @param {Number} radius - * @private - */ -Edge.prototype._circle = function (ctx, x, y, radius) { - // draw a circle - ctx.beginPath(); - ctx.arc(x, y, radius, 0, 2 * Math.PI, false); - ctx.stroke(); -}; + // optional strict keyword + if (token == 'strict') { + graph.strict = true; + getToken(); + } -/** - * Draw label with white background and with the middle at (x, y) - * @param {CanvasRenderingContext2D} ctx - * @param {String} text - * @param {Number} x - * @param {Number} y - * @private - */ -Edge.prototype._label = function (ctx, text, x, y) { - if (text) { - // TODO: cache the calculated size - ctx.font = ((this.from.selected || this.to.selected) ? "bold " : "") + - this.fontSize + "px " + this.fontFace; - ctx.fillStyle = 'white'; - var width = ctx.measureText(text).width; - var height = this.fontSize; - var left = x - width / 2; - var top = y - height / 2; + // graph or digraph keyword + if (token == 'graph' || token == 'digraph') { + graph.type = token; + getToken(); + } - ctx.fillRect(left, top, width, height); + // optional graph id + if (tokenType == TOKENTYPE.IDENTIFIER) { + graph.id = token; + getToken(); + } - // draw text - ctx.fillStyle = this.fontColor || "black"; - ctx.textAlign = "left"; - ctx.textBaseline = "top"; - ctx.fillText(text, left, top); - } -}; + // open angle bracket + if (token != '{') { + throw newSyntaxError('Angle bracket { expected'); + } + getToken(); -/** - * Redraw a edge as a dashed line - * Draw this edge in the given canvas - * @author David Jordan - * @date 2012-08-08 - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Edge.prototype._drawDashLine = function(ctx) { - // set style - ctx.strokeStyle = this.color; - ctx.lineWidth = this._getLineWidth(); + // statements + parseStatements(graph); - // draw dashed line - ctx.beginPath(); - ctx.lineCap = 'round'; - if (this.dash.altLength != undefined) //If an alt dash value has been set add to the array this value - { - ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, - [this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]); - } - else if (this.dash.length != undefined && this.dash.gap != undefined) //If a dash and gap value has been set add to the array this value - { - ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, - [this.dash.length,this.dash.gap]); - } - else //If all else fails draw a line - { - ctx.moveTo(this.from.x, this.from.y); - ctx.lineTo(this.to.x, this.to.y); - } - ctx.stroke(); + // close angle bracket + if (token != '}') { + throw newSyntaxError('Angle bracket } expected'); + } + getToken(); - // draw label - if (this.label) { - var point = this._pointOnLine(0.5); - this._label(ctx, this.label, point.x, point.y); - } -}; + // end of file + if (token !== '') { + throw newSyntaxError('End of file expected'); + } + getToken(); -/** - * Get a point on a line - * @param {Number} percentage. Value between 0 (line start) and 1 (line end) - * @return {Object} point - * @private - */ -Edge.prototype._pointOnLine = function (percentage) { - return { - x: (1 - percentage) * this.from.x + percentage * this.to.x, - y: (1 - percentage) * this.from.y + percentage * this.to.y - } -}; + // remove temporary default properties + delete graph.node; + delete graph.edge; + delete graph.graph; -/** - * Get a point on a circle - * @param {Number} x - * @param {Number} y - * @param {Number} radius - * @param {Number} percentage. Value between 0 (line start) and 1 (line end) - * @return {Object} point - * @private - */ -Edge.prototype._pointOnCircle = function (x, y, radius, percentage) { - var angle = (percentage - 3/8) * 2 * Math.PI; - return { - x: x + radius * Math.cos(angle), - y: y - radius * Math.sin(angle) + return graph; } -}; - -/** - * Redraw a edge as a line with an arrow halfway the line - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Edge.prototype._drawArrowCenter = function(ctx) { - var point; - // set style - ctx.strokeStyle = this.color; - ctx.fillStyle = this.color; - ctx.lineWidth = this._getLineWidth(); - - if (this.from != this.to) { - // draw line - this._line(ctx); - - // draw an arrow halfway the line - var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); - var length = 10 + 5 * this.width; // TODO: make customizable? - point = this._pointOnLine(0.5); - ctx.arrow(point.x, point.y, angle, length); - ctx.fill(); - ctx.stroke(); - // draw label - if (this.label) { - point = this._pointOnLine(0.5); - this._label(ctx, this.label, point.x, point.y); + /** + * Parse a list with statements. + * @param {Object} graph + */ + function parseStatements (graph) { + while (token !== '' && token != '}') { + parseStatement(graph); + if (token == ';') { + getToken(); + } } } - else { - // draw circle - var x, y; - var radius = this.length / 4; - var node = this.from; - if (!node.width) { - node.resize(ctx); - } - if (node.width > node.height) { - x = node.x + node.width / 2; - y = node.y - radius; + + /** + * Parse a single statement. Can be a an attribute statement, node + * statement, a series of node statements and edge statements, or a + * parameter. + * @param {Object} graph + */ + function parseStatement(graph) { + // parse subgraph + var subgraph = parseSubgraph(graph); + if (subgraph) { + // edge statements + parseEdge(graph, subgraph); + + return; } - else { - x = node.x + radius; - y = node.y - node.height / 2; + + // parse an attribute statement + var attr = parseAttributeStatement(graph); + if (attr) { + return; } - this._circle(ctx, x, y, radius); - // draw all arrows - var angle = 0.2 * Math.PI; - var length = 10 + 5 * this.width; // TODO: make customizable? - point = this._pointOnCircle(x, y, radius, 0.5); - ctx.arrow(point.x, point.y, angle, length); - ctx.fill(); - ctx.stroke(); + // parse node + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Identifier expected'); + } + var id = token; // id can be a string or a number + getToken(); - // draw label - if (this.label) { - point = this._pointOnCircle(x, y, radius, 0.5); - this._label(ctx, this.label, point.x, point.y); + if (token == '=') { + // id statement + getToken(); + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Identifier expected'); + } + graph[id] = token; + getToken(); + // TODO: implement comma separated list with "a_list: ID=ID [','] [a_list] " + } + else { + parseNodeStatement(graph, id); } } -}; + /** + * Parse a subgraph + * @param {Object} graph parent graph object + * @return {Object | null} subgraph + */ + function parseSubgraph (graph) { + var subgraph = null; + // optional subgraph keyword + if (token == 'subgraph') { + subgraph = {}; + subgraph.type = 'subgraph'; + getToken(); -/** - * Redraw a edge as a line with an arrow - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Edge.prototype._drawArrow = function(ctx) { - // set style - ctx.strokeStyle = this.color; - ctx.fillStyle = this.color; - ctx.lineWidth = this._getLineWidth(); + // optional graph id + if (tokenType == TOKENTYPE.IDENTIFIER) { + subgraph.id = token; + getToken(); + } + } - // draw line - var angle, length; - if (this.from != this.to) { - // calculate length and angle of the line - angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); - var dx = (this.to.x - this.from.x); - var dy = (this.to.y - this.from.y); - var lEdge = Math.sqrt(dx * dx + dy * dy); + // open angle bracket + if (token == '{') { + getToken(); - var lFrom = this.from.distanceToBorder(ctx, angle + Math.PI); - var pFrom = (lEdge - lFrom) / lEdge; - var xFrom = (pFrom) * this.from.x + (1 - pFrom) * this.to.x; - var yFrom = (pFrom) * this.from.y + (1 - pFrom) * this.to.y; + if (!subgraph) { + subgraph = {}; + } + subgraph.parent = graph; + subgraph.node = graph.node; + subgraph.edge = graph.edge; + subgraph.graph = graph.graph; - var lTo = this.to.distanceToBorder(ctx, angle); - var pTo = (lEdge - lTo) / lEdge; - var xTo = (1 - pTo) * this.from.x + pTo * this.to.x; - var yTo = (1 - pTo) * this.from.y + pTo * this.to.y; + // statements + parseStatements(subgraph); - ctx.beginPath(); - ctx.moveTo(xFrom, yFrom); - ctx.lineTo(xTo, yTo); - ctx.stroke(); + // close angle bracket + if (token != '}') { + throw newSyntaxError('Angle bracket } expected'); + } + getToken(); - // draw arrow at the end of the line - length = 10 + 5 * this.width; // TODO: make customizable? - ctx.arrow(xTo, yTo, angle, length); - ctx.fill(); - ctx.stroke(); + // remove temporary default properties + delete subgraph.node; + delete subgraph.edge; + delete subgraph.graph; + delete subgraph.parent; - // draw label - if (this.label) { - var point = this._pointOnLine(0.5); - this._label(ctx, this.label, point.x, point.y); + // register at the parent graph + if (!graph.subgraphs) { + graph.subgraphs = []; + } + graph.subgraphs.push(subgraph); } + + return subgraph; } - else { - // draw circle - var node = this.from; - var x, y, arrow; - var radius = this.length / 4; - if (!node.width) { - node.resize(ctx); - } - if (node.width > node.height) { - x = node.x + node.width / 2; - y = node.y - radius; - arrow = { - x: x, - y: node.y, - angle: 0.9 * Math.PI - }; - } - else { - x = node.x + radius; - y = node.y - node.height / 2; - arrow = { - x: node.x, - y: y, - angle: 0.6 * Math.PI - }; - } - ctx.beginPath(); - // TODO: do not draw a circle, but an arc - // TODO: similarly, for a line without arrows, draw to the border of the nodes instead of the center - ctx.arc(x, y, radius, 0, 2 * Math.PI, false); - ctx.stroke(); - // draw all arrows - length = 10 + 5 * this.width; // TODO: make customizable? - ctx.arrow(arrow.x, arrow.y, arrow.angle, length); - ctx.fill(); - ctx.stroke(); + /** + * parse an attribute statement like "node [shape=circle fontSize=16]". + * Available keywords are 'node', 'edge', 'graph'. + * The previous list with default attributes will be replaced + * @param {Object} graph + * @returns {String | null} keyword Returns the name of the parsed attribute + * (node, edge, graph), or null if nothing + * is parsed. + */ + function parseAttributeStatement (graph) { + // attribute statements + if (token == 'node') { + getToken(); - // draw label - if (this.label) { - point = this._pointOnCircle(x, y, radius, 0.5); - this._label(ctx, this.label, point.x, point.y); + // node attributes + graph.node = parseAttributeList(); + return 'node'; } - } -}; - + else if (token == 'edge') { + getToken(); + // edge attributes + graph.edge = parseAttributeList(); + return 'edge'; + } + else if (token == 'graph') { + getToken(); -/** - * Calculate the distance between a point (x3,y3) and a line segment from - * (x1,y1) to (x2,y2). - * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment - * @param {number} x1 - * @param {number} y1 - * @param {number} x2 - * @param {number} y2 - * @param {number} x3 - * @param {number} y3 - * @private - */ -Edge._dist = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point - var px = x2-x1, - py = y2-y1, - something = px*px + py*py, - u = ((x3 - x1) * px + (y3 - y1) * py) / something; + // graph attributes + graph.graph = parseAttributeList(); + return 'graph'; + } - if (u > 1) { - u = 1; + return null; } - else if (u < 0) { - u = 0; + + /** + * parse a node statement + * @param {Object} graph + * @param {String | Number} id + */ + function parseNodeStatement(graph, id) { + // node statement + var node = { + id: id + }; + var attr = parseAttributeList(); + if (attr) { + node.attr = attr; + } + addNode(graph, node); + + // edge statements + parseEdge(graph, id); } - var x = x1 + u * px, - y = y1 + u * py, - dx = x - x3, - dy = y - y3; + /** + * Parse an edge or a series of edges + * @param {Object} graph + * @param {String | Number} from Id of the from node + */ + function parseEdge(graph, from) { + while (token == '->' || token == '--') { + var to; + var type = token; + getToken(); - //# Note: If the actual distance does not matter, - //# if you only want to compare what this function - //# returns to other results of this function, you - //# can just return the squared distance instead - //# (i.e. remove the sqrt) to gain a little performance + var subgraph = parseSubgraph(graph); + if (subgraph) { + to = subgraph; + } + else { + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Identifier or subgraph expected'); + } + to = token; + addNode(graph, { + id: to + }); + getToken(); + } - return Math.sqrt(dx*dx + dy*dy); -}; + // parse edge attributes + var attr = parseAttributeList(); -/** - * Popup is a class to create a popup window with some text - * @param {Element} container The container object. - * @param {Number} [x] - * @param {Number} [y] - * @param {String} [text] - */ -function Popup(container, x, y, text) { - if (container) { - this.container = container; - } - else { - this.container = document.body; - } - this.x = 0; - this.y = 0; - this.padding = 5; + // create edge + var edge = createEdge(graph, from, to, type, attr); + addEdge(graph, edge); - if (x !== undefined && y !== undefined ) { - this.setPosition(x, y); - } - if (text !== undefined) { - this.setText(text); + from = to; + } } - // create the frame - this.frame = document.createElement("div"); - var style = this.frame.style; - style.position = "absolute"; - style.visibility = "hidden"; - style.border = "1px solid #666"; - style.color = "black"; - style.padding = this.padding + "px"; - style.backgroundColor = "#FFFFC6"; - style.borderRadius = "3px"; - style.MozBorderRadius = "3px"; - style.WebkitBorderRadius = "3px"; - style.boxShadow = "3px 3px 10px rgba(128, 128, 128, 0.5)"; - style.whiteSpace = "nowrap"; - this.container.appendChild(this.frame); -}; + /** + * Parse a set with attributes, + * for example [label="1.000", shape=solid] + * @return {Object | null} attr + */ + function parseAttributeList() { + var attr = null; -/** - * @param {number} x Horizontal position of the popup window - * @param {number} y Vertical position of the popup window - */ -Popup.prototype.setPosition = function(x, y) { - this.x = parseInt(x); - this.y = parseInt(y); -}; + while (token == '[') { + getToken(); + attr = {}; + while (token !== '' && token != ']') { + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Attribute name expected'); + } + var name = token; -/** - * Set the text for the popup window. This can be HTML code - * @param {string} text - */ -Popup.prototype.setText = function(text) { - this.frame.innerHTML = text; -}; + getToken(); + if (token != '=') { + throw newSyntaxError('Equal sign = expected'); + } + getToken(); -/** - * Show the popup window - * @param {boolean} show Optional. Show or hide the window - */ -Popup.prototype.show = function (show) { - if (show === undefined) { - show = true; - } + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Attribute value expected'); + } + var value = token; + setValue(attr, name, value); // name can be a path - if (show) { - var height = this.frame.clientHeight; - var width = this.frame.clientWidth; - var maxHeight = this.frame.parentNode.clientHeight; - var maxWidth = this.frame.parentNode.clientWidth; + getToken(); + if (token ==',') { + getToken(); + } + } - var top = (this.y - height); - if (top + height + this.padding > maxHeight) { - top = maxHeight - height - this.padding; - } - if (top < this.padding) { - top = this.padding; + if (token != ']') { + throw newSyntaxError('Bracket ] expected'); + } + getToken(); } - var left = this.x; - if (left + width + this.padding > maxWidth) { - left = maxWidth - width - this.padding; - } - if (left < this.padding) { - left = this.padding; - } + return attr; + } - this.frame.style.left = left + "px"; - this.frame.style.top = top + "px"; - this.frame.style.visibility = "visible"; + /** + * Create a syntax error with extra information on current token and index. + * @param {String} message + * @returns {SyntaxError} err + */ + function newSyntaxError(message) { + return new SyntaxError(message + ', got "' + chop(token, 30) + '" (char ' + index + ')'); } - else { - this.hide(); + + /** + * Chop off text after a maximum length + * @param {String} text + * @param {Number} maxLength + * @returns {String} + */ + function chop (text, maxLength) { + return (text.length <= maxLength) ? text : (text.substr(0, 27) + '...'); } -}; -/** - * Hide the popup window - */ -Popup.prototype.hide = function () { - this.frame.style.visibility = "hidden"; -}; + /** + * Execute a function fn for each pair of elements in two arrays + * @param {Array | *} array1 + * @param {Array | *} array2 + * @param {function} fn + */ + function forEach2(array1, array2, fn) { + if (array1 instanceof Array) { + array1.forEach(function (elem1) { + if (array2 instanceof Array) { + array2.forEach(function (elem2) { + fn(elem1, elem2); + }); + } + else { + fn(elem1, array2); + } + }); + } + else { + if (array2 instanceof Array) { + array2.forEach(function (elem2) { + fn(array1, elem2); + }); + } + else { + fn(array1, array2); + } + } + } -/** - * @class Groups - * This class can store groups and properties specific for groups. - */ -Groups = function () { - this.clear(); - this.defaultIndex = 0; -}; + /** + * Convert a string containing a graph in DOT language into a map containing + * with nodes and edges in the format of graph. + * @param {String} data Text containing a graph in DOT-notation + * @return {Object} graphData + */ + function DOTToGraph (data) { + // parse the DOT file + var dotData = parseDOT(data); + var graphData = { + nodes: [], + edges: [], + options: {} + }; + // copy the nodes + if (dotData.nodes) { + dotData.nodes.forEach(function (dotNode) { + var graphNode = { + id: dotNode.id, + label: String(dotNode.label || dotNode.id) + }; + merge(graphNode, dotNode.attr); + if (graphNode.image) { + graphNode.shape = 'image'; + } + graphData.nodes.push(graphNode); + }); + } -/** - * default constants for group colors - */ -Groups.DEFAULT = [ - {border: "#2B7CE9", background: "#97C2FC", highlight: {border: "#2B7CE9", background: "#D2E5FF"}}, // blue - {border: "#FFA500", background: "#FFFF00", highlight: {border: "#FFA500", background: "#FFFFA3"}}, // yellow - {border: "#FA0A10", background: "#FB7E81", highlight: {border: "#FA0A10", background: "#FFAFB1"}}, // red - {border: "#41A906", background: "#7BE141", highlight: {border: "#41A906", background: "#A1EC76"}}, // green - {border: "#E129F0", background: "#EB7DF4", highlight: {border: "#E129F0", background: "#F0B3F5"}}, // magenta - {border: "#7C29F0", background: "#AD85E4", highlight: {border: "#7C29F0", background: "#D3BDF0"}}, // purple - {border: "#C37F00", background: "#FFA807", highlight: {border: "#C37F00", background: "#FFCA66"}}, // orange - {border: "#4220FB", background: "#6E6EFD", highlight: {border: "#4220FB", background: "#9B9BFD"}}, // darkblue - {border: "#FD5A77", background: "#FFC0CB", highlight: {border: "#FD5A77", background: "#FFD1D9"}}, // pink - {border: "#4AD63A", background: "#C2FABC", highlight: {border: "#4AD63A", background: "#E6FFE3"}} // mint -]; + // copy the edges + if (dotData.edges) { + /** + * Convert an edge in DOT format to an edge with VisGraph format + * @param {Object} dotEdge + * @returns {Object} graphEdge + */ + function convertEdge(dotEdge) { + var graphEdge = { + from: dotEdge.from, + to: dotEdge.to + }; + merge(graphEdge, dotEdge.attr); + graphEdge.style = (dotEdge.type == '->') ? 'arrow' : 'line'; + return graphEdge; + } + dotData.edges.forEach(function (dotEdge) { + var from, to; + if (dotEdge.from instanceof Object) { + from = dotEdge.from.nodes; + } + else { + from = { + id: dotEdge.from + } + } -/** - * Clear all groups - */ -Groups.prototype.clear = function () { - this.groups = {}; - this.groups.length = function() - { - var i = 0; - for ( var p in this ) { - if (this.hasOwnProperty(p)) { - i++; - } - } - return i; - } -}; + if (dotEdge.to instanceof Object) { + to = dotEdge.to.nodes; + } + else { + to = { + id: dotEdge.to + } + } + if (dotEdge.from instanceof Object && dotEdge.from.edges) { + dotEdge.from.edges.forEach(function (subEdge) { + var graphEdge = convertEdge(subEdge); + graphData.edges.push(graphEdge); + }); + } -/** - * get group properties of a groupname. If groupname is not found, a new group - * is added. - * @param {*} groupname Can be a number, string, Date, etc. - * @return {Object} group The created group, containing all group properties - */ -Groups.prototype.get = function (groupname) { - var group = this.groups[groupname]; + forEach2(from, to, function (from, to) { + var subEdge = createEdge(graphData, from.id, to.id, dotEdge.type, dotEdge.attr); + var graphEdge = convertEdge(subEdge); + graphData.edges.push(graphEdge); + }); - if (group == undefined) { - // create new group - var index = this.defaultIndex % Groups.DEFAULT.length; - this.defaultIndex++; - group = {}; - group.color = Groups.DEFAULT[index]; - this.groups[groupname] = group; - } + if (dotEdge.to instanceof Object && dotEdge.to.edges) { + dotEdge.to.edges.forEach(function (subEdge) { + var graphEdge = convertEdge(subEdge); + graphData.edges.push(graphEdge); + }); + } + }); + } - return group; -}; + // copy the options + if (dotData.attr) { + graphData.options = dotData.attr; + } -/** - * Add a custom group style - * @param {String} groupname - * @param {Object} style An object containing borderColor, - * backgroundColor, etc. - * @return {Object} group The created group object - */ -Groups.prototype.add = function (groupname, style) { - this.groups[groupname] = style; - if (style.color) { - style.color = Node.parseColor(style.color); + return graphData; } - return style; -}; -/** - * @class Images - * This class loads images and keeps them stored. - */ -Images = function () { - this.images = {}; + // exports + exports.parseDOT = parseDOT; + exports.DOTToGraph = DOTToGraph; - this.callback = undefined; -}; +})(typeof util !== 'undefined' ? util : exports); /** - * Set an onload callback function. This will be called each time an image - * is loaded - * @param {function} callback + * Canvas shapes used by the Graph */ -Images.prototype.setOnloadCallback = function(callback) { - this.callback = callback; -}; +if (typeof CanvasRenderingContext2D !== 'undefined') { -/** - * - * @param {string} url Url of the image - * @return {Image} img The image object - */ -Images.prototype.load = function(url) { - var img = this.images[url]; - if (img == undefined) { - // create the image - var images = this; - img = new Image(); - this.images[url] = img; - img.onload = function() { - if (images.callback) { - images.callback(this); - } - }; - img.src = url; - } + /** + * Draw a circle shape + */ + CanvasRenderingContext2D.prototype.circle = function(x, y, r) { + this.beginPath(); + this.arc(x, y, r, 0, 2*Math.PI, false); + }; - return img; -}; + /** + * Draw a square shape + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r size, width and height of the square + */ + CanvasRenderingContext2D.prototype.square = function(x, y, r) { + this.beginPath(); + this.rect(x - r, y - r, r * 2, r * 2); + }; -/** - * @constructor Graph - * Create a graph visualization, displaying nodes and edges. - * - * @param {Element} container The DOM element in which the Graph will - * be created. Normally a div element. - * @param {Object} data An object containing parameters - * {Array} nodes - * {Array} edges - * @param {Object} options Options - */ -function Graph (container, data, options) { - // create variables and set default values - this.containerElement = container; - this.width = '100%'; - this.height = '100%'; - this.refreshRate = 50; // milliseconds - this.stabilize = true; // stabilize before displaying the graph - this.selectable = true; + /** + * Draw a triangle shape + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r radius, half the length of the sides of the triangle + */ + CanvasRenderingContext2D.prototype.triangle = function(x, y, r) { + // http://en.wikipedia.org/wiki/Equilateral_triangle + this.beginPath(); - // set constant values - this.constants = { - nodes: { - radiusMin: 5, - radiusMax: 20, - radius: 5, - distance: 100, // px - shape: 'ellipse', - image: undefined, - widthMin: 16, // px - widthMax: 64, // px - fontColor: 'black', - fontSize: 14, // px - //fontFace: verdana, - fontFace: 'arial', - color: { - border: '#2B7CE9', - background: '#97C2FC', - highlight: { - border: '#2B7CE9', - background: '#D2E5FF' - } - }, - borderColor: '#2B7CE9', - backgroundColor: '#97C2FC', - highlightColor: '#D2E5FF', - group: undefined - }, - edges: { - widthMin: 1, - widthMax: 15, - width: 1, - style: 'line', - color: '#343434', - fontColor: '#343434', - fontSize: 14, // px - fontFace: 'arial', - //distance: 100, //px - length: 100, // px - dash: { - length: 10, - gap: 5, - altLength: undefined - } - }, - minForce: 0.05, - minVelocity: 0.02, // px/s - maxIterations: 1000 // maximum number of iteration to stabilize + var s = r * 2; + var s2 = s / 2; + var ir = Math.sqrt(3) / 6 * s; // radius of inner circle + var h = Math.sqrt(s * s - s2 * s2); // height + + this.moveTo(x, y - (h - ir)); + this.lineTo(x + s2, y + ir); + this.lineTo(x - s2, y + ir); + this.lineTo(x, y - (h - ir)); + this.closePath(); }; - var graph = this; - this.nodes = {}; // object with Node objects - this.edges = {}; // object with Edge objects - // TODO: create a counter to keep track on the number of nodes having values - // TODO: create a counter to keep track on the number of nodes currently moving - // TODO: create a counter to keep track on the number of edges having values + /** + * Draw a triangle shape in downward orientation + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r radius + */ + CanvasRenderingContext2D.prototype.triangleDown = function(x, y, r) { + // http://en.wikipedia.org/wiki/Equilateral_triangle + this.beginPath(); + + var s = r * 2; + var s2 = s / 2; + var ir = Math.sqrt(3) / 6 * s; // radius of inner circle + var h = Math.sqrt(s * s - s2 * s2); // height + + this.moveTo(x, y + (h - ir)); + this.lineTo(x + s2, y - ir); + this.lineTo(x - s2, y - ir); + this.lineTo(x, y + (h - ir)); + this.closePath(); + }; - this.nodesData = null; // A DataSet or DataView - this.edgesData = null; // A DataSet or DataView + /** + * Draw a star shape, a star with 5 points + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r radius, half the length of the sides of the triangle + */ + CanvasRenderingContext2D.prototype.star = function(x, y, r) { + // http://www.html5canvastutorials.com/labs/html5-canvas-star-spinner/ + this.beginPath(); - // create event listeners used to subscribe on the DataSets of the nodes and edges - var me = this; - this.nodesListeners = { - 'add': function (event, params) { - me._addNodes(params.items); - me.start(); - }, - 'update': function (event, params) { - me._updateNodes(params.items); - me.start(); - }, - 'remove': function (event, params) { - me._removeNodes(params.items); - me.start(); + for (var n = 0; n < 10; n++) { + var radius = (n % 2 === 0) ? r * 1.3 : r * 0.5; + this.lineTo( + x + radius * Math.sin(n * 2 * Math.PI / 10), + y - radius * Math.cos(n * 2 * Math.PI / 10) + ); } + + this.closePath(); }; - this.edgesListeners = { - 'add': function (event, params) { - me._addEdges(params.items); - me.start(); - }, - 'update': function (event, params) { - me._updateEdges(params.items); - me.start(); - }, - 'remove': function (event, params) { - me._removeEdges(params.items); - me.start(); - } + + /** + * http://stackoverflow.com/questions/1255512/how-to-draw-a-rounded-rectangle-on-html-canvas + */ + CanvasRenderingContext2D.prototype.roundRect = function(x, y, w, h, r) { + var r2d = Math.PI/180; + if( w - ( 2 * r ) < 0 ) { r = ( w / 2 ); } //ensure that the radius isn't too large for x + if( h - ( 2 * r ) < 0 ) { r = ( h / 2 ); } //ensure that the radius isn't too large for y + this.beginPath(); + this.moveTo(x+r,y); + this.lineTo(x+w-r,y); + this.arc(x+w-r,y+r,r,r2d*270,r2d*360,false); + this.lineTo(x+w,y+h-r); + this.arc(x+w-r,y+h-r,r,0,r2d*90,false); + this.lineTo(x+r,y+h); + this.arc(x+r,y+h-r,r,r2d*90,r2d*180,false); + this.lineTo(x,y+r); + this.arc(x+r,y+r,r,r2d*180,r2d*270,false); }; - this.groups = new Groups(); // object with groups - this.images = new Images(); // object with images - this.images.setOnloadCallback(function () { - graph._redraw(); - }); + /** + * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + */ + CanvasRenderingContext2D.prototype.ellipse = function(x, y, w, h) { + var kappa = .5522848, + ox = (w / 2) * kappa, // control point offset horizontal + oy = (h / 2) * kappa, // control point offset vertical + xe = x + w, // x-end + ye = y + h, // y-end + xm = x + w / 2, // x-middle + ym = y + h / 2; // y-middle - // properties of the data - this.moving = false; // True if any of the nodes have an undefined position + this.beginPath(); + this.moveTo(x, ym); + this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); + this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); + this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); + this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); + }; - this.selection = []; - this.timer = undefined; - // create a frame and canvas - this._create(); - // apply options - this.setOptions(options); + /** + * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + */ + CanvasRenderingContext2D.prototype.database = function(x, y, w, h) { + var f = 1/3; + var wEllipse = w; + var hEllipse = h * f; - // draw data - this.setData(data); -} + var kappa = .5522848, + ox = (wEllipse / 2) * kappa, // control point offset horizontal + oy = (hEllipse / 2) * kappa, // control point offset vertical + xe = x + wEllipse, // x-end + ye = y + hEllipse, // y-end + xm = x + wEllipse / 2, // x-middle + ym = y + hEllipse / 2, // y-middle + ymb = y + (h - hEllipse/2), // y-midlle, bottom ellipse + yeb = y + h; // y-end, bottom ellipse -/** - * Set nodes and edges, and optionally options as well. - * - * @param {Object} data Object containing parameters: - * {Array | DataSet | DataView} [nodes] Array with nodes - * {Array | DataSet | DataView} [edges] Array with edges - * {String} [dot] String containing data in DOT format - * {Options} [options] Object with options - */ -Graph.prototype.setData = function(data) { - if (data && data.dot && (data.nodes || data.edges)) { - throw new SyntaxError('Data must contain either parameter "dot" or ' + - ' parameter pair "nodes" and "edges", but not both.'); - } + this.beginPath(); + this.moveTo(xe, ym); - // set options - this.setOptions(data && data.options); + this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); + this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - // set all data - if (data && data.dot) { - // parse DOT file - if(data && data.dot) { - var dotData = vis.util.DOTToGraph(data.dot); - this.setData(dotData); - return; - } - } - else { - this._setNodes(data && data.nodes); - this._setEdges(data && data.edges); - } + this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); + this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); + this.lineTo(xe, ymb); - // find a stable position or start animating to a stable position - if (this.stabilize) { - this._doStabilize(); - } - this.start(); -}; + this.bezierCurveTo(xe, ymb + oy, xm + ox, yeb, xm, yeb); + this.bezierCurveTo(xm - ox, yeb, x, ymb + oy, x, ymb); -/** - * Set options - * @param {Object} options - */ -Graph.prototype.setOptions = function (options) { - if (options) { - // retrieve parameter values - if (options.width != undefined) {this.width = options.width;} - if (options.height != undefined) {this.height = options.height;} - if (options.stabilize != undefined) {this.stabilize = options.stabilize;} - if (options.selectable != undefined) {this.selectable = options.selectable;} + this.lineTo(x, ym); + }; - // TODO: work out these options and document them - if (options.edges) { - for (var prop in options.edges) { - if (options.edges.hasOwnProperty(prop)) { - this.constants.edges[prop] = options.edges[prop]; - } - } - if (options.edges.length != undefined && - options.nodes && options.nodes.distance == undefined) { - this.constants.edges.length = options.edges.length; - this.constants.nodes.distance = options.edges.length * 1.25; - } + /** + * Draw an arrow point (no line) + */ + CanvasRenderingContext2D.prototype.arrow = function(x, y, angle, length) { + // tail + var xt = x - length * Math.cos(angle); + var yt = y - length * Math.sin(angle); + + // inner tail + // TODO: allow to customize different shapes + var xi = x - length * 0.9 * Math.cos(angle); + var yi = y - length * 0.9 * Math.sin(angle); + + // left + var xl = xt + length / 3 * Math.cos(angle + 0.5 * Math.PI); + var yl = yt + length / 3 * Math.sin(angle + 0.5 * Math.PI); + + // right + var xr = xt + length / 3 * Math.cos(angle - 0.5 * Math.PI); + var yr = yt + length / 3 * Math.sin(angle - 0.5 * Math.PI); + + this.beginPath(); + this.moveTo(x, y); + this.lineTo(xl, yl); + this.lineTo(xi, yi); + this.lineTo(xr, yr); + this.closePath(); + }; + + /** + * Sets up the dashedLine functionality for drawing + * Original code came from http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas + * @author David Jordan + * @date 2012-08-08 + */ + CanvasRenderingContext2D.prototype.dashedLine = function(x,y,x2,y2,dashArray){ + if (!dashArray) dashArray=[10,5]; + if (dashLength==0) dashLength = 0.001; // Hack for Safari + var dashCount = dashArray.length; + this.moveTo(x, y); + var dx = (x2-x), dy = (y2-y); + var slope = dy/dx; + var distRemaining = Math.sqrt( dx*dx + dy*dy ); + var dashIndex=0, draw=true; + while (distRemaining>=0.1){ + var dashLength = dashArray[dashIndex++%dashCount]; + if (dashLength > distRemaining) dashLength = distRemaining; + var xStep = Math.sqrt( dashLength*dashLength / (1 + slope*slope) ); + if (dx<0) xStep = -xStep; + x += xStep; + y += slope*xStep; + this[draw ? 'lineTo' : 'moveTo'](x,y); + distRemaining -= dashLength; + draw = !draw; + } + }; + + // TODO: add diamond shape +} + +/** + * @class Node + * A node. A node can be connected to other nodes via one or multiple edges. + * @param {object} properties An object containing properties for the node. All + * properties are optional, except for the id. + * {number} id Id of the node. Required + * {string} label Text label for the node + * {number} x Horizontal position of the node + * {number} y Vertical position of the node + * {string} shape Node shape, available: + * "database", "circle", "ellipse", + * "box", "image", "text", "dot", + * "star", "triangle", "triangleDown", + * "square" + * {string} image An image url + * {string} title An title text, can be HTML + * {anytype} group A group name or number + * @param {Graph.Images} imagelist A list with images. Only needed + * when the node has an image + * @param {Graph.Groups} grouplist A list with groups. Needed for + * retrieving group properties + * @param {Object} constants An object with default values for + * example for the color + */ +function Node(properties, imagelist, grouplist, constants) { + this.selected = false; - if (!options.edges.fontColor) { - this.constants.edges.fontColor = options.edges.color; - } + this.edges = []; // all edges connected to this node + this.group = constants.nodes.group; - // Added to support dashed lines - // David Jordan - // 2012-08-08 - if (options.edges.dash) { - if (options.edges.dash.length != undefined) { - this.constants.edges.dash.length = options.edges.dash.length; - } - if (options.edges.dash.gap != undefined) { - this.constants.edges.dash.gap = options.edges.dash.gap; - } - if (options.edges.dash.altLength != undefined) { - this.constants.edges.dash.altLength = options.edges.dash.altLength; - } - } - } + this.fontSize = constants.nodes.fontSize; + this.fontFace = constants.nodes.fontFace; + this.fontColor = constants.nodes.fontColor; - if (options.nodes) { - for (prop in options.nodes) { - if (options.nodes.hasOwnProperty(prop)) { - this.constants.nodes[prop] = options.nodes[prop]; - } - } + this.color = constants.nodes.color; - if (options.nodes.color) { - this.constants.nodes.color = Node.parseColor(options.nodes.color); - } + // set defaults for the properties + this.id = undefined; + this.shape = constants.nodes.shape; + this.image = constants.nodes.image; + this.x = 0; + this.y = 0; + this.xFixed = false; + this.yFixed = false; + this.radius = constants.nodes.radius; + this.radiusFixed = false; + this.radiusMin = constants.nodes.radiusMin; + this.radiusMax = constants.nodes.radiusMax; - /* - if (options.nodes.widthMin) this.constants.nodes.radiusMin = options.nodes.widthMin; - if (options.nodes.widthMax) this.constants.nodes.radiusMax = options.nodes.widthMax; - */ - } + this.imagelist = imagelist; + this.grouplist = grouplist; - if (options.groups) { - for (var groupname in options.groups) { - if (options.groups.hasOwnProperty(groupname)) { - var group = options.groups[groupname]; - this.groups.add(groupname, group); - } - } - } - } + this.setProperties(properties, constants); - this.setSize(this.width, this.height); - this._setTranslation(this.frame.clientWidth / 2, this.frame.clientHeight / 2); - this._setScale(1); + // mass, force, velocity + this.mass = 50; // kg (mass is adjusted for the number of connected edges) + this.fx = 0.0; // external force x + this.fy = 0.0; // external force y + this.vx = 0.0; // velocity x + this.vy = 0.0; // velocity y + this.minForce = constants.minForce; + this.damping = 0.9; // damping factor }; /** - * fire an event - * @param {String} event The name of an event, for example "select" - * @param {Object} params Optional object with event parameters - * @private + * Attach a edge to the node + * @param {Edge} edge */ -Graph.prototype._trigger = function (event, params) { - events.trigger(this, event, params); +Node.prototype.attachEdge = function(edge) { + if (this.edges.indexOf(edge) == -1) { + this.edges.push(edge); + } + this._updateMass(); }; - /** - * Create the main frame for the Graph. - * This function is executed once when a Graph object is created. The frame - * contains a canvas, and this canvas contains all objects like the axis and - * nodes. - * @private + * Detach a edge from the node + * @param {Edge} edge */ -Graph.prototype._create = function () { - // remove all elements from the container element. - while (this.containerElement.hasChildNodes()) { - this.containerElement.removeChild(this.containerElement.firstChild); - } - - this.frame = document.createElement("div"); - this.frame.className = "graph-frame"; - this.frame.style.position = "relative"; - this.frame.style.overflow = "hidden"; - - // create the graph canvas (HTML canvas element) - this.frame.canvas = document.createElement( "canvas" ); - this.frame.canvas.style.position = "relative"; - this.frame.appendChild(this.frame.canvas); - if (!this.frame.canvas.getContext) { - var noCanvas = document.createElement( "DIV" ); - noCanvas.style.color = "red"; - noCanvas.style.fontWeight = "bold" ; - noCanvas.style.padding = "10px"; - noCanvas.innerHTML = "Error: your browser does not support HTML canvas"; - this.frame.canvas.appendChild(noCanvas); +Node.prototype.detachEdge = function(edge) { + var index = this.edges.indexOf(edge); + if (index != -1) { + this.edges.splice(index, 1); } - - // create event listeners - var me = this; - var onmousedown = function (event) {me._onMouseDown(event);}; - var onmousemove = function (event) {me._onMouseMoveTitle(event);}; - var onmousewheel = function (event) {me._onMouseWheel(event);}; - var ontouchstart = function (event) {me._onTouchStart(event);}; - vis.util.addEventListener(this.frame.canvas, "mousedown", onmousedown); - vis.util.addEventListener(this.frame.canvas, "mousemove", onmousemove); - vis.util.addEventListener(this.frame.canvas, "mousewheel", onmousewheel); - vis.util.addEventListener(this.frame.canvas, "touchstart", ontouchstart); - - // add the frame to the container element - this.containerElement.appendChild(this.frame); + this._updateMass(); }; /** - * handle on mouse down event + * Update the nodes mass, which is determined by the number of edges connecting + * to it (more edges -> heavier node). * @private */ -Graph.prototype._onMouseDown = function (event) { - event = event || window.event; +Node.prototype._updateMass = function() { + this.mass = 50 + 20 * this.edges.length; // kg +}; - if (!this.selectable) { +/** + * Set or overwrite properties for the node + * @param {Object} properties an object with properties + * @param {Object} constants and object with default, global properties + */ +Node.prototype.setProperties = function(properties, constants) { + if (!properties) { return; } - // check if mouse is still down (may be up when focus is lost for example - // in an iframe) - if (this.leftButtonDown) { - this._onMouseUp(event); - } + // basic properties + if (properties.id != undefined) {this.id = properties.id;} + if (properties.label != undefined) {this.label = properties.label;} + if (properties.title != undefined) {this.title = properties.title;} + if (properties.group != undefined) {this.group = properties.group;} + if (properties.x != undefined) {this.x = properties.x;} + if (properties.y != undefined) {this.y = properties.y;} + if (properties.value != undefined) {this.value = properties.value;} - // only react on left mouse button down - this.leftButtonDown = event.which ? (event.which == 1) : (event.button == 1); - if (!this.leftButtonDown && !this.touchDown) { - return; + if (this.id === undefined) { + throw "Node must have an id"; } - // add event listeners to handle moving the contents - // we store the function onmousemove and onmouseup in the timeline, so we can - // remove the eventlisteners lateron in the function mouseUp() - var me = this; - if (!this.onmousemove) { - this.onmousemove = function (event) {me._onMouseMove(event);}; - vis.util.addEventListener(document, "mousemove", me.onmousemove); - } - if (!this.onmouseup) { - this.onmouseup = function (event) {me._onMouseUp(event);}; - vis.util.addEventListener(document, "mouseup", me.onmouseup); + // copy group properties + if (this.group) { + var groupObj = this.grouplist.get(this.group); + for (var prop in groupObj) { + if (groupObj.hasOwnProperty(prop)) { + this[prop] = groupObj[prop]; + } + } } - vis.util.preventDefault(event); - - // store the start x and y position of the mouse - this.startMouseX = util.getPageX(event); - this.startMouseY = util.getPageY(event); - this.startFrameLeft = vis.util.getAbsoluteLeft(this.frame.canvas); - this.startFrameTop = vis.util.getAbsoluteTop(this.frame.canvas); - this.startTranslation = this._getTranslation(); - this.ctrlKeyDown = event.ctrlKey; - this.shiftKeyDown = event.shiftKey; - - var obj = { - left: this._xToCanvas(this.startMouseX - this.startFrameLeft), - top: this._yToCanvas(this.startMouseY - this.startFrameTop), - right: this._xToCanvas(this.startMouseX - this.startFrameLeft), - bottom: this._yToCanvas(this.startMouseY - this.startFrameTop) - }; - var overlappingNodes = this._getNodesOverlappingWith(obj); - // if there are overlapping nodes, select the last one, this is the - // one which is drawn on top of the others - this.startClickedObj = (overlappingNodes.length > 0) ? - overlappingNodes[overlappingNodes.length - 1] : undefined; + // individual shape properties + if (properties.shape != undefined) {this.shape = properties.shape;} + if (properties.image != undefined) {this.image = properties.image;} + if (properties.radius != undefined) {this.radius = properties.radius;} + if (properties.color != undefined) {this.color = Node.parseColor(properties.color);} - if (this.startClickedObj) { - // move clicked node with the mouse + if (properties.fontColor != undefined) {this.fontColor = properties.fontColor;} + if (properties.fontSize != undefined) {this.fontSize = properties.fontSize;} + if (properties.fontFace != undefined) {this.fontFace = properties.fontFace;} - // make the clicked node temporarily fixed, and store their original state - var node = this.nodes[this.startClickedObj]; - this.startClickedObj.xFixed = node.xFixed; - this.startClickedObj.yFixed = node.yFixed; - node.xFixed = true; - node.yFixed = true; - if (!this.ctrlKeyDown || !node.isSelected()) { - // select this node - this._selectNodes([this.startClickedObj], this.ctrlKeyDown); + if (this.image != undefined) { + if (this.imagelist) { + this.imageObj = this.imagelist.load(this.image); } else { - // unselect this node - this._unselectNodes([this.startClickedObj]); + throw "No imagelist provided"; } + } - if (!this.moving) { - this._redraw(); - } + this.xFixed = this.xFixed || (properties.x != undefined); + this.yFixed = this.yFixed || (properties.y != undefined); + this.radiusFixed = this.radiusFixed || (properties.radius != undefined); + + if (this.shape == 'image') { + this.radiusMin = constants.nodes.widthMin; + this.radiusMax = constants.nodes.widthMax; + } + + // choose draw method depending on the shape + switch (this.shape) { + case 'database': this.draw = this._drawDatabase; this.resize = this._resizeDatabase; break; + case 'box': this.draw = this._drawBox; this.resize = this._resizeBox; break; + case 'circle': this.draw = this._drawCircle; this.resize = this._resizeCircle; break; + case 'ellipse': this.draw = this._drawEllipse; this.resize = this._resizeEllipse; break; + // TODO: add diamond shape + case 'image': this.draw = this._drawImage; this.resize = this._resizeImage; break; + case 'text': this.draw = this._drawText; this.resize = this._resizeText; break; + case 'dot': this.draw = this._drawDot; this.resize = this._resizeShape; break; + case 'square': this.draw = this._drawSquare; this.resize = this._resizeShape; break; + case 'triangle': this.draw = this._drawTriangle; this.resize = this._resizeShape; break; + case 'triangleDown': this.draw = this._drawTriangleDown; this.resize = this._resizeShape; break; + case 'star': this.draw = this._drawStar; this.resize = this._resizeShape; break; + default: this.draw = this._drawEllipse; this.resize = this._resizeEllipse; break; } - else if (this.shiftKeyDown) { - // start selection of multiple nodes + + // reset the size of the node, this can be changed + this._reset(); +}; + +/** + * Parse a color property into an object with border, background, and + * hightlight colors + * @param {Object | String} color + * @return {Object} colorObject + */ +Node.parseColor = function(color) { + var c; + if (util.isString(color)) { + c = { + border: color, + background: color, + highlight: { + border: color, + background: color + } + }; + // TODO: automatically generate a nice highlight color } else { - // start moving the graph - this.moved = false; + c = {}; + c.background = color.background || 'white'; + c.border = color.border || c.background; + if (util.isString(color.highlight)) { + c.highlight = { + border: color.highlight, + background: color.highlight + } + } + else { + c.highlight = {}; + c.highlight.background = color.highlight && color.highlight.background || c.background; + c.highlight.border = color.highlight && color.highlight.border || c.border; + } } + return c; }; /** - * handle on mouse move event - * @param {Event} event - * @private + * select this node */ -Graph.prototype._onMouseMove = function (event) { - event = event || window.event; - - if (!this.selectable) { - return; - } +Node.prototype.select = function() { + this.selected = true; + this._reset(); +}; - var mouseX = util.getPageX(event); - var mouseY = util.getPageY(event); - this.mouseX = mouseX; - this.mouseY = mouseY; +/** + * unselect this node + */ +Node.prototype.unselect = function() { + this.selected = false; + this._reset(); +}; - if (this.startClickedObj) { - var node = this.nodes[this.startClickedObj]; +/** + * Reset the calculated size of the node, forces it to recalculate its size + * @private + */ +Node.prototype._reset = function() { + this.width = undefined; + this.height = undefined; +}; - if (!this.startClickedObj.xFixed) - node.x = this._xToCanvas(mouseX - this.startFrameLeft); +/** + * get the title of this node. + * @return {string} title The title of the node, or undefined when no title + * has been set. + */ +Node.prototype.getTitle = function() { + return this.title; +}; - if (!this.startClickedObj.yFixed) - node.y = this._yToCanvas(mouseY - this.startFrameTop); +/** + * Calculate the distance to the border of the Node + * @param {CanvasRenderingContext2D} ctx + * @param {Number} angle Angle in radians + * @returns {number} distance Distance to the border in pixels + */ +Node.prototype.distanceToBorder = function (ctx, angle) { + var borderWidth = 1; - // start animation if not yet running - if (!this.moving) { - this.moving = true; - this.start(); - } + if (!this.width) { + this.resize(ctx); } - else if (this.shiftKeyDown) { - // draw a rect from start mouse location to current mouse location - if (this.frame.selRect == undefined) { - this.frame.selRect = document.createElement("DIV"); - this.frame.appendChild(this.frame.selRect); - this.frame.selRect.style.position = "absolute"; - this.frame.selRect.style.border = "1px dashed red"; - } + //noinspection FallthroughInSwitchStatementJS + switch (this.shape) { + case 'circle': + case 'dot': + return this.radius + borderWidth; - var left = Math.min(this.startMouseX, mouseX) - this.startFrameLeft; - var top = Math.min(this.startMouseY, mouseY) - this.startFrameTop; - var right = Math.max(this.startMouseX, mouseX) - this.startFrameLeft; - var bottom = Math.max(this.startMouseY, mouseY) - this.startFrameTop; + case 'ellipse': + var a = this.width / 2; + var b = this.height / 2; + var w = (Math.sin(angle) * a); + var h = (Math.cos(angle) * b); + return a * b / Math.sqrt(w * w + h * h); - this.frame.selRect.style.left = left + "px"; - this.frame.selRect.style.top = top + "px"; - this.frame.selRect.style.width = (right - left) + "px"; - this.frame.selRect.style.height = (bottom - top) + "px"; - } - else { - // move the graph - var diffX = mouseX - this.startMouseX; - var diffY = mouseY - this.startMouseY; + // TODO: implement distanceToBorder for database + // TODO: implement distanceToBorder for triangle + // TODO: implement distanceToBorder for triangleDown - this._setTranslation( - this.startTranslation.x + diffX, - this.startTranslation.y + diffY); - this._redraw(); + case 'box': + case 'image': + case 'text': + default: + if (this.width) { + return Math.min( + Math.abs(this.width / 2 / Math.cos(angle)), + Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth; + // TODO: reckon with border radius too in case of box + } + else { + return 0; + } - this.moved = true; } - vis.util.preventDefault(event); + // TODO: implement calculation of distance to border for all shapes +}; + +/** + * Set forces acting on the node + * @param {number} fx Force in horizontal direction + * @param {number} fy Force in vertical direction + */ +Node.prototype._setForce = function(fx, fy) { + this.fx = fx; + this.fy = fy; }; /** - * handle on mouse up event - * @param {Event} event + * Add forces acting on the node + * @param {number} fx Force in horizontal direction + * @param {number} fy Force in vertical direction * @private */ -Graph.prototype._onMouseUp = function (event) { - event = event || window.event; +Node.prototype._addForce = function(fx, fy) { + this.fx += fx; + this.fy += fy; +}; - if (!this.selectable) { - return; +/** + * Perform one discrete step for the node + * @param {number} interval Time interval in seconds + */ +Node.prototype.discreteStep = function(interval) { + if (!this.xFixed) { + var dx = -this.damping * this.vx; // damping force + var ax = (this.fx + dx) / this.mass; // acceleration + this.vx += ax / interval; // velocity + this.x += this.vx / interval; // position } - // remove event listeners here, important for Safari - if (this.onmousemove) { - vis.util.removeEventListener(document, "mousemove", this.onmousemove); - this.onmousemove = undefined; - } - if (this.onmouseup) { - vis.util.removeEventListener(document, "mouseup", this.onmouseup); - this.onmouseup = undefined; - } - vis.util.preventDefault(event); - - // check selected nodes - var endMouseX = util.getPageX(event) || this.mouseX || 0; - var endMouseY = util.getPageY(event) || this.mouseY || 0; - - var ctrlKey = event ? event.ctrlKey : window.event.ctrlKey; - - if (this.startClickedObj) { - // restore the original fixed state - var node = this.nodes[this.startClickedObj]; - node.xFixed = this.startClickedObj.xFixed; - node.yFixed = this.startClickedObj.yFixed; - } - else if (this.shiftKeyDown) { - // select nodes inside selection area - var obj = { - "left": this._xToCanvas(Math.min(this.startMouseX, endMouseX) - this.startFrameLeft), - "top": this._yToCanvas(Math.min(this.startMouseY, endMouseY) - this.startFrameTop), - "right": this._xToCanvas(Math.max(this.startMouseX, endMouseX) - this.startFrameLeft), - "bottom": this._yToCanvas(Math.max(this.startMouseY, endMouseY) - this.startFrameTop) - }; - var overlappingNodes = this._getNodesOverlappingWith(obj); - this._selectNodes(overlappingNodes, ctrlKey); - this.redraw(); - - // remove the selection rectangle - if (this.frame.selRect) { - this.frame.removeChild(this.frame.selRect); - this.frame.selRect = undefined; - } - } - else { - if (!this.ctrlKeyDown && !this.moved) { - // remove selection - this._unselectNodes(); - this._redraw(); - } + if (!this.yFixed) { + var dy = -this.damping * this.vy; // damping force + var ay = (this.fy + dy) / this.mass; // acceleration + this.vy += ay / interval; // velocity + this.y += this.vy / interval; // position } - - this.leftButtonDown = false; - this.ctrlKeyDown = false; }; /** - * Event handler for mouse wheel event, used to zoom the timeline - * Code from http://adomas.org/javascript-mouse-wheel/ - * @param {Event} event - * @private + * Check if this node has a fixed x and y position + * @return {boolean} true if fixed, false if not */ -Graph.prototype._onMouseWheel = function(event) { - event = event || window.event; - var mouseX = util.getPageX(event); - var mouseY = util.getPageY(event); +Node.prototype.isFixed = function() { + return (this.xFixed && this.yFixed); +}; - // retrieve delta - var delta = 0; - if (event.wheelDelta) { /* IE/Opera. */ - delta = event.wheelDelta/120; - } else if (event.detail) { /* Mozilla case. */ - // In Mozilla, sign of delta is different than in IE. - // Also, delta is multiple of 3. - delta = -event.detail/3; - } +/** + * Check if this node is moving + * @param {number} vmin the minimum velocity considered as "moving" + * @return {boolean} true if moving, false if it has no velocity + */ +// TODO: replace this method with calculating the kinetic energy +Node.prototype.isMoving = function(vmin) { + return (Math.abs(this.vx) > vmin || Math.abs(this.vy) > vmin || + (!this.xFixed && Math.abs(this.fx) > this.minForce) || + (!this.yFixed && Math.abs(this.fy) > this.minForce)); +}; - // If delta is nonzero, handle it. - // Basically, delta is now positive if wheel was scrolled up, - // and negative, if wheel was scrolled down. - if (delta) { - // determine zoom factor, and adjust the zoom factor such that zooming in - // and zooming out correspond wich each other - var zoom = delta / 10; - if (delta < 0) { - zoom = zoom / (1 - zoom); - } +/** + * check if this node is selecte + * @return {boolean} selected True if node is selected, else false + */ +Node.prototype.isSelected = function() { + return this.selected; +}; - var scaleOld = this._getScale(); - var scaleNew = scaleOld * (1 + zoom); - if (scaleNew < 0.01) { - scaleNew = 0.01; - } - if (scaleNew > 10) { - scaleNew = 10; - } +/** + * Retrieve the value of the node. Can be undefined + * @return {Number} value + */ +Node.prototype.getValue = function() { + return this.value; +}; - var frameLeft = vis.util.getAbsoluteLeft(this.frame.canvas); - var frameTop = vis.util.getAbsoluteTop(this.frame.canvas); - var x = mouseX - frameLeft; - var y = mouseY - frameTop; +/** + * Calculate the distance from the nodes location to the given location (x,y) + * @param {Number} x + * @param {Number} y + * @return {Number} value + */ +Node.prototype.getDistance = function(x, y) { + var dx = this.x - x, + dy = this.y - y; + return Math.sqrt(dx * dx + dy * dy); +}; - var translation = this._getTranslation(); - var scaleFrac = scaleNew / scaleOld; - var tx = (1 - scaleFrac) * x + translation.x * scaleFrac; - var ty = (1 - scaleFrac) * y + translation.y * scaleFrac; - this._setScale(scaleNew); - this._setTranslation(tx, ty); - this._redraw(); +/** + * Adjust the value range of the node. The node will adjust it's radius + * based on its value. + * @param {Number} min + * @param {Number} max + */ +Node.prototype.setValueRange = function(min, max) { + if (!this.radiusFixed && this.value !== undefined) { + var scale = (this.radiusMax - this.radiusMin) / (max - min); + this.radius = (this.value - min) * scale + this.radiusMin; } - - // Prevent default actions caused by mouse wheel. - // That might be ugly, but we handle scrolls somehow - // anyway, so don't bother here... - vis.util.preventDefault(event); }; - /** - * Mouse move handler for checking whether the title moves over a node with a title. - * @param {Event} event - * @private + * Draw this node in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx */ -Graph.prototype._onMouseMoveTitle = function (event) { - event = event || window.event; - - var startMouseX = util.getPageX(event); - var startMouseY = util.getPageY(event); - this.startFrameLeft = this.startFrameLeft || vis.util.getAbsoluteLeft(this.frame.canvas); - this.startFrameTop = this.startFrameTop || vis.util.getAbsoluteTop(this.frame.canvas); - - var x = startMouseX - this.startFrameLeft; - var y = startMouseY - this.startFrameTop; - - // check if the previously selected node is still selected - if (this.popupNode) { - this._checkHidePopup(x, y); - } +Node.prototype.draw = function(ctx) { + throw "Draw method not initialized for node"; +}; - // start a timeout that will check if the mouse is positioned above - // an element - var me = this; - var checkShow = function() { - me._checkShowPopup(x, y); - }; - if (this.popupTimer) { - clearInterval(this.popupTimer); // stop any running timer - } - if (!this.leftButtonDown) { - this.popupTimer = setTimeout(checkShow, 300); - } +/** + * Recalculate the size of this node in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + */ +Node.prototype.resize = function(ctx) { + throw "Resize method not initialized for node"; }; /** - * Check if there is an element on the given position in the graph - * (a node or edge). If so, and if this element has a title, - * show a popup window with its title. - * - * @param {number} x - * @param {number} y - * @private + * Check if this object is overlapping with the provided object + * @param {Object} obj an object with parameters left, top, right, bottom + * @return {boolean} True if location is located on node */ -Graph.prototype._checkShowPopup = function (x, y) { - var obj = { - "left" : this._xToCanvas(x), - "top" : this._yToCanvas(y), - "right" : this._xToCanvas(x), - "bottom" : this._yToCanvas(y) - }; - - var id; - var lastPopupNode = this.popupNode; +Node.prototype.isOverlappingWith = function(obj) { + return (this.left < obj.right && + this.left + this.width > obj.left && + this.top < obj.bottom && + this.top + this.height > obj.top); +}; - if (this.popupNode == undefined) { - // search the nodes for overlap, select the top one in case of multiple nodes - var nodes = this.nodes; - for (id in nodes) { - if (nodes.hasOwnProperty(id)) { - var node = nodes[id]; - if (node.getTitle() != undefined && node.isOverlappingWith(obj)) { - this.popupNode = node; - break; - } - } +Node.prototype._resizeImage = function (ctx) { + // TODO: pre calculate the image size + if (!this.width) { // undefined or 0 + var width, height; + if (this.value) { + var scale = this.imageObj.height / this.imageObj.width; + width = this.radius || this.imageObj.width; + height = this.radius * scale || this.imageObj.height; } - } - - if (this.popupNode == undefined) { - // search the edges for overlap - var edges = this.edges; - for (id in edges) { - if (edges.hasOwnProperty(id)) { - var edge = edges[id]; - if (edge.connected && (edge.getTitle() != undefined) && - edge.isOverlappingWith(obj)) { - this.popupNode = edge; - break; - } - } + else { + width = this.imageObj.width; + height = this.imageObj.height; } + this.width = width; + this.height = height; } +}; - if (this.popupNode) { - // show popup message window - if (this.popupNode != lastPopupNode) { - var me = this; - if (!me.popup) { - me.popup = new Popup(me.frame); - } +Node.prototype._drawImage = function (ctx) { + this._resizeImage(ctx); - // adjust a small offset such that the mouse cursor is located in the - // bottom left location of the popup, and you can easily move over the - // popup area - me.popup.setPosition(x - 3, y - 3); - me.popup.setText(me.popupNode.getTitle()); - me.popup.show(); - } + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; + + var yLabel; + if (this.imageObj) { + ctx.drawImage(this.imageObj, this.left, this.top, this.width, this.height); + yLabel = this.y + this.height / 2; } else { - if (this.popup) { - this.popup.hide(); - } + // image still loading... just draw the label for now + yLabel = this.y; } + + this._label(ctx, this.label, this.x, yLabel, undefined, "top"); }; -/** - * Check if the popup must be hided, which is the case when the mouse is no - * longer hovering on the object - * @param {number} x - * @param {number} y - * @private - */ -Graph.prototype._checkHidePopup = function (x, y) { - var obj = { - "left" : x, - "top" : y, - "right" : x, - "bottom" : y - }; - if (!this.popupNode || !this.popupNode.isOverlappingWith(obj) ) { - this.popupNode = undefined; - if (this.popup) { - this.popup.hide(); - } +Node.prototype._resizeBox = function (ctx) { + if (!this.width) { + var margin = 5; + var textSize = this.getTextSize(ctx); + this.width = textSize.width + 2 * margin; + this.height = textSize.height + 2 * margin; } }; -/** - * Event handler for touchstart event on mobile devices - * @param {Event} event - * @private - */ -Graph.prototype._onTouchStart = function(event) { - vis.util.preventDefault(event); +Node.prototype._drawBox = function (ctx) { + this._resizeBox(ctx); - if (this.touchDown) { - // if already moving, return - return; - } - this.touchDown = true; + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; - var me = this; - if (!this.ontouchmove) { - this.ontouchmove = function (event) {me._onTouchMove(event);}; - vis.util.addEventListener(document, "touchmove", this.ontouchmove); - } - if (!this.ontouchend) { - this.ontouchend = function (event) {me._onTouchEnd(event);}; - vis.util.addEventListener(document, "touchend", this.ontouchend); - } + ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; + ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; + ctx.lineWidth = this.selected ? 2.0 : 1.0; + ctx.roundRect(this.left, this.top, this.width, this.height, this.radius); + ctx.fill(); + ctx.stroke(); - this._onMouseDown(event); + this._label(ctx, this.label, this.x, this.y); }; -/** - * Event handler for touchmove event on mobile devices - * @param {Event} event - * @private - */ -Graph.prototype._onTouchMove = function(event) { - vis.util.preventDefault(event); - this._onMouseMove(event); + +Node.prototype._resizeDatabase = function (ctx) { + if (!this.width) { + var margin = 5; + var textSize = this.getTextSize(ctx); + var size = textSize.width + 2 * margin; + this.width = size; + this.height = size; + } }; -/** - * Event handler for touchend event on mobile devices - * @param {Event} event - * @private - */ -Graph.prototype._onTouchEnd = function(event) { - vis.util.preventDefault(event); +Node.prototype._drawDatabase = function (ctx) { + this._resizeDatabase(ctx); + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; + + ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; + ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; + ctx.lineWidth = this.selected ? 2.0 : 1.0; + ctx.database(this.x - this.width/2, this.y - this.height*0.5, this.width, this.height); + ctx.fill(); + ctx.stroke(); + + this._label(ctx, this.label, this.x, this.y); +}; - this.touchDown = false; - if (this.ontouchmove) { - vis.util.removeEventListener(document, "touchmove", this.ontouchmove); - this.ontouchmove = undefined; - } - if (this.ontouchend) { - vis.util.removeEventListener(document, "touchend", this.ontouchend); - this.ontouchend = undefined; - } +Node.prototype._resizeCircle = function (ctx) { + if (!this.width) { + var margin = 5; + var textSize = this.getTextSize(ctx); + var diameter = Math.max(textSize.width, textSize.height) + 2 * margin; + this.radius = diameter / 2; - this._onMouseUp(event); + this.width = diameter; + this.height = diameter; + } }; +Node.prototype._drawCircle = function (ctx) { + this._resizeCircle(ctx); + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; -/** - * Unselect selected nodes. If no selection array is provided, all nodes - * are unselected - * @param {Object[]} selection Array with selection objects, each selection - * object has a parameter row. Optional - * @param {Boolean} triggerSelect If true (default), the select event - * is triggered when nodes are unselected - * @return {Boolean} changed True if the selection is changed - * @private - */ -Graph.prototype._unselectNodes = function(selection, triggerSelect) { - var changed = false; - var i, iMax, id; + ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; + ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; + ctx.lineWidth = this.selected ? 2.0 : 1.0; + ctx.circle(this.x, this.y, this.radius); + ctx.fill(); + ctx.stroke(); - if (selection) { - // remove provided selections - for (i = 0, iMax = selection.length; i < iMax; i++) { - id = selection[i]; - this.nodes[id].unselect(); + this._label(ctx, this.label, this.x, this.y); +}; - var j = 0; - while (j < this.selection.length) { - if (this.selection[j] == id) { - this.selection.splice(j, 1); - changed = true; - } - else { - j++; - } - } - } - } - else if (this.selection && this.selection.length) { - // remove all selections - for (i = 0, iMax = this.selection.length; i < iMax; i++) { - id = this.selection[i]; - this.nodes[id].unselect(); - changed = true; +Node.prototype._resizeEllipse = function (ctx) { + if (!this.width) { + var textSize = this.getTextSize(ctx); + + this.width = textSize.width * 1.5; + this.height = textSize.height * 2; + if (this.width < this.height) { + this.width = this.height; } - this.selection = []; } +}; - if (changed && (triggerSelect == true || triggerSelect == undefined)) { - // fire the select event - this._trigger('select'); - } +Node.prototype._drawEllipse = function (ctx) { + this._resizeEllipse(ctx); + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; - return changed; + ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; + ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; + ctx.lineWidth = this.selected ? 2.0 : 1.0; + ctx.ellipse(this.left, this.top, this.width, this.height); + ctx.fill(); + ctx.stroke(); + + this._label(ctx, this.label, this.x, this.y); }; -/** - * select all nodes on given location x, y - * @param {Array} selection an array with node ids - * @param {boolean} append If true, the new selection will be appended to the - * current selection (except for duplicate entries) - * @return {Boolean} changed True if the selection is changed - * @private - */ -Graph.prototype._selectNodes = function(selection, append) { - var changed = false; - var i, iMax; +Node.prototype._drawDot = function (ctx) { + this._drawShape(ctx, 'circle'); +}; + +Node.prototype._drawTriangle = function (ctx) { + this._drawShape(ctx, 'triangle'); +}; + +Node.prototype._drawTriangleDown = function (ctx) { + this._drawShape(ctx, 'triangleDown'); +}; - // TODO: the selectNodes method is a little messy, rework this +Node.prototype._drawSquare = function (ctx) { + this._drawShape(ctx, 'square'); +}; - // check if the current selection equals the desired selection - var selectionAlreadyThere = true; - if (selection.length != this.selection.length) { - selectionAlreadyThere = false; - } - else { - for (i = 0, iMax = Math.min(selection.length, this.selection.length); i < iMax; i++) { - if (selection[i] != this.selection[i]) { - selectionAlreadyThere = false; - break; - } - } - } - if (selectionAlreadyThere) { - return changed; - } +Node.prototype._drawStar = function (ctx) { + this._drawShape(ctx, 'star'); +}; - if (append == undefined || append == false) { - // first deselect any selected node - var triggerSelect = false; - changed = this._unselectNodes(undefined, triggerSelect); +Node.prototype._resizeShape = function (ctx) { + if (!this.width) { + var size = 2 * this.radius; + this.width = size; + this.height = size; } +}; - for (i = 0, iMax = selection.length; i < iMax; i++) { - // add each of the new selections, but only when they are not duplicate - var id = selection[i]; - var isDuplicate = (this.selection.indexOf(id) != -1); - if (!isDuplicate) { - this.nodes[id].select(); - this.selection.push(id); - changed = true; - } - } +Node.prototype._drawShape = function (ctx, shape) { + this._resizeShape(ctx); - if (changed) { - // fire the select event - this._trigger('select'); - } + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; - return changed; -}; + ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; + ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; + ctx.lineWidth = this.selected ? 2.0 : 1.0; -/** - * retrieve all nodes overlapping with given object - * @param {Object} obj An object with parameters left, top, right, bottom - * @return {Object[]} An array with selection objects containing - * the parameter row. - * @private - */ -Graph.prototype._getNodesOverlappingWith = function (obj) { - var nodes = this.nodes, - overlappingNodes = []; + ctx[shape](this.x, this.y, this.radius); + ctx.fill(); + ctx.stroke(); - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - if (nodes[id].isOverlappingWith(obj)) { - overlappingNodes.push(id); - } - } + if (this.label) { + this._label(ctx, this.label, this.x, this.y + this.height / 2, undefined, 'top'); } - - return overlappingNodes; }; -/** - * retrieve the currently selected nodes - * @return {Number[] | String[]} selection An array with the ids of the - * selected nodes. - */ -Graph.prototype.getSelection = function() { - return this.selection.concat([]); +Node.prototype._resizeText = function (ctx) { + if (!this.width) { + var margin = 5; + var textSize = this.getTextSize(ctx); + this.width = textSize.width + 2 * margin; + this.height = textSize.height + 2 * margin; + } }; -/** - * select zero or more nodes - * @param {Number[] | String[]} selection An array with the ids of the - * selected nodes. - */ -Graph.prototype.setSelection = function(selection) { - var i, iMax, id; +Node.prototype._drawText = function (ctx) { + this._resizeText(ctx); + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; - if (selection.length == undefined) - throw "Selection must be an array with ids"; + this._label(ctx, this.label, this.x, this.y); +}; - // first unselect any selected node - for (i = 0, iMax = this.selection.length; i < iMax; i++) { - id = this.selection[i]; - this.nodes[id].unselect(); - } - this.selection = []; +Node.prototype._label = function (ctx, text, x, y, align, baseline) { + if (text) { + ctx.font = (this.selected ? "bold " : "") + this.fontSize + "px " + this.fontFace; + ctx.fillStyle = this.fontColor || "black"; + ctx.textAlign = align || "center"; + ctx.textBaseline = baseline || "middle"; - for (i = 0, iMax = selection.length; i < iMax; i++) { - id = selection[i]; + var lines = text.split('\n'), + lineCount = lines.length, + fontSize = (this.fontSize + 4), + yLine = y + (1 - lineCount) / 2 * fontSize; - var node = this.nodes[id]; - if (!node) { - throw new RangeError('Node with id "' + id + '" not found'); + for (var i = 0; i < lineCount; i++) { + ctx.fillText(lines[i], x, yLine); + yLine += fontSize; } - node.select(); - this.selection.push(id); } - - this.redraw(); }; -/** - * Validate the selection: remove ids of nodes which no longer exist - * @private - */ -Graph.prototype._updateSelection = function () { - var i = 0; - while (i < this.selection.length) { - var id = this.selection[i]; - if (!this.nodes[id]) { - this.selection.splice(i, 1); - } - else { - i++; + +Node.prototype.getTextSize = function(ctx) { + if (this.label != undefined) { + ctx.font = (this.selected ? "bold " : "") + this.fontSize + "px " + this.fontFace; + + var lines = this.label.split('\n'), + height = (this.fontSize + 4) * lines.length, + width = 0; + + for (var i = 0, iMax = lines.length; i < iMax; i++) { + width = Math.max(width, ctx.measureText(lines[i]).width); } + + return {"width": width, "height": height}; + } + else { + return {"width": 0, "height": 0}; } }; /** - * Temporary method to test calculating a hub value for the nodes - * @param {number} level Maximum number edges between two nodes in order - * to call them connected. Optional, 1 by default - * @return {Number[]} connectioncount array with the connection count - * for each node - * @private + * @class Edge + * + * A edge connects two nodes + * @param {Object} properties Object with properties. Must contain + * At least properties from and to. + * Available properties: from (number), + * to (number), label (string, color (string), + * width (number), style (string), + * length (number), title (string) + * @param {Graph} graph A graph object, used to find and edge to + * nodes. + * @param {Object} constants An object with default values for + * example for the color */ -Graph.prototype._getConnectionCount = function(level) { - if (level == undefined) { - level = 1; +function Edge (properties, graph, constants) { + if (!graph) { + throw "No graph provided"; } + this.graph = graph; - // get the nodes connected to given nodes - function getConnectedNodes(nodes) { - var connectedNodes = []; + // initialize constants + this.widthMin = constants.edges.widthMin; + this.widthMax = constants.edges.widthMax; - for (var j = 0, jMax = nodes.length; j < jMax; j++) { - var node = nodes[j]; + // initialize variables + this.id = undefined; + this.fromId = undefined; + this.toId = undefined; + this.style = constants.edges.style; + this.title = undefined; + this.width = constants.edges.width; + this.value = undefined; + this.length = constants.edges.length; - // find all nodes connected to this node - var edges = node.edges; - for (var i = 0, iMax = edges.length; i < iMax; i++) { - var edge = edges[i]; - var other = null; + this.from = null; // a node + this.to = null; // a node + this.connected = false; - // check if connected - if (edge.from == node) - other = edge.to; - else if (edge.to == node) - other = edge.from; + // Added to support dashed lines + // David Jordan + // 2012-08-08 + this.dash = util.extend({}, constants.edges.dash); // contains properties length, gap, altLength - // check if the other node is not already in the list with nodes - var k, kMax; - if (other) { - for (k = 0, kMax = nodes.length; k < kMax; k++) { - if (nodes[k] == other) { - other = null; - break; - } - } - } - if (other) { - for (k = 0, kMax = connectedNodes.length; k < kMax; k++) { - if (connectedNodes[k] == other) { - other = null; - break; - } - } - } + this.stiffness = undefined; // depends on the length of the edge + this.color = constants.edges.color; + this.widthFixed = false; + this.lengthFixed = false; - if (other) - connectedNodes.push(other); - } - } + this.setProperties(properties, constants); +} - return connectedNodes; +/** + * Set or overwrite properties for the edge + * @param {Object} properties an object with properties + * @param {Object} constants and object with default, global properties + */ +Edge.prototype.setProperties = function(properties, constants) { + if (!properties) { + return; } - var connections = []; - var nodes = this.nodes; - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - var c = [nodes[id]]; - for (var l = 0; l < level; l++) { - c = c.concat(getConnectedNodes(c)); - } - connections.push(c); - } + if (properties.from != undefined) {this.fromId = properties.from;} + if (properties.to != undefined) {this.toId = properties.to;} + + if (properties.id != undefined) {this.id = properties.id;} + if (properties.style != undefined) {this.style = properties.style;} + if (properties.label != undefined) {this.label = properties.label;} + if (this.label) { + this.fontSize = constants.edges.fontSize; + this.fontFace = constants.edges.fontFace; + this.fontColor = constants.edges.fontColor; + if (properties.fontColor != undefined) {this.fontColor = properties.fontColor;} + if (properties.fontSize != undefined) {this.fontSize = properties.fontSize;} + if (properties.fontFace != undefined) {this.fontFace = properties.fontFace;} } + if (properties.title != undefined) {this.title = properties.title;} + if (properties.width != undefined) {this.width = properties.width;} + if (properties.value != undefined) {this.value = properties.value;} + if (properties.length != undefined) {this.length = properties.length;} - var hubs = []; - for (var i = 0, len = connections.length; i < len; i++) { - hubs.push(connections[i].length); + // Added to support dashed lines + // David Jordan + // 2012-08-08 + if (properties.dash) { + if (properties.dash.length != undefined) {this.dash.length = properties.dash.length;} + if (properties.dash.gap != undefined) {this.dash.gap = properties.dash.gap;} + if (properties.dash.altLength != undefined) {this.dash.altLength = properties.dash.altLength;} } + + if (properties.color != undefined) {this.color = properties.color;} - return hubs; -}; + // A node is connected when it has a from and to node. + this.connect(); + + this.widthFixed = this.widthFixed || (properties.width != undefined); + this.lengthFixed = this.lengthFixed || (properties.length != undefined); + this.stiffness = 1 / this.length; + // set draw method based on style + switch (this.style) { + case 'line': this.draw = this._drawLine; break; + case 'arrow': this.draw = this._drawArrow; break; + case 'arrow-center': this.draw = this._drawArrowCenter; break; + case 'dash-line': this.draw = this._drawDashLine; break; + default: this.draw = this._drawLine; break; + } +}; /** - * Set a new size for the graph - * @param {string} width Width in pixels or percentage (for example "800px" - * or "50%") - * @param {string} height Height in pixels or percentage (for example "400px" - * or "30%") + * Connect an edge to its nodes */ -Graph.prototype.setSize = function(width, height) { - this.frame.style.width = width; - this.frame.style.height = height; +Edge.prototype.connect = function () { + this.disconnect(); - this.frame.canvas.style.width = "100%"; - this.frame.canvas.style.height = "100%"; + this.from = this.graph.nodes[this.fromId] || null; + this.to = this.graph.nodes[this.toId] || null; + this.connected = (this.from && this.to); - this.frame.canvas.width = this.frame.canvas.clientWidth; - this.frame.canvas.height = this.frame.canvas.clientHeight; + if (this.connected) { + this.from.attachEdge(this); + this.to.attachEdge(this); + } + else { + if (this.from) { + this.from.detachEdge(this); + } + if (this.to) { + this.to.detachEdge(this); + } + } }; /** - * Set a data set with nodes for the graph - * @param {Array | DataSet | DataView} nodes The data containing the nodes. - * @private + * Disconnect an edge from its nodes */ -Graph.prototype._setNodes = function(nodes) { - var oldNodesData = this.nodesData; - - if (nodes instanceof DataSet || nodes instanceof DataView) { - this.nodesData = nodes; - } - else if (nodes instanceof Array) { - this.nodesData = new DataSet(); - this.nodesData.add(nodes); - } - else if (!nodes) { - this.nodesData = new DataSet(); +Edge.prototype.disconnect = function () { + if (this.from) { + this.from.detachEdge(this); + this.from = null; } - else { - throw new TypeError('Array or DataSet expected'); + if (this.to) { + this.to.detachEdge(this); + this.to = null; } - if (oldNodesData) { - // unsubscribe from old dataset - util.forEach(this.nodesListeners, function (callback, event) { - oldNodesData.unsubscribe(event, callback); - }); - } + this.connected = false; +}; - // remove drawn nodes - this.nodes = {}; +/** + * get the title of this edge. + * @return {string} title The title of the edge, or undefined when no title + * has been set. + */ +Edge.prototype.getTitle = function() { + return this.title; +}; - if (this.nodesData) { - // subscribe to new dataset - var me = this; - util.forEach(this.nodesListeners, function (callback, event) { - me.nodesData.subscribe(event, callback); - }); - // draw all new nodes - var ids = this.nodesData.getIds(); - this._addNodes(ids); +/** + * Retrieve the value of the edge. Can be undefined + * @return {Number} value + */ +Edge.prototype.getValue = function() { + return this.value; +}; + +/** + * Adjust the value range of the edge. The edge will adjust it's width + * based on its value. + * @param {Number} min + * @param {Number} max + */ +Edge.prototype.setValueRange = function(min, max) { + if (!this.widthFixed && this.value !== undefined) { + var factor = (this.widthMax - this.widthMin) / (max - min); + this.width = (this.value - min) * factor + this.widthMin; } +}; - this._updateSelection(); +/** + * Redraw a edge + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + */ +Edge.prototype.draw = function(ctx) { + throw "Method draw not initialized in edge"; }; /** - * Add nodes - * @param {Number[] | String[]} ids - * @private + * Check if this object is overlapping with the provided object + * @param {Object} obj an object with parameters left, top + * @return {boolean} True if location is located on the edge */ -Graph.prototype._addNodes = function(ids) { - var id; - for (var i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - var data = this.nodesData.get(id); - var node = new Node(data, this.images, this.groups, this.constants); - this.nodes[id] = node; // note: this may replace an existing node +Edge.prototype.isOverlappingWith = function(obj) { + var distMax = 10; - if (!node.isFixed()) { - // TODO: position new nodes in a smarter way! - var radius = this.constants.edges.length * 2; - var count = ids.length; - var angle = 2 * Math.PI * (i / count); - node.x = radius * Math.cos(angle); - node.y = radius * Math.sin(angle); + var xFrom = this.from.x; + var yFrom = this.from.y; + var xTo = this.to.x; + var yTo = this.to.y; + var xObj = obj.left; + var yObj = obj.top; - // note: no not use node.isMoving() here, as that gives the current - // velocity of the node, which is zero after creation of the node. - this.moving = true; - } - } - this._reconnectEdges(); - this._updateValueRange(this.nodes); + var dist = Edge._dist(xFrom, yFrom, xTo, yTo, xObj, yObj); + + return (dist < distMax); }; + /** - * Update existing nodes, or create them when not yet existing - * @param {Number[] | String[]} ids + * Redraw a edge as a line + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx * @private */ -Graph.prototype._updateNodes = function(ids) { - var nodes = this.nodes, - nodesData = this.nodesData; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - var node = nodes[id]; - var data = nodesData.get(id); - if (node) { - // update node - node.setProperties(data, this.constants); +Edge.prototype._drawLine = function(ctx) { + // set style + ctx.strokeStyle = this.color; + ctx.lineWidth = this._getLineWidth(); + + var point; + if (this.from != this.to) { + // draw line + this._line(ctx); + + // draw label + if (this.label) { + point = this._pointOnLine(0.5); + this._label(ctx, this.label, point.x, point.y); + } + } + else { + var x, y; + var radius = this.length / 4; + var node = this.from; + if (!node.width) { + node.resize(ctx); + } + if (node.width > node.height) { + x = node.x + node.width / 2; + y = node.y - radius; } else { - // create node - node = new Node(properties, this.images, this.groups, this.constants); - nodes[id] = node; - - if (!node.isFixed()) { - this.moving = true; - } + x = node.x + radius; + y = node.y - node.height / 2; } + this._circle(ctx, x, y, radius); + point = this._pointOnCircle(x, y, radius, 0.5); + this._label(ctx, this.label, point.x, point.y); } - - this._reconnectEdges(); - this._updateValueRange(nodes); }; /** - * Remove existing nodes. If nodes do not exist, the method will just ignore it. - * @param {Number[] | String[]} ids + * Get the line width of the edge. Depends on width and whether one of the + * connected nodes is selected. + * @return {Number} width * @private */ -Graph.prototype._removeNodes = function(ids) { - var nodes = this.nodes; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - delete nodes[id]; +Edge.prototype._getLineWidth = function() { + if (this.from.selected || this.to.selected) { + return Math.min(this.width * 2, this.widthMax); + } + else { + return this.width; } - - this._reconnectEdges(); - this._updateSelection(); - this._updateValueRange(nodes); }; /** - * Load edges by reading the data table - * @param {Array | DataSet | DataView} edges The data containing the edges. - * @private + * Draw a line between two nodes + * @param {CanvasRenderingContext2D} ctx * @private */ -Graph.prototype._setEdges = function(edges) { - var oldEdgesData = this.edgesData; - - if (edges instanceof DataSet || edges instanceof DataView) { - this.edgesData = edges; - } - else if (edges instanceof Array) { - this.edgesData = new DataSet(); - this.edgesData.add(edges); - } - else if (!edges) { - this.edgesData = new DataSet(); - } - else { - throw new TypeError('Array or DataSet expected'); - } - - if (oldEdgesData) { - // unsubscribe from old dataset - util.forEach(this.edgesListeners, function (callback, event) { - oldEdgesData.unsubscribe(event, callback); - }); - } - - // remove drawn edges - this.edges = {}; - - if (this.edgesData) { - // subscribe to new dataset - var me = this; - util.forEach(this.edgesListeners, function (callback, event) { - me.edgesData.subscribe(event, callback); - }); - - // draw all new nodes - var ids = this.edgesData.getIds(); - this._addEdges(ids); - } +Edge.prototype._line = function (ctx) { + // draw a straight line + ctx.beginPath(); + ctx.moveTo(this.from.x, this.from.y); + ctx.lineTo(this.to.x, this.to.y); + ctx.stroke(); +}; - this._reconnectEdges(); +/** + * Draw a line from a node to itself, a circle + * @param {CanvasRenderingContext2D} ctx + * @param {Number} x + * @param {Number} y + * @param {Number} radius + * @private + */ +Edge.prototype._circle = function (ctx, x, y, radius) { + // draw a circle + ctx.beginPath(); + ctx.arc(x, y, radius, 0, 2 * Math.PI, false); + ctx.stroke(); }; /** - * Add edges - * @param {Number[] | String[]} ids + * Draw label with white background and with the middle at (x, y) + * @param {CanvasRenderingContext2D} ctx + * @param {String} text + * @param {Number} x + * @param {Number} y * @private */ -Graph.prototype._addEdges = function (ids) { - var edges = this.edges, - edgesData = this.edgesData; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; +Edge.prototype._label = function (ctx, text, x, y) { + if (text) { + // TODO: cache the calculated size + ctx.font = ((this.from.selected || this.to.selected) ? "bold " : "") + + this.fontSize + "px " + this.fontFace; + ctx.fillStyle = 'white'; + var width = ctx.measureText(text).width; + var height = this.fontSize; + var left = x - width / 2; + var top = y - height / 2; - var oldEdge = edges[id]; - if (oldEdge) { - oldEdge.disconnect(); - } + ctx.fillRect(left, top, width, height); - var data = edgesData.get(id); - edges[id] = new Edge(data, this, this.constants); + // draw text + ctx.fillStyle = this.fontColor || "black"; + ctx.textAlign = "left"; + ctx.textBaseline = "top"; + ctx.fillText(text, left, top); } - - this.moving = true; - this._updateValueRange(edges); }; /** - * Update existing edges, or create them when not yet existing - * @param {Number[] | String[]} ids + * Redraw a edge as a dashed line + * Draw this edge in the given canvas + * @author David Jordan + * @date 2012-08-08 + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx * @private */ -Graph.prototype._updateEdges = function (ids) { - var edges = this.edges, - edgesData = this.edgesData; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; +Edge.prototype._drawDashLine = function(ctx) { + // set style + ctx.strokeStyle = this.color; + ctx.lineWidth = this._getLineWidth(); - var data = edgesData.get(id); - var edge = edges[id]; - if (edge) { - // update edge - edge.disconnect(); - edge.setProperties(data, this.constants); - edge.connect(); - } - else { - // create edge - edge = new Edge(data, this, this.constants); - this.edges[id] = edge; - } + // draw dashed line + ctx.beginPath(); + ctx.lineCap = 'round'; + if (this.dash.altLength != undefined) //If an alt dash value has been set add to the array this value + { + ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, + [this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]); + } + else if (this.dash.length != undefined && this.dash.gap != undefined) //If a dash and gap value has been set add to the array this value + { + ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, + [this.dash.length,this.dash.gap]); + } + else //If all else fails draw a line + { + ctx.moveTo(this.from.x, this.from.y); + ctx.lineTo(this.to.x, this.to.y); } + ctx.stroke(); - this.moving = true; - this._updateValueRange(edges); + // draw label + if (this.label) { + var point = this._pointOnLine(0.5); + this._label(ctx, this.label, point.x, point.y); + } }; /** - * Remove existing edges. Non existing ids will be ignored - * @param {Number[] | String[]} ids + * Get a point on a line + * @param {Number} percentage. Value between 0 (line start) and 1 (line end) + * @return {Object} point * @private */ -Graph.prototype._removeEdges = function (ids) { - var edges = this.edges; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - var edge = edges[id]; - if (edge) { - edge.disconnect(); - delete edges[id]; - } +Edge.prototype._pointOnLine = function (percentage) { + return { + x: (1 - percentage) * this.from.x + percentage * this.to.x, + y: (1 - percentage) * this.from.y + percentage * this.to.y } - - this.moving = true; - this._updateValueRange(edges); }; /** - * Reconnect all edges + * Get a point on a circle + * @param {Number} x + * @param {Number} y + * @param {Number} radius + * @param {Number} percentage. Value between 0 (line start) and 1 (line end) + * @return {Object} point * @private */ -Graph.prototype._reconnectEdges = function() { - var id, - nodes = this.nodes, - edges = this.edges; - for (id in nodes) { - if (nodes.hasOwnProperty(id)) { - nodes[id].edges = []; - } - } - - for (id in edges) { - if (edges.hasOwnProperty(id)) { - var edge = edges[id]; - edge.from = null; - edge.to = null; - edge.connect(); - } +Edge.prototype._pointOnCircle = function (x, y, radius, percentage) { + var angle = (percentage - 3/8) * 2 * Math.PI; + return { + x: x + radius * Math.cos(angle), + y: y - radius * Math.sin(angle) } }; /** - * Update the values of all object in the given array according to the current - * value range of the objects in the array. - * @param {Object} obj An object containing a set of Edges or Nodes - * The objects must have a method getValue() and - * setValueRange(min, max). + * Redraw a edge as a line with an arrow halfway the line + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx * @private */ -Graph.prototype._updateValueRange = function(obj) { - var id; +Edge.prototype._drawArrowCenter = function(ctx) { + var point; + // set style + ctx.strokeStyle = this.color; + ctx.fillStyle = this.color; + ctx.lineWidth = this._getLineWidth(); + + if (this.from != this.to) { + // draw line + this._line(ctx); + + // draw an arrow halfway the line + var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); + var length = 10 + 5 * this.width; // TODO: make customizable? + point = this._pointOnLine(0.5); + ctx.arrow(point.x, point.y, angle, length); + ctx.fill(); + ctx.stroke(); - // determine the range of the objects - var valueMin = undefined; - var valueMax = undefined; - for (id in obj) { - if (obj.hasOwnProperty(id)) { - var value = obj[id].getValue(); - if (value !== undefined) { - valueMin = (valueMin === undefined) ? value : Math.min(value, valueMin); - valueMax = (valueMax === undefined) ? value : Math.max(value, valueMax); - } + // draw label + if (this.label) { + point = this._pointOnLine(0.5); + this._label(ctx, this.label, point.x, point.y); } } + else { + // draw circle + var x, y; + var radius = this.length / 4; + var node = this.from; + if (!node.width) { + node.resize(ctx); + } + if (node.width > node.height) { + x = node.x + node.width / 2; + y = node.y - radius; + } + else { + x = node.x + radius; + y = node.y - node.height / 2; + } + this._circle(ctx, x, y, radius); - // adjust the range of all objects - if (valueMin !== undefined && valueMax !== undefined) { - for (id in obj) { - if (obj.hasOwnProperty(id)) { - obj[id].setValueRange(valueMin, valueMax); - } + // draw all arrows + var angle = 0.2 * Math.PI; + var length = 10 + 5 * this.width; // TODO: make customizable? + point = this._pointOnCircle(x, y, radius, 0.5); + ctx.arrow(point.x, point.y, angle, length); + ctx.fill(); + ctx.stroke(); + + // draw label + if (this.label) { + point = this._pointOnCircle(x, y, radius, 0.5); + this._label(ctx, this.label, point.x, point.y); } } }; -/** - * Redraw the graph with the current data - * chart will be resized too. - */ -Graph.prototype.redraw = function() { - this.setSize(this.width, this.height); - this._redraw(); -}; /** - * Redraw the graph with the current data + * Redraw a edge as a line with an arrow + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx * @private */ -Graph.prototype._redraw = function() { - var ctx = this.frame.canvas.getContext("2d"); +Edge.prototype._drawArrow = function(ctx) { + // set style + ctx.strokeStyle = this.color; + ctx.fillStyle = this.color; + ctx.lineWidth = this._getLineWidth(); - // clear the canvas - var w = this.frame.canvas.width; - var h = this.frame.canvas.height; - ctx.clearRect(0, 0, w, h); + // draw line + var angle, length; + if (this.from != this.to) { + // calculate length and angle of the line + angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); + var dx = (this.to.x - this.from.x); + var dy = (this.to.y - this.from.y); + var lEdge = Math.sqrt(dx * dx + dy * dy); - // set scaling and translation - ctx.save(); - ctx.translate(this.translation.x, this.translation.y); - ctx.scale(this.scale, this.scale); + var lFrom = this.from.distanceToBorder(ctx, angle + Math.PI); + var pFrom = (lEdge - lFrom) / lEdge; + var xFrom = (pFrom) * this.from.x + (1 - pFrom) * this.to.x; + var yFrom = (pFrom) * this.from.y + (1 - pFrom) * this.to.y; - this._drawEdges(ctx); - this._drawNodes(ctx); + var lTo = this.to.distanceToBorder(ctx, angle); + var pTo = (lEdge - lTo) / lEdge; + var xTo = (1 - pTo) * this.from.x + pTo * this.to.x; + var yTo = (1 - pTo) * this.from.y + pTo * this.to.y; - // restore original scaling and translation - ctx.restore(); -}; + ctx.beginPath(); + ctx.moveTo(xFrom, yFrom); + ctx.lineTo(xTo, yTo); + ctx.stroke(); -/** - * Set the translation of the graph - * @param {Number} offsetX Horizontal offset - * @param {Number} offsetY Vertical offset - * @private - */ -Graph.prototype._setTranslation = function(offsetX, offsetY) { - if (this.translation === undefined) { - this.translation = { - "x": 0, - "y": 0 - }; - } + // draw arrow at the end of the line + length = 10 + 5 * this.width; // TODO: make customizable? + ctx.arrow(xTo, yTo, angle, length); + ctx.fill(); + ctx.stroke(); - if (offsetX !== undefined) { - this.translation.x = offsetX; + // draw label + if (this.label) { + var point = this._pointOnLine(0.5); + this._label(ctx, this.label, point.x, point.y); + } } - if (offsetY !== undefined) { - this.translation.y = offsetY; + else { + // draw circle + var node = this.from; + var x, y, arrow; + var radius = this.length / 4; + if (!node.width) { + node.resize(ctx); + } + if (node.width > node.height) { + x = node.x + node.width / 2; + y = node.y - radius; + arrow = { + x: x, + y: node.y, + angle: 0.9 * Math.PI + }; + } + else { + x = node.x + radius; + y = node.y - node.height / 2; + arrow = { + x: node.x, + y: y, + angle: 0.6 * Math.PI + }; + } + ctx.beginPath(); + // TODO: do not draw a circle, but an arc + // TODO: similarly, for a line without arrows, draw to the border of the nodes instead of the center + ctx.arc(x, y, radius, 0, 2 * Math.PI, false); + ctx.stroke(); + + // draw all arrows + length = 10 + 5 * this.width; // TODO: make customizable? + ctx.arrow(arrow.x, arrow.y, arrow.angle, length); + ctx.fill(); + ctx.stroke(); + + // draw label + if (this.label) { + point = this._pointOnCircle(x, y, radius, 0.5); + this._label(ctx, this.label, point.x, point.y); + } } }; -/** - * Get the translation of the graph - * @return {Object} translation An object with parameters x and y, both a number - * @private - */ -Graph.prototype._getTranslation = function() { - return { - "x": this.translation.x, - "y": this.translation.y - }; -}; + /** - * Scale the graph - * @param {Number} scale Scaling factor 1.0 is unscaled - * @private - */ -Graph.prototype._setScale = function(scale) { - this.scale = scale; -}; -/** - * Get the current scale of the graph - * @return {Number} scale Scaling factor 1.0 is unscaled + * Calculate the distance between a point (x3,y3) and a line segment from + * (x1,y1) to (x2,y2). + * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment + * @param {number} x1 + * @param {number} y1 + * @param {number} x2 + * @param {number} y2 + * @param {number} x3 + * @param {number} y3 * @private */ -Graph.prototype._getScale = function() { - return this.scale; -}; +Edge._dist = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point + var px = x2-x1, + py = y2-y1, + something = px*px + py*py, + u = ((x3 - x1) * px + (y3 - y1) * py) / something; -Graph.prototype._xToCanvas = function(x) { - return (x - this.translation.x) / this.scale; -}; + if (u > 1) { + u = 1; + } + else if (u < 0) { + u = 0; + } -Graph.prototype._canvasToX = function(x) { - return x * this.scale + this.translation.x; -}; + var x = x1 + u * px, + y = y1 + u * py, + dx = x - x3, + dy = y - y3; -Graph.prototype._yToCanvas = function(y) { - return (y - this.translation.y) / this.scale; -}; + //# Note: If the actual distance does not matter, + //# if you only want to compare what this function + //# returns to other results of this function, you + //# can just return the squared distance instead + //# (i.e. remove the sqrt) to gain a little performance -Graph.prototype._canvasToY = function(y) { - return y * this.scale + this.translation.y ; + return Math.sqrt(dx*dx + dy*dy); }; /** - * Redraw all nodes - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Graph.prototype._drawNodes = function(ctx) { - // first draw the unselected nodes - var nodes = this.nodes; - var selected = []; - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - if (nodes[id].isSelected()) { - selected.push(id); - } - else { - nodes[id].draw(ctx); - } - } + * Popup is a class to create a popup window with some text + * @param {Element} container The container object. + * @param {Number} [x] + * @param {Number} [y] + * @param {String} [text] + */ +function Popup(container, x, y, text) { + if (container) { + this.container = container; + } + else { + this.container = document.body; } + this.x = 0; + this.y = 0; + this.padding = 5; - // draw the selected nodes on top - for (var s = 0, sMax = selected.length; s < sMax; s++) { - nodes[selected[s]].draw(ctx); + if (x !== undefined && y !== undefined ) { + this.setPosition(x, y); + } + if (text !== undefined) { + this.setText(text); } + + // create the frame + this.frame = document.createElement("div"); + var style = this.frame.style; + style.position = "absolute"; + style.visibility = "hidden"; + style.border = "1px solid #666"; + style.color = "black"; + style.padding = this.padding + "px"; + style.backgroundColor = "#FFFFC6"; + style.borderRadius = "3px"; + style.MozBorderRadius = "3px"; + style.WebkitBorderRadius = "3px"; + style.boxShadow = "3px 3px 10px rgba(128, 128, 128, 0.5)"; + style.whiteSpace = "nowrap"; + this.container.appendChild(this.frame); }; /** - * Redraw all edges - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private + * @param {number} x Horizontal position of the popup window + * @param {number} y Vertical position of the popup window */ -Graph.prototype._drawEdges = function(ctx) { - var edges = this.edges; - for (var id in edges) { - if (edges.hasOwnProperty(id)) { - var edge = edges[id]; - if (edge.connected) { - edges[id].draw(ctx); - } - } - } +Popup.prototype.setPosition = function(x, y) { + this.x = parseInt(x); + this.y = parseInt(y); }; /** - * Find a stable position for all nodes - * @private + * Set the text for the popup window. This can be HTML code + * @param {string} text */ -Graph.prototype._doStabilize = function() { - var start = new Date(); - - // find stable position - var count = 0; - var vmin = this.constants.minVelocity; - var stable = false; - while (!stable && count < this.constants.maxIterations) { - this._calculateForces(); - this._discreteStepNodes(); - stable = !this._isMoving(vmin); - count++; - } - - var end = new Date(); - - // console.log("Stabilized in " + (end-start) + " ms, " + count + " iterations" ); // TODO: cleanup +Popup.prototype.setText = function(text) { + this.frame.innerHTML = text; }; /** - * Calculate the external forces acting on the nodes - * Forces are caused by: edges, repulsing forces between nodes, gravity - * @private + * Show the popup window + * @param {boolean} show Optional. Show or hide the window */ -Graph.prototype._calculateForces = function() { - // create a local edge to the nodes and edges, that is faster - var id, dx, dy, angle, distance, fx, fy, - repulsingForce, springForce, length, edgeLength, - nodes = this.nodes, - edges = this.edges; - - // gravity, add a small constant force to pull the nodes towards the center of - // the graph - // Also, the forces are reset to zero in this loop by using _setForce instead - // of _addForce - var gravity = 0.01, - gx = this.frame.canvas.clientWidth / 2, - gy = this.frame.canvas.clientHeight / 2; - for (id in nodes) { - if (nodes.hasOwnProperty(id)) { - var node = nodes[id]; - dx = gx - node.x; - dy = gy - node.y; - angle = Math.atan2(dy, dx); - fx = Math.cos(angle) * gravity; - fy = Math.sin(angle) * gravity; - - node._setForce(fx, fy); - } +Popup.prototype.show = function (show) { + if (show === undefined) { + show = true; } - // repulsing forces between nodes - var minimumDistance = this.constants.nodes.distance, - steepness = 10; // higher value gives steeper slope of the force around the given minimumDistance - - for (var id1 in nodes) { - if (nodes.hasOwnProperty(id1)) { - var node1 = nodes[id1]; - for (var id2 in nodes) { - if (nodes.hasOwnProperty(id2)) { - var node2 = nodes[id2]; - // calculate normally distributed force - dx = node2.x - node1.x; - dy = node2.y - node1.y; - distance = Math.sqrt(dx * dx + dy * dy); - angle = Math.atan2(dy, dx); - - // TODO: correct factor for repulsing force - //repulsingForce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force - //repulsingForce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force - repulsingForce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)); // TODO: customize the repulsing force - fx = Math.cos(angle) * repulsingForce; - fy = Math.sin(angle) * repulsingForce; + if (show) { + var height = this.frame.clientHeight; + var width = this.frame.clientWidth; + var maxHeight = this.frame.parentNode.clientHeight; + var maxWidth = this.frame.parentNode.clientWidth; - node1._addForce(-fx, -fy); - node2._addForce(fx, fy); - } - } + var top = (this.y - height); + if (top + height + this.padding > maxHeight) { + top = maxHeight - height - this.padding; + } + if (top < this.padding) { + top = this.padding; } - } - - /* TODO: re-implement repulsion of edges - for (var n = 0; n < nodes.length; n++) { - for (var l = 0; l < edges.length; l++) { - var lx = edges[l].from.x+(edges[l].to.x - edges[l].from.x)/2, - ly = edges[l].from.y+(edges[l].to.y - edges[l].from.y)/2, - - // calculate normally distributed force - dx = nodes[n].x - lx, - dy = nodes[n].y - ly, - distance = Math.sqrt(dx * dx + dy * dy), - angle = Math.atan2(dy, dx), + var left = this.x; + if (left + width + this.padding > maxWidth) { + left = maxWidth - width - this.padding; + } + if (left < this.padding) { + left = this.padding; + } - // TODO: correct factor for repulsing force - //var repulsingforce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force - //repulsingforce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ), // TODO: customize the repulsing force - repulsingforce = 1 / (1 + Math.exp((distance / (minimumDistance / 2) - 1) * steepness)), // TODO: customize the repulsing force - fx = Math.cos(angle) * repulsingforce, - fy = Math.sin(angle) * repulsingforce; - nodes[n]._addForce(fx, fy); - edges[l].from._addForce(-fx/2,-fy/2); - edges[l].to._addForce(-fx/2,-fy/2); - } + this.frame.style.left = left + "px"; + this.frame.style.top = top + "px"; + this.frame.style.visibility = "visible"; } - */ - - // forces caused by the edges, modelled as springs - for (id in edges) { - if (edges.hasOwnProperty(id)) { - var edge = edges[id]; - if (edge.connected) { - dx = (edge.to.x - edge.from.x); - dy = (edge.to.y - edge.from.y); - //edgeLength = (edge.from.width + edge.from.height + edge.to.width + edge.to.height)/2 || edge.length; // TODO: dmin - //edgeLength = (edge.from.width + edge.to.width)/2 || edge.length; // TODO: dmin - //edgeLength = 20 + ((edge.from.width + edge.to.width) || 0) / 2; - edgeLength = edge.length; - length = Math.sqrt(dx * dx + dy * dy); - angle = Math.atan2(dy, dx); - - springForce = edge.stiffness * (edgeLength - length); - - fx = Math.cos(angle) * springForce; - fy = Math.sin(angle) * springForce; - - edge.from._addForce(-fx, -fy); - edge.to._addForce(fx, fy); - } - } + else { + this.hide(); } +}; - /* TODO: re-implement repulsion of edges - // repulsing forces between edges - var minimumDistance = this.constants.edges.distance, - steepness = 10; // higher value gives steeper slope of the force around the given minimumDistance - for (var l = 0; l < edges.length; l++) { - //Keep distance from other edge centers - for (var l2 = l + 1; l2 < this.edges.length; l2++) { - //var dmin = (nodes[n].width + nodes[n].height + nodes[n2].width + nodes[n2].height) / 1 || minimumDistance, // TODO: dmin - //var dmin = (nodes[n].width + nodes[n2].width)/2 || minimumDistance, // TODO: dmin - //dmin = 40 + ((nodes[n].width/2 + nodes[n2].width/2) || 0), - var lx = edges[l].from.x+(edges[l].to.x - edges[l].from.x)/2, - ly = edges[l].from.y+(edges[l].to.y - edges[l].from.y)/2, - l2x = edges[l2].from.x+(edges[l2].to.x - edges[l2].from.x)/2, - l2y = edges[l2].from.y+(edges[l2].to.y - edges[l2].from.y)/2, - - // calculate normally distributed force - dx = l2x - lx, - dy = l2y - ly, - distance = Math.sqrt(dx * dx + dy * dy), - angle = Math.atan2(dy, dx), - - - // TODO: correct factor for repulsing force - //var repulsingforce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force - //repulsingforce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ), // TODO: customize the repulsing force - repulsingforce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)), // TODO: customize the repulsing force - fx = Math.cos(angle) * repulsingforce, - fy = Math.sin(angle) * repulsingforce; +/** + * Hide the popup window + */ +Popup.prototype.hide = function () { + this.frame.style.visibility = "hidden"; +}; - edges[l].from._addForce(-fx, -fy); - edges[l].to._addForce(-fx, -fy); - edges[l2].from._addForce(fx, fy); - edges[l2].to._addForce(fx, fy); - } - } - */ +/** + * @class Groups + * This class can store groups and properties specific for groups. + */ +Groups = function () { + this.clear(); + this.defaultIndex = 0; }; /** - * Check if any of the nodes is still moving - * @param {number} vmin the minimum velocity considered as "moving" - * @return {boolean} true if moving, false if non of the nodes is moving - * @private + * default constants for group colors */ -Graph.prototype._isMoving = function(vmin) { - // TODO: ismoving does not work well: should check the kinetic energy, not its velocity - var nodes = this.nodes; - for (var id in nodes) { - if (nodes.hasOwnProperty(id) && nodes[id].isMoving(vmin)) { - return true; - } - } - return false; -}; +Groups.DEFAULT = [ + {border: "#2B7CE9", background: "#97C2FC", highlight: {border: "#2B7CE9", background: "#D2E5FF"}}, // blue + {border: "#FFA500", background: "#FFFF00", highlight: {border: "#FFA500", background: "#FFFFA3"}}, // yellow + {border: "#FA0A10", background: "#FB7E81", highlight: {border: "#FA0A10", background: "#FFAFB1"}}, // red + {border: "#41A906", background: "#7BE141", highlight: {border: "#41A906", background: "#A1EC76"}}, // green + {border: "#E129F0", background: "#EB7DF4", highlight: {border: "#E129F0", background: "#F0B3F5"}}, // magenta + {border: "#7C29F0", background: "#AD85E4", highlight: {border: "#7C29F0", background: "#D3BDF0"}}, // purple + {border: "#C37F00", background: "#FFA807", highlight: {border: "#C37F00", background: "#FFCA66"}}, // orange + {border: "#4220FB", background: "#6E6EFD", highlight: {border: "#4220FB", background: "#9B9BFD"}}, // darkblue + {border: "#FD5A77", background: "#FFC0CB", highlight: {border: "#FD5A77", background: "#FFD1D9"}}, // pink + {border: "#4AD63A", background: "#C2FABC", highlight: {border: "#4AD63A", background: "#E6FFE3"}} // mint +]; /** - * Perform one discrete step for all nodes - * @private + * Clear all groups */ -Graph.prototype._discreteStepNodes = function() { - var interval = this.refreshRate / 1000.0; // in seconds - var nodes = this.nodes; - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - nodes[id].discreteStep(interval); +Groups.prototype.clear = function () { + this.groups = {}; + this.groups.length = function() + { + var i = 0; + for ( var p in this ) { + if (this.hasOwnProperty(p)) { + i++; + } } + return i; } }; + /** - * Start animating nodes and edges + * get group properties of a groupname. If groupname is not found, a new group + * is added. + * @param {*} groupname Can be a number, string, Date, etc. + * @return {Object} group The created group, containing all group properties */ -Graph.prototype.start = function() { - if (this.moving) { - this._calculateForces(); - this._discreteStepNodes(); +Groups.prototype.get = function (groupname) { + var group = this.groups[groupname]; - var vmin = this.constants.minVelocity; - this.moving = this._isMoving(vmin); + if (group == undefined) { + // create new group + var index = this.defaultIndex % Groups.DEFAULT.length; + this.defaultIndex++; + group = {}; + group.color = Groups.DEFAULT[index]; + this.groups[groupname] = group; } - if (this.moving) { - // start animation. only start timer if it is not already running - if (!this.timer) { - var graph = this; - this.timer = window.setTimeout(function () { - graph.timer = undefined; - graph.start(); - graph._redraw(); - }, this.refreshRate); - } - } - else { - this._redraw(); - } + return group; }; /** - * Stop animating nodes and edges. + * Add a custom group style + * @param {String} groupname + * @param {Object} style An object containing borderColor, + * backgroundColor, etc. + * @return {Object} group The created group object */ -Graph.prototype.stop = function () { - if (this.timer) { - window.clearInterval(this.timer); - this.timer = undefined; +Groups.prototype.add = function (groupname, style) { + this.groups[groupname] = style; + if (style.color) { + style.color = Node.parseColor(style.color); } + return style; }; /** - * vis.js module exports + * @class Images + * This class loads images and keeps them stored. */ -var vis = { - util: util, - events: events, - - Controller: Controller, - DataSet: DataSet, - DataView: DataView, - Range: Range, - Stack: Stack, - TimeStep: TimeStep, - EventBus: EventBus, - - components: { - items: { - Item: Item, - ItemBox: ItemBox, - ItemPoint: ItemPoint, - ItemRange: ItemRange - }, - - Component: Component, - Panel: Panel, - RootPanel: RootPanel, - ItemSet: ItemSet, - TimeAxis: TimeAxis - }, - - graph: { - Node: Node, - Edge: Edge, - Popup: Popup, - Groups: Groups, - Images: Images - }, +Images = function () { + this.images = {}; - Timeline: Timeline, - Graph: Graph + this.callback = undefined; }; /** - * CommonJS module exports + * Set an onload callback function. This will be called each time an image + * is loaded + * @param {function} callback */ -if (typeof exports !== 'undefined') { - exports = vis; -} -if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { - module.exports = vis; -} +Images.prototype.setOnloadCallback = function(callback) { + this.callback = callback; +}; /** - * AMD module exports + * + * @param {string} url Url of the image + * @return {Image} img The image object */ -if (typeof(define) === 'function') { - define(function () { - return vis; - }); -} +Images.prototype.load = function(url) { + var img = this.images[url]; + if (img == undefined) { + // create the image + var images = this; + img = new Image(); + this.images[url] = img; + img.onload = function() { + if (images.callback) { + images.callback(this); + } + }; + img.src = url; + } + + return img; +}; /** - * Window exports + * @constructor Graph + * Create a graph visualization, displaying nodes and edges. + * + * @param {Element} container The DOM element in which the Graph will + * be created. Normally a div element. + * @param {Object} data An object containing parameters + * {Array} nodes + * {Array} edges + * @param {Object} options Options */ -if (typeof window !== 'undefined') { - // attach the module to the window, load as a regular javascript file - window['vis'] = vis; -} +function Graph (container, data, options) { + // create variables and set default values + this.containerElement = container; + this.width = '100%'; + this.height = '100%'; + this.refreshRate = 50; // milliseconds + this.stabilize = true; // stabilize before displaying the graph + this.selectable = true; + + // set constant values + this.constants = { + nodes: { + radiusMin: 5, + radiusMax: 20, + radius: 5, + distance: 100, // px + shape: 'ellipse', + image: undefined, + widthMin: 16, // px + widthMax: 64, // px + fontColor: 'black', + fontSize: 14, // px + //fontFace: verdana, + fontFace: 'arial', + color: { + border: '#2B7CE9', + background: '#97C2FC', + highlight: { + border: '#2B7CE9', + background: '#D2E5FF' + } + }, + borderColor: '#2B7CE9', + backgroundColor: '#97C2FC', + highlightColor: '#D2E5FF', + group: undefined + }, + edges: { + widthMin: 1, + widthMax: 15, + width: 1, + style: 'line', + color: '#343434', + fontColor: '#343434', + fontSize: 14, // px + fontFace: 'arial', + //distance: 100, //px + length: 100, // px + dash: { + length: 10, + gap: 5, + altLength: undefined + } + }, + minForce: 0.05, + minVelocity: 0.02, // px/s + maxIterations: 1000 // maximum number of iteration to stabilize + }; + + var graph = this; + this.nodes = {}; // object with Node objects + this.edges = {}; // object with Edge objects + // TODO: create a counter to keep track on the number of nodes having values + // TODO: create a counter to keep track on the number of nodes currently moving + // TODO: create a counter to keep track on the number of edges having values -// inject css -util.loadCss("/* vis.js stylesheet */\n.vis.timeline {\n}\n\n\n.vis.timeline.rootpanel {\n position: relative;\n overflow: hidden;\n\n border: 1px solid #bfbfbf;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n\n.vis.timeline .panel {\n position: absolute;\n overflow: hidden;\n}\n\n\n.vis.timeline .groupset {\n position: absolute;\n padding: 0;\n margin: 0;\n}\n\n.vis.timeline .labels {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n\n padding: 0;\n margin: 0;\n\n border-right: 1px solid #bfbfbf;\n box-sizing: border-box;\n -moz-box-sizing: border-box;\n}\n\n.vis.timeline .labels .label {\n position: absolute;\n left: 0;\n top: 0;\n width: 100%;\n border-bottom: 1px solid #bfbfbf;\n color: #4d4d4d;\n}\n\n.vis.timeline .labels .label .inner {\n display: inline-block;\n padding: 5px;\n}\n\n\n.vis.timeline .itemset {\n position: absolute;\n padding: 0;\n margin: 0;\n overflow: hidden;\n}\n\n.vis.timeline .background {\n}\n\n.vis.timeline .foreground {\n}\n\n.vis.timeline .itemset-axis {\n position: absolute;\n}\n\n.vis.timeline .groupset .itemset-axis {\n border-top: 1px solid #bfbfbf;\n}\n\n/* TODO: with orientation=='bottom', this will more or less overlap with timeline axis\n.vis.timeline .groupset .itemset-axis:last-child {\n border-top: none;\n}\n*/\n\n\n.vis.timeline .item {\n position: absolute;\n color: #1A1A1A;\n border-color: #97B0F8;\n background-color: #D5DDF6;\n display: inline-block;\n}\n\n.vis.timeline .item.selected {\n border-color: #FFC200;\n background-color: #FFF785;\n z-index: 999;\n}\n\n.vis.timeline .item.cluster {\n /* TODO: use another color or pattern? */\n background: #97B0F8 url('img/cluster_bg.png');\n color: white;\n}\n.vis.timeline .item.cluster.point {\n border-color: #D5DDF6;\n}\n\n.vis.timeline .item.box {\n text-align: center;\n border-style: solid;\n border-width: 1px;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.point {\n background: none;\n}\n\n.vis.timeline .dot {\n border: 5px solid #97B0F8;\n position: absolute;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.range {\n overflow: hidden;\n border-style: solid;\n border-width: 1px;\n border-radius: 2px;\n -moz-border-radius: 2px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.range .drag-left {\n cursor: w-resize;\n z-index: 1000;\n}\n\n.vis.timeline .item.range .drag-right {\n cursor: e-resize;\n z-index: 1000;\n}\n\n.vis.timeline .item.range .content {\n position: relative;\n display: inline-block;\n}\n\n.vis.timeline .item.line {\n position: absolute;\n width: 0;\n border-left-width: 1px;\n border-left-style: solid;\n}\n\n.vis.timeline .item .content {\n margin: 5px;\n white-space: nowrap;\n overflow: hidden;\n}\n\n.vis.timeline .axis {\n position: relative;\n}\n\n.vis.timeline .axis .text {\n position: absolute;\n color: #4d4d4d;\n padding: 3px;\n white-space: nowrap;\n}\n\n.vis.timeline .axis .text.measure {\n position: absolute;\n padding-left: 0;\n padding-right: 0;\n margin-left: 0;\n margin-right: 0;\n visibility: hidden;\n}\n\n.vis.timeline .axis .grid.vertical {\n position: absolute;\n width: 0;\n border-right: 1px solid;\n}\n\n.vis.timeline .axis .grid.horizontal {\n position: absolute;\n left: 0;\n width: 100%;\n height: 0;\n border-bottom: 1px solid;\n}\n\n.vis.timeline .axis .grid.minor {\n border-color: #e5e5e5;\n}\n\n.vis.timeline .axis .grid.major {\n border-color: #bfbfbf;\n}\n\n"); + this.nodesData = null; // A DataSet or DataView + this.edgesData = null; // A DataSet or DataView -})() -},{"moment":2}],2:[function(require,module,exports){ -(function(){// moment.js -// version : 2.0.0 -// author : Tim Wood -// license : MIT -// momentjs.com + // create event listeners used to subscribe on the DataSets of the nodes and edges + var me = this; + this.nodesListeners = { + 'add': function (event, params) { + me._addNodes(params.items); + me.start(); + }, + 'update': function (event, params) { + me._updateNodes(params.items); + me.start(); + }, + 'remove': function (event, params) { + me._removeNodes(params.items); + me.start(); + } + }; + this.edgesListeners = { + 'add': function (event, params) { + me._addEdges(params.items); + me.start(); + }, + 'update': function (event, params) { + me._updateEdges(params.items); + me.start(); + }, + 'remove': function (event, params) { + me._removeEdges(params.items); + me.start(); + } + }; -(function (undefined) { + this.groups = new Groups(); // object with groups + this.images = new Images(); // object with images + this.images.setOnloadCallback(function () { + graph._redraw(); + }); - /************************************ - Constants - ************************************/ + // properties of the data + this.moving = false; // True if any of the nodes have an undefined position - var moment, - VERSION = "2.0.0", - round = Math.round, i, - // internal storage for language config files - languages = {}, + this.selection = []; + this.timer = undefined; - // check for nodeJS - hasModule = (typeof module !== 'undefined' && module.exports), + // create a frame and canvas + this._create(); - // ASP.NET json date format regex - aspNetJsonRegex = /^\/?Date\((\-?\d+)/i, + // apply options + this.setOptions(options); - // format tokens - formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYY|YYYY|YY|a|A|hh?|HH?|mm?|ss?|SS?S?|X|zz?|ZZ?|.)/g, - localFormattingTokens = /(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g, + // draw data + this.setData(data); +} - // parsing tokens - parseMultipleFormatChunker = /([0-9a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)/gi, +/** + * Set nodes and edges, and optionally options as well. + * + * @param {Object} data Object containing parameters: + * {Array | DataSet | DataView} [nodes] Array with nodes + * {Array | DataSet | DataView} [edges] Array with edges + * {String} [dot] String containing data in DOT format + * {Options} [options] Object with options + */ +Graph.prototype.setData = function(data) { + if (data && data.dot && (data.nodes || data.edges)) { + throw new SyntaxError('Data must contain either parameter "dot" or ' + + ' parameter pair "nodes" and "edges", but not both.'); + } - // parsing token regexes - parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99 - parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999 - parseTokenThreeDigits = /\d{3}/, // 000 - 999 - parseTokenFourDigits = /\d{1,4}/, // 0 - 9999 - parseTokenSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999 - parseTokenWord = /[0-9]*[a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF]+\s*?[\u0600-\u06FF]+/i, // any word (or two) characters or numbers including two word month in arabic. - parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/i, // +00:00 -00:00 +0000 -0000 or Z - parseTokenT = /T/i, // T (ISO seperator) - parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123 + // set options + this.setOptions(data && data.options); - // preliminary iso regex - // 0000-00-00 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 - isoRegex = /^\s*\d{4}-\d\d-\d\d((T| )(\d\d(:\d\d(:\d\d(\.\d\d?\d?)?)?)?)?([\+\-]\d\d:?\d\d)?)?/, - isoFormat = 'YYYY-MM-DDTHH:mm:ssZ', + // set all data + if (data && data.dot) { + // parse DOT file + if(data && data.dot) { + var dotData = vis.util.DOTToGraph(data.dot); + this.setData(dotData); + return; + } + } + else { + this._setNodes(data && data.nodes); + this._setEdges(data && data.edges); + } - // iso time formats and regexes - isoTimes = [ - ['HH:mm:ss.S', /(T| )\d\d:\d\d:\d\d\.\d{1,3}/], - ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/], - ['HH:mm', /(T| )\d\d:\d\d/], - ['HH', /(T| )\d\d/] - ], + // find a stable position or start animating to a stable position + if (this.stabilize) { + this._doStabilize(); + } + this.start(); +}; - // timezone chunker "+10:00" > ["10", "00"] or "-1530" > ["-15", "30"] - parseTimezoneChunker = /([\+\-]|\d\d)/gi, +/** + * Set options + * @param {Object} options + */ +Graph.prototype.setOptions = function (options) { + if (options) { + // retrieve parameter values + if (options.width != undefined) {this.width = options.width;} + if (options.height != undefined) {this.height = options.height;} + if (options.stabilize != undefined) {this.stabilize = options.stabilize;} + if (options.selectable != undefined) {this.selectable = options.selectable;} - // getter and setter names - proxyGettersAndSetters = 'Month|Date|Hours|Minutes|Seconds|Milliseconds'.split('|'), - unitMillisecondFactors = { - 'Milliseconds' : 1, - 'Seconds' : 1e3, - 'Minutes' : 6e4, - 'Hours' : 36e5, - 'Days' : 864e5, - 'Months' : 2592e6, - 'Years' : 31536e6 - }, + // TODO: work out these options and document them + if (options.edges) { + for (var prop in options.edges) { + if (options.edges.hasOwnProperty(prop)) { + this.constants.edges[prop] = options.edges[prop]; + } + } - // format function strings - formatFunctions = {}, + if (options.edges.length != undefined && + options.nodes && options.nodes.distance == undefined) { + this.constants.edges.length = options.edges.length; + this.constants.nodes.distance = options.edges.length * 1.25; + } - // tokens to ordinalize and pad - ordinalizeTokens = 'DDD w W M D d'.split(' '), - paddedTokens = 'M D H h m s w W'.split(' '), + if (!options.edges.fontColor) { + this.constants.edges.fontColor = options.edges.color; + } - formatTokenFunctions = { - M : function () { - return this.month() + 1; - }, - MMM : function (format) { - return this.lang().monthsShort(this, format); - }, - MMMM : function (format) { - return this.lang().months(this, format); - }, - D : function () { - return this.date(); - }, - DDD : function () { - return this.dayOfYear(); - }, - d : function () { - return this.day(); - }, - dd : function (format) { - return this.lang().weekdaysMin(this, format); - }, - ddd : function (format) { - return this.lang().weekdaysShort(this, format); - }, - dddd : function (format) { - return this.lang().weekdays(this, format); - }, - w : function () { - return this.week(); - }, - W : function () { - return this.isoWeek(); - }, - YY : function () { - return leftZeroFill(this.year() % 100, 2); - }, - YYYY : function () { - return leftZeroFill(this.year(), 4); - }, - YYYYY : function () { - return leftZeroFill(this.year(), 5); - }, - a : function () { - return this.lang().meridiem(this.hours(), this.minutes(), true); - }, - A : function () { - return this.lang().meridiem(this.hours(), this.minutes(), false); - }, - H : function () { - return this.hours(); - }, - h : function () { - return this.hours() % 12 || 12; - }, - m : function () { - return this.minutes(); - }, - s : function () { - return this.seconds(); - }, - S : function () { - return ~~(this.milliseconds() / 100); - }, - SS : function () { - return leftZeroFill(~~(this.milliseconds() / 10), 2); - }, - SSS : function () { - return leftZeroFill(this.milliseconds(), 3); - }, - Z : function () { - var a = -this.zone(), - b = "+"; - if (a < 0) { - a = -a; - b = "-"; + // Added to support dashed lines + // David Jordan + // 2012-08-08 + if (options.edges.dash) { + if (options.edges.dash.length != undefined) { + this.constants.edges.dash.length = options.edges.dash.length; } - return b + leftZeroFill(~~(a / 60), 2) + ":" + leftZeroFill(~~a % 60, 2); - }, - ZZ : function () { - var a = -this.zone(), - b = "+"; - if (a < 0) { - a = -a; - b = "-"; + if (options.edges.dash.gap != undefined) { + this.constants.edges.dash.gap = options.edges.dash.gap; + } + if (options.edges.dash.altLength != undefined) { + this.constants.edges.dash.altLength = options.edges.dash.altLength; } - return b + leftZeroFill(~~(10 * a / 6), 4); - }, - X : function () { - return this.unix(); } - }; + } - function padToken(func, count) { - return function (a) { - return leftZeroFill(func.call(this, a), count); - }; - } - function ordinalizeToken(func) { - return function (a) { - return this.lang().ordinal(func.call(this, a)); - }; - } + if (options.nodes) { + for (prop in options.nodes) { + if (options.nodes.hasOwnProperty(prop)) { + this.constants.nodes[prop] = options.nodes[prop]; + } + } - while (ordinalizeTokens.length) { - i = ordinalizeTokens.pop(); - formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i]); - } - while (paddedTokens.length) { - i = paddedTokens.pop(); - formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2); + if (options.nodes.color) { + this.constants.nodes.color = Node.parseColor(options.nodes.color); + } + + /* + if (options.nodes.widthMin) this.constants.nodes.radiusMin = options.nodes.widthMin; + if (options.nodes.widthMax) this.constants.nodes.radiusMax = options.nodes.widthMax; + */ + } + + if (options.groups) { + for (var groupname in options.groups) { + if (options.groups.hasOwnProperty(groupname)) { + var group = options.groups[groupname]; + this.groups.add(groupname, group); + } + } + } } - formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3); + this.setSize(this.width, this.height); + this._setTranslation(this.frame.clientWidth / 2, this.frame.clientHeight / 2); + this._setScale(1); +}; - /************************************ - Constructors - ************************************/ +/** + * fire an event + * @param {String} event The name of an event, for example 'select' + * @param {Object} params Optional object with event parameters + * @private + */ +Graph.prototype._trigger = function (event, params) { + events.trigger(this, event, params); +}; - function Language() { +/** + * Create the main frame for the Graph. + * This function is executed once when a Graph object is created. The frame + * contains a canvas, and this canvas contains all objects like the axis and + * nodes. + * @private + */ +Graph.prototype._create = function () { + // remove all elements from the container element. + while (this.containerElement.hasChildNodes()) { + this.containerElement.removeChild(this.containerElement.firstChild); } - // Moment prototype object - function Moment(config) { - extend(this, config); + this.frame = document.createElement('div'); + this.frame.className = 'graph-frame'; + this.frame.style.position = 'relative'; + this.frame.style.overflow = 'hidden'; + + // create the graph canvas (HTML canvas element) + this.frame.canvas = document.createElement( 'canvas' ); + this.frame.canvas.style.position = 'relative'; + this.frame.appendChild(this.frame.canvas); + if (!this.frame.canvas.getContext) { + var noCanvas = document.createElement( 'DIV' ); + noCanvas.style.color = 'red'; + noCanvas.style.fontWeight = 'bold' ; + noCanvas.style.padding = '10px'; + noCanvas.innerHTML = 'Error: your browser does not support HTML canvas'; + this.frame.canvas.appendChild(noCanvas); } - // Duration Constructor - function Duration(duration) { - var data = this._data = {}, - years = duration.years || duration.year || duration.y || 0, - months = duration.months || duration.month || duration.M || 0, - weeks = duration.weeks || duration.week || duration.w || 0, - days = duration.days || duration.day || duration.d || 0, - hours = duration.hours || duration.hour || duration.h || 0, - minutes = duration.minutes || duration.minute || duration.m || 0, - seconds = duration.seconds || duration.second || duration.s || 0, - milliseconds = duration.milliseconds || duration.millisecond || duration.ms || 0; + var me = this; + this.drag = {}; + this.pinch = {}; + this.hammer = Hammer(this.frame.canvas, { + prevent_default: true + }); + this.hammer.on('tap', me._onTap.bind(me) ); + this.hammer.on('hold', me._onHold.bind(me) ); + this.hammer.on('pinch', me._onPinch.bind(me) ); + this.hammer.on('touch', me._onTouch.bind(me) ); + this.hammer.on('dragstart', me._onDragStart.bind(me) ); + this.hammer.on('drag', me._onDrag.bind(me) ); + this.hammer.on('dragend', me._onDragEnd.bind(me) ); + this.hammer.on('mousewheel',me._onMouseWheel.bind(me) ); + this.hammer.on('mousemove', me._onMouseMoveTitle.bind(me) ); - // representation for dateAddRemove - this._milliseconds = milliseconds + - seconds * 1e3 + // 1000 - minutes * 6e4 + // 1000 * 60 - hours * 36e5; // 1000 * 60 * 60 - // Because of dateAddRemove treats 24 hours as different from a - // day when working around DST, we need to store them separately - this._days = days + - weeks * 7; - // It is impossible translate months into days without knowing - // which months you are are talking about, so we have to store - // it separately. - this._months = months + - years * 12; + // add the frame to the container element + this.containerElement.appendChild(this.frame); +}; + +/** + * + * @param {{x: Number, y: Number}} pointer + * @return {Number | null} node + * @private + */ +Graph.prototype._getNodeAt = function (pointer) { + var x = this._canvasToX(pointer.x); + var y = this._canvasToY(pointer.y); + + var obj = { + left: x, + top: y, + right: x, + bottom: y + }; + + // if there are overlapping nodes, select the last one, this is the + // one which is drawn on top of the others + var overlappingNodes = this._getNodesOverlappingWith(obj); + return (overlappingNodes.length > 0) ? + overlappingNodes[overlappingNodes.length - 1] : null; +}; + +/** + * Get the pointer location from a touch location + * @param {{pageX: Number, pageY: Number}} touch + * @return {{x: Number, y: Number}} pointer + * @private + */ +Graph.prototype._getPointer = function (touch) { + return { + x: touch.pageX - vis.util.getAbsoluteLeft(this.frame.canvas), + y: touch.pageY - vis.util.getAbsoluteTop(this.frame.canvas) + }; +}; + +/** + * On start of a touch gesture, store the pointer + * @param event + * @private + */ +Graph.prototype._onTouch = function (event) { + this.drag.pointer = this._getPointer(event.gesture.touches[0]); + this.drag.pinched = false; + this.pinch.scale = this._getScale(); +}; - // The following code bubbles up values, see the tests for - // examples of what that means. - data.milliseconds = milliseconds % 1000; - seconds += absRound(milliseconds / 1000); +/** + * handle drag start event + * @private + */ +Graph.prototype._onDragStart = function () { + var drag = this.drag; - data.seconds = seconds % 60; - minutes += absRound(seconds / 60); + drag.selection = []; + drag.translation = this._getTranslation(); + drag.nodeId = this._getNodeAt(drag.pointer); + // note: drag.pointer is set in _onTouch to get the initial touch location - data.minutes = minutes % 60; - hours += absRound(minutes / 60); + var node = this.nodes[drag.nodeId]; + if (node) { + // select the clicked node if not yet selected + if (!node.isSelected()) { + this._selectNodes([drag.nodeId]); + } - data.hours = hours % 24; - days += absRound(hours / 24); + // create an array with the selected nodes and their original location and status + var me = this; + this.selection.forEach(function (id) { + var node = me.nodes[id]; + if (node) { + var s = { + id: id, + node: node, + + // store original x, y, xFixed and yFixed, make the node temporarily Fixed + x: node.x, + y: node.y, + xFixed: node.xFixed, + yFixed: node.yFixed + }; - days += weeks * 7; - data.days = days % 30; + node.xFixed = true; + node.yFixed = true; - months += absRound(days / 30); + drag.selection.push(s); + } + }); - data.months = months % 12; - years += absRound(months / 12); + } +}; - data.years = years; +/** + * handle drag event + * @private + */ +Graph.prototype._onDrag = function (event) { + if (this.drag.pinched) { + return; } + var pointer = this._getPointer(event.gesture.touches[0]); - /************************************ - Helpers - ************************************/ + var me = this, + drag = this.drag, + selection = drag.selection; + if (selection && selection.length) { + // calculate delta's and new location + var deltaX = pointer.x - drag.pointer.x, + deltaY = pointer.y - drag.pointer.y; + // update position of all selected nodes + selection.forEach(function (s) { + var node = s.node; - function extend(a, b) { - for (var i in b) { - if (b.hasOwnProperty(i)) { - a[i] = b[i]; + if (!s.xFixed) { + node.x = me._canvasToX(me._xToCanvas(s.x) + deltaX); + } + + if (!s.yFixed) { + node.y = me._canvasToY(me._yToCanvas(s.y) + deltaY); } + }); + + // start animation if not yet running + if (!this.moving) { + this.moving = true; + this.start(); } - return a; } + else { + // move the graph + var diffX = pointer.x - this.drag.pointer.x; + var diffY = pointer.y - this.drag.pointer.y; - function absRound(number) { - if (number < 0) { - return Math.ceil(number); - } else { - return Math.floor(number); - } + this._setTranslation( + this.drag.translation.x + diffX, + this.drag.translation.y + diffY); + this._redraw(); + + this.moved = true; } +}; - // left zero fill a number - // see http://jsperf.com/left-zero-filling for performance comparison - function leftZeroFill(number, targetLength) { - var output = number + ''; - while (output.length < targetLength) { - output = '0' + output; - } - return output; +/** + * handle drag start event + * @private + */ +Graph.prototype._onDragEnd = function () { + var selection = this.drag.selection; + if (selection) { + selection.forEach(function (s) { + // restore original xFixed and yFixed + s.node.xFixed = s.xFixed; + s.node.yFixed = s.yFixed; + }); } +}; - // helper function for _.addTime and _.subtractTime - function addOrSubtractDurationFromMoment(mom, duration, isAdding) { - var ms = duration._milliseconds, - d = duration._days, - M = duration._months, - currentDate; +/** + * handle tap/click event: select/unselect a node + * @private + */ +Graph.prototype._onTap = function (event) { + var pointer = this._getPointer(event.gesture.touches[0]); - if (ms) { - mom._d.setTime(+mom + ms * isAdding); - } - if (d) { - mom.date(mom.date() + d * isAdding); - } - if (M) { - currentDate = mom.date(); - mom.date(1) - .month(mom.month() + M * isAdding) - .date(Math.min(currentDate, mom.daysInMonth())); + var nodeId = this._getNodeAt(pointer); + var node = this.nodes[nodeId]; + if (node) { + // select this node + this._selectNodes([nodeId]); + + if (!this.moving) { + this._redraw(); } } - - // check if is an array - function isArray(input) { - return Object.prototype.toString.call(input) === '[object Array]'; + else { + // remove selection + this._unselectNodes(); + this._redraw(); } +}; - // compare two arrays, return the number of differences - function compareArrays(array1, array2) { - var len = Math.min(array1.length, array2.length), - lengthDiff = Math.abs(array1.length - array2.length), - diffs = 0, - i; - for (i = 0; i < len; i++) { - if (~~array1[i] !== ~~array2[i]) { - diffs++; - } +/** + * handle long tap event: multi select nodes + * @private + */ +Graph.prototype._onHold = function (event) { + var pointer = this._getPointer(event.gesture.touches[0]); + var nodeId = this._getNodeAt(pointer); + var node = this.nodes[nodeId]; + if (node) { + if (!node.isSelected()) { + // select this node, keep previous selection + var append = true; + this._selectNodes([nodeId], append); + } + else { + this._unselectNodes([nodeId]); } - return diffs + lengthDiff; - } + if (!this.moving) { + this._redraw(); + } + } + else { + // Do nothing + } +}; - /************************************ - Languages - ************************************/ +/** + * Handle pinch event + * @param event + * @private + */ +Graph.prototype._onPinch = function (event) { + var pointer = this._getPointer(event.gesture.center); + this.drag.pinched = true; + if (!('scale' in this.pinch)) { + this.pinch.scale = 1; + } - Language.prototype = { - set : function (config) { - var prop, i; - for (i in config) { - prop = config[i]; - if (typeof prop === 'function') { - this[i] = prop; - } else { - this['_' + i] = prop; - } - } - }, + // TODO: enable moving while pinching? + var scale = this.pinch.scale * event.gesture.scale; + this._zoom(scale, pointer) +}; - _months : "January_February_March_April_May_June_July_August_September_October_November_December".split("_"), - months : function (m) { - return this._months[m.month()]; - }, +/** + * Zoom the graph in or out + * @param {Number} scale a number around 1, and between 0.01 and 10 + * @param {{x: Number, y: Number}} pointer + * @return {Number} appliedScale scale is limited within the boundaries + * @private + */ +Graph.prototype._zoom = function(scale, pointer) { + var scaleOld = this._getScale(); + if (scale < 0.01) { + scale = 0.01; + } + if (scale > 10) { + scale = 10; + } - _monthsShort : "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"), - monthsShort : function (m) { - return this._monthsShort[m.month()]; - }, + var translation = this._getTranslation(); + var scaleFrac = scale / scaleOld; + var tx = (1 - scaleFrac) * pointer.x + translation.x * scaleFrac; + var ty = (1 - scaleFrac) * pointer.y + translation.y * scaleFrac; - monthsParse : function (monthName) { - var i, mom, regex, output; + this._setScale(scale); + this._setTranslation(tx, ty); + this._redraw(); - if (!this._monthsParse) { - this._monthsParse = []; - } + return scale; +}; - for (i = 0; i < 12; i++) { - // make the regex if we don't have it already - if (!this._monthsParse[i]) { - mom = moment([2000, i]); - regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); - this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); - } - // test the regex - if (this._monthsParse[i].test(monthName)) { - return i; - } - } - }, +/** + * Event handler for mouse wheel event, used to zoom the timeline + * See http://adomas.org/javascript-mouse-wheel/ + * https://github.com/EightMedia/hammer.js/issues/256 + * @param {MouseEvent} event + * @private + */ +Graph.prototype._onMouseWheel = function(event) { + // retrieve delta + var delta = 0; + if (event.wheelDelta) { /* IE/Opera. */ + delta = event.wheelDelta/120; + } else if (event.detail) { /* Mozilla case. */ + // In Mozilla, sign of delta is different than in IE. + // Also, delta is multiple of 3. + delta = -event.detail/3; + } - _weekdays : "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), - weekdays : function (m) { - return this._weekdays[m.day()]; - }, + // If delta is nonzero, handle it. + // Basically, delta is now positive if wheel was scrolled up, + // and negative, if wheel was scrolled down. + if (delta) { + if (!('mouswheelScale' in this.pinch)) { + this.pinch.mouswheelScale = 1; + } - _weekdaysShort : "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"), - weekdaysShort : function (m) { - return this._weekdaysShort[m.day()]; - }, + // calculate the new scale + var scale = this.pinch.mouswheelScale; + var zoom = delta / 10; + if (delta < 0) { + zoom = zoom / (1 - zoom); + } + scale *= (1 + zoom); - _weekdaysMin : "Su_Mo_Tu_We_Th_Fr_Sa".split("_"), - weekdaysMin : function (m) { - return this._weekdaysMin[m.day()]; - }, + // calculate the pointer location + var gesture = Hammer.event.collectEventData(this, 'scroll', event); + var pointer = this._getPointer(gesture.center); - _longDateFormat : { - LT : "h:mm A", - L : "MM/DD/YYYY", - LL : "MMMM D YYYY", - LLL : "MMMM D YYYY LT", - LLLL : "dddd, MMMM D YYYY LT" - }, - longDateFormat : function (key) { - var output = this._longDateFormat[key]; - if (!output && this._longDateFormat[key.toUpperCase()]) { - output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) { - return val.slice(1); - }); - this._longDateFormat[key] = output; - } - return output; - }, + // apply the new scale + scale = this._zoom(scale, pointer); - meridiem : function (hours, minutes, isLower) { - if (hours > 11) { - return isLower ? 'pm' : 'PM'; - } else { - return isLower ? 'am' : 'AM'; - } - }, + // store the new, applied scale + this.pinch.mouswheelScale = scale; + } - _calendar : { - sameDay : '[Today at] LT', - nextDay : '[Tomorrow at] LT', - nextWeek : 'dddd [at] LT', - lastDay : '[Yesterday at] LT', - lastWeek : '[last] dddd [at] LT', - sameElse : 'L' - }, - calendar : function (key, mom) { - var output = this._calendar[key]; - return typeof output === 'function' ? output.apply(mom) : output; - }, + // Prevent default actions caused by mouse wheel. + event.preventDefault(); +}; - _relativeTime : { - future : "in %s", - past : "%s ago", - s : "a few seconds", - m : "a minute", - mm : "%d minutes", - h : "an hour", - hh : "%d hours", - d : "a day", - dd : "%d days", - M : "a month", - MM : "%d months", - y : "a year", - yy : "%d years" - }, - relativeTime : function (number, withoutSuffix, string, isFuture) { - var output = this._relativeTime[string]; - return (typeof output === 'function') ? - output(number, withoutSuffix, string, isFuture) : - output.replace(/%d/i, number); - }, - pastFuture : function (diff, output) { - var format = this._relativeTime[diff > 0 ? 'future' : 'past']; - return typeof format === 'function' ? format(output) : format.replace(/%s/i, output); - }, - ordinal : function (number) { - return this._ordinal.replace("%d", number); - }, - _ordinal : "%d", +/** + * Mouse move handler for checking whether the title moves over a node with a title. + * @param {Event} event + * @private + */ +Graph.prototype._onMouseMoveTitle = function (event) { + var gesture = Hammer.event.collectEventData(this, 'mousemove', event); + var pointer = this._getPointer(gesture.center); - preparse : function (string) { - return string; - }, + // check if the previously selected node is still selected + if (this.popupNode) { + this._checkHidePopup(pointer); + } - postformat : function (string) { - return string; - }, + // start a timeout that will check if the mouse is positioned above + // an element + var me = this; + var checkShow = function() { + me._checkShowPopup(pointer); + }; + if (this.popupTimer) { + clearInterval(this.popupTimer); // stop any running timer + } + if (!this.leftButtonDown) { + this.popupTimer = setTimeout(checkShow, 300); + } +}; - week : function (mom) { - return weekOfYear(mom, this._week.dow, this._week.doy); - }, - _week : { - dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. - } +/** + * Check if there is an element on the given position in the graph + * (a node or edge). If so, and if this element has a title, + * show a popup window with its title. + * + * @param {{x:Number, y:Number}} pointer + * @private + */ +Graph.prototype._checkShowPopup = function (pointer) { + var obj = { + left: this._canvasToX(pointer.x), + top: this._canvasToY(pointer.y), + right: this._canvasToX(pointer.x), + bottom: this._canvasToY(pointer.y) }; - // Loads a language definition into the `languages` cache. The function - // takes a key and optionally values. If not in the browser and no values - // are provided, it will load the language file module. As a convenience, - // this function also returns the language values. - function loadLang(key, values) { - values.abbr = key; - if (!languages[key]) { - languages[key] = new Language(); + var id; + var lastPopupNode = this.popupNode; + + if (this.popupNode == undefined) { + // search the nodes for overlap, select the top one in case of multiple nodes + var nodes = this.nodes; + for (id in nodes) { + if (nodes.hasOwnProperty(id)) { + var node = nodes[id]; + if (node.getTitle() != undefined && node.isOverlappingWith(obj)) { + this.popupNode = node; + break; + } + } } - languages[key].set(values); - return languages[key]; } - // Determines which language definition to use and returns it. - // - // With no parameters, it will return the global language. If you - // pass in a language key, such as 'en', it will return the - // definition for 'en', so long as 'en' has already been loaded using - // moment.lang. - function getLangDefinition(key) { - if (!key) { - return moment.fn._lang; - } - if (!languages[key] && hasModule) { - require('./lang/' + key); + if (this.popupNode == undefined) { + // search the edges for overlap + var edges = this.edges; + for (id in edges) { + if (edges.hasOwnProperty(id)) { + var edge = edges[id]; + if (edge.connected && (edge.getTitle() != undefined) && + edge.isOverlappingWith(obj)) { + this.popupNode = edge; + break; + } + } } - return languages[key]; } + if (this.popupNode) { + // show popup message window + if (this.popupNode != lastPopupNode) { + var me = this; + if (!me.popup) { + me.popup = new Popup(me.frame); + } - /************************************ - Formatting - ************************************/ - - - function removeFormattingTokens(input) { - if (input.match(/\[.*\]/)) { - return input.replace(/^\[|\]$/g, ""); + // adjust a small offset such that the mouse cursor is located in the + // bottom left location of the popup, and you can easily move over the + // popup area + me.popup.setPosition(pointer.x - 3, pointer.y - 3); + me.popup.setText(me.popupNode.getTitle()); + me.popup.show(); } - return input.replace(/\\/g, ""); } + else { + if (this.popup) { + this.popup.hide(); + } + } +}; - function makeFormatFunction(format) { - var array = format.match(formattingTokens), i, length; - - for (i = 0, length = array.length; i < length; i++) { - if (formatTokenFunctions[array[i]]) { - array[i] = formatTokenFunctions[array[i]]; - } else { - array[i] = removeFormattingTokens(array[i]); - } +/** + * Check if the popup must be hided, which is the case when the mouse is no + * longer hovering on the object + * @param {{x:Number, y:Number}} pointer + * @private + */ +Graph.prototype._checkHidePopup = function (pointer) { + if (!this.popupNode || !this._getNodeAt(pointer) ) { + this.popupNode = undefined; + if (this.popup) { + this.popup.hide(); } - - return function (mom) { - var output = ""; - for (i = 0; i < length; i++) { - output += typeof array[i].call === 'function' ? array[i].call(mom, format) : array[i]; - } - return output; - }; } +}; - // format date using native date object - function formatMoment(m, format) { - var i = 5; +/** + * Unselect selected nodes. If no selection array is provided, all nodes + * are unselected + * @param {Object[]} selection Array with selection objects, each selection + * object has a parameter row. Optional + * @param {Boolean} triggerSelect If true (default), the select event + * is triggered when nodes are unselected + * @return {Boolean} changed True if the selection is changed + * @private + */ +Graph.prototype._unselectNodes = function(selection, triggerSelect) { + var changed = false; + var i, iMax, id; - function replaceLongDateFormatTokens(input) { - return m.lang().longDateFormat(input) || input; - } + if (selection) { + // remove provided selections + for (i = 0, iMax = selection.length; i < iMax; i++) { + id = selection[i]; + this.nodes[id].unselect(); - while (i-- && localFormattingTokens.test(format)) { - format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); + var j = 0; + while (j < this.selection.length) { + if (this.selection[j] == id) { + this.selection.splice(j, 1); + changed = true; + } + else { + j++; + } + } } - - if (!formatFunctions[format]) { - formatFunctions[format] = makeFormatFunction(format); + } + else if (this.selection && this.selection.length) { + // remove all selections + for (i = 0, iMax = this.selection.length; i < iMax; i++) { + id = this.selection[i]; + this.nodes[id].unselect(); + changed = true; } + this.selection = []; + } - return formatFunctions[format](m); + if (changed && (triggerSelect == true || triggerSelect == undefined)) { + // fire the select event + this._trigger('select'); } + return changed; +}; - /************************************ - Parsing - ************************************/ +/** + * select all nodes on given location x, y + * @param {Array} selection an array with node ids + * @param {boolean} append If true, the new selection will be appended to the + * current selection (except for duplicate entries) + * @return {Boolean} changed True if the selection is changed + * @private + */ +Graph.prototype._selectNodes = function(selection, append) { + var changed = false; + var i, iMax; + // TODO: the selectNodes method is a little messy, rework this - // get the regex to find the next token - function getParseRegexForToken(token) { - switch (token) { - case 'DDDD': - return parseTokenThreeDigits; - case 'YYYY': - return parseTokenFourDigits; - case 'YYYYY': - return parseTokenSixDigits; - case 'S': - case 'SS': - case 'SSS': - case 'DDD': - return parseTokenOneToThreeDigits; - case 'MMM': - case 'MMMM': - case 'dd': - case 'ddd': - case 'dddd': - case 'a': - case 'A': - return parseTokenWord; - case 'X': - return parseTokenTimestampMs; - case 'Z': - case 'ZZ': - return parseTokenTimezone; - case 'T': - return parseTokenT; - case 'MM': - case 'DD': - case 'YY': - case 'HH': - case 'hh': - case 'mm': - case 'ss': - case 'M': - case 'D': - case 'd': - case 'H': - case 'h': - case 'm': - case 's': - return parseTokenOneOrTwoDigits; - default : - return new RegExp(token.replace('\\', '')); + // check if the current selection equals the desired selection + var selectionAlreadyThere = true; + if (selection.length != this.selection.length) { + selectionAlreadyThere = false; + } + else { + for (i = 0, iMax = Math.min(selection.length, this.selection.length); i < iMax; i++) { + if (selection[i] != this.selection[i]) { + selectionAlreadyThere = false; + break; + } } } + if (selectionAlreadyThere) { + return changed; + } - // function to convert string input to date - function addTimeToArrayFromToken(token, input, config) { - var a, b, - datePartArray = config._a; + if (append == undefined || append == false) { + // first deselect any selected node + var triggerSelect = false; + changed = this._unselectNodes(undefined, triggerSelect); + } - switch (token) { - // MONTH - case 'M' : // fall through to MM - case 'MM' : - datePartArray[1] = (input == null) ? 0 : ~~input - 1; - break; - case 'MMM' : // fall through to MMMM - case 'MMMM' : - a = getLangDefinition(config._l).monthsParse(input); - // if we didn't find a month name, mark the date as invalid. - if (a != null) { - datePartArray[1] = a; - } else { - config._isValid = false; - } - break; - // DAY OF MONTH - case 'D' : // fall through to DDDD - case 'DD' : // fall through to DDDD - case 'DDD' : // fall through to DDDD - case 'DDDD' : - if (input != null) { - datePartArray[2] = ~~input; - } - break; - // YEAR - case 'YY' : - datePartArray[0] = ~~input + (~~input > 68 ? 1900 : 2000); - break; - case 'YYYY' : - case 'YYYYY' : - datePartArray[0] = ~~input; - break; - // AM / PM - case 'a' : // fall through to A - case 'A' : - config._isPm = ((input + '').toLowerCase() === 'pm'); - break; - // 24 HOUR - case 'H' : // fall through to hh - case 'HH' : // fall through to hh - case 'h' : // fall through to hh - case 'hh' : - datePartArray[3] = ~~input; - break; - // MINUTE - case 'm' : // fall through to mm - case 'mm' : - datePartArray[4] = ~~input; - break; - // SECOND - case 's' : // fall through to ss - case 'ss' : - datePartArray[5] = ~~input; - break; - // MILLISECOND - case 'S' : - case 'SS' : - case 'SSS' : - datePartArray[6] = ~~ (('0.' + input) * 1000); - break; - // UNIX TIMESTAMP WITH MS - case 'X': - config._d = new Date(parseFloat(input) * 1000); - break; - // TIMEZONE - case 'Z' : // fall through to ZZ - case 'ZZ' : - config._useUTC = true; - a = (input + '').match(parseTimezoneChunker); - if (a && a[1]) { - config._tzh = ~~a[1]; - } - if (a && a[2]) { - config._tzm = ~~a[2]; - } - // reverse offsets - if (a && a[0] === '+') { - config._tzh = -config._tzh; - config._tzm = -config._tzm; - } - break; + for (i = 0, iMax = selection.length; i < iMax; i++) { + // add each of the new selections, but only when they are not duplicate + var id = selection[i]; + var isDuplicate = (this.selection.indexOf(id) != -1); + if (!isDuplicate) { + this.nodes[id].select(); + this.selection.push(id); + changed = true; } + } - // if the input is null, the date is not valid - if (input == null) { - config._isValid = false; - } + if (changed) { + // fire the select event + this._trigger('select'); } - // convert an array to a date. - // the array should mirror the parameters below - // note: all values past the year are optional and will default to the lowest possible value. - // [year, month, day , hour, minute, second, millisecond] - function dateFromArray(config) { - var i, date, input = []; + return changed; +}; - if (config._d) { - return; - } +/** + * retrieve all nodes overlapping with given object + * @param {Object} obj An object with parameters left, top, right, bottom + * @return {Number[]} An array with id's of the overlapping nodes + * @private + */ +Graph.prototype._getNodesOverlappingWith = function (obj) { + var nodes = this.nodes, + overlappingNodes = []; - for (i = 0; i < 7; i++) { - config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + if (nodes[id].isOverlappingWith(obj)) { + overlappingNodes.push(id); + } } + } + + return overlappingNodes; +}; - // add the offsets to the time to be parsed so that we can have a clean array for checking isValid - input[3] += config._tzh || 0; - input[4] += config._tzm || 0; +/** + * retrieve the currently selected nodes + * @return {Number[] | String[]} selection An array with the ids of the + * selected nodes. + */ +Graph.prototype.getSelection = function() { + return this.selection.concat([]); +}; - date = new Date(0); +/** + * select zero or more nodes + * @param {Number[] | String[]} selection An array with the ids of the + * selected nodes. + */ +Graph.prototype.setSelection = function(selection) { + var i, iMax, id; - if (config._useUTC) { - date.setUTCFullYear(input[0], input[1], input[2]); - date.setUTCHours(input[3], input[4], input[5], input[6]); - } else { - date.setFullYear(input[0], input[1], input[2]); - date.setHours(input[3], input[4], input[5], input[6]); - } + if (!selection || (selection.length == undefined)) + throw 'Selection must be an array with ids'; - config._d = date; + // first unselect any selected node + for (i = 0, iMax = this.selection.length; i < iMax; i++) { + id = this.selection[i]; + this.nodes[id].unselect(); } - // date from string and format string - function makeDateFromStringAndFormat(config) { - // This array is used to make a Date, either with `new Date` or `Date.UTC` - var tokens = config._f.match(formattingTokens), - string = config._i, - i, parsedInput; + this.selection = []; - config._a = []; + for (i = 0, iMax = selection.length; i < iMax; i++) { + id = selection[i]; - for (i = 0; i < tokens.length; i++) { - parsedInput = (getParseRegexForToken(tokens[i]).exec(string) || [])[0]; - if (parsedInput) { - string = string.slice(string.indexOf(parsedInput) + parsedInput.length); - } - // don't parse if its not a known token - if (formatTokenFunctions[tokens[i]]) { - addTimeToArrayFromToken(tokens[i], parsedInput, config); - } + var node = this.nodes[id]; + if (!node) { + throw new RangeError('Node with id "' + id + '" not found'); } - // handle am pm - if (config._isPm && config._a[3] < 12) { - config._a[3] += 12; + node.select(); + this.selection.push(id); + } + + this.redraw(); +}; + +/** + * Validate the selection: remove ids of nodes which no longer exist + * @private + */ +Graph.prototype._updateSelection = function () { + var i = 0; + while (i < this.selection.length) { + var id = this.selection[i]; + if (!this.nodes[id]) { + this.selection.splice(i, 1); } - // if is 12 am, change hours to 0 - if (config._isPm === false && config._a[3] === 12) { - config._a[3] = 0; + else { + i++; } - // return - dateFromArray(config); } +}; - // date from string and array of format strings - function makeDateFromStringAndArray(config) { - var tempConfig, - tempMoment, - bestMoment, +/** + * Temporary method to test calculating a hub value for the nodes + * @param {number} level Maximum number edges between two nodes in order + * to call them connected. Optional, 1 by default + * @return {Number[]} connectioncount array with the connection count + * for each node + * @private + */ +Graph.prototype._getConnectionCount = function(level) { + if (level == undefined) { + level = 1; + } - scoreToBeat = 99, - i, - currentDate, - currentScore; + // get the nodes connected to given nodes + function getConnectedNodes(nodes) { + var connectedNodes = []; - while (config._f.length) { - tempConfig = extend({}, config); - tempConfig._f = config._f.pop(); - makeDateFromStringAndFormat(tempConfig); - tempMoment = new Moment(tempConfig); + for (var j = 0, jMax = nodes.length; j < jMax; j++) { + var node = nodes[j]; - if (tempMoment.isValid()) { - bestMoment = tempMoment; - break; - } + // find all nodes connected to this node + var edges = node.edges; + for (var i = 0, iMax = edges.length; i < iMax; i++) { + var edge = edges[i]; + var other = null; - currentScore = compareArrays(tempConfig._a, tempMoment.toArray()); + // check if connected + if (edge.from == node) + other = edge.to; + else if (edge.to == node) + other = edge.from; - if (currentScore < scoreToBeat) { - scoreToBeat = currentScore; - bestMoment = tempMoment; + // check if the other node is not already in the list with nodes + var k, kMax; + if (other) { + for (k = 0, kMax = nodes.length; k < kMax; k++) { + if (nodes[k] == other) { + other = null; + break; + } + } + } + if (other) { + for (k = 0, kMax = connectedNodes.length; k < kMax; k++) { + if (connectedNodes[k] == other) { + other = null; + break; + } + } + } + + if (other) + connectedNodes.push(other); } } - extend(config, bestMoment); + return connectedNodes; } - // date from iso format - function makeDateFromString(config) { - var i, - string = config._i; - if (isoRegex.exec(string)) { - config._f = 'YYYY-MM-DDT'; - for (i = 0; i < 4; i++) { - if (isoTimes[i][1].exec(string)) { - config._f += isoTimes[i][0]; - break; - } - } - if (parseTokenTimezone.exec(string)) { - config._f += " Z"; + var connections = []; + var nodes = this.nodes; + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + var c = [nodes[id]]; + for (var l = 0; l < level; l++) { + c = c.concat(getConnectedNodes(c)); } - makeDateFromStringAndFormat(config); - } else { - config._d = new Date(string); + connections.push(c); } } - function makeDateFromInput(config) { - var input = config._i, - matched = aspNetJsonRegex.exec(input); - - if (input === undefined) { - config._d = new Date(); - } else if (matched) { - config._d = new Date(+matched[1]); - } else if (typeof input === 'string') { - makeDateFromString(config); - } else if (isArray(input)) { - config._a = input.slice(0); - dateFromArray(config); - } else { - config._d = input instanceof Date ? new Date(+input) : new Date(input); - } + var hubs = []; + for (var i = 0, len = connections.length; i < len; i++) { + hubs.push(connections[i].length); } + return hubs; +}; - /************************************ - Relative Time - ************************************/ - - - // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize - function substituteTimeAgo(string, number, withoutSuffix, isFuture, lang) { - return lang.relativeTime(number || 1, !!withoutSuffix, string, isFuture); - } - function relativeTime(milliseconds, withoutSuffix, lang) { - var seconds = round(Math.abs(milliseconds) / 1000), - minutes = round(seconds / 60), - hours = round(minutes / 60), - days = round(hours / 24), - years = round(days / 365), - args = seconds < 45 && ['s', seconds] || - minutes === 1 && ['m'] || - minutes < 45 && ['mm', minutes] || - hours === 1 && ['h'] || - hours < 22 && ['hh', hours] || - days === 1 && ['d'] || - days <= 25 && ['dd', days] || - days <= 45 && ['M'] || - days < 345 && ['MM', round(days / 30)] || - years === 1 && ['y'] || ['yy', years]; - args[2] = withoutSuffix; - args[3] = milliseconds > 0; - args[4] = lang; - return substituteTimeAgo.apply({}, args); - } +/** + * Set a new size for the graph + * @param {string} width Width in pixels or percentage (for example '800px' + * or '50%') + * @param {string} height Height in pixels or percentage (for example '400px' + * or '30%') + */ +Graph.prototype.setSize = function(width, height) { + this.frame.style.width = width; + this.frame.style.height = height; + this.frame.canvas.style.width = '100%'; + this.frame.canvas.style.height = '100%'; - /************************************ - Week of Year - ************************************/ + this.frame.canvas.width = this.frame.canvas.clientWidth; + this.frame.canvas.height = this.frame.canvas.clientHeight; +}; +/** + * Set a data set with nodes for the graph + * @param {Array | DataSet | DataView} nodes The data containing the nodes. + * @private + */ +Graph.prototype._setNodes = function(nodes) { + var oldNodesData = this.nodesData; - // firstDayOfWeek 0 = sun, 6 = sat - // the day of the week that starts the week - // (usually sunday or monday) - // firstDayOfWeekOfYear 0 = sun, 6 = sat - // the first week is the week that contains the first - // of this day of the week - // (eg. ISO weeks use thursday (4)) - function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { - var end = firstDayOfWeekOfYear - firstDayOfWeek, - daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(); + if (nodes instanceof DataSet || nodes instanceof DataView) { + this.nodesData = nodes; + } + else if (nodes instanceof Array) { + this.nodesData = new DataSet(); + this.nodesData.add(nodes); + } + else if (!nodes) { + this.nodesData = new DataSet(); + } + else { + throw new TypeError('Array or DataSet expected'); + } + if (oldNodesData) { + // unsubscribe from old dataset + util.forEach(this.nodesListeners, function (callback, event) { + oldNodesData.unsubscribe(event, callback); + }); + } - if (daysToDayOfWeek > end) { - daysToDayOfWeek -= 7; - } + // remove drawn nodes + this.nodes = {}; - if (daysToDayOfWeek < end - 7) { - daysToDayOfWeek += 7; - } + if (this.nodesData) { + // subscribe to new dataset + var me = this; + util.forEach(this.nodesListeners, function (callback, event) { + me.nodesData.subscribe(event, callback); + }); - return Math.ceil(moment(mom).add('d', daysToDayOfWeek).dayOfYear() / 7); + // draw all new nodes + var ids = this.nodesData.getIds(); + this._addNodes(ids); } + this._updateSelection(); +}; - /************************************ - Top Level Functions - ************************************/ +/** + * Add nodes + * @param {Number[] | String[]} ids + * @private + */ +Graph.prototype._addNodes = function(ids) { + var id; + for (var i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + var data = this.nodesData.get(id); + var node = new Node(data, this.images, this.groups, this.constants); + this.nodes[id] = node; // note: this may replace an existing node - function makeMoment(config) { - var input = config._i, - format = config._f; + if (!node.isFixed()) { + // TODO: position new nodes in a smarter way! + var radius = this.constants.edges.length * 2; + var count = ids.length; + var angle = 2 * Math.PI * (i / count); + node.x = radius * Math.cos(angle); + node.y = radius * Math.sin(angle); - if (input === null || input === '') { - return null; + // note: no not use node.isMoving() here, as that gives the current + // velocity of the node, which is zero after creation of the node. + this.moving = true; } + } - if (typeof input === 'string') { - config._i = input = getLangDefinition().preparse(input); + this._reconnectEdges(); + this._updateValueRange(this.nodes); +}; + +/** + * Update existing nodes, or create them when not yet existing + * @param {Number[] | String[]} ids + * @private + */ +Graph.prototype._updateNodes = function(ids) { + var nodes = this.nodes, + nodesData = this.nodesData; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + var node = nodes[id]; + var data = nodesData.get(id); + if (node) { + // update node + node.setProperties(data, this.constants); } + else { + // create node + node = new Node(properties, this.images, this.groups, this.constants); + nodes[id] = node; - if (moment.isMoment(input)) { - config = extend({}, input); - config._d = new Date(+input._d); - } else if (format) { - if (isArray(format)) { - makeDateFromStringAndArray(config); - } else { - makeDateFromStringAndFormat(config); + if (!node.isFixed()) { + this.moving = true; } - } else { - makeDateFromInput(config); } + } - return new Moment(config); + this._reconnectEdges(); + this._updateValueRange(nodes); +}; + +/** + * Remove existing nodes. If nodes do not exist, the method will just ignore it. + * @param {Number[] | String[]} ids + * @private + */ +Graph.prototype._removeNodes = function(ids) { + var nodes = this.nodes; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + delete nodes[id]; } - moment = function (input, format, lang) { - return makeMoment({ - _i : input, - _f : format, - _l : lang, - _isUTC : false + this._reconnectEdges(); + this._updateSelection(); + this._updateValueRange(nodes); +}; + +/** + * Load edges by reading the data table + * @param {Array | DataSet | DataView} edges The data containing the edges. + * @private + * @private + */ +Graph.prototype._setEdges = function(edges) { + var oldEdgesData = this.edgesData; + + if (edges instanceof DataSet || edges instanceof DataView) { + this.edgesData = edges; + } + else if (edges instanceof Array) { + this.edgesData = new DataSet(); + this.edgesData.add(edges); + } + else if (!edges) { + this.edgesData = new DataSet(); + } + else { + throw new TypeError('Array or DataSet expected'); + } + + if (oldEdgesData) { + // unsubscribe from old dataset + util.forEach(this.edgesListeners, function (callback, event) { + oldEdgesData.unsubscribe(event, callback); }); - }; + } - // creating with utc - moment.utc = function (input, format, lang) { - return makeMoment({ - _useUTC : true, - _isUTC : true, - _l : lang, - _i : input, - _f : format + // remove drawn edges + this.edges = {}; + + if (this.edgesData) { + // subscribe to new dataset + var me = this; + util.forEach(this.edgesListeners, function (callback, event) { + me.edgesData.subscribe(event, callback); }); - }; - // creating with unix timestamp (in seconds) - moment.unix = function (input) { - return moment(input * 1000); - }; + // draw all new nodes + var ids = this.edgesData.getIds(); + this._addEdges(ids); + } - // duration - moment.duration = function (input, key) { - var isDuration = moment.isDuration(input), - isNumber = (typeof input === 'number'), - duration = (isDuration ? input._data : (isNumber ? {} : input)), - ret; + this._reconnectEdges(); +}; - if (isNumber) { - if (key) { - duration[key] = input; - } else { - duration.milliseconds = input; - } +/** + * Add edges + * @param {Number[] | String[]} ids + * @private + */ +Graph.prototype._addEdges = function (ids) { + var edges = this.edges, + edgesData = this.edgesData; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + + var oldEdge = edges[id]; + if (oldEdge) { + oldEdge.disconnect(); } - ret = new Duration(duration); + var data = edgesData.get(id); + edges[id] = new Edge(data, this, this.constants); + } - if (isDuration && input.hasOwnProperty('_lang')) { - ret._lang = input._lang; - } + this.moving = true; + this._updateValueRange(edges); +}; - return ret; - }; +/** + * Update existing edges, or create them when not yet existing + * @param {Number[] | String[]} ids + * @private + */ +Graph.prototype._updateEdges = function (ids) { + var edges = this.edges, + edgesData = this.edgesData; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; - // version number - moment.version = VERSION; + var data = edgesData.get(id); + var edge = edges[id]; + if (edge) { + // update edge + edge.disconnect(); + edge.setProperties(data, this.constants); + edge.connect(); + } + else { + // create edge + edge = new Edge(data, this, this.constants); + this.edges[id] = edge; + } + } - // default format - moment.defaultFormat = isoFormat; + this.moving = true; + this._updateValueRange(edges); +}; + +/** + * Remove existing edges. Non existing ids will be ignored + * @param {Number[] | String[]} ids + * @private + */ +Graph.prototype._removeEdges = function (ids) { + var edges = this.edges; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + var edge = edges[id]; + if (edge) { + edge.disconnect(); + delete edges[id]; + } + } - // This function will load languages and then set the global language. If - // no arguments are passed in, it will simply return the current global - // language key. - moment.lang = function (key, values) { - var i; + this.moving = true; + this._updateValueRange(edges); +}; - if (!key) { - return moment.fn._lang._abbr; - } - if (values) { - loadLang(key, values); - } else if (!languages[key]) { - getLangDefinition(key); +/** + * Reconnect all edges + * @private + */ +Graph.prototype._reconnectEdges = function() { + var id, + nodes = this.nodes, + edges = this.edges; + for (id in nodes) { + if (nodes.hasOwnProperty(id)) { + nodes[id].edges = []; } - moment.duration.fn._lang = moment.fn._lang = getLangDefinition(key); - }; + } - // returns language data - moment.langData = function (key) { - if (key && key._lang && key._lang._abbr) { - key = key._lang._abbr; + for (id in edges) { + if (edges.hasOwnProperty(id)) { + var edge = edges[id]; + edge.from = null; + edge.to = null; + edge.connect(); } - return getLangDefinition(key); - }; - - // compare moment object - moment.isMoment = function (obj) { - return obj instanceof Moment; - }; - - // for typechecking Duration objects - moment.isDuration = function (obj) { - return obj instanceof Duration; - }; + } +}; +/** + * Update the values of all object in the given array according to the current + * value range of the objects in the array. + * @param {Object} obj An object containing a set of Edges or Nodes + * The objects must have a method getValue() and + * setValueRange(min, max). + * @private + */ +Graph.prototype._updateValueRange = function(obj) { + var id; - /************************************ - Moment Prototype - ************************************/ + // determine the range of the objects + var valueMin = undefined; + var valueMax = undefined; + for (id in obj) { + if (obj.hasOwnProperty(id)) { + var value = obj[id].getValue(); + if (value !== undefined) { + valueMin = (valueMin === undefined) ? value : Math.min(value, valueMin); + valueMax = (valueMax === undefined) ? value : Math.max(value, valueMax); + } + } + } + // adjust the range of all objects + if (valueMin !== undefined && valueMax !== undefined) { + for (id in obj) { + if (obj.hasOwnProperty(id)) { + obj[id].setValueRange(valueMin, valueMax); + } + } + } +}; - moment.fn = Moment.prototype = { +/** + * Redraw the graph with the current data + * chart will be resized too. + */ +Graph.prototype.redraw = function() { + this.setSize(this.width, this.height); - clone : function () { - return moment(this); - }, + this._redraw(); +}; - valueOf : function () { - return +this._d; - }, +/** + * Redraw the graph with the current data + * @private + */ +Graph.prototype._redraw = function() { + var ctx = this.frame.canvas.getContext('2d'); - unix : function () { - return Math.floor(+this._d / 1000); - }, + // clear the canvas + var w = this.frame.canvas.width; + var h = this.frame.canvas.height; + ctx.clearRect(0, 0, w, h); - toString : function () { - return this.format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ"); - }, + // set scaling and translation + ctx.save(); + ctx.translate(this.translation.x, this.translation.y); + ctx.scale(this.scale, this.scale); - toDate : function () { - return this._d; - }, + this._drawEdges(ctx); + this._drawNodes(ctx); - toJSON : function () { - return moment.utc(this).format('YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); - }, + // restore original scaling and translation + ctx.restore(); +}; - toArray : function () { - var m = this; - return [ - m.year(), - m.month(), - m.date(), - m.hours(), - m.minutes(), - m.seconds(), - m.milliseconds() - ]; - }, +/** + * Set the translation of the graph + * @param {Number} offsetX Horizontal offset + * @param {Number} offsetY Vertical offset + * @private + */ +Graph.prototype._setTranslation = function(offsetX, offsetY) { + if (this.translation === undefined) { + this.translation = { + x: 0, + y: 0 + }; + } - isValid : function () { - if (this._isValid == null) { - if (this._a) { - this._isValid = !compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()); - } else { - this._isValid = !isNaN(this._d.getTime()); - } - } - return !!this._isValid; - }, + if (offsetX !== undefined) { + this.translation.x = offsetX; + } + if (offsetY !== undefined) { + this.translation.y = offsetY; + } +}; - utc : function () { - this._isUTC = true; - return this; - }, +/** + * Get the translation of the graph + * @return {Object} translation An object with parameters x and y, both a number + * @private + */ +Graph.prototype._getTranslation = function() { + return { + x: this.translation.x, + y: this.translation.y + }; +}; - local : function () { - this._isUTC = false; - return this; - }, +/** + * Scale the graph + * @param {Number} scale Scaling factor 1.0 is unscaled + * @private + */ +Graph.prototype._setScale = function(scale) { + this.scale = scale; +}; +/** + * Get the current scale of the graph + * @return {Number} scale Scaling factor 1.0 is unscaled + * @private + */ +Graph.prototype._getScale = function() { + return this.scale; +}; - format : function (inputString) { - var output = formatMoment(this, inputString || moment.defaultFormat); - return this.lang().postformat(output); - }, +/** + * Convert a horizontal point on the HTML canvas to the x-value of the model + * @param {number} x + * @returns {number} + * @private + */ +Graph.prototype._canvasToX = function(x) { + return (x - this.translation.x) / this.scale; +}; - add : function (input, val) { - var dur; - // switch args to support add('s', 1) and add(1, 's') - if (typeof input === 'string') { - dur = moment.duration(+val, input); - } else { - dur = moment.duration(input, val); - } - addOrSubtractDurationFromMoment(this, dur, 1); - return this; - }, +/** + * Convert an x-value in the model to a horizontal point on the HTML canvas + * @param {number} x + * @returns {number} + * @private + */ +Graph.prototype._xToCanvas = function(x) { + return x * this.scale + this.translation.x; +}; - subtract : function (input, val) { - var dur; - // switch args to support subtract('s', 1) and subtract(1, 's') - if (typeof input === 'string') { - dur = moment.duration(+val, input); - } else { - dur = moment.duration(input, val); - } - addOrSubtractDurationFromMoment(this, dur, -1); - return this; - }, +/** + * Convert a vertical point on the HTML canvas to the y-value of the model + * @param {number} y + * @returns {number} + * @private + */ +Graph.prototype._canvasToY = function(y) { + return (y - this.translation.y) / this.scale; +}; - diff : function (input, units, asFloat) { - var that = this._isUTC ? moment(input).utc() : moment(input).local(), - zoneDiff = (this.zone() - that.zone()) * 6e4, - diff, output; +/** + * Convert an y-value in the model to a vertical point on the HTML canvas + * @param {number} y + * @returns {number} + * @private + */ +Graph.prototype._yToCanvas = function(y) { + return y * this.scale + this.translation.y ; +}; - if (units) { - // standardize on singular form - units = units.replace(/s$/, ''); +/** + * Redraw all nodes + * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); + * @param {CanvasRenderingContext2D} ctx + * @private + */ +Graph.prototype._drawNodes = function(ctx) { + // first draw the unselected nodes + var nodes = this.nodes; + var selected = []; + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + if (nodes[id].isSelected()) { + selected.push(id); } - - if (units === 'year' || units === 'month') { - diff = (this.daysInMonth() + that.daysInMonth()) * 432e5; // 24 * 60 * 60 * 1000 / 2 - output = ((this.year() - that.year()) * 12) + (this.month() - that.month()); - output += ((this - moment(this).startOf('month')) - (that - moment(that).startOf('month'))) / diff; - if (units === 'year') { - output = output / 12; - } - } else { - diff = (this - that) - zoneDiff; - output = units === 'second' ? diff / 1e3 : // 1000 - units === 'minute' ? diff / 6e4 : // 1000 * 60 - units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60 - units === 'day' ? diff / 864e5 : // 1000 * 60 * 60 * 24 - units === 'week' ? diff / 6048e5 : // 1000 * 60 * 60 * 24 * 7 - diff; + else { + nodes[id].draw(ctx); } - return asFloat ? output : absRound(output); - }, - - from : function (time, withoutSuffix) { - return moment.duration(this.diff(time)).lang(this.lang()._abbr).humanize(!withoutSuffix); - }, + } + } - fromNow : function (withoutSuffix) { - return this.from(moment(), withoutSuffix); - }, + // draw the selected nodes on top + for (var s = 0, sMax = selected.length; s < sMax; s++) { + nodes[selected[s]].draw(ctx); + } +}; - calendar : function () { - var diff = this.diff(moment().startOf('day'), 'days', true), - format = diff < -6 ? 'sameElse' : - diff < -1 ? 'lastWeek' : - diff < 0 ? 'lastDay' : - diff < 1 ? 'sameDay' : - diff < 2 ? 'nextDay' : - diff < 7 ? 'nextWeek' : 'sameElse'; - return this.format(this.lang().calendar(format, this)); - }, +/** + * Redraw all edges + * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); + * @param {CanvasRenderingContext2D} ctx + * @private + */ +Graph.prototype._drawEdges = function(ctx) { + var edges = this.edges; + for (var id in edges) { + if (edges.hasOwnProperty(id)) { + var edge = edges[id]; + if (edge.connected) { + edges[id].draw(ctx); + } + } + } +}; - isLeapYear : function () { - var year = this.year(); - return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; - }, +/** + * Find a stable position for all nodes + * @private + */ +Graph.prototype._doStabilize = function() { + var start = new Date(); - isDST : function () { - return (this.zone() < moment([this.year()]).zone() || - this.zone() < moment([this.year(), 5]).zone()); - }, + // find stable position + var count = 0; + var vmin = this.constants.minVelocity; + var stable = false; + while (!stable && count < this.constants.maxIterations) { + this._calculateForces(); + this._discreteStepNodes(); + stable = !this._isMoving(vmin); + count++; + } - day : function (input) { - var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); - return input == null ? day : - this.add({ d : input - day }); - }, + var end = new Date(); - startOf: function (units) { - units = units.replace(/s$/, ''); - // the following switch intentionally omits break keywords - // to utilize falling through the cases. - switch (units) { - case 'year': - this.month(0); - /* falls through */ - case 'month': - this.date(1); - /* falls through */ - case 'week': - case 'day': - this.hours(0); - /* falls through */ - case 'hour': - this.minutes(0); - /* falls through */ - case 'minute': - this.seconds(0); - /* falls through */ - case 'second': - this.milliseconds(0); - /* falls through */ - } + // console.log('Stabilized in ' + (end-start) + ' ms, ' + count + ' iterations' ); // TODO: cleanup +}; - // weeks are a special case - if (units === 'week') { - this.day(0); - } +/** + * Calculate the external forces acting on the nodes + * Forces are caused by: edges, repulsing forces between nodes, gravity + * @private + */ +Graph.prototype._calculateForces = function() { + // create a local edge to the nodes and edges, that is faster + var id, dx, dy, angle, distance, fx, fy, + repulsingForce, springForce, length, edgeLength, + nodes = this.nodes, + edges = this.edges; - return this; - }, + // gravity, add a small constant force to pull the nodes towards the center of + // the graph + // Also, the forces are reset to zero in this loop by using _setForce instead + // of _addForce + var gravity = 0.01, + gx = this.frame.canvas.clientWidth / 2, + gy = this.frame.canvas.clientHeight / 2; + for (id in nodes) { + if (nodes.hasOwnProperty(id)) { + var node = nodes[id]; + dx = gx - node.x; + dy = gy - node.y; + angle = Math.atan2(dy, dx); + fx = Math.cos(angle) * gravity; + fy = Math.sin(angle) * gravity; - endOf: function (units) { - return this.startOf(units).add(units.replace(/s?$/, 's'), 1).subtract('ms', 1); - }, + node._setForce(fx, fy); + } + } - isAfter: function (input, units) { - units = typeof units !== 'undefined' ? units : 'millisecond'; - return +this.clone().startOf(units) > +moment(input).startOf(units); - }, + // repulsing forces between nodes + var minimumDistance = this.constants.nodes.distance, + steepness = 10; // higher value gives steeper slope of the force around the given minimumDistance - isBefore: function (input, units) { - units = typeof units !== 'undefined' ? units : 'millisecond'; - return +this.clone().startOf(units) < +moment(input).startOf(units); - }, + for (var id1 in nodes) { + if (nodes.hasOwnProperty(id1)) { + var node1 = nodes[id1]; + for (var id2 in nodes) { + if (nodes.hasOwnProperty(id2)) { + var node2 = nodes[id2]; + // calculate normally distributed force + dx = node2.x - node1.x; + dy = node2.y - node1.y; + distance = Math.sqrt(dx * dx + dy * dy); + angle = Math.atan2(dy, dx); - isSame: function (input, units) { - units = typeof units !== 'undefined' ? units : 'millisecond'; - return +this.clone().startOf(units) === +moment(input).startOf(units); - }, + // TODO: correct factor for repulsing force + //repulsingForce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force + //repulsingForce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force + repulsingForce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)); // TODO: customize the repulsing force + fx = Math.cos(angle) * repulsingForce; + fy = Math.sin(angle) * repulsingForce; - zone : function () { - return this._isUTC ? 0 : this._d.getTimezoneOffset(); - }, + node1._addForce(-fx, -fy); + node2._addForce(fx, fy); + } + } + } + } - daysInMonth : function () { - return moment.utc([this.year(), this.month() + 1, 0]).date(); - }, + /* TODO: re-implement repulsion of edges + for (var n = 0; n < nodes.length; n++) { + for (var l = 0; l < edges.length; l++) { + var lx = edges[l].from.x+(edges[l].to.x - edges[l].from.x)/2, + ly = edges[l].from.y+(edges[l].to.y - edges[l].from.y)/2, - dayOfYear : function (input) { - var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1; - return input == null ? dayOfYear : this.add("d", (input - dayOfYear)); - }, + // calculate normally distributed force + dx = nodes[n].x - lx, + dy = nodes[n].y - ly, + distance = Math.sqrt(dx * dx + dy * dy), + angle = Math.atan2(dy, dx), - isoWeek : function (input) { - var week = weekOfYear(this, 1, 4); - return input == null ? week : this.add("d", (input - week) * 7); - }, - week : function (input) { - var week = this.lang().week(this); - return input == null ? week : this.add("d", (input - week) * 7); - }, + // TODO: correct factor for repulsing force + //var repulsingforce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force + //repulsingforce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ), // TODO: customize the repulsing force + repulsingforce = 1 / (1 + Math.exp((distance / (minimumDistance / 2) - 1) * steepness)), // TODO: customize the repulsing force + fx = Math.cos(angle) * repulsingforce, + fy = Math.sin(angle) * repulsingforce; + nodes[n]._addForce(fx, fy); + edges[l].from._addForce(-fx/2,-fy/2); + edges[l].to._addForce(-fx/2,-fy/2); + } + } + */ - // If passed a language key, it will set the language for this - // instance. Otherwise, it will return the language configuration - // variables for this instance. - lang : function (key) { - if (key === undefined) { - return this._lang; - } else { - this._lang = getLangDefinition(key); - return this; - } - } - }; + // forces caused by the edges, modelled as springs + for (id in edges) { + if (edges.hasOwnProperty(id)) { + var edge = edges[id]; + if (edge.connected) { + dx = (edge.to.x - edge.from.x); + dy = (edge.to.y - edge.from.y); + //edgeLength = (edge.from.width + edge.from.height + edge.to.width + edge.to.height)/2 || edge.length; // TODO: dmin + //edgeLength = (edge.from.width + edge.to.width)/2 || edge.length; // TODO: dmin + //edgeLength = 20 + ((edge.from.width + edge.to.width) || 0) / 2; + edgeLength = edge.length; + length = Math.sqrt(dx * dx + dy * dy); + angle = Math.atan2(dy, dx); - // helper for adding shortcuts - function makeGetterAndSetter(name, key) { - moment.fn[name] = moment.fn[name + 's'] = function (input) { - var utc = this._isUTC ? 'UTC' : ''; - if (input != null) { - this._d['set' + utc + key](input); - return this; - } else { - return this._d['get' + utc + key](); - } - }; - } + springForce = edge.stiffness * (edgeLength - length); - // loop through and add shortcuts (Month, Date, Hours, Minutes, Seconds, Milliseconds) - for (i = 0; i < proxyGettersAndSetters.length; i ++) { - makeGetterAndSetter(proxyGettersAndSetters[i].toLowerCase().replace(/s$/, ''), proxyGettersAndSetters[i]); + fx = Math.cos(angle) * springForce; + fy = Math.sin(angle) * springForce; + + edge.from._addForce(-fx, -fy); + edge.to._addForce(fx, fy); + } + } } - // add shortcut for year (uses different syntax than the getter/setter 'year' == 'FullYear') - makeGetterAndSetter('year', 'FullYear'); + /* TODO: re-implement repulsion of edges + // repulsing forces between edges + var minimumDistance = this.constants.edges.distance, + steepness = 10; // higher value gives steeper slope of the force around the given minimumDistance + for (var l = 0; l < edges.length; l++) { + //Keep distance from other edge centers + for (var l2 = l + 1; l2 < this.edges.length; l2++) { + //var dmin = (nodes[n].width + nodes[n].height + nodes[n2].width + nodes[n2].height) / 1 || minimumDistance, // TODO: dmin + //var dmin = (nodes[n].width + nodes[n2].width)/2 || minimumDistance, // TODO: dmin + //dmin = 40 + ((nodes[n].width/2 + nodes[n2].width/2) || 0), + var lx = edges[l].from.x+(edges[l].to.x - edges[l].from.x)/2, + ly = edges[l].from.y+(edges[l].to.y - edges[l].from.y)/2, + l2x = edges[l2].from.x+(edges[l2].to.x - edges[l2].from.x)/2, + l2y = edges[l2].from.y+(edges[l2].to.y - edges[l2].from.y)/2, - // add plural methods - moment.fn.days = moment.fn.day; - moment.fn.weeks = moment.fn.week; - moment.fn.isoWeeks = moment.fn.isoWeek; + // calculate normally distributed force + dx = l2x - lx, + dy = l2y - ly, + distance = Math.sqrt(dx * dx + dy * dy), + angle = Math.atan2(dy, dx), - /************************************ - Duration Prototype - ************************************/ + // TODO: correct factor for repulsing force + //var repulsingforce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force + //repulsingforce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ), // TODO: customize the repulsing force + repulsingforce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)), // TODO: customize the repulsing force + fx = Math.cos(angle) * repulsingforce, + fy = Math.sin(angle) * repulsingforce; - moment.duration.fn = Duration.prototype = { - weeks : function () { - return absRound(this.days() / 7); - }, + edges[l].from._addForce(-fx, -fy); + edges[l].to._addForce(-fx, -fy); + edges[l2].from._addForce(fx, fy); + edges[l2].to._addForce(fx, fy); + } + } + */ +}; - valueOf : function () { - return this._milliseconds + - this._days * 864e5 + - this._months * 2592e6; - }, - humanize : function (withSuffix) { - var difference = +this, - output = relativeTime(difference, !withSuffix, this.lang()); +/** + * Check if any of the nodes is still moving + * @param {number} vmin the minimum velocity considered as 'moving' + * @return {boolean} true if moving, false if non of the nodes is moving + * @private + */ +Graph.prototype._isMoving = function(vmin) { + // TODO: ismoving does not work well: should check the kinetic energy, not its velocity + var nodes = this.nodes; + for (var id in nodes) { + if (nodes.hasOwnProperty(id) && nodes[id].isMoving(vmin)) { + return true; + } + } + return false; +}; - if (withSuffix) { - output = this.lang().pastFuture(difference, output); - } - return this.lang().postformat(output); - }, +/** + * Perform one discrete step for all nodes + * @private + */ +Graph.prototype._discreteStepNodes = function() { + var interval = this.refreshRate / 1000.0; // in seconds + var nodes = this.nodes; + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + nodes[id].discreteStep(interval); + } + } +}; - lang : moment.fn.lang - }; +/** + * Start animating nodes and edges + */ +Graph.prototype.start = function() { + if (this.moving) { + this._calculateForces(); + this._discreteStepNodes(); - function makeDurationGetter(name) { - moment.duration.fn[name] = function () { - return this._data[name]; - }; + var vmin = this.constants.minVelocity; + this.moving = this._isMoving(vmin); } - function makeDurationAsGetter(name, factor) { - moment.duration.fn['as' + name] = function () { - return +this / factor; - }; + if (this.moving) { + // start animation. only start timer if it is not already running + if (!this.timer) { + var graph = this; + this.timer = window.setTimeout(function () { + graph.timer = undefined; + graph.start(); + graph._redraw(); + }, this.refreshRate); + } } + else { + this._redraw(); + } +}; - for (i in unitMillisecondFactors) { - if (unitMillisecondFactors.hasOwnProperty(i)) { - makeDurationAsGetter(i, unitMillisecondFactors[i]); - makeDurationGetter(i.toLowerCase()); - } +/** + * Stop animating nodes and edges. + */ +Graph.prototype.stop = function () { + if (this.timer) { + window.clearInterval(this.timer); + this.timer = undefined; } +}; - makeDurationAsGetter('Weeks', 6048e5); +/** + * vis.js module exports + */ +var vis = { + util: util, + events: events, + Controller: Controller, + DataSet: DataSet, + DataView: DataView, + Range: Range, + Stack: Stack, + TimeStep: TimeStep, + EventBus: EventBus, - /************************************ - Default Lang - ************************************/ + components: { + items: { + Item: Item, + ItemBox: ItemBox, + ItemPoint: ItemPoint, + ItemRange: ItemRange + }, + Component: Component, + Panel: Panel, + RootPanel: RootPanel, + ItemSet: ItemSet, + TimeAxis: TimeAxis + }, - // Set default language, other languages will inherit from English. - moment.lang('en', { - ordinal : function (number) { - var b = number % 10, - output = (~~ (number % 100 / 10) === 1) ? 'th' : - (b === 1) ? 'st' : - (b === 2) ? 'nd' : - (b === 3) ? 'rd' : 'th'; - return number + output; - } - }); + graph: { + Node: Node, + Edge: Edge, + Popup: Popup, + Groups: Groups, + Images: Images + }, + + Timeline: Timeline, + Graph: Graph +}; +/** + * CommonJS module exports + */ +if (typeof exports !== 'undefined') { + exports = vis; +} +if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { + module.exports = vis; +} - /************************************ - Exposing Moment - ************************************/ +/** + * AMD module exports + */ +if (typeof(define) === 'function') { + define(function () { + return vis; + }); +} +/** + * Window exports + */ +if (typeof window !== 'undefined') { + // attach the module to the window, load as a regular javascript file + window['vis'] = vis; +} - // CommonJS module is defined - if (hasModule) { - module.exports = moment; - } - /*global ender:false */ - if (typeof ender === 'undefined') { - // here, `this` means `window` in the browser, or `global` on the server - // add `moment` as a global object via a string identifier, - // for Closure Compiler "advanced" mode - this['moment'] = moment; - } - /*global define:false */ - if (typeof define === "function" && define.amd) { - define("moment", [], function () { - return moment; - }); - } -}).call(this); +// inject css +util.loadCss("/* vis.js stylesheet */\n.vis.timeline {\n}\n\n\n.vis.timeline.rootpanel {\n position: relative;\n overflow: hidden;\n\n border: 1px solid #bfbfbf;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n\n.vis.timeline .panel {\n position: absolute;\n overflow: hidden;\n}\n\n\n.vis.timeline .groupset {\n position: absolute;\n padding: 0;\n margin: 0;\n}\n\n.vis.timeline .labels {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n\n padding: 0;\n margin: 0;\n\n border-right: 1px solid #bfbfbf;\n box-sizing: border-box;\n -moz-box-sizing: border-box;\n}\n\n.vis.timeline .labels .label {\n position: absolute;\n left: 0;\n top: 0;\n width: 100%;\n border-bottom: 1px solid #bfbfbf;\n color: #4d4d4d;\n}\n\n.vis.timeline .labels .label .inner {\n display: inline-block;\n padding: 5px;\n}\n\n\n.vis.timeline .itemset {\n position: absolute;\n padding: 0;\n margin: 0;\n overflow: hidden;\n}\n\n.vis.timeline .background {\n}\n\n.vis.timeline .foreground {\n}\n\n.vis.timeline .itemset-axis {\n position: absolute;\n}\n\n.vis.timeline .groupset .itemset-axis {\n border-top: 1px solid #bfbfbf;\n}\n\n/* TODO: with orientation=='bottom', this will more or less overlap with timeline axis\n.vis.timeline .groupset .itemset-axis:last-child {\n border-top: none;\n}\n*/\n\n\n.vis.timeline .item {\n position: absolute;\n color: #1A1A1A;\n border-color: #97B0F8;\n background-color: #D5DDF6;\n display: inline-block;\n}\n\n.vis.timeline .item.selected {\n border-color: #FFC200;\n background-color: #FFF785;\n z-index: 999;\n}\n\n.vis.timeline .item.cluster {\n /* TODO: use another color or pattern? */\n background: #97B0F8 url('img/cluster_bg.png');\n color: white;\n}\n.vis.timeline .item.cluster.point {\n border-color: #D5DDF6;\n}\n\n.vis.timeline .item.box {\n text-align: center;\n border-style: solid;\n border-width: 1px;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.point {\n background: none;\n}\n\n.vis.timeline .dot {\n border: 5px solid #97B0F8;\n position: absolute;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.range {\n overflow: hidden;\n border-style: solid;\n border-width: 1px;\n border-radius: 2px;\n -moz-border-radius: 2px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.range .drag-left {\n cursor: w-resize;\n z-index: 1000;\n}\n\n.vis.timeline .item.range .drag-right {\n cursor: e-resize;\n z-index: 1000;\n}\n\n.vis.timeline .item.range .content {\n position: relative;\n display: inline-block;\n}\n\n.vis.timeline .item.line {\n position: absolute;\n width: 0;\n border-left-width: 1px;\n border-left-style: solid;\n}\n\n.vis.timeline .item .content {\n margin: 5px;\n white-space: nowrap;\n overflow: hidden;\n}\n\n.vis.timeline .axis {\n position: relative;\n}\n\n.vis.timeline .axis .text {\n position: absolute;\n color: #4d4d4d;\n padding: 3px;\n white-space: nowrap;\n}\n\n.vis.timeline .axis .text.measure {\n position: absolute;\n padding-left: 0;\n padding-right: 0;\n margin-left: 0;\n margin-right: 0;\n visibility: hidden;\n}\n\n.vis.timeline .axis .grid.vertical {\n position: absolute;\n width: 0;\n border-right: 1px solid;\n}\n\n.vis.timeline .axis .grid.horizontal {\n position: absolute;\n left: 0;\n width: 100%;\n height: 0;\n border-bottom: 1px solid;\n}\n\n.vis.timeline .axis .grid.minor {\n border-color: #e5e5e5;\n}\n\n.vis.timeline .axis .grid.major {\n border-color: #bfbfbf;\n}\n\n"); -})() -},{}]},{},[1])(1) +},{"hammerjs":1,"moment":2}]},{},[3]) +(3) }); ; \ No newline at end of file diff --git a/vis.min.js b/vis.min.js index 523f7179..3f3d76a8 100644 --- a/vis.min.js +++ b/vis.min.js @@ -4,8 +4,8 @@ * * A dynamic, browser-based visualization library. * - * @version 0.1.0 - * @date 2013-06-20 + * @version 0.2.0 + * @date 2013-09-20 * * @license * Copyright (C) 2011-2013 Almende B.V, http://almende.com @@ -22,8 +22,8 @@ * License for the specific language governing permissions and limitations under * the License. */ -(function(t){if("function"==typeof bootstrap)bootstrap("vis",t);else if("object"==typeof exports)module.exports=t();else if("function"==typeof define&&define.amd)define(t);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeVis=t}else"undefined"!=typeof window?window.vis=t():global.vis=t()})(function(){var t;return function(t,e,i){function s(i,o){if(!e[i]){if(!t[i]){var r="function"==typeof require&&require;if(!o&&r)return r(i,!0);if(n)return n(i,!0);throw Error("Cannot find module '"+i+"'")}var a=e[i]={exports:{}};t[i][0].call(a.exports,function(e){var n=t[i][1][e];return s(n?n:e)},a,a.exports)}return e[i].exports}for(var n="function"==typeof require&&require,o=0;i.length>o;o++)s(i[o]);return s}({1:[function(e,i,s){(function(){function n(){this.subscriptions=[]}function o(t){if(this.id=D.randomUUID(),this.options=t||{},this.data={},this.fieldId=this.options.fieldId||"id",this.convert={},this.options.convert)for(var e in this.options.convert)if(this.options.convert.hasOwnProperty(e)){var i=this.options.convert[e];this.convert[e]="Date"==i||"ISODate"==i||"ASPDate"==i?"Date":i}this.subscribers={},this.internalIds={}}function r(t,e){this.id=D.randomUUID(),this.data=null,this.ids={},this.options=e||{},this.fieldId="id",this.subscribers={};var i=this;this.listener=function(){i._onEvent.apply(i,arguments)},this.setData(t)}function a(t,e){this.parent=t,this.options=e||{},this.defaultOptions={order:function(t,e){if(t instanceof y){if(e instanceof y){var i=t.data.end-t.data.start,s=e.data.end-e.data.start;return i-s||t.data.start-e.data.start}return-1}return e instanceof y?1:t.data.start-e.data.start},margin:{item:10}},this.ordered=[]}function h(t){this.id=D.randomUUID(),this.start=0,this.end=0,this.options={min:null,max:null,zoomMin:null,zoomMax:null},this.listeners=[],this.setOptions(t)}function d(){this.id=D.randomUUID(),this.components={},this.repaintTimer=void 0,this.reflowTimer=void 0}function l(){this.id=null,this.parent=null,this.depends=null,this.controller=null,this.options=null,this.frame=null,this.top=0,this.left=0,this.width=0,this.height=0}function p(t,e,i){this.id=D.randomUUID(),this.parent=t,this.depends=e,this.options=i||{}}function c(t,e){this.id=D.randomUUID(),this.container=t,this.options=e||{},this.defaultOptions={autoResize:!0},this.listeners={}}function u(t,e,i){this.id=D.randomUUID(),this.parent=t,this.depends=e,this.dom={majorLines:[],majorTexts:[],minorLines:[],minorTexts:[],redundant:{majorLines:[],majorTexts:[],minorLines:[],minorTexts:[]}},this.props={range:{start:0,end:0,minimumStep:0},lineTop:0},this.options=i||{},this.defaultOptions={orientation:"bottom",showMinorLabels:!0,showMajorLabels:!0},this.conversion=null,this.range=null}function f(t,e,i){this.id=D.randomUUID(),this.parent=t,this.depends=e,this.options=i||{},this.defaultOptions={type:"box",align:"center",orientation:"bottom",margin:{axis:20,item:10},padding:5},this.dom={};var s=this;this.itemsData=null,this.range=null,this.listeners={add:function(t,e,i){i!=s.id&&s._onAdd(e.items)},update:function(t,e,i){i!=s.id&&s._onUpdate(e.items)},remove:function(t,e,i){i!=s.id&&s._onRemove(e.items)}},this.items={},this.queue={},this.stack=new a(this,Object.create(this.options)),this.conversion=null}function m(t,e,i,s){this.parent=t,this.data=e,this.dom=null,this.options=i||{},this.defaultOptions=s||{},this.selected=!1,this.visible=!1,this.top=0,this.left=0,this.width=0,this.height=0}function g(t,e,i,s){this.props={dot:{left:0,top:0,width:0,height:0},line:{top:0,left:0,width:0,height:0}},m.call(this,t,e,i,s)}function v(t,e,i,s){this.props={dot:{top:0,width:0,height:0},content:{height:0,marginLeft:0}},m.call(this,t,e,i,s)}function y(t,e,i,s){this.props={content:{left:0,width:0}},m.call(this,t,e,i,s)}function b(t,e,i){this.id=D.randomUUID(),this.parent=t,this.groupId=e,this.itemsData=null,this.itemset=null,this.options=i||{},this.options.top=0,this.props={label:{width:0,height:0}},this.top=0,this.left=0,this.width=0,this.height=0}function w(t,e,i){this.id=D.randomUUID(),this.parent=t,this.depends=e,this.options=i||{},this.range=null,this.itemsData=null,this.groupsData=null,this.groups={},this.dom={},this.props={labels:{width:0}},this.queue={};var s=this;this.listeners={add:function(t,e){s._onAdd(e.items)},update:function(t,e){s._onUpdate(e.items)},remove:function(t,e){s._onRemove(e.items)}}}function _(t,e,i){var s=this;if(this.options=D.extend({orientation:"bottom",min:null,max:null,zoomMin:10,zoomMax:31536e10,showMinorLabels:!0,showMajorLabels:!0,autoResize:!1},i),this.controller=new d,!t)throw Error("No container element provided");var n=Object.create(this.options);n.height=function(){return s.options.height?s.options.height:s.timeaxis.height+s.content.height},this.rootPanel=new c(t,n),this.controller.add(this.rootPanel);var o=Object.create(this.options);o.left=function(){return s.labelPanel.width},o.width=function(){return s.rootPanel.width-s.labelPanel.width},o.top=null,o.height=null,this.itemPanel=new p(this.rootPanel,[],o),this.controller.add(this.itemPanel);var r=Object.create(this.options);r.top=null,r.left=null,r.height=null,r.width=function(){return s.content&&"function"==typeof s.content.getLabelsWidth?s.content.getLabelsWidth():0},this.labelPanel=new p(this.rootPanel,[],r),this.controller.add(this.labelPanel);var a=E().hours(0).minutes(0).seconds(0).milliseconds(0);this.range=new h({start:a.clone().add("days",-3).valueOf(),end:a.clone().add("days",4).valueOf()}),this.range.subscribe(this.rootPanel,"move","horizontal"),this.range.subscribe(this.rootPanel,"zoom","horizontal"),this.range.on("rangechange",function(){var t=!0;s.controller.requestReflow(t)}),this.range.on("rangechanged",function(){var t=!0;s.controller.requestReflow(t)});var l=Object.create(n);l.range=this.range,l.left=null,l.top=null,l.width="100%",l.height=null,this.timeaxis=new u(this.itemPanel,[],l),this.timeaxis.setRange(this.range),this.controller.add(this.timeaxis),this.setGroups(null),this.itemsData=null,this.groupsData=null,e&&this.setItems(e)}function x(t,e,i,s){this.selected=!1,this.edges=[],this.group=s.nodes.group,this.fontSize=s.nodes.fontSize,this.fontFace=s.nodes.fontFace,this.fontColor=s.nodes.fontColor,this.color=s.nodes.color,this.id=void 0,this.shape=s.nodes.shape,this.image=s.nodes.image,this.x=0,this.y=0,this.xFixed=!1,this.yFixed=!1,this.radius=s.nodes.radius,this.radiusFixed=!1,this.radiusMin=s.nodes.radiusMin,this.radiusMax=s.nodes.radiusMax,this.imagelist=e,this.grouplist=i,this.setProperties(t,s),this.mass=50,this.fx=0,this.fy=0,this.vx=0,this.vy=0,this.minForce=s.minForce,this.damping=.9}function T(t,e,i){if(!e)throw"No graph provided";this.graph=e,this.widthMin=i.edges.widthMin,this.widthMax=i.edges.widthMax,this.id=void 0,this.fromId=void 0,this.toId=void 0,this.style=i.edges.style,this.title=void 0,this.width=i.edges.width,this.value=void 0,this.length=i.edges.length,this.from=null,this.to=null,this.connected=!1,this.dash=D.extend({},i.edges.dash),this.stiffness=void 0,this.color=i.edges.color,this.widthFixed=!1,this.lengthFixed=!1,this.setProperties(t,i)}function S(t,e,i,s){this.container=t?t:document.body,this.x=0,this.y=0,this.padding=5,void 0!==e&&void 0!==i&&this.setPosition(e,i),void 0!==s&&this.setText(s),this.frame=document.createElement("div");var n=this.frame.style;n.position="absolute",n.visibility="hidden",n.border="1px solid #666",n.color="black",n.padding=this.padding+"px",n.backgroundColor="#FFFFC6",n.borderRadius="3px",n.MozBorderRadius="3px",n.WebkitBorderRadius="3px",n.boxShadow="3px 3px 10px rgba(128, 128, 128, 0.5)",n.whiteSpace="nowrap",this.container.appendChild(this.frame)}function M(t,e,i){this.containerElement=t,this.width="100%",this.height="100%",this.refreshRate=50,this.stabilize=!0,this.selectable=!0,this.constants={nodes:{radiusMin:5,radiusMax:20,radius:5,distance:100,shape:"ellipse",image:void 0,widthMin:16,widthMax:64,fontColor:"black",fontSize:14,fontFace:"arial",color:{border:"#2B7CE9",background:"#97C2FC",highlight:{border:"#2B7CE9",background:"#D2E5FF"}},borderColor:"#2B7CE9",backgroundColor:"#97C2FC",highlightColor:"#D2E5FF",group:void 0},edges:{widthMin:1,widthMax:15,width:1,style:"line",color:"#343434",fontColor:"#343434",fontSize:14,fontFace:"arial",length:100,dash:{length:10,gap:5,altLength:void 0}},minForce:.05,minVelocity:.02,maxIterations:1e3};var s=this;this.nodes={},this.edges={},this.nodesData=null,this.edgesData=null;var n=this;this.nodesListeners={add:function(t,e){n._addNodes(e.items),n.start()},update:function(t,e){n._updateNodes(e.items),n.start()},remove:function(t,e){n._removeNodes(e.items),n.start()}},this.edgesListeners={add:function(t,e){n._addEdges(e.items),n.start()},update:function(t,e){n._updateEdges(e.items),n.start()},remove:function(t,e){n._removeEdges(e.items),n.start()}},this.groups=new Groups,this.images=new Images,this.images.setOnloadCallback(function(){s._redraw()}),this.moving=!1,this.selection=[],this.timer=void 0,this._create(),this.setOptions(i),this.setData(e)}var E=e("moment"),D={};D.isNumber=function(t){return t instanceof Number||"number"==typeof t},D.isString=function(t){return t instanceof String||"string"==typeof t},D.isDate=function(t){if(t instanceof Date)return!0;if(D.isString(t)){var e=C.exec(t);if(e)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},D.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},D.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},D.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var s=arguments[e];for(var n in s)s.hasOwnProperty(n)&&void 0!==s[n]&&(t[n]=s[n])}return t},D.convert=function(t,e){var i;if(void 0===t)return void 0;if(null===t)return null;if(!e)return t;if("string"!=typeof e&&!(e instanceof String))throw Error("Type must be a string");switch(e){case"boolean":case"Boolean":return Boolean(t);case"number":case"Number":return Number(t.valueOf());case"string":case"String":return t+"";case"Date":if(D.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(E.isMoment(t))return new Date(t.valueOf());if(D.isString(t))return i=C.exec(t),i?new Date(Number(i[1])):E(t).toDate();throw Error("Cannot convert object of type "+D.getType(t)+" to type Date");case"Moment":if(D.isNumber(t))return E(t);if(t instanceof Date)return E(t.valueOf());if(E.isMoment(t))return E.clone();if(D.isString(t))return i=C.exec(t),i?E(Number(i[1])):E(t);throw Error("Cannot convert object of type "+D.getType(t)+" to type Date");case"ISODate":if(D.isNumber(t))return new Date(t);if(t instanceof Date)return t.toISOString();if(E.isMoment(t))return t.toDate().toISOString();if(D.isString(t))return i=C.exec(t),i?new Date(Number(i[1])).toISOString():new Date(t).toISOString();throw Error("Cannot convert object of type "+D.getType(t)+" to type ISODate");case"ASPDate":if(D.isNumber(t))return"/Date("+t+")/";if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(D.isString(t)){i=C.exec(t);var s;return s=i?new Date(Number(i[1])).valueOf():new Date(t).valueOf(),"/Date("+s+")/"}throw Error("Cannot convert object of type "+D.getType(t)+" to type ASPDate");default:throw Error("Cannot convert object of type "+D.getType(t)+' to type "'+e+'"')}};var C=/^\/?Date\((\-?\d+)/i;if(D.getType=function(t){var e=typeof t;return"object"==e?null==t?"null":t instanceof Boolean?"Boolean":t instanceof Number?"Number":t instanceof String?"String":t instanceof Array?"Array":t instanceof Date?"Date":"Object":"number"==e?"Number":"boolean"==e?"Boolean":"string"==e?"String":e},D.getAbsoluteLeft=function(t){for(var e=document.documentElement,i=document.body,s=t.offsetLeft,n=t.offsetParent;null!=n&&n!=i&&n!=e;)s+=n.offsetLeft,s-=n.scrollLeft,n=n.offsetParent;return s},D.getAbsoluteTop=function(t){for(var e=document.documentElement,i=document.body,s=t.offsetTop,n=t.offsetParent;null!=n&&n!=i&&n!=e;)s+=n.offsetTop,s-=n.scrollTop,n=n.offsetParent;return s},D.getPageY=function(t){if("pageY"in t)return t.pageY;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientY:t.clientY;var i=document.documentElement,s=document.body;return e+(i&&i.scrollTop||s&&s.scrollTop||0)-(i&&i.clientTop||s&&s.clientTop||0)},D.getPageX=function(t){if("pageY"in t)return t.pageX;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientX:t.clientX;var i=document.documentElement,s=document.body;return e+(i&&i.scrollLeft||s&&s.scrollLeft||0)-(i&&i.clientLeft||s&&s.clientLeft||0)},D.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},D.removeClassName=function(t,e){var i=t.className.split(" "),s=i.indexOf(e);-1!=s&&(i.splice(s,1),t.className=i.join(" "))},D.forEach=function(t,e){var i,s;if(t instanceof Array)for(i=0,s=t.length;s>i;i++)e(t[i],i,t);else for(i in t)t.hasOwnProperty(i)&&e(t[i],i,t)},D.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},D.addEventListener=function(t,e,i,s){t.addEventListener?(void 0===s&&(s=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.addEventListener(e,i,s)):t.attachEvent("on"+e,i)},D.removeEventListener=function(t,e,i,s){t.removeEventListener?(void 0===s&&(s=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.removeEventListener(e,i,s)):t.detachEvent("on"+e,i)},D.getTarget=function(t){t||(t=window.event);var e;return t.target?e=t.target:t.srcElement&&(e=t.srcElement),void 0!=e.nodeType&&3==e.nodeType&&(e=e.parentNode),e},D.stopPropagation=function(t){t||(t=window.event),t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},D.preventDefault=function(t){t||(t=window.event),t.preventDefault?t.preventDefault():t.returnValue=!1},D.option={},D.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},D.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},D.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?t+"":e||null},D.option.asSize=function(t,e){return"function"==typeof t&&(t=t()),D.isString(t)?t:D.isNumber(t)?t+"px":e||null},D.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null},D.loadCss=function(t){if("undefined"!=typeof document){var e=document.createElement("style");e.type="text/css",e.styleSheet?e.styleSheet.cssText=t:e.appendChild(document.createTextNode(t)),document.getElementsByTagName("head")[0].appendChild(e)}},!Array.prototype.indexOf){Array.prototype.indexOf=function(t){for(var e=0;this.length>e;e++)if(this[e]==t)return e;return-1};try{console.log("Warning: Ancient browser detected. Please update your browser")}catch(L){}}Array.prototype.forEach||(Array.prototype.forEach=function(t,e){for(var i=0,s=this.length;s>i;++i)t.call(e||this,this[i],i,this)}),Array.prototype.map||(Array.prototype.map=function(t,e){var i,s,n;if(null==this)throw new TypeError(" this is null or not defined");var o=Object(this),r=o.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(e&&(i=e),s=Array(r),n=0;r>n;){var a,h;n in o&&(a=o[n],h=t.call(i,a,n,o),s[n]=h),n++}return s}),Array.prototype.filter||(Array.prototype.filter=function(t){"use strict";if(null==this)throw new TypeError;var e=Object(this),i=e.length>>>0;if("function"!=typeof t)throw new TypeError;for(var s=[],n=arguments[1],o=0;i>o;o++)if(o in e){var r=e[o];t.call(n,r,o,e)&&s.push(r)}return s}),Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,e=!{toString:null}.propertyIsEnumerable("toString"),i=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],s=i.length;return function(n){if("object"!=typeof n&&"function"!=typeof n||null===n)throw new TypeError("Object.keys called on non-object");var o=[];for(var r in n)t.call(n,r)&&o.push(r);if(e)for(var a=0;s>a;a++)t.call(n,i[a])&&o.push(i[a]);return o}}()),Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,s=function(){},n=function(){return i.apply(this instanceof s&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return s.prototype=this.prototype,n.prototype=new s,n}),Object.create||(Object.create=function(t){function e(){}if(arguments.length>1)throw Error("Object.create implementation only accepts the first parameter.");return e.prototype=t,new e});var O={listeners:[],indexOf:function(t){for(var e=this.listeners,i=0,s=this.listeners.length;s>i;i++){var n=e[i];if(n&&n.object==t)return i}return-1},addListener:function(t,e,i){var s=this.indexOf(t),n=this.listeners[s];n||(n={object:t,events:{}},this.listeners.push(n));var o=n.events[e];o||(o=[],n.events[e]=o),-1==o.indexOf(i)&&o.push(i)},removeListener:function(t,e,i){var s=this.indexOf(t),n=this.listeners[s];if(n){var o=n.events[e];o&&(s=o.indexOf(i),-1!=s&&o.splice(s,1),0==o.length&&delete n.events[e]);var r=0,a=n.events;for(var h in a)a.hasOwnProperty(h)&&r++;0==r&&delete this.listeners[s]}},removeAllListeners:function(){this.listeners=[]},trigger:function(t,e,i){var s=this.indexOf(t),n=this.listeners[s];if(n){var o=n.events[e];if(o)for(var r=0,a=o.length;a>r;r++)o[r](i)}}};n.prototype.on=function(t,e,i){var s=t instanceof RegExp?t:RegExp(t.replace("*","\\w+")),n={id:D.randomUUID(),event:t,regexp:s,callback:"function"==typeof e?e:null,target:i};return this.subscriptions.push(n),n.id},n.prototype.off=function(t){for(var e=0;this.subscriptions.length>e;){var i=this.subscriptions[e],s=!0;if(t instanceof Object)for(var n in t)t.hasOwnProperty(n)&&t[n]!==i[n]&&(s=!1);else s=i.id==t;s?this.subscriptions.splice(e,1):e++}},n.prototype.emit=function(t,e,i){for(var s=0;this.subscriptions.length>s;s++){var n=this.subscriptions[s];n.regexp.test(t)&&n.callback&&n.callback(t,e,i)}},o.prototype.subscribe=function(t,e){var i=this.subscribers[t];i||(i=[],this.subscribers[t]=i),i.push({callback:e})},o.prototype.unsubscribe=function(t,e){var i=this.subscribers[t];i&&(this.subscribers[t]=i.filter(function(t){return t.callback!=e}))},o.prototype._trigger=function(t,e,i){if("*"==t)throw Error("Cannot trigger event *");var s=[];t in this.subscribers&&(s=s.concat(this.subscribers[t])),"*"in this.subscribers&&(s=s.concat(this.subscribers["*"]));for(var n=0;s.length>n;n++){var o=s[n];o.callback&&o.callback(t,e,i||null)}},o.prototype.add=function(t,e){var i,s=[],n=this;if(t instanceof Array)for(var o=0,r=t.length;r>o;o++)i=n._addItem(t[o]),s.push(i);else if(D.isDataTable(t))for(var a=this._getColumnNames(t),h=0,d=t.getNumberOfRows();d>h;h++){for(var l={},p=0,c=a.length;c>p;p++){var u=a[p];l[u]=t.getValue(h,p)}i=n._addItem(l),s.push(i)}else{if(!(t instanceof Object))throw Error("Unknown dataType");i=n._addItem(t),s.push(i)}return s.length&&this._trigger("add",{items:s},e),s},o.prototype.update=function(t,e){var i=[],s=[],n=this,o=n.fieldId,r=function(t){var e=t[o];n.data[e]?(e=n._updateItem(t),s.push(e)):(e=n._addItem(t),i.push(e))};if(t instanceof Array)for(var a=0,h=t.length;h>a;a++)r(t[a]);else if(D.isDataTable(t))for(var d=this._getColumnNames(t),l=0,p=t.getNumberOfRows();p>l;l++){for(var c={},u=0,f=d.length;f>u;u++){var m=d[u];c[m]=t.getValue(l,u)}r(c)}else{if(!(t instanceof Object))throw Error("Unknown dataType");r(t)}return i.length&&this._trigger("add",{items:i},e),s.length&&this._trigger("update",{items:s},e),i.concat(s)},o.prototype.get=function(){var t,e,i,s,n=this,o=D.getType(arguments[0]);"String"==o||"Number"==o?(t=arguments[0],i=arguments[1],s=arguments[2]):"Array"==o?(e=arguments[0],i=arguments[1],s=arguments[2]):(i=arguments[0],s=arguments[1]);var r;if(i&&i.type){if(r="DataTable"==i.type?"DataTable":"Array",s&&r!=D.getType(s))throw Error('Type of parameter "data" ('+D.getType(s)+") "+"does not correspond with specified options.type ("+i.type+")");if("DataTable"==r&&!D.isDataTable(s))throw Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else r=s?"DataTable"==D.getType(s)?"DataTable":"Array":"Array";var a,h,d,l,p=i&&i.convert||this.options.convert,c=i&&i.filter,u=[];if(void 0!=t)a=n._getItem(t,p),c&&!c(a)&&(a=null);else if(void 0!=e)for(d=0,l=e.length;l>d;d++)a=n._getItem(e[d],p),(!c||c(a))&&u.push(a);else for(h in this.data)this.data.hasOwnProperty(h)&&(a=n._getItem(h,p),(!c||c(a))&&u.push(a));if(i&&i.order&&void 0==t&&this._sort(u,i.order),i&&i.fields){var f=i.fields;if(void 0!=t)a=this._filterFields(a,f);else for(d=0,l=u.length;l>d;d++)u[d]=this._filterFields(u[d],f)}if("DataTable"==r){var m=this._getColumnNames(s);if(void 0!=t)n._appendRow(s,m,a);else for(d=0,l=u.length;l>d;d++)n._appendRow(s,m,u[d]);return s}if(void 0!=t)return a;if(s){for(d=0,l=u.length;l>d;d++)s.push(u[d]);return s}return u},o.prototype.getIds=function(t){var e,i,s,n,o,r=this.data,a=t&&t.filter,h=t&&t.order,d=t&&t.convert||this.options.convert,l=[];if(a)if(h){o=[];for(s in r)r.hasOwnProperty(s)&&(n=this._getItem(s,d),a(n)&&o.push(n));for(this._sort(o,h),e=0,i=o.length;i>e;e++)l[e]=o[e][this.fieldId]}else for(s in r)r.hasOwnProperty(s)&&(n=this._getItem(s,d),a(n)&&l.push(n[this.fieldId]));else if(h){o=[];for(s in r)r.hasOwnProperty(s)&&o.push(r[s]);for(this._sort(o,h),e=0,i=o.length;i>e;e++)l[e]=o[e][this.fieldId]}else for(s in r)r.hasOwnProperty(s)&&(n=r[s],l.push(n[this.fieldId]));return l},o.prototype.forEach=function(t,e){var i,s,n=e&&e.filter,o=e&&e.convert||this.options.convert,r=this.data;if(e&&e.order)for(var a=this.get(e),h=0,d=a.length;d>h;h++)i=a[h],s=i[this.fieldId],t(i,s);else for(s in r)r.hasOwnProperty(s)&&(i=this._getItem(s,o),(!n||n(i))&&t(i,s))},o.prototype.map=function(t,e){var i,s=e&&e.filter,n=e&&e.convert||this.options.convert,o=[],r=this.data;for(var a in r)r.hasOwnProperty(a)&&(i=this._getItem(a,n),(!s||s(i))&&o.push(t(i,a)));return e&&e.order&&this._sort(o,e.order),o},o.prototype._filterFields=function(t,e){var i={};for(var s in t)t.hasOwnProperty(s)&&-1!=e.indexOf(s)&&(i[s]=t[s]);return i},o.prototype._sort=function(t,e){if(D.isString(e)){var i=e;t.sort(function(t,e){var s=t[i],n=e[i];return s>n?1:n>s?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},o.prototype.remove=function(t,e){var i,s,n,o=[];if(t instanceof Array)for(i=0,s=t.length;s>i;i++)n=this._remove(t[i]),null!=n&&o.push(n);else n=this._remove(t),null!=n&&o.push(n);return o.length&&this._trigger("remove",{items:o},e),o},o.prototype._remove=function(t){if(D.isNumber(t)||D.isString(t)){if(this.data[t])return delete this.data[t],delete this.internalIds[t],t}else if(t instanceof Object){var e=t[this.fieldId];if(e&&this.data[e])return delete this.data[e],delete this.internalIds[e],e}return null},o.prototype.clear=function(t){var e=Object.keys(this.data);return this.data={},this.internalIds={},this._trigger("remove",{items:e},t),e},o.prototype.max=function(t){var e=this.data,i=null,s=null;for(var n in e)if(e.hasOwnProperty(n)){var o=e[n],r=o[t];null!=r&&(!i||r>s)&&(i=o,s=r)}return i},o.prototype.min=function(t){var e=this.data,i=null,s=null;for(var n in e)if(e.hasOwnProperty(n)){var o=e[n],r=o[t];null!=r&&(!i||s>r)&&(i=o,s=r)}return i},o.prototype.distinct=function(t){var e=this.data,i=[],s=this.options.convert[t],n=0;for(var o in e)if(e.hasOwnProperty(o)){for(var r=e[o],a=D.convert(r[t],s),h=!1,d=0;n>d;d++)if(i[d]==a){h=!0;break}h||(i[n]=a,n++)}return i},o.prototype._addItem=function(t){var e=t[this.fieldId];if(void 0!=e){if(this.data[e])throw Error("Cannot add item: item with id "+e+" already exists")}else e=D.randomUUID(),t[this.fieldId]=e,this.internalIds[e]=t;var i={};for(var s in t)if(t.hasOwnProperty(s)){var n=this.convert[s];i[s]=D.convert(t[s],n)}return this.data[e]=i,e},o.prototype._getItem=function(t,e){var i,s,n=this.data[t];if(!n)return null;var o={},r=this.fieldId,a=this.internalIds;if(e)for(i in n)n.hasOwnProperty(i)&&(s=n[i],i==r&&s in a||(o[i]=D.convert(s,e[i])));else for(i in n)n.hasOwnProperty(i)&&(s=n[i],i==r&&s in a||(o[i]=s));return o},o.prototype._updateItem=function(t){var e=t[this.fieldId];if(void 0==e)throw Error("Cannot update item: item has no id (item: "+JSON.stringify(t)+")");var i=this.data[e];if(!i)throw Error("Cannot update item: no item with id "+e+" found");for(var s in t)if(t.hasOwnProperty(s)){var n=this.convert[s];i[s]=D.convert(t[s],n)}return e},o.prototype._getColumnNames=function(t){for(var e=[],i=0,s=t.getNumberOfColumns();s>i;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},o.prototype._appendRow=function(t,e,i){for(var s=t.addRow(),n=0,o=e.length;o>n;n++){var r=e[n];t.setValue(s,n,i[r])}},r.prototype.setData=function(t){var e,i,s;if(this.data){this.data.unsubscribe&&this.data.unsubscribe("*",this.listener),e=[];for(var n in this.ids)this.ids.hasOwnProperty(n)&&e.push(n);this.ids={},this._trigger("remove",{items:e})}if(this.data=t,this.data){for(this.fieldId=this.options.fieldId||this.data&&this.data.options&&this.data.options.fieldId||"id",e=this.data.getIds({filter:this.options&&this.options.filter}),i=0,s=e.length;s>i;i++)n=e[i],this.ids[n]=!0;this._trigger("add",{items:e}),this.data.subscribe&&this.data.subscribe("*",this.listener)}},r.prototype.get=function(){var t,e,i,s=this,n=D.getType(arguments[0]);"String"==n||"Number"==n||"Array"==n?(t=arguments[0],e=arguments[1],i=arguments[2]):(e=arguments[0],i=arguments[1]);var o=D.extend({},this.options,e);this.options.filter&&e&&e.filter&&(o.filter=function(t){return s.options.filter(t)&&e.filter(t)});var r=[];return void 0!=t&&r.push(t),r.push(o),r.push(i),this.data&&this.data.get.apply(this.data,r)},r.prototype.getIds=function(t){var e;if(this.data){var i,s=this.options.filter;i=t&&t.filter?s?function(e){return s(e)&&t.filter(e)}:t.filter:s,e=this.data.getIds({filter:i,order:t&&t.order})}else e=[];return e},r.prototype._onEvent=function(t,e,i){var s,n,o,r,a=e&&e.items,h=this.data,d=[],l=[],p=[];if(a&&h){switch(t){case"add":for(s=0,n=a.length;n>s;s++)o=a[s],r=this.get(o),r&&(this.ids[o]=!0,d.push(o));break;case"update":for(s=0,n=a.length;n>s;s++)o=a[s],r=this.get(o),r?this.ids[o]?l.push(o):(this.ids[o]=!0,d.push(o)):this.ids[o]&&(delete this.ids[o],p.push(o));break;case"remove":for(s=0,n=a.length;n>s;s++)o=a[s],this.ids[o]&&(delete this.ids[o],p.push(o))}d.length&&this._trigger("add",{items:d},i),l.length&&this._trigger("update",{items:l},i),p.length&&this._trigger("remove",{items:p},i)}},r.prototype.subscribe=o.prototype.subscribe,r.prototype.unsubscribe=o.prototype.unsubscribe,r.prototype._trigger=o.prototype._trigger,TimeStep=function(t,e,i){this.current=new Date,this._start=new Date,this._end=new Date,this.autoScale=!0,this.scale=TimeStep.SCALE.DAY,this.step=1,this.setRange(t,e,i)},TimeStep.SCALE={MILLISECOND:1,SECOND:2,MINUTE:3,HOUR:4,DAY:5,WEEKDAY:6,MONTH:7,YEAR:8},TimeStep.prototype.setRange=function(t,e,i){t instanceof Date&&e instanceof Date&&(this._start=void 0!=t?new Date(t.valueOf()):new Date,this._end=void 0!=e?new Date(e.valueOf()):new Date,this.autoScale&&this.setMinimumStep(i))},TimeStep.prototype.first=function(){this.current=new Date(this._start.valueOf()),this.roundToMinor()},TimeStep.prototype.roundToMinor=function(){switch(this.scale){case TimeStep.SCALE.YEAR:this.current.setFullYear(this.step*Math.floor(this.current.getFullYear()/this.step)),this.current.setMonth(0);case TimeStep.SCALE.MONTH:this.current.setDate(1);case TimeStep.SCALE.DAY:case TimeStep.SCALE.WEEKDAY:this.current.setHours(0);case TimeStep.SCALE.HOUR:this.current.setMinutes(0);case TimeStep.SCALE.MINUTE:this.current.setSeconds(0);case TimeStep.SCALE.SECOND:this.current.setMilliseconds(0)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.setMilliseconds(this.current.getMilliseconds()-this.current.getMilliseconds()%this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()-this.current.getSeconds()%this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()-this.current.getMinutes()%this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()-this.current.getHours()%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()-1-(this.current.getDate()-1)%this.step+1);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()-this.current.getMonth()%this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()-this.current.getFullYear()%this.step);break;default:}},TimeStep.prototype.hasNext=function(){return this.current.valueOf()<=this._end.valueOf()},TimeStep.prototype.next=function(){var t=this.current.valueOf();if(6>this.current.getMonth())switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current=new Date(this.current.valueOf()+1e3*this.step);break;case TimeStep.SCALE.MINUTE:this.current=new Date(this.current.valueOf()+60*1e3*this.step);break;case TimeStep.SCALE.HOUR:this.current=new Date(this.current.valueOf()+60*60*1e3*this.step);var e=this.current.getHours();this.current.setHours(e-e%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step);break;default:}else switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()+this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()+this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()+this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step);break;default:}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.getMilliseconds()0&&(this.step=e),this.autoScale=!1},TimeStep.prototype.setAutoScale=function(t){this.autoScale=t},TimeStep.prototype.setMinimumStep=function(t){if(void 0!=t){var e=31104e6,i=2592e6,s=864e5,n=36e5,o=6e4,r=1e3,a=1;1e3*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1e3),500*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=500),100*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=100),50*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=50),10*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=10),5*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=5),e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1),3*i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=3),i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=1),5*s>t&&(this.scale=TimeStep.SCALE.DAY,this.step=5),2*s>t&&(this.scale=TimeStep.SCALE.DAY,this.step=2),s>t&&(this.scale=TimeStep.SCALE.DAY,this.step=1),s/2>t&&(this.scale=TimeStep.SCALE.WEEKDAY,this.step=1),4*n>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=4),n>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=1),15*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=15),10*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=10),5*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=5),o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=1),15*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=15),10*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=10),5*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=5),r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=1),200*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=200),100*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=100),50*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=50),10*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=10),5*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=5),a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=1) -}},TimeStep.prototype.snap=function(t){if(this.scale==TimeStep.SCALE.YEAR){var e=t.getFullYear()+Math.round(t.getMonth()/12);t.setFullYear(Math.round(e/this.step)*this.step),t.setMonth(0),t.setDate(0),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MONTH)t.getDate()>15?(t.setDate(1),t.setMonth(t.getMonth()+1)):t.setDate(1),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0);else if(this.scale==TimeStep.SCALE.DAY||this.scale==TimeStep.SCALE.WEEKDAY){switch(this.step){case 5:case 2:t.setHours(24*Math.round(t.getHours()/24));break;default:t.setHours(12*Math.round(t.getHours()/12))}t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.HOUR){switch(this.step){case 4:t.setMinutes(60*Math.round(t.getMinutes()/60));break;default:t.setMinutes(30*Math.round(t.getMinutes()/30))}t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MINUTE){switch(this.step){case 15:case 10:t.setMinutes(5*Math.round(t.getMinutes()/5)),t.setSeconds(0);break;case 5:t.setSeconds(60*Math.round(t.getSeconds()/60));break;default:t.setSeconds(30*Math.round(t.getSeconds()/30))}t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.SECOND)switch(this.step){case 15:case 10:t.setSeconds(5*Math.round(t.getSeconds()/5)),t.setMilliseconds(0);break;case 5:t.setMilliseconds(1e3*Math.round(t.getMilliseconds()/1e3));break;default:t.setMilliseconds(500*Math.round(t.getMilliseconds()/500))}else if(this.scale==TimeStep.SCALE.MILLISECOND){var i=this.step>5?this.step/2:1;t.setMilliseconds(Math.round(t.getMilliseconds()/i)*i)}},TimeStep.prototype.isMajor=function(){switch(this.scale){case TimeStep.SCALE.MILLISECOND:return 0==this.current.getMilliseconds();case TimeStep.SCALE.SECOND:return 0==this.current.getSeconds();case TimeStep.SCALE.MINUTE:return 0==this.current.getHours()&&0==this.current.getMinutes();case TimeStep.SCALE.HOUR:return 0==this.current.getHours();case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return 1==this.current.getDate();case TimeStep.SCALE.MONTH:return 0==this.current.getMonth();case TimeStep.SCALE.YEAR:return!1;default:return!1}},TimeStep.prototype.getLabelMinor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return E(t).format("SSS");case TimeStep.SCALE.SECOND:return E(t).format("s");case TimeStep.SCALE.MINUTE:return E(t).format("HH:mm");case TimeStep.SCALE.HOUR:return E(t).format("HH:mm");case TimeStep.SCALE.WEEKDAY:return E(t).format("ddd D");case TimeStep.SCALE.DAY:return E(t).format("D");case TimeStep.SCALE.MONTH:return E(t).format("MMM");case TimeStep.SCALE.YEAR:return E(t).format("YYYY");default:return""}},TimeStep.prototype.getLabelMajor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return E(t).format("HH:mm:ss");case TimeStep.SCALE.SECOND:return E(t).format("D MMMM HH:mm");case TimeStep.SCALE.MINUTE:case TimeStep.SCALE.HOUR:return E(t).format("ddd D MMMM");case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return E(t).format("MMMM YYYY");case TimeStep.SCALE.MONTH:return E(t).format("YYYY");case TimeStep.SCALE.YEAR:return"";default:return""}},a.prototype.setOptions=function(t){D.extend(this.options,t)},a.prototype.update=function(){this._order(),this._stack()},a.prototype._order=function(){var t=this.parent.items;if(!t)throw Error("Cannot stack items: parent does not contain items");var e=[],i=0;D.forEach(t,function(t){t.visible&&(e[i]=t,i++)});var s=this.options.order||this.defaultOptions.order;if("function"!=typeof s)throw Error("Option order must be a function");e.sort(s),this.ordered=e},a.prototype._stack=function(){var t,e,i,s=this.ordered,n=this.options,o=n.orientation||this.defaultOptions.orientation,r="top"==o;for(i=n.margin&&void 0!==n.margin.item?n.margin.item:this.defaultOptions.margin.item,t=0,e=s.length;e>t;t++){var a=s[t],h=null;do h=this.checkOverlap(s,t,0,t-1,i),null!=h&&(a.top=r?h.top+h.height+i:h.top-a.height-i);while(h)}},a.prototype.checkOverlap=function(t,e,i,s,n){for(var o=this.collision,r=t[e],a=s;a>=i;a--){var h=t[a];if(o(r,h,n)&&a!=e)return h}return null},a.prototype.collision=function(t,e,i){return t.left-ie.left&&t.top-ie.top},h.prototype.setOptions=function(t){D.extend(this.options,t),(null!=t.start||null!=t.end)&&this.setRange(t.start,t.end)},h.prototype.subscribe=function(t,e,i){var s,n=this;if("horizontal"!=i&&"vertical"!=i)throw new TypeError('Unknown direction "'+i+'". '+'Choose "horizontal" or "vertical".');if("move"==e)s={component:t,event:e,direction:i,callback:function(t){n._onMouseDown(t,s)},params:{}},t.on("mousedown",s.callback),n.listeners.push(s);else{if("zoom"!=e)throw new TypeError('Unknown event "'+e+'". '+'Choose "move" or "zoom".');s={component:t,event:e,direction:i,callback:function(t){n._onMouseWheel(t,s)},params:{}},t.on("mousewheel",s.callback),n.listeners.push(s)}},h.prototype.on=function(t,e){O.addListener(this,t,e)},h.prototype._trigger=function(t){O.trigger(this,t,{start:this.start,end:this.end})},h.prototype.setRange=function(t,e){var i=this._applyRange(t,e);i&&(this._trigger("rangechange"),this._trigger("rangechanged"))},h.prototype._applyRange=function(t,e){var i,s=null!=t?D.convert(t,"Number"):this.start,n=null!=e?D.convert(e,"Number"):this.end;if(isNaN(s))throw Error('Invalid start "'+t+'"');if(isNaN(n))throw Error('Invalid end "'+e+'"');if(s>n&&(n=s),null!=this.options.min){var o=this.options.min.valueOf();o>s&&(i=o-s,s+=i,n+=i)}if(null!=this.options.max){var r=this.options.max.valueOf();n>r&&(i=n-r,s-=i,n-=i)}if(null!=this.options.zoomMin){var a=this.options.zoomMin.valueOf();0>a&&(a=0),a>n-s&&(this.end-this.start>a?(i=a-(n-s),s-=i/2,n+=i/2):(s=this.start,n=this.end))}if(null!=this.options.zoomMax){var h=this.options.zoomMax.valueOf();0>h&&(h=0),n-s>h&&(h>this.end-this.start?(i=n-s-h,s+=i/2,n-=i/2):(s=this.start,n=this.end))}var d=this.start!=s||this.end!=n;return this.start=s,this.end=n,d},h.prototype.getRange=function(){return{start:this.start,end:this.end}},h.prototype.conversion=function(t){return this.start,this.end,h.conversion(this.start,this.end,t)},h.conversion=function(t,e,i){return 0!=i&&0!=e-t?{offset:t,factor:i/(e-t)}:{offset:0,factor:1}},h.prototype._onMouseDown=function(t,e){t=t||window.event;var i=e.params,s=t.which?1==t.which:1==t.button;if(s){i.mouseX=D.getPageX(t),i.mouseY=D.getPageY(t),i.previousLeft=0,i.previousOffset=0,i.moved=!1,i.start=this.start,i.end=this.end;var n=e.component.frame;n&&(n.style.cursor="move");var o=this;i.onMouseMove||(i.onMouseMove=function(t){o._onMouseMove(t,e)},D.addEventListener(document,"mousemove",i.onMouseMove)),i.onMouseUp||(i.onMouseUp=function(t){o._onMouseUp(t,e)},D.addEventListener(document,"mouseup",i.onMouseUp)),D.preventDefault(t)}},h.prototype._onMouseMove=function(t,e){t=t||window.event;var i=e.params,s=D.getPageX(t),n=D.getPageY(t);void 0==i.mouseX&&(i.mouseX=s),void 0==i.mouseY&&(i.mouseY=n);var o=s-i.mouseX,r=n-i.mouseY,a="horizontal"==e.direction?o:r;Math.abs(a)>=1&&(i.moved=!0);var h=i.end-i.start,d="horizontal"==e.direction?e.component.width:e.component.height,l=-a/d*h;this._applyRange(i.start+l,i.end+l),this._trigger("rangechange"),D.preventDefault(t)},h.prototype._onMouseUp=function(t,e){t=t||window.event;var i=e.params;e.component.frame&&(e.component.frame.style.cursor="auto"),i.onMouseMove&&(D.removeEventListener(document,"mousemove",i.onMouseMove),i.onMouseMove=null),i.onMouseUp&&(D.removeEventListener(document,"mouseup",i.onMouseUp),i.onMouseUp=null),i.moved&&this._trigger("rangechanged")},h.prototype._onMouseWheel=function(t,e){t=t||window.event;var i=0;if(t.wheelDelta?i=t.wheelDelta/120:t.detail&&(i=-t.detail/3),i){var s=this,n=function(){var n=i/5,o=null,r=e.component.frame;if(r){var a,h;if("horizontal"==e.direction){a=e.component.width,h=s.conversion(a);var d=D.getAbsoluteLeft(r),l=D.getPageX(t);o=(l-d)/h.factor+h.offset}else{a=e.component.height,h=s.conversion(a);var p=D.getAbsoluteTop(r),c=D.getPageY(t);o=(p+a-c-p)/h.factor+h.offset}}s.zoom(n,o)};n()}D.preventDefault(t)},h.prototype.zoom=function(t,e){null==e&&(e=(this.start+this.end)/2),t>=1&&(t=.9),-1>=t&&(t=-.9),0>t&&(t/=1+t);var i=this.start-e,s=this.end-e,n=this.start-i*t,o=this.end-s*t;this.setRange(n,o)},h.prototype.move=function(t){var e=this.end-this.start,i=this.start+e*t,s=this.end+e*t;this.start=i,this.end=s},d.prototype.add=function(t){if(void 0==t.id)throw Error("Component has no field id");if(!(t instanceof l||t instanceof d))throw new TypeError("Component must be an instance of prototype Component or Controller");t.controller=this,this.components[t.id]=t},d.prototype.remove=function(t){var e;for(e in this.components)if(this.components.hasOwnProperty(e)&&(e==t||this.components[e]==t))break;e&&delete this.components[e]},d.prototype.requestReflow=function(t){if(t)this.reflow();else if(!this.reflowTimer){var e=this;this.reflowTimer=setTimeout(function(){e.reflowTimer=void 0,e.reflow()},0)}},d.prototype.requestRepaint=function(t){if(t)this.repaint();else if(!this.repaintTimer){var e=this;this.repaintTimer=setTimeout(function(){e.repaintTimer=void 0,e.repaint()},0)}},d.prototype.repaint=function(){function t(s,n){n in i||(s.depends&&s.depends.forEach(function(e){t(e,e.id)}),s.parent&&t(s.parent,s.parent.id),e=s.repaint()||e,i[n]=!0)}var e=!1;this.repaintTimer&&(clearTimeout(this.repaintTimer),this.repaintTimer=void 0);var i={};D.forEach(this.components,t),e&&this.reflow()},d.prototype.reflow=function(){function t(s,n){n in i||(s.depends&&s.depends.forEach(function(e){t(e,e.id)}),s.parent&&t(s.parent,s.parent.id),e=s.reflow()||e,i[n]=!0)}var e=!1;this.reflowTimer&&(clearTimeout(this.reflowTimer),this.reflowTimer=void 0);var i={};D.forEach(this.components,t),e&&this.repaint()},l.prototype.setOptions=function(t){t&&(D.extend(this.options,t),this.controller&&(this.requestRepaint(),this.requestReflow()))},l.prototype.getOption=function(t){var e;return this.options&&(e=this.options[t]),void 0===e&&this.defaultOptions&&(e=this.defaultOptions[t]),e},l.prototype.getContainer=function(){return null},l.prototype.getFrame=function(){return this.frame},l.prototype.repaint=function(){return!1},l.prototype.reflow=function(){return!1},l.prototype.hide=function(){return this.frame&&this.frame.parentNode?(this.frame.parentNode.removeChild(this.frame),!0):!1},l.prototype.show=function(){return this.frame&&this.frame.parentNode?!1:this.repaint()},l.prototype.requestRepaint=function(){if(!this.controller)throw Error("Cannot request a repaint: no controller configured");this.controller.requestRepaint()},l.prototype.requestReflow=function(){if(!this.controller)throw Error("Cannot request a reflow: no controller configured");this.controller.requestReflow()},p.prototype=new l,p.prototype.setOptions=l.prototype.setOptions,p.prototype.getContainer=function(){return this.frame},p.prototype.repaint=function(){var t=0,e=D.updateProperty,i=D.option.asSize,s=this.options,n=this.frame;if(!n){n=document.createElement("div"),n.className="panel";var o=s.className;o&&("function"==typeof o?D.addClassName(n,o()+""):D.addClassName(n,o+"")),this.frame=n,t+=1}if(!n.parentNode){if(!this.parent)throw Error("Cannot repaint panel: no parent attached");var r=this.parent.getContainer();if(!r)throw Error("Cannot repaint panel: parent has no container element");r.appendChild(n),t+=1}return t+=e(n.style,"top",i(s.top,"0px")),t+=e(n.style,"left",i(s.left,"0px")),t+=e(n.style,"width",i(s.width,"100%")),t+=e(n.style,"height",i(s.height,"100%")),t>0},p.prototype.reflow=function(){var t=0,e=D.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},c.prototype=new p,c.prototype.setOptions=l.prototype.setOptions,c.prototype.repaint=function(){var t=0,e=D.updateProperty,i=D.option.asSize,s=this.options,n=this.frame;if(!n){n=document.createElement("div"),n.className="vis timeline rootpanel";var o=s.className;o&&D.addClassName(n,D.option.asString(o)),this.frame=n,t+=1}if(!n.parentNode){if(!this.container)throw Error("Cannot repaint root panel: no container attached");this.container.appendChild(n),t+=1}return t+=e(n.style,"top",i(s.top,"0px")),t+=e(n.style,"left",i(s.left,"0px")),t+=e(n.style,"width",i(s.width,"100%")),t+=e(n.style,"height",i(s.height,"100%")),this._updateEventEmitters(),this._updateWatch(),t>0},c.prototype.reflow=function(){var t=0,e=D.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},c.prototype._updateWatch=function(){var t=this.getOption("autoResize");t?this._watch():this._unwatch()},c.prototype._watch=function(){var t=this;this._unwatch();var e=function(){var e=t.getOption("autoResize");return e?(t.frame&&(t.frame.clientWidth!=t.width||t.frame.clientHeight!=t.height)&&t.requestReflow(),void 0):(t._unwatch(),void 0)};D.addEventListener(window,"resize",e),this.watchTimer=setInterval(e,1e3)},c.prototype._unwatch=function(){this.watchTimer&&(clearInterval(this.watchTimer),this.watchTimer=void 0)},c.prototype.on=function(t,e){var i=this.listeners[t];i||(i=[],this.listeners[t]=i),i.push(e),this._updateEventEmitters()},c.prototype._updateEventEmitters=function(){if(this.listeners){var t=this;D.forEach(this.listeners,function(e,i){if(t.emitters||(t.emitters={}),!(i in t.emitters)){var s=t.frame;if(s){var n=function(t){e.forEach(function(e){e(t)})};t.emitters[i]=n,D.addEventListener(s,i,n)}}})}},u.prototype=new l,u.prototype.setOptions=l.prototype.setOptions,u.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},u.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.factor+e.offset)},u.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.factor},u.prototype.repaint=function(){var t=0,e=D.updateProperty,i=D.option.asSize,s=this.options,n=this.getOption("orientation"),o=this.props,r=this.step,a=this.frame;if(a||(a=document.createElement("div"),this.frame=a,t+=1),a.className="axis "+n,!a.parentNode){if(!this.parent)throw Error("Cannot repaint time axis: no parent attached");var h=this.parent.getContainer();if(!h)throw Error("Cannot repaint time axis: parent has no container element");h.appendChild(a),t+=1}var d=a.parentNode;if(d){var l=a.nextSibling;d.removeChild(a);var p="bottom"==n&&this.props.parentHeight&&this.height?this.props.parentHeight-this.height+"px":"0px";if(t+=e(a.style,"top",i(s.top,p)),t+=e(a.style,"left",i(s.left,"0px")),t+=e(a.style,"width",i(s.width,"100%")),t+=e(a.style,"height",i(s.height,this.height+"px")),this._repaintMeasureChars(),this.step){this._repaintStart(),r.first();for(var c=void 0,u=0;r.hasNext()&&1e3>u;){u++;var f=r.getCurrent(),m=this.toScreen(f),g=r.isMajor();this.getOption("showMinorLabels")&&this._repaintMinorText(m,r.getLabelMinor()),g&&this.getOption("showMajorLabels")?(m>0&&(void 0==c&&(c=m),this._repaintMajorText(m,r.getLabelMajor())),this._repaintMajorLine(m)):this._repaintMinorLine(m),r.next()}if(this.getOption("showMajorLabels")){var v=this.toTime(0),y=r.getLabelMajor(v),b=y.length*(o.majorCharWidth||10)+10;(void 0==c||c>b)&&this._repaintMajorText(0,y)}this._repaintEnd()}this._repaintLine(),l?d.insertBefore(a,l):d.appendChild(a)}return t>0},u.prototype._repaintStart=function(){var t=this.dom,e=t.redundant;e.majorLines=t.majorLines,e.majorTexts=t.majorTexts,e.minorLines=t.minorLines,e.minorTexts=t.minorTexts,t.majorLines=[],t.majorTexts=[],t.minorLines=[],t.minorTexts=[]},u.prototype._repaintEnd=function(){D.forEach(this.dom.redundant,function(t){for(;t.length;){var e=t.pop();e&&e.parentNode&&e.parentNode.removeChild(e)}})},u.prototype._repaintMinorText=function(t,e){var i=this.dom.redundant.minorTexts.shift();if(!i){var s=document.createTextNode("");i=document.createElement("div"),i.appendChild(s),i.className="text minor",this.frame.appendChild(i)}this.dom.minorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.left=t+"px",i.style.top=this.props.minorLabelTop+"px"},u.prototype._repaintMajorText=function(t,e){var i=this.dom.redundant.majorTexts.shift();if(!i){var s=document.createTextNode(e);i=document.createElement("div"),i.className="text major",i.appendChild(s),this.frame.appendChild(i)}this.dom.majorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.top=this.props.majorLabelTop+"px",i.style.left=t+"px"},u.prototype._repaintMinorLine=function(t){var e=this.dom.redundant.minorLines.shift();e||(e=document.createElement("div"),e.className="grid vertical minor",this.frame.appendChild(e)),this.dom.minorLines.push(e);var i=this.props;e.style.top=i.minorLineTop+"px",e.style.height=i.minorLineHeight+"px",e.style.left=t-i.minorLineWidth/2+"px"},u.prototype._repaintMajorLine=function(t){var e=this.dom.redundant.majorLines.shift();e||(e=document.createElement("DIV"),e.className="grid vertical major",this.frame.appendChild(e)),this.dom.majorLines.push(e);var i=this.props;e.style.top=i.majorLineTop+"px",e.style.left=t-i.majorLineWidth/2+"px",e.style.height=i.majorLineHeight+"px"},u.prototype._repaintLine=function(){var t=this.dom.line,e=this.frame;this.options,this.getOption("showMinorLabels")||this.getOption("showMajorLabels")?(t?(e.removeChild(t),e.appendChild(t)):(t=document.createElement("div"),t.className="grid horizontal major",e.appendChild(t),this.dom.line=t),t.style.top=this.props.lineTop+"px"):t&&axis.parentElement&&(e.removeChild(axis.line),delete this.dom.line)},u.prototype._repaintMeasureChars=function(){var t,e=this.dom;if(!e.measureCharMinor){t=document.createTextNode("0");var i=document.createElement("DIV");i.className="text minor measure",i.appendChild(t),this.frame.appendChild(i),e.measureCharMinor=i}if(!e.measureCharMajor){t=document.createTextNode("0");var s=document.createElement("DIV");s.className="text major measure",s.appendChild(t),this.frame.appendChild(s),e.measureCharMajor=s}},u.prototype.reflow=function(){var t=0,e=D.updateProperty,i=this.frame,s=this.range;if(!s)throw Error("Cannot repaint time axis: no range configured");if(i){t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft);var n=this.props,o=this.getOption("showMinorLabels"),r=this.getOption("showMajorLabels"),a=this.dom.measureCharMinor,h=this.dom.measureCharMajor;a&&(n.minorCharHeight=a.clientHeight,n.minorCharWidth=a.clientWidth),h&&(n.majorCharHeight=h.clientHeight,n.majorCharWidth=h.clientWidth);var d=i.parentNode?i.parentNode.offsetHeight:0;switch(d!=n.parentHeight&&(n.parentHeight=d,t+=1),this.getOption("orientation")){case"bottom":n.minorLabelHeight=o?n.minorCharHeight:0,n.majorLabelHeight=r?n.majorCharHeight:0,n.minorLabelTop=0,n.majorLabelTop=n.minorLabelTop+n.minorLabelHeight,n.minorLineTop=-this.top,n.minorLineHeight=Math.max(this.top+n.majorLabelHeight,0),n.minorLineWidth=1,n.majorLineTop=-this.top,n.majorLineHeight=Math.max(this.top+n.minorLabelHeight+n.majorLabelHeight,0),n.majorLineWidth=1,n.lineTop=0;break;case"top":n.minorLabelHeight=o?n.minorCharHeight:0,n.majorLabelHeight=r?n.majorCharHeight:0,n.majorLabelTop=0,n.minorLabelTop=n.majorLabelTop+n.majorLabelHeight,n.minorLineTop=n.minorLabelTop,n.minorLineHeight=Math.max(d-n.majorLabelHeight-this.top),n.minorLineWidth=1,n.majorLineTop=0,n.majorLineHeight=Math.max(d-this.top),n.majorLineWidth=1,n.lineTop=n.majorLabelHeight+n.minorLabelHeight;break;default:throw Error('Unkown orientation "'+this.getOption("orientation")+'"')}var l=n.minorLabelHeight+n.majorLabelHeight;t+=e(this,"width",i.offsetWidth),t+=e(this,"height",l),this._updateConversion();var p=D.convert(s.start,"Date"),c=D.convert(s.end,"Date"),u=this.toTime(5*(n.minorCharWidth||10))-this.toTime(0);this.step=new TimeStep(p,c,u),t+=e(n.range,"start",p.valueOf()),t+=e(n.range,"end",c.valueOf()),t+=e(n.range,"minimumStep",u.valueOf())}return t>0},u.prototype._updateConversion=function(){var t=this.range;if(!t)throw Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},f.prototype=new p,f.types={box:g,range:y,point:v},f.prototype.setOptions=l.prototype.setOptions,f.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},f.prototype.repaint=function(){var t=0,e=D.updateProperty,i=D.option.asSize,s=this.options,n=this.getOption("orientation"),o=this.defaultOptions,r=this.frame;if(!r){r=document.createElement("div"),r.className="itemset";var a=s.className;a&&D.addClassName(r,D.option.asString(a));var h=document.createElement("div");h.className="background",r.appendChild(h),this.dom.background=h;var d=document.createElement("div");d.className="foreground",r.appendChild(d),this.dom.foreground=d;var l=document.createElement("div");l.className="itemset-axis",this.dom.axis=l,this.frame=r,t+=1}if(!this.parent)throw Error("Cannot repaint itemset: no parent attached");var p=this.parent.getContainer();if(!p)throw Error("Cannot repaint itemset: parent has no container element");r.parentNode||(p.appendChild(r),t+=1),this.dom.axis.parentNode||(p.appendChild(this.dom.axis),t+=1),t+=e(r.style,"left",i(s.left,"0px")),t+=e(r.style,"top",i(s.top,"0px")),t+=e(r.style,"width",i(s.width,"100%")),t+=e(r.style,"height",i(s.height,this.height+"px")),t+=e(this.dom.axis.style,"left",i(s.left,"0px")),t+=e(this.dom.axis.style,"width",i(s.width,"100%")),t+="bottom"==n?e(this.dom.axis.style,"top",this.height+this.top+"px"):e(this.dom.axis.style,"top",this.top+"px"),this._updateConversion();var c=this,u=this.queue,m=this.itemsData,g=this.items,v={fields:[m&&m.fieldId||"id","start","end","content","type"]};return Object.keys(u).forEach(function(e){var i=u[e],n=g[e];switch(i){case"add":case"update":var r=m&&m.get(e,v);if(r){var a=r.type||r.start&&r.end&&"range"||s.type||"box",h=f.types[a];if(n&&(h&&n instanceof h?(n.data=r,t++):(t+=n.hide(),n=null)),!n){if(!h)throw new TypeError('Unknown item type "'+a+'"');n=new h(c,r,s,o),t++}n.repaint(),g[e]=n}delete u[e];break;case"remove":n&&(t+=n.hide()),delete g[e],delete u[e];break;default:console.log('Error: unknown action "'+i+'"')}}),D.forEach(this.items,function(e){e.visible?(t+=e.show(),e.reposition()):t+=e.hide()}),t>0},f.prototype.getForeground=function(){return this.dom.foreground},f.prototype.getBackground=function(){return this.dom.background},f.prototype.getAxis=function(){return this.dom.axis},f.prototype.reflow=function(){var t=0,e=this.options,i=e.margin&&e.margin.axis||this.defaultOptions.margin.axis,s=e.margin&&e.margin.item||this.defaultOptions.margin.item,n=D.updateProperty,o=D.option.asNumber,r=D.option.asSize,a=this.frame;if(a){this._updateConversion(),D.forEach(this.items,function(e){t+=e.reflow()}),this.stack.update();var h,d=o(e.maxHeight),l=null!=r(e.height);if(l)h=a.offsetHeight;else{var p=this.stack.ordered;if(p.length){var c=p[0].top,u=p[0].top+p[0].height;D.forEach(p,function(t){c=Math.min(c,t.top),u=Math.max(u,t.top+t.height)}),h=u-c+i+s}else h=i+s}null!=d&&(h=Math.min(h,d)),t+=n(this,"height",h),t+=n(this,"top",a.offsetTop),t+=n(this,"left",a.offsetLeft),t+=n(this,"width",a.offsetWidth)}else t+=1;return t>0},f.prototype.hide=function(){var t=!1;return this.frame&&this.frame.parentNode&&(this.frame.parentNode.removeChild(this.frame),t=!0),this.dom.axis&&this.dom.axis.parentNode&&(this.dom.axis.parentNode.removeChild(this.dom.axis),t=!0),t},f.prototype.setItems=function(t){var e,i=this,s=this.itemsData;if(t){if(!(t instanceof o||t instanceof r))throw new TypeError("Data must be an instance of DataSet");this.itemsData=t}else this.itemsData=null;if(s&&(D.forEach(this.listeners,function(t,e){s.unsubscribe(e,t)}),e=s.getIds(),this._onRemove(e)),this.itemsData){var n=this.id;D.forEach(this.listeners,function(t,e){i.itemsData.subscribe(e,t,n)}),e=this.itemsData.getIds(),this._onAdd(e)}},f.prototype.getItems=function(){return this.itemsData},f.prototype._onUpdate=function(t){this._toQueue("update",t)},f.prototype._onAdd=function(t){this._toQueue("add",t)},f.prototype._onRemove=function(t){this._toQueue("remove",t)},f.prototype._toQueue=function(t,e){var i=this.queue;e.forEach(function(e){i[e]=t}),this.controller&&this.requestRepaint()},f.prototype._updateConversion=function(){var t=this.range;if(!t)throw Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},f.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.factor+e.offset)},f.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.factor},m.prototype.select=function(){this.selected=!0},m.prototype.unselect=function(){this.selected=!1},m.prototype.show=function(){return!1},m.prototype.hide=function(){return!1},m.prototype.repaint=function(){return!1},m.prototype.reflow=function(){return!1},g.prototype=new m(null,null),g.prototype.select=function(){this.selected=!0},g.prototype.unselect=function(){this.selected=!1},g.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw Error("Cannot repaint time axis: parent has no foreground container element");var s=this.parent.getBackground();if(!s)throw Error("Cannot repaint time axis: parent has no background container element");var n=this.parent.getAxis();if(!s)throw Error("Cannot repaint time axis: parent has no axis container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),e.line.parentNode||(s.appendChild(e.line),t=!0),e.dot.parentNode||(n.appendChild(e.dot),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var o=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=o&&(this.className=o,e.box.className="item box"+o,e.line.className="item line"+o,e.dot.className="item dot"+o,t=!0)}return t},g.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},g.prototype.hide=function(){var t=!1,e=this.dom;return e&&(e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),e.line.parentNode&&e.line.parentNode.removeChild(e.line),e.dot.parentNode&&e.dot.parentNode.removeChild(e.dot)),t},g.prototype.reflow=function(){var t,e,i,s,n,o,r,a,h,d,l,p,c=0;if(void 0==this.data.start)throw Error('Property "start" missing in item '+this.data.id);if(l=this.data,p=this.parent&&this.parent.range,l&&p){var u=p.end-p.start;this.visible=l.start>p.start-u&&l.start0},g.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("DIV"),t.content=document.createElement("DIV"),t.content.className="content",t.box.appendChild(t.content),t.line=document.createElement("DIV"),t.line.className="line",t.dot=document.createElement("DIV"),t.dot.className="dot")},g.prototype.reposition=function(){var t=this.dom,e=this.props,i=this.options.orientation||this.defaultOptions.orientation;if(t){var s=t.box,n=t.line,o=t.dot;s.style.left=this.left+"px",s.style.top=this.top+"px",n.style.left=e.line.left+"px","top"==i?(n.style.top="0px",n.style.height=this.top+"px"):(n.style.top=this.top+this.height+"px",n.style.height=Math.max(this.parent.height-this.top-this.height+this.props.dot.height/2,0)+"px"),o.style.left=e.dot.left+"px",o.style.top=e.dot.top+"px"}},v.prototype=new m(null,null),v.prototype.select=function(){this.selected=!0},v.prototype.unselect=function(){this.selected=!1},v.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw Error("Cannot repaint time axis: parent has no foreground container element");if(e.point.parentNode||(i.appendChild(e.point),i.appendChild(e.point),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var s=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=s&&(this.className=s,e.point.className="item point"+s,t=!0)}return t},v.prototype.show=function(){return this.dom&&this.dom.point.parentNode?!1:this.repaint()},v.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.point.parentNode&&(e.point.parentNode.removeChild(e.point),t=!0),t},v.prototype.reflow=function(){var t,e,i,s,n,o,r,a,h,d,l=0;if(void 0==this.data.start)throw Error('Property "start" missing in item '+this.data.id);if(h=this.data,d=this.parent&&this.parent.range,h&&d){var p=d.end-d.start;this.visible=h.start>d.start-p&&h.start0},v.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.point=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.point.appendChild(t.content),t.dot=document.createElement("div"),t.dot.className="dot",t.point.appendChild(t.dot))},v.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.point.style.top=this.top+"px",t.point.style.left=this.left+"px",t.content.style.marginLeft=e.content.marginLeft+"px",t.dot.style.top=e.dot.top+"px")},y.prototype=new m(null,null),y.prototype.select=function(){this.selected=!0},y.prototype.unselect=function(){this.selected=!1},y.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content -}t=!0}var s=this.data.className?""+this.data.className:"";this.className!=s&&(this.className=s,e.box.className="item range"+s,t=!0)}return t},y.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},y.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),t},y.prototype.reflow=function(){var t,e,i,s,n,o,r,a,h,d,l,p,c,u,f,m,g=0;if(void 0==this.data.start)throw Error('Property "start" missing in item '+this.data.id);if(void 0==this.data.end)throw Error('Property "end" missing in item '+this.data.id);return h=this.data,d=this.parent&&this.parent.range,this.visible=h&&d?h.startd.start:!1,this.visible&&(t=this.dom,t?(e=this.props,i=this.options,o=this.parent,r=o.toScreen(this.data.start),a=o.toScreen(this.data.end),l=D.updateProperty,p=t.box,c=o.width,f=i.orientation||this.defaultOptions.orientation,s=i.margin&&i.margin.axis||this.defaultOptions.margin.axis,n=i.padding||this.defaultOptions.padding,g+=l(e.content,"width",t.content.offsetWidth),g+=l(this,"height",p.offsetHeight),-c>r&&(r=-c),a>2*c&&(a=2*c),u=0>r?Math.min(-r,a-r-e.content.width-2*n):0,g+=l(e.content,"left",u),"top"==f?(m=s,g+=l(this,"top",m)):(m=o.height-this.height-s,g+=l(this,"top",m)),g+=l(this,"left",r),g+=l(this,"width",Math.max(a-r,1))):g+=1),g>0},y.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content))},y.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.box.style.top=this.top+"px",t.box.style.left=this.left+"px",t.box.style.width=this.width+"px",t.content.style.left=e.content.left+"px")},b.prototype=new l,b.prototype.setOptions=l.prototype.setOptions,b.prototype.getContainer=function(){return this.parent.getContainer()},b.prototype.setItems=function(t){if(this.itemset&&(this.itemset.hide(),this.itemset.setItems(),this.parent.controller.remove(this.itemset),this.itemset=null),t){var e=this.groupId,i=Object.create(this.options);this.itemset=new f(this,null,i),this.itemset.setRange(this.parent.range),this.view=new r(t,{filter:function(t){return t.group==e}}),this.itemset.setItems(this.view),this.parent.controller.add(this.itemset)}},b.prototype.repaint=function(){return!1},b.prototype.reflow=function(){var t=0,e=D.updateProperty;if(t+=e(this,"top",this.itemset?this.itemset.top:0),t+=e(this,"height",this.itemset?this.itemset.height:0),this.label){var i=this.label.firstChild;t+=e(this.props.label,"width",i.clientWidth),t+=e(this.props.label,"height",i.clientHeight)}else t+=e(this.props.label,"width",0),t+=e(this.props.label,"height",0);return t>0},w.prototype=new p,w.prototype.setOptions=l.prototype.setOptions,w.prototype.setRange=function(){},w.prototype.setItems=function(t){this.itemsData=t;for(var e in this.groups)if(this.groups.hasOwnProperty(e)){var i=this.groups[e];i.setItems(t)}},w.prototype.getItems=function(){return this.itemsData},w.prototype.setRange=function(t){this.range=t},w.prototype.setGroups=function(t){var e,i=this;if(this.groupsData&&(D.forEach(this.listeners,function(t,e){i.groupsData.unsubscribe(e,t)}),e=this.groupsData.getIds(),this._onRemove(e)),t?t instanceof o?this.groupsData=t:(this.groupsData=new o({convert:{start:"Date",end:"Date"}}),this.groupsData.add(t)):this.groupsData=null,this.groupsData){var s=this.id;D.forEach(this.listeners,function(t,e){i.groupsData.subscribe(e,t,s)}),e=this.groupsData.getIds(),this._onAdd(e)}},w.prototype.getGroups=function(){return this.groupsData},w.prototype.repaint=function(){var t,e,i,s,n=0,o=D.updateProperty,r=D.option.asSize,a=D.option.asElement,h=this.options,d=this.dom.frame,l=this.dom.labels;if(!this.parent)throw Error("Cannot repaint groupset: no parent attached");var p=this.parent.getContainer();if(!p)throw Error("Cannot repaint groupset: parent has no container element");if(!d){d=document.createElement("div"),d.className="groupset",this.dom.frame=d;var c=h.className;c&&D.addClassName(d,D.option.asString(c)),n+=1}d.parentNode||(p.appendChild(d),n+=1);var u=a(h.labelContainer);if(!u)throw Error('Cannot repaint groupset: option "labelContainer" not defined');l||(l=document.createElement("div"),l.className="labels",this.dom.labels=l),l.parentNode&&l.parentNode==u||(l.parentNode&&l.parentNode.removeChild(l.parentNode),u.appendChild(l)),n+=o(d.style,"height",r(h.height,this.height+"px")),n+=o(d.style,"top",r(h.top,"0px")),n+=o(d.style,"left",r(h.left,"0px")),n+=o(d.style,"width",r(h.width,"100%")),n+=o(l.style,"top",r(h.top,"0px"));var f=this,m=this.queue,g=this.groups,v=this.groupsData,y=Object.keys(m);if(y.length){y.forEach(function(t){var e=m[t],i=g[t];switch(e){case"add":case"update":if(!i){var s=Object.create(f.options);i=new b(f,t,s),i.setItems(f.itemsData),g[t]=i,f.controller.add(i)}i.data=v.get(t),delete m[t];break;case"remove":i&&(i.setItems(),delete g[t],f.controller.remove(i)),delete m[t];break;default:console.log('Error: unknown action "'+e+'"')}});var w=this.groupsData.getIds({order:this.options.groupsOrder});for(t=0;w.length>t;t++)(function(t,e){var i=0;e&&(i=function(){return e.top+e.height}),t.setOptions({top:i})})(g[w[t]],g[w[t-1]]);for(;l.firstChild;)l.removeChild(l.firstChild);for(t=0;w.length>t;t++)e=w[t],s=this._createLabel(e),l.appendChild(s);n++}for(e in g)g.hasOwnProperty(e)&&(i=g[e],s=i.label,s&&(s.style.top=i.top+"px",s.style.height=i.height+"px"));return n>0},w.prototype._createLabel=function(t){var e=this.groups[t],i=document.createElement("div");i.className="label";var s=document.createElement("div");s.className="inner",i.appendChild(s);var n=e.data&&e.data.content;n instanceof Element?s.appendChild(n):void 0!=n&&(s.innerHTML=n);var o=e.data&&e.data.className;return o&&D.addClassName(i,o),e.label=i,i},w.prototype.getContainer=function(){return this.dom.frame},w.prototype.getLabelsWidth=function(){return this.props.labels.width},w.prototype.reflow=function(){var t,e,i=0,s=this.options,n=D.updateProperty,o=D.option.asNumber,r=D.option.asSize,a=this.dom.frame;if(a){var h,d=o(s.maxHeight),l=null!=r(s.height);if(l)h=a.offsetHeight;else{h=0;for(t in this.groups)this.groups.hasOwnProperty(t)&&(e=this.groups[t],h+=e.height)}null!=d&&(h=Math.min(h,d)),i+=n(this,"height",h),i+=n(this,"top",a.offsetTop),i+=n(this,"left",a.offsetLeft),i+=n(this,"width",a.offsetWidth)}var p=0;for(t in this.groups)if(this.groups.hasOwnProperty(t)){e=this.groups[t];var c=e.props&&e.props.label&&e.props.label.width||0;p=Math.max(p,c)}return i+=n(this.props.labels,"width",p),i>0},w.prototype.hide=function(){return this.dom.frame&&this.dom.frame.parentNode?(this.dom.frame.parentNode.removeChild(this.dom.frame),!0):!1},w.prototype.show=function(){return this.dom.frame&&this.dom.frame.parentNode?!1:this.repaint()},w.prototype._onUpdate=function(t){this._toQueue(t,"update")},w.prototype._onAdd=function(t){this._toQueue(t,"add")},w.prototype._onRemove=function(t){this._toQueue(t,"remove")},w.prototype._toQueue=function(t,e){var i=this.queue;t.forEach(function(t){i[t]=e}),this.controller&&this.requestRepaint()},_.prototype.setOptions=function(t){t&&D.extend(this.options,t),this.controller.reflow(),this.controller.repaint()},_.prototype.setItems=function(t){var e,i=null==this.itemsData;if(t?t instanceof o&&(e=t):e=null,t instanceof o||(e=new o({convert:{start:"Date",end:"Date"}}),e.add(t)),this.itemsData=e,this.content.setItems(e),i&&(void 0==this.options.start||void 0==this.options.end)){var s=this.getItemRange(),n=s.min,r=s.max;if(null!=n&&null!=r){var a=r.valueOf()-n.valueOf();n=new Date(n.valueOf()-.05*a),r=new Date(r.valueOf()+.05*a)}void 0!=this.options.start&&(n=new Date(this.options.start.valueOf())),void 0!=this.options.end&&(r=new Date(this.options.end.valueOf())),(null!=n||null!=r)&&this.range.setRange(n,r)}},_.prototype.setGroups=function(t){var e=this;this.groupsData=t;var i=this.groupsData?w:f;if(!(this.content instanceof i)){this.content&&(this.content.hide(),this.content.setItems&&this.content.setItems(),this.content.setGroups&&this.content.setGroups(),this.controller.remove(this.content));var s=Object.create(this.options);D.extend(s,{top:function(){return"top"==e.options.orientation?e.timeaxis.height:e.itemPanel.height-e.timeaxis.height-e.content.height},left:null,width:"100%",height:function(){return e.options.height?e.itemPanel.height-e.timeaxis.height:null},maxHeight:function(){if(e.options.maxHeight){if(!D.isNumber(e.options.maxHeight))throw new TypeError("Number expected for property maxHeight");return e.options.maxHeight-e.timeaxis.height}return null},labelContainer:function(){return e.labelPanel.getContainer()}}),this.content=new i(this.itemPanel,[this.timeaxis],s),this.content.setRange&&this.content.setRange(this.range),this.content.setItems&&this.content.setItems(this.itemsData),this.content.setGroups&&this.content.setGroups(this.groupsData),this.controller.add(this.content)}},_.prototype.getItemRange=function(){var t=this.itemsData,e=null,i=null;if(t){var s=t.min("start");e=s?s.start.valueOf():null;var n=t.max("start");n&&(i=n.start.valueOf());var o=t.max("end");o&&(i=null==i?o.end.valueOf():Math.max(i,o.end.valueOf()))}return{min:null!=e?new Date(e):null,max:null!=i?new Date(i):null}},function(t){function e(t){return E=t,c()}function i(){D=0,C=E.charAt(0)}function s(){D++,C=E.charAt(D)}function n(){return E.charAt(D+1)}function o(t){return N.test(t)}function r(t,e){if(t||(t={}),e)for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function a(t,e,i){for(var s=e.split("."),n=t;s.length;){var o=s.shift();s.length?(n[o]||(n[o]={}),n=n[o]):n[o]=i}}function h(t,e){for(var i,s,n=null,o=[t],a=t;a.parent;)o.push(a.parent),a=a.parent;if(a.nodes)for(i=0,s=a.nodes.length;s>i;i++)if(e.id===a.nodes[i].id){n=a.nodes[i];break}for(n||(n={id:e.id},t.node&&(n.attr=r(n.attr,t.node))),i=o.length-1;i>=0;i--){var h=o[i];h.nodes||(h.nodes=[]),-1==h.nodes.indexOf(n)&&h.nodes.push(n)}e.attr&&(n.attr=r(n.attr,e.attr))}function d(t,e){if(t.edges||(t.edges=[]),t.edges.push(e),t.edge){var i=r({},t.edge);e.attr=r(i,e.attr)}}function l(t,e,i,s,n){var o={from:e,to:i,type:s};return t.edge&&(o.attr=r({},t.edge)),o.attr=r(o.attr||{},n),o}function p(){for(O=S.NULL,L="";" "==C||" "==C||"\n"==C||"\r"==C;)s();do{var t=!1;if("#"==C){for(var e=D-1;" "==E.charAt(e)||" "==E.charAt(e);)e--;if("\n"==E.charAt(e)||""==E.charAt(e)){for(;""!=C&&"\n"!=C;)s();t=!0}}if("/"==C&&"/"==n()){for(;""!=C&&"\n"!=C;)s();t=!0}if("/"==C&&"*"==n()){for(;""!=C;){if("*"==C&&"/"==n()){s(),s();break}s()}t=!0}for(;" "==C||" "==C||"\n"==C||"\r"==C;)s()}while(t);if(""==C)return O=S.DELIMITER,void 0;var i=C+n();if(M[i])return O=S.DELIMITER,L=i,s(),s(),void 0;if(M[C])return O=S.DELIMITER,L=C,s(),void 0;if(o(C)||"-"==C){for(L+=C,s();o(C);)L+=C,s();return"false"==L?L=!1:"true"==L?L=!0:isNaN(Number(L))||(L=Number(L)),O=S.IDENTIFIER,void 0}if('"'==C){for(s();""!=C&&('"'!=C||'"'==C&&'"'==n());)L+=C,'"'==C&&s(),s();if('"'!=C)throw w('End of string " expected');return s(),O=S.IDENTIFIER,void 0}for(O=S.UNKNOWN;""!=C;)L+=C,s();throw new SyntaxError('Syntax error in part "'+_(L,30)+'"')}function c(){var t={};if(i(),p(),"strict"==L&&(t.strict=!0,p()),("graph"==L||"digraph"==L)&&(t.type=L,p()),O==S.IDENTIFIER&&(t.id=L,p()),"{"!=L)throw w("Angle bracket { expected");if(p(),u(t),"}"!=L)throw w("Angle bracket } expected");if(p(),""!==L)throw w("End of file expected");return p(),delete t.node,delete t.edge,delete t.graph,t}function u(t){for(;""!==L&&"}"!=L;)f(t),";"==L&&p()}function f(t){var e=m(t);if(e)return y(t,e),void 0;var i=g(t);if(!i){if(O!=S.IDENTIFIER)throw w("Identifier expected");var s=L;if(p(),"="==L){if(p(),O!=S.IDENTIFIER)throw w("Identifier expected");t[s]=L,p()}else v(t,s)}}function m(t){var e=null;if("subgraph"==L&&(e={},e.type="subgraph",p(),O==S.IDENTIFIER&&(e.id=L,p())),"{"==L){if(p(),e||(e={}),e.parent=t,e.node=t.node,e.edge=t.edge,e.graph=t.graph,u(e),"}"!=L)throw w("Angle bracket } expected");p(),delete e.node,delete e.edge,delete e.graph,delete e.parent,t.subgraphs||(t.subgraphs=[]),t.subgraphs.push(e)}return e}function g(t){return"node"==L?(p(),t.node=b(),"node"):"edge"==L?(p(),t.edge=b(),"edge"):"graph"==L?(p(),t.graph=b(),"graph"):null}function v(t,e){var i={id:e},s=b();s&&(i.attr=s),h(t,i),y(t,e)}function y(t,e){for(;"->"==L||"--"==L;){var i,s=L;p();var n=m(t);if(n)i=n;else{if(O!=S.IDENTIFIER)throw w("Identifier or subgraph expected");i=L,h(t,{id:i}),p()}var o=b(),r=l(t,e,i,s,o);d(t,r),e=i}}function b(){for(var t=null;"["==L;){for(p(),t={};""!==L&&"]"!=L;){if(O!=S.IDENTIFIER)throw w("Attribute name expected");var e=L;if(p(),"="!=L)throw w("Equal sign = expected");if(p(),O!=S.IDENTIFIER)throw w("Attribute value expected");var i=L;a(t,e,i),p(),","==L&&p()}if("]"!=L)throw w("Bracket ] expected");p()}return t}function w(t){return new SyntaxError(t+', got "'+_(L,30)+'" (char '+D+")")}function _(t,e){return e>=t.length?t:t.substr(0,27)+"..."}function x(t,e,i){t instanceof Array?t.forEach(function(t){e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}):e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}function T(t){function i(t){var e={from:t.from,to:t.to};return r(e,t.attr),e.style="->"==t.type?"arrow":"line",e}var s=e(t),n={nodes:[],edges:[],options:{}};return s.nodes&&s.nodes.forEach(function(t){var e={id:t.id,label:(t.label||t.id)+""};r(e,t.attr),e.image&&(e.shape="image"),n.nodes.push(e)}),s.edges&&s.edges.forEach(function(t){var e,s;e=t.from instanceof Object?t.from.nodes:{id:t.from},s=t.to instanceof Object?t.to.nodes:{id:t.to},t.from instanceof Object&&t.from.edges&&t.from.edges.forEach(function(t){var e=i(t);n.edges.push(e)}),x(e,s,function(e,s){var o=l(n,e.id,s.id,t.type,t.attr),r=i(o);n.edges.push(r)}),t.to instanceof Object&&t.to.edges&&t.to.edges.forEach(function(t){var e=i(t);n.edges.push(e)})}),s.attr&&(n.options=s.attr),n}var S={NULL:0,DELIMITER:1,IDENTIFIER:2,UNKNOWN:3},M={"{":!0,"}":!0,"[":!0,"]":!0,";":!0,"=":!0,",":!0,"->":!0,"--":!0},E="",D=0,C="",L="",O=S.NULL,N=/[a-zA-Z_0-9.:#]/;t.parseDOT=e,t.DOTToGraph=T}(D!==void 0?D:s),"undefined"!=typeof CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.circle=function(t,e,i){this.beginPath(),this.arc(t,e,i,0,2*Math.PI,!1)},CanvasRenderingContext2D.prototype.square=function(t,e,i){this.beginPath(),this.rect(t-i,e-i,2*i,2*i)},CanvasRenderingContext2D.prototype.triangle=function(t,e,i){this.beginPath();var s=2*i,n=s/2,o=Math.sqrt(3)/6*s,r=Math.sqrt(s*s-n*n);this.moveTo(t,e-(r-o)),this.lineTo(t+n,e+o),this.lineTo(t-n,e+o),this.lineTo(t,e-(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.triangleDown=function(t,e,i){this.beginPath();var s=2*i,n=s/2,o=Math.sqrt(3)/6*s,r=Math.sqrt(s*s-n*n);this.moveTo(t,e+(r-o)),this.lineTo(t+n,e-o),this.lineTo(t-n,e-o),this.lineTo(t,e+(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.star=function(t,e,i){this.beginPath();for(var s=0;10>s;s++){var n=0===s%2?1.3*i:.5*i;this.lineTo(t+n*Math.sin(2*s*Math.PI/10),e-n*Math.cos(2*s*Math.PI/10))}this.closePath()},CanvasRenderingContext2D.prototype.roundRect=function(t,e,i,s,n){var o=Math.PI/180;0>i-2*n&&(n=i/2),0>s-2*n&&(n=s/2),this.beginPath(),this.moveTo(t+n,e),this.lineTo(t+i-n,e),this.arc(t+i-n,e+n,n,270*o,360*o,!1),this.lineTo(t+i,e+s-n),this.arc(t+i-n,e+s-n,n,0,90*o,!1),this.lineTo(t+n,e+s),this.arc(t+n,e+s-n,n,90*o,180*o,!1),this.lineTo(t,e+n),this.arc(t+n,e+n,n,180*o,270*o,!1)},CanvasRenderingContext2D.prototype.ellipse=function(t,e,i,s){var n=.5522848,o=i/2*n,r=s/2*n,a=t+i,h=e+s,d=t+i/2,l=e+s/2;this.beginPath(),this.moveTo(t,l),this.bezierCurveTo(t,l-r,d-o,e,d,e),this.bezierCurveTo(d+o,e,a,l-r,a,l),this.bezierCurveTo(a,l+r,d+o,h,d,h),this.bezierCurveTo(d-o,h,t,l+r,t,l)},CanvasRenderingContext2D.prototype.database=function(t,e,i,s){var n=1/3,o=i,r=s*n,a=.5522848,h=o/2*a,d=r/2*a,l=t+o,p=e+r,c=t+o/2,u=e+r/2,f=e+(s-r/2),m=e+s;this.beginPath(),this.moveTo(l,u),this.bezierCurveTo(l,u+d,c+h,p,c,p),this.bezierCurveTo(c-h,p,t,u+d,t,u),this.bezierCurveTo(t,u-d,c-h,e,c,e),this.bezierCurveTo(c+h,e,l,u-d,l,u),this.lineTo(l,f),this.bezierCurveTo(l,f+d,c+h,m,c,m),this.bezierCurveTo(c-h,m,t,f+d,t,f),this.lineTo(t,u)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,s){var n=t-s*Math.cos(i),o=e-s*Math.sin(i),r=t-.9*s*Math.cos(i),a=e-.9*s*Math.sin(i),h=n+s/3*Math.cos(i+.5*Math.PI),d=o+s/3*Math.sin(i+.5*Math.PI),l=n+s/3*Math.cos(i-.5*Math.PI),p=o+s/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,d),this.lineTo(r,a),this.lineTo(l,p),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,s,n){n||(n=[10,5]),0==c&&(c=.001);var o=n.length;this.moveTo(t,e);for(var r=i-t,a=s-e,h=a/r,d=Math.sqrt(r*r+a*a),l=0,p=!0;d>=.1;){var c=n[l++%o];c>d&&(c=d);var u=Math.sqrt(c*c/(1+h*h));0>r&&(u=-u),t+=u,e+=h*u,this[p?"lineTo":"moveTo"](t,e),d-=c,p=!p}}),x.prototype.attachEdge=function(t){-1==this.edges.indexOf(t)&&this.edges.push(t),this._updateMass()},x.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&this.edges.splice(e,1),this._updateMass()},x.prototype._updateMass=function(){this.mass=50+20*this.edges.length},x.prototype.setProperties=function(t,e){if(t){if(void 0!=t.id&&(this.id=t.id),void 0!=t.label&&(this.label=t.label),void 0!=t.title&&(this.title=t.title),void 0!=t.group&&(this.group=t.group),void 0!=t.x&&(this.x=t.x),void 0!=t.y&&(this.y=t.y),void 0!=t.value&&(this.value=t.value),void 0===this.id)throw"Node must have an id";if(this.group){var i=this.grouplist.get(this.group);for(var s in i)i.hasOwnProperty(s)&&(this[s]=i[s])}if(void 0!=t.shape&&(this.shape=t.shape),void 0!=t.image&&(this.image=t.image),void 0!=t.radius&&(this.radius=t.radius),void 0!=t.color&&(this.color=x.parseColor(t.color)),void 0!=t.fontColor&&(this.fontColor=t.fontColor),void 0!=t.fontSize&&(this.fontSize=t.fontSize),void 0!=t.fontFace&&(this.fontFace=t.fontFace),void 0!=this.image){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.image)}switch(this.xFixed=this.xFixed||void 0!=t.x,this.yFixed=this.yFixed||void 0!=t.y,this.radiusFixed=this.radiusFixed||void 0!=t.radius,"image"==this.shape&&(this.radiusMin=e.nodes.widthMin,this.radiusMax=e.nodes.widthMax),this.shape){case"database":this.draw=this._drawDatabase,this.resize=this._resizeDatabase;break;case"box":this.draw=this._drawBox,this.resize=this._resizeBox;break;case"circle":this.draw=this._drawCircle,this.resize=this._resizeCircle;break;case"ellipse":this.draw=this._drawEllipse,this.resize=this._resizeEllipse;break;case"image":this.draw=this._drawImage,this.resize=this._resizeImage;break;case"text":this.draw=this._drawText,this.resize=this._resizeText;break;case"dot":this.draw=this._drawDot,this.resize=this._resizeShape;break;case"square":this.draw=this._drawSquare,this.resize=this._resizeShape;break;case"triangle":this.draw=this._drawTriangle,this.resize=this._resizeShape;break;case"triangleDown":this.draw=this._drawTriangleDown,this.resize=this._resizeShape;break;case"star":this.draw=this._drawStar,this.resize=this._resizeShape;break;default:this.draw=this._drawEllipse,this.resize=this._resizeEllipse}this._reset()}},x.parseColor=function(t){var e;return D.isString(t)?e={border:t,background:t,highlight:{border:t,background:t}}:(e={},e.background=t.background||"white",e.border=t.border||e.background,D.isString(t.highlight)?e.highlight={border:t.highlight,background:t.highlight}:(e.highlight={},e.highlight.background=t.highlight&&t.highlight.background||e.background,e.highlight.border=t.highlight&&t.highlight.border||e.border)),e},x.prototype.select=function(){this.selected=!0,this._reset()},x.prototype.unselect=function(){this.selected=!1,this._reset()},x.prototype._reset=function(){this.width=void 0,this.height=void 0},x.prototype.getTitle=function(){return this.title},x.prototype.distanceToBorder=function(t,e){var i=1;switch(this.width||this.resize(t),this.shape){case"circle":case"dot":return this.radius+i;case"ellipse":var s=this.width/2,n=this.height/2,o=Math.sin(e)*s,r=Math.cos(e)*n;return s*n/Math.sqrt(o*o+r*r);case"box":case"image":case"text":default:return this.width?Math.min(Math.abs(this.width/2/Math.cos(e)),Math.abs(this.height/2/Math.sin(e)))+i:0}},x.prototype._setForce=function(t,e){this.fx=t,this.fy=e},x.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},x.prototype.discreteStep=function(t){if(!this.xFixed){var e=-this.damping*this.vx,i=(this.fx+e)/this.mass;this.vx+=i/t,this.x+=this.vx/t}if(!this.yFixed){var s=-this.damping*this.vy,n=(this.fy+s)/this.mass;this.vy+=n/t,this.y+=this.vy/t}},x.prototype.isFixed=function(){return this.xFixed&&this.yFixed},x.prototype.isMoving=function(t){return Math.abs(this.vx)>t||Math.abs(this.vy)>t||!this.xFixed&&Math.abs(this.fx)>this.minForce||!this.yFixed&&Math.abs(this.fy)>this.minForce},x.prototype.isSelected=function(){return this.selected},x.prototype.getValue=function(){return this.value},x.prototype.getDistance=function(t,e){var i=this.x-t,s=this.y-e;return Math.sqrt(i*i+s*s)},x.prototype.setValueRange=function(t,e){if(!this.radiusFixed&&void 0!==this.value){var i=(this.radiusMax-this.radiusMin)/(e-t);this.radius=(this.value-t)*i+this.radiusMin}},x.prototype.draw=function(){throw"Draw method not initialized for node"},x.prototype.resize=function(){throw"Resize method not initialized for node"},x.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},x.prototype._resizeImage=function(){if(!this.width){var t,e;if(this.value){var i=this.imageObj.height/this.imageObj.width;t=this.radius||this.imageObj.width,e=this.radius*i||this.imageObj.height}else t=this.imageObj.width,e=this.imageObj.height;this.width=t,this.height=e}},x.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e;this.imageObj?(t.drawImage(this.imageObj,this.left,this.top,this.width,this.height),e=this.y+this.height/2):e=this.y,this._label(t,this.label,this.x,e,void 0,"top")},x.prototype._resizeBox=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e}},x.prototype._drawBox=function(t){this._resizeBox(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,t.roundRect(this.left,this.top,this.width,this.height,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},x.prototype._resizeDatabase=function(t){if(!this.width){var e=5,i=this.getTextSize(t),s=i.width+2*e;this.width=s,this.height=s}},x.prototype._drawDatabase=function(t){this._resizeDatabase(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,t.database(this.x-this.width/2,this.y-.5*this.height,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},x.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),s=Math.max(i.width,i.height)+2*e;this.radius=s/2,this.width=s,this.height=s}},x.prototype._drawCircle=function(t){this._resizeCircle(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,t.circle(this.x,this.y,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},x.prototype._resizeEllipse=function(t){if(!this.width){var e=this.getTextSize(t);this.width=1.5*e.width,this.height=2*e.height,this.widthl;l++)t.fillText(r[l],i,d),d+=h}},x.prototype.getTextSize=function(t){if(void 0!=this.label){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace;for(var e=this.label.split("\n"),i=(this.fontSize+4)*e.length,s=0,n=0,o=e.length;o>n;n++)s=Math.max(s,t.measureText(e[n]).width);return{width:s,height:i}}return{width:0,height:0}},T.prototype.setProperties=function(t,e){if(t)switch(void 0!=t.from&&(this.fromId=t.from),void 0!=t.to&&(this.toId=t.to),void 0!=t.id&&(this.id=t.id),void 0!=t.style&&(this.style=t.style),void 0!=t.label&&(this.label=t.label),this.label&&(this.fontSize=e.edges.fontSize,this.fontFace=e.edges.fontFace,this.fontColor=e.edges.fontColor,void 0!=t.fontColor&&(this.fontColor=t.fontColor),void 0!=t.fontSize&&(this.fontSize=t.fontSize),void 0!=t.fontFace&&(this.fontFace=t.fontFace)),void 0!=t.title&&(this.title=t.title),void 0!=t.width&&(this.width=t.width),void 0!=t.value&&(this.value=t.value),void 0!=t.length&&(this.length=t.length),t.dash&&(void 0!=t.dash.length&&(this.dash.length=t.dash.length),void 0!=t.dash.gap&&(this.dash.gap=t.dash.gap),void 0!=t.dash.altLength&&(this.dash.altLength=t.dash.altLength)),void 0!=t.color&&(this.color=t.color),this.connect(),this.widthFixed=this.widthFixed||void 0!=t.width,this.lengthFixed=this.lengthFixed||void 0!=t.length,this.stiffness=1/this.length,this.style){case"line":this.draw=this._drawLine;break;case"arrow":this.draw=this._drawArrow;break;case"arrow-center":this.draw=this._drawArrowCenter;break;case"dash-line":this.draw=this._drawDashLine;break;default:this.draw=this._drawLine}},T.prototype.connect=function(){this.disconnect(),this.from=this.graph.nodes[this.fromId]||null,this.to=this.graph.nodes[this.toId]||null,this.connected=this.from&&this.to,this.connected?(this.from.attachEdge(this),this.to.attachEdge(this)):(this.from&&this.from.detachEdge(this),this.to&&this.to.detachEdge(this))},T.prototype.disconnect=function(){this.from&&(this.from.detachEdge(this),this.from=null),this.to&&(this.to.detachEdge(this),this.to=null),this.connected=!1},T.prototype.getTitle=function(){return this.title},T.prototype.getValue=function(){return this.value},T.prototype.setValueRange=function(t,e){if(!this.widthFixed&&void 0!==this.value){var i=(this.widthMax-this.widthMin)/(e-t);this.width=(this.value-t)*i+this.widthMin}},T.prototype.draw=function(){throw"Method draw not initialized in edge"},T.prototype.isOverlappingWith=function(t){var e=10,i=this.from.x,s=this.from.y,n=this.to.x,o=this.to.y,r=t.left,a=t.top,h=T._dist(i,s,n,o,r,a);return e>h},T.prototype._drawLine=function(t){t.strokeStyle=this.color,t.lineWidth=this._getLineWidth();var e;if(this.from!=this.to)this._line(t),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y));else{var i,s,n=this.length/4,o=this.from;o.width||o.resize(t),o.width>o.height?(i=o.x+o.width/2,s=o.y-n):(i=o.x+n,s=o.y-o.height/2),this._circle(t,i,s,n),e=this._pointOnCircle(i,s,n,.5),this._label(t,this.label,e.x,e.y)}},T.prototype._getLineWidth=function(){return this.from.selected||this.to.selected?Math.min(2*this.width,this.widthMax):this.width},T.prototype._line=function(t){t.beginPath(),t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y),t.stroke()},T.prototype._circle=function(t,e,i,s){t.beginPath(),t.arc(e,i,s,0,2*Math.PI,!1),t.stroke()},T.prototype._label=function(t,e,i,s){if(e){t.font=(this.from.selected||this.to.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle="white";var n=t.measureText(e).width,o=this.fontSize,r=i-n/2,a=s-o/2;t.fillRect(r,a,n,o),t.fillStyle=this.fontColor||"black",t.textAlign="left",t.textBaseline="top",t.fillText(e,r,a)}},T.prototype._drawDashLine=function(t){if(t.strokeStyle=this.color,t.lineWidth=this._getLineWidth(),t.beginPath(),t.lineCap="round",void 0!=this.dash.altLength?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]):void 0!=this.dash.length&&void 0!=this.dash.gap?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap]):(t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y)),t.stroke(),this.label){var e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}},T.prototype._pointOnLine=function(t){return{x:(1-t)*this.from.x+t*this.to.x,y:(1-t)*this.from.y+t*this.to.y}},T.prototype._pointOnCircle=function(t,e,i,s){var n=2*(s-3/8)*Math.PI;return{x:t+i*Math.cos(n),y:e-i*Math.sin(n)}},T.prototype._drawArrowCenter=function(t){var e;if(t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth(),this.from!=this.to){this._line(t);var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),s=10+5*this.width;e=this._pointOnLine(.5),t.arrow(e.x,e.y,i,s),t.fill(),t.stroke(),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y))}else{var n,o,r=this.length/4,a=this.from;a.width||a.resize(t),a.width>a.height?(n=a.x+a.width/2,o=a.y-r):(n=a.x+r,o=a.y-a.height/2),this._circle(t,n,o,r);var i=.2*Math.PI,s=10+5*this.width;e=this._pointOnCircle(n,o,r,.5),t.arrow(e.x,e.y,i,s),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(n,o,r,.5),this._label(t,this.label,e.x,e.y))}},T.prototype._drawArrow=function(t){t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth();var e,i;if(this.from!=this.to){e=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x);var s=this.to.x-this.from.x,n=this.to.y-this.from.y,o=Math.sqrt(s*s+n*n),r=this.from.distanceToBorder(t,e+Math.PI),a=(o-r)/o,h=a*this.from.x+(1-a)*this.to.x,d=a*this.from.y+(1-a)*this.to.y,l=this.to.distanceToBorder(t,e),p=(o-l)/o,c=(1-p)*this.from.x+p*this.to.x,u=(1-p)*this.from.y+p*this.to.y;if(t.beginPath(),t.moveTo(h,d),t.lineTo(c,u),t.stroke(),i=10+5*this.width,t.arrow(c,u,e,i),t.fill(),t.stroke(),this.label){var f=this._pointOnLine(.5);this._label(t,this.label,f.x,f.y)}}else{var m,g,v,y=this.from,b=this.length/4;y.width||y.resize(t),y.width>y.height?(m=y.x+y.width/2,g=y.y-b,v={x:m,y:y.y,angle:.9*Math.PI}):(m=y.x+b,g=y.y-y.height/2,v={x:y.x,y:g,angle:.6*Math.PI}),t.beginPath(),t.arc(m,g,b,0,2*Math.PI,!1),t.stroke(),i=10+5*this.width,t.arrow(v.x,v.y,v.angle,i),t.fill(),t.stroke(),this.label&&(f=this._pointOnCircle(m,g,b,.5),this._label(t,this.label,f.x,f.y))}},T._dist=function(t,e,i,s,n,o){var r=i-t,a=s-e,h=r*r+a*a,d=((n-t)*r+(o-e)*a)/h; -d>1?d=1:0>d&&(d=0);var l=t+d*r,p=e+d*a,c=l-n,u=p-o;return Math.sqrt(c*c+u*u)},S.prototype.setPosition=function(t,e){this.x=parseInt(t),this.y=parseInt(e)},S.prototype.setText=function(t){this.frame.innerHTML=t},S.prototype.show=function(t){if(void 0===t&&(t=!0),t){var e=this.frame.clientHeight,i=this.frame.clientWidth,s=this.frame.parentNode.clientHeight,n=this.frame.parentNode.clientWidth,o=this.y-e;o+e+this.padding>s&&(o=s-e-this.padding),this.padding>o&&(o=this.padding);var r=this.x;r+i+this.padding>n&&(r=n-i-this.padding),this.padding>r&&(r=this.padding),this.frame.style.left=r+"px",this.frame.style.top=o+"px",this.frame.style.visibility="visible"}else this.hide()},S.prototype.hide=function(){this.frame.style.visibility="hidden"},Groups=function(){this.clear(),this.defaultIndex=0},Groups.DEFAULT=[{border:"#2B7CE9",background:"#97C2FC",highlight:{border:"#2B7CE9",background:"#D2E5FF"}},{border:"#FFA500",background:"#FFFF00",highlight:{border:"#FFA500",background:"#FFFFA3"}},{border:"#FA0A10",background:"#FB7E81",highlight:{border:"#FA0A10",background:"#FFAFB1"}},{border:"#41A906",background:"#7BE141",highlight:{border:"#41A906",background:"#A1EC76"}},{border:"#E129F0",background:"#EB7DF4",highlight:{border:"#E129F0",background:"#F0B3F5"}},{border:"#7C29F0",background:"#AD85E4",highlight:{border:"#7C29F0",background:"#D3BDF0"}},{border:"#C37F00",background:"#FFA807",highlight:{border:"#C37F00",background:"#FFCA66"}},{border:"#4220FB",background:"#6E6EFD",highlight:{border:"#4220FB",background:"#9B9BFD"}},{border:"#FD5A77",background:"#FFC0CB",highlight:{border:"#FD5A77",background:"#FFD1D9"}},{border:"#4AD63A",background:"#C2FABC",highlight:{border:"#4AD63A",background:"#E6FFE3"}}],Groups.prototype.clear=function(){this.groups={},this.groups.length=function(){var t=0;for(var e in this)this.hasOwnProperty(e)&&t++;return t}},Groups.prototype.get=function(t){var e=this.groups[t];if(void 0==e){var i=this.defaultIndex%Groups.DEFAULT.length;this.defaultIndex++,e={},e.color=Groups.DEFAULT[i],this.groups[t]=e}return e},Groups.prototype.add=function(t,e){return this.groups[t]=e,e.color&&(e.color=x.parseColor(e.color)),e},Images=function(){this.images={},this.callback=void 0},Images.prototype.setOnloadCallback=function(t){this.callback=t},Images.prototype.load=function(t){var e=this.images[t];if(void 0==e){var i=this;e=new Image,this.images[t]=e,e.onload=function(){i.callback&&i.callback(this)},e.src=t}return e},M.prototype.setData=function(t){if(t&&t.dot&&(t.nodes||t.edges))throw new SyntaxError('Data must contain either parameter "dot" or parameter pair "nodes" and "edges", but not both.');if(this.setOptions(t&&t.options),t&&t.dot){if(t&&t.dot){var e=N.util.DOTToGraph(t.dot);return this.setData(e),void 0}}else this._setNodes(t&&t.nodes),this._setEdges(t&&t.edges);this.stabilize&&this._doStabilize(),this.start()},M.prototype.setOptions=function(t){if(t){if(void 0!=t.width&&(this.width=t.width),void 0!=t.height&&(this.height=t.height),void 0!=t.stabilize&&(this.stabilize=t.stabilize),void 0!=t.selectable&&(this.selectable=t.selectable),t.edges){for(var e in t.edges)t.edges.hasOwnProperty(e)&&(this.constants.edges[e]=t.edges[e]);void 0!=t.edges.length&&t.nodes&&void 0==t.nodes.distance&&(this.constants.edges.length=t.edges.length,this.constants.nodes.distance=1.25*t.edges.length),t.edges.fontColor||(this.constants.edges.fontColor=t.edges.color),t.edges.dash&&(void 0!=t.edges.dash.length&&(this.constants.edges.dash.length=t.edges.dash.length),void 0!=t.edges.dash.gap&&(this.constants.edges.dash.gap=t.edges.dash.gap),void 0!=t.edges.dash.altLength&&(this.constants.edges.dash.altLength=t.edges.dash.altLength))}if(t.nodes){for(e in t.nodes)t.nodes.hasOwnProperty(e)&&(this.constants.nodes[e]=t.nodes[e]);t.nodes.color&&(this.constants.nodes.color=x.parseColor(t.nodes.color))}if(t.groups)for(var i in t.groups)if(t.groups.hasOwnProperty(i)){var s=t.groups[i];this.groups.add(i,s)}}this.setSize(this.width,this.height),this._setTranslation(this.frame.clientWidth/2,this.frame.clientHeight/2),this._setScale(1)},M.prototype._trigger=function(t,e){O.trigger(this,t,e)},M.prototype._create=function(){for(;this.containerElement.hasChildNodes();)this.containerElement.removeChild(this.containerElement.firstChild);if(this.frame=document.createElement("div"),this.frame.className="graph-frame",this.frame.style.position="relative",this.frame.style.overflow="hidden",this.frame.canvas=document.createElement("canvas"),this.frame.canvas.style.position="relative",this.frame.appendChild(this.frame.canvas),!this.frame.canvas.getContext){var t=document.createElement("DIV");t.style.color="red",t.style.fontWeight="bold",t.style.padding="10px",t.innerHTML="Error: your browser does not support HTML canvas",this.frame.canvas.appendChild(t)}var e=this,i=function(t){e._onMouseDown(t)},s=function(t){e._onMouseMoveTitle(t)},n=function(t){e._onMouseWheel(t)},o=function(t){e._onTouchStart(t)};N.util.addEventListener(this.frame.canvas,"mousedown",i),N.util.addEventListener(this.frame.canvas,"mousemove",s),N.util.addEventListener(this.frame.canvas,"mousewheel",n),N.util.addEventListener(this.frame.canvas,"touchstart",o),this.containerElement.appendChild(this.frame)},M.prototype._onMouseDown=function(t){if(t=t||window.event,this.selectable&&(this.leftButtonDown&&this._onMouseUp(t),this.leftButtonDown=t.which?1==t.which:1==t.button,this.leftButtonDown||this.touchDown)){var e=this;this.onmousemove||(this.onmousemove=function(t){e._onMouseMove(t)},N.util.addEventListener(document,"mousemove",e.onmousemove)),this.onmouseup||(this.onmouseup=function(t){e._onMouseUp(t)},N.util.addEventListener(document,"mouseup",e.onmouseup)),N.util.preventDefault(t),this.startMouseX=D.getPageX(t),this.startMouseY=D.getPageY(t),this.startFrameLeft=N.util.getAbsoluteLeft(this.frame.canvas),this.startFrameTop=N.util.getAbsoluteTop(this.frame.canvas),this.startTranslation=this._getTranslation(),this.ctrlKeyDown=t.ctrlKey,this.shiftKeyDown=t.shiftKey;var i={left:this._xToCanvas(this.startMouseX-this.startFrameLeft),top:this._yToCanvas(this.startMouseY-this.startFrameTop),right:this._xToCanvas(this.startMouseX-this.startFrameLeft),bottom:this._yToCanvas(this.startMouseY-this.startFrameTop)},s=this._getNodesOverlappingWith(i);if(this.startClickedObj=s.length>0?s[s.length-1]:void 0,this.startClickedObj){var n=this.nodes[this.startClickedObj];this.startClickedObj.xFixed=n.xFixed,this.startClickedObj.yFixed=n.yFixed,n.xFixed=!0,n.yFixed=!0,this.ctrlKeyDown&&n.isSelected()?this._unselectNodes([this.startClickedObj]):this._selectNodes([this.startClickedObj],this.ctrlKeyDown),this.moving||this._redraw()}else this.shiftKeyDown||(this.moved=!1)}},M.prototype._onMouseMove=function(t){if(t=t||window.event,this.selectable){var e=D.getPageX(t),i=D.getPageY(t);if(this.mouseX=e,this.mouseY=i,this.startClickedObj){var s=this.nodes[this.startClickedObj];this.startClickedObj.xFixed||(s.x=this._xToCanvas(e-this.startFrameLeft)),this.startClickedObj.yFixed||(s.y=this._yToCanvas(i-this.startFrameTop)),this.moving||(this.moving=!0,this.start())}else if(this.shiftKeyDown){void 0==this.frame.selRect&&(this.frame.selRect=document.createElement("DIV"),this.frame.appendChild(this.frame.selRect),this.frame.selRect.style.position="absolute",this.frame.selRect.style.border="1px dashed red");var n=Math.min(this.startMouseX,e)-this.startFrameLeft,o=Math.min(this.startMouseY,i)-this.startFrameTop,r=Math.max(this.startMouseX,e)-this.startFrameLeft,a=Math.max(this.startMouseY,i)-this.startFrameTop;this.frame.selRect.style.left=n+"px",this.frame.selRect.style.top=o+"px",this.frame.selRect.style.width=r-n+"px",this.frame.selRect.style.height=a-o+"px"}else{var h=e-this.startMouseX,d=i-this.startMouseY;this._setTranslation(this.startTranslation.x+h,this.startTranslation.y+d),this._redraw(),this.moved=!0}N.util.preventDefault(t)}},M.prototype._onMouseUp=function(t){if(t=t||window.event,this.selectable){this.onmousemove&&(N.util.removeEventListener(document,"mousemove",this.onmousemove),this.onmousemove=void 0),this.onmouseup&&(N.util.removeEventListener(document,"mouseup",this.onmouseup),this.onmouseup=void 0),N.util.preventDefault(t);var e=D.getPageX(t)||this.mouseX||0,i=D.getPageY(t)||this.mouseY||0,s=t?t.ctrlKey:window.event.ctrlKey;if(this.startClickedObj){var n=this.nodes[this.startClickedObj];n.xFixed=this.startClickedObj.xFixed,n.yFixed=this.startClickedObj.yFixed}else if(this.shiftKeyDown){var o={left:this._xToCanvas(Math.min(this.startMouseX,e)-this.startFrameLeft),top:this._yToCanvas(Math.min(this.startMouseY,i)-this.startFrameTop),right:this._xToCanvas(Math.max(this.startMouseX,e)-this.startFrameLeft),bottom:this._yToCanvas(Math.max(this.startMouseY,i)-this.startFrameTop)},r=this._getNodesOverlappingWith(o);this._selectNodes(r,s),this.redraw(),this.frame.selRect&&(this.frame.removeChild(this.frame.selRect),this.frame.selRect=void 0)}else this.ctrlKeyDown||this.moved||(this._unselectNodes(),this._redraw());this.leftButtonDown=!1,this.ctrlKeyDown=!1}},M.prototype._onMouseWheel=function(t){t=t||window.event;var e=D.getPageX(t),i=D.getPageY(t),s=0;if(t.wheelDelta?s=t.wheelDelta/120:t.detail&&(s=-t.detail/3),s){var n=s/10;0>s&&(n/=1-n);var o=this._getScale(),r=o*(1+n);.01>r&&(r=.01),r>10&&(r=10);var a=N.util.getAbsoluteLeft(this.frame.canvas),h=N.util.getAbsoluteTop(this.frame.canvas),d=e-a,l=i-h,p=this._getTranslation(),c=r/o,u=(1-c)*d+p.x*c,f=(1-c)*l+p.y*c;this._setScale(r),this._setTranslation(u,f),this._redraw()}N.util.preventDefault(t)},M.prototype._onMouseMoveTitle=function(t){t=t||window.event;var e=D.getPageX(t),i=D.getPageY(t);this.startFrameLeft=this.startFrameLeft||N.util.getAbsoluteLeft(this.frame.canvas),this.startFrameTop=this.startFrameTop||N.util.getAbsoluteTop(this.frame.canvas);var s=e-this.startFrameLeft,n=i-this.startFrameTop;this.popupNode&&this._checkHidePopup(s,n);var o=this,r=function(){o._checkShowPopup(s,n)};this.popupTimer&&clearInterval(this.popupTimer),this.leftButtonDown||(this.popupTimer=setTimeout(r,300))},M.prototype._checkShowPopup=function(t,e){var i,s={left:this._xToCanvas(t),top:this._yToCanvas(e),right:this._xToCanvas(t),bottom:this._yToCanvas(e)},n=this.popupNode;if(void 0==this.popupNode){var o=this.nodes;for(i in o)if(o.hasOwnProperty(i)){var r=o[i];if(void 0!=r.getTitle()&&r.isOverlappingWith(s)){this.popupNode=r;break}}}if(void 0==this.popupNode){var a=this.edges;for(i in a)if(a.hasOwnProperty(i)){var h=a[i];if(h.connected&&void 0!=h.getTitle()&&h.isOverlappingWith(s)){this.popupNode=h;break}}}if(this.popupNode){if(this.popupNode!=n){var d=this;d.popup||(d.popup=new S(d.frame)),d.popup.setPosition(t-3,e-3),d.popup.setText(d.popupNode.getTitle()),d.popup.show()}}else this.popup&&this.popup.hide()},M.prototype._checkHidePopup=function(t,e){var i={left:t,top:e,right:t,bottom:e};this.popupNode&&this.popupNode.isOverlappingWith(i)||(this.popupNode=void 0,this.popup&&this.popup.hide())},M.prototype._onTouchStart=function(t){if(N.util.preventDefault(t),!this.touchDown){this.touchDown=!0;var e=this;this.ontouchmove||(this.ontouchmove=function(t){e._onTouchMove(t)},N.util.addEventListener(document,"touchmove",this.ontouchmove)),this.ontouchend||(this.ontouchend=function(t){e._onTouchEnd(t)},N.util.addEventListener(document,"touchend",this.ontouchend)),this._onMouseDown(t)}},M.prototype._onTouchMove=function(t){N.util.preventDefault(t),this._onMouseMove(t)},M.prototype._onTouchEnd=function(t){N.util.preventDefault(t),this.touchDown=!1,this.ontouchmove&&(N.util.removeEventListener(document,"touchmove",this.ontouchmove),this.ontouchmove=void 0),this.ontouchend&&(N.util.removeEventListener(document,"touchend",this.ontouchend),this.ontouchend=void 0),this._onMouseUp(t)},M.prototype._unselectNodes=function(t,e){var i,s,n,o=!1;if(t)for(i=0,s=t.length;s>i;i++){n=t[i],this.nodes[n].unselect();for(var r=0;this.selection.length>r;)this.selection[r]==n?(this.selection.splice(r,1),o=!0):r++}else if(this.selection&&this.selection.length){for(i=0,s=this.selection.length;s>i;i++)n=this.selection[i],this.nodes[n].unselect(),o=!0;this.selection=[]}return!o||1!=e&&void 0!=e||this._trigger("select"),o},M.prototype._selectNodes=function(t,e){var i,s,n=!1,o=!0;if(t.length!=this.selection.length)o=!1;else for(i=0,s=Math.min(t.length,this.selection.length);s>i;i++)if(t[i]!=this.selection[i]){o=!1;break}if(o)return n;if(void 0==e||0==e){var r=!1;n=this._unselectNodes(void 0,r)}for(i=0,s=t.length;s>i;i++){var a=t[i],h=-1!=this.selection.indexOf(a);h||(this.nodes[a].select(),this.selection.push(a),n=!0)}return n&&this._trigger("select"),n},M.prototype._getNodesOverlappingWith=function(t){var e=this.nodes,i=[];for(var s in e)e.hasOwnProperty(s)&&e[s].isOverlappingWith(t)&&i.push(s);return i},M.prototype.getSelection=function(){return this.selection.concat([])},M.prototype.setSelection=function(t){var e,i,s;if(void 0==t.length)throw"Selection must be an array with ids";for(e=0,i=this.selection.length;i>e;e++)s=this.selection[e],this.nodes[s].unselect();for(this.selection=[],e=0,i=t.length;i>e;e++){s=t[e];var n=this.nodes[s];if(!n)throw new RangeError('Node with id "'+s+'" not found');n.select(),this.selection.push(s)}this.redraw()},M.prototype._updateSelection=function(){for(var t=0;this.selection.length>t;){var e=this.selection[t];this.nodes[e]?t++:this.selection.splice(t,1)}},M.prototype._getConnectionCount=function(t){function e(t){for(var e=[],i=0,s=t.length;s>i;i++)for(var n=t[i],o=n.edges,r=0,a=o.length;a>r;r++){var h=o[r],d=null;h.from==n?d=h.to:h.to==n&&(d=h.from);var l,p;if(d)for(l=0,p=t.length;p>l;l++)if(t[l]==d){d=null;break}if(d)for(l=0,p=e.length;p>l;l++)if(e[l]==d){d=null;break}d&&e.push(d)}return e}void 0==t&&(t=1);var i=[],s=this.nodes;for(var n in s)if(s.hasOwnProperty(n)){for(var o=[s[n]],r=0;t>r;r++)o=o.concat(e(o));i.push(o)}for(var a=[],h=0,d=i.length;d>h;h++)a.push(i[h].length);return a},M.prototype.setSize=function(t,e){this.frame.style.width=t,this.frame.style.height=e,this.frame.canvas.style.width="100%",this.frame.canvas.style.height="100%",this.frame.canvas.width=this.frame.canvas.clientWidth,this.frame.canvas.height=this.frame.canvas.clientHeight},M.prototype._setNodes=function(t){var e=this.nodesData;if(t instanceof o||t instanceof r)this.nodesData=t;else if(t instanceof Array)this.nodesData=new o,this.nodesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.nodesData=new o}if(e&&D.forEach(this.nodesListeners,function(t,i){e.unsubscribe(i,t)}),this.nodes={},this.nodesData){var i=this;D.forEach(this.nodesListeners,function(t,e){i.nodesData.subscribe(e,t)});var s=this.nodesData.getIds();this._addNodes(s)}this._updateSelection()},M.prototype._addNodes=function(t){for(var e,i=0,s=t.length;s>i;i++){e=t[i];var n=this.nodesData.get(e),o=new x(n,this.images,this.groups,this.constants);if(this.nodes[e]=o,!o.isFixed()){var r=2*this.constants.edges.length,a=t.length,h=2*Math.PI*(i/a);o.x=r*Math.cos(h),o.y=r*Math.sin(h),this.moving=!0}}this._reconnectEdges(),this._updateValueRange(this.nodes)},M.prototype._updateNodes=function(t){for(var e=this.nodes,i=this.nodesData,s=0,n=t.length;n>s;s++){var o=t[s],r=e[o],a=i.get(o);r?r.setProperties(a,this.constants):(r=new x(properties,this.images,this.groups,this.constants),e[o]=r,r.isFixed()||(this.moving=!0))}this._reconnectEdges(),this._updateValueRange(e)},M.prototype._removeNodes=function(t){for(var e=this.nodes,i=0,s=t.length;s>i;i++){var n=t[i];delete e[n]}this._reconnectEdges(),this._updateSelection(),this._updateValueRange(e)},M.prototype._setEdges=function(t){var e=this.edgesData;if(t instanceof o||t instanceof r)this.edgesData=t;else if(t instanceof Array)this.edgesData=new o,this.edgesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.edgesData=new o}if(e&&D.forEach(this.edgesListeners,function(t,i){e.unsubscribe(i,t)}),this.edges={},this.edgesData){var i=this;D.forEach(this.edgesListeners,function(t,e){i.edgesData.subscribe(e,t)});var s=this.edgesData.getIds();this._addEdges(s)}this._reconnectEdges()},M.prototype._addEdges=function(t){for(var e=this.edges,i=this.edgesData,s=0,n=t.length;n>s;s++){var o=t[s],r=e[o];r&&r.disconnect();var a=i.get(o);e[o]=new T(a,this,this.constants)}this.moving=!0,this._updateValueRange(e)},M.prototype._updateEdges=function(t){for(var e=this.edges,i=this.edgesData,s=0,n=t.length;n>s;s++){var o=t[s],r=i.get(o),a=e[o];a?(a.disconnect(),a.setProperties(r,this.constants),a.connect()):(a=new T(r,this,this.constants),this.edges[o]=a)}this.moving=!0,this._updateValueRange(e)},M.prototype._removeEdges=function(t){for(var e=this.edges,i=0,s=t.length;s>i;i++){var n=t[i],o=e[n];o&&(o.disconnect(),delete e[n])}this.moving=!0,this._updateValueRange(e)},M.prototype._reconnectEdges=function(){var t,e=this.nodes,i=this.edges;for(t in e)e.hasOwnProperty(t)&&(e[t].edges=[]);for(t in i)if(i.hasOwnProperty(t)){var s=i[t];s.from=null,s.to=null,s.connect()}},M.prototype._updateValueRange=function(t){var e,i=void 0,s=void 0;for(e in t)if(t.hasOwnProperty(e)){var n=t[e].getValue();void 0!==n&&(i=void 0===i?n:Math.min(n,i),s=void 0===s?n:Math.max(n,s))}if(void 0!==i&&void 0!==s)for(e in t)t.hasOwnProperty(e)&&t[e].setValueRange(i,s)},M.prototype.redraw=function(){this.setSize(this.width,this.height),this._redraw()},M.prototype._redraw=function(){var t=this.frame.canvas.getContext("2d"),e=this.frame.canvas.width,i=this.frame.canvas.height;t.clearRect(0,0,e,i),t.save(),t.translate(this.translation.x,this.translation.y),t.scale(this.scale,this.scale),this._drawEdges(t),this._drawNodes(t),t.restore()},M.prototype._setTranslation=function(t,e){void 0===this.translation&&(this.translation={x:0,y:0}),void 0!==t&&(this.translation.x=t),void 0!==e&&(this.translation.y=e)},M.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},M.prototype._setScale=function(t){this.scale=t},M.prototype._getScale=function(){return this.scale},M.prototype._xToCanvas=function(t){return(t-this.translation.x)/this.scale},M.prototype._canvasToX=function(t){return t*this.scale+this.translation.x},M.prototype._yToCanvas=function(t){return(t-this.translation.y)/this.scale},M.prototype._canvasToY=function(t){return t*this.scale+this.translation.y},M.prototype._drawNodes=function(t){var e=this.nodes,i=[];for(var s in e)e.hasOwnProperty(s)&&(e[s].isSelected()?i.push(s):e[s].draw(t));for(var n=0,o=i.length;o>n;n++)e[i[n]].draw(t)},M.prototype._drawEdges=function(t){var e=this.edges;for(var i in e)if(e.hasOwnProperty(i)){var s=e[i];s.connected&&e[i].draw(t)}},M.prototype._doStabilize=function(){new Date;for(var t=0,e=this.constants.minVelocity,i=!1;!i&&this.constants.maxIterations>t;)this._calculateForces(),this._discreteStepNodes(),i=!this._isMoving(e),t++;new Date},M.prototype._calculateForces=function(){var t,e,i,s,n,o,r,a,h,d,l,p=this.nodes,c=this.edges,u=.01,f=this.frame.canvas.clientWidth/2,m=this.frame.canvas.clientHeight/2;for(t in p)if(p.hasOwnProperty(t)){var g=p[t];e=f-g.x,i=m-g.y,s=Math.atan2(i,e),o=Math.cos(s)*u,r=Math.sin(s)*u,g._setForce(o,r)}var v=this.constants.nodes.distance,y=10;for(var b in p)if(p.hasOwnProperty(b)){var w=p[b];for(var _ in p)if(p.hasOwnProperty(_)){var x=p[_];e=x.x-w.x,i=x.y-w.y,n=Math.sqrt(e*e+i*i),s=Math.atan2(i,e),a=1/(1+Math.exp((n/v-1)*y)),o=Math.cos(s)*a,r=Math.sin(s)*a,w._addForce(-o,-r),x._addForce(o,r)}}for(t in c)if(c.hasOwnProperty(t)){var T=c[t];T.connected&&(e=T.to.x-T.from.x,i=T.to.y-T.from.y,l=T.length,d=Math.sqrt(e*e+i*i),s=Math.atan2(i,e),h=T.stiffness*(l-d),o=Math.cos(s)*h,r=Math.sin(s)*h,T.from._addForce(-o,-r),T.to._addForce(o,r))}},M.prototype._isMoving=function(t){var e=this.nodes;for(var i in e)if(e.hasOwnProperty(i)&&e[i].isMoving(t))return!0;return!1},M.prototype._discreteStepNodes=function(){var t=this.refreshRate/1e3,e=this.nodes;for(var i in e)e.hasOwnProperty(i)&&e[i].discreteStep(t)},M.prototype.start=function(){if(this.moving){this._calculateForces(),this._discreteStepNodes();var t=this.constants.minVelocity;this.moving=this._isMoving(t)}if(this.moving){if(!this.timer){var e=this;this.timer=window.setTimeout(function(){e.timer=void 0,e.start(),e._redraw()},this.refreshRate)}}else this._redraw()},M.prototype.stop=function(){this.timer&&(window.clearInterval(this.timer),this.timer=void 0)};var N={util:D,events:O,Controller:d,DataSet:o,DataView:r,Range:h,Stack:a,TimeStep:TimeStep,EventBus:n,components:{items:{Item:m,ItemBox:g,ItemPoint:v,ItemRange:y},Component:l,Panel:p,RootPanel:c,ItemSet:f,TimeAxis:u},graph:{Node:x,Edge:T,Popup:S,Groups:Groups,Images:Images},Timeline:_,Graph:M};s!==void 0&&(s=N),i!==void 0&&i.exports!==void 0&&(i.exports=N),"function"==typeof t&&t(function(){return N}),"undefined"!=typeof window&&(window.vis=N),D.loadCss("/* vis.js stylesheet */\n.vis.timeline {\n}\n\n\n.vis.timeline.rootpanel {\n position: relative;\n overflow: hidden;\n\n border: 1px solid #bfbfbf;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n\n.vis.timeline .panel {\n position: absolute;\n overflow: hidden;\n}\n\n\n.vis.timeline .groupset {\n position: absolute;\n padding: 0;\n margin: 0;\n}\n\n.vis.timeline .labels {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n\n padding: 0;\n margin: 0;\n\n border-right: 1px solid #bfbfbf;\n box-sizing: border-box;\n -moz-box-sizing: border-box;\n}\n\n.vis.timeline .labels .label {\n position: absolute;\n left: 0;\n top: 0;\n width: 100%;\n border-bottom: 1px solid #bfbfbf;\n color: #4d4d4d;\n}\n\n.vis.timeline .labels .label .inner {\n display: inline-block;\n padding: 5px;\n}\n\n\n.vis.timeline .itemset {\n position: absolute;\n padding: 0;\n margin: 0;\n overflow: hidden;\n}\n\n.vis.timeline .background {\n}\n\n.vis.timeline .foreground {\n}\n\n.vis.timeline .itemset-axis {\n position: absolute;\n}\n\n.vis.timeline .groupset .itemset-axis {\n border-top: 1px solid #bfbfbf;\n}\n\n/* TODO: with orientation=='bottom', this will more or less overlap with timeline axis\n.vis.timeline .groupset .itemset-axis:last-child {\n border-top: none;\n}\n*/\n\n\n.vis.timeline .item {\n position: absolute;\n color: #1A1A1A;\n border-color: #97B0F8;\n background-color: #D5DDF6;\n display: inline-block;\n}\n\n.vis.timeline .item.selected {\n border-color: #FFC200;\n background-color: #FFF785;\n z-index: 999;\n}\n\n.vis.timeline .item.cluster {\n /* TODO: use another color or pattern? */\n background: #97B0F8 url('img/cluster_bg.png');\n color: white;\n}\n.vis.timeline .item.cluster.point {\n border-color: #D5DDF6;\n}\n\n.vis.timeline .item.box {\n text-align: center;\n border-style: solid;\n border-width: 1px;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.point {\n background: none;\n}\n\n.vis.timeline .dot {\n border: 5px solid #97B0F8;\n position: absolute;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.range {\n overflow: hidden;\n border-style: solid;\n border-width: 1px;\n border-radius: 2px;\n -moz-border-radius: 2px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.range .drag-left {\n cursor: w-resize;\n z-index: 1000;\n}\n\n.vis.timeline .item.range .drag-right {\n cursor: e-resize;\n z-index: 1000;\n}\n\n.vis.timeline .item.range .content {\n position: relative;\n display: inline-block;\n}\n\n.vis.timeline .item.line {\n position: absolute;\n width: 0;\n border-left-width: 1px;\n border-left-style: solid;\n}\n\n.vis.timeline .item .content {\n margin: 5px;\n white-space: nowrap;\n overflow: hidden;\n}\n\n.vis.timeline .axis {\n position: relative;\n}\n\n.vis.timeline .axis .text {\n position: absolute;\n color: #4d4d4d;\n padding: 3px;\n white-space: nowrap;\n}\n\n.vis.timeline .axis .text.measure {\n position: absolute;\n padding-left: 0;\n padding-right: 0;\n margin-left: 0;\n margin-right: 0;\n visibility: hidden;\n}\n\n.vis.timeline .axis .grid.vertical {\n position: absolute;\n width: 0;\n border-right: 1px solid;\n}\n\n.vis.timeline .axis .grid.horizontal {\n position: absolute;\n left: 0;\n width: 100%;\n height: 0;\n border-bottom: 1px solid;\n}\n\n.vis.timeline .axis .grid.minor {\n border-color: #e5e5e5;\n}\n\n.vis.timeline .axis .grid.major {\n border-color: #bfbfbf;\n}\n\n")})()},{moment:2}],2:[function(e,i){(function(){(function(s){function n(t,e){return function(i){return p(t.call(this,i),e)}}function o(t){return function(e){return this.lang().ordinal(t.call(this,e))}}function r(){}function a(t){d(this,t)}function h(t){var e=this._data={},i=t.years||t.year||t.y||0,s=t.months||t.month||t.M||0,n=t.weeks||t.week||t.w||0,o=t.days||t.day||t.d||0,r=t.hours||t.hour||t.h||0,a=t.minutes||t.minute||t.m||0,h=t.seconds||t.second||t.s||0,d=t.milliseconds||t.millisecond||t.ms||0;this._milliseconds=d+1e3*h+6e4*a+36e5*r,this._days=o+7*n,this._months=s+12*i,e.milliseconds=d%1e3,h+=l(d/1e3),e.seconds=h%60,a+=l(h/60),e.minutes=a%60,r+=l(a/60),e.hours=r%24,o+=l(r/24),o+=7*n,e.days=o%30,s+=l(o/30),e.months=s%12,i+=l(s/12),e.years=i}function d(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function l(t){return 0>t?Math.ceil(t):Math.floor(t)}function p(t,e){for(var i=t+"";e>i.length;)i="0"+i;return i}function c(t,e,i){var s,n=e._milliseconds,o=e._days,r=e._months;n&&t._d.setTime(+t+n*i),o&&t.date(t.date()+o*i),r&&(s=t.date(),t.date(1).month(t.month()+r*i).date(Math.min(s,t.daysInMonth())))}function u(t){return"[object Array]"===Object.prototype.toString.call(t)}function f(t,e){var i,s=Math.min(t.length,e.length),n=Math.abs(t.length-e.length),o=0;for(i=0;s>i;i++)~~t[i]!==~~e[i]&&o++;return o+n}function m(t,e){return e.abbr=t,z[t]||(z[t]=new r),z[t].set(e),z[t]}function g(t){return t?(!z[t]&&H&&e("./lang/"+t),z[t]):I.fn._lang}function v(t){return t.match(/\[.*\]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function y(t){var e,i,s=t.match(j);for(e=0,i=s.length;i>e;e++)s[e]=ae[s[e]]?ae[s[e]]:v(s[e]);return function(n){var o="";for(e=0;i>e;e++)o+="function"==typeof s[e].call?s[e].call(n,t):s[e];return o}}function b(t,e){function i(e){return t.lang().longDateFormat(e)||e}for(var s=5;s--&&U.test(e);)e=e.replace(U,i);return ne[e]||(ne[e]=y(e)),ne[e](t)}function w(t){switch(t){case"DDDD":return q;case"YYYY":return V;case"YYYYY":return X;case"S":case"SS":case"SSS":case"DDD":return B;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":case"a":case"A":return K;case"X":return J;case"Z":case"ZZ":return G;case"T":return Z;case"MM":case"DD":case"YY":case"HH":case"hh":case"mm":case"ss":case"M":case"D":case"d":case"H":case"h":case"m":case"s":return W;default:return RegExp(t.replace("\\",""))}}function _(t,e,i){var s,n=i._a;switch(t){case"M":case"MM":n[1]=null==e?0:~~e-1;break;case"MMM":case"MMMM":s=g(i._l).monthsParse(e),null!=s?n[1]=s:i._isValid=!1;break;case"D":case"DD":case"DDD":case"DDDD":null!=e&&(n[2]=~~e);break;case"YY":n[0]=~~e+(~~e>68?1900:2e3);break;case"YYYY":case"YYYYY":n[0]=~~e;break;case"a":case"A":i._isPm="pm"===(e+"").toLowerCase();break;case"H":case"HH":case"h":case"hh":n[3]=~~e;break;case"m":case"mm":n[4]=~~e;break;case"s":case"ss":n[5]=~~e;break;case"S":case"SS":case"SSS":n[6]=~~(1e3*("0."+e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,s=(e+"").match(ee),s&&s[1]&&(i._tzh=~~s[1]),s&&s[2]&&(i._tzm=~~s[2]),s&&"+"===s[0]&&(i._tzh=-i._tzh,i._tzm=-i._tzm)}null==e&&(i._isValid=!1)}function x(t){var e,i,s=[];if(!t._d){for(e=0;7>e;e++)t._a[e]=s[e]=null==t._a[e]?2===e?1:0:t._a[e];s[3]+=t._tzh||0,s[4]+=t._tzm||0,i=new Date(0),t._useUTC?(i.setUTCFullYear(s[0],s[1],s[2]),i.setUTCHours(s[3],s[4],s[5],s[6])):(i.setFullYear(s[0],s[1],s[2]),i.setHours(s[3],s[4],s[5],s[6])),t._d=i}}function T(t){var e,i,s=t._f.match(j),n=t._i;for(t._a=[],e=0;s.length>e;e++)i=(w(s[e]).exec(n)||[])[0],i&&(n=n.slice(n.indexOf(i)+i.length)),ae[s[e]]&&_(s[e],i,t);t._isPm&&12>t._a[3]&&(t._a[3]+=12),t._isPm===!1&&12===t._a[3]&&(t._a[3]=0),x(t)}function S(t){for(var e,i,s,n,o=99;t._f.length;){if(e=d({},t),e._f=t._f.pop(),T(e),i=new a(e),i.isValid()){s=i;break}n=f(e._a,i.toArray()),o>n&&(o=n,s=i)}d(t,s)}function M(t){var e,i=t._i;if(Q.exec(i)){for(t._f="YYYY-MM-DDT",e=0;4>e;e++)if(te[e][1].exec(i)){t._f+=te[e][0];break}G.exec(i)&&(t._f+=" Z"),T(t)}else t._d=new Date(i)}function E(t){var e=t._i,i=R.exec(e);e===s?t._d=new Date:i?t._d=new Date(+i[1]):"string"==typeof e?M(t):u(e)?(t._a=e.slice(0),x(t)):t._d=e instanceof Date?new Date(+e):new Date(e)}function D(t,e,i,s,n){return n.relativeTime(e||1,!!i,t,s)}function C(t,e,i){var s=Y(Math.abs(t)/1e3),n=Y(s/60),o=Y(n/60),r=Y(o/24),a=Y(r/365),h=45>s&&["s",s]||1===n&&["m"]||45>n&&["mm",n]||1===o&&["h"]||22>o&&["hh",o]||1===r&&["d"]||25>=r&&["dd",r]||45>=r&&["M"]||345>r&&["MM",Y(r/30)]||1===a&&["y"]||["yy",a];return h[2]=e,h[3]=t>0,h[4]=i,D.apply({},h)}function L(t,e,i){var s=i-e,n=i-t.day();return n>s&&(n-=7),s-7>n&&(n+=7),Math.ceil(I(t).add("d",n).dayOfYear()/7)}function O(t){var e=t._i,i=t._f;return null===e||""===e?null:("string"==typeof e&&(t._i=e=g().preparse(e)),I.isMoment(e)?(t=d({},e),t._d=new Date(+e._d)):i?u(i)?S(t):T(t):E(t),new a(t))}function N(t,e){I.fn[t]=I.fn[t+"s"]=function(t){var i=this._isUTC?"UTC":"";return null!=t?(this._d["set"+i+e](t),this):this._d["get"+i+e]()}}function A(t){I.duration.fn[t]=function(){return this._data[t]}}function k(t,e){I.duration.fn["as"+t]=function(){return+this/e}}for(var I,F,P="2.0.0",Y=Math.round,z={},H=i!==s&&i.exports,R=/^\/?Date\((\-?\d+)/i,j=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYY|YYYY|YY|a|A|hh?|HH?|mm?|ss?|SS?S?|X|zz?|ZZ?|.)/g,U=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,W=/\d\d?/,B=/\d{1,3}/,q=/\d{3}/,V=/\d{1,4}/,X=/[+\-]?\d{1,6}/,K=/[0-9]*[a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF]+\s*?[\u0600-\u06FF]+/i,G=/Z|[\+\-]\d\d:?\d\d/i,Z=/T/i,J=/[\+\-]?\d+(\.\d{1,3})?/,Q=/^\s*\d{4}-\d\d-\d\d((T| )(\d\d(:\d\d(:\d\d(\.\d\d?\d?)?)?)?)?([\+\-]\d\d:?\d\d)?)?/,$="YYYY-MM-DDTHH:mm:ssZ",te=[["HH:mm:ss.S",/(T| )\d\d:\d\d:\d\d\.\d{1,3}/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],ee=/([\+\-]|\d\d)/gi,ie="Month|Date|Hours|Minutes|Seconds|Milliseconds".split("|"),se={Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6},ne={},oe="DDD w W M D d".split(" "),re="M D H h m s w W".split(" "),ae={M:function(){return this.month()+1},MMM:function(t){return this.lang().monthsShort(this,t)},MMMM:function(t){return this.lang().months(this,t)},D:function(){return this.date()},DDD:function(){return this.dayOfYear()},d:function(){return this.day()},dd:function(t){return this.lang().weekdaysMin(this,t)},ddd:function(t){return this.lang().weekdaysShort(this,t)},dddd:function(t){return this.lang().weekdays(this,t)},w:function(){return this.week()},W:function(){return this.isoWeek()},YY:function(){return p(this.year()%100,2)},YYYY:function(){return p(this.year(),4)},YYYYY:function(){return p(this.year(),5)},a:function(){return this.lang().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.lang().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return~~(this.milliseconds()/100)},SS:function(){return p(~~(this.milliseconds()/10),2)},SSS:function(){return p(this.milliseconds(),3)},Z:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(~~(t/60),2)+":"+p(~~t%60,2)},ZZ:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(~~(10*t/6),4)},X:function(){return this.unix()}};oe.length;)F=oe.pop(),ae[F+"o"]=o(ae[F]);for(;re.length;)F=re.pop(),ae[F+F]=n(ae[F],2);for(ae.DDDD=n(ae.DDD,3),r.prototype={set:function(t){var e,i;for(i in t)e=t[i],"function"==typeof e?this[i]=e:this["_"+i]=e -},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(t){return this._months[t.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(t){return this._monthsShort[t.month()]},monthsParse:function(t){var e,i,s;for(this._monthsParse||(this._monthsParse=[]),e=0;12>e;e++)if(this._monthsParse[e]||(i=I([2e3,e]),s="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[e]=RegExp(s.replace(".",""),"i")),this._monthsParse[e].test(t))return e},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(t){return this._weekdays[t.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(t){return this._weekdaysShort[t.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(t){return this._weekdaysMin[t.day()]},_longDateFormat:{LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D YYYY",LLL:"MMMM D YYYY LT",LLLL:"dddd, MMMM D YYYY LT"},longDateFormat:function(t){var e=this._longDateFormat[t];return!e&&this._longDateFormat[t.toUpperCase()]&&(e=this._longDateFormat[t.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t]=e),e},meridiem:function(t,e,i){return t>11?i?"pm":"PM":i?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[last] dddd [at] LT",sameElse:"L"},calendar:function(t,e){var i=this._calendar[t];return"function"==typeof i?i.apply(e):i},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(t,e,i,s){var n=this._relativeTime[i];return"function"==typeof n?n(t,e,i,s):n.replace(/%d/i,t)},pastFuture:function(t,e){var i=this._relativeTime[t>0?"future":"past"];return"function"==typeof i?i(e):i.replace(/%s/i,e)},ordinal:function(t){return this._ordinal.replace("%d",t)},_ordinal:"%d",preparse:function(t){return t},postformat:function(t){return t},week:function(t){return L(t,this._week.dow,this._week.doy)},_week:{dow:0,doy:6}},I=function(t,e,i){return O({_i:t,_f:e,_l:i,_isUTC:!1})},I.utc=function(t,e,i){return O({_useUTC:!0,_isUTC:!0,_l:i,_i:t,_f:e})},I.unix=function(t){return I(1e3*t)},I.duration=function(t,e){var i,s=I.isDuration(t),n="number"==typeof t,o=s?t._data:n?{}:t;return n&&(e?o[e]=t:o.milliseconds=t),i=new h(o),s&&t.hasOwnProperty("_lang")&&(i._lang=t._lang),i},I.version=P,I.defaultFormat=$,I.lang=function(t,e){return t?(e?m(t,e):z[t]||g(t),I.duration.fn._lang=I.fn._lang=g(t),s):I.fn._lang._abbr},I.langData=function(t){return t&&t._lang&&t._lang._abbr&&(t=t._lang._abbr),g(t)},I.isMoment=function(t){return t instanceof a},I.isDuration=function(t){return t instanceof h},I.fn=a.prototype={clone:function(){return I(this)},valueOf:function(){return+this._d},unix:function(){return Math.floor(+this._d/1e3)},toString:function(){return this.format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._d},toJSON:function(){return I.utc(this).format("YYYY-MM-DD[T]HH:mm:ss.SSS[Z]")},toArray:function(){var t=this;return[t.year(),t.month(),t.date(),t.hours(),t.minutes(),t.seconds(),t.milliseconds()]},isValid:function(){return null==this._isValid&&(this._isValid=this._a?!f(this._a,(this._isUTC?I.utc(this._a):I(this._a)).toArray()):!isNaN(this._d.getTime())),!!this._isValid},utc:function(){return this._isUTC=!0,this},local:function(){return this._isUTC=!1,this},format:function(t){var e=b(this,t||I.defaultFormat);return this.lang().postformat(e)},add:function(t,e){var i;return i="string"==typeof t?I.duration(+e,t):I.duration(t,e),c(this,i,1),this},subtract:function(t,e){var i;return i="string"==typeof t?I.duration(+e,t):I.duration(t,e),c(this,i,-1),this},diff:function(t,e,i){var s,n,o=this._isUTC?I(t).utc():I(t).local(),r=6e4*(this.zone()-o.zone());return e&&(e=e.replace(/s$/,"")),"year"===e||"month"===e?(s=432e5*(this.daysInMonth()+o.daysInMonth()),n=12*(this.year()-o.year())+(this.month()-o.month()),n+=(this-I(this).startOf("month")-(o-I(o).startOf("month")))/s,"year"===e&&(n/=12)):(s=this-o-r,n="second"===e?s/1e3:"minute"===e?s/6e4:"hour"===e?s/36e5:"day"===e?s/864e5:"week"===e?s/6048e5:s),i?n:l(n)},from:function(t,e){return I.duration(this.diff(t)).lang(this.lang()._abbr).humanize(!e)},fromNow:function(t){return this.from(I(),t)},calendar:function(){var t=this.diff(I().startOf("day"),"days",!0),e=-6>t?"sameElse":-1>t?"lastWeek":0>t?"lastDay":1>t?"sameDay":2>t?"nextDay":7>t?"nextWeek":"sameElse";return this.format(this.lang().calendar(e,this))},isLeapYear:function(){var t=this.year();return 0===t%4&&0!==t%100||0===t%400},isDST:function(){return this.zone()+I(t).startOf(e)},isBefore:function(t,e){return e=e!==s?e:"millisecond",+this.clone().startOf(e)<+I(t).startOf(e)},isSame:function(t,e){return e=e!==s?e:"millisecond",+this.clone().startOf(e)===+I(t).startOf(e)},zone:function(){return this._isUTC?0:this._d.getTimezoneOffset()},daysInMonth:function(){return I.utc([this.year(),this.month()+1,0]).date()},dayOfYear:function(t){var e=Y((I(this).startOf("day")-I(this).startOf("year"))/864e5)+1;return null==t?e:this.add("d",t-e)},isoWeek:function(t){var e=L(this,1,4);return null==t?e:this.add("d",7*(t-e))},week:function(t){var e=this.lang().week(this);return null==t?e:this.add("d",7*(t-e))},lang:function(t){return t===s?this._lang:(this._lang=g(t),this)}},F=0;ie.length>F;F++)N(ie[F].toLowerCase().replace(/s$/,""),ie[F]);N("year","FullYear"),I.fn.days=I.fn.day,I.fn.weeks=I.fn.week,I.fn.isoWeeks=I.fn.isoWeek,I.duration.fn=h.prototype={weeks:function(){return l(this.days()/7)},valueOf:function(){return this._milliseconds+864e5*this._days+2592e6*this._months},humanize:function(t){var e=+this,i=C(e,!t,this.lang());return t&&(i=this.lang().pastFuture(e,i)),this.lang().postformat(i)},lang:I.fn.lang};for(F in se)se.hasOwnProperty(F)&&(k(F,se[F]),A(F.toLowerCase()));k("Weeks",6048e5),I.lang("en",{ordinal:function(t){var e=t%10,i=1===~~(t%100/10)?"th":1===e?"st":2===e?"nd":3===e?"rd":"th";return t+i}}),H&&(i.exports=I),"undefined"==typeof ender&&(this.moment=I),"function"==typeof t&&t.amd&&t("moment",[],function(){return I})}).call(this)})()},{}]},{},[1])(1)}); \ No newline at end of file +(function(t){if("function"==typeof bootstrap)bootstrap("vis",t);else if("object"==typeof exports)module.exports=t();else if("function"==typeof define&&define.amd)define(t);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeVis=t}else"undefined"!=typeof window?window.vis=t():global.vis=t()})(function(){var t;return function e(t,i,n){function s(r,a){if(!i[r]){if(!t[r]){var h="function"==typeof require&&require;if(!a&&h)return h(r,!0);if(o)return o(r,!0);throw Error("Cannot find module '"+r+"'")}var d=i[r]={exports:{}};t[r][0].call(d.exports,function(e){var i=t[r][1][e];return s(i?i:e)},d,d.exports,e,t,i,n)}return i[r].exports}for(var o="function"==typeof require&&require,r=0;n.length>r;r++)s(n[r]);return s}({1:[function(t,e){(function(t,i){"use strict";function n(){if(!s.READY){s.event.determineEventTypes();for(var t in s.gestures)s.gestures.hasOwnProperty(t)&&s.detection.register(s.gestures[t]);s.event.onTouch(s.DOCUMENT,s.EVENT_MOVE,s.detection.detect),s.event.onTouch(s.DOCUMENT,s.EVENT_END,s.detection.detect),s.READY=!0}}var s=function(t,e){return new s.Instance(t,e||{})};s.defaults={stop_browser_behavior:{userSelect:"none",touchAction:"none",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}},s.HAS_POINTEREVENTS=navigator.pointerEnabled||navigator.msPointerEnabled,s.HAS_TOUCHEVENTS="ontouchstart"in t,s.MOBILE_REGEX=/mobile|tablet|ip(ad|hone|od)|android/i,s.NO_MOUSEEVENTS=s.HAS_TOUCHEVENTS&&navigator.userAgent.match(s.MOBILE_REGEX),s.EVENT_TYPES={},s.DIRECTION_DOWN="down",s.DIRECTION_LEFT="left",s.DIRECTION_UP="up",s.DIRECTION_RIGHT="right",s.POINTER_MOUSE="mouse",s.POINTER_TOUCH="touch",s.POINTER_PEN="pen",s.EVENT_START="start",s.EVENT_MOVE="move",s.EVENT_END="end",s.DOCUMENT=document,s.plugins={},s.READY=!1,s.Instance=function(t,e){var i=this;return n(),this.element=t,this.enabled=!0,this.options=s.utils.extend(s.utils.extend({},s.defaults),e||{}),this.options.stop_browser_behavior&&s.utils.stopDefaultBrowserBehavior(this.element,this.options.stop_browser_behavior),s.event.onTouch(t,s.EVENT_START,function(t){i.enabled&&s.detection.startDetect(i,t)}),this},s.Instance.prototype={on:function(t,e){for(var i=t.split(" "),n=0;i.length>n;n++)this.element.addEventListener(i[n],e,!1);return this},off:function(t,e){for(var i=t.split(" "),n=0;i.length>n;n++)this.element.removeEventListener(i[n],e,!1);return this},trigger:function(t,e){var i=s.DOCUMENT.createEvent("Event");i.initEvent(t,!0,!0),i.gesture=e;var n=this.element;return s.utils.hasParent(e.target,n)&&(n=e.target),n.dispatchEvent(i),this},enable:function(t){return this.enabled=t,this}};var o=null,r=!1,a=!1;s.event={bindDom:function(t,e,i){for(var n=e.split(" "),s=0;n.length>s;s++)t.addEventListener(n[s],i,!1)},onTouch:function(t,e,i){var n=this;this.bindDom(t,s.EVENT_TYPES[e],function(h){var d=h.type.toLowerCase();if(!d.match(/mouse/)||!a){(d.match(/touch/)||d.match(/pointerdown/)||d.match(/mouse/)&&1===h.which)&&(r=!0),d.match(/touch|pointer/)&&(a=!0);var l=0;r&&(s.HAS_POINTEREVENTS&&e!=s.EVENT_END?l=s.PointerEvent.updatePointer(e,h):d.match(/touch/)?l=h.touches.length:a||(l=d.match(/up/)?0:1),l>0&&e==s.EVENT_END?e=s.EVENT_MOVE:l||(e=s.EVENT_END),l||null===o?o=h:h=o,i.call(s.detection,n.collectEventData(t,e,h)),s.HAS_POINTEREVENTS&&e==s.EVENT_END&&(l=s.PointerEvent.updatePointer(e,h))),l||(o=null,r=!1,a=!1,s.PointerEvent.reset())}})},determineEventTypes:function(){var t;t=s.HAS_POINTEREVENTS?s.PointerEvent.getEvents():s.NO_MOUSEEVENTS?["touchstart","touchmove","touchend touchcancel"]:["touchstart mousedown","touchmove mousemove","touchend touchcancel mouseup"],s.EVENT_TYPES[s.EVENT_START]=t[0],s.EVENT_TYPES[s.EVENT_MOVE]=t[1],s.EVENT_TYPES[s.EVENT_END]=t[2]},getTouchList:function(t){return s.HAS_POINTEREVENTS?s.PointerEvent.getTouchList():t.touches?t.touches:[{identifier:1,pageX:t.pageX,pageY:t.pageY,target:t.target}]},collectEventData:function(t,e,i){var n=this.getTouchList(i,e),o=s.POINTER_TOUCH;return(i.type.match(/mouse/)||s.PointerEvent.matchType(s.POINTER_MOUSE,i))&&(o=s.POINTER_MOUSE),{center:s.utils.getCenter(n),timeStamp:(new Date).getTime(),target:i.target,touches:n,eventType:e,pointerType:o,srcEvent:i,preventDefault:function(){this.srcEvent.preventManipulation&&this.srcEvent.preventManipulation(),this.srcEvent.preventDefault&&this.srcEvent.preventDefault()},stopPropagation:function(){this.srcEvent.stopPropagation()},stopDetect:function(){return s.detection.stopDetect()}}}},s.PointerEvent={pointers:{},getTouchList:function(){var t=this,e=[];return Object.keys(t.pointers).sort().forEach(function(i){e.push(t.pointers[i])}),e},updatePointer:function(t,e){return t==s.EVENT_END?this.pointers={}:(e.identifier=e.pointerId,this.pointers[e.pointerId]=e),Object.keys(this.pointers).length},matchType:function(t,e){if(!e.pointerType)return!1;var i={};return i[s.POINTER_MOUSE]=e.pointerType==e.MSPOINTER_TYPE_MOUSE||e.pointerType==s.POINTER_MOUSE,i[s.POINTER_TOUCH]=e.pointerType==e.MSPOINTER_TYPE_TOUCH||e.pointerType==s.POINTER_TOUCH,i[s.POINTER_PEN]=e.pointerType==e.MSPOINTER_TYPE_PEN||e.pointerType==s.POINTER_PEN,i[t]},getEvents:function(){return["pointerdown MSPointerDown","pointermove MSPointerMove","pointerup pointercancel MSPointerUp MSPointerCancel"]},reset:function(){this.pointers={}}},s.utils={extend:function(t,e,n){for(var s in e)t[s]!==i&&n||(t[s]=e[s]);return t},hasParent:function(t,e){for(;t;){if(t==e)return!0;t=t.parentNode}return!1},getCenter:function(t){for(var e=[],i=[],n=0,s=t.length;s>n;n++)e.push(t[n].pageX),i.push(t[n].pageY);return{pageX:(Math.min.apply(Math,e)+Math.max.apply(Math,e))/2,pageY:(Math.min.apply(Math,i)+Math.max.apply(Math,i))/2}},getVelocity:function(t,e,i){return{x:Math.abs(e/t)||0,y:Math.abs(i/t)||0}},getAngle:function(t,e){var i=e.pageY-t.pageY,n=e.pageX-t.pageX;return 180*Math.atan2(i,n)/Math.PI},getDirection:function(t,e){var i=Math.abs(t.pageX-e.pageX),n=Math.abs(t.pageY-e.pageY);return i>=n?t.pageX-e.pageX>0?s.DIRECTION_LEFT:s.DIRECTION_RIGHT:t.pageY-e.pageY>0?s.DIRECTION_UP:s.DIRECTION_DOWN},getDistance:function(t,e){var i=e.pageX-t.pageX,n=e.pageY-t.pageY;return Math.sqrt(i*i+n*n)},getScale:function(t,e){return t.length>=2&&e.length>=2?this.getDistance(e[0],e[1])/this.getDistance(t[0],t[1]):1},getRotation:function(t,e){return t.length>=2&&e.length>=2?this.getAngle(e[1],e[0])-this.getAngle(t[1],t[0]):0},isVertical:function(t){return t==s.DIRECTION_UP||t==s.DIRECTION_DOWN},stopDefaultBrowserBehavior:function(t,e){var i,n=["webkit","khtml","moz","ms","o",""];if(e&&t.style){for(var s=0;n.length>s;s++)for(var o in e)e.hasOwnProperty(o)&&(i=o,n[s]&&(i=n[s]+i.substring(0,1).toUpperCase()+i.substring(1)),t.style[i]=e[o]);"none"==e.userSelect&&(t.onselectstart=function(){return!1})}}},s.detection={gestures:[],current:null,previous:null,stopped:!1,startDetect:function(t,e){this.current||(this.stopped=!1,this.current={inst:t,startEvent:s.utils.extend({},e),lastEvent:!1,name:""},this.detect(e))},detect:function(t){if(this.current&&!this.stopped){t=this.extendEventData(t);for(var e=this.current.inst.options,i=0,n=this.gestures.length;n>i;i++){var o=this.gestures[i];if(!this.stopped&&e[o.name]!==!1&&o.handler.call(o,t,this.current.inst)===!1){this.stopDetect();break}}return this.current&&(this.current.lastEvent=t),t.eventType==s.EVENT_END&&!t.touches.length-1&&this.stopDetect(),t}},stopDetect:function(){this.previous=s.utils.extend({},this.current),this.current=null,this.stopped=!0},extendEventData:function(t){var e=this.current.startEvent;if(e&&(t.touches.length!=e.touches.length||t.touches===e.touches)){e.touches=[];for(var i=0,n=t.touches.length;n>i;i++)e.touches.push(s.utils.extend({},t.touches[i]))}var o=t.timeStamp-e.timeStamp,r=t.center.pageX-e.center.pageX,a=t.center.pageY-e.center.pageY,h=s.utils.getVelocity(o,r,a);return s.utils.extend(t,{deltaTime:o,deltaX:r,deltaY:a,velocityX:h.x,velocityY:h.y,distance:s.utils.getDistance(e.center,t.center),angle:s.utils.getAngle(e.center,t.center),direction:s.utils.getDirection(e.center,t.center),scale:s.utils.getScale(e.touches,t.touches),rotation:s.utils.getRotation(e.touches,t.touches),startEvent:e}),t},register:function(t){var e=t.defaults||{};return e[t.name]===i&&(e[t.name]=!0),s.utils.extend(s.defaults,e,!0),t.index=t.index||1e3,this.gestures.push(t),this.gestures.sort(function(t,e){return t.indexe.index?1:0}),this.gestures}},s.gestures=s.gestures||{},s.gestures.Hold={name:"hold",index:10,defaults:{hold_timeout:500,hold_threshold:1},timer:null,handler:function(t,e){switch(t.eventType){case s.EVENT_START:clearTimeout(this.timer),s.detection.current.name=this.name,this.timer=setTimeout(function(){"hold"==s.detection.current.name&&e.trigger("hold",t)},e.options.hold_timeout);break;case s.EVENT_MOVE:t.distance>e.options.hold_threshold&&clearTimeout(this.timer);break;case s.EVENT_END:clearTimeout(this.timer)}}},s.gestures.Tap={name:"tap",index:100,defaults:{tap_max_touchtime:250,tap_max_distance:10,tap_always:!0,doubletap_distance:20,doubletap_interval:300},handler:function(t,e){if(t.eventType==s.EVENT_END){var i=s.detection.previous,n=!1;if(t.deltaTime>e.options.tap_max_touchtime||t.distance>e.options.tap_max_distance)return;i&&"tap"==i.name&&t.timeStamp-i.lastEvent.timeStamp0&&t.touches.length>e.options.swipe_max_touches)return;(t.velocityX>e.options.swipe_velocity||t.velocityY>e.options.swipe_velocity)&&(e.trigger(this.name,t),e.trigger(this.name+t.direction,t))}}},s.gestures.Drag={name:"drag",index:50,defaults:{drag_min_distance:10,drag_max_touches:1,drag_block_horizontal:!1,drag_block_vertical:!1,drag_lock_to_axis:!1,drag_lock_min_distance:25},triggered:!1,handler:function(t,e){if(s.detection.current.name!=this.name&&this.triggered)return e.trigger(this.name+"end",t),this.triggered=!1,i;if(!(e.options.drag_max_touches>0&&t.touches.length>e.options.drag_max_touches))switch(t.eventType){case s.EVENT_START:this.triggered=!1;break;case s.EVENT_MOVE:if(t.distancet.deltaY?s.DIRECTION_UP:s.DIRECTION_DOWN:0>t.deltaX?s.DIRECTION_LEFT:s.DIRECTION_RIGHT),this.triggered||(e.trigger(this.name+"start",t),this.triggered=!0),e.trigger(this.name,t),e.trigger(this.name+t.direction,t),(e.options.drag_block_vertical&&s.utils.isVertical(t.direction)||e.options.drag_block_horizontal&&!s.utils.isVertical(t.direction))&&t.preventDefault();break;case s.EVENT_END:this.triggered&&e.trigger(this.name+"end",t),this.triggered=!1}}},s.gestures.Transform={name:"transform",index:45,defaults:{transform_min_scale:.01,transform_min_rotation:1,transform_always_block:!1},triggered:!1,handler:function(t,e){if(s.detection.current.name!=this.name&&this.triggered)return e.trigger(this.name+"end",t),this.triggered=!1,i;if(!(2>t.touches.length))switch(e.options.transform_always_block&&t.preventDefault(),t.eventType){case s.EVENT_START:this.triggered=!1;break;case s.EVENT_MOVE:var n=Math.abs(1-t.scale),o=Math.abs(t.rotation);if(e.options.transform_min_scale>n&&e.options.transform_min_rotation>o)return;s.detection.current.name=this.name,this.triggered||(e.trigger(this.name+"start",t),this.triggered=!0),e.trigger(this.name,t),o>e.options.transform_min_rotation&&e.trigger("rotate",t),n>e.options.transform_min_scale&&(e.trigger("pinch",t),e.trigger("pinch"+(1>t.scale?"in":"out"),t));break;case s.EVENT_END:this.triggered&&e.trigger(this.name+"end",t),this.triggered=!1}}},s.gestures.Touch={name:"touch",index:-1/0,defaults:{prevent_default:!1,prevent_mouseevents:!1},handler:function(t,e){return e.options.prevent_mouseevents&&t.pointerType==s.POINTER_MOUSE?(t.stopDetect(),i):(e.options.prevent_default&&t.preventDefault(),t.eventType==s.EVENT_START&&e.trigger(this.name,t),i)}},s.gestures.Release={name:"release",index:1/0,handler:function(t,e){t.eventType==s.EVENT_END&&e.trigger(this.name,t)}},"object"==typeof e&&"object"==typeof e.exports?e.exports=s:(t.Hammer=s,"function"==typeof t.define&&t.define.amd&&t.define("hammer",[],function(){return s}))})(this)},{}],2:[function(e,i){(function(n){function s(t,e){return function(i){return p(t.call(this,i),e)}}function o(t,e){return function(i){return this.lang().ordinal(t.call(this,i),e)}}function r(){}function a(t){d(this,t)}function h(t){var e=t.years||t.year||t.y||0,i=t.months||t.month||t.M||0,n=t.weeks||t.week||t.w||0,s=t.days||t.day||t.d||0,o=t.hours||t.hour||t.h||0,r=t.minutes||t.minute||t.m||0,a=t.seconds||t.second||t.s||0,h=t.milliseconds||t.millisecond||t.ms||0;this._input=t,this._milliseconds=+h+1e3*a+6e4*r+36e5*o,this._days=+s+7*n,this._months=+i+12*e,this._data={},this._bubble()}function d(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function l(t){return 0>t?Math.ceil(t):Math.floor(t)}function p(t,e){for(var i=t+"";e>i.length;)i="0"+i;return i}function c(t,e,i,n){var s,o,r=e._milliseconds,a=e._days,h=e._months;r&&t._d.setTime(+t._d+r*i),(a||h)&&(s=t.minute(),o=t.hour()),a&&t.date(t.date()+a*i),h&&t.month(t.month()+h*i),r&&!n&&H.updateOffset(t),(a||h)&&(t.minute(s),t.hour(o))}function u(t){return"[object Array]"===Object.prototype.toString.call(t)}function f(t,e){var i,n=Math.min(t.length,e.length),s=Math.abs(t.length-e.length),o=0;for(i=0;n>i;i++)~~t[i]!==~~e[i]&&o++;return o+s}function m(t){return t?pe[t]||t.toLowerCase().replace(/(.)s$/,"$1"):t}function g(t,e){return e.abbr=t,V[t]||(V[t]=new r),V[t].set(e),V[t]}function v(t){delete V[t]}function y(t){if(!t)return H.fn._lang;if(!V[t]&&B)try{e("./lang/"+t)}catch(i){return H.fn._lang}return V[t]||H.fn._lang}function b(t){return t.match(/\[.*\]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function w(t){var e,i,n=t.match(X);for(e=0,i=n.length;i>e;e++)n[e]=me[n[e]]?me[n[e]]:b(n[e]);return function(s){var o="";for(e=0;i>e;e++)o+=n[e]instanceof Function?n[e].call(s,t):n[e];return o}}function _(t,e){return e=E(e,t.lang()),ce[e]||(ce[e]=w(e)),ce[e](t)}function E(t,e){function i(t){return e.longDateFormat(t)||t}for(var n=5;n--&&(Z.lastIndex=0,Z.test(t));)t=t.replace(Z,i);return t}function T(t,e){switch(t){case"DDDD":return Q;case"YYYY":return $;case"YYYYY":return te;case"S":case"SS":case"SSS":case"DDD":return J;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return ee;case"a":case"A":return y(e._l)._meridiemParse;case"X":return se;case"Z":case"ZZ":return ie;case"T":return ne;case"MM":case"DD":case"YY":case"HH":case"hh":case"mm":case"ss":case"M":case"D":case"d":case"H":case"h":case"m":case"s":return K;default:return RegExp(t.replace("\\",""))}}function x(t){var e=(ie.exec(t)||[])[0],i=(e+"").match(he)||["-",0,0],n=+(60*i[1])+~~i[2];return"+"===i[0]?-n:n}function S(t,e,i){var n,s=i._a;switch(t){case"M":case"MM":null!=e&&(s[1]=~~e-1);break;case"MMM":case"MMMM":n=y(i._l).monthsParse(e),null!=n?s[1]=n:i._isValid=!1;break;case"D":case"DD":null!=e&&(s[2]=~~e);break;case"DDD":case"DDDD":null!=e&&(s[1]=0,s[2]=~~e);break;case"YY":s[0]=~~e+(~~e>68?1900:2e3);break;case"YYYY":case"YYYYY":s[0]=~~e;break;case"a":case"A":i._isPm=y(i._l).isPM(e);break;case"H":case"HH":case"h":case"hh":s[3]=~~e;break;case"m":case"mm":s[4]=~~e;break;case"s":case"ss":s[5]=~~e;break;case"S":case"SS":case"SSS":s[6]=~~(1e3*("0."+e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,i._tzm=x(e)}null==e&&(i._isValid=!1)}function M(t){var e,i,n,s=[];if(!t._d){for(n=C(t),e=0;3>e&&null==t._a[e];++e)t._a[e]=s[e]=n[e];for(;7>e;e++)t._a[e]=s[e]=null==t._a[e]?2===e?1:0:t._a[e];s[3]+=~~((t._tzm||0)/60),s[4]+=~~((t._tzm||0)%60),i=new Date(0),t._useUTC?(i.setUTCFullYear(s[0],s[1],s[2]),i.setUTCHours(s[3],s[4],s[5],s[6])):(i.setFullYear(s[0],s[1],s[2]),i.setHours(s[3],s[4],s[5],s[6])),t._d=i}}function D(t){var e=t._i;t._d||(t._a=[e.years||e.year||e.y,e.months||e.month||e.M,e.days||e.day||e.d,e.hours||e.hour||e.h,e.minutes||e.minute||e.m,e.seconds||e.second||e.s,e.milliseconds||e.millisecond||e.ms],M(t))}function C(t){var e=new Date;return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function O(t){var e,i,n,s=y(t._l),o=""+t._i;for(n=E(t._f,s).match(X),t._a=[],e=0;n.length>e;e++)i=(T(n[e],t).exec(o)||[])[0],i&&(o=o.slice(o.indexOf(i)+i.length)),me[n[e]]&&S(n[e],i,t);o&&(t._il=o),t._isPm&&12>t._a[3]&&(t._a[3]+=12),t._isPm===!1&&12===t._a[3]&&(t._a[3]=0),M(t)}function N(t){var e,i,n,s,o,r=99;for(s=0;t._f.length>s;s++)e=d({},t),e._f=t._f[s],O(e),i=new a(e),o=f(e._a,i.toArray()),i._il&&(o+=i._il.length),r>o&&(r=o,n=i);d(t,n)}function L(t){var e,i=t._i,n=oe.exec(i);if(n){for(t._f="YYYY-MM-DD"+(n[2]||" "),e=0;4>e;e++)if(ae[e][1].exec(i)){t._f+=ae[e][0];break}ie.exec(i)&&(t._f+=" Z"),O(t)}else t._d=new Date(i)}function k(t){var e=t._i,i=q.exec(e);e===n?t._d=new Date:i?t._d=new Date(+i[1]):"string"==typeof e?L(t):u(e)?(t._a=e.slice(0),M(t)):e instanceof Date?t._d=new Date(+e):"object"==typeof e?D(t):t._d=new Date(e)}function I(t,e,i,n,s){return s.relativeTime(e||1,!!i,t,n)}function A(t,e,i){var n=W(Math.abs(t)/1e3),s=W(n/60),o=W(s/60),r=W(o/24),a=W(r/365),h=45>n&&["s",n]||1===s&&["m"]||45>s&&["mm",s]||1===o&&["h"]||22>o&&["hh",o]||1===r&&["d"]||25>=r&&["dd",r]||45>=r&&["M"]||345>r&&["MM",W(r/30)]||1===a&&["y"]||["yy",a];return h[2]=e,h[3]=t>0,h[4]=i,I.apply({},h)}function P(t,e,i){var n,s=i-e,o=i-t.day();return o>s&&(o-=7),s-7>o&&(o+=7),n=H(t).add("d",o),{week:Math.ceil(n.dayOfYear()/7),year:n.year()}}function F(t){var e=t._i,i=t._f;return null===e||""===e?null:("string"==typeof e&&(t._i=e=y().preparse(e)),H.isMoment(e)?(t=d({},e),t._d=new Date(+e._d)):i?u(i)?N(t):O(t):k(t),new a(t))}function Y(t,e){H.fn[t]=H.fn[t+"s"]=function(t){var i=this._isUTC?"UTC":"";return null!=t?(this._d["set"+i+e](t),H.updateOffset(this),this):this._d["get"+i+e]()}}function R(t){H.duration.fn[t]=function(){return this._data[t]}}function z(t,e){H.duration.fn["as"+t]=function(){return+this/e}}for(var H,U,j="2.2.1",W=Math.round,V={},B=i!==n&&i.exports,q=/^\/?Date\((\-?\d+)/i,G=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)\:(\d+)\.?(\d{3})?/,X=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|SS?S?|X|zz?|ZZ?|.)/g,Z=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,K=/\d\d?/,J=/\d{1,3}/,Q=/\d{3}/,$=/\d{1,4}/,te=/[+\-]?\d{1,6}/,ee=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,ie=/Z|[\+\-]\d\d:?\d\d/i,ne=/T/i,se=/[\+\-]?\d+(\.\d{1,3})?/,oe=/^\s*\d{4}-\d\d-\d\d((T| )(\d\d(:\d\d(:\d\d(\.\d\d?\d?)?)?)?)?([\+\-]\d\d:?\d\d)?)?/,re="YYYY-MM-DDTHH:mm:ssZ",ae=[["HH:mm:ss.S",/(T| )\d\d:\d\d:\d\d\.\d{1,3}/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],he=/([\+\-]|\d\d)/gi,de="Date|Hours|Minutes|Seconds|Milliseconds".split("|"),le={Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6},pe={ms:"millisecond",s:"second",m:"minute",h:"hour",d:"day",w:"week",W:"isoweek",M:"month",y:"year"},ce={},ue="DDD w W M D d".split(" "),fe="M D H h m s w W".split(" "),me={M:function(){return this.month()+1},MMM:function(t){return this.lang().monthsShort(this,t)},MMMM:function(t){return this.lang().months(this,t)},D:function(){return this.date()},DDD:function(){return this.dayOfYear()},d:function(){return this.day()},dd:function(t){return this.lang().weekdaysMin(this,t)},ddd:function(t){return this.lang().weekdaysShort(this,t)},dddd:function(t){return this.lang().weekdays(this,t)},w:function(){return this.week()},W:function(){return this.isoWeek()},YY:function(){return p(this.year()%100,2)},YYYY:function(){return p(this.year(),4)},YYYYY:function(){return p(this.year(),5)},gg:function(){return p(this.weekYear()%100,2)},gggg:function(){return this.weekYear()},ggggg:function(){return p(this.weekYear(),5)},GG:function(){return p(this.isoWeekYear()%100,2)},GGGG:function(){return this.isoWeekYear()},GGGGG:function(){return p(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.lang().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.lang().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return~~(this.milliseconds()/100)},SS:function(){return p(~~(this.milliseconds()/10),2)},SSS:function(){return p(this.milliseconds(),3)},Z:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(~~(t/60),2)+":"+p(~~t%60,2)},ZZ:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(~~(10*t/6),4)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},X:function(){return this.unix()}};ue.length;)U=ue.pop(),me[U+"o"]=o(me[U],U);for(;fe.length;)U=fe.pop(),me[U+U]=s(me[U],2);for(me.DDDD=s(me.DDD,3),d(r.prototype,{set:function(t){var e,i;for(i in t)e=t[i],"function"==typeof e?this[i]=e:this["_"+i]=e},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(t){return this._months[t.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(t){return this._monthsShort[t.month()]},monthsParse:function(t){var e,i,n;for(this._monthsParse||(this._monthsParse=[]),e=0;12>e;e++)if(this._monthsParse[e]||(i=H.utc([2e3,e]),n="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[e]=RegExp(n.replace(".",""),"i")),this._monthsParse[e].test(t))return e},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(t){return this._weekdays[t.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(t){return this._weekdaysShort[t.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(t){return this._weekdaysMin[t.day()]},weekdaysParse:function(t){var e,i,n;for(this._weekdaysParse||(this._weekdaysParse=[]),e=0;7>e;e++)if(this._weekdaysParse[e]||(i=H([2e3,1]).day(e),n="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[e]=RegExp(n.replace(".",""),"i")),this._weekdaysParse[e].test(t))return e},_longDateFormat:{LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D YYYY",LLL:"MMMM D YYYY LT",LLLL:"dddd, MMMM D YYYY LT"},longDateFormat:function(t){var e=this._longDateFormat[t];return!e&&this._longDateFormat[t.toUpperCase()]&&(e=this._longDateFormat[t.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t]=e),e},isPM:function(t){return"p"===(t+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(t,e,i){return t>11?i?"pm":"PM":i?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(t,e){var i=this._calendar[t];return"function"==typeof i?i.apply(e):i},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(t,e,i,n){var s=this._relativeTime[i];return"function"==typeof s?s(t,e,i,n):s.replace(/%d/i,t)},pastFuture:function(t,e){var i=this._relativeTime[t>0?"future":"past"];return"function"==typeof i?i(e):i.replace(/%s/i,e)},ordinal:function(t){return this._ordinal.replace("%d",t)},_ordinal:"%d",preparse:function(t){return t},postformat:function(t){return t},week:function(t){return P(t,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6}}),H=function(t,e,i){return F({_i:t,_f:e,_l:i,_isUTC:!1})},H.utc=function(t,e,i){return F({_useUTC:!0,_isUTC:!0,_l:i,_i:t,_f:e}).utc()},H.unix=function(t){return H(1e3*t)},H.duration=function(t,e){var i,n,s=H.isDuration(t),o="number"==typeof t,r=s?t._input:o?{}:t,a=G.exec(t);return o?e?r[e]=t:r.milliseconds=t:a&&(i="-"===a[1]?-1:1,r={y:0,d:~~a[2]*i,h:~~a[3]*i,m:~~a[4]*i,s:~~a[5]*i,ms:~~a[6]*i}),n=new h(r),s&&t.hasOwnProperty("_lang")&&(n._lang=t._lang),n},H.version=j,H.defaultFormat=re,H.updateOffset=function(){},H.lang=function(t,e){return t?(t=t.toLowerCase(),t=t.replace("_","-"),e?g(t,e):null===e?(v(t),t="en"):V[t]||y(t),H.duration.fn._lang=H.fn._lang=y(t),n):H.fn._lang._abbr},H.langData=function(t){return t&&t._lang&&t._lang._abbr&&(t=t._lang._abbr),y(t)},H.isMoment=function(t){return t instanceof a},H.isDuration=function(t){return t instanceof h},d(H.fn=a.prototype,{clone:function(){return H(this)},valueOf:function(){return+this._d+6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){return _(H(this).utc(),"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]")},toArray:function(){var t=this;return[t.year(),t.month(),t.date(),t.hours(),t.minutes(),t.seconds(),t.milliseconds()]},isValid:function(){return null==this._isValid&&(this._isValid=this._a?!f(this._a,(this._isUTC?H.utc(this._a):H(this._a)).toArray()):!isNaN(this._d.getTime())),!!this._isValid},invalidAt:function(){var t,e=this._a,i=(this._isUTC?H.utc(this._a):H(this._a)).toArray();for(t=6;t>=0&&e[t]===i[t];--t);return t},utc:function(){return this.zone(0)},local:function(){return this.zone(0),this._isUTC=!1,this},format:function(t){var e=_(this,t||H.defaultFormat);return this.lang().postformat(e)},add:function(t,e){var i;return i="string"==typeof t?H.duration(+e,t):H.duration(t,e),c(this,i,1),this},subtract:function(t,e){var i;return i="string"==typeof t?H.duration(+e,t):H.duration(t,e),c(this,i,-1),this},diff:function(t,e,i){var n,s,o=this._isUTC?H(t).zone(this._offset||0):H(t).local(),r=6e4*(this.zone()-o.zone());return e=m(e),"year"===e||"month"===e?(n=432e5*(this.daysInMonth()+o.daysInMonth()),s=12*(this.year()-o.year())+(this.month()-o.month()),s+=(this-H(this).startOf("month")-(o-H(o).startOf("month")))/n,s-=6e4*(this.zone()-H(this).startOf("month").zone()-(o.zone()-H(o).startOf("month").zone()))/n,"year"===e&&(s/=12)):(n=this-o,s="second"===e?n/1e3:"minute"===e?n/6e4:"hour"===e?n/36e5:"day"===e?(n-r)/864e5:"week"===e?(n-r)/6048e5:n),i?s:l(s)},from:function(t,e){return H.duration(this.diff(t)).lang(this.lang()._abbr).humanize(!e)},fromNow:function(t){return this.from(H(),t)},calendar:function(){var t=this.diff(H().zone(this.zone()).startOf("day"),"days",!0),e=-6>t?"sameElse":-1>t?"lastWeek":0>t?"lastDay":1>t?"sameDay":2>t?"nextDay":7>t?"nextWeek":"sameElse";return this.format(this.lang().calendar(e,this))},isLeapYear:function(){var t=this.year();return 0===t%4&&0!==t%100||0===t%400},isDST:function(){return this.zone()+H(t).startOf(e)},isBefore:function(t,e){return e=e!==n?e:"millisecond",+this.clone().startOf(e)<+H(t).startOf(e)},isSame:function(t,e){return e=e!==n?e:"millisecond",+this.clone().startOf(e)===+H(t).startOf(e)},min:function(t){return t=H.apply(null,arguments),this>t?this:t},max:function(t){return t=H.apply(null,arguments),t>this?this:t},zone:function(t){var e=this._offset||0;return null==t?this._isUTC?e:this._d.getTimezoneOffset():("string"==typeof t&&(t=x(t)),16>Math.abs(t)&&(t=60*t),this._offset=t,this._isUTC=!0,e!==t&&c(this,H.duration(e-t,"m"),1,!0),this)},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},hasAlignedHourOffset:function(t){return t=t?H(t).zone():0,0===(this.zone()-t)%60},daysInMonth:function(){return H.utc([this.year(),this.month()+1,0]).date()},dayOfYear:function(t){var e=W((H(this).startOf("day")-H(this).startOf("year"))/864e5)+1;return null==t?e:this.add("d",t-e)},weekYear:function(t){var e=P(this,this.lang()._week.dow,this.lang()._week.doy).year;return null==t?e:this.add("y",t-e)},isoWeekYear:function(t){var e=P(this,1,4).year;return null==t?e:this.add("y",t-e)},week:function(t){var e=this.lang().week(this);return null==t?e:this.add("d",7*(t-e))},isoWeek:function(t){var e=P(this,1,4).week;return null==t?e:this.add("d",7*(t-e))},weekday:function(t){var e=(this._d.getDay()+7-this.lang()._week.dow)%7;return null==t?e:this.add("d",t-e)},isoWeekday:function(t){return null==t?this.day()||7:this.day(this.day()%7?t:t-7)},get:function(t){return t=m(t),this[t.toLowerCase()]()},set:function(t,e){t=m(t),this[t.toLowerCase()](e)},lang:function(t){return t===n?this._lang:(this._lang=y(t),this)}}),U=0;de.length>U;U++)Y(de[U].toLowerCase().replace(/s$/,""),de[U]);Y("year","FullYear"),H.fn.days=H.fn.day,H.fn.months=H.fn.month,H.fn.weeks=H.fn.week,H.fn.isoWeeks=H.fn.isoWeek,H.fn.toJSON=H.fn.toISOString,d(H.duration.fn=h.prototype,{_bubble:function(){var t,e,i,n,s=this._milliseconds,o=this._days,r=this._months,a=this._data;a.milliseconds=s%1e3,t=l(s/1e3),a.seconds=t%60,e=l(t/60),a.minutes=e%60,i=l(e/60),a.hours=i%24,o+=l(i/24),a.days=o%30,r+=l(o/30),a.months=r%12,n=l(r/12),a.years=n},weeks:function(){return l(this.days()/7)},valueOf:function(){return this._milliseconds+864e5*this._days+2592e6*(this._months%12)+31536e6*~~(this._months/12)},humanize:function(t){var e=+this,i=A(e,!t,this.lang());return t&&(i=this.lang().pastFuture(e,i)),this.lang().postformat(i)},add:function(t,e){var i=H.duration(t,e);return this._milliseconds+=i._milliseconds,this._days+=i._days,this._months+=i._months,this._bubble(),this},subtract:function(t,e){var i=H.duration(t,e);return this._milliseconds-=i._milliseconds,this._days-=i._days,this._months-=i._months,this._bubble(),this},get:function(t){return t=m(t),this[t.toLowerCase()+"s"]()},as:function(t){return t=m(t),this["as"+t.charAt(0).toUpperCase()+t.slice(1)+"s"]()},lang:H.fn.lang});for(U in le)le.hasOwnProperty(U)&&(z(U,le[U]),R(U.toLowerCase()));z("Weeks",6048e5),H.duration.fn.asMonths=function(){return(+this-31536e6*this.years())/2592e6+12*this.years()},H.lang("en",{ordinal:function(t){var e=t%10,i=1===~~(t%100/10)?"th":1===e?"st":2===e?"nd":3===e?"rd":"th";return t+i}}),B&&(i.exports=H),"undefined"==typeof ender&&(this.moment=H),"function"==typeof t&&t.amd&&t("moment",[],function(){return H})}).call(this)},{}],3:[function(e,i,n){function s(){this.subscriptions=[]}function o(t){if(this.id=O.randomUUID(),this.options=t||{},this.data={},this.fieldId=this.options.fieldId||"id",this.convert={},this.options.convert)for(var e in this.options.convert)if(this.options.convert.hasOwnProperty(e)){var i=this.options.convert[e];this.convert[e]="Date"==i||"ISODate"==i||"ASPDate"==i?"Date":i +}this.subscribers={},this.internalIds={}}function r(t,e){this.id=O.randomUUID(),this.data=null,this.ids={},this.options=e||{},this.fieldId="id",this.subscribers={};var i=this;this.listener=function(){i._onEvent.apply(i,arguments)},this.setData(t)}function a(t,e){this.parent=t,this.options=e||{},this.defaultOptions={order:function(t,e){if(t instanceof y){if(e instanceof y){var i=t.data.end-t.data.start,n=e.data.end-e.data.start;return i-n||t.data.start-e.data.start}return-1}return e instanceof y?1:t.data.start-e.data.start},margin:{item:10}},this.ordered=[]}function h(t){this.id=O.randomUUID(),this.start=0,this.end=0,this.options={min:null,max:null,zoomMin:null,zoomMax:null},this.listeners=[],this.setOptions(t)}function d(){this.id=O.randomUUID(),this.components={},this.repaintTimer=void 0,this.reflowTimer=void 0}function l(){this.id=null,this.parent=null,this.depends=null,this.controller=null,this.options=null,this.frame=null,this.top=0,this.left=0,this.width=0,this.height=0}function p(t,e,i){this.id=O.randomUUID(),this.parent=t,this.depends=e,this.options=i||{}}function c(t,e){this.id=O.randomUUID(),this.container=t,this.options=e||{},this.defaultOptions={autoResize:!0},this.listeners={}}function u(t,e,i){this.id=O.randomUUID(),this.parent=t,this.depends=e,this.dom={majorLines:[],majorTexts:[],minorLines:[],minorTexts:[],redundant:{majorLines:[],majorTexts:[],minorLines:[],minorTexts:[]}},this.props={range:{start:0,end:0,minimumStep:0},lineTop:0},this.options=i||{},this.defaultOptions={orientation:"bottom",showMinorLabels:!0,showMajorLabels:!0},this.conversion=null,this.range=null}function f(t,e,i){this.id=O.randomUUID(),this.parent=t,this.depends=e,this.options=i||{},this.defaultOptions={type:"box",align:"center",orientation:"bottom",margin:{axis:20,item:10},padding:5},this.dom={};var n=this;this.itemsData=null,this.range=null,this.listeners={add:function(t,e,i){i!=n.id&&n._onAdd(e.items)},update:function(t,e,i){i!=n.id&&n._onUpdate(e.items)},remove:function(t,e,i){i!=n.id&&n._onRemove(e.items)}},this.items={},this.queue={},this.stack=new a(this,Object.create(this.options)),this.conversion=null}function m(t,e,i,n){this.parent=t,this.data=e,this.dom=null,this.options=i||{},this.defaultOptions=n||{},this.selected=!1,this.visible=!1,this.top=0,this.left=0,this.width=0,this.height=0}function g(t,e,i,n){this.props={dot:{left:0,top:0,width:0,height:0},line:{top:0,left:0,width:0,height:0}},m.call(this,t,e,i,n)}function v(t,e,i,n){this.props={dot:{top:0,width:0,height:0},content:{height:0,marginLeft:0}},m.call(this,t,e,i,n)}function y(t,e,i,n){this.props={content:{left:0,width:0}},m.call(this,t,e,i,n)}function b(t,e,i){this.id=O.randomUUID(),this.parent=t,this.groupId=e,this.itemset=null,this.options=i||{},this.options.top=0,this.props={label:{width:0,height:0}},this.top=0,this.left=0,this.width=0,this.height=0}function w(t,e,i){this.id=O.randomUUID(),this.parent=t,this.depends=e,this.options=i||{},this.range=null,this.itemsData=null,this.groupsData=null,this.groups={},this.dom={},this.props={labels:{width:0}},this.queue={};var n=this;this.listeners={add:function(t,e){n._onAdd(e.items)},update:function(t,e){n._onUpdate(e.items)},remove:function(t,e){n._onRemove(e.items)}}}function _(t,e,i){var n=this;if(this.options=O.extend({orientation:"bottom",min:null,max:null,zoomMin:10,zoomMax:31536e10,showMinorLabels:!0,showMajorLabels:!0,autoResize:!1},i),this.controller=new d,!t)throw Error("No container element provided");var s=Object.create(this.options);s.height=function(){return n.options.height?n.options.height:n.timeaxis.height+n.content.height},this.rootPanel=new c(t,s),this.controller.add(this.rootPanel);var o=Object.create(this.options);o.left=function(){return n.labelPanel.width},o.width=function(){return n.rootPanel.width-n.labelPanel.width},o.top=null,o.height=null,this.itemPanel=new p(this.rootPanel,[],o),this.controller.add(this.itemPanel);var r=Object.create(this.options);r.top=null,r.left=null,r.height=null,r.width=function(){return n.content&&"function"==typeof n.content.getLabelsWidth?n.content.getLabelsWidth():0},this.labelPanel=new p(this.rootPanel,[],r),this.controller.add(this.labelPanel);var a=M().hours(0).minutes(0).seconds(0).milliseconds(0);this.range=new h({start:a.clone().add("days",-3).valueOf(),end:a.clone().add("days",4).valueOf()}),this.range.subscribe(this.rootPanel,"move","horizontal"),this.range.subscribe(this.rootPanel,"zoom","horizontal"),this.range.on("rangechange",function(){var t=!0;n.controller.requestReflow(t)}),this.range.on("rangechanged",function(){var t=!0;n.controller.requestReflow(t)});var l=Object.create(s);l.range=this.range,l.left=null,l.top=null,l.width="100%",l.height=null,this.timeaxis=new u(this.itemPanel,[],l),this.timeaxis.setRange(this.range),this.controller.add(this.timeaxis),this.setGroups(null),this.itemsData=null,this.groupsData=null,e&&this.setItems(e)}function E(t,e,i,n){this.selected=!1,this.edges=[],this.group=n.nodes.group,this.fontSize=n.nodes.fontSize,this.fontFace=n.nodes.fontFace,this.fontColor=n.nodes.fontColor,this.color=n.nodes.color,this.id=void 0,this.shape=n.nodes.shape,this.image=n.nodes.image,this.x=0,this.y=0,this.xFixed=!1,this.yFixed=!1,this.radius=n.nodes.radius,this.radiusFixed=!1,this.radiusMin=n.nodes.radiusMin,this.radiusMax=n.nodes.radiusMax,this.imagelist=e,this.grouplist=i,this.setProperties(t,n),this.mass=50,this.fx=0,this.fy=0,this.vx=0,this.vy=0,this.minForce=n.minForce,this.damping=.9}function T(t,e,i){if(!e)throw"No graph provided";this.graph=e,this.widthMin=i.edges.widthMin,this.widthMax=i.edges.widthMax,this.id=void 0,this.fromId=void 0,this.toId=void 0,this.style=i.edges.style,this.title=void 0,this.width=i.edges.width,this.value=void 0,this.length=i.edges.length,this.from=null,this.to=null,this.connected=!1,this.dash=O.extend({},i.edges.dash),this.stiffness=void 0,this.color=i.edges.color,this.widthFixed=!1,this.lengthFixed=!1,this.setProperties(t,i)}function x(t,e,i,n){this.container=t?t:document.body,this.x=0,this.y=0,this.padding=5,void 0!==e&&void 0!==i&&this.setPosition(e,i),void 0!==n&&this.setText(n),this.frame=document.createElement("div");var s=this.frame.style;s.position="absolute",s.visibility="hidden",s.border="1px solid #666",s.color="black",s.padding=this.padding+"px",s.backgroundColor="#FFFFC6",s.borderRadius="3px",s.MozBorderRadius="3px",s.WebkitBorderRadius="3px",s.boxShadow="3px 3px 10px rgba(128, 128, 128, 0.5)",s.whiteSpace="nowrap",this.container.appendChild(this.frame)}function S(t,e,i){this.containerElement=t,this.width="100%",this.height="100%",this.refreshRate=50,this.stabilize=!0,this.selectable=!0,this.constants={nodes:{radiusMin:5,radiusMax:20,radius:5,distance:100,shape:"ellipse",image:void 0,widthMin:16,widthMax:64,fontColor:"black",fontSize:14,fontFace:"arial",color:{border:"#2B7CE9",background:"#97C2FC",highlight:{border:"#2B7CE9",background:"#D2E5FF"}},borderColor:"#2B7CE9",backgroundColor:"#97C2FC",highlightColor:"#D2E5FF",group:void 0},edges:{widthMin:1,widthMax:15,width:1,style:"line",color:"#343434",fontColor:"#343434",fontSize:14,fontFace:"arial",length:100,dash:{length:10,gap:5,altLength:void 0}},minForce:.05,minVelocity:.02,maxIterations:1e3};var n=this;this.nodes={},this.edges={},this.nodesData=null,this.edgesData=null;var s=this;this.nodesListeners={add:function(t,e){s._addNodes(e.items),s.start()},update:function(t,e){s._updateNodes(e.items),s.start()},remove:function(t,e){s._removeNodes(e.items),s.start()}},this.edgesListeners={add:function(t,e){s._addEdges(e.items),s.start()},update:function(t,e){s._updateEdges(e.items),s.start()},remove:function(t,e){s._removeEdges(e.items),s.start()}},this.groups=new Groups,this.images=new Images,this.images.setOnloadCallback(function(){n._redraw()}),this.moving=!1,this.selection=[],this.timer=void 0,this._create(),this.setOptions(i),this.setData(e)}var M="undefined"!=typeof window&&window.moment||e("moment"),D="undefined"!=typeof window&&window.Hammer||e("hammerjs");if(!Array.prototype.indexOf){Array.prototype.indexOf=function(t){for(var e=0;this.length>e;e++)if(this[e]==t)return e;return-1};try{console.log("Warning: Ancient browser detected. Please update your browser")}catch(C){}}Array.prototype.forEach||(Array.prototype.forEach=function(t,e){for(var i=0,n=this.length;n>i;++i)t.call(e||this,this[i],i,this)}),Array.prototype.map||(Array.prototype.map=function(t,e){var i,n,s;if(null==this)throw new TypeError(" this is null or not defined");var o=Object(this),r=o.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(e&&(i=e),n=Array(r),s=0;r>s;){var a,h;s in o&&(a=o[s],h=t.call(i,a,s,o),n[s]=h),s++}return n}),Array.prototype.filter||(Array.prototype.filter=function(t){"use strict";if(null==this)throw new TypeError;var e=Object(this),i=e.length>>>0;if("function"!=typeof t)throw new TypeError;for(var n=[],s=arguments[1],o=0;i>o;o++)if(o in e){var r=e[o];t.call(s,r,o,e)&&n.push(r)}return n}),Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,e=!{toString:null}.propertyIsEnumerable("toString"),i=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],n=i.length;return function(s){if("object"!=typeof s&&"function"!=typeof s||null===s)throw new TypeError("Object.keys called on non-object");var o=[];for(var r in s)t.call(s,r)&&o.push(r);if(e)for(var a=0;n>a;a++)t.call(s,i[a])&&o.push(i[a]);return o}}()),Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s}),Object.create||(Object.create=function(t){function e(){}if(arguments.length>1)throw Error("Object.create implementation only accepts the first parameter.");return e.prototype=t,new e}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s});var O={};O.isNumber=function(t){return t instanceof Number||"number"==typeof t},O.isString=function(t){return t instanceof String||"string"==typeof t},O.isDate=function(t){if(t instanceof Date)return!0;if(O.isString(t)){var e=N.exec(t);if(e)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},O.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},O.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},O.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var n=arguments[e];for(var s in n)n.hasOwnProperty(s)&&void 0!==n[s]&&(t[s]=n[s])}return t},O.convert=function(t,e){var i;if(void 0===t)return void 0;if(null===t)return null;if(!e)return t;if("string"!=typeof e&&!(e instanceof String))throw Error("Type must be a string");switch(e){case"boolean":case"Boolean":return Boolean(t);case"number":case"Number":return Number(t.valueOf());case"string":case"String":return t+"";case"Date":if(O.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(M.isMoment(t))return new Date(t.valueOf());if(O.isString(t))return i=N.exec(t),i?new Date(Number(i[1])):M(t).toDate();throw Error("Cannot convert object of type "+O.getType(t)+" to type Date");case"Moment":if(O.isNumber(t))return M(t);if(t instanceof Date)return M(t.valueOf());if(M.isMoment(t))return M.clone();if(O.isString(t))return i=N.exec(t),i?M(Number(i[1])):M(t);throw Error("Cannot convert object of type "+O.getType(t)+" to type Date");case"ISODate":if(O.isNumber(t))return new Date(t);if(t instanceof Date)return t.toISOString();if(M.isMoment(t))return t.toDate().toISOString();if(O.isString(t))return i=N.exec(t),i?new Date(Number(i[1])).toISOString():new Date(t).toISOString();throw Error("Cannot convert object of type "+O.getType(t)+" to type ISODate");case"ASPDate":if(O.isNumber(t))return"/Date("+t+")/";if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(O.isString(t)){i=N.exec(t);var n;return n=i?new Date(Number(i[1])).valueOf():new Date(t).valueOf(),"/Date("+n+")/"}throw Error("Cannot convert object of type "+O.getType(t)+" to type ASPDate");default:throw Error("Cannot convert object of type "+O.getType(t)+' to type "'+e+'"')}};var N=/^\/?Date\((\-?\d+)/i;O.getType=function(t){var e=typeof t;return"object"==e?null==t?"null":t instanceof Boolean?"Boolean":t instanceof Number?"Number":t instanceof String?"String":t instanceof Array?"Array":t instanceof Date?"Date":"Object":"number"==e?"Number":"boolean"==e?"Boolean":"string"==e?"String":e},O.getAbsoluteLeft=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetLeft,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetLeft,n-=s.scrollLeft,s=s.offsetParent;return n},O.getAbsoluteTop=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetTop,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetTop,n-=s.scrollTop,s=s.offsetParent;return n},O.getPageY=function(t){if("pageY"in t)return t.pageY;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientY:t.clientY;var i=document.documentElement,n=document.body;return e+(i&&i.scrollTop||n&&n.scrollTop||0)-(i&&i.clientTop||n&&n.clientTop||0)},O.getPageX=function(t){if("pageY"in t)return t.pageX;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientX:t.clientX;var i=document.documentElement,n=document.body;return e+(i&&i.scrollLeft||n&&n.scrollLeft||0)-(i&&i.clientLeft||n&&n.clientLeft||0)},O.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},O.removeClassName=function(t,e){var i=t.className.split(" "),n=i.indexOf(e);-1!=n&&(i.splice(n,1),t.className=i.join(" "))},O.forEach=function(t,e){var i,n;if(t instanceof Array)for(i=0,n=t.length;n>i;i++)e(t[i],i,t);else for(i in t)t.hasOwnProperty(i)&&e(t[i],i,t)},O.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},O.addEventListener=function(t,e,i,n){t.addEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.addEventListener(e,i,n)):t.attachEvent("on"+e,i)},O.removeEventListener=function(t,e,i,n){t.removeEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.removeEventListener(e,i,n)):t.detachEvent("on"+e,i)},O.getTarget=function(t){t||(t=window.event);var e;return t.target?e=t.target:t.srcElement&&(e=t.srcElement),void 0!=e.nodeType&&3==e.nodeType&&(e=e.parentNode),e},O.stopPropagation=function(t){t||(t=window.event),t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},O.preventDefault=function(t){t||(t=window.event),t.preventDefault?t.preventDefault():t.returnValue=!1},O.option={},O.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},O.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},O.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?t+"":e||null},O.option.asSize=function(t,e){return"function"==typeof t&&(t=t()),O.isString(t)?t:O.isNumber(t)?t+"px":e||null},O.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null},O.loadCss=function(t){if("undefined"!=typeof document){var e=document.createElement("style");e.type="text/css",e.styleSheet?e.styleSheet.cssText=t:e.appendChild(document.createTextNode(t)),document.getElementsByTagName("head")[0].appendChild(e)}};var L={listeners:[],indexOf:function(t){for(var e=this.listeners,i=0,n=this.listeners.length;n>i;i++){var s=e[i];if(s&&s.object==t)return i}return-1},addListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];s||(s={object:t,events:{}},this.listeners.push(s));var o=s.events[e];o||(o=[],s.events[e]=o),-1==o.indexOf(i)&&o.push(i)},removeListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];o&&(n=o.indexOf(i),-1!=n&&o.splice(n,1),0==o.length&&delete s.events[e]);var r=0,a=s.events;for(var h in a)a.hasOwnProperty(h)&&r++;0==r&&delete this.listeners[n]}},removeAllListeners:function(){this.listeners=[]},trigger:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];if(o)for(var r=0,a=o.length;a>r;r++)o[r](i)}}};s.prototype.on=function(t,e,i){var n=t instanceof RegExp?t:RegExp(t.replace("*","\\w+")),s={id:O.randomUUID(),event:t,regexp:n,callback:"function"==typeof e?e:null,target:i};return this.subscriptions.push(s),s.id},s.prototype.off=function(t){for(var e=0;this.subscriptions.length>e;){var i=this.subscriptions[e],n=!0;if(t instanceof Object)for(var s in t)t.hasOwnProperty(s)&&t[s]!==i[s]&&(n=!1);else n=i.id==t;n?this.subscriptions.splice(e,1):e++}},s.prototype.emit=function(t,e,i){for(var n=0;this.subscriptions.length>n;n++){var s=this.subscriptions[n];s.regexp.test(t)&&s.callback&&s.callback(t,e,i)}},o.prototype.subscribe=function(t,e){var i=this.subscribers[t];i||(i=[],this.subscribers[t]=i),i.push({callback:e})},o.prototype.unsubscribe=function(t,e){var i=this.subscribers[t];i&&(this.subscribers[t]=i.filter(function(t){return t.callback!=e}))},o.prototype._trigger=function(t,e,i){if("*"==t)throw Error("Cannot trigger event *");var n=[];t in this.subscribers&&(n=n.concat(this.subscribers[t])),"*"in this.subscribers&&(n=n.concat(this.subscribers["*"]));for(var s=0;n.length>s;s++){var o=n[s];o.callback&&o.callback(t,e,i||null)}},o.prototype.add=function(t,e){var i,n=[],s=this;if(t instanceof Array)for(var o=0,r=t.length;r>o;o++)i=s._addItem(t[o]),n.push(i);else if(O.isDataTable(t))for(var a=this._getColumnNames(t),h=0,d=t.getNumberOfRows();d>h;h++){for(var l={},p=0,c=a.length;c>p;p++){var u=a[p];l[u]=t.getValue(h,p)}i=s._addItem(l),n.push(i)}else{if(!(t instanceof Object))throw Error("Unknown dataType");i=s._addItem(t),n.push(i)}return n.length&&this._trigger("add",{items:n},e),n},o.prototype.update=function(t,e){var i=[],n=[],s=this,o=s.fieldId,r=function(t){var e=t[o];s.data[e]?(e=s._updateItem(t),n.push(e)):(e=s._addItem(t),i.push(e))};if(t instanceof Array)for(var a=0,h=t.length;h>a;a++)r(t[a]);else if(O.isDataTable(t))for(var d=this._getColumnNames(t),l=0,p=t.getNumberOfRows();p>l;l++){for(var c={},u=0,f=d.length;f>u;u++){var m=d[u];c[m]=t.getValue(l,u)}r(c)}else{if(!(t instanceof Object))throw Error("Unknown dataType");r(t)}return i.length&&this._trigger("add",{items:i},e),n.length&&this._trigger("update",{items:n},e),i.concat(n)},o.prototype.get=function(){var t,e,i,n,s=this,o=O.getType(arguments[0]);"String"==o||"Number"==o?(t=arguments[0],i=arguments[1],n=arguments[2]):"Array"==o?(e=arguments[0],i=arguments[1],n=arguments[2]):(i=arguments[0],n=arguments[1]);var r;if(i&&i.type){if(r="DataTable"==i.type?"DataTable":"Array",n&&r!=O.getType(n))throw Error('Type of parameter "data" ('+O.getType(n)+") "+"does not correspond with specified options.type ("+i.type+")");if("DataTable"==r&&!O.isDataTable(n))throw Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else r=n?"DataTable"==O.getType(n)?"DataTable":"Array":"Array";var a,h,d,l,p=i&&i.convert||this.options.convert,c=i&&i.filter,u=[];if(void 0!=t)a=s._getItem(t,p),c&&!c(a)&&(a=null);else if(void 0!=e)for(d=0,l=e.length;l>d;d++)a=s._getItem(e[d],p),(!c||c(a))&&u.push(a);else for(h in this.data)this.data.hasOwnProperty(h)&&(a=s._getItem(h,p),(!c||c(a))&&u.push(a));if(i&&i.order&&void 0==t&&this._sort(u,i.order),i&&i.fields){var f=i.fields;if(void 0!=t)a=this._filterFields(a,f);else for(d=0,l=u.length;l>d;d++)u[d]=this._filterFields(u[d],f)}if("DataTable"==r){var m=this._getColumnNames(n);if(void 0!=t)s._appendRow(n,m,a);else for(d=0,l=u.length;l>d;d++)s._appendRow(n,m,u[d]);return n}if(void 0!=t)return a;if(n){for(d=0,l=u.length;l>d;d++)n.push(u[d]);return n}return u},o.prototype.getIds=function(t){var e,i,n,s,o,r=this.data,a=t&&t.filter,h=t&&t.order,d=t&&t.convert||this.options.convert,l=[];if(a)if(h){o=[];for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,d),a(s)&&o.push(s));for(this._sort(o,h),e=0,i=o.length;i>e;e++)l[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,d),a(s)&&l.push(s[this.fieldId]));else if(h){o=[];for(n in r)r.hasOwnProperty(n)&&o.push(r[n]);for(this._sort(o,h),e=0,i=o.length;i>e;e++)l[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=r[n],l.push(s[this.fieldId]));return l},o.prototype.forEach=function(t,e){var i,n,s=e&&e.filter,o=e&&e.convert||this.options.convert,r=this.data;if(e&&e.order)for(var a=this.get(e),h=0,d=a.length;d>h;h++)i=a[h],n=i[this.fieldId],t(i,n);else for(n in r)r.hasOwnProperty(n)&&(i=this._getItem(n,o),(!s||s(i))&&t(i,n))},o.prototype.map=function(t,e){var i,n=e&&e.filter,s=e&&e.convert||this.options.convert,o=[],r=this.data;for(var a in r)r.hasOwnProperty(a)&&(i=this._getItem(a,s),(!n||n(i))&&o.push(t(i,a)));return e&&e.order&&this._sort(o,e.order),o},o.prototype._filterFields=function(t,e){var i={};for(var n in t)t.hasOwnProperty(n)&&-1!=e.indexOf(n)&&(i[n]=t[n]);return i},o.prototype._sort=function(t,e){if(O.isString(e)){var i=e;t.sort(function(t,e){var n=t[i],s=e[i];return n>s?1:s>n?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},o.prototype.remove=function(t,e){var i,n,s,o=[];if(t instanceof Array)for(i=0,n=t.length;n>i;i++)s=this._remove(t[i]),null!=s&&o.push(s);else s=this._remove(t),null!=s&&o.push(s);return o.length&&this._trigger("remove",{items:o},e),o},o.prototype._remove=function(t){if(O.isNumber(t)||O.isString(t)){if(this.data[t])return delete this.data[t],delete this.internalIds[t],t}else if(t instanceof Object){var e=t[this.fieldId];if(e&&this.data[e])return delete this.data[e],delete this.internalIds[e],e}return null},o.prototype.clear=function(t){var e=Object.keys(this.data);return this.data={},this.internalIds={},this._trigger("remove",{items:e},t),e},o.prototype.max=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||r>n)&&(i=o,n=r)}return i},o.prototype.min=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||n>r)&&(i=o,n=r)}return i},o.prototype.distinct=function(t){var e=this.data,i=[],n=this.options.convert[t],s=0;for(var o in e)if(e.hasOwnProperty(o)){for(var r=e[o],a=O.convert(r[t],n),h=!1,d=0;s>d;d++)if(i[d]==a){h=!0;break}h||(i[s]=a,s++)}return i},o.prototype._addItem=function(t){var e=t[this.fieldId];if(void 0!=e){if(this.data[e])throw Error("Cannot add item: item with id "+e+" already exists")}else e=O.randomUUID(),t[this.fieldId]=e,this.internalIds[e]=t;var i={};for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=O.convert(t[n],s)}return this.data[e]=i,e},o.prototype._getItem=function(t,e){var i,n,s=this.data[t];if(!s)return null;var o={},r=this.fieldId,a=this.internalIds;if(e)for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a||(o[i]=O.convert(n,e[i])));else for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a||(o[i]=n));return o},o.prototype._updateItem=function(t){var e=t[this.fieldId];if(void 0==e)throw Error("Cannot update item: item has no id (item: "+JSON.stringify(t)+")");var i=this.data[e];if(!i)throw Error("Cannot update item: no item with id "+e+" found");for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=O.convert(t[n],s)}return e},o.prototype._getColumnNames=function(t){for(var e=[],i=0,n=t.getNumberOfColumns();n>i;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},o.prototype._appendRow=function(t,e,i){for(var n=t.addRow(),s=0,o=e.length;o>s;s++){var r=e[s];t.setValue(n,s,i[r])}},r.prototype.setData=function(t){var e,i,n;if(this.data){this.data.unsubscribe&&this.data.unsubscribe("*",this.listener),e=[];for(var s in this.ids)this.ids.hasOwnProperty(s)&&e.push(s);this.ids={},this._trigger("remove",{items:e})}if(this.data=t,this.data){for(this.fieldId=this.options.fieldId||this.data&&this.data.options&&this.data.options.fieldId||"id",e=this.data.getIds({filter:this.options&&this.options.filter}),i=0,n=e.length;n>i;i++)s=e[i],this.ids[s]=!0;this._trigger("add",{items:e}),this.data.subscribe&&this.data.subscribe("*",this.listener)}},r.prototype.get=function(){var t,e,i,n=this,s=O.getType(arguments[0]);"String"==s||"Number"==s||"Array"==s?(t=arguments[0],e=arguments[1],i=arguments[2]):(e=arguments[0],i=arguments[1]);var o=O.extend({},this.options,e);this.options.filter&&e&&e.filter&&(o.filter=function(t){return n.options.filter(t)&&e.filter(t)});var r=[];return void 0!=t&&r.push(t),r.push(o),r.push(i),this.data&&this.data.get.apply(this.data,r)},r.prototype.getIds=function(t){var e;if(this.data){var i,n=this.options.filter;i=t&&t.filter?n?function(e){return n(e)&&t.filter(e)}:t.filter:n,e=this.data.getIds({filter:i,order:t&&t.order})}else e=[];return e},r.prototype._onEvent=function(t,e,i){var n,s,o,r,a=e&&e.items,h=this.data,d=[],l=[],p=[];if(a&&h){switch(t){case"add":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r&&(this.ids[o]=!0,d.push(o));break;case"update":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r?this.ids[o]?l.push(o):(this.ids[o]=!0,d.push(o)):this.ids[o]&&(delete this.ids[o],p.push(o));break;case"remove":for(n=0,s=a.length;s>n;n++)o=a[n],this.ids[o]&&(delete this.ids[o],p.push(o))}d.length&&this._trigger("add",{items:d},i),l.length&&this._trigger("update",{items:l},i),p.length&&this._trigger("remove",{items:p},i)}},r.prototype.subscribe=o.prototype.subscribe,r.prototype.unsubscribe=o.prototype.unsubscribe,r.prototype._trigger=o.prototype._trigger,TimeStep=function(t,e,i){this.current=new Date,this._start=new Date,this._end=new Date,this.autoScale=!0,this.scale=TimeStep.SCALE.DAY,this.step=1,this.setRange(t,e,i)},TimeStep.SCALE={MILLISECOND:1,SECOND:2,MINUTE:3,HOUR:4,DAY:5,WEEKDAY:6,MONTH:7,YEAR:8},TimeStep.prototype.setRange=function(t,e,i){t instanceof Date&&e instanceof Date&&(this._start=void 0!=t?new Date(t.valueOf()):new Date,this._end=void 0!=e?new Date(e.valueOf()):new Date,this.autoScale&&this.setMinimumStep(i))},TimeStep.prototype.first=function(){this.current=new Date(this._start.valueOf()),this.roundToMinor()},TimeStep.prototype.roundToMinor=function(){switch(this.scale){case TimeStep.SCALE.YEAR:this.current.setFullYear(this.step*Math.floor(this.current.getFullYear()/this.step)),this.current.setMonth(0);case TimeStep.SCALE.MONTH:this.current.setDate(1);case TimeStep.SCALE.DAY:case TimeStep.SCALE.WEEKDAY:this.current.setHours(0);case TimeStep.SCALE.HOUR:this.current.setMinutes(0);case TimeStep.SCALE.MINUTE:this.current.setSeconds(0);case TimeStep.SCALE.SECOND:this.current.setMilliseconds(0)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.setMilliseconds(this.current.getMilliseconds()-this.current.getMilliseconds()%this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()-this.current.getSeconds()%this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()-this.current.getMinutes()%this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()-this.current.getHours()%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()-1-(this.current.getDate()-1)%this.step+1);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()-this.current.getMonth()%this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()-this.current.getFullYear()%this.step);break;default:}},TimeStep.prototype.hasNext=function(){return this.current.valueOf()<=this._end.valueOf()},TimeStep.prototype.next=function(){var t=this.current.valueOf();if(6>this.current.getMonth())switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current=new Date(this.current.valueOf()+1e3*this.step);break;case TimeStep.SCALE.MINUTE:this.current=new Date(this.current.valueOf()+60*1e3*this.step);break;case TimeStep.SCALE.HOUR:this.current=new Date(this.current.valueOf()+60*60*1e3*this.step);var e=this.current.getHours();this.current.setHours(e-e%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step);break;default:}else switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()+this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()+this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()+this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step);break;default:}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.getMilliseconds()0&&(this.step=e),this.autoScale=!1},TimeStep.prototype.setAutoScale=function(t){this.autoScale=t},TimeStep.prototype.setMinimumStep=function(t){if(void 0!=t){var e=31104e6,i=2592e6,n=864e5,s=36e5,o=6e4,r=1e3,a=1;1e3*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1e3),500*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=500),100*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=100),50*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=50),10*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=10),5*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=5),e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1),3*i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=3),i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=1),5*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=5),2*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=2),n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=1),n/2>t&&(this.scale=TimeStep.SCALE.WEEKDAY,this.step=1),4*s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=4),s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=1),15*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=15),10*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=10),5*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=5),o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=1),15*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=15),10*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=10),5*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=5),r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=1),200*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=200),100*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=100),50*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=50),10*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=10),5*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=5),a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=1) +}},TimeStep.prototype.snap=function(t){if(this.scale==TimeStep.SCALE.YEAR){var e=t.getFullYear()+Math.round(t.getMonth()/12);t.setFullYear(Math.round(e/this.step)*this.step),t.setMonth(0),t.setDate(0),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MONTH)t.getDate()>15?(t.setDate(1),t.setMonth(t.getMonth()+1)):t.setDate(1),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0);else if(this.scale==TimeStep.SCALE.DAY||this.scale==TimeStep.SCALE.WEEKDAY){switch(this.step){case 5:case 2:t.setHours(24*Math.round(t.getHours()/24));break;default:t.setHours(12*Math.round(t.getHours()/12))}t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.HOUR){switch(this.step){case 4:t.setMinutes(60*Math.round(t.getMinutes()/60));break;default:t.setMinutes(30*Math.round(t.getMinutes()/30))}t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MINUTE){switch(this.step){case 15:case 10:t.setMinutes(5*Math.round(t.getMinutes()/5)),t.setSeconds(0);break;case 5:t.setSeconds(60*Math.round(t.getSeconds()/60));break;default:t.setSeconds(30*Math.round(t.getSeconds()/30))}t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.SECOND)switch(this.step){case 15:case 10:t.setSeconds(5*Math.round(t.getSeconds()/5)),t.setMilliseconds(0);break;case 5:t.setMilliseconds(1e3*Math.round(t.getMilliseconds()/1e3));break;default:t.setMilliseconds(500*Math.round(t.getMilliseconds()/500))}else if(this.scale==TimeStep.SCALE.MILLISECOND){var i=this.step>5?this.step/2:1;t.setMilliseconds(Math.round(t.getMilliseconds()/i)*i)}},TimeStep.prototype.isMajor=function(){switch(this.scale){case TimeStep.SCALE.MILLISECOND:return 0==this.current.getMilliseconds();case TimeStep.SCALE.SECOND:return 0==this.current.getSeconds();case TimeStep.SCALE.MINUTE:return 0==this.current.getHours()&&0==this.current.getMinutes();case TimeStep.SCALE.HOUR:return 0==this.current.getHours();case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return 1==this.current.getDate();case TimeStep.SCALE.MONTH:return 0==this.current.getMonth();case TimeStep.SCALE.YEAR:return!1;default:return!1}},TimeStep.prototype.getLabelMinor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return M(t).format("SSS");case TimeStep.SCALE.SECOND:return M(t).format("s");case TimeStep.SCALE.MINUTE:return M(t).format("HH:mm");case TimeStep.SCALE.HOUR:return M(t).format("HH:mm");case TimeStep.SCALE.WEEKDAY:return M(t).format("ddd D");case TimeStep.SCALE.DAY:return M(t).format("D");case TimeStep.SCALE.MONTH:return M(t).format("MMM");case TimeStep.SCALE.YEAR:return M(t).format("YYYY");default:return""}},TimeStep.prototype.getLabelMajor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return M(t).format("HH:mm:ss");case TimeStep.SCALE.SECOND:return M(t).format("D MMMM HH:mm");case TimeStep.SCALE.MINUTE:case TimeStep.SCALE.HOUR:return M(t).format("ddd D MMMM");case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return M(t).format("MMMM YYYY");case TimeStep.SCALE.MONTH:return M(t).format("YYYY");case TimeStep.SCALE.YEAR:return"";default:return""}},a.prototype.setOptions=function(t){O.extend(this.options,t)},a.prototype.update=function(){this._order(),this._stack()},a.prototype._order=function(){var t=this.parent.items;if(!t)throw Error("Cannot stack items: parent does not contain items");var e=[],i=0;O.forEach(t,function(t){t.visible&&(e[i]=t,i++)});var n=this.options.order||this.defaultOptions.order;if("function"!=typeof n)throw Error("Option order must be a function");e.sort(n),this.ordered=e},a.prototype._stack=function(){var t,e,i,n=this.ordered,s=this.options,o=s.orientation||this.defaultOptions.orientation,r="top"==o;for(i=s.margin&&void 0!==s.margin.item?s.margin.item:this.defaultOptions.margin.item,t=0,e=n.length;e>t;t++){var a=n[t],h=null;do h=this.checkOverlap(n,t,0,t-1,i),null!=h&&(a.top=r?h.top+h.height+i:h.top-a.height-i);while(h)}},a.prototype.checkOverlap=function(t,e,i,n,s){for(var o=this.collision,r=t[e],a=n;a>=i;a--){var h=t[a];if(o(r,h,s)&&a!=e)return h}return null},a.prototype.collision=function(t,e,i){return t.left-ie.left&&t.top-ie.top},h.prototype.setOptions=function(t){O.extend(this.options,t),(null!=t.start||null!=t.end)&&this.setRange(t.start,t.end)},h.prototype.subscribe=function(t,e,i){var n,s=this;if("horizontal"!=i&&"vertical"!=i)throw new TypeError('Unknown direction "'+i+'". '+'Choose "horizontal" or "vertical".');if("move"==e)n={component:t,event:e,direction:i,callback:function(t){s._onMouseDown(t,n)},params:{}},t.on("mousedown",n.callback),s.listeners.push(n);else{if("zoom"!=e)throw new TypeError('Unknown event "'+e+'". '+'Choose "move" or "zoom".');n={component:t,event:e,direction:i,callback:function(t){s._onMouseWheel(t,n)},params:{}},t.on("mousewheel",n.callback),s.listeners.push(n)}},h.prototype.on=function(t,e){L.addListener(this,t,e)},h.prototype._trigger=function(t){L.trigger(this,t,{start:this.start,end:this.end})},h.prototype.setRange=function(t,e){var i=this._applyRange(t,e);i&&(this._trigger("rangechange"),this._trigger("rangechanged"))},h.prototype._applyRange=function(t,e){var i,n=null!=t?O.convert(t,"Number"):this.start,s=null!=e?O.convert(e,"Number"):this.end;if(isNaN(n))throw Error('Invalid start "'+t+'"');if(isNaN(s))throw Error('Invalid end "'+e+'"');if(n>s&&(s=n),null!=this.options.min){var o=this.options.min.valueOf();o>n&&(i=o-n,n+=i,s+=i)}if(null!=this.options.max){var r=this.options.max.valueOf();s>r&&(i=s-r,n-=i,s-=i)}if(null!=this.options.zoomMin){var a=this.options.zoomMin.valueOf();0>a&&(a=0),a>s-n&&(this.end-this.start>a?(i=a-(s-n),n-=i/2,s+=i/2):(n=this.start,s=this.end))}if(null!=this.options.zoomMax){var h=this.options.zoomMax.valueOf();0>h&&(h=0),s-n>h&&(h>this.end-this.start?(i=s-n-h,n+=i/2,s-=i/2):(n=this.start,s=this.end))}var d=this.start!=n||this.end!=s;return this.start=n,this.end=s,d},h.prototype.getRange=function(){return{start:this.start,end:this.end}},h.prototype.conversion=function(t){return this.start,this.end,h.conversion(this.start,this.end,t)},h.conversion=function(t,e,i){return 0!=i&&0!=e-t?{offset:t,factor:i/(e-t)}:{offset:0,factor:1}},h.prototype._onMouseDown=function(t,e){t=t||window.event;var i=e.params,n=t.which?1==t.which:1==t.button;if(n){i.mouseX=O.getPageX(t),i.mouseY=O.getPageY(t),i.previousLeft=0,i.previousOffset=0,i.moved=!1,i.start=this.start,i.end=this.end;var s=e.component.frame;s&&(s.style.cursor="move");var o=this;i.onMouseMove||(i.onMouseMove=function(t){o._onMouseMove(t,e)},O.addEventListener(document,"mousemove",i.onMouseMove)),i.onMouseUp||(i.onMouseUp=function(t){o._onMouseUp(t,e)},O.addEventListener(document,"mouseup",i.onMouseUp)),O.preventDefault(t)}},h.prototype._onMouseMove=function(t,e){t=t||window.event;var i=e.params,n=O.getPageX(t),s=O.getPageY(t);void 0==i.mouseX&&(i.mouseX=n),void 0==i.mouseY&&(i.mouseY=s);var o=n-i.mouseX,r=s-i.mouseY,a="horizontal"==e.direction?o:r;Math.abs(a)>=1&&(i.moved=!0);var h=i.end-i.start,d="horizontal"==e.direction?e.component.width:e.component.height,l=-a/d*h;this._applyRange(i.start+l,i.end+l),this._trigger("rangechange"),O.preventDefault(t)},h.prototype._onMouseUp=function(t,e){t=t||window.event;var i=e.params;e.component.frame&&(e.component.frame.style.cursor="auto"),i.onMouseMove&&(O.removeEventListener(document,"mousemove",i.onMouseMove),i.onMouseMove=null),i.onMouseUp&&(O.removeEventListener(document,"mouseup",i.onMouseUp),i.onMouseUp=null),i.moved&&this._trigger("rangechanged")},h.prototype._onMouseWheel=function(t,e){t=t||window.event;var i=0;if(t.wheelDelta?i=t.wheelDelta/120:t.detail&&(i=-t.detail/3),i){var n=this,s=function(){var s=i/5,o=null,r=e.component.frame;if(r){var a,h;if("horizontal"==e.direction){a=e.component.width,h=n.conversion(a);var d=O.getAbsoluteLeft(r),l=O.getPageX(t);o=(l-d)/h.factor+h.offset}else{a=e.component.height,h=n.conversion(a);var p=O.getAbsoluteTop(r),c=O.getPageY(t);o=(p+a-c-p)/h.factor+h.offset}}n.zoom(s,o)};s()}O.preventDefault(t)},h.prototype.zoom=function(t,e){null==e&&(e=(this.start+this.end)/2),t>=1&&(t=.9),-1>=t&&(t=-.9),0>t&&(t/=1+t);var i=this.start-e,n=this.end-e,s=this.start-i*t,o=this.end-n*t;this.setRange(s,o)},h.prototype.move=function(t){var e=this.end-this.start,i=this.start+e*t,n=this.end+e*t;this.start=i,this.end=n},h.prototype.moveTo=function(t){var e=(this.start+this.end)/2,i=e-t,n=this.start-i,s=this.end-i;this.setRange(n,s)},d.prototype.add=function(t){if(void 0==t.id)throw Error("Component has no field id");if(!(t instanceof l||t instanceof d))throw new TypeError("Component must be an instance of prototype Component or Controller");t.controller=this,this.components[t.id]=t},d.prototype.remove=function(t){var e;for(e in this.components)if(this.components.hasOwnProperty(e)&&(e==t||this.components[e]==t))break;e&&delete this.components[e]},d.prototype.requestReflow=function(t){if(t)this.reflow();else if(!this.reflowTimer){var e=this;this.reflowTimer=setTimeout(function(){e.reflowTimer=void 0,e.reflow()},0)}},d.prototype.requestRepaint=function(t){if(t)this.repaint();else if(!this.repaintTimer){var e=this;this.repaintTimer=setTimeout(function(){e.repaintTimer=void 0,e.repaint()},0)}},d.prototype.repaint=function(){function t(n,s){s in i||(n.depends&&n.depends.forEach(function(e){t(e,e.id)}),n.parent&&t(n.parent,n.parent.id),e=n.repaint()||e,i[s]=!0)}var e=!1;this.repaintTimer&&(clearTimeout(this.repaintTimer),this.repaintTimer=void 0);var i={};O.forEach(this.components,t),e&&this.reflow()},d.prototype.reflow=function(){function t(n,s){s in i||(n.depends&&n.depends.forEach(function(e){t(e,e.id)}),n.parent&&t(n.parent,n.parent.id),e=n.reflow()||e,i[s]=!0)}var e=!1;this.reflowTimer&&(clearTimeout(this.reflowTimer),this.reflowTimer=void 0);var i={};O.forEach(this.components,t),e&&this.repaint()},l.prototype.setOptions=function(t){t&&(O.extend(this.options,t),this.controller&&(this.requestRepaint(),this.requestReflow()))},l.prototype.getOption=function(t){var e;return this.options&&(e=this.options[t]),void 0===e&&this.defaultOptions&&(e=this.defaultOptions[t]),e},l.prototype.getContainer=function(){return null},l.prototype.getFrame=function(){return this.frame},l.prototype.repaint=function(){return!1},l.prototype.reflow=function(){return!1},l.prototype.hide=function(){return this.frame&&this.frame.parentNode?(this.frame.parentNode.removeChild(this.frame),!0):!1},l.prototype.show=function(){return this.frame&&this.frame.parentNode?!1:this.repaint()},l.prototype.requestRepaint=function(){if(!this.controller)throw Error("Cannot request a repaint: no controller configured");this.controller.requestRepaint()},l.prototype.requestReflow=function(){if(!this.controller)throw Error("Cannot request a reflow: no controller configured");this.controller.requestReflow()},p.prototype=new l,p.prototype.setOptions=l.prototype.setOptions,p.prototype.getContainer=function(){return this.frame},p.prototype.repaint=function(){var t=0,e=O.updateProperty,i=O.option.asSize,n=this.options,s=this.frame;if(!s){s=document.createElement("div"),s.className="panel";var o=n.className;o&&("function"==typeof o?O.addClassName(s,o()+""):O.addClassName(s,o+"")),this.frame=s,t+=1}if(!s.parentNode){if(!this.parent)throw Error("Cannot repaint panel: no parent attached");var r=this.parent.getContainer();if(!r)throw Error("Cannot repaint panel: parent has no container element");r.appendChild(s),t+=1}return t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),t>0},p.prototype.reflow=function(){var t=0,e=O.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},c.prototype=new p,c.prototype.setOptions=l.prototype.setOptions,c.prototype.repaint=function(){var t=0,e=O.updateProperty,i=O.option.asSize,n=this.options,s=this.frame;if(!s){s=document.createElement("div"),s.className="vis timeline rootpanel";var o=n.className;o&&O.addClassName(s,O.option.asString(o)),this.frame=s,t+=1}if(!s.parentNode){if(!this.container)throw Error("Cannot repaint root panel: no container attached");this.container.appendChild(s),t+=1}return t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),this._updateEventEmitters(),this._updateWatch(),t>0},c.prototype.reflow=function(){var t=0,e=O.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},c.prototype._updateWatch=function(){var t=this.getOption("autoResize");t?this._watch():this._unwatch()},c.prototype._watch=function(){var t=this;this._unwatch();var e=function(){var e=t.getOption("autoResize");return e?(t.frame&&(t.frame.clientWidth!=t.width||t.frame.clientHeight!=t.height)&&t.requestReflow(),void 0):(t._unwatch(),void 0)};O.addEventListener(window,"resize",e),this.watchTimer=setInterval(e,1e3)},c.prototype._unwatch=function(){this.watchTimer&&(clearInterval(this.watchTimer),this.watchTimer=void 0)},c.prototype.on=function(t,e){var i=this.listeners[t];i||(i=[],this.listeners[t]=i),i.push(e),this._updateEventEmitters()},c.prototype._updateEventEmitters=function(){if(this.listeners){var t=this;O.forEach(this.listeners,function(e,i){if(t.emitters||(t.emitters={}),!(i in t.emitters)){var n=t.frame;if(n){var s=function(t){e.forEach(function(e){e(t)})};t.emitters[i]=s,O.addEventListener(n,i,s)}}})}},u.prototype=new l,u.prototype.setOptions=l.prototype.setOptions,u.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},u.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.factor+e.offset)},u.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.factor},u.prototype.repaint=function(){var t=0,e=O.updateProperty,i=O.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.props,r=this.step,a=this.frame;if(a||(a=document.createElement("div"),this.frame=a,t+=1),a.className="axis "+s,!a.parentNode){if(!this.parent)throw Error("Cannot repaint time axis: no parent attached");var h=this.parent.getContainer();if(!h)throw Error("Cannot repaint time axis: parent has no container element");h.appendChild(a),t+=1}var d=a.parentNode;if(d){var l=a.nextSibling;d.removeChild(a);var p="bottom"==s&&this.props.parentHeight&&this.height?this.props.parentHeight-this.height+"px":"0px";if(t+=e(a.style,"top",i(n.top,p)),t+=e(a.style,"left",i(n.left,"0px")),t+=e(a.style,"width",i(n.width,"100%")),t+=e(a.style,"height",i(n.height,this.height+"px")),this._repaintMeasureChars(),this.step){this._repaintStart(),r.first();for(var c=void 0,u=0;r.hasNext()&&1e3>u;){u++;var f=r.getCurrent(),m=this.toScreen(f),g=r.isMajor();this.getOption("showMinorLabels")&&this._repaintMinorText(m,r.getLabelMinor()),g&&this.getOption("showMajorLabels")?(m>0&&(void 0==c&&(c=m),this._repaintMajorText(m,r.getLabelMajor())),this._repaintMajorLine(m)):this._repaintMinorLine(m),r.next()}if(this.getOption("showMajorLabels")){var v=this.toTime(0),y=r.getLabelMajor(v),b=y.length*(o.majorCharWidth||10)+10;(void 0==c||c>b)&&this._repaintMajorText(0,y)}this._repaintEnd()}this._repaintLine(),l?d.insertBefore(a,l):d.appendChild(a)}return t>0},u.prototype._repaintStart=function(){var t=this.dom,e=t.redundant;e.majorLines=t.majorLines,e.majorTexts=t.majorTexts,e.minorLines=t.minorLines,e.minorTexts=t.minorTexts,t.majorLines=[],t.majorTexts=[],t.minorLines=[],t.minorTexts=[]},u.prototype._repaintEnd=function(){O.forEach(this.dom.redundant,function(t){for(;t.length;){var e=t.pop();e&&e.parentNode&&e.parentNode.removeChild(e)}})},u.prototype._repaintMinorText=function(t,e){var i=this.dom.redundant.minorTexts.shift();if(!i){var n=document.createTextNode("");i=document.createElement("div"),i.appendChild(n),i.className="text minor",this.frame.appendChild(i)}this.dom.minorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.left=t+"px",i.style.top=this.props.minorLabelTop+"px"},u.prototype._repaintMajorText=function(t,e){var i=this.dom.redundant.majorTexts.shift();if(!i){var n=document.createTextNode(e);i=document.createElement("div"),i.className="text major",i.appendChild(n),this.frame.appendChild(i)}this.dom.majorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.top=this.props.majorLabelTop+"px",i.style.left=t+"px"},u.prototype._repaintMinorLine=function(t){var e=this.dom.redundant.minorLines.shift();e||(e=document.createElement("div"),e.className="grid vertical minor",this.frame.appendChild(e)),this.dom.minorLines.push(e);var i=this.props;e.style.top=i.minorLineTop+"px",e.style.height=i.minorLineHeight+"px",e.style.left=t-i.minorLineWidth/2+"px"},u.prototype._repaintMajorLine=function(t){var e=this.dom.redundant.majorLines.shift();e||(e=document.createElement("DIV"),e.className="grid vertical major",this.frame.appendChild(e)),this.dom.majorLines.push(e);var i=this.props;e.style.top=i.majorLineTop+"px",e.style.left=t-i.majorLineWidth/2+"px",e.style.height=i.majorLineHeight+"px"},u.prototype._repaintLine=function(){var t=this.dom.line,e=this.frame;this.options,this.getOption("showMinorLabels")||this.getOption("showMajorLabels")?(t?(e.removeChild(t),e.appendChild(t)):(t=document.createElement("div"),t.className="grid horizontal major",e.appendChild(t),this.dom.line=t),t.style.top=this.props.lineTop+"px"):t&&axis.parentElement&&(e.removeChild(axis.line),delete this.dom.line)},u.prototype._repaintMeasureChars=function(){var t,e=this.dom;if(!e.measureCharMinor){t=document.createTextNode("0");var i=document.createElement("DIV");i.className="text minor measure",i.appendChild(t),this.frame.appendChild(i),e.measureCharMinor=i}if(!e.measureCharMajor){t=document.createTextNode("0");var n=document.createElement("DIV");n.className="text major measure",n.appendChild(t),this.frame.appendChild(n),e.measureCharMajor=n}},u.prototype.reflow=function(){var t=0,e=O.updateProperty,i=this.frame,n=this.range;if(!n)throw Error("Cannot repaint time axis: no range configured");if(i){t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft);var s=this.props,o=this.getOption("showMinorLabels"),r=this.getOption("showMajorLabels"),a=this.dom.measureCharMinor,h=this.dom.measureCharMajor;a&&(s.minorCharHeight=a.clientHeight,s.minorCharWidth=a.clientWidth),h&&(s.majorCharHeight=h.clientHeight,s.majorCharWidth=h.clientWidth);var d=i.parentNode?i.parentNode.offsetHeight:0;switch(d!=s.parentHeight&&(s.parentHeight=d,t+=1),this.getOption("orientation")){case"bottom":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.minorLabelTop=0,s.majorLabelTop=s.minorLabelTop+s.minorLabelHeight,s.minorLineTop=-this.top,s.minorLineHeight=Math.max(this.top+s.majorLabelHeight,0),s.minorLineWidth=1,s.majorLineTop=-this.top,s.majorLineHeight=Math.max(this.top+s.minorLabelHeight+s.majorLabelHeight,0),s.majorLineWidth=1,s.lineTop=0;break;case"top":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.majorLabelTop=0,s.minorLabelTop=s.majorLabelTop+s.majorLabelHeight,s.minorLineTop=s.minorLabelTop,s.minorLineHeight=Math.max(d-s.majorLabelHeight-this.top),s.minorLineWidth=1,s.majorLineTop=0,s.majorLineHeight=Math.max(d-this.top),s.majorLineWidth=1,s.lineTop=s.majorLabelHeight+s.minorLabelHeight;break;default:throw Error('Unkown orientation "'+this.getOption("orientation")+'"')}var l=s.minorLabelHeight+s.majorLabelHeight;t+=e(this,"width",i.offsetWidth),t+=e(this,"height",l),this._updateConversion();var p=O.convert(n.start,"Date"),c=O.convert(n.end,"Date"),u=this.toTime(5*(s.minorCharWidth||10))-this.toTime(0);this.step=new TimeStep(p,c,u),t+=e(s.range,"start",p.valueOf()),t+=e(s.range,"end",c.valueOf()),t+=e(s.range,"minimumStep",u.valueOf())}return t>0},u.prototype._updateConversion=function(){var t=this.range;if(!t)throw Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},f.prototype=new p,f.types={box:g,range:y,point:v},f.prototype.setOptions=l.prototype.setOptions,f.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},f.prototype.repaint=function(){var t=0,e=O.updateProperty,i=O.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.defaultOptions,r=this.frame;if(!r){r=document.createElement("div"),r.className="itemset";var a=n.className;a&&O.addClassName(r,O.option.asString(a));var h=document.createElement("div");h.className="background",r.appendChild(h),this.dom.background=h;var d=document.createElement("div");d.className="foreground",r.appendChild(d),this.dom.foreground=d;var l=document.createElement("div");l.className="itemset-axis",this.dom.axis=l,this.frame=r,t+=1}if(!this.parent)throw Error("Cannot repaint itemset: no parent attached");var p=this.parent.getContainer();if(!p)throw Error("Cannot repaint itemset: parent has no container element");r.parentNode||(p.appendChild(r),t+=1),this.dom.axis.parentNode||(p.appendChild(this.dom.axis),t+=1),t+=e(r.style,"left",i(n.left,"0px")),t+=e(r.style,"top",i(n.top,"0px")),t+=e(r.style,"width",i(n.width,"100%")),t+=e(r.style,"height",i(n.height,this.height+"px")),t+=e(this.dom.axis.style,"left",i(n.left,"0px")),t+=e(this.dom.axis.style,"width",i(n.width,"100%")),t+="bottom"==s?e(this.dom.axis.style,"top",this.height+this.top+"px"):e(this.dom.axis.style,"top",this.top+"px"),this._updateConversion();var c=this,u=this.queue,m=this.itemsData,g=this.items,v={};return Object.keys(u).forEach(function(e){var i=u[e],s=g[e];switch(i){case"add":case"update":var r=m&&m.get(e,v);if(r){var a=r.type||r.start&&r.end&&"range"||n.type||"box",h=f.types[a];if(s&&(h&&s instanceof h?(s.data=r,t++):(t+=s.hide(),s=null)),!s){if(!h)throw new TypeError('Unknown item type "'+a+'"');s=new h(c,r,n,o),t++}s.repaint(),g[e]=s}delete u[e];break;case"remove":s&&(t+=s.hide()),delete g[e],delete u[e];break;default:console.log('Error: unknown action "'+i+'"')}}),O.forEach(this.items,function(e){e.visible?(t+=e.show(),e.reposition()):t+=e.hide()}),t>0},f.prototype.getForeground=function(){return this.dom.foreground},f.prototype.getBackground=function(){return this.dom.background},f.prototype.getAxis=function(){return this.dom.axis},f.prototype.reflow=function(){var t=0,e=this.options,i=e.margin&&e.margin.axis||this.defaultOptions.margin.axis,n=e.margin&&e.margin.item||this.defaultOptions.margin.item,s=O.updateProperty,o=O.option.asNumber,r=O.option.asSize,a=this.frame;if(a){this._updateConversion(),O.forEach(this.items,function(e){t+=e.reflow()}),this.stack.update();var h,d=o(e.maxHeight),l=null!=r(e.height);if(l)h=a.offsetHeight;else{var p=this.stack.ordered;if(p.length){var c=p[0].top,u=p[0].top+p[0].height;O.forEach(p,function(t){c=Math.min(c,t.top),u=Math.max(u,t.top+t.height)}),h=u-c+i+n}else h=i+n}null!=d&&(h=Math.min(h,d)),t+=s(this,"height",h),t+=s(this,"top",a.offsetTop),t+=s(this,"left",a.offsetLeft),t+=s(this,"width",a.offsetWidth)}else t+=1;return t>0},f.prototype.hide=function(){var t=!1;return this.frame&&this.frame.parentNode&&(this.frame.parentNode.removeChild(this.frame),t=!0),this.dom.axis&&this.dom.axis.parentNode&&(this.dom.axis.parentNode.removeChild(this.dom.axis),t=!0),t},f.prototype.setItems=function(t){var e,i=this,n=this.itemsData;if(t){if(!(t instanceof o||t instanceof r))throw new TypeError("Data must be an instance of DataSet");this.itemsData=t}else this.itemsData=null;if(n&&(O.forEach(this.listeners,function(t,e){n.unsubscribe(e,t)}),e=n.getIds(),this._onRemove(e)),this.itemsData){var s=this.id;O.forEach(this.listeners,function(t,e){i.itemsData.subscribe(e,t,s)}),e=this.itemsData.getIds(),this._onAdd(e)}},f.prototype.getItems=function(){return this.itemsData},f.prototype._onUpdate=function(t){this._toQueue("update",t)},f.prototype._onAdd=function(t){this._toQueue("add",t)},f.prototype._onRemove=function(t){this._toQueue("remove",t)},f.prototype._toQueue=function(t,e){var i=this.queue;e.forEach(function(e){i[e]=t}),this.controller&&this.requestRepaint()},f.prototype._updateConversion=function(){var t=this.range;if(!t)throw Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},f.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.factor+e.offset)},f.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.factor},m.prototype.select=function(){this.selected=!0},m.prototype.unselect=function(){this.selected=!1},m.prototype.show=function(){return!1},m.prototype.hide=function(){return!1},m.prototype.repaint=function(){return!1},m.prototype.reflow=function(){return!1},g.prototype=new m(null,null),g.prototype.select=function(){this.selected=!0},g.prototype.unselect=function(){this.selected=!1},g.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw Error("Cannot repaint time axis: parent has no foreground container element");var n=this.parent.getBackground();if(!n)throw Error("Cannot repaint time axis: parent has no background container element");var s=this.parent.getAxis();if(!n)throw Error("Cannot repaint time axis: parent has no axis container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),e.line.parentNode||(n.appendChild(e.line),t=!0),e.dot.parentNode||(s.appendChild(e.dot),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var o=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=o&&(this.className=o,e.box.className="item box"+o,e.line.className="item line"+o,e.dot.className="item dot"+o,t=!0)}return t},g.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},g.prototype.hide=function(){var t=!1,e=this.dom;return e&&(e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),e.line.parentNode&&e.line.parentNode.removeChild(e.line),e.dot.parentNode&&e.dot.parentNode.removeChild(e.dot)),t},g.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,d,l,p,c=0;if(void 0==this.data.start)throw Error('Property "start" missing in item '+this.data.id);if(l=this.data,p=this.parent&&this.parent.range,l&&p){var u=p.end-p.start;this.visible=l.start>p.start-u&&l.start0},g.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("DIV"),t.content=document.createElement("DIV"),t.content.className="content",t.box.appendChild(t.content),t.line=document.createElement("DIV"),t.line.className="line",t.dot=document.createElement("DIV"),t.dot.className="dot")},g.prototype.reposition=function(){var t=this.dom,e=this.props,i=this.options.orientation||this.defaultOptions.orientation;if(t){var n=t.box,s=t.line,o=t.dot;n.style.left=this.left+"px",n.style.top=this.top+"px",s.style.left=e.line.left+"px","top"==i?(s.style.top="0px",s.style.height=this.top+"px"):(s.style.top=this.top+this.height+"px",s.style.height=Math.max(this.parent.height-this.top-this.height+this.props.dot.height/2,0)+"px"),o.style.left=e.dot.left+"px",o.style.top=e.dot.top+"px"}},v.prototype=new m(null,null),v.prototype.select=function(){this.selected=!0},v.prototype.unselect=function(){this.selected=!1},v.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw Error("Cannot repaint time axis: parent has no foreground container element");if(e.point.parentNode||(i.appendChild(e.point),i.appendChild(e.point),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.point.className="item point"+n,t=!0)}return t},v.prototype.show=function(){return this.dom&&this.dom.point.parentNode?!1:this.repaint()},v.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.point.parentNode&&(e.point.parentNode.removeChild(e.point),t=!0),t},v.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,d,l=0;if(void 0==this.data.start)throw Error('Property "start" missing in item '+this.data.id);if(h=this.data,d=this.parent&&this.parent.range,h&&d){var p=d.end-d.start;this.visible=h.start>d.start-p&&h.start0},v.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.point=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.point.appendChild(t.content),t.dot=document.createElement("div"),t.dot.className="dot",t.point.appendChild(t.dot))},v.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.point.style.top=this.top+"px",t.point.style.left=this.left+"px",t.content.style.marginLeft=e.content.marginLeft+"px",t.dot.style.top=e.dot.top+"px")},y.prototype=new m(null,null),y.prototype.select=function(){this.selected=!0},y.prototype.unselect=function(){this.selected=!1},y.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw Error('Property "content" missing in item '+this.data.id); +e.content.innerHTML=this.content}t=!0}var n=this.data.className?" "+this.data.className:"";this.className!=n&&(this.className=n,e.box.className="item range"+n,t=!0)}return t},y.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},y.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),t},y.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,d,l,p,c,u,f,m,g=0;if(void 0==this.data.start)throw Error('Property "start" missing in item '+this.data.id);if(void 0==this.data.end)throw Error('Property "end" missing in item '+this.data.id);return h=this.data,d=this.parent&&this.parent.range,this.visible=h&&d?h.startd.start:!1,this.visible&&(t=this.dom,t?(e=this.props,i=this.options,o=this.parent,r=o.toScreen(this.data.start),a=o.toScreen(this.data.end),l=O.updateProperty,p=t.box,c=o.width,f=i.orientation||this.defaultOptions.orientation,n=i.margin&&i.margin.axis||this.defaultOptions.margin.axis,s=i.padding||this.defaultOptions.padding,g+=l(e.content,"width",t.content.offsetWidth),g+=l(this,"height",p.offsetHeight),-c>r&&(r=-c),a>2*c&&(a=2*c),u=0>r?Math.min(-r,a-r-e.content.width-2*s):0,g+=l(e.content,"left",u),"top"==f?(m=n,g+=l(this,"top",m)):(m=o.height-this.height-n,g+=l(this,"top",m)),g+=l(this,"left",r),g+=l(this,"width",Math.max(a-r,1))):g+=1),g>0},y.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content))},y.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.box.style.top=this.top+"px",t.box.style.left=this.left+"px",t.box.style.width=this.width+"px",t.content.style.left=e.content.left+"px")},b.prototype=new l,b.prototype.setOptions=l.prototype.setOptions,b.prototype.getContainer=function(){return this.parent.getContainer()},b.prototype.setItems=function(t){if(this.itemset&&(this.itemset.hide(),this.itemset.setItems(),this.parent.controller.remove(this.itemset),this.itemset=null),t){var e=this.groupId,i=Object.create(this.options);this.itemset=new f(this,null,i),this.itemset.setRange(this.parent.range),this.view=new r(t,{filter:function(t){return t.group==e}}),this.itemset.setItems(this.view),this.parent.controller.add(this.itemset)}},b.prototype.repaint=function(){return!1},b.prototype.reflow=function(){var t=0,e=O.updateProperty;if(t+=e(this,"top",this.itemset?this.itemset.top:0),t+=e(this,"height",this.itemset?this.itemset.height:0),this.label){var i=this.label.firstChild;t+=e(this.props.label,"width",i.clientWidth),t+=e(this.props.label,"height",i.clientHeight)}else t+=e(this.props.label,"width",0),t+=e(this.props.label,"height",0);return t>0},w.prototype=new p,w.prototype.setOptions=l.prototype.setOptions,w.prototype.setRange=function(){},w.prototype.setItems=function(t){this.itemsData=t;for(var e in this.groups)if(this.groups.hasOwnProperty(e)){var i=this.groups[e];i.setItems(t)}},w.prototype.getItems=function(){return this.itemsData},w.prototype.setRange=function(t){this.range=t},w.prototype.setGroups=function(t){var e,i=this;if(this.groupsData&&(O.forEach(this.listeners,function(t,e){i.groupsData.unsubscribe(e,t)}),e=this.groupsData.getIds(),this._onRemove(e)),t?t instanceof o?this.groupsData=t:(this.groupsData=new o({convert:{start:"Date",end:"Date"}}),this.groupsData.add(t)):this.groupsData=null,this.groupsData){var n=this.id;O.forEach(this.listeners,function(t,e){i.groupsData.subscribe(e,t,n)}),e=this.groupsData.getIds(),this._onAdd(e)}},w.prototype.getGroups=function(){return this.groupsData},w.prototype.repaint=function(){var t,e,i,n,s=0,o=O.updateProperty,r=O.option.asSize,a=O.option.asElement,h=this.options,d=this.dom.frame,l=this.dom.labels;if(!this.parent)throw Error("Cannot repaint groupset: no parent attached");var p=this.parent.getContainer();if(!p)throw Error("Cannot repaint groupset: parent has no container element");if(!d){d=document.createElement("div"),d.className="groupset",this.dom.frame=d;var c=h.className;c&&O.addClassName(d,O.option.asString(c)),s+=1}d.parentNode||(p.appendChild(d),s+=1);var u=a(h.labelContainer);if(!u)throw Error('Cannot repaint groupset: option "labelContainer" not defined');l||(l=document.createElement("div"),l.className="labels",this.dom.labels=l),l.parentNode&&l.parentNode==u||(l.parentNode&&l.parentNode.removeChild(l.parentNode),u.appendChild(l)),s+=o(d.style,"height",r(h.height,this.height+"px")),s+=o(d.style,"top",r(h.top,"0px")),s+=o(d.style,"left",r(h.left,"0px")),s+=o(d.style,"width",r(h.width,"100%")),s+=o(l.style,"top",r(h.top,"0px"));var f=this,m=this.queue,g=this.groups,v=this.groupsData,y=Object.keys(m);if(y.length){y.forEach(function(t){var e=m[t],i=g[t];switch(e){case"add":case"update":if(!i){var n=Object.create(f.options);i=new b(f,t,n),i.setItems(f.itemsData),g[t]=i,f.controller.add(i)}i.data=v.get(t),delete m[t];break;case"remove":i&&(i.setItems(),delete g[t],f.controller.remove(i)),delete m[t];break;default:console.log('Error: unknown action "'+e+'"')}});var w=this.groupsData.getIds({order:this.options.groupsOrder});for(t=0;w.length>t;t++)(function(t,e){var i=0;e&&(i=function(){return e.top+e.height}),t.setOptions({top:i})})(g[w[t]],g[w[t-1]]);for(;l.firstChild;)l.removeChild(l.firstChild);for(t=0;w.length>t;t++)e=w[t],n=this._createLabel(e),l.appendChild(n);s++}for(e in g)g.hasOwnProperty(e)&&(i=g[e],n=i.label,n&&(n.style.top=i.top+"px",n.style.height=i.height+"px"));return s>0},w.prototype._createLabel=function(t){var e=this.groups[t],i=document.createElement("div");i.className="label";var n=document.createElement("div");n.className="inner",i.appendChild(n);var s=e.data&&e.data.content;s instanceof Element?n.appendChild(s):void 0!=s&&(n.innerHTML=s);var o=e.data&&e.data.className;return o&&O.addClassName(i,o),e.label=i,i},w.prototype.getContainer=function(){return this.dom.frame},w.prototype.getLabelsWidth=function(){return this.props.labels.width},w.prototype.reflow=function(){var t,e,i=0,n=this.options,s=O.updateProperty,o=O.option.asNumber,r=O.option.asSize,a=this.dom.frame;if(a){var h,d=o(n.maxHeight),l=null!=r(n.height);if(l)h=a.offsetHeight;else{h=0;for(t in this.groups)this.groups.hasOwnProperty(t)&&(e=this.groups[t],h+=e.height)}null!=d&&(h=Math.min(h,d)),i+=s(this,"height",h),i+=s(this,"top",a.offsetTop),i+=s(this,"left",a.offsetLeft),i+=s(this,"width",a.offsetWidth)}var p=0;for(t in this.groups)if(this.groups.hasOwnProperty(t)){e=this.groups[t];var c=e.props&&e.props.label&&e.props.label.width||0;p=Math.max(p,c)}return i+=s(this.props.labels,"width",p),i>0},w.prototype.hide=function(){return this.dom.frame&&this.dom.frame.parentNode?(this.dom.frame.parentNode.removeChild(this.dom.frame),!0):!1},w.prototype.show=function(){return this.dom.frame&&this.dom.frame.parentNode?!1:this.repaint()},w.prototype._onUpdate=function(t){this._toQueue(t,"update")},w.prototype._onAdd=function(t){this._toQueue(t,"add")},w.prototype._onRemove=function(t){this._toQueue(t,"remove")},w.prototype._toQueue=function(t,e){var i=this.queue;t.forEach(function(t){i[t]=e}),this.controller&&this.requestRepaint()},_.prototype.setOptions=function(t){t&&O.extend(this.options,t),this.controller.reflow(),this.controller.repaint()},_.prototype.setItems=function(t){var e,i=null==this.itemsData;if(t?t instanceof o&&(e=t):e=null,t instanceof o||(e=new o({convert:{start:"Date",end:"Date"}}),e.add(t)),this.itemsData=e,this.content.setItems(e),i&&(void 0==this.options.start||void 0==this.options.end)){var n=this.getItemRange(),s=n.min,r=n.max;if(null!=s&&null!=r){var a=r.valueOf()-s.valueOf();0>=a&&(a=864e5),s=new Date(s.valueOf()-.05*a),r=new Date(r.valueOf()+.05*a)}void 0!=this.options.start&&(s=new Date(this.options.start.valueOf())),void 0!=this.options.end&&(r=new Date(this.options.end.valueOf())),(null!=s||null!=r)&&this.range.setRange(s,r)}},_.prototype.setGroups=function(t){var e=this;this.groupsData=t;var i=this.groupsData?w:f;if(!(this.content instanceof i)){this.content&&(this.content.hide(),this.content.setItems&&this.content.setItems(),this.content.setGroups&&this.content.setGroups(),this.controller.remove(this.content));var n=Object.create(this.options);O.extend(n,{top:function(){return"top"==e.options.orientation?e.timeaxis.height:e.itemPanel.height-e.timeaxis.height-e.content.height},left:null,width:"100%",height:function(){return e.options.height?e.itemPanel.height-e.timeaxis.height:null},maxHeight:function(){if(e.options.maxHeight){if(!O.isNumber(e.options.maxHeight))throw new TypeError("Number expected for property maxHeight");return e.options.maxHeight-e.timeaxis.height}return null},labelContainer:function(){return e.labelPanel.getContainer()}}),this.content=new i(this.itemPanel,[this.timeaxis],n),this.content.setRange&&this.content.setRange(this.range),this.content.setItems&&this.content.setItems(this.itemsData),this.content.setGroups&&this.content.setGroups(this.groupsData),this.controller.add(this.content)}},_.prototype.getItemRange=function(){var t=this.itemsData,e=null,i=null;if(t){var n=t.min("start");e=n?n.start.valueOf():null;var s=t.max("start");s&&(i=s.start.valueOf());var o=t.max("end");o&&(i=null==i?o.end.valueOf():Math.max(i,o.end.valueOf()))}return{min:null!=e?new Date(e):null,max:null!=i?new Date(i):null}},function(t){function e(t){return M=t,c()}function i(){D=0,C=M.charAt(0)}function n(){D++,C=M.charAt(D)}function s(){return M.charAt(D+1)}function o(t){return L.test(t)}function r(t,e){if(t||(t={}),e)for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function a(t,e,i){for(var n=e.split("."),s=t;n.length;){var o=n.shift();n.length?(s[o]||(s[o]={}),s=s[o]):s[o]=i}}function h(t,e){for(var i,n,s=null,o=[t],a=t;a.parent;)o.push(a.parent),a=a.parent;if(a.nodes)for(i=0,n=a.nodes.length;n>i;i++)if(e.id===a.nodes[i].id){s=a.nodes[i];break}for(s||(s={id:e.id},t.node&&(s.attr=r(s.attr,t.node))),i=o.length-1;i>=0;i--){var h=o[i];h.nodes||(h.nodes=[]),-1==h.nodes.indexOf(s)&&h.nodes.push(s)}e.attr&&(s.attr=r(s.attr,e.attr))}function d(t,e){if(t.edges||(t.edges=[]),t.edges.push(e),t.edge){var i=r({},t.edge);e.attr=r(i,e.attr)}}function l(t,e,i,n,s){var o={from:e,to:i,type:n};return t.edge&&(o.attr=r({},t.edge)),o.attr=r(o.attr||{},s),o}function p(){for(N=x.NULL,O="";" "==C||" "==C||"\n"==C||"\r"==C;)n();do{var t=!1;if("#"==C){for(var e=D-1;" "==M.charAt(e)||" "==M.charAt(e);)e--;if("\n"==M.charAt(e)||""==M.charAt(e)){for(;""!=C&&"\n"!=C;)n();t=!0}}if("/"==C&&"/"==s()){for(;""!=C&&"\n"!=C;)n();t=!0}if("/"==C&&"*"==s()){for(;""!=C;){if("*"==C&&"/"==s()){n(),n();break}n()}t=!0}for(;" "==C||" "==C||"\n"==C||"\r"==C;)n()}while(t);if(""==C)return N=x.DELIMITER,void 0;var i=C+s();if(S[i])return N=x.DELIMITER,O=i,n(),n(),void 0;if(S[C])return N=x.DELIMITER,O=C,n(),void 0;if(o(C)||"-"==C){for(O+=C,n();o(C);)O+=C,n();return"false"==O?O=!1:"true"==O?O=!0:isNaN(Number(O))||(O=Number(O)),N=x.IDENTIFIER,void 0}if('"'==C){for(n();""!=C&&('"'!=C||'"'==C&&'"'==s());)O+=C,'"'==C&&n(),n();if('"'!=C)throw w('End of string " expected');return n(),N=x.IDENTIFIER,void 0}for(N=x.UNKNOWN;""!=C;)O+=C,n();throw new SyntaxError('Syntax error in part "'+_(O,30)+'"')}function c(){var t={};if(i(),p(),"strict"==O&&(t.strict=!0,p()),("graph"==O||"digraph"==O)&&(t.type=O,p()),N==x.IDENTIFIER&&(t.id=O,p()),"{"!=O)throw w("Angle bracket { expected");if(p(),u(t),"}"!=O)throw w("Angle bracket } expected");if(p(),""!==O)throw w("End of file expected");return p(),delete t.node,delete t.edge,delete t.graph,t}function u(t){for(;""!==O&&"}"!=O;)f(t),";"==O&&p()}function f(t){var e=m(t);if(e)return y(t,e),void 0;var i=g(t);if(!i){if(N!=x.IDENTIFIER)throw w("Identifier expected");var n=O;if(p(),"="==O){if(p(),N!=x.IDENTIFIER)throw w("Identifier expected");t[n]=O,p()}else v(t,n)}}function m(t){var e=null;if("subgraph"==O&&(e={},e.type="subgraph",p(),N==x.IDENTIFIER&&(e.id=O,p())),"{"==O){if(p(),e||(e={}),e.parent=t,e.node=t.node,e.edge=t.edge,e.graph=t.graph,u(e),"}"!=O)throw w("Angle bracket } expected");p(),delete e.node,delete e.edge,delete e.graph,delete e.parent,t.subgraphs||(t.subgraphs=[]),t.subgraphs.push(e)}return e}function g(t){return"node"==O?(p(),t.node=b(),"node"):"edge"==O?(p(),t.edge=b(),"edge"):"graph"==O?(p(),t.graph=b(),"graph"):null}function v(t,e){var i={id:e},n=b();n&&(i.attr=n),h(t,i),y(t,e)}function y(t,e){for(;"->"==O||"--"==O;){var i,n=O;p();var s=m(t);if(s)i=s;else{if(N!=x.IDENTIFIER)throw w("Identifier or subgraph expected");i=O,h(t,{id:i}),p()}var o=b(),r=l(t,e,i,n,o);d(t,r),e=i}}function b(){for(var t=null;"["==O;){for(p(),t={};""!==O&&"]"!=O;){if(N!=x.IDENTIFIER)throw w("Attribute name expected");var e=O;if(p(),"="!=O)throw w("Equal sign = expected");if(p(),N!=x.IDENTIFIER)throw w("Attribute value expected");var i=O;a(t,e,i),p(),","==O&&p()}if("]"!=O)throw w("Bracket ] expected");p()}return t}function w(t){return new SyntaxError(t+', got "'+_(O,30)+'" (char '+D+")")}function _(t,e){return e>=t.length?t:t.substr(0,27)+"..."}function E(t,e,i){t instanceof Array?t.forEach(function(t){e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}):e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}function T(t){function i(t){var e={from:t.from,to:t.to};return r(e,t.attr),e.style="->"==t.type?"arrow":"line",e}var n=e(t),s={nodes:[],edges:[],options:{}};return n.nodes&&n.nodes.forEach(function(t){var e={id:t.id,label:(t.label||t.id)+""};r(e,t.attr),e.image&&(e.shape="image"),s.nodes.push(e)}),n.edges&&n.edges.forEach(function(t){var e,n;e=t.from instanceof Object?t.from.nodes:{id:t.from},n=t.to instanceof Object?t.to.nodes:{id:t.to},t.from instanceof Object&&t.from.edges&&t.from.edges.forEach(function(t){var e=i(t);s.edges.push(e)}),E(e,n,function(e,n){var o=l(s,e.id,n.id,t.type,t.attr),r=i(o);s.edges.push(r)}),t.to instanceof Object&&t.to.edges&&t.to.edges.forEach(function(t){var e=i(t);s.edges.push(e)})}),n.attr&&(s.options=n.attr),s}var x={NULL:0,DELIMITER:1,IDENTIFIER:2,UNKNOWN:3},S={"{":!0,"}":!0,"[":!0,"]":!0,";":!0,"=":!0,",":!0,"->":!0,"--":!0},M="",D=0,C="",O="",N=x.NULL,L=/[a-zA-Z_0-9.:#]/;t.parseDOT=e,t.DOTToGraph=T}(O!==void 0?O:n),"undefined"!=typeof CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.circle=function(t,e,i){this.beginPath(),this.arc(t,e,i,0,2*Math.PI,!1)},CanvasRenderingContext2D.prototype.square=function(t,e,i){this.beginPath(),this.rect(t-i,e-i,2*i,2*i)},CanvasRenderingContext2D.prototype.triangle=function(t,e,i){this.beginPath();var n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e-(r-o)),this.lineTo(t+s,e+o),this.lineTo(t-s,e+o),this.lineTo(t,e-(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.triangleDown=function(t,e,i){this.beginPath();var n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e+(r-o)),this.lineTo(t+s,e-o),this.lineTo(t-s,e-o),this.lineTo(t,e+(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.star=function(t,e,i){this.beginPath();for(var n=0;10>n;n++){var s=0===n%2?1.3*i:.5*i;this.lineTo(t+s*Math.sin(2*n*Math.PI/10),e-s*Math.cos(2*n*Math.PI/10))}this.closePath()},CanvasRenderingContext2D.prototype.roundRect=function(t,e,i,n,s){var o=Math.PI/180;0>i-2*s&&(s=i/2),0>n-2*s&&(s=n/2),this.beginPath(),this.moveTo(t+s,e),this.lineTo(t+i-s,e),this.arc(t+i-s,e+s,s,270*o,360*o,!1),this.lineTo(t+i,e+n-s),this.arc(t+i-s,e+n-s,s,0,90*o,!1),this.lineTo(t+s,e+n),this.arc(t+s,e+n-s,s,90*o,180*o,!1),this.lineTo(t,e+s),this.arc(t+s,e+s,s,180*o,270*o,!1)},CanvasRenderingContext2D.prototype.ellipse=function(t,e,i,n){var s=.5522848,o=i/2*s,r=n/2*s,a=t+i,h=e+n,d=t+i/2,l=e+n/2;this.beginPath(),this.moveTo(t,l),this.bezierCurveTo(t,l-r,d-o,e,d,e),this.bezierCurveTo(d+o,e,a,l-r,a,l),this.bezierCurveTo(a,l+r,d+o,h,d,h),this.bezierCurveTo(d-o,h,t,l+r,t,l)},CanvasRenderingContext2D.prototype.database=function(t,e,i,n){var s=1/3,o=i,r=n*s,a=.5522848,h=o/2*a,d=r/2*a,l=t+o,p=e+r,c=t+o/2,u=e+r/2,f=e+(n-r/2),m=e+n;this.beginPath(),this.moveTo(l,u),this.bezierCurveTo(l,u+d,c+h,p,c,p),this.bezierCurveTo(c-h,p,t,u+d,t,u),this.bezierCurveTo(t,u-d,c-h,e,c,e),this.bezierCurveTo(c+h,e,l,u-d,l,u),this.lineTo(l,f),this.bezierCurveTo(l,f+d,c+h,m,c,m),this.bezierCurveTo(c-h,m,t,f+d,t,f),this.lineTo(t,u)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,n){var s=t-n*Math.cos(i),o=e-n*Math.sin(i),r=t-.9*n*Math.cos(i),a=e-.9*n*Math.sin(i),h=s+n/3*Math.cos(i+.5*Math.PI),d=o+n/3*Math.sin(i+.5*Math.PI),l=s+n/3*Math.cos(i-.5*Math.PI),p=o+n/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,d),this.lineTo(r,a),this.lineTo(l,p),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,n,s){s||(s=[10,5]),0==c&&(c=.001);var o=s.length;this.moveTo(t,e);for(var r=i-t,a=n-e,h=a/r,d=Math.sqrt(r*r+a*a),l=0,p=!0;d>=.1;){var c=s[l++%o];c>d&&(c=d);var u=Math.sqrt(c*c/(1+h*h));0>r&&(u=-u),t+=u,e+=h*u,this[p?"lineTo":"moveTo"](t,e),d-=c,p=!p}}),E.prototype.attachEdge=function(t){-1==this.edges.indexOf(t)&&this.edges.push(t),this._updateMass()},E.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&this.edges.splice(e,1),this._updateMass()},E.prototype._updateMass=function(){this.mass=50+20*this.edges.length},E.prototype.setProperties=function(t,e){if(t){if(void 0!=t.id&&(this.id=t.id),void 0!=t.label&&(this.label=t.label),void 0!=t.title&&(this.title=t.title),void 0!=t.group&&(this.group=t.group),void 0!=t.x&&(this.x=t.x),void 0!=t.y&&(this.y=t.y),void 0!=t.value&&(this.value=t.value),void 0===this.id)throw"Node must have an id";if(this.group){var i=this.grouplist.get(this.group);for(var n in i)i.hasOwnProperty(n)&&(this[n]=i[n])}if(void 0!=t.shape&&(this.shape=t.shape),void 0!=t.image&&(this.image=t.image),void 0!=t.radius&&(this.radius=t.radius),void 0!=t.color&&(this.color=E.parseColor(t.color)),void 0!=t.fontColor&&(this.fontColor=t.fontColor),void 0!=t.fontSize&&(this.fontSize=t.fontSize),void 0!=t.fontFace&&(this.fontFace=t.fontFace),void 0!=this.image){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.image)}switch(this.xFixed=this.xFixed||void 0!=t.x,this.yFixed=this.yFixed||void 0!=t.y,this.radiusFixed=this.radiusFixed||void 0!=t.radius,"image"==this.shape&&(this.radiusMin=e.nodes.widthMin,this.radiusMax=e.nodes.widthMax),this.shape){case"database":this.draw=this._drawDatabase,this.resize=this._resizeDatabase;break;case"box":this.draw=this._drawBox,this.resize=this._resizeBox;break;case"circle":this.draw=this._drawCircle,this.resize=this._resizeCircle;break;case"ellipse":this.draw=this._drawEllipse,this.resize=this._resizeEllipse;break;case"image":this.draw=this._drawImage,this.resize=this._resizeImage;break;case"text":this.draw=this._drawText,this.resize=this._resizeText;break;case"dot":this.draw=this._drawDot,this.resize=this._resizeShape;break;case"square":this.draw=this._drawSquare,this.resize=this._resizeShape;break;case"triangle":this.draw=this._drawTriangle,this.resize=this._resizeShape;break;case"triangleDown":this.draw=this._drawTriangleDown,this.resize=this._resizeShape;break;case"star":this.draw=this._drawStar,this.resize=this._resizeShape;break;default:this.draw=this._drawEllipse,this.resize=this._resizeEllipse}this._reset()}},E.parseColor=function(t){var e;return O.isString(t)?e={border:t,background:t,highlight:{border:t,background:t}}:(e={},e.background=t.background||"white",e.border=t.border||e.background,O.isString(t.highlight)?e.highlight={border:t.highlight,background:t.highlight}:(e.highlight={},e.highlight.background=t.highlight&&t.highlight.background||e.background,e.highlight.border=t.highlight&&t.highlight.border||e.border)),e},E.prototype.select=function(){this.selected=!0,this._reset()},E.prototype.unselect=function(){this.selected=!1,this._reset()},E.prototype._reset=function(){this.width=void 0,this.height=void 0},E.prototype.getTitle=function(){return this.title},E.prototype.distanceToBorder=function(t,e){var i=1;switch(this.width||this.resize(t),this.shape){case"circle":case"dot":return this.radius+i;case"ellipse":var n=this.width/2,s=this.height/2,o=Math.sin(e)*n,r=Math.cos(e)*s;return n*s/Math.sqrt(o*o+r*r);case"box":case"image":case"text":default:return this.width?Math.min(Math.abs(this.width/2/Math.cos(e)),Math.abs(this.height/2/Math.sin(e)))+i:0}},E.prototype._setForce=function(t,e){this.fx=t,this.fy=e},E.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},E.prototype.discreteStep=function(t){if(!this.xFixed){var e=-this.damping*this.vx,i=(this.fx+e)/this.mass;this.vx+=i/t,this.x+=this.vx/t}if(!this.yFixed){var n=-this.damping*this.vy,s=(this.fy+n)/this.mass;this.vy+=s/t,this.y+=this.vy/t}},E.prototype.isFixed=function(){return this.xFixed&&this.yFixed},E.prototype.isMoving=function(t){return Math.abs(this.vx)>t||Math.abs(this.vy)>t||!this.xFixed&&Math.abs(this.fx)>this.minForce||!this.yFixed&&Math.abs(this.fy)>this.minForce},E.prototype.isSelected=function(){return this.selected},E.prototype.getValue=function(){return this.value},E.prototype.getDistance=function(t,e){var i=this.x-t,n=this.y-e;return Math.sqrt(i*i+n*n)},E.prototype.setValueRange=function(t,e){if(!this.radiusFixed&&void 0!==this.value){var i=(this.radiusMax-this.radiusMin)/(e-t);this.radius=(this.value-t)*i+this.radiusMin}},E.prototype.draw=function(){throw"Draw method not initialized for node"},E.prototype.resize=function(){throw"Resize method not initialized for node"},E.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},E.prototype._resizeImage=function(){if(!this.width){var t,e;if(this.value){var i=this.imageObj.height/this.imageObj.width;t=this.radius||this.imageObj.width,e=this.radius*i||this.imageObj.height}else t=this.imageObj.width,e=this.imageObj.height;this.width=t,this.height=e}},E.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e;this.imageObj?(t.drawImage(this.imageObj,this.left,this.top,this.width,this.height),e=this.y+this.height/2):e=this.y,this._label(t,this.label,this.x,e,void 0,"top")},E.prototype._resizeBox=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e}},E.prototype._drawBox=function(t){this._resizeBox(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,t.roundRect(this.left,this.top,this.width,this.height,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},E.prototype._resizeDatabase=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=i.width+2*e;this.width=n,this.height=n}},E.prototype._drawDatabase=function(t){this._resizeDatabase(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,t.database(this.x-this.width/2,this.y-.5*this.height,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},E.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=Math.max(i.width,i.height)+2*e;this.radius=n/2,this.width=n,this.height=n}},E.prototype._drawCircle=function(t){this._resizeCircle(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,t.circle(this.x,this.y,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},E.prototype._resizeEllipse=function(t){if(!this.width){var e=this.getTextSize(t);this.width=1.5*e.width,this.height=2*e.height,this.widthl;l++)t.fillText(r[l],i,d),d+=h}},E.prototype.getTextSize=function(t){if(void 0!=this.label){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace;for(var e=this.label.split("\n"),i=(this.fontSize+4)*e.length,n=0,s=0,o=e.length;o>s;s++)n=Math.max(n,t.measureText(e[s]).width);return{width:n,height:i}}return{width:0,height:0}},T.prototype.setProperties=function(t,e){if(t)switch(void 0!=t.from&&(this.fromId=t.from),void 0!=t.to&&(this.toId=t.to),void 0!=t.id&&(this.id=t.id),void 0!=t.style&&(this.style=t.style),void 0!=t.label&&(this.label=t.label),this.label&&(this.fontSize=e.edges.fontSize,this.fontFace=e.edges.fontFace,this.fontColor=e.edges.fontColor,void 0!=t.fontColor&&(this.fontColor=t.fontColor),void 0!=t.fontSize&&(this.fontSize=t.fontSize),void 0!=t.fontFace&&(this.fontFace=t.fontFace)),void 0!=t.title&&(this.title=t.title),void 0!=t.width&&(this.width=t.width),void 0!=t.value&&(this.value=t.value),void 0!=t.length&&(this.length=t.length),t.dash&&(void 0!=t.dash.length&&(this.dash.length=t.dash.length),void 0!=t.dash.gap&&(this.dash.gap=t.dash.gap),void 0!=t.dash.altLength&&(this.dash.altLength=t.dash.altLength)),void 0!=t.color&&(this.color=t.color),this.connect(),this.widthFixed=this.widthFixed||void 0!=t.width,this.lengthFixed=this.lengthFixed||void 0!=t.length,this.stiffness=1/this.length,this.style){case"line":this.draw=this._drawLine;break;case"arrow":this.draw=this._drawArrow;break;case"arrow-center":this.draw=this._drawArrowCenter;break;case"dash-line":this.draw=this._drawDashLine;break;default:this.draw=this._drawLine}},T.prototype.connect=function(){this.disconnect(),this.from=this.graph.nodes[this.fromId]||null,this.to=this.graph.nodes[this.toId]||null,this.connected=this.from&&this.to,this.connected?(this.from.attachEdge(this),this.to.attachEdge(this)):(this.from&&this.from.detachEdge(this),this.to&&this.to.detachEdge(this))},T.prototype.disconnect=function(){this.from&&(this.from.detachEdge(this),this.from=null),this.to&&(this.to.detachEdge(this),this.to=null),this.connected=!1},T.prototype.getTitle=function(){return this.title},T.prototype.getValue=function(){return this.value},T.prototype.setValueRange=function(t,e){if(!this.widthFixed&&void 0!==this.value){var i=(this.widthMax-this.widthMin)/(e-t);this.width=(this.value-t)*i+this.widthMin}},T.prototype.draw=function(){throw"Method draw not initialized in edge"},T.prototype.isOverlappingWith=function(t){var e=10,i=this.from.x,n=this.from.y,s=this.to.x,o=this.to.y,r=t.left,a=t.top,h=T._dist(i,n,s,o,r,a);return e>h},T.prototype._drawLine=function(t){t.strokeStyle=this.color,t.lineWidth=this._getLineWidth();var e;if(this.from!=this.to)this._line(t),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y));else{var i,n,s=this.length/4,o=this.from;o.width||o.resize(t),o.width>o.height?(i=o.x+o.width/2,n=o.y-s):(i=o.x+s,n=o.y-o.height/2),this._circle(t,i,n,s),e=this._pointOnCircle(i,n,s,.5),this._label(t,this.label,e.x,e.y)}},T.prototype._getLineWidth=function(){return this.from.selected||this.to.selected?Math.min(2*this.width,this.widthMax):this.width},T.prototype._line=function(t){t.beginPath(),t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y),t.stroke()},T.prototype._circle=function(t,e,i,n){t.beginPath(),t.arc(e,i,n,0,2*Math.PI,!1),t.stroke()},T.prototype._label=function(t,e,i,n){if(e){t.font=(this.from.selected||this.to.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle="white";var s=t.measureText(e).width,o=this.fontSize,r=i-s/2,a=n-o/2;t.fillRect(r,a,s,o),t.fillStyle=this.fontColor||"black",t.textAlign="left",t.textBaseline="top",t.fillText(e,r,a)}},T.prototype._drawDashLine=function(t){if(t.strokeStyle=this.color,t.lineWidth=this._getLineWidth(),t.beginPath(),t.lineCap="round",void 0!=this.dash.altLength?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]):void 0!=this.dash.length&&void 0!=this.dash.gap?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap]):(t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y)),t.stroke(),this.label){var e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}},T.prototype._pointOnLine=function(t){return{x:(1-t)*this.from.x+t*this.to.x,y:(1-t)*this.from.y+t*this.to.y}},T.prototype._pointOnCircle=function(t,e,i,n){var s=2*(n-3/8)*Math.PI;return{x:t+i*Math.cos(s),y:e-i*Math.sin(s)}},T.prototype._drawArrowCenter=function(t){var e;if(t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth(),this.from!=this.to){this._line(t);var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),n=10+5*this.width;e=this._pointOnLine(.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y))}else{var s,o,r=this.length/4,a=this.from;a.width||a.resize(t),a.width>a.height?(s=a.x+a.width/2,o=a.y-r):(s=a.x+r,o=a.y-a.height/2),this._circle(t,s,o,r);var i=.2*Math.PI,n=10+5*this.width;e=this._pointOnCircle(s,o,r,.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(s,o,r,.5),this._label(t,this.label,e.x,e.y))}},T.prototype._drawArrow=function(t){t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth();var e,i;if(this.from!=this.to){e=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x);var n=this.to.x-this.from.x,s=this.to.y-this.from.y,o=Math.sqrt(n*n+s*s),r=this.from.distanceToBorder(t,e+Math.PI),a=(o-r)/o,h=a*this.from.x+(1-a)*this.to.x,d=a*this.from.y+(1-a)*this.to.y,l=this.to.distanceToBorder(t,e),p=(o-l)/o,c=(1-p)*this.from.x+p*this.to.x,u=(1-p)*this.from.y+p*this.to.y;if(t.beginPath(),t.moveTo(h,d),t.lineTo(c,u),t.stroke(),i=10+5*this.width,t.arrow(c,u,e,i),t.fill(),t.stroke(),this.label){var f=this._pointOnLine(.5);this._label(t,this.label,f.x,f.y)}}else{var m,g,v,y=this.from,b=this.length/4;y.width||y.resize(t),y.width>y.height?(m=y.x+y.width/2,g=y.y-b,v={x:m,y:y.y,angle:.9*Math.PI}):(m=y.x+b,g=y.y-y.height/2,v={x:y.x,y:g,angle:.6*Math.PI}),t.beginPath(),t.arc(m,g,b,0,2*Math.PI,!1),t.stroke(),i=10+5*this.width,t.arrow(v.x,v.y,v.angle,i),t.fill(),t.stroke(),this.label&&(f=this._pointOnCircle(m,g,b,.5),this._label(t,this.label,f.x,f.y)) +}},T._dist=function(t,e,i,n,s,o){var r=i-t,a=n-e,h=r*r+a*a,d=((s-t)*r+(o-e)*a)/h;d>1?d=1:0>d&&(d=0);var l=t+d*r,p=e+d*a,c=l-s,u=p-o;return Math.sqrt(c*c+u*u)},x.prototype.setPosition=function(t,e){this.x=parseInt(t),this.y=parseInt(e)},x.prototype.setText=function(t){this.frame.innerHTML=t},x.prototype.show=function(t){if(void 0===t&&(t=!0),t){var e=this.frame.clientHeight,i=this.frame.clientWidth,n=this.frame.parentNode.clientHeight,s=this.frame.parentNode.clientWidth,o=this.y-e;o+e+this.padding>n&&(o=n-e-this.padding),this.padding>o&&(o=this.padding);var r=this.x;r+i+this.padding>s&&(r=s-i-this.padding),this.padding>r&&(r=this.padding),this.frame.style.left=r+"px",this.frame.style.top=o+"px",this.frame.style.visibility="visible"}else this.hide()},x.prototype.hide=function(){this.frame.style.visibility="hidden"},Groups=function(){this.clear(),this.defaultIndex=0},Groups.DEFAULT=[{border:"#2B7CE9",background:"#97C2FC",highlight:{border:"#2B7CE9",background:"#D2E5FF"}},{border:"#FFA500",background:"#FFFF00",highlight:{border:"#FFA500",background:"#FFFFA3"}},{border:"#FA0A10",background:"#FB7E81",highlight:{border:"#FA0A10",background:"#FFAFB1"}},{border:"#41A906",background:"#7BE141",highlight:{border:"#41A906",background:"#A1EC76"}},{border:"#E129F0",background:"#EB7DF4",highlight:{border:"#E129F0",background:"#F0B3F5"}},{border:"#7C29F0",background:"#AD85E4",highlight:{border:"#7C29F0",background:"#D3BDF0"}},{border:"#C37F00",background:"#FFA807",highlight:{border:"#C37F00",background:"#FFCA66"}},{border:"#4220FB",background:"#6E6EFD",highlight:{border:"#4220FB",background:"#9B9BFD"}},{border:"#FD5A77",background:"#FFC0CB",highlight:{border:"#FD5A77",background:"#FFD1D9"}},{border:"#4AD63A",background:"#C2FABC",highlight:{border:"#4AD63A",background:"#E6FFE3"}}],Groups.prototype.clear=function(){this.groups={},this.groups.length=function(){var t=0;for(var e in this)this.hasOwnProperty(e)&&t++;return t}},Groups.prototype.get=function(t){var e=this.groups[t];if(void 0==e){var i=this.defaultIndex%Groups.DEFAULT.length;this.defaultIndex++,e={},e.color=Groups.DEFAULT[i],this.groups[t]=e}return e},Groups.prototype.add=function(t,e){return this.groups[t]=e,e.color&&(e.color=E.parseColor(e.color)),e},Images=function(){this.images={},this.callback=void 0},Images.prototype.setOnloadCallback=function(t){this.callback=t},Images.prototype.load=function(t){var e=this.images[t];if(void 0==e){var i=this;e=new Image,this.images[t]=e,e.onload=function(){i.callback&&i.callback(this)},e.src=t}return e},S.prototype.setData=function(t){if(t&&t.dot&&(t.nodes||t.edges))throw new SyntaxError('Data must contain either parameter "dot" or parameter pair "nodes" and "edges", but not both.');if(this.setOptions(t&&t.options),t&&t.dot){if(t&&t.dot){var e=k.util.DOTToGraph(t.dot);return this.setData(e),void 0}}else this._setNodes(t&&t.nodes),this._setEdges(t&&t.edges);this.stabilize&&this._doStabilize(),this.start()},S.prototype.setOptions=function(t){if(t){if(void 0!=t.width&&(this.width=t.width),void 0!=t.height&&(this.height=t.height),void 0!=t.stabilize&&(this.stabilize=t.stabilize),void 0!=t.selectable&&(this.selectable=t.selectable),t.edges){for(var e in t.edges)t.edges.hasOwnProperty(e)&&(this.constants.edges[e]=t.edges[e]);void 0!=t.edges.length&&t.nodes&&void 0==t.nodes.distance&&(this.constants.edges.length=t.edges.length,this.constants.nodes.distance=1.25*t.edges.length),t.edges.fontColor||(this.constants.edges.fontColor=t.edges.color),t.edges.dash&&(void 0!=t.edges.dash.length&&(this.constants.edges.dash.length=t.edges.dash.length),void 0!=t.edges.dash.gap&&(this.constants.edges.dash.gap=t.edges.dash.gap),void 0!=t.edges.dash.altLength&&(this.constants.edges.dash.altLength=t.edges.dash.altLength))}if(t.nodes){for(e in t.nodes)t.nodes.hasOwnProperty(e)&&(this.constants.nodes[e]=t.nodes[e]);t.nodes.color&&(this.constants.nodes.color=E.parseColor(t.nodes.color))}if(t.groups)for(var i in t.groups)if(t.groups.hasOwnProperty(i)){var n=t.groups[i];this.groups.add(i,n)}}this.setSize(this.width,this.height),this._setTranslation(this.frame.clientWidth/2,this.frame.clientHeight/2),this._setScale(1)},S.prototype._trigger=function(t,e){L.trigger(this,t,e)},S.prototype._create=function(){for(;this.containerElement.hasChildNodes();)this.containerElement.removeChild(this.containerElement.firstChild);if(this.frame=document.createElement("div"),this.frame.className="graph-frame",this.frame.style.position="relative",this.frame.style.overflow="hidden",this.frame.canvas=document.createElement("canvas"),this.frame.canvas.style.position="relative",this.frame.appendChild(this.frame.canvas),!this.frame.canvas.getContext){var t=document.createElement("DIV");t.style.color="red",t.style.fontWeight="bold",t.style.padding="10px",t.innerHTML="Error: your browser does not support HTML canvas",this.frame.canvas.appendChild(t)}var e=this;this.drag={},this.pinch={},this.hammer=D(this.frame.canvas,{prevent_default:!0}),this.hammer.on("tap",e._onTap.bind(e)),this.hammer.on("hold",e._onHold.bind(e)),this.hammer.on("pinch",e._onPinch.bind(e)),this.hammer.on("touch",e._onTouch.bind(e)),this.hammer.on("dragstart",e._onDragStart.bind(e)),this.hammer.on("drag",e._onDrag.bind(e)),this.hammer.on("dragend",e._onDragEnd.bind(e)),this.hammer.on("mousewheel",e._onMouseWheel.bind(e)),this.hammer.on("mousemove",e._onMouseMoveTitle.bind(e)),this.containerElement.appendChild(this.frame)},S.prototype._getNodeAt=function(t){var e=this._canvasToX(t.x),i=this._canvasToY(t.y),n={left:e,top:i,right:e,bottom:i},s=this._getNodesOverlappingWith(n);return s.length>0?s[s.length-1]:null},S.prototype._getPointer=function(t){return{x:t.pageX-k.util.getAbsoluteLeft(this.frame.canvas),y:t.pageY-k.util.getAbsoluteTop(this.frame.canvas)}},S.prototype._onTouch=function(t){this.drag.pointer=this._getPointer(t.gesture.touches[0]),this.drag.pinched=!1,this.pinch.scale=this._getScale()},S.prototype._onDragStart=function(){var t=this.drag;t.selection=[],t.translation=this._getTranslation(),t.nodeId=this._getNodeAt(t.pointer);var e=this.nodes[t.nodeId];if(e){e.isSelected()||this._selectNodes([t.nodeId]);var i=this;this.selection.forEach(function(e){var n=i.nodes[e];if(n){var s={id:e,node:n,x:n.x,y:n.y,xFixed:n.xFixed,yFixed:n.yFixed};n.xFixed=!0,n.yFixed=!0,t.selection.push(s)}})}},S.prototype._onDrag=function(t){if(!this.drag.pinched){var e=this._getPointer(t.gesture.touches[0]),i=this,n=this.drag,s=n.selection;if(s&&s.length){var o=e.x-n.pointer.x,r=e.y-n.pointer.y;s.forEach(function(t){var e=t.node;t.xFixed||(e.x=i._canvasToX(i._xToCanvas(t.x)+o)),t.yFixed||(e.y=i._canvasToY(i._yToCanvas(t.y)+r))}),this.moving||(this.moving=!0,this.start())}else{var a=e.x-this.drag.pointer.x,h=e.y-this.drag.pointer.y;this._setTranslation(this.drag.translation.x+a,this.drag.translation.y+h),this._redraw(),this.moved=!0}}},S.prototype._onDragEnd=function(){var t=this.drag.selection;t&&t.forEach(function(t){t.node.xFixed=t.xFixed,t.node.yFixed=t.yFixed})},S.prototype._onTap=function(t){var e=this._getPointer(t.gesture.touches[0]),i=this._getNodeAt(e),n=this.nodes[i];n?(this._selectNodes([i]),this.moving||this._redraw()):(this._unselectNodes(),this._redraw())},S.prototype._onHold=function(t){var e=this._getPointer(t.gesture.touches[0]),i=this._getNodeAt(e),n=this.nodes[i];if(n){if(n.isSelected())this._unselectNodes([i]);else{var s=!0;this._selectNodes([i],s)}this.moving||this._redraw()}},S.prototype._onPinch=function(t){var e=this._getPointer(t.gesture.center);this.drag.pinched=!0,"scale"in this.pinch||(this.pinch.scale=1);var i=this.pinch.scale*t.gesture.scale;this._zoom(i,e)},S.prototype._zoom=function(t,e){var i=this._getScale();.01>t&&(t=.01),t>10&&(t=10);var n=this._getTranslation(),s=t/i,o=(1-s)*e.x+n.x*s,r=(1-s)*e.y+n.y*s;return this._setScale(t),this._setTranslation(o,r),this._redraw(),t},S.prototype._onMouseWheel=function(t){var e=0;if(t.wheelDelta?e=t.wheelDelta/120:t.detail&&(e=-t.detail/3),e){"mouswheelScale"in this.pinch||(this.pinch.mouswheelScale=1);var i=this.pinch.mouswheelScale,n=e/10;0>e&&(n/=1-n),i*=1+n;var s=D.event.collectEventData(this,"scroll",t),o=this._getPointer(s.center);i=this._zoom(i,o),this.pinch.mouswheelScale=i}t.preventDefault()},S.prototype._onMouseMoveTitle=function(t){var e=D.event.collectEventData(this,"mousemove",t),i=this._getPointer(e.center);this.popupNode&&this._checkHidePopup(i);var n=this,s=function(){n._checkShowPopup(i)};this.popupTimer&&clearInterval(this.popupTimer),this.leftButtonDown||(this.popupTimer=setTimeout(s,300))},S.prototype._checkShowPopup=function(t){var e,i={left:this._canvasToX(t.x),top:this._canvasToY(t.y),right:this._canvasToX(t.x),bottom:this._canvasToY(t.y)},n=this.popupNode;if(void 0==this.popupNode){var s=this.nodes;for(e in s)if(s.hasOwnProperty(e)){var o=s[e];if(void 0!=o.getTitle()&&o.isOverlappingWith(i)){this.popupNode=o;break}}}if(void 0==this.popupNode){var r=this.edges;for(e in r)if(r.hasOwnProperty(e)){var a=r[e];if(a.connected&&void 0!=a.getTitle()&&a.isOverlappingWith(i)){this.popupNode=a;break}}}if(this.popupNode){if(this.popupNode!=n){var h=this;h.popup||(h.popup=new x(h.frame)),h.popup.setPosition(t.x-3,t.y-3),h.popup.setText(h.popupNode.getTitle()),h.popup.show()}}else this.popup&&this.popup.hide()},S.prototype._checkHidePopup=function(t){this.popupNode&&this._getNodeAt(t)||(this.popupNode=void 0,this.popup&&this.popup.hide())},S.prototype._unselectNodes=function(t,e){var i,n,s,o=!1;if(t)for(i=0,n=t.length;n>i;i++){s=t[i],this.nodes[s].unselect();for(var r=0;this.selection.length>r;)this.selection[r]==s?(this.selection.splice(r,1),o=!0):r++}else if(this.selection&&this.selection.length){for(i=0,n=this.selection.length;n>i;i++)s=this.selection[i],this.nodes[s].unselect(),o=!0;this.selection=[]}return!o||1!=e&&void 0!=e||this._trigger("select"),o},S.prototype._selectNodes=function(t,e){var i,n,s=!1,o=!0;if(t.length!=this.selection.length)o=!1;else for(i=0,n=Math.min(t.length,this.selection.length);n>i;i++)if(t[i]!=this.selection[i]){o=!1;break}if(o)return s;if(void 0==e||0==e){var r=!1;s=this._unselectNodes(void 0,r)}for(i=0,n=t.length;n>i;i++){var a=t[i],h=-1!=this.selection.indexOf(a);h||(this.nodes[a].select(),this.selection.push(a),s=!0)}return s&&this._trigger("select"),s},S.prototype._getNodesOverlappingWith=function(t){var e=this.nodes,i=[];for(var n in e)e.hasOwnProperty(n)&&e[n].isOverlappingWith(t)&&i.push(n);return i},S.prototype.getSelection=function(){return this.selection.concat([])},S.prototype.setSelection=function(t){var e,i,n;if(!t||void 0==t.length)throw"Selection must be an array with ids";for(e=0,i=this.selection.length;i>e;e++)n=this.selection[e],this.nodes[n].unselect();for(this.selection=[],e=0,i=t.length;i>e;e++){n=t[e];var s=this.nodes[n];if(!s)throw new RangeError('Node with id "'+n+'" not found');s.select(),this.selection.push(n)}this.redraw()},S.prototype._updateSelection=function(){for(var t=0;this.selection.length>t;){var e=this.selection[t];this.nodes[e]?t++:this.selection.splice(t,1)}},S.prototype._getConnectionCount=function(t){function e(t){for(var e=[],i=0,n=t.length;n>i;i++)for(var s=t[i],o=s.edges,r=0,a=o.length;a>r;r++){var h=o[r],d=null;h.from==s?d=h.to:h.to==s&&(d=h.from);var l,p;if(d)for(l=0,p=t.length;p>l;l++)if(t[l]==d){d=null;break}if(d)for(l=0,p=e.length;p>l;l++)if(e[l]==d){d=null;break}d&&e.push(d)}return e}void 0==t&&(t=1);var i=[],n=this.nodes;for(var s in n)if(n.hasOwnProperty(s)){for(var o=[n[s]],r=0;t>r;r++)o=o.concat(e(o));i.push(o)}for(var a=[],h=0,d=i.length;d>h;h++)a.push(i[h].length);return a},S.prototype.setSize=function(t,e){this.frame.style.width=t,this.frame.style.height=e,this.frame.canvas.style.width="100%",this.frame.canvas.style.height="100%",this.frame.canvas.width=this.frame.canvas.clientWidth,this.frame.canvas.height=this.frame.canvas.clientHeight},S.prototype._setNodes=function(t){var e=this.nodesData;if(t instanceof o||t instanceof r)this.nodesData=t;else if(t instanceof Array)this.nodesData=new o,this.nodesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.nodesData=new o}if(e&&O.forEach(this.nodesListeners,function(t,i){e.unsubscribe(i,t)}),this.nodes={},this.nodesData){var i=this;O.forEach(this.nodesListeners,function(t,e){i.nodesData.subscribe(e,t)});var n=this.nodesData.getIds();this._addNodes(n)}this._updateSelection()},S.prototype._addNodes=function(t){for(var e,i=0,n=t.length;n>i;i++){e=t[i];var s=this.nodesData.get(e),o=new E(s,this.images,this.groups,this.constants);if(this.nodes[e]=o,!o.isFixed()){var r=2*this.constants.edges.length,a=t.length,h=2*Math.PI*(i/a);o.x=r*Math.cos(h),o.y=r*Math.sin(h),this.moving=!0}}this._reconnectEdges(),this._updateValueRange(this.nodes)},S.prototype._updateNodes=function(t){for(var e=this.nodes,i=this.nodesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o],a=i.get(o);r?r.setProperties(a,this.constants):(r=new E(properties,this.images,this.groups,this.constants),e[o]=r,r.isFixed()||(this.moving=!0))}this._reconnectEdges(),this._updateValueRange(e)},S.prototype._removeNodes=function(t){for(var e=this.nodes,i=0,n=t.length;n>i;i++){var s=t[i];delete e[s]}this._reconnectEdges(),this._updateSelection(),this._updateValueRange(e)},S.prototype._setEdges=function(t){var e=this.edgesData;if(t instanceof o||t instanceof r)this.edgesData=t;else if(t instanceof Array)this.edgesData=new o,this.edgesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.edgesData=new o}if(e&&O.forEach(this.edgesListeners,function(t,i){e.unsubscribe(i,t)}),this.edges={},this.edgesData){var i=this;O.forEach(this.edgesListeners,function(t,e){i.edgesData.subscribe(e,t)});var n=this.edgesData.getIds();this._addEdges(n)}this._reconnectEdges()},S.prototype._addEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o];r&&r.disconnect();var a=i.get(o);e[o]=new T(a,this,this.constants)}this.moving=!0,this._updateValueRange(e)},S.prototype._updateEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=i.get(o),a=e[o];a?(a.disconnect(),a.setProperties(r,this.constants),a.connect()):(a=new T(r,this,this.constants),this.edges[o]=a)}this.moving=!0,this._updateValueRange(e)},S.prototype._removeEdges=function(t){for(var e=this.edges,i=0,n=t.length;n>i;i++){var s=t[i],o=e[s];o&&(o.disconnect(),delete e[s])}this.moving=!0,this._updateValueRange(e)},S.prototype._reconnectEdges=function(){var t,e=this.nodes,i=this.edges;for(t in e)e.hasOwnProperty(t)&&(e[t].edges=[]);for(t in i)if(i.hasOwnProperty(t)){var n=i[t];n.from=null,n.to=null,n.connect()}},S.prototype._updateValueRange=function(t){var e,i=void 0,n=void 0;for(e in t)if(t.hasOwnProperty(e)){var s=t[e].getValue();void 0!==s&&(i=void 0===i?s:Math.min(s,i),n=void 0===n?s:Math.max(s,n))}if(void 0!==i&&void 0!==n)for(e in t)t.hasOwnProperty(e)&&t[e].setValueRange(i,n)},S.prototype.redraw=function(){this.setSize(this.width,this.height),this._redraw()},S.prototype._redraw=function(){var t=this.frame.canvas.getContext("2d"),e=this.frame.canvas.width,i=this.frame.canvas.height;t.clearRect(0,0,e,i),t.save(),t.translate(this.translation.x,this.translation.y),t.scale(this.scale,this.scale),this._drawEdges(t),this._drawNodes(t),t.restore()},S.prototype._setTranslation=function(t,e){void 0===this.translation&&(this.translation={x:0,y:0}),void 0!==t&&(this.translation.x=t),void 0!==e&&(this.translation.y=e)},S.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},S.prototype._setScale=function(t){this.scale=t},S.prototype._getScale=function(){return this.scale},S.prototype._canvasToX=function(t){return(t-this.translation.x)/this.scale},S.prototype._xToCanvas=function(t){return t*this.scale+this.translation.x},S.prototype._canvasToY=function(t){return(t-this.translation.y)/this.scale},S.prototype._yToCanvas=function(t){return t*this.scale+this.translation.y},S.prototype._drawNodes=function(t){var e=this.nodes,i=[];for(var n in e)e.hasOwnProperty(n)&&(e[n].isSelected()?i.push(n):e[n].draw(t));for(var s=0,o=i.length;o>s;s++)e[i[s]].draw(t)},S.prototype._drawEdges=function(t){var e=this.edges;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];n.connected&&e[i].draw(t)}},S.prototype._doStabilize=function(){new Date;for(var t=0,e=this.constants.minVelocity,i=!1;!i&&this.constants.maxIterations>t;)this._calculateForces(),this._discreteStepNodes(),i=!this._isMoving(e),t++;new Date},S.prototype._calculateForces=function(){var t,e,i,n,s,o,r,a,h,d,l,p=this.nodes,c=this.edges,u=.01,f=this.frame.canvas.clientWidth/2,m=this.frame.canvas.clientHeight/2;for(t in p)if(p.hasOwnProperty(t)){var g=p[t];e=f-g.x,i=m-g.y,n=Math.atan2(i,e),o=Math.cos(n)*u,r=Math.sin(n)*u,g._setForce(o,r)}var v=this.constants.nodes.distance,y=10;for(var b in p)if(p.hasOwnProperty(b)){var w=p[b];for(var _ in p)if(p.hasOwnProperty(_)){var E=p[_];e=E.x-w.x,i=E.y-w.y,s=Math.sqrt(e*e+i*i),n=Math.atan2(i,e),a=1/(1+Math.exp((s/v-1)*y)),o=Math.cos(n)*a,r=Math.sin(n)*a,w._addForce(-o,-r),E._addForce(o,r)}}for(t in c)if(c.hasOwnProperty(t)){var T=c[t];T.connected&&(e=T.to.x-T.from.x,i=T.to.y-T.from.y,l=T.length,d=Math.sqrt(e*e+i*i),n=Math.atan2(i,e),h=T.stiffness*(l-d),o=Math.cos(n)*h,r=Math.sin(n)*h,T.from._addForce(-o,-r),T.to._addForce(o,r))}},S.prototype._isMoving=function(t){var e=this.nodes;for(var i in e)if(e.hasOwnProperty(i)&&e[i].isMoving(t))return!0;return!1},S.prototype._discreteStepNodes=function(){var t=this.refreshRate/1e3,e=this.nodes;for(var i in e)e.hasOwnProperty(i)&&e[i].discreteStep(t)},S.prototype.start=function(){if(this.moving){this._calculateForces(),this._discreteStepNodes();var t=this.constants.minVelocity;this.moving=this._isMoving(t)}if(this.moving){if(!this.timer){var e=this;this.timer=window.setTimeout(function(){e.timer=void 0,e.start(),e._redraw()},this.refreshRate)}}else this._redraw()},S.prototype.stop=function(){this.timer&&(window.clearInterval(this.timer),this.timer=void 0)};var k={util:O,events:L,Controller:d,DataSet:o,DataView:r,Range:h,Stack:a,TimeStep:TimeStep,EventBus:s,components:{items:{Item:m,ItemBox:g,ItemPoint:v,ItemRange:y},Component:l,Panel:p,RootPanel:c,ItemSet:f,TimeAxis:u},graph:{Node:E,Edge:T,Popup:x,Groups:Groups,Images:Images},Timeline:_,Graph:S};n!==void 0&&(n=k),i!==void 0&&i.exports!==void 0&&(i.exports=k),"function"==typeof t&&t(function(){return k}),"undefined"!=typeof window&&(window.vis=k),O.loadCss("/* vis.js stylesheet */\n.vis.timeline {\n}\n\n\n.vis.timeline.rootpanel {\n position: relative;\n overflow: hidden;\n\n border: 1px solid #bfbfbf;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n\n.vis.timeline .panel {\n position: absolute;\n overflow: hidden;\n}\n\n\n.vis.timeline .groupset {\n position: absolute;\n padding: 0;\n margin: 0;\n}\n\n.vis.timeline .labels {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n\n padding: 0;\n margin: 0;\n\n border-right: 1px solid #bfbfbf;\n box-sizing: border-box;\n -moz-box-sizing: border-box;\n}\n\n.vis.timeline .labels .label {\n position: absolute;\n left: 0;\n top: 0;\n width: 100%;\n border-bottom: 1px solid #bfbfbf;\n color: #4d4d4d;\n}\n\n.vis.timeline .labels .label .inner {\n display: inline-block;\n padding: 5px;\n}\n\n\n.vis.timeline .itemset {\n position: absolute;\n padding: 0;\n margin: 0;\n overflow: hidden;\n}\n\n.vis.timeline .background {\n}\n\n.vis.timeline .foreground {\n}\n\n.vis.timeline .itemset-axis {\n position: absolute;\n}\n\n.vis.timeline .groupset .itemset-axis {\n border-top: 1px solid #bfbfbf;\n}\n\n/* TODO: with orientation=='bottom', this will more or less overlap with timeline axis\n.vis.timeline .groupset .itemset-axis:last-child {\n border-top: none;\n}\n*/\n\n\n.vis.timeline .item {\n position: absolute;\n color: #1A1A1A;\n border-color: #97B0F8;\n background-color: #D5DDF6;\n display: inline-block;\n}\n\n.vis.timeline .item.selected {\n border-color: #FFC200;\n background-color: #FFF785;\n z-index: 999;\n}\n\n.vis.timeline .item.cluster {\n /* TODO: use another color or pattern? */\n background: #97B0F8 url('img/cluster_bg.png');\n color: white;\n}\n.vis.timeline .item.cluster.point {\n border-color: #D5DDF6;\n}\n\n.vis.timeline .item.box {\n text-align: center;\n border-style: solid;\n border-width: 1px;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.point {\n background: none;\n}\n\n.vis.timeline .dot {\n border: 5px solid #97B0F8;\n position: absolute;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.range {\n overflow: hidden;\n border-style: solid;\n border-width: 1px;\n border-radius: 2px;\n -moz-border-radius: 2px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.range .drag-left {\n cursor: w-resize;\n z-index: 1000;\n}\n\n.vis.timeline .item.range .drag-right {\n cursor: e-resize;\n z-index: 1000;\n}\n\n.vis.timeline .item.range .content {\n position: relative;\n display: inline-block;\n}\n\n.vis.timeline .item.line {\n position: absolute;\n width: 0;\n border-left-width: 1px;\n border-left-style: solid;\n}\n\n.vis.timeline .item .content {\n margin: 5px;\n white-space: nowrap;\n overflow: hidden;\n}\n\n.vis.timeline .axis {\n position: relative;\n}\n\n.vis.timeline .axis .text {\n position: absolute;\n color: #4d4d4d;\n padding: 3px;\n white-space: nowrap;\n}\n\n.vis.timeline .axis .text.measure {\n position: absolute;\n padding-left: 0;\n padding-right: 0;\n margin-left: 0;\n margin-right: 0;\n visibility: hidden;\n}\n\n.vis.timeline .axis .grid.vertical {\n position: absolute;\n width: 0;\n border-right: 1px solid;\n}\n\n.vis.timeline .axis .grid.horizontal {\n position: absolute;\n left: 0;\n width: 100%;\n height: 0;\n border-bottom: 1px solid;\n}\n\n.vis.timeline .axis .grid.minor {\n border-color: #e5e5e5;\n}\n\n.vis.timeline .axis .grid.major {\n border-color: #bfbfbf;\n}\n\n")},{hammerjs:1,moment:2}]},{},[3])(3)}); \ No newline at end of file From 563a21b886aa1d2dda2eb55944255a175e9352e5 Mon Sep 17 00:00:00 2001 From: josdejong Date: Fri, 20 Sep 2013 12:29:37 +0200 Subject: [PATCH 21/52] Fixed css style of subtitle --- css/style.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/css/style.css b/css/style.css index 289dc26f..9f66bc84 100644 --- a/css/style.css +++ b/css/style.css @@ -56,6 +56,12 @@ div.nav a { font-weight: bold; } +.subtitle { + color: gray; + text-transform: uppercase; + font-size: 11pt; +} + .download td { border: none; padding: 5px 20px 5px 0; From 63f0622fc62de8d9a2677411128e41c40aef5fff Mon Sep 17 00:00:00 2001 From: josdejong Date: Mon, 21 Oct 2013 15:00:30 +0200 Subject: [PATCH 22/52] Fixed broken links to moment.js --- examples/timeline/02_dataset.html | 2 +- examples/timeline/03_much_data.html | 2 +- examples/timeline/05_groups.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/timeline/02_dataset.html b/examples/timeline/02_dataset.html index ad74d2d5..36575945 100644 --- a/examples/timeline/02_dataset.html +++ b/examples/timeline/02_dataset.html @@ -20,7 +20,7 @@ - + diff --git a/examples/timeline/03_much_data.html b/examples/timeline/03_much_data.html index db94f807..45c4f40e 100644 --- a/examples/timeline/03_much_data.html +++ b/examples/timeline/03_much_data.html @@ -11,7 +11,7 @@ - + diff --git a/examples/timeline/05_groups.html b/examples/timeline/05_groups.html index 17b85200..d6c9ced4 100644 --- a/examples/timeline/05_groups.html +++ b/examples/timeline/05_groups.html @@ -17,7 +17,7 @@ - + From 748a5ba8f7fc6bea37a5e8f36aa32f0fbc8ae6bf Mon Sep 17 00:00:00 2001 From: josdejong Date: Fri, 3 Jan 2014 13:23:43 +0100 Subject: [PATCH 23/52] Switched to 2-space indentation --- css/style.css | 92 ++++---- index.html | 546 +++++++++++++++++++++++------------------------ updateversion.js | 132 ++++++------ 3 files changed, 385 insertions(+), 385 deletions(-) diff --git a/css/style.css b/css/style.css index 9f66bc84..60e54dab 100644 --- a/css/style.css +++ b/css/style.css @@ -1,94 +1,94 @@ #menu { - position: absolute; - left: -170px; - top: 35px; - background-color: #a7c8f9; - padding: 15px; - border-radius: 3px; + position: absolute; + left: -170px; + top: 35px; + background-color: #a7c8f9; + padding: 15px; + border-radius: 3px; } #forkme { - position: fixed; - top: 0; - right: 0; - border: 0; + position: fixed; + top: 0; + right: 0; + border: 0; } div.nav { - text-align: center; + text-align: center; } div.nav ul { - text-decoration: none; - text-transform: uppercase; + text-decoration: none; + text-transform: uppercase; - margin-bottom: 30px; - padding-left: 0; + margin-bottom: 30px; + padding-left: 0; } li.nav { } div.nav ul li { - text-decoration: none; - text-transform: uppercase; - font-weight: normal; - font-size: 11pt; + text-decoration: none; + text-transform: uppercase; + font-weight: normal; + font-size: 11pt; - list-style: none; - margin-top: 5px; + list-style: none; + margin-top: 5px; } div.nav ul li ul li { - text-decoration: none; - text-transform: none; - font-weight: normal; - font-size: 11pt; - color: #4D4D4D; + text-decoration: none; + text-transform: none; + font-weight: normal; + font-size: 11pt; + color: #4D4D4D; - list-style: none; + list-style: none; } div.nav a { - color: #2B7CE9; - color: white; - font-weight: bold; + color: #2B7CE9; + color: white; + font-weight: bold; } .subtitle { - color: gray; - text-transform: uppercase; - font-size: 11pt; + color: gray; + text-transform: uppercase; + font-size: 11pt; } .download td { - border: none; - padding: 5px 20px 5px 0; + border: none; + padding: 5px 20px 5px 0; } .gallery .thumb { - display: inline-block; - text-align: center; - margin-right: 10px; - margin-bottom: 20px; + display: inline-block; + text-align: center; + margin-right: 10px; + margin-bottom: 20px; } .gallery .thumb img { - border: 1px solid white; - border-radius: 5px; - height: 90px; - margin: 0; + border: 1px solid white; + border-radius: 5px; + height: 90px; + margin: 0; } .gallery .thumb a:hover img { - border-color: lightgray; + border-color: lightgray; } .gallery .thumb div { - margin: 0; + margin: 0; } img { - border: 0; + border: 0; } \ No newline at end of file diff --git a/index.html b/index.html index 65261521..4ba37bae 100644 --- a/index.html +++ b/index.html @@ -2,104 +2,104 @@ - vis.js | a dynamic, browser-based visualization library + vis.js | a dynamic, browser-based visualization library - - - - - + + + + + - - - + + + - +
    - - -

    - vis.js
    - a visual interaction system -

    - -

    - Vis.js is a dynamic, browser based visualization library. - The library is designed to be easy to use, to handle large amounts - of dynamic data, and to enable manipulation of and interaction with the data. - The library consists of the components DataSet, Timeline, and Graph. -

    -

    - The vis.js library is developed by Almende B.V, - as part of the CHAP. -

    - - -

    Install

    - -

    npm

    + + +

    + vis.js
    + a visual interaction system +

    + +

    + Vis.js is a dynamic, browser based visualization library. + The library is designed to be easy to use, to handle large amounts + of dynamic data, and to enable manipulation of and interaction with the data. + The library consists of the components DataSet, Timeline, and Graph. +

    +

    + The vis.js library is developed by Almende B.V, + as part of the CHAP. +

    + + +

    Install

    + +

    npm

     npm install vis
     
    -

    bower

    +

    bower

     bower install vis
     
    -

    download

    - - - - - - - - - - -
    - Development - (version 0.2.0) - - 441 kB, uncompressed with comments -
    - Production - (version 0.2.0) - - 39 kB, minified and gzipped -
    - - -

    Example

    - -

    - A basic example demonstrating how to use the vis.js timeline is shown below. - See the gallery below for more examples. -

    +

    download

    + + + + + + + + + + +
    + Development + (version 0.2.0) + + 441 kB, uncompressed with comments +
    + Production + (version 0.2.0) + + 39 kB, minified and gzipped +
    + + +

    Example

    + +

    + A basic example demonstrating how to use the vis.js timeline is shown below. + See the gallery below for more examples. +

    <!doctype html>
     <html>
    @@ -134,200 +134,200 @@ bower install vis
     
    - - This gallery gives an idea of the features and possibilities of the library. - The source code of the examples can be found in the - examples directory. - -

    Timeline

    -

    - The timeline from vis.js displays different types of data on a timeline. -

    - - -

    Graph

    -

    - The graph from vis.js visualizes graphs and networks with - customizable styles. -

    - - - -

    Docs

    - -

    - Documentation is available here: - Documentation -

    - - -

    License

    - -

    - Copyright (C) 2010-2013 Almende B.V. -

    - -

    - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at -

    - -

    - http://www.apache.org/licenses/LICENSE-2.0 -

    - -

    - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -

    - - - Fork me on GitHub + +This gallery gives an idea of the features and possibilities of the library. +The source code of the examples can be found in the +examples directory. + +

    Timeline

    +

    + The timeline from vis.js displays different types of data on a timeline. +

    + + +

    Graph

    +

    + The graph from vis.js visualizes graphs and networks with + customizable styles. +

    + + + +

    Docs

    + +

    + Documentation is available here: + Documentation +

    + + +

    License

    + +

    + Copyright (C) 2010-2013 Almende B.V. +

    + +

    + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at +

    + +

    + http://www.apache.org/licenses/LICENSE-2.0 +

    + +

    + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +

    + + + Fork me on GitHub +
    diff --git a/updateversion.js b/updateversion.js index 99a21d1a..094dfd16 100644 --- a/updateversion.js +++ b/updateversion.js @@ -9,94 +9,94 @@ var VIS = 'vis.js', // get development size function developmentSize(callback) { - fs.readFile(VIS, function (err, data) { - if (!err) { - var size = Math.round(data.length / 1024) + ' kB'; - callback(null, size); - } - else { - callback(err); - } - }); + fs.readFile(VIS, function (err, data) { + if (!err) { + var size = Math.round(data.length / 1024) + ' kB'; + callback(null, size); + } + else { + callback(err); + } + }); } // get (gzipped) production size function productionSize(callback) { - fs.readFile(VIS_MIN, function (err, data) { + fs.readFile(VIS_MIN, function (err, data) { + if (!err) { + zlib.gzip(data, function (err, data) { if (!err) { - zlib.gzip(data, function (err, data) { - if (!err) { - var size = Math.round(data.length / 1024) + ' kB'; - callback(null, size) - } - else { - callback(err); - } - }); + var size = Math.round(data.length / 1024) + ' kB'; + callback(null, size) } else { - callback(err); + callback(err); } - }); + }); + } + else { + callback(err); + } + }); } // get version function version(callback) { - fs.readFile(VIS_MIN, function (err, data) { - if (!err) { - var match = /@version\s*([\w\.-]*)/i.exec(data); - var version = undefined; - if (match) { - version = match[1]; - } - callback(null, version); - } - else { - callback(err); - } - }); + fs.readFile(VIS_MIN, function (err, data) { + if (!err) { + var match = /@version\s*([\w\.-]*)/i.exec(data); + var version = undefined; + if (match) { + version = match[1]; + } + callback(null, version); + } + else { + callback(err); + } + }); } // update version and library sizes in index.md function updateVersion(developmentSize, productionSize, version, callback) { - fs.readFile(INDEX, function (err, data) { - if (!err) { - data = String(data); - data = data.replace(/([\w\s]*)<\/span>/g, - '' + developmentSize + ''); + fs.readFile(INDEX, function (err, data) { + if (!err) { + data = String(data); + data = data.replace(/([\w\s]*)<\/span>/g, + '' + developmentSize + ''); - data = data.replace(/([\w\s]*)<\/span>/g, - '' + productionSize + ''); + data = data.replace(/([\w\s]*)<\/span>/g, + '' + productionSize + ''); - data = data.replace(/([\w\.-]*)<\/span>/g, - '' + version + ''); + data = data.replace(/([\w\.-]*)<\/span>/g, + '' + version + ''); - fs.writeFile(INDEX, data, callback); - } - else { - callback(err); - } - }); + fs.writeFile(INDEX, data, callback); + } + else { + callback(err); + } + }); } developmentSize(function (err, devSize) { - console.log('development size: ' + devSize); - productionSize(function (err, prodSize) { - console.log('production size: ' + prodSize); - version(function (err, version) { - console.log('version: ' + version); - if (devSize && prodSize && version) { - updateVersion(devSize, prodSize, version, function (err, res) { - if (err) { - console.log(err); - } - else { - console.log('done'); - } - }); - } - else { - } + console.log('development size: ' + devSize); + productionSize(function (err, prodSize) { + console.log('production size: ' + prodSize); + version(function (err, version) { + console.log('version: ' + version); + if (devSize && prodSize && version) { + updateVersion(devSize, prodSize, version, function (err, res) { + if (err) { + console.log(err); + } + else { + console.log('done'); + } }); + } + else { + } }); + }); }); From 1f6064b491c473d2b957aadadaa05bbc3e2393aa Mon Sep 17 00:00:00 2001 From: josdejong Date: Tue, 14 Jan 2014 17:29:19 +0100 Subject: [PATCH 24/52] Released version 0.3.0 --- dist/vis.css | 235 + dist/vis.js | 15765 ++++++++++++++++ dist/vis.min.js | 29 + docs/css/prettify.css | 102 +- docs/css/style.css | 78 +- docs/dataset.html | 1095 +- docs/dataview.html | 272 +- docs/graph.html | 1636 +- docs/index.html | 255 +- docs/timeline.html | 883 +- download/vis.zip | Bin 0 -> 941597 bytes examples/graph/01_basic_usage.html | 68 +- examples/graph/02_random_nodes.html | 168 +- examples/graph/03_images.html | 144 +- examples/graph/04_shapes.html | 114 +- examples/graph/05_social_network.html | 116 +- examples/graph/06_groups.html | 282 +- examples/graph/07_selections.html | 88 +- examples/graph/08_mobile_friendly.html | 174 +- examples/graph/09_sizing.html | 126 +- examples/graph/10_multiline_text.html | 72 +- examples/graph/11_custom_style.html | 228 +- examples/graph/12_scalable_images.html | 132 +- examples/graph/13_dashed_lines.html | 104 +- examples/graph/14_dot_language.html | 20 +- .../graph/15_dot_language_playground.html | 344 +- examples/graph/16_dynamic_data.html | 448 +- examples/graph/17_network_info.html | 280 +- examples/graph/graphviz/graphviz_gallery.html | 120 +- examples/graph/index.html | 42 +- examples/timeline/01_basic.html | 37 +- examples/timeline/02_dataset.html | 100 +- examples/timeline/03_much_data.html | 3 +- examples/timeline/04_html_data.html | 99 +- examples/timeline/05_groups.html | 101 +- examples/timeline/index.html | 16 +- .../timeline/requirejs/requirejs_example.html | 8 +- examples/timeline/requirejs/scripts/main.js | 28 +- index.html | 63 +- package.js | 0 updateversion.js | 78 +- vis.js | 14667 -------------- vis.min.js | 29 - 43 files changed, 19997 insertions(+), 18652 deletions(-) create mode 100644 dist/vis.css create mode 100644 dist/vis.js create mode 100644 dist/vis.min.js create mode 100644 download/vis.zip create mode 100644 package.js delete mode 100644 vis.js delete mode 100644 vis.min.js diff --git a/dist/vis.css b/dist/vis.css new file mode 100644 index 00000000..4f54a95f --- /dev/null +++ b/dist/vis.css @@ -0,0 +1,235 @@ +.vis.timeline { +} + + +.vis.timeline.rootpanel { + position: relative; + overflow: hidden; + + border: 1px solid #bfbfbf; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.vis.timeline .panel { + position: absolute; + overflow: hidden; +} + + +.vis.timeline .groupset { + position: absolute; + padding: 0; + margin: 0; +} + +.vis.timeline .labels { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + + padding: 0; + margin: 0; + + border-right: 1px solid #bfbfbf; + box-sizing: border-box; + -moz-box-sizing: border-box; +} + +.vis.timeline .labels .label-set { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + + overflow: hidden; + + border-top: none; + border-bottom: 1px solid #bfbfbf; +} + +.vis.timeline .labels .label-set .label { + position: absolute; + left: 0; + top: 0; + width: 100%; + color: #4d4d4d; +} + +.vis.timeline.top .labels .label-set .label, +.vis.timeline.top .groupset .itemset-axis { + border-top: 1px solid #bfbfbf; + border-bottom: none; +} + +.vis.timeline.bottom .labels .label-set .label, +.vis.timeline.bottom .groupset .itemset-axis { + border-top: none; + border-bottom: 1px solid #bfbfbf; +} + +.vis.timeline .labels .label-set .label .inner { + display: inline-block; + padding: 5px; +} + + +.vis.timeline .itemset { + position: absolute; + padding: 0; + margin: 0; + overflow: hidden; +} + +.vis.timeline .background { +} + +.vis.timeline .foreground { +} + +.vis.timeline .itemset-axis { + position: absolute; +} + + +.vis.timeline .item { + position: absolute; + color: #1A1A1A; + border-color: #97B0F8; + background-color: #D5DDF6; + display: inline-block; +} + +.vis.timeline .item.selected { + border-color: #FFC200; + background-color: #FFF785; + z-index: 999; +} + +.vis.timeline .item.cluster { + /* TODO: use another color or pattern? */ + background: #97B0F8 url('img/cluster_bg.png'); + color: white; +} +.vis.timeline .item.cluster.point { + border-color: #D5DDF6; +} + +.vis.timeline .item.box { + text-align: center; + border-style: solid; + border-width: 1px; + border-radius: 5px; + -moz-border-radius: 5px; /* For Firefox 3.6 and older */ +} + +.vis.timeline .item.point { + background: none; +} + +.vis.timeline .dot { + border: 5px solid #97B0F8; + position: absolute; + border-radius: 5px; + -moz-border-radius: 5px; /* For Firefox 3.6 and older */ +} + +.vis.timeline .item.range { + overflow: hidden; + border-style: solid; + border-width: 1px; + border-radius: 2px; + -moz-border-radius: 2px; /* For Firefox 3.6 and older */ +} + +.vis.timeline .item.rangeoverflow { + border-style: solid; + border-width: 1px; + border-radius: 2px; + -moz-border-radius: 2px; /* For Firefox 3.6 and older */ +} + +.vis.timeline .item.range .drag-left, .vis.timeline .item.rangeoverflow .drag-left { + cursor: w-resize; + z-index: 1000; +} + +.vis.timeline .item.range .drag-right, .vis.timeline .item.rangeoverflow .drag-right { + cursor: e-resize; + z-index: 1000; +} + +.vis.timeline .item.range .content, .vis.timeline .item.rangeoverflow .content { + position: relative; + display: inline-block; +} + +.vis.timeline .item.line { + position: absolute; + width: 0; + border-left-width: 1px; + border-left-style: solid; +} + +.vis.timeline .item .content { + margin: 5px; + white-space: nowrap; + overflow: hidden; +} + +.vis.timeline .axis { + position: relative; +} + +.vis.timeline .axis .text { + position: absolute; + color: #4d4d4d; + padding: 3px; + white-space: nowrap; +} + +.vis.timeline .axis .text.measure { + position: absolute; + padding-left: 0; + padding-right: 0; + margin-left: 0; + margin-right: 0; + visibility: hidden; +} + +.vis.timeline .axis .grid.vertical { + position: absolute; + width: 0; + border-right: 1px solid; +} + +.vis.timeline .axis .grid.horizontal { + position: absolute; + left: 0; + width: 100%; + height: 0; + border-bottom: 1px solid; +} + +.vis.timeline .axis .grid.minor { + border-color: #e5e5e5; +} + +.vis.timeline .axis .grid.major { + border-color: #bfbfbf; +} + +.vis.timeline .currenttime { + background-color: #FF7F6E; + width: 2px; + z-index: 9; +} +.vis.timeline .customtime { + background-color: #6E94FF; + width: 2px; + cursor: move; + z-index: 9; +} diff --git a/dist/vis.js b/dist/vis.js new file mode 100644 index 00000000..7594f2f9 --- /dev/null +++ b/dist/vis.js @@ -0,0 +1,15765 @@ +/** + * vis.js + * https://github.com/almende/vis + * + * A dynamic, browser-based visualization library. + * + * @version 0.3.0 + * @date 2014-01-14 + * + * @license + * Copyright (C) 2011-2013 Almende B.V, http://almende.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +!function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.vis=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o>> 0; + + // 4. If IsCallable(callback) is false, throw a TypeError exception. + // See: http://es5.github.com/#x9.11 + if (typeof callback !== "function") { + throw new TypeError(callback + " is not a function"); + } + + // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. + if (thisArg) { + T = thisArg; + } + + // 6. Let A be a new array created as if by the expression new Array(len) where Array is + // the standard built-in constructor with that name and len is the value of len. + A = new Array(len); + + // 7. Let k be 0 + k = 0; + + // 8. Repeat, while k < len + while(k < len) { + + var kValue, mappedValue; + + // a. Let Pk be ToString(k). + // This is implicit for LHS operands of the in operator + // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk. + // This step can be combined with c + // c. If kPresent is true, then + if (k in O) { + + // i. Let kValue be the result of calling the Get internal method of O with argument Pk. + kValue = O[ k ]; + + // ii. Let mappedValue be the result of calling the Call internal method of callback + // with T as the this value and argument list containing kValue, k, and O. + mappedValue = callback.call(T, kValue, k, O); + + // iii. Call the DefineOwnProperty internal method of A with arguments + // Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true}, + // and false. + + // In browsers that support Object.defineProperty, use the following: + // Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true }); + + // For best browser support, use the following: + A[ k ] = mappedValue; + } + // d. Increase k by 1. + k++; + } + + // 9. return A + return A; + }; +} + +// Internet Explorer 8 and older does not support Array.filter, so we define it +// here in that case. +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/filter +if (!Array.prototype.filter) { + Array.prototype.filter = function(fun /*, thisp */) { + "use strict"; + + if (this == null) { + throw new TypeError(); + } + + var t = Object(this); + var len = t.length >>> 0; + if (typeof fun != "function") { + throw new TypeError(); + } + + var res = []; + var thisp = arguments[1]; + for (var i = 0; i < len; i++) { + if (i in t) { + var val = t[i]; // in case fun mutates this + if (fun.call(thisp, val, i, t)) + res.push(val); + } + } + + return res; + }; +} + + +// Internet Explorer 8 and older does not support Object.keys, so we define it +// here in that case. +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys +if (!Object.keys) { + Object.keys = (function () { + var hasOwnProperty = Object.prototype.hasOwnProperty, + hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), + dontEnums = [ + 'toString', + 'toLocaleString', + 'valueOf', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'constructor' + ], + dontEnumsLength = dontEnums.length; + + return function (obj) { + if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) { + throw new TypeError('Object.keys called on non-object'); + } + + var result = []; + + for (var prop in obj) { + if (hasOwnProperty.call(obj, prop)) result.push(prop); + } + + if (hasDontEnumBug) { + for (var i=0; i < dontEnumsLength; i++) { + if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]); + } + } + return result; + } + })() +} + +// Internet Explorer 8 and older does not support Array.isArray, +// so we define it here in that case. +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/isArray +if(!Array.isArray) { + Array.isArray = function (vArg) { + return Object.prototype.toString.call(vArg) === "[object Array]"; + }; +} + +// Internet Explorer 8 and older does not support Function.bind, +// so we define it here in that case. +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind +if (!Function.prototype.bind) { + Function.prototype.bind = function (oThis) { + if (typeof this !== "function") { + // closest thing possible to the ECMAScript 5 internal IsCallable function + throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); + } + + var aArgs = Array.prototype.slice.call(arguments, 1), + fToBind = this, + fNOP = function () {}, + fBound = function () { + return fToBind.apply(this instanceof fNOP && oThis + ? this + : oThis, + aArgs.concat(Array.prototype.slice.call(arguments))); + }; + + fNOP.prototype = this.prototype; + fBound.prototype = new fNOP(); + + return fBound; + }; +} + +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create +if (!Object.create) { + Object.create = function (o) { + if (arguments.length > 1) { + throw new Error('Object.create implementation only accepts the first parameter.'); + } + function F() {} + F.prototype = o; + return new F(); + }; +} + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind +if (!Function.prototype.bind) { + Function.prototype.bind = function (oThis) { + if (typeof this !== "function") { + // closest thing possible to the ECMAScript 5 internal IsCallable function + throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); + } + + var aArgs = Array.prototype.slice.call(arguments, 1), + fToBind = this, + fNOP = function () {}, + fBound = function () { + return fToBind.apply(this instanceof fNOP && oThis + ? this + : oThis, + aArgs.concat(Array.prototype.slice.call(arguments))); + }; + + fNOP.prototype = this.prototype; + fBound.prototype = new fNOP(); + + return fBound; + }; +} + +/** + * utility functions + */ +var util = {}; + +/** + * Test whether given object is a number + * @param {*} object + * @return {Boolean} isNumber + */ +util.isNumber = function isNumber(object) { + return (object instanceof Number || typeof object == 'number'); +}; + +/** + * Test whether given object is a string + * @param {*} object + * @return {Boolean} isString + */ +util.isString = function isString(object) { + return (object instanceof String || typeof object == 'string'); +}; + +/** + * Test whether given object is a Date, or a String containing a Date + * @param {Date | String} object + * @return {Boolean} isDate + */ +util.isDate = function isDate(object) { + if (object instanceof Date) { + return true; + } + else if (util.isString(object)) { + // test whether this string contains a date + var match = ASPDateRegex.exec(object); + if (match) { + return true; + } + else if (!isNaN(Date.parse(object))) { + return true; + } + } + + return false; +}; + +/** + * Test whether given object is an instance of google.visualization.DataTable + * @param {*} object + * @return {Boolean} isDataTable + */ +util.isDataTable = function isDataTable(object) { + return (typeof (google) !== 'undefined') && + (google.visualization) && + (google.visualization.DataTable) && + (object instanceof google.visualization.DataTable); +}; + +/** + * Create a semi UUID + * source: http://stackoverflow.com/a/105074/1262753 + * @return {String} uuid + */ +util.randomUUID = function randomUUID () { + var S4 = function () { + return Math.floor( + Math.random() * 0x10000 /* 65536 */ + ).toString(16); + }; + + return ( + S4() + S4() + '-' + + S4() + '-' + + S4() + '-' + + S4() + '-' + + S4() + S4() + S4() + ); +}; + +/** + * Extend object a with the properties of object b or a series of objects + * Only properties with defined values are copied + * @param {Object} a + * @param {... Object} b + * @return {Object} a + */ +util.extend = function (a, b) { + for (var i = 1, len = arguments.length; i < len; i++) { + var other = arguments[i]; + for (var prop in other) { + if (other.hasOwnProperty(prop) && other[prop] !== undefined) { + a[prop] = other[prop]; + } + } + } + + return a; +}; + +/** + * Convert an object to another type + * @param {Boolean | Number | String | Date | Moment | Null | undefined} object + * @param {String | undefined} type Name of the type. Available types: + * 'Boolean', 'Number', 'String', + * 'Date', 'Moment', ISODate', 'ASPDate'. + * @return {*} object + * @throws Error + */ +util.convert = function convert(object, type) { + var match; + + if (object === undefined) { + return undefined; + } + if (object === null) { + return null; + } + + if (!type) { + return object; + } + if (!(typeof type === 'string') && !(type instanceof String)) { + throw new Error('Type must be a string'); + } + + //noinspection FallthroughInSwitchStatementJS + switch (type) { + case 'boolean': + case 'Boolean': + return Boolean(object); + + case 'number': + case 'Number': + return Number(object.valueOf()); + + case 'string': + case 'String': + return String(object); + + case 'Date': + if (util.isNumber(object)) { + return new Date(object); + } + if (object instanceof Date) { + return new Date(object.valueOf()); + } + else if (moment.isMoment(object)) { + return new Date(object.valueOf()); + } + if (util.isString(object)) { + match = ASPDateRegex.exec(object); + if (match) { + // object is an ASP date + return new Date(Number(match[1])); // parse number + } + else { + return moment(object).toDate(); // parse string + } + } + else { + throw new Error( + 'Cannot convert object of type ' + util.getType(object) + + ' to type Date'); + } + + case 'Moment': + if (util.isNumber(object)) { + return moment(object); + } + if (object instanceof Date) { + return moment(object.valueOf()); + } + else if (moment.isMoment(object)) { + return moment(object); + } + if (util.isString(object)) { + match = ASPDateRegex.exec(object); + if (match) { + // object is an ASP date + return moment(Number(match[1])); // parse number + } + else { + return moment(object); // parse string + } + } + else { + throw new Error( + 'Cannot convert object of type ' + util.getType(object) + + ' to type Date'); + } + + case 'ISODate': + if (util.isNumber(object)) { + return new Date(object); + } + else if (object instanceof Date) { + return object.toISOString(); + } + else if (moment.isMoment(object)) { + return object.toDate().toISOString(); + } + else if (util.isString(object)) { + match = ASPDateRegex.exec(object); + if (match) { + // object is an ASP date + return new Date(Number(match[1])).toISOString(); // parse number + } + else { + return new Date(object).toISOString(); // parse string + } + } + else { + throw new Error( + 'Cannot convert object of type ' + util.getType(object) + + ' to type ISODate'); + } + + case 'ASPDate': + if (util.isNumber(object)) { + return '/Date(' + object + ')/'; + } + else if (object instanceof Date) { + return '/Date(' + object.valueOf() + ')/'; + } + else if (util.isString(object)) { + match = ASPDateRegex.exec(object); + var value; + if (match) { + // object is an ASP date + value = new Date(Number(match[1])).valueOf(); // parse number + } + else { + value = new Date(object).valueOf(); // parse string + } + return '/Date(' + value + ')/'; + } + else { + throw new Error( + 'Cannot convert object of type ' + util.getType(object) + + ' to type ASPDate'); + } + + default: + throw new Error('Cannot convert object of type ' + util.getType(object) + + ' to type "' + type + '"'); + } +}; + +// parse ASP.Net Date pattern, +// for example '/Date(1198908717056)/' or '/Date(1198908717056-0700)/' +// code from http://momentjs.com/ +var ASPDateRegex = /^\/?Date\((\-?\d+)/i; + +/** + * Get the type of an object, for example util.getType([]) returns 'Array' + * @param {*} object + * @return {String} type + */ +util.getType = function getType(object) { + var type = typeof object; + + if (type == 'object') { + if (object == null) { + return 'null'; + } + if (object instanceof Boolean) { + return 'Boolean'; + } + if (object instanceof Number) { + return 'Number'; + } + if (object instanceof String) { + return 'String'; + } + if (object instanceof Array) { + return 'Array'; + } + if (object instanceof Date) { + return 'Date'; + } + return 'Object'; + } + else if (type == 'number') { + return 'Number'; + } + else if (type == 'boolean') { + return 'Boolean'; + } + else if (type == 'string') { + return 'String'; + } + + return type; +}; + +/** + * Retrieve the absolute left value of a DOM element + * @param {Element} elem A dom element, for example a div + * @return {number} left The absolute left position of this element + * in the browser page. + */ +util.getAbsoluteLeft = function getAbsoluteLeft (elem) { + var doc = document.documentElement; + var body = document.body; + + var left = elem.offsetLeft; + var e = elem.offsetParent; + while (e != null && e != body && e != doc) { + left += e.offsetLeft; + left -= e.scrollLeft; + e = e.offsetParent; + } + return left; +}; + +/** + * Retrieve the absolute top value of a DOM element + * @param {Element} elem A dom element, for example a div + * @return {number} top The absolute top position of this element + * in the browser page. + */ +util.getAbsoluteTop = function getAbsoluteTop (elem) { + var doc = document.documentElement; + var body = document.body; + + var top = elem.offsetTop; + var e = elem.offsetParent; + while (e != null && e != body && e != doc) { + top += e.offsetTop; + top -= e.scrollTop; + e = e.offsetParent; + } + return top; +}; + +/** + * Get the absolute, vertical mouse position from an event. + * @param {Event} event + * @return {Number} pageY + */ +util.getPageY = function getPageY (event) { + if ('pageY' in event) { + return event.pageY; + } + else { + var clientY; + if (('targetTouches' in event) && event.targetTouches.length) { + clientY = event.targetTouches[0].clientY; + } + else { + clientY = event.clientY; + } + + var doc = document.documentElement; + var body = document.body; + return clientY + + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - + ( doc && doc.clientTop || body && body.clientTop || 0 ); + } +}; + +/** + * Get the absolute, horizontal mouse position from an event. + * @param {Event} event + * @return {Number} pageX + */ +util.getPageX = function getPageX (event) { + if ('pageY' in event) { + return event.pageX; + } + else { + var clientX; + if (('targetTouches' in event) && event.targetTouches.length) { + clientX = event.targetTouches[0].clientX; + } + else { + clientX = event.clientX; + } + + var doc = document.documentElement; + var body = document.body; + return clientX + + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - + ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + } +}; + +/** + * add a className to the given elements style + * @param {Element} elem + * @param {String} className + */ +util.addClassName = function addClassName(elem, className) { + var classes = elem.className.split(' '); + if (classes.indexOf(className) == -1) { + classes.push(className); // add the class to the array + elem.className = classes.join(' '); + } +}; + +/** + * add a className to the given elements style + * @param {Element} elem + * @param {String} className + */ +util.removeClassName = function removeClassname(elem, className) { + var classes = elem.className.split(' '); + var index = classes.indexOf(className); + if (index != -1) { + classes.splice(index, 1); // remove the class from the array + elem.className = classes.join(' '); + } +}; + +/** + * For each method for both arrays and objects. + * In case of an array, the built-in Array.forEach() is applied. + * In case of an Object, the method loops over all properties of the object. + * @param {Object | Array} object An Object or Array + * @param {function} callback Callback method, called for each item in + * the object or array with three parameters: + * callback(value, index, object) + */ +util.forEach = function forEach (object, callback) { + var i, + len; + if (object instanceof Array) { + // array + for (i = 0, len = object.length; i < len; i++) { + callback(object[i], i, object); + } + } + else { + // object + for (i in object) { + if (object.hasOwnProperty(i)) { + callback(object[i], i, object); + } + } + } +}; + +/** + * Update a property in an object + * @param {Object} object + * @param {String} key + * @param {*} value + * @return {Boolean} changed + */ +util.updateProperty = function updateProp (object, key, value) { + if (object[key] !== value) { + object[key] = value; + return true; + } + else { + return false; + } +}; + +/** + * Add and event listener. Works for all browsers + * @param {Element} element An html element + * @param {string} action The action, for example "click", + * without the prefix "on" + * @param {function} listener The callback function to be executed + * @param {boolean} [useCapture] + */ +util.addEventListener = function addEventListener(element, action, listener, useCapture) { + if (element.addEventListener) { + if (useCapture === undefined) + useCapture = false; + + if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) { + action = "DOMMouseScroll"; // For Firefox + } + + element.addEventListener(action, listener, useCapture); + } else { + element.attachEvent("on" + action, listener); // IE browsers + } +}; + +/** + * Remove an event listener from an element + * @param {Element} element An html dom element + * @param {string} action The name of the event, for example "mousedown" + * @param {function} listener The listener function + * @param {boolean} [useCapture] + */ +util.removeEventListener = function removeEventListener(element, action, listener, useCapture) { + if (element.removeEventListener) { + // non-IE browsers + if (useCapture === undefined) + useCapture = false; + + if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) { + action = "DOMMouseScroll"; // For Firefox + } + + element.removeEventListener(action, listener, useCapture); + } else { + // IE browsers + element.detachEvent("on" + action, listener); + } +}; + + +/** + * Get HTML element which is the target of the event + * @param {Event} event + * @return {Element} target element + */ +util.getTarget = function getTarget(event) { + // code from http://www.quirksmode.org/js/events_properties.html + if (!event) { + event = window.event; + } + + var target; + + if (event.target) { + target = event.target; + } + else if (event.srcElement) { + target = event.srcElement; + } + + if (target.nodeType != undefined && target.nodeType == 3) { + // defeat Safari bug + target = target.parentNode; + } + + return target; +}; + +/** + * Stop event propagation + */ +util.stopPropagation = function stopPropagation(event) { + if (!event) + event = window.event; + + if (event.stopPropagation) { + event.stopPropagation(); // non-IE browsers + } + else { + event.cancelBubble = true; // IE browsers + } +}; + +/** + * Fake a hammer.js gesture. Event can be a ScrollEvent or MouseMoveEvent + * @param {Element} element + * @param {Event} event + */ +util.fakeGesture = function fakeGesture (element, event) { + var eventType = null; + + // for hammer.js 1.0.5 + return Hammer.event.collectEventData(this, eventType, event); + + // for hammer.js 1.0.6 + //var touches = Hammer.event.getTouchList(event, eventType); + //return Hammer.event.collectEventData(this, eventType, touches, event); +}; + +/** + * Cancels the event if it is cancelable, without stopping further propagation of the event. + */ +util.preventDefault = function preventDefault (event) { + if (!event) + event = window.event; + + if (event.preventDefault) { + event.preventDefault(); // non-IE browsers + } + else { + event.returnValue = false; // IE browsers + } +}; + + +util.option = {}; + +/** + * Convert a value into a boolean + * @param {Boolean | function | undefined} value + * @param {Boolean} [defaultValue] + * @returns {Boolean} bool + */ +util.option.asBoolean = function (value, defaultValue) { + if (typeof value == 'function') { + value = value(); + } + + if (value != null) { + return (value != false); + } + + return defaultValue || null; +}; + +/** + * Convert a value into a number + * @param {Boolean | function | undefined} value + * @param {Number} [defaultValue] + * @returns {Number} number + */ +util.option.asNumber = function (value, defaultValue) { + if (typeof value == 'function') { + value = value(); + } + + if (value != null) { + return Number(value) || defaultValue || null; + } + + return defaultValue || null; +}; + +/** + * Convert a value into a string + * @param {String | function | undefined} value + * @param {String} [defaultValue] + * @returns {String} str + */ +util.option.asString = function (value, defaultValue) { + if (typeof value == 'function') { + value = value(); + } + + if (value != null) { + return String(value); + } + + return defaultValue || null; +}; + +/** + * Convert a size or location into a string with pixels or a percentage + * @param {String | Number | function | undefined} value + * @param {String} [defaultValue] + * @returns {String} size + */ +util.option.asSize = function (value, defaultValue) { + if (typeof value == 'function') { + value = value(); + } + + if (util.isString(value)) { + return value; + } + else if (util.isNumber(value)) { + return value + 'px'; + } + else { + return defaultValue || null; + } +}; + +/** + * Convert a value into a DOM element + * @param {HTMLElement | function | undefined} value + * @param {HTMLElement} [defaultValue] + * @returns {HTMLElement | null} dom + */ +util.option.asElement = function (value, defaultValue) { + if (typeof value == 'function') { + value = value(); + } + + return value || defaultValue || null; +}; + +/** + * Event listener (singleton) + */ +// TODO: replace usage of the event listener for the EventBus +var events = { + 'listeners': [], + + /** + * Find a single listener by its object + * @param {Object} object + * @return {Number} index -1 when not found + */ + 'indexOf': function (object) { + var listeners = this.listeners; + for (var i = 0, iMax = this.listeners.length; i < iMax; i++) { + var listener = listeners[i]; + if (listener && listener.object == object) { + return i; + } + } + return -1; + }, + + /** + * Add an event listener + * @param {Object} object + * @param {String} event The name of an event, for example 'select' + * @param {function} callback The callback method, called when the + * event takes place + */ + 'addListener': function (object, event, callback) { + var index = this.indexOf(object); + var listener = this.listeners[index]; + if (!listener) { + listener = { + 'object': object, + 'events': {} + }; + this.listeners.push(listener); + } + + var callbacks = listener.events[event]; + if (!callbacks) { + callbacks = []; + listener.events[event] = callbacks; + } + + // add the callback if it does not yet exist + if (callbacks.indexOf(callback) == -1) { + callbacks.push(callback); + } + }, + + /** + * Remove an event listener + * @param {Object} object + * @param {String} event The name of an event, for example 'select' + * @param {function} callback The registered callback method + */ + 'removeListener': function (object, event, callback) { + var index = this.indexOf(object); + var listener = this.listeners[index]; + if (listener) { + var callbacks = listener.events[event]; + if (callbacks) { + index = callbacks.indexOf(callback); + if (index != -1) { + callbacks.splice(index, 1); + } + + // remove the array when empty + if (callbacks.length == 0) { + delete listener.events[event]; + } + } + + // count the number of registered events. remove listener when empty + var count = 0; + var events = listener.events; + for (var e in events) { + if (events.hasOwnProperty(e)) { + count++; + } + } + if (count == 0) { + delete this.listeners[index]; + } + } + }, + + /** + * Remove all registered event listeners + */ + 'removeAllListeners': function () { + this.listeners = []; + }, + + /** + * Trigger an event. All registered event handlers will be called + * @param {Object} object + * @param {String} event + * @param {Object} properties (optional) + */ + 'trigger': function (object, event, properties) { + var index = this.indexOf(object); + var listener = this.listeners[index]; + if (listener) { + var callbacks = listener.events[event]; + if (callbacks) { + for (var i = 0, iMax = callbacks.length; i < iMax; i++) { + callbacks[i](properties); + } + } + } + } +}; + +/** + * An event bus can be used to emit events, and to subscribe to events + * @constructor EventBus + */ +function EventBus() { + this.subscriptions = []; +} + +/** + * Subscribe to an event + * @param {String | RegExp} event The event can be a regular expression, or + * a string with wildcards, like 'server.*'. + * @param {function} callback. Callback are called with three parameters: + * {String} event, {*} [data], {*} [source] + * @param {*} [target] + * @returns {String} id A subscription id + */ +EventBus.prototype.on = function (event, callback, target) { + var regexp = (event instanceof RegExp) ? + event : + new RegExp(event.replace('*', '\\w+')); + + var subscription = { + id: util.randomUUID(), + event: event, + regexp: regexp, + callback: (typeof callback === 'function') ? callback : null, + target: target + }; + + this.subscriptions.push(subscription); + + return subscription.id; +}; + +/** + * Unsubscribe from an event + * @param {String | Object} filter Filter for subscriptions to be removed + * Filter can be a string containing a + * subscription id, or an object containing + * one or more of the fields id, event, + * callback, and target. + */ +EventBus.prototype.off = function (filter) { + var i = 0; + while (i < this.subscriptions.length) { + var subscription = this.subscriptions[i]; + + var match = true; + if (filter instanceof Object) { + // filter is an object. All fields must match + for (var prop in filter) { + if (filter.hasOwnProperty(prop)) { + if (filter[prop] !== subscription[prop]) { + match = false; + } + } + } + } + else { + // filter is a string, filter on id + match = (subscription.id == filter); + } + + if (match) { + this.subscriptions.splice(i, 1); + } + else { + i++; + } + } +}; + +/** + * Emit an event + * @param {String} event + * @param {*} [data] + * @param {*} [source] + */ +EventBus.prototype.emit = function (event, data, source) { + for (var i =0; i < this.subscriptions.length; i++) { + var subscription = this.subscriptions[i]; + if (subscription.regexp.test(event)) { + if (subscription.callback) { + subscription.callback(event, data, source); + } + } + } +}; + +/** + * DataSet + * + * Usage: + * var dataSet = new DataSet({ + * fieldId: '_id', + * convert: { + * // ... + * } + * }); + * + * dataSet.add(item); + * dataSet.add(data); + * dataSet.update(item); + * dataSet.update(data); + * dataSet.remove(id); + * dataSet.remove(ids); + * var data = dataSet.get(); + * var data = dataSet.get(id); + * var data = dataSet.get(ids); + * var data = dataSet.get(ids, options, data); + * dataSet.clear(); + * + * A data set can: + * - add/remove/update data + * - gives triggers upon changes in the data + * - can import/export data in various data formats + * + * @param {Object} [options] Available options: + * {String} fieldId Field name of the id in the + * items, 'id' by default. + * {Object.} [convert] + * {String[]} [fields] field names to be returned + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * {Array | DataTable} [data] If provided, items will be appended to this + * array or table. Required in case of Google + * DataTable. + * + * @throws Error + */ +DataSet.prototype.get = function (args) { + var me = this; + + // parse the arguments + var id, ids, options, data; + var firstType = util.getType(arguments[0]); + if (firstType == 'String' || firstType == 'Number') { + // get(id [, options] [, data]) + id = arguments[0]; + options = arguments[1]; + data = arguments[2]; + } + else if (firstType == 'Array') { + // get(ids [, options] [, data]) + ids = arguments[0]; + options = arguments[1]; + data = arguments[2]; + } + else { + // get([, options] [, data]) + options = arguments[0]; + data = arguments[1]; + } + + // determine the return type + var type; + if (options && options.type) { + type = (options.type == 'DataTable') ? 'DataTable' : 'Array'; + + if (data && (type != util.getType(data))) { + throw new Error('Type of parameter "data" (' + util.getType(data) + ') ' + + 'does not correspond with specified options.type (' + options.type + ')'); + } + if (type == 'DataTable' && !util.isDataTable(data)) { + throw new Error('Parameter "data" must be a DataTable ' + + 'when options.type is "DataTable"'); + } + } + else if (data) { + type = (util.getType(data) == 'DataTable') ? 'DataTable' : 'Array'; + } + else { + type = 'Array'; + } + + // build options + var convert = options && options.convert || this.options.convert; + var filter = options && options.filter; + var items = [], item, itemId, i, len; + + // convert items + if (id != undefined) { + // return a single item + item = me._getItem(id, convert); + if (filter && !filter(item)) { + item = null; + } + } + else if (ids != undefined) { + // return a subset of items + for (i = 0, len = ids.length; i < len; i++) { + item = me._getItem(ids[i], convert); + if (!filter || filter(item)) { + items.push(item); + } + } + } + else { + // return all items + for (itemId in this.data) { + if (this.data.hasOwnProperty(itemId)) { + item = me._getItem(itemId, convert); + if (!filter || filter(item)) { + items.push(item); + } + } + } + } + + // order the results + if (options && options.order && id == undefined) { + this._sort(items, options.order); + } + + // filter fields of the items + if (options && options.fields) { + var fields = options.fields; + if (id != undefined) { + item = this._filterFields(item, fields); + } + else { + for (i = 0, len = items.length; i < len; i++) { + items[i] = this._filterFields(items[i], fields); + } + } + } + + // return the results + if (type == 'DataTable') { + var columns = this._getColumnNames(data); + if (id != undefined) { + // append a single item to the data table + me._appendRow(data, columns, item); + } + else { + // copy the items to the provided data table + for (i = 0, len = items.length; i < len; i++) { + me._appendRow(data, columns, items[i]); + } + } + return data; + } + else { + // return an array + if (id != undefined) { + // a single item + return item; + } + else { + // multiple items + if (data) { + // copy the items to the provided array + for (i = 0, len = items.length; i < len; i++) { + data.push(items[i]); + } + return data; + } + else { + // just return our array + return items; + } + } + } +}; + +/** + * Get ids of all items or from a filtered set of items. + * @param {Object} [options] An Object with options. Available options: + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * @return {Array} ids + */ +DataSet.prototype.getIds = function (options) { + var data = this.data, + filter = options && options.filter, + order = options && options.order, + convert = options && options.convert || this.options.convert, + i, + len, + id, + item, + items, + ids = []; + + if (filter) { + // get filtered items + if (order) { + // create ordered list + items = []; + for (id in data) { + if (data.hasOwnProperty(id)) { + item = this._getItem(id, convert); + if (filter(item)) { + items.push(item); + } + } + } + + this._sort(items, order); + + for (i = 0, len = items.length; i < len; i++) { + ids[i] = items[i][this.fieldId]; + } + } + else { + // create unordered list + for (id in data) { + if (data.hasOwnProperty(id)) { + item = this._getItem(id, convert); + if (filter(item)) { + ids.push(item[this.fieldId]); + } + } + } + } + } + else { + // get all items + if (order) { + // create an ordered list + items = []; + for (id in data) { + if (data.hasOwnProperty(id)) { + items.push(data[id]); + } + } + + this._sort(items, order); + + for (i = 0, len = items.length; i < len; i++) { + ids[i] = items[i][this.fieldId]; + } + } + else { + // create unordered list + for (id in data) { + if (data.hasOwnProperty(id)) { + item = data[id]; + ids.push(item[this.fieldId]); + } + } + } + } + + return ids; +}; + +/** + * Execute a callback function for every item in the dataset. + * The order of the items is not determined. + * @param {function} callback + * @param {Object} [options] Available options: + * {Object.} [convert] + * {String[]} [fields] filter fields + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + */ +DataSet.prototype.forEach = function (callback, options) { + var filter = options && options.filter, + convert = options && options.convert || this.options.convert, + data = this.data, + item, + id; + + if (options && options.order) { + // execute forEach on ordered list + var items = this.get(options); + + for (var i = 0, len = items.length; i < len; i++) { + item = items[i]; + id = item[this.fieldId]; + callback(item, id); + } + } + else { + // unordered + for (id in data) { + if (data.hasOwnProperty(id)) { + item = this._getItem(id, convert); + if (!filter || filter(item)) { + callback(item, id); + } + } + } + } +}; + +/** + * Map every item in the dataset. + * @param {function} callback + * @param {Object} [options] Available options: + * {Object.} [convert] + * {String[]} [fields] filter fields + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * @return {Object[]} mappedItems + */ +DataSet.prototype.map = function (callback, options) { + var filter = options && options.filter, + convert = options && options.convert || this.options.convert, + mappedItems = [], + data = this.data, + item; + + // convert and filter items + for (var id in data) { + if (data.hasOwnProperty(id)) { + item = this._getItem(id, convert); + if (!filter || filter(item)) { + mappedItems.push(callback(item, id)); + } + } + } + + // order items + if (options && options.order) { + this._sort(mappedItems, options.order); + } + + return mappedItems; +}; + +/** + * Filter the fields of an item + * @param {Object} item + * @param {String[]} fields Field names + * @return {Object} filteredItem + * @private + */ +DataSet.prototype._filterFields = function (item, fields) { + var filteredItem = {}; + + for (var field in item) { + if (item.hasOwnProperty(field) && (fields.indexOf(field) != -1)) { + filteredItem[field] = item[field]; + } + } + + return filteredItem; +}; + +/** + * Sort the provided array with items + * @param {Object[]} items + * @param {String | function} order A field name or custom sort function. + * @private + */ +DataSet.prototype._sort = function (items, order) { + if (util.isString(order)) { + // order by provided field name + var name = order; // field name + items.sort(function (a, b) { + var av = a[name]; + var bv = b[name]; + return (av > bv) ? 1 : ((av < bv) ? -1 : 0); + }); + } + else if (typeof order === 'function') { + // order by sort function + items.sort(order); + } + // TODO: extend order by an Object {field:String, direction:String} + // where direction can be 'asc' or 'desc' + else { + throw new TypeError('Order must be a function or a string'); + } +}; + +/** + * Remove an object by pointer or by id + * @param {String | Number | Object | Array} id Object or id, or an array with + * objects or ids to be removed + * @param {String} [senderId] Optional sender id + * @return {Array} removedIds + */ +DataSet.prototype.remove = function (id, senderId) { + var removedIds = [], + i, len, removedId; + + if (id instanceof Array) { + for (i = 0, len = id.length; i < len; i++) { + removedId = this._remove(id[i]); + if (removedId != null) { + removedIds.push(removedId); + } + } + } + else { + removedId = this._remove(id); + if (removedId != null) { + removedIds.push(removedId); + } + } + + if (removedIds.length) { + this._trigger('remove', {items: removedIds}, senderId); + } + + return removedIds; +}; + +/** + * Remove an item by its id + * @param {Number | String | Object} id id or item + * @returns {Number | String | null} id + * @private + */ +DataSet.prototype._remove = function (id) { + if (util.isNumber(id) || util.isString(id)) { + if (this.data[id]) { + delete this.data[id]; + delete this.internalIds[id]; + return id; + } + } + else if (id instanceof Object) { + var itemId = id[this.fieldId]; + if (itemId && this.data[itemId]) { + delete this.data[itemId]; + delete this.internalIds[itemId]; + return itemId; + } + } + return null; +}; + +/** + * Clear the data + * @param {String} [senderId] Optional sender id + * @return {Array} removedIds The ids of all removed items + */ +DataSet.prototype.clear = function (senderId) { + var ids = Object.keys(this.data); + + this.data = {}; + this.internalIds = {}; + + this._trigger('remove', {items: ids}, senderId); + + return ids; +}; + +/** + * Find the item with maximum value of a specified field + * @param {String} field + * @return {Object | null} item Item containing max value, or null if no items + */ +DataSet.prototype.max = function (field) { + var data = this.data, + max = null, + maxField = null; + + for (var id in data) { + if (data.hasOwnProperty(id)) { + var item = data[id]; + var itemField = item[field]; + if (itemField != null && (!max || itemField > maxField)) { + max = item; + maxField = itemField; + } + } + } + + return max; +}; + +/** + * Find the item with minimum value of a specified field + * @param {String} field + * @return {Object | null} item Item containing max value, or null if no items + */ +DataSet.prototype.min = function (field) { + var data = this.data, + min = null, + minField = null; + + for (var id in data) { + if (data.hasOwnProperty(id)) { + var item = data[id]; + var itemField = item[field]; + if (itemField != null && (!min || itemField < minField)) { + min = item; + minField = itemField; + } + } + } + + return min; +}; + +/** + * Find all distinct values of a specified field + * @param {String} field + * @return {Array} values Array containing all distinct values. If the data + * items do not contain the specified field, an array + * containing a single value undefined is returned. + * The returned array is unordered. + */ +DataSet.prototype.distinct = function (field) { + var data = this.data, + values = [], + fieldType = this.options.convert[field], + count = 0; + + for (var prop in data) { + if (data.hasOwnProperty(prop)) { + var item = data[prop]; + var value = util.convert(item[field], fieldType); + var exists = false; + for (var i = 0; i < count; i++) { + if (values[i] == value) { + exists = true; + break; + } + } + if (!exists) { + values[count] = value; + count++; + } + } + } + + return values; +}; + +/** + * Add a single item. Will fail when an item with the same id already exists. + * @param {Object} item + * @return {String} id + * @private + */ +DataSet.prototype._addItem = function (item) { + var id = item[this.fieldId]; + + if (id != undefined) { + // check whether this id is already taken + if (this.data[id]) { + // item already exists + throw new Error('Cannot add item: item with id ' + id + ' already exists'); + } + } + else { + // generate an id + id = util.randomUUID(); + item[this.fieldId] = id; + this.internalIds[id] = item; + } + + var d = {}; + for (var field in item) { + if (item.hasOwnProperty(field)) { + var fieldType = this.convert[field]; // type may be undefined + d[field] = util.convert(item[field], fieldType); + } + } + this.data[id] = d; + + return id; +}; + +/** + * Get an item. Fields can be converted to a specific type + * @param {String} id + * @param {Object.} [convert] field types to convert + * @return {Object | null} item + * @private + */ +DataSet.prototype._getItem = function (id, convert) { + var field, value; + + // get the item from the dataset + var raw = this.data[id]; + if (!raw) { + return null; + } + + // convert the items field types + var converted = {}, + fieldId = this.fieldId, + internalIds = this.internalIds; + if (convert) { + for (field in raw) { + if (raw.hasOwnProperty(field)) { + value = raw[field]; + // output all fields, except internal ids + if ((field != fieldId) || !(value in internalIds)) { + converted[field] = util.convert(value, convert[field]); + } + } + } + } + else { + // no field types specified, no converting needed + for (field in raw) { + if (raw.hasOwnProperty(field)) { + value = raw[field]; + // output all fields, except internal ids + if ((field != fieldId) || !(value in internalIds)) { + converted[field] = value; + } + } + } + } + + return converted; +}; + +/** + * Update a single item: merge with existing item. + * Will fail when the item has no id, or when there does not exist an item + * with the same id. + * @param {Object} item + * @return {String} id + * @private + */ +DataSet.prototype._updateItem = function (item) { + var id = item[this.fieldId]; + if (id == undefined) { + throw new Error('Cannot update item: item has no id (item: ' + JSON.stringify(item) + ')'); + } + var d = this.data[id]; + if (!d) { + // item doesn't exist + throw new Error('Cannot update item: no item with id ' + id + ' found'); + } + + // merge with current item + for (var field in item) { + if (item.hasOwnProperty(field)) { + var fieldType = this.convert[field]; // type may be undefined + d[field] = util.convert(item[field], fieldType); + } + } + + return id; +}; + +/** + * Get an array with the column names of a Google DataTable + * @param {DataTable} dataTable + * @return {String[]} columnNames + * @private + */ +DataSet.prototype._getColumnNames = function (dataTable) { + var columns = []; + for (var col = 0, cols = dataTable.getNumberOfColumns(); col < cols; col++) { + columns[col] = dataTable.getColumnId(col) || dataTable.getColumnLabel(col); + } + return columns; +}; + +/** + * Append an item as a row to the dataTable + * @param dataTable + * @param columns + * @param item + * @private + */ +DataSet.prototype._appendRow = function (dataTable, columns, item) { + var row = dataTable.addRow(); + + for (var col = 0, cols = columns.length; col < cols; col++) { + var field = columns[col]; + dataTable.setValue(row, col, item[field]); + } +}; + +/** + * DataView + * + * a dataview offers a filtered view on a dataset or an other dataview. + * + * @param {DataSet | DataView} data + * @param {Object} [options] Available options: see method get + * + * @constructor DataView + */ +function DataView (data, options) { + this.id = util.randomUUID(); + + this.data = null; + this.ids = {}; // ids of the items currently in memory (just contains a boolean true) + this.options = options || {}; + this.fieldId = 'id'; // name of the field containing id + this.subscribers = {}; // event subscribers + + var me = this; + this.listener = function () { + me._onEvent.apply(me, arguments); + }; + + this.setData(data); +} + +// TODO: implement a function .config() to dynamically update things like configured filter +// and trigger changes accordingly + +/** + * Set a data source for the view + * @param {DataSet | DataView} data + */ +DataView.prototype.setData = function (data) { + var ids, dataItems, i, len; + + if (this.data) { + // unsubscribe from current dataset + if (this.data.unsubscribe) { + this.data.unsubscribe('*', this.listener); + } + + // trigger a remove of all items in memory + ids = []; + for (var id in this.ids) { + if (this.ids.hasOwnProperty(id)) { + ids.push(id); + } + } + this.ids = {}; + this._trigger('remove', {items: ids}); + } + + this.data = data; + + if (this.data) { + // update fieldId + this.fieldId = this.options.fieldId || + (this.data && this.data.options && this.data.options.fieldId) || + 'id'; + + // trigger an add of all added items + ids = this.data.getIds({filter: this.options && this.options.filter}); + for (i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + this.ids[id] = true; + } + this._trigger('add', {items: ids}); + + // subscribe to new dataset + if (this.data.subscribe) { + this.data.subscribe('*', this.listener); + } + } +}; + +/** + * Get data from the data view + * + * Usage: + * + * get() + * get(options: Object) + * get(options: Object, data: Array | DataTable) + * + * get(id: Number) + * get(id: Number, options: Object) + * get(id: Number, options: Object, data: Array | DataTable) + * + * get(ids: Number[]) + * get(ids: Number[], options: Object) + * get(ids: Number[], options: Object, data: Array | DataTable) + * + * Where: + * + * {Number | String} id The id of an item + * {Number[] | String{}} ids An array with ids of items + * {Object} options An Object with options. Available options: + * {String} [type] Type of data to be returned. Can + * be 'DataTable' or 'Array' (default) + * {Object.} [convert] + * {String[]} [fields] field names to be returned + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * {Array | DataTable} [data] If provided, items will be appended to this + * array or table. Required in case of Google + * DataTable. + * @param args + */ +DataView.prototype.get = function (args) { + var me = this; + + // parse the arguments + var ids, options, data; + var firstType = util.getType(arguments[0]); + if (firstType == 'String' || firstType == 'Number' || firstType == 'Array') { + // get(id(s) [, options] [, data]) + ids = arguments[0]; // can be a single id or an array with ids + options = arguments[1]; + data = arguments[2]; + } + else { + // get([, options] [, data]) + options = arguments[0]; + data = arguments[1]; + } + + // extend the options with the default options and provided options + var viewOptions = util.extend({}, this.options, options); + + // create a combined filter method when needed + if (this.options.filter && options && options.filter) { + viewOptions.filter = function (item) { + return me.options.filter(item) && options.filter(item); + } + } + + // build up the call to the linked data set + var getArguments = []; + if (ids != undefined) { + getArguments.push(ids); + } + getArguments.push(viewOptions); + getArguments.push(data); + + return this.data && this.data.get.apply(this.data, getArguments); +}; + +/** + * Get ids of all items or from a filtered set of items. + * @param {Object} [options] An Object with options. Available options: + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * @return {Array} ids + */ +DataView.prototype.getIds = function (options) { + var ids; + + if (this.data) { + var defaultFilter = this.options.filter; + var filter; + + if (options && options.filter) { + if (defaultFilter) { + filter = function (item) { + return defaultFilter(item) && options.filter(item); + } + } + else { + filter = options.filter; + } + } + else { + filter = defaultFilter; + } + + ids = this.data.getIds({ + filter: filter, + order: options && options.order + }); + } + else { + ids = []; + } + + return ids; +}; + +/** + * Event listener. Will propagate all events from the connected data set to + * the subscribers of the DataView, but will filter the items and only trigger + * when there are changes in the filtered data set. + * @param {String} event + * @param {Object | null} params + * @param {String} senderId + * @private + */ +DataView.prototype._onEvent = function (event, params, senderId) { + var i, len, id, item, + ids = params && params.items, + data = this.data, + added = [], + updated = [], + removed = []; + + if (ids && data) { + switch (event) { + case 'add': + // filter the ids of the added items + for (i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + item = this.get(id); + if (item) { + this.ids[id] = true; + added.push(id); + } + } + + break; + + case 'update': + // determine the event from the views viewpoint: an updated + // item can be added, updated, or removed from this view. + for (i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + item = this.get(id); + + if (item) { + if (this.ids[id]) { + updated.push(id); + } + else { + this.ids[id] = true; + added.push(id); + } + } + else { + if (this.ids[id]) { + delete this.ids[id]; + removed.push(id); + } + else { + // nothing interesting for me :-( + } + } + } + + break; + + case 'remove': + // filter the ids of the removed items + for (i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + if (this.ids[id]) { + delete this.ids[id]; + removed.push(id); + } + } + + break; + } + + if (added.length) { + this._trigger('add', {items: added}, senderId); + } + if (updated.length) { + this._trigger('update', {items: updated}, senderId); + } + if (removed.length) { + this._trigger('remove', {items: removed}, senderId); + } + } +}; + +// copy subscription functionality from DataSet +DataView.prototype.subscribe = DataSet.prototype.subscribe; +DataView.prototype.unsubscribe = DataSet.prototype.unsubscribe; +DataView.prototype._trigger = DataSet.prototype._trigger; + +/** + * @constructor TimeStep + * The class TimeStep is an iterator for dates. You provide a start date and an + * end date. The class itself determines the best scale (step size) based on the + * provided start Date, end Date, and minimumStep. + * + * If minimumStep is provided, the step size is chosen as close as possible + * to the minimumStep but larger than minimumStep. If minimumStep is not + * provided, the scale is set to 1 DAY. + * The minimumStep should correspond with the onscreen size of about 6 characters + * + * Alternatively, you can set a scale by hand. + * After creation, you can initialize the class by executing first(). Then you + * can iterate from the start date to the end date via next(). You can check if + * the end date is reached with the function hasNext(). After each step, you can + * retrieve the current date via getCurrent(). + * The TimeStep has scales ranging from milliseconds, seconds, minutes, hours, + * days, to years. + * + * Version: 1.2 + * + * @param {Date} [start] The start date, for example new Date(2010, 9, 21) + * or new Date(2010, 9, 21, 23, 45, 00) + * @param {Date} [end] The end date + * @param {Number} [minimumStep] Optional. Minimum step size in milliseconds + */ +TimeStep = function(start, end, minimumStep) { + // variables + this.current = new Date(); + this._start = new Date(); + this._end = new Date(); + + this.autoScale = true; + this.scale = TimeStep.SCALE.DAY; + this.step = 1; + + // initialize the range + this.setRange(start, end, minimumStep); +}; + +/// enum scale +TimeStep.SCALE = { + MILLISECOND: 1, + SECOND: 2, + MINUTE: 3, + HOUR: 4, + DAY: 5, + WEEKDAY: 6, + MONTH: 7, + YEAR: 8 +}; + + +/** + * Set a new range + * If minimumStep is provided, the step size is chosen as close as possible + * to the minimumStep but larger than minimumStep. If minimumStep is not + * provided, the scale is set to 1 DAY. + * The minimumStep should correspond with the onscreen size of about 6 characters + * @param {Date} [start] The start date and time. + * @param {Date} [end] The end date and time. + * @param {int} [minimumStep] Optional. Minimum step size in milliseconds + */ +TimeStep.prototype.setRange = function(start, end, minimumStep) { + if (!(start instanceof Date) || !(end instanceof Date)) { + throw "No legal start or end date in method setRange"; + } + + this._start = (start != undefined) ? new Date(start.valueOf()) : new Date(); + this._end = (end != undefined) ? new Date(end.valueOf()) : new Date(); + + if (this.autoScale) { + this.setMinimumStep(minimumStep); + } +}; + +/** + * Set the range iterator to the start date. + */ +TimeStep.prototype.first = function() { + this.current = new Date(this._start.valueOf()); + this.roundToMinor(); +}; + +/** + * Round the current date to the first minor date value + * This must be executed once when the current date is set to start Date + */ +TimeStep.prototype.roundToMinor = function() { + // round to floor + // IMPORTANT: we have no breaks in this switch! (this is no bug) + //noinspection FallthroughInSwitchStatementJS + switch (this.scale) { + case TimeStep.SCALE.YEAR: + this.current.setFullYear(this.step * Math.floor(this.current.getFullYear() / this.step)); + this.current.setMonth(0); + case TimeStep.SCALE.MONTH: this.current.setDate(1); + case TimeStep.SCALE.DAY: // intentional fall through + case TimeStep.SCALE.WEEKDAY: this.current.setHours(0); + case TimeStep.SCALE.HOUR: this.current.setMinutes(0); + case TimeStep.SCALE.MINUTE: this.current.setSeconds(0); + case TimeStep.SCALE.SECOND: this.current.setMilliseconds(0); + //case TimeStep.SCALE.MILLISECOND: // nothing to do for milliseconds + } + + if (this.step != 1) { + // round down to the first minor value that is a multiple of the current step size + switch (this.scale) { + case TimeStep.SCALE.MILLISECOND: this.current.setMilliseconds(this.current.getMilliseconds() - this.current.getMilliseconds() % this.step); break; + case TimeStep.SCALE.SECOND: this.current.setSeconds(this.current.getSeconds() - this.current.getSeconds() % this.step); break; + case TimeStep.SCALE.MINUTE: this.current.setMinutes(this.current.getMinutes() - this.current.getMinutes() % this.step); break; + case TimeStep.SCALE.HOUR: this.current.setHours(this.current.getHours() - this.current.getHours() % this.step); break; + case TimeStep.SCALE.WEEKDAY: // intentional fall through + case TimeStep.SCALE.DAY: this.current.setDate((this.current.getDate()-1) - (this.current.getDate()-1) % this.step + 1); break; + case TimeStep.SCALE.MONTH: this.current.setMonth(this.current.getMonth() - this.current.getMonth() % this.step); break; + case TimeStep.SCALE.YEAR: this.current.setFullYear(this.current.getFullYear() - this.current.getFullYear() % this.step); break; + default: break; + } + } +}; + +/** + * Check if the there is a next step + * @return {boolean} true if the current date has not passed the end date + */ +TimeStep.prototype.hasNext = function () { + return (this.current.valueOf() <= this._end.valueOf()); +}; + +/** + * Do the next step + */ +TimeStep.prototype.next = function() { + var prev = this.current.valueOf(); + + // Two cases, needed to prevent issues with switching daylight savings + // (end of March and end of October) + if (this.current.getMonth() < 6) { + switch (this.scale) { + case TimeStep.SCALE.MILLISECOND: + + this.current = new Date(this.current.valueOf() + this.step); break; + case TimeStep.SCALE.SECOND: this.current = new Date(this.current.valueOf() + this.step * 1000); break; + case TimeStep.SCALE.MINUTE: this.current = new Date(this.current.valueOf() + this.step * 1000 * 60); break; + case TimeStep.SCALE.HOUR: + this.current = new Date(this.current.valueOf() + this.step * 1000 * 60 * 60); + // in case of skipping an hour for daylight savings, adjust the hour again (else you get: 0h 5h 9h ... instead of 0h 4h 8h ...) + var h = this.current.getHours(); + this.current.setHours(h - (h % this.step)); + break; + case TimeStep.SCALE.WEEKDAY: // intentional fall through + case TimeStep.SCALE.DAY: this.current.setDate(this.current.getDate() + this.step); break; + case TimeStep.SCALE.MONTH: this.current.setMonth(this.current.getMonth() + this.step); break; + case TimeStep.SCALE.YEAR: this.current.setFullYear(this.current.getFullYear() + this.step); break; + default: break; + } + } + else { + switch (this.scale) { + case TimeStep.SCALE.MILLISECOND: this.current = new Date(this.current.valueOf() + this.step); break; + case TimeStep.SCALE.SECOND: this.current.setSeconds(this.current.getSeconds() + this.step); break; + case TimeStep.SCALE.MINUTE: this.current.setMinutes(this.current.getMinutes() + this.step); break; + case TimeStep.SCALE.HOUR: this.current.setHours(this.current.getHours() + this.step); break; + case TimeStep.SCALE.WEEKDAY: // intentional fall through + case TimeStep.SCALE.DAY: this.current.setDate(this.current.getDate() + this.step); break; + case TimeStep.SCALE.MONTH: this.current.setMonth(this.current.getMonth() + this.step); break; + case TimeStep.SCALE.YEAR: this.current.setFullYear(this.current.getFullYear() + this.step); break; + default: break; + } + } + + if (this.step != 1) { + // round down to the correct major value + switch (this.scale) { + case TimeStep.SCALE.MILLISECOND: if(this.current.getMilliseconds() < this.step) this.current.setMilliseconds(0); break; + case TimeStep.SCALE.SECOND: if(this.current.getSeconds() < this.step) this.current.setSeconds(0); break; + case TimeStep.SCALE.MINUTE: if(this.current.getMinutes() < this.step) this.current.setMinutes(0); break; + case TimeStep.SCALE.HOUR: if(this.current.getHours() < this.step) this.current.setHours(0); break; + case TimeStep.SCALE.WEEKDAY: // intentional fall through + case TimeStep.SCALE.DAY: if(this.current.getDate() < this.step+1) this.current.setDate(1); break; + case TimeStep.SCALE.MONTH: if(this.current.getMonth() < this.step) this.current.setMonth(0); break; + case TimeStep.SCALE.YEAR: break; // nothing to do for year + default: break; + } + } + + // safety mechanism: if current time is still unchanged, move to the end + if (this.current.valueOf() == prev) { + this.current = new Date(this._end.valueOf()); + } +}; + + +/** + * Get the current datetime + * @return {Date} current The current date + */ +TimeStep.prototype.getCurrent = function() { + return this.current; +}; + +/** + * Set a custom scale. Autoscaling will be disabled. + * For example setScale(SCALE.MINUTES, 5) will result + * in minor steps of 5 minutes, and major steps of an hour. + * + * @param {TimeStep.SCALE} newScale + * A scale. Choose from SCALE.MILLISECOND, + * SCALE.SECOND, SCALE.MINUTE, SCALE.HOUR, + * SCALE.WEEKDAY, SCALE.DAY, SCALE.MONTH, + * SCALE.YEAR. + * @param {Number} newStep A step size, by default 1. Choose for + * example 1, 2, 5, or 10. + */ +TimeStep.prototype.setScale = function(newScale, newStep) { + this.scale = newScale; + + if (newStep > 0) { + this.step = newStep; + } + + this.autoScale = false; +}; + +/** + * Enable or disable autoscaling + * @param {boolean} enable If true, autoascaling is set true + */ +TimeStep.prototype.setAutoScale = function (enable) { + this.autoScale = enable; +}; + + +/** + * Automatically determine the scale that bests fits the provided minimum step + * @param {Number} [minimumStep] The minimum step size in milliseconds + */ +TimeStep.prototype.setMinimumStep = function(minimumStep) { + if (minimumStep == undefined) { + return; + } + + var stepYear = (1000 * 60 * 60 * 24 * 30 * 12); + var stepMonth = (1000 * 60 * 60 * 24 * 30); + var stepDay = (1000 * 60 * 60 * 24); + var stepHour = (1000 * 60 * 60); + var stepMinute = (1000 * 60); + var stepSecond = (1000); + var stepMillisecond= (1); + + // find the smallest step that is larger than the provided minimumStep + if (stepYear*1000 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 1000;} + if (stepYear*500 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 500;} + if (stepYear*100 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 100;} + if (stepYear*50 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 50;} + if (stepYear*10 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 10;} + if (stepYear*5 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 5;} + if (stepYear > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 1;} + if (stepMonth*3 > minimumStep) {this.scale = TimeStep.SCALE.MONTH; this.step = 3;} + if (stepMonth > minimumStep) {this.scale = TimeStep.SCALE.MONTH; this.step = 1;} + if (stepDay*5 > minimumStep) {this.scale = TimeStep.SCALE.DAY; this.step = 5;} + if (stepDay*2 > minimumStep) {this.scale = TimeStep.SCALE.DAY; this.step = 2;} + if (stepDay > minimumStep) {this.scale = TimeStep.SCALE.DAY; this.step = 1;} + if (stepDay/2 > minimumStep) {this.scale = TimeStep.SCALE.WEEKDAY; this.step = 1;} + if (stepHour*4 > minimumStep) {this.scale = TimeStep.SCALE.HOUR; this.step = 4;} + if (stepHour > minimumStep) {this.scale = TimeStep.SCALE.HOUR; this.step = 1;} + if (stepMinute*15 > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 15;} + if (stepMinute*10 > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 10;} + if (stepMinute*5 > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 5;} + if (stepMinute > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 1;} + if (stepSecond*15 > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 15;} + if (stepSecond*10 > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 10;} + if (stepSecond*5 > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 5;} + if (stepSecond > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 1;} + if (stepMillisecond*200 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 200;} + if (stepMillisecond*100 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 100;} + if (stepMillisecond*50 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 50;} + if (stepMillisecond*10 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 10;} + if (stepMillisecond*5 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 5;} + if (stepMillisecond > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 1;} +}; + +/** + * Snap a date to a rounded value. The snap intervals are dependent on the + * current scale and step. + * @param {Date} date the date to be snapped + */ +TimeStep.prototype.snap = function(date) { + if (this.scale == TimeStep.SCALE.YEAR) { + var year = date.getFullYear() + Math.round(date.getMonth() / 12); + date.setFullYear(Math.round(year / this.step) * this.step); + date.setMonth(0); + date.setDate(0); + date.setHours(0); + date.setMinutes(0); + date.setSeconds(0); + date.setMilliseconds(0); + } + else if (this.scale == TimeStep.SCALE.MONTH) { + if (date.getDate() > 15) { + date.setDate(1); + date.setMonth(date.getMonth() + 1); + // important: first set Date to 1, after that change the month. + } + else { + date.setDate(1); + } + + date.setHours(0); + date.setMinutes(0); + date.setSeconds(0); + date.setMilliseconds(0); + } + else if (this.scale == TimeStep.SCALE.DAY || + this.scale == TimeStep.SCALE.WEEKDAY) { + //noinspection FallthroughInSwitchStatementJS + switch (this.step) { + case 5: + case 2: + date.setHours(Math.round(date.getHours() / 24) * 24); break; + default: + date.setHours(Math.round(date.getHours() / 12) * 12); break; + } + date.setMinutes(0); + date.setSeconds(0); + date.setMilliseconds(0); + } + else if (this.scale == TimeStep.SCALE.HOUR) { + switch (this.step) { + case 4: + date.setMinutes(Math.round(date.getMinutes() / 60) * 60); break; + default: + date.setMinutes(Math.round(date.getMinutes() / 30) * 30); break; + } + date.setSeconds(0); + date.setMilliseconds(0); + } else if (this.scale == TimeStep.SCALE.MINUTE) { + //noinspection FallthroughInSwitchStatementJS + switch (this.step) { + case 15: + case 10: + date.setMinutes(Math.round(date.getMinutes() / 5) * 5); + date.setSeconds(0); + break; + case 5: + date.setSeconds(Math.round(date.getSeconds() / 60) * 60); break; + default: + date.setSeconds(Math.round(date.getSeconds() / 30) * 30); break; + } + date.setMilliseconds(0); + } + else if (this.scale == TimeStep.SCALE.SECOND) { + //noinspection FallthroughInSwitchStatementJS + switch (this.step) { + case 15: + case 10: + date.setSeconds(Math.round(date.getSeconds() / 5) * 5); + date.setMilliseconds(0); + break; + case 5: + date.setMilliseconds(Math.round(date.getMilliseconds() / 1000) * 1000); break; + default: + date.setMilliseconds(Math.round(date.getMilliseconds() / 500) * 500); break; + } + } + else if (this.scale == TimeStep.SCALE.MILLISECOND) { + var step = this.step > 5 ? this.step / 2 : 1; + date.setMilliseconds(Math.round(date.getMilliseconds() / step) * step); + } +}; + +/** + * Check if the current value is a major value (for example when the step + * is DAY, a major value is each first day of the MONTH) + * @return {boolean} true if current date is major, else false. + */ +TimeStep.prototype.isMajor = function() { + switch (this.scale) { + case TimeStep.SCALE.MILLISECOND: + return (this.current.getMilliseconds() == 0); + case TimeStep.SCALE.SECOND: + return (this.current.getSeconds() == 0); + case TimeStep.SCALE.MINUTE: + return (this.current.getHours() == 0) && (this.current.getMinutes() == 0); + // Note: this is no bug. Major label is equal for both minute and hour scale + case TimeStep.SCALE.HOUR: + return (this.current.getHours() == 0); + case TimeStep.SCALE.WEEKDAY: // intentional fall through + case TimeStep.SCALE.DAY: + return (this.current.getDate() == 1); + case TimeStep.SCALE.MONTH: + return (this.current.getMonth() == 0); + case TimeStep.SCALE.YEAR: + return false; + default: + return false; + } +}; + + +/** + * Returns formatted text for the minor axislabel, depending on the current + * date and the scale. For example when scale is MINUTE, the current time is + * formatted as "hh:mm". + * @param {Date} [date] custom date. if not provided, current date is taken + */ +TimeStep.prototype.getLabelMinor = function(date) { + if (date == undefined) { + date = this.current; + } + + switch (this.scale) { + case TimeStep.SCALE.MILLISECOND: return moment(date).format('SSS'); + case TimeStep.SCALE.SECOND: return moment(date).format('s'); + case TimeStep.SCALE.MINUTE: return moment(date).format('HH:mm'); + case TimeStep.SCALE.HOUR: return moment(date).format('HH:mm'); + case TimeStep.SCALE.WEEKDAY: return moment(date).format('ddd D'); + case TimeStep.SCALE.DAY: return moment(date).format('D'); + case TimeStep.SCALE.MONTH: return moment(date).format('MMM'); + case TimeStep.SCALE.YEAR: return moment(date).format('YYYY'); + default: return ''; + } +}; + + +/** + * Returns formatted text for the major axis label, depending on the current + * date and the scale. For example when scale is MINUTE, the major scale is + * hours, and the hour will be formatted as "hh". + * @param {Date} [date] custom date. if not provided, current date is taken + */ +TimeStep.prototype.getLabelMajor = function(date) { + if (date == undefined) { + date = this.current; + } + + //noinspection FallthroughInSwitchStatementJS + switch (this.scale) { + case TimeStep.SCALE.MILLISECOND:return moment(date).format('HH:mm:ss'); + case TimeStep.SCALE.SECOND: return moment(date).format('D MMMM HH:mm'); + case TimeStep.SCALE.MINUTE: + case TimeStep.SCALE.HOUR: return moment(date).format('ddd D MMMM'); + case TimeStep.SCALE.WEEKDAY: + case TimeStep.SCALE.DAY: return moment(date).format('MMMM YYYY'); + case TimeStep.SCALE.MONTH: return moment(date).format('YYYY'); + case TimeStep.SCALE.YEAR: return ''; + default: return ''; + } +}; + +/** + * @constructor Stack + * Stacks items on top of each other. + * @param {ItemSet} parent + * @param {Object} [options] + */ +function Stack (parent, options) { + this.parent = parent; + + this.options = options || {}; + this.defaultOptions = { + order: function (a, b) { + //return (b.width - a.width) || (a.left - b.left); // TODO: cleanup + // Order: ranges over non-ranges, ranged ordered by width, and + // lastly ordered by start. + if (a instanceof ItemRange) { + if (b instanceof ItemRange) { + var aInt = (a.data.end - a.data.start); + var bInt = (b.data.end - b.data.start); + return (aInt - bInt) || (a.data.start - b.data.start); + } + else { + return -1; + } + } + else { + if (b instanceof ItemRange) { + return 1; + } + else { + return (a.data.start - b.data.start); + } + } + }, + margin: { + item: 10 + } + }; + + this.ordered = []; // ordered items +} + +/** + * Set options for the stack + * @param {Object} options Available options: + * {ItemSet} parent + * {Number} margin + * {function} order Stacking order + */ +Stack.prototype.setOptions = function setOptions (options) { + util.extend(this.options, options); + + // TODO: register on data changes at the connected parent itemset, and update the changed part only and immediately +}; + +/** + * Stack the items such that they don't overlap. The items will have a minimal + * distance equal to options.margin.item. + */ +Stack.prototype.update = function update() { + this._order(); + this._stack(); +}; + +/** + * Order the items. The items are ordered by width first, and by left position + * second. + * If a custom order function has been provided via the options, then this will + * be used. + * @private + */ +Stack.prototype._order = function _order () { + var items = this.parent.items; + if (!items) { + throw new Error('Cannot stack items: parent does not contain items'); + } + + // TODO: store the sorted items, to have less work later on + var ordered = []; + var index = 0; + // items is a map (no array) + util.forEach(items, function (item) { + if (item.visible) { + ordered[index] = item; + index++; + } + }); + + //if a customer stack order function exists, use it. + var order = this.options.order || this.defaultOptions.order; + if (!(typeof order === 'function')) { + throw new Error('Option order must be a function'); + } + + ordered.sort(order); + + this.ordered = ordered; +}; + +/** + * Adjust vertical positions of the events such that they don't overlap each + * other. + * @private + */ +Stack.prototype._stack = function _stack () { + var i, + iMax, + ordered = this.ordered, + options = this.options, + orientation = options.orientation || this.defaultOptions.orientation, + axisOnTop = (orientation == 'top'), + margin; + + if (options.margin && options.margin.item !== undefined) { + margin = options.margin.item; + } + else { + margin = this.defaultOptions.margin.item + } + + // calculate new, non-overlapping positions + for (i = 0, iMax = ordered.length; i < iMax; i++) { + var item = ordered[i]; + var collidingItem = null; + do { + // TODO: optimize checking for overlap. when there is a gap without items, + // you only need to check for items from the next item on, not from zero + collidingItem = this.checkOverlap(ordered, i, 0, i - 1, margin); + if (collidingItem != null) { + // There is a collision. Reposition the event above the colliding element + if (axisOnTop) { + item.top = collidingItem.top + collidingItem.height + margin; + } + else { + item.top = collidingItem.top - item.height - margin; + } + } + } while (collidingItem); + } +}; + +/** + * Check if the destiny position of given item overlaps with any + * of the other items from index itemStart to itemEnd. + * @param {Array} items Array with items + * @param {int} itemIndex Number of the item to be checked for overlap + * @param {int} itemStart First item to be checked. + * @param {int} itemEnd Last item to be checked. + * @return {Object | null} colliding item, or undefined when no collisions + * @param {Number} margin A minimum required margin. + * If margin is provided, the two items will be + * marked colliding when they overlap or + * when the margin between the two is smaller than + * the requested margin. + */ +Stack.prototype.checkOverlap = function checkOverlap (items, itemIndex, + itemStart, itemEnd, margin) { + var collision = this.collision; + + // we loop from end to start, as we suppose that the chance of a + // collision is larger for items at the end, so check these first. + var a = items[itemIndex]; + for (var i = itemEnd; i >= itemStart; i--) { + var b = items[i]; + if (collision(a, b, margin)) { + if (i != itemIndex) { + return b; + } + } + } + + return null; +}; + +/** + * Test if the two provided items collide + * The items must have parameters left, width, top, and height. + * @param {Component} a The first item + * @param {Component} b The second item + * @param {Number} margin A minimum required margin. + * If margin is provided, the two items will be + * marked colliding when they overlap or + * when the margin between the two is smaller than + * the requested margin. + * @return {boolean} true if a and b collide, else false + */ +Stack.prototype.collision = function collision (a, b, margin) { + return ((a.left - margin) < (b.left + b.getWidth()) && + (a.left + a.getWidth() + margin) > b.left && + (a.top - margin) < (b.top + b.height) && + (a.top + a.height + margin) > b.top); +}; + +/** + * @constructor Range + * A Range controls a numeric range with a start and end value. + * The Range adjusts the range based on mouse events or programmatic changes, + * and triggers events when the range is changing or has been changed. + * @param {Object} [options] See description at Range.setOptions + * @extends Controller + */ +function Range(options) { + this.id = util.randomUUID(); + this.start = null; // Number + this.end = null; // Number + + this.options = options || {}; + + this.setOptions(options); +} + +/** + * Set options for the range controller + * @param {Object} options Available options: + * {Number} min Minimum value for start + * {Number} max Maximum value for end + * {Number} zoomMin Set a minimum value for + * (end - start). + * {Number} zoomMax Set a maximum value for + * (end - start). + */ +Range.prototype.setOptions = function (options) { + util.extend(this.options, options); + + // re-apply range with new limitations + if (this.start !== null && this.end !== null) { + this.setRange(this.start, this.end); + } +}; + +/** + * Test whether direction has a valid value + * @param {String} direction 'horizontal' or 'vertical' + */ +function validateDirection (direction) { + if (direction != 'horizontal' && direction != 'vertical') { + throw new TypeError('Unknown direction "' + direction + '". ' + + 'Choose "horizontal" or "vertical".'); + } +} + +/** + * Add listeners for mouse and touch events to the component + * @param {Component} component + * @param {String} event Available events: 'move', 'zoom' + * @param {String} direction Available directions: 'horizontal', 'vertical' + */ +Range.prototype.subscribe = function (component, event, direction) { + var me = this; + + if (event == 'move') { + // drag start listener + component.on('dragstart', function (event) { + me._onDragStart(event, component); + }); + + // drag listener + component.on('drag', function (event) { + me._onDrag(event, component, direction); + }); + + // drag end listener + component.on('dragend', function (event) { + me._onDragEnd(event, component); + }); + } + else if (event == 'zoom') { + // mouse wheel + function mousewheel (event) { + me._onMouseWheel(event, component, direction); + } + component.on('mousewheel', mousewheel); + component.on('DOMMouseScroll', mousewheel); // For FF + + // pinch + component.on('touch', function (event) { + me._onTouch(); + }); + component.on('pinch', function (event) { + me._onPinch(event, component, direction); + }); + } + else { + throw new TypeError('Unknown event "' + event + '". ' + + 'Choose "move" or "zoom".'); + } +}; + +/** + * Event handler + * @param {String} event name of the event, for example 'click', 'mousemove' + * @param {function} callback callback handler, invoked with the raw HTML Event + * as parameter. + */ +Range.prototype.on = function (event, callback) { + events.addListener(this, event, callback); +}; + +/** + * Trigger an event + * @param {String} event name of the event, available events: 'rangechange', + * 'rangechanged' + * @private + */ +Range.prototype._trigger = function (event) { + events.trigger(this, event, { + start: this.start, + end: this.end + }); +}; + +/** + * Set a new start and end range + * @param {Number} [start] + * @param {Number} [end] + */ +Range.prototype.setRange = function(start, end) { + var changed = this._applyRange(start, end); + if (changed) { + this._trigger('rangechange'); + this._trigger('rangechanged'); + } +}; + +/** + * Set a new start and end range. This method is the same as setRange, but + * does not trigger a range change and range changed event, and it returns + * true when the range is changed + * @param {Number} [start] + * @param {Number} [end] + * @return {Boolean} changed + * @private + */ +Range.prototype._applyRange = function(start, end) { + var newStart = (start != null) ? util.convert(start, 'Number') : this.start, + newEnd = (end != null) ? util.convert(end, 'Number') : this.end, + max = (this.options.max != null) ? util.convert(this.options.max, 'Date').valueOf() : null, + min = (this.options.min != null) ? util.convert(this.options.min, 'Date').valueOf() : null, + diff; + + // check for valid number + if (isNaN(newStart) || newStart === null) { + throw new Error('Invalid start "' + start + '"'); + } + if (isNaN(newEnd) || newEnd === null) { + throw new Error('Invalid end "' + end + '"'); + } + + // prevent start < end + if (newEnd < newStart) { + newEnd = newStart; + } + + // prevent start < min + if (min !== null) { + if (newStart < min) { + diff = (min - newStart); + newStart += diff; + newEnd += diff; + + // prevent end > max + if (max != null) { + if (newEnd > max) { + newEnd = max; + } + } + } + } + + // prevent end > max + if (max !== null) { + if (newEnd > max) { + diff = (newEnd - max); + newStart -= diff; + newEnd -= diff; + + // prevent start < min + if (min != null) { + if (newStart < min) { + newStart = min; + } + } + } + } + + // prevent (end-start) < zoomMin + if (this.options.zoomMin !== null) { + var zoomMin = parseFloat(this.options.zoomMin); + if (zoomMin < 0) { + zoomMin = 0; + } + if ((newEnd - newStart) < zoomMin) { + if ((this.end - this.start) === zoomMin) { + // ignore this action, we are already zoomed to the minimum + newStart = this.start; + newEnd = this.end; + } + else { + // zoom to the minimum + diff = (zoomMin - (newEnd - newStart)); + newStart -= diff / 2; + newEnd += diff / 2; + } + } + } + + // prevent (end-start) > zoomMax + if (this.options.zoomMax !== null) { + var zoomMax = parseFloat(this.options.zoomMax); + if (zoomMax < 0) { + zoomMax = 0; + } + if ((newEnd - newStart) > zoomMax) { + if ((this.end - this.start) === zoomMax) { + // ignore this action, we are already zoomed to the maximum + newStart = this.start; + newEnd = this.end; + } + else { + // zoom to the maximum + diff = ((newEnd - newStart) - zoomMax); + newStart += diff / 2; + newEnd -= diff / 2; + } + } + } + + var changed = (this.start != newStart || this.end != newEnd); + + this.start = newStart; + this.end = newEnd; + + return changed; +}; + +/** + * Retrieve the current range. + * @return {Object} An object with start and end properties + */ +Range.prototype.getRange = function() { + return { + start: this.start, + end: this.end + }; +}; + +/** + * Calculate the conversion offset and scale for current range, based on + * the provided width + * @param {Number} width + * @returns {{offset: number, scale: number}} conversion + */ +Range.prototype.conversion = function (width) { + return Range.conversion(this.start, this.end, width); +}; + +/** + * Static method to calculate the conversion offset and scale for a range, + * based on the provided start, end, and width + * @param {Number} start + * @param {Number} end + * @param {Number} width + * @returns {{offset: number, scale: number}} conversion + */ +Range.conversion = function (start, end, width) { + if (width != 0 && (end - start != 0)) { + return { + offset: start, + scale: width / (end - start) + } + } + else { + return { + offset: 0, + scale: 1 + }; + } +}; + +// global (private) object to store drag params +var touchParams = {}; + +/** + * Start dragging horizontally or vertically + * @param {Event} event + * @param {Object} component + * @private + */ +Range.prototype._onDragStart = function(event, component) { + // refuse to drag when we where pinching to prevent the timeline make a jump + // when releasing the fingers in opposite order from the touch screen + if (touchParams.pinching) return; + + touchParams.start = this.start; + touchParams.end = this.end; + + var frame = component.frame; + if (frame) { + frame.style.cursor = 'move'; + } +}; + +/** + * Perform dragging operating. + * @param {Event} event + * @param {Component} component + * @param {String} direction 'horizontal' or 'vertical' + * @private + */ +Range.prototype._onDrag = function (event, component, direction) { + validateDirection(direction); + + // refuse to drag when we where pinching to prevent the timeline make a jump + // when releasing the fingers in opposite order from the touch screen + if (touchParams.pinching) return; + + var delta = (direction == 'horizontal') ? event.gesture.deltaX : event.gesture.deltaY, + interval = (touchParams.end - touchParams.start), + width = (direction == 'horizontal') ? component.width : component.height, + diffRange = -delta / width * interval; + + this._applyRange(touchParams.start + diffRange, touchParams.end + diffRange); + + // fire a rangechange event + this._trigger('rangechange'); +}; + +/** + * Stop dragging operating. + * @param {event} event + * @param {Component} component + * @private + */ +Range.prototype._onDragEnd = function (event, component) { + // refuse to drag when we where pinching to prevent the timeline make a jump + // when releasing the fingers in opposite order from the touch screen + if (touchParams.pinching) return; + + if (component.frame) { + component.frame.style.cursor = 'auto'; + } + + // fire a rangechanged event + this._trigger('rangechanged'); +}; + +/** + * Event handler for mouse wheel event, used to zoom + * Code from http://adomas.org/javascript-mouse-wheel/ + * @param {Event} event + * @param {Component} component + * @param {String} direction 'horizontal' or 'vertical' + * @private + */ +Range.prototype._onMouseWheel = function(event, component, direction) { + validateDirection(direction); + + // retrieve delta + var delta = 0; + if (event.wheelDelta) { /* IE/Opera. */ + delta = event.wheelDelta / 120; + } else if (event.detail) { /* Mozilla case. */ + // In Mozilla, sign of delta is different than in IE. + // Also, delta is multiple of 3. + delta = -event.detail / 3; + } + + // If delta is nonzero, handle it. + // Basically, delta is now positive if wheel was scrolled up, + // and negative, if wheel was scrolled down. + if (delta) { + // perform the zoom action. Delta is normally 1 or -1 + + // adjust a negative delta such that zooming in with delta 0.1 + // equals zooming out with a delta -0.1 + var scale; + if (delta < 0) { + scale = 1 - (delta / 5); + } + else { + scale = 1 / (1 + (delta / 5)) ; + } + + // calculate center, the date to zoom around + var gesture = util.fakeGesture(this, event), + pointer = getPointer(gesture.touches[0], component.frame), + pointerDate = this._pointerToDate(component, direction, pointer); + + this.zoom(scale, pointerDate); + } + + // Prevent default actions caused by mouse wheel + // (else the page and timeline both zoom and scroll) + util.preventDefault(event); +}; + +/** + * On start of a touch gesture, initialize scale to 1 + * @private + */ +Range.prototype._onTouch = function () { + touchParams.start = this.start; + touchParams.end = this.end; + touchParams.pinching = false; + touchParams.center = null; +}; + +/** + * Handle pinch event + * @param {Event} event + * @param {Component} component + * @param {String} direction 'horizontal' or 'vertical' + * @private + */ +Range.prototype._onPinch = function (event, component, direction) { + touchParams.pinching = true; + + if (event.gesture.touches.length > 1) { + if (!touchParams.center) { + touchParams.center = getPointer(event.gesture.center, component.frame); + } + + var scale = 1 / event.gesture.scale, + initDate = this._pointerToDate(component, direction, touchParams.center), + center = getPointer(event.gesture.center, component.frame), + date = this._pointerToDate(component, direction, center), + delta = date - initDate; // TODO: utilize delta + + // calculate new start and end + var newStart = parseInt(initDate + (touchParams.start - initDate) * scale); + var newEnd = parseInt(initDate + (touchParams.end - initDate) * scale); + + // apply new range + this.setRange(newStart, newEnd); + } +}; + +/** + * Helper function to calculate the center date for zooming + * @param {Component} component + * @param {{x: Number, y: Number}} pointer + * @param {String} direction 'horizontal' or 'vertical' + * @return {number} date + * @private + */ +Range.prototype._pointerToDate = function (component, direction, pointer) { + var conversion; + if (direction == 'horizontal') { + var width = component.width; + conversion = this.conversion(width); + return pointer.x / conversion.scale + conversion.offset; + } + else { + var height = component.height; + conversion = this.conversion(height); + return pointer.y / conversion.scale + conversion.offset; + } +}; + +/** + * Get the pointer location relative to the location of the dom element + * @param {{pageX: Number, pageY: Number}} touch + * @param {Element} element HTML DOM element + * @return {{x: Number, y: Number}} pointer + * @private + */ +function getPointer (touch, element) { + return { + x: touch.pageX - vis.util.getAbsoluteLeft(element), + y: touch.pageY - vis.util.getAbsoluteTop(element) + }; +} + +/** + * Zoom the range the given scale in or out. Start and end date will + * be adjusted, and the timeline will be redrawn. You can optionally give a + * date around which to zoom. + * For example, try scale = 0.9 or 1.1 + * @param {Number} scale Scaling factor. Values above 1 will zoom out, + * values below 1 will zoom in. + * @param {Number} [center] Value representing a date around which will + * be zoomed. + */ +Range.prototype.zoom = function(scale, center) { + // if centerDate is not provided, take it half between start Date and end Date + if (center == null) { + center = (this.start + this.end) / 2; + } + + // calculate new start and end + var newStart = center + (this.start - center) * scale; + var newEnd = center + (this.end - center) * scale; + + this.setRange(newStart, newEnd); +}; + +/** + * Move the range with a given delta to the left or right. Start and end + * value will be adjusted. For example, try delta = 0.1 or -0.1 + * @param {Number} delta Moving amount. Positive value will move right, + * negative value will move left + */ +Range.prototype.move = function(delta) { + // zoom start Date and end Date relative to the centerDate + var diff = (this.end - this.start); + + // apply new values + var newStart = this.start + diff * delta; + var newEnd = this.end + diff * delta; + + // TODO: reckon with min and max range + + this.start = newStart; + this.end = newEnd; +}; + +/** + * Move the range to a new center point + * @param {Number} moveTo New center point of the range + */ +Range.prototype.moveTo = function(moveTo) { + var center = (this.start + this.end) / 2; + + var diff = center - moveTo; + + // calculate new start and end + var newStart = this.start - diff; + var newEnd = this.end - diff; + + this.setRange(newStart, newEnd); +}; + +/** + * @constructor Controller + * + * A Controller controls the reflows and repaints of all visual components + */ +function Controller () { + this.id = util.randomUUID(); + this.components = {}; + + this.repaintTimer = undefined; + this.reflowTimer = undefined; +} + +/** + * Add a component to the controller + * @param {Component} component + */ +Controller.prototype.add = function add(component) { + // validate the component + if (component.id == undefined) { + throw new Error('Component has no field id'); + } + if (!(component instanceof Component) && !(component instanceof Controller)) { + throw new TypeError('Component must be an instance of ' + + 'prototype Component or Controller'); + } + + // add the component + component.controller = this; + this.components[component.id] = component; +}; + +/** + * Remove a component from the controller + * @param {Component | String} component + */ +Controller.prototype.remove = function remove(component) { + var id; + for (id in this.components) { + if (this.components.hasOwnProperty(id)) { + if (id == component || this.components[id] == component) { + break; + } + } + } + + if (id) { + delete this.components[id]; + } +}; + +/** + * Request a reflow. The controller will schedule a reflow + * @param {Boolean} [force] If true, an immediate reflow is forced. Default + * is false. + */ +Controller.prototype.requestReflow = function requestReflow(force) { + if (force) { + this.reflow(); + } + else { + if (!this.reflowTimer) { + var me = this; + this.reflowTimer = setTimeout(function () { + me.reflowTimer = undefined; + me.reflow(); + }, 0); + } + } +}; + +/** + * Request a repaint. The controller will schedule a repaint + * @param {Boolean} [force] If true, an immediate repaint is forced. Default + * is false. + */ +Controller.prototype.requestRepaint = function requestRepaint(force) { + if (force) { + this.repaint(); + } + else { + if (!this.repaintTimer) { + var me = this; + this.repaintTimer = setTimeout(function () { + me.repaintTimer = undefined; + me.repaint(); + }, 0); + } + } +}; + +/** + * Repaint all components + */ +Controller.prototype.repaint = function repaint() { + var changed = false; + + // cancel any running repaint request + if (this.repaintTimer) { + clearTimeout(this.repaintTimer); + this.repaintTimer = undefined; + } + + var done = {}; + + function repaint(component, id) { + if (!(id in done)) { + // first repaint the components on which this component is dependent + if (component.depends) { + component.depends.forEach(function (dep) { + repaint(dep, dep.id); + }); + } + if (component.parent) { + repaint(component.parent, component.parent.id); + } + + // repaint the component itself and mark as done + changed = component.repaint() || changed; + done[id] = true; + } + } + + util.forEach(this.components, repaint); + + // immediately reflow when needed + if (changed) { + this.reflow(); + } + // TODO: limit the number of nested reflows/repaints, prevent loop +}; + +/** + * Reflow all components + */ +Controller.prototype.reflow = function reflow() { + var resized = false; + + // cancel any running repaint request + if (this.reflowTimer) { + clearTimeout(this.reflowTimer); + this.reflowTimer = undefined; + } + + var done = {}; + + function reflow(component, id) { + if (!(id in done)) { + // first reflow the components on which this component is dependent + if (component.depends) { + component.depends.forEach(function (dep) { + reflow(dep, dep.id); + }); + } + if (component.parent) { + reflow(component.parent, component.parent.id); + } + + // reflow the component itself and mark as done + resized = component.reflow() || resized; + done[id] = true; + } + } + + util.forEach(this.components, reflow); + + // immediately repaint when needed + if (resized) { + this.repaint(); + } + // TODO: limit the number of nested reflows/repaints, prevent loop +}; + +/** + * Prototype for visual components + */ +function Component () { + this.id = null; + this.parent = null; + this.depends = null; + this.controller = null; + this.options = null; + + this.frame = null; // main DOM element + this.top = 0; + this.left = 0; + this.width = 0; + this.height = 0; +} + +/** + * Set parameters for the frame. Parameters will be merged in current parameter + * set. + * @param {Object} options Available parameters: + * {String | function} [className] + * {EventBus} [eventBus] + * {String | Number | function} [left] + * {String | Number | function} [top] + * {String | Number | function} [width] + * {String | Number | function} [height] + */ +Component.prototype.setOptions = function setOptions(options) { + if (options) { + util.extend(this.options, options); + + if (this.controller) { + this.requestRepaint(); + this.requestReflow(); + } + } +}; + +/** + * Get an option value by name + * The function will first check this.options object, and else will check + * this.defaultOptions. + * @param {String} name + * @return {*} value + */ +Component.prototype.getOption = function getOption(name) { + var value; + if (this.options) { + value = this.options[name]; + } + if (value === undefined && this.defaultOptions) { + value = this.defaultOptions[name]; + } + return value; +}; + +/** + * Get the container element of the component, which can be used by a child to + * add its own widgets. Not all components do have a container for childs, in + * that case null is returned. + * @returns {HTMLElement | null} container + */ +// TODO: get rid of the getContainer and getFrame methods, provide these via the options +Component.prototype.getContainer = function getContainer() { + // should be implemented by the component + return null; +}; + +/** + * Get the frame element of the component, the outer HTML DOM element. + * @returns {HTMLElement | null} frame + */ +Component.prototype.getFrame = function getFrame() { + return this.frame; +}; + +/** + * Repaint the component + * @return {Boolean} changed + */ +Component.prototype.repaint = function repaint() { + // should be implemented by the component + return false; +}; + +/** + * Reflow the component + * @return {Boolean} resized + */ +Component.prototype.reflow = function reflow() { + // should be implemented by the component + return false; +}; + +/** + * Hide the component from the DOM + * @return {Boolean} changed + */ +Component.prototype.hide = function hide() { + if (this.frame && this.frame.parentNode) { + this.frame.parentNode.removeChild(this.frame); + return true; + } + else { + return false; + } +}; + +/** + * Show the component in the DOM (when not already visible). + * A repaint will be executed when the component is not visible + * @return {Boolean} changed + */ +Component.prototype.show = function show() { + if (!this.frame || !this.frame.parentNode) { + return this.repaint(); + } + else { + return false; + } +}; + +/** + * Request a repaint. The controller will schedule a repaint + */ +Component.prototype.requestRepaint = function requestRepaint() { + if (this.controller) { + this.controller.requestRepaint(); + } + else { + throw new Error('Cannot request a repaint: no controller configured'); + // TODO: just do a repaint when no parent is configured? + } +}; + +/** + * Request a reflow. The controller will schedule a reflow + */ +Component.prototype.requestReflow = function requestReflow() { + if (this.controller) { + this.controller.requestReflow(); + } + else { + throw new Error('Cannot request a reflow: no controller configured'); + // TODO: just do a reflow when no parent is configured? + } +}; + +/** + * A panel can contain components + * @param {Component} [parent] + * @param {Component[]} [depends] Components on which this components depends + * (except for the parent) + * @param {Object} [options] Available parameters: + * {String | Number | function} [left] + * {String | Number | function} [top] + * {String | Number | function} [width] + * {String | Number | function} [height] + * {String | function} [className] + * @constructor Panel + * @extends Component + */ +function Panel(parent, depends, options) { + this.id = util.randomUUID(); + this.parent = parent; + this.depends = depends; + + this.options = options || {}; +} + +Panel.prototype = new Component(); + +/** + * Set options. Will extend the current options. + * @param {Object} [options] Available parameters: + * {String | function} [className] + * {String | Number | function} [left] + * {String | Number | function} [top] + * {String | Number | function} [width] + * {String | Number | function} [height] + */ +Panel.prototype.setOptions = Component.prototype.setOptions; + +/** + * Get the container element of the panel, which can be used by a child to + * add its own widgets. + * @returns {HTMLElement} container + */ +Panel.prototype.getContainer = function () { + return this.frame; +}; + +/** + * Repaint the component + * @return {Boolean} changed + */ +Panel.prototype.repaint = function () { + var changed = 0, + update = util.updateProperty, + asSize = util.option.asSize, + options = this.options, + frame = this.frame; + if (!frame) { + frame = document.createElement('div'); + frame.className = 'panel'; + + var className = options.className; + if (className) { + if (typeof className == 'function') { + util.addClassName(frame, String(className())); + } + else { + util.addClassName(frame, String(className)); + } + } + + this.frame = frame; + changed += 1; + } + if (!frame.parentNode) { + if (!this.parent) { + throw new Error('Cannot repaint panel: no parent attached'); + } + var parentContainer = this.parent.getContainer(); + if (!parentContainer) { + throw new Error('Cannot repaint panel: parent has no container element'); + } + parentContainer.appendChild(frame); + changed += 1; + } + + changed += update(frame.style, 'top', asSize(options.top, '0px')); + changed += update(frame.style, 'left', asSize(options.left, '0px')); + changed += update(frame.style, 'width', asSize(options.width, '100%')); + changed += update(frame.style, 'height', asSize(options.height, '100%')); + + return (changed > 0); +}; + +/** + * Reflow the component + * @return {Boolean} resized + */ +Panel.prototype.reflow = function () { + var changed = 0, + update = util.updateProperty, + frame = this.frame; + + if (frame) { + changed += update(this, 'top', frame.offsetTop); + changed += update(this, 'left', frame.offsetLeft); + changed += update(this, 'width', frame.offsetWidth); + changed += update(this, 'height', frame.offsetHeight); + } + else { + changed += 1; + } + + return (changed > 0); +}; + +/** + * A root panel can hold components. The root panel must be initialized with + * a DOM element as container. + * @param {HTMLElement} container + * @param {Object} [options] Available parameters: see RootPanel.setOptions. + * @constructor RootPanel + * @extends Panel + */ +function RootPanel(container, options) { + this.id = util.randomUUID(); + this.container = container; + + this.options = options || {}; + this.defaultOptions = { + autoResize: true + }; + + this.listeners = {}; // event listeners +} + +RootPanel.prototype = new Panel(); + +/** + * Set options. Will extend the current options. + * @param {Object} [options] Available parameters: + * {String | function} [className] + * {String | Number | function} [left] + * {String | Number | function} [top] + * {String | Number | function} [width] + * {String | Number | function} [height] + * {Boolean | function} [autoResize] + */ +RootPanel.prototype.setOptions = Component.prototype.setOptions; + +/** + * Repaint the component + * @return {Boolean} changed + */ +RootPanel.prototype.repaint = function () { + var changed = 0, + update = util.updateProperty, + asSize = util.option.asSize, + options = this.options, + frame = this.frame; + + if (!frame) { + frame = document.createElement('div'); + + this.frame = frame; + + changed += 1; + } + if (!frame.parentNode) { + if (!this.container) { + throw new Error('Cannot repaint root panel: no container attached'); + } + this.container.appendChild(frame); + changed += 1; + } + + frame.className = 'vis timeline rootpanel ' + options.orientation; + var className = options.className; + if (className) { + util.addClassName(frame, util.option.asString(className)); + } + + changed += update(frame.style, 'top', asSize(options.top, '0px')); + changed += update(frame.style, 'left', asSize(options.left, '0px')); + changed += update(frame.style, 'width', asSize(options.width, '100%')); + changed += update(frame.style, 'height', asSize(options.height, '100%')); + + this._updateEventEmitters(); + this._updateWatch(); + + return (changed > 0); +}; + +/** + * Reflow the component + * @return {Boolean} resized + */ +RootPanel.prototype.reflow = function () { + var changed = 0, + update = util.updateProperty, + frame = this.frame; + + if (frame) { + changed += update(this, 'top', frame.offsetTop); + changed += update(this, 'left', frame.offsetLeft); + changed += update(this, 'width', frame.offsetWidth); + changed += update(this, 'height', frame.offsetHeight); + } + else { + changed += 1; + } + + return (changed > 0); +}; + +/** + * Update watching for resize, depending on the current option + * @private + */ +RootPanel.prototype._updateWatch = function () { + var autoResize = this.getOption('autoResize'); + if (autoResize) { + this._watch(); + } + else { + this._unwatch(); + } +}; + +/** + * Watch for changes in the size of the frame. On resize, the Panel will + * automatically redraw itself. + * @private + */ +RootPanel.prototype._watch = function () { + var me = this; + + this._unwatch(); + + var checkSize = function () { + var autoResize = me.getOption('autoResize'); + if (!autoResize) { + // stop watching when the option autoResize is changed to false + me._unwatch(); + return; + } + + if (me.frame) { + // check whether the frame is resized + if ((me.frame.clientWidth != me.width) || + (me.frame.clientHeight != me.height)) { + me.requestReflow(); + } + } + }; + + // TODO: automatically cleanup the event listener when the frame is deleted + util.addEventListener(window, 'resize', checkSize); + + this.watchTimer = setInterval(checkSize, 1000); +}; + +/** + * Stop watching for a resize of the frame. + * @private + */ +RootPanel.prototype._unwatch = function () { + if (this.watchTimer) { + clearInterval(this.watchTimer); + this.watchTimer = undefined; + } + + // TODO: remove event listener on window.resize +}; + +/** + * Event handler + * @param {String} event name of the event, for example 'click', 'mousemove' + * @param {function} callback callback handler, invoked with the raw HTML Event + * as parameter. + */ +RootPanel.prototype.on = function (event, callback) { + // register the listener at this component + var arr = this.listeners[event]; + if (!arr) { + arr = []; + this.listeners[event] = arr; + } + arr.push(callback); + + this._updateEventEmitters(); +}; + +/** + * Update the event listeners for all event emitters + * @private + */ +RootPanel.prototype._updateEventEmitters = function () { + if (this.listeners) { + var me = this; + util.forEach(this.listeners, function (listeners, event) { + if (!me.emitters) { + me.emitters = {}; + } + if (!(event in me.emitters)) { + // create event + var frame = me.frame; + if (frame) { + //console.log('Created a listener for event ' + event + ' on component ' + me.id); // TODO: cleanup logging + var callback = function(event) { + listeners.forEach(function (listener) { + // TODO: filter on event target! + listener(event); + }); + }; + me.emitters[event] = callback; + + if (!me.hammer) { + me.hammer = Hammer(frame, { + prevent_default: true + }); + } + me.hammer.on(event, callback); + } + } + }); + + // TODO: be able to delete event listeners + // TODO: be able to move event listeners to a parent when available + } +}; + +/** + * A horizontal time axis + * @param {Component} parent + * @param {Component[]} [depends] Components on which this components depends + * (except for the parent) + * @param {Object} [options] See TimeAxis.setOptions for the available + * options. + * @constructor TimeAxis + * @extends Component + */ +function TimeAxis (parent, depends, options) { + this.id = util.randomUUID(); + this.parent = parent; + this.depends = depends; + + this.dom = { + majorLines: [], + majorTexts: [], + minorLines: [], + minorTexts: [], + redundant: { + majorLines: [], + majorTexts: [], + minorLines: [], + minorTexts: [] + } + }; + this.props = { + range: { + start: 0, + end: 0, + minimumStep: 0 + }, + lineTop: 0 + }; + + this.options = options || {}; + this.defaultOptions = { + orientation: 'bottom', // supported: 'top', 'bottom' + // TODO: implement timeaxis orientations 'left' and 'right' + showMinorLabels: true, + showMajorLabels: true + }; + + this.conversion = null; + this.range = null; +} + +TimeAxis.prototype = new Component(); + +// TODO: comment options +TimeAxis.prototype.setOptions = Component.prototype.setOptions; + +/** + * Set a range (start and end) + * @param {Range | Object} range A Range or an object containing start and end. + */ +TimeAxis.prototype.setRange = function (range) { + if (!(range instanceof Range) && (!range || !range.start || !range.end)) { + throw new TypeError('Range must be an instance of Range, ' + + 'or an object containing start and end.'); + } + this.range = range; +}; + +/** + * Convert a position on screen (pixels) to a datetime + * @param {int} x Position on the screen in pixels + * @return {Date} time The datetime the corresponds with given position x + */ +TimeAxis.prototype.toTime = function(x) { + var conversion = this.conversion; + return new Date(x / conversion.scale + conversion.offset); +}; + +/** + * Convert a datetime (Date object) into a position on the screen + * @param {Date} time A date + * @return {int} x The position on the screen in pixels which corresponds + * with the given date. + * @private + */ +TimeAxis.prototype.toScreen = function(time) { + var conversion = this.conversion; + return (time.valueOf() - conversion.offset) * conversion.scale; +}; + +/** + * Repaint the component + * @return {Boolean} changed + */ +TimeAxis.prototype.repaint = function () { + var changed = 0, + update = util.updateProperty, + asSize = util.option.asSize, + options = this.options, + orientation = this.getOption('orientation'), + props = this.props, + step = this.step; + + var frame = this.frame; + if (!frame) { + frame = document.createElement('div'); + this.frame = frame; + changed += 1; + } + frame.className = 'axis'; + // TODO: custom className? + + if (!frame.parentNode) { + if (!this.parent) { + throw new Error('Cannot repaint time axis: no parent attached'); + } + var parentContainer = this.parent.getContainer(); + if (!parentContainer) { + throw new Error('Cannot repaint time axis: parent has no container element'); + } + parentContainer.appendChild(frame); + + changed += 1; + } + + var parent = frame.parentNode; + if (parent) { + var beforeChild = frame.nextSibling; + parent.removeChild(frame); // take frame offline while updating (is almost twice as fast) + + var defaultTop = (orientation == 'bottom' && this.props.parentHeight && this.height) ? + (this.props.parentHeight - this.height) + 'px' : + '0px'; + changed += update(frame.style, 'top', asSize(options.top, defaultTop)); + changed += update(frame.style, 'left', asSize(options.left, '0px')); + changed += update(frame.style, 'width', asSize(options.width, '100%')); + changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); + + // get characters width and height + this._repaintMeasureChars(); + + if (this.step) { + this._repaintStart(); + + step.first(); + var xFirstMajorLabel = undefined; + var max = 0; + while (step.hasNext() && max < 1000) { + max++; + var cur = step.getCurrent(), + x = this.toScreen(cur), + isMajor = step.isMajor(); + + // TODO: lines must have a width, such that we can create css backgrounds + + if (this.getOption('showMinorLabels')) { + this._repaintMinorText(x, step.getLabelMinor()); + } + + if (isMajor && this.getOption('showMajorLabels')) { + if (x > 0) { + if (xFirstMajorLabel == undefined) { + xFirstMajorLabel = x; + } + this._repaintMajorText(x, step.getLabelMajor()); + } + this._repaintMajorLine(x); + } + else { + this._repaintMinorLine(x); + } + + step.next(); + } + + // create a major label on the left when needed + if (this.getOption('showMajorLabels')) { + var leftTime = this.toTime(0), + leftText = step.getLabelMajor(leftTime), + widthText = leftText.length * (props.majorCharWidth || 10) + 10; // upper bound estimation + + if (xFirstMajorLabel == undefined || widthText < xFirstMajorLabel) { + this._repaintMajorText(0, leftText); + } + } + + this._repaintEnd(); + } + + this._repaintLine(); + + // put frame online again + if (beforeChild) { + parent.insertBefore(frame, beforeChild); + } + else { + parent.appendChild(frame) + } + } + + return (changed > 0); +}; + +/** + * Start a repaint. Move all DOM elements to a redundant list, where they + * can be picked for re-use, or can be cleaned up in the end + * @private + */ +TimeAxis.prototype._repaintStart = function () { + var dom = this.dom, + redundant = dom.redundant; + + redundant.majorLines = dom.majorLines; + redundant.majorTexts = dom.majorTexts; + redundant.minorLines = dom.minorLines; + redundant.minorTexts = dom.minorTexts; + + dom.majorLines = []; + dom.majorTexts = []; + dom.minorLines = []; + dom.minorTexts = []; +}; + +/** + * End a repaint. Cleanup leftover DOM elements in the redundant list + * @private + */ +TimeAxis.prototype._repaintEnd = function () { + util.forEach(this.dom.redundant, function (arr) { + while (arr.length) { + var elem = arr.pop(); + if (elem && elem.parentNode) { + elem.parentNode.removeChild(elem); + } + } + }); +}; + + +/** + * Create a minor label for the axis at position x + * @param {Number} x + * @param {String} text + * @private + */ +TimeAxis.prototype._repaintMinorText = function (x, text) { + // reuse redundant label + var label = this.dom.redundant.minorTexts.shift(); + + if (!label) { + // create new label + var content = document.createTextNode(''); + label = document.createElement('div'); + label.appendChild(content); + label.className = 'text minor'; + this.frame.appendChild(label); + } + this.dom.minorTexts.push(label); + + label.childNodes[0].nodeValue = text; + label.style.left = x + 'px'; + label.style.top = this.props.minorLabelTop + 'px'; + //label.title = title; // TODO: this is a heavy operation +}; + +/** + * Create a Major label for the axis at position x + * @param {Number} x + * @param {String} text + * @private + */ +TimeAxis.prototype._repaintMajorText = function (x, text) { + // reuse redundant label + var label = this.dom.redundant.majorTexts.shift(); + + if (!label) { + // create label + var content = document.createTextNode(text); + label = document.createElement('div'); + label.className = 'text major'; + label.appendChild(content); + this.frame.appendChild(label); + } + this.dom.majorTexts.push(label); + + label.childNodes[0].nodeValue = text; + label.style.top = this.props.majorLabelTop + 'px'; + label.style.left = x + 'px'; + //label.title = title; // TODO: this is a heavy operation +}; + +/** + * Create a minor line for the axis at position x + * @param {Number} x + * @private + */ +TimeAxis.prototype._repaintMinorLine = function (x) { + // reuse redundant line + var line = this.dom.redundant.minorLines.shift(); + + if (!line) { + // create vertical line + line = document.createElement('div'); + line.className = 'grid vertical minor'; + this.frame.appendChild(line); + } + this.dom.minorLines.push(line); + + var props = this.props; + line.style.top = props.minorLineTop + 'px'; + line.style.height = props.minorLineHeight + 'px'; + line.style.left = (x - props.minorLineWidth / 2) + 'px'; +}; + +/** + * Create a Major line for the axis at position x + * @param {Number} x + * @private + */ +TimeAxis.prototype._repaintMajorLine = function (x) { + // reuse redundant line + var line = this.dom.redundant.majorLines.shift(); + + if (!line) { + // create vertical line + line = document.createElement('DIV'); + line.className = 'grid vertical major'; + this.frame.appendChild(line); + } + this.dom.majorLines.push(line); + + var props = this.props; + line.style.top = props.majorLineTop + 'px'; + line.style.left = (x - props.majorLineWidth / 2) + 'px'; + line.style.height = props.majorLineHeight + 'px'; +}; + + +/** + * Repaint the horizontal line for the axis + * @private + */ +TimeAxis.prototype._repaintLine = function() { + var line = this.dom.line, + frame = this.frame, + options = this.options; + + // line before all axis elements + if (this.getOption('showMinorLabels') || this.getOption('showMajorLabels')) { + if (line) { + // put this line at the end of all childs + frame.removeChild(line); + frame.appendChild(line); + } + else { + // create the axis line + line = document.createElement('div'); + line.className = 'grid horizontal major'; + frame.appendChild(line); + this.dom.line = line; + } + + line.style.top = this.props.lineTop + 'px'; + } + else { + if (line && line.parentElement) { + frame.removeChild(line.line); + delete this.dom.line; + } + } +}; + +/** + * Create characters used to determine the size of text on the axis + * @private + */ +TimeAxis.prototype._repaintMeasureChars = function () { + // calculate the width and height of a single character + // this is used to calculate the step size, and also the positioning of the + // axis + var dom = this.dom, + text; + + if (!dom.measureCharMinor) { + text = document.createTextNode('0'); + var measureCharMinor = document.createElement('DIV'); + measureCharMinor.className = 'text minor measure'; + measureCharMinor.appendChild(text); + this.frame.appendChild(measureCharMinor); + + dom.measureCharMinor = measureCharMinor; + } + + if (!dom.measureCharMajor) { + text = document.createTextNode('0'); + var measureCharMajor = document.createElement('DIV'); + measureCharMajor.className = 'text major measure'; + measureCharMajor.appendChild(text); + this.frame.appendChild(measureCharMajor); + + dom.measureCharMajor = measureCharMajor; + } +}; + +/** + * Reflow the component + * @return {Boolean} resized + */ +TimeAxis.prototype.reflow = function () { + var changed = 0, + update = util.updateProperty, + frame = this.frame, + range = this.range; + + if (!range) { + throw new Error('Cannot repaint time axis: no range configured'); + } + + if (frame) { + changed += update(this, 'top', frame.offsetTop); + changed += update(this, 'left', frame.offsetLeft); + + // calculate size of a character + var props = this.props, + showMinorLabels = this.getOption('showMinorLabels'), + showMajorLabels = this.getOption('showMajorLabels'), + measureCharMinor = this.dom.measureCharMinor, + measureCharMajor = this.dom.measureCharMajor; + if (measureCharMinor) { + props.minorCharHeight = measureCharMinor.clientHeight; + props.minorCharWidth = measureCharMinor.clientWidth; + } + if (measureCharMajor) { + props.majorCharHeight = measureCharMajor.clientHeight; + props.majorCharWidth = measureCharMajor.clientWidth; + } + + var parentHeight = frame.parentNode ? frame.parentNode.offsetHeight : 0; + if (parentHeight != props.parentHeight) { + props.parentHeight = parentHeight; + changed += 1; + } + switch (this.getOption('orientation')) { + case 'bottom': + props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; + props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; + + props.minorLabelTop = 0; + props.majorLabelTop = props.minorLabelTop + props.minorLabelHeight; + + props.minorLineTop = -this.top; + props.minorLineHeight = Math.max(this.top + props.majorLabelHeight, 0); + props.minorLineWidth = 1; // TODO: really calculate width + + props.majorLineTop = -this.top; + props.majorLineHeight = Math.max(this.top + props.minorLabelHeight + props.majorLabelHeight, 0); + props.majorLineWidth = 1; // TODO: really calculate width + + props.lineTop = 0; + + break; + + case 'top': + props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; + props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; + + props.majorLabelTop = 0; + props.minorLabelTop = props.majorLabelTop + props.majorLabelHeight; + + props.minorLineTop = props.minorLabelTop; + props.minorLineHeight = Math.max(parentHeight - props.majorLabelHeight - this.top); + props.minorLineWidth = 1; // TODO: really calculate width + + props.majorLineTop = 0; + props.majorLineHeight = Math.max(parentHeight - this.top); + props.majorLineWidth = 1; // TODO: really calculate width + + props.lineTop = props.majorLabelHeight + props.minorLabelHeight; + + break; + + default: + throw new Error('Unkown orientation "' + this.getOption('orientation') + '"'); + } + + var height = props.minorLabelHeight + props.majorLabelHeight; + changed += update(this, 'width', frame.offsetWidth); + changed += update(this, 'height', height); + + // calculate range and step + this._updateConversion(); + + var start = util.convert(range.start, 'Number'), + end = util.convert(range.end, 'Number'), + minimumStep = this.toTime((props.minorCharWidth || 10) * 5).valueOf() + -this.toTime(0).valueOf(); + this.step = new TimeStep(new Date(start), new Date(end), minimumStep); + changed += update(props.range, 'start', start); + changed += update(props.range, 'end', end); + changed += update(props.range, 'minimumStep', minimumStep.valueOf()); + } + + return (changed > 0); +}; + +/** + * Calculate the scale and offset to convert a position on screen to the + * corresponding date and vice versa. + * After the method _updateConversion is executed once, the methods toTime + * and toScreen can be used. + * @private + */ +TimeAxis.prototype._updateConversion = function() { + var range = this.range; + if (!range) { + throw new Error('No range configured'); + } + + if (range.conversion) { + this.conversion = range.conversion(this.width); + } + else { + this.conversion = Range.conversion(range.start, range.end, this.width); + } +}; + +/** + * A current time bar + * @param {Component} parent + * @param {Component[]} [depends] Components on which this components depends + * (except for the parent) + * @param {Object} [options] Available parameters: + * {Boolean} [showCurrentTime] + * @constructor CurrentTime + * @extends Component + */ + +function CurrentTime (parent, depends, options) { + this.id = util.randomUUID(); + this.parent = parent; + this.depends = depends; + + this.options = options || {}; + this.defaultOptions = { + showCurrentTime: false + }; +} + +CurrentTime.prototype = new Component(); + +CurrentTime.prototype.setOptions = Component.prototype.setOptions; + +/** + * Get the container element of the bar, which can be used by a child to + * add its own widgets. + * @returns {HTMLElement} container + */ +CurrentTime.prototype.getContainer = function () { + return this.frame; +}; + +/** + * Repaint the component + * @return {Boolean} changed + */ +CurrentTime.prototype.repaint = function () { + var bar = this.frame, + parent = this.parent, + parentContainer = parent.parent.getContainer(); + + if (!parent) { + throw new Error('Cannot repaint bar: no parent attached'); + } + + if (!parentContainer) { + throw new Error('Cannot repaint bar: parent has no container element'); + } + + if (!this.getOption('showCurrentTime')) { + if (bar) { + parentContainer.removeChild(bar); + delete this.frame; + } + + return; + } + + if (!bar) { + bar = document.createElement('div'); + bar.className = 'currenttime'; + bar.style.position = 'absolute'; + bar.style.top = '0px'; + bar.style.height = '100%'; + + parentContainer.appendChild(bar); + this.frame = bar; + } + + if (!parent.conversion) { + parent._updateConversion(); + } + + var now = new Date(); + var x = parent.toScreen(now); + + bar.style.left = x + 'px'; + bar.title = 'Current time: ' + now; + + // start a timer to adjust for the new time + if (this.currentTimeTimer !== undefined) { + clearTimeout(this.currentTimeTimer); + delete this.currentTimeTimer; + } + + var timeline = this; + var interval = 1 / parent.conversion.scale / 2; + + if (interval < 30) { + interval = 30; + } + + this.currentTimeTimer = setTimeout(function() { + timeline.repaint(); + }, interval); + + return false; +}; + +/** + * A custom time bar + * @param {Component} parent + * @param {Component[]} [depends] Components on which this components depends + * (except for the parent) + * @param {Object} [options] Available parameters: + * {Boolean} [showCustomTime] + * @constructor CustomTime + * @extends Component + */ + +function CustomTime (parent, depends, options) { + this.id = util.randomUUID(); + this.parent = parent; + this.depends = depends; + + this.options = options || {}; + this.defaultOptions = { + showCustomTime: false + }; + + this.listeners = []; + this.customTime = new Date(); +} + +CustomTime.prototype = new Component(); + +CustomTime.prototype.setOptions = Component.prototype.setOptions; + +/** + * Get the container element of the bar, which can be used by a child to + * add its own widgets. + * @returns {HTMLElement} container + */ +CustomTime.prototype.getContainer = function () { + return this.frame; +}; + +/** + * Repaint the component + * @return {Boolean} changed + */ +CustomTime.prototype.repaint = function () { + var bar = this.frame, + parent = this.parent, + parentContainer = parent.parent.getContainer(); + + if (!parent) { + throw new Error('Cannot repaint bar: no parent attached'); + } + + if (!parentContainer) { + throw new Error('Cannot repaint bar: parent has no container element'); + } + + if (!this.getOption('showCustomTime')) { + if (bar) { + parentContainer.removeChild(bar); + delete this.frame; + } + + return; + } + + if (!bar) { + bar = document.createElement('div'); + bar.className = 'customtime'; + bar.style.position = 'absolute'; + bar.style.top = '0px'; + bar.style.height = '100%'; + + parentContainer.appendChild(bar); + + var drag = document.createElement('div'); + drag.style.position = 'relative'; + drag.style.top = '0px'; + drag.style.left = '-10px'; + drag.style.height = '100%'; + drag.style.width = '20px'; + bar.appendChild(drag); + + this.frame = bar; + + this.subscribe(this, 'movetime'); + } + + if (!parent.conversion) { + parent._updateConversion(); + } + + var x = parent.toScreen(this.customTime); + + bar.style.left = x + 'px'; + bar.title = 'Time: ' + this.customTime; + + return false; +}; + +/** + * Set custom time. + * @param {Date} time + */ +CustomTime.prototype._setCustomTime = function(time) { + this.customTime = new Date(time.valueOf()); + this.repaint(); +}; + +/** + * Retrieve the current custom time. + * @return {Date} customTime + */ +CustomTime.prototype._getCustomTime = function() { + return new Date(this.customTime.valueOf()); +}; + +/** + * Add listeners for mouse and touch events to the component + * @param {Component} component + */ +CustomTime.prototype.subscribe = function (component, event) { + var me = this; + var listener = { + component: component, + event: event, + callback: function (event) { + me._onMouseDown(event, listener); + }, + params: {} + }; + + component.on('mousedown', listener.callback); + me.listeners.push(listener); + +}; + +/** + * Event handler + * @param {String} event name of the event, for example 'click', 'mousemove' + * @param {function} callback callback handler, invoked with the raw HTML Event + * as parameter. + */ +CustomTime.prototype.on = function (event, callback) { + var bar = this.frame; + if (!bar) { + throw new Error('Cannot add event listener: no parent attached'); + } + + events.addListener(this, event, callback); + util.addEventListener(bar, event, callback); +}; + +/** + * Start moving horizontally + * @param {Event} event + * @param {Object} listener Listener containing the component and params + * @private + */ +CustomTime.prototype._onMouseDown = function(event, listener) { + event = event || window.event; + var params = listener.params; + + // only react on left mouse button down + var leftButtonDown = event.which ? (event.which == 1) : (event.button == 1); + if (!leftButtonDown) { + return; + } + + // get mouse position + params.mouseX = util.getPageX(event); + params.moved = false; + + params.customTime = this.customTime; + + // add event listeners to handle moving the custom time bar + var me = this; + if (!params.onMouseMove) { + params.onMouseMove = function (event) { + me._onMouseMove(event, listener); + }; + util.addEventListener(document, 'mousemove', params.onMouseMove); + } + if (!params.onMouseUp) { + params.onMouseUp = function (event) { + me._onMouseUp(event, listener); + }; + util.addEventListener(document, 'mouseup', params.onMouseUp); + } + + util.stopPropagation(event); + util.preventDefault(event); +}; + +/** + * Perform moving operating. + * This function activated from within the funcion CustomTime._onMouseDown(). + * @param {Event} event + * @param {Object} listener + * @private + */ +CustomTime.prototype._onMouseMove = function (event, listener) { + event = event || window.event; + var params = listener.params; + var parent = this.parent; + + // calculate change in mouse position + var mouseX = util.getPageX(event); + + if (params.mouseX === undefined) { + params.mouseX = mouseX; + } + + var diff = mouseX - params.mouseX; + + // if mouse movement is big enough, register it as a "moved" event + if (Math.abs(diff) >= 1) { + params.moved = true; + } + + var x = parent.toScreen(params.customTime); + var xnew = x + diff; + var time = parent.toTime(xnew); + this._setCustomTime(time); + + // fire a timechange event + events.trigger(this, 'timechange', {customTime: this.customTime}); + + util.preventDefault(event); +}; + +/** + * Stop moving operating. + * This function activated from within the function CustomTime._onMouseDown(). + * @param {event} event + * @param {Object} listener + * @private + */ +CustomTime.prototype._onMouseUp = function (event, listener) { + event = event || window.event; + var params = listener.params; + + // remove event listeners here, important for Safari + if (params.onMouseMove) { + util.removeEventListener(document, 'mousemove', params.onMouseMove); + params.onMouseMove = null; + } + if (params.onMouseUp) { + util.removeEventListener(document, 'mouseup', params.onMouseUp); + params.onMouseUp = null; + } + + if (params.moved) { + // fire a timechanged event + events.trigger(this, 'timechanged', {customTime: this.customTime}); + } +}; + +/** + * An ItemSet holds a set of items and ranges which can be displayed in a + * range. The width is determined by the parent of the ItemSet, and the height + * is determined by the size of the items. + * @param {Component} parent + * @param {Component[]} [depends] Components on which this components depends + * (except for the parent) + * @param {Object} [options] See ItemSet.setOptions for the available + * options. + * @constructor ItemSet + * @extends Panel + */ +// TODO: improve performance by replacing all Array.forEach with a for loop +function ItemSet(parent, depends, options) { + this.id = util.randomUUID(); + this.parent = parent; + this.depends = depends; + + // one options object is shared by this itemset and all its items + this.options = options || {}; + this.defaultOptions = { + type: 'box', + align: 'center', + orientation: 'bottom', + margin: { + axis: 20, + item: 10 + }, + padding: 5 + }; + + this.dom = {}; + + var me = this; + this.itemsData = null; // DataSet + this.range = null; // Range or Object {start: number, end: number} + + this.listeners = { + 'add': function (event, params, senderId) { + if (senderId != me.id) { + me._onAdd(params.items); + } + }, + 'update': function (event, params, senderId) { + if (senderId != me.id) { + me._onUpdate(params.items); + } + }, + 'remove': function (event, params, senderId) { + if (senderId != me.id) { + me._onRemove(params.items); + } + } + }; + + this.items = {}; // object with an Item for every data item + this.queue = {}; // queue with id/actions: 'add', 'update', 'delete' + this.stack = new Stack(this, Object.create(this.options)); + this.conversion = null; + + // TODO: ItemSet should also attach event listeners for rangechange and rangechanged, like timeaxis +} + +ItemSet.prototype = new Panel(); + +// available item types will be registered here +ItemSet.types = { + box: ItemBox, + range: ItemRange, + rangeoverflow: ItemRangeOverflow, + point: ItemPoint +}; + +/** + * Set options for the ItemSet. Existing options will be extended/overwritten. + * @param {Object} [options] The following options are available: + * {String | function} [className] + * class name for the itemset + * {String} [type] + * Default type for the items. Choose from 'box' + * (default), 'point', or 'range'. The default + * Style can be overwritten by individual items. + * {String} align + * Alignment for the items, only applicable for + * ItemBox. Choose 'center' (default), 'left', or + * 'right'. + * {String} orientation + * Orientation of the item set. Choose 'top' or + * 'bottom' (default). + * {Number} margin.axis + * Margin between the axis and the items in pixels. + * Default is 20. + * {Number} margin.item + * Margin between items in pixels. Default is 10. + * {Number} padding + * Padding of the contents of an item in pixels. + * Must correspond with the items css. Default is 5. + */ +ItemSet.prototype.setOptions = Component.prototype.setOptions; + +/** + * Set range (start and end). + * @param {Range | Object} range A Range or an object containing start and end. + */ +ItemSet.prototype.setRange = function setRange(range) { + if (!(range instanceof Range) && (!range || !range.start || !range.end)) { + throw new TypeError('Range must be an instance of Range, ' + + 'or an object containing start and end.'); + } + this.range = range; +}; + +/** + * Repaint the component + * @return {Boolean} changed + */ +ItemSet.prototype.repaint = function repaint() { + var changed = 0, + update = util.updateProperty, + asSize = util.option.asSize, + options = this.options, + orientation = this.getOption('orientation'), + defaultOptions = this.defaultOptions, + frame = this.frame; + + if (!frame) { + frame = document.createElement('div'); + frame.className = 'itemset'; + + var className = options.className; + if (className) { + util.addClassName(frame, util.option.asString(className)); + } + + // create background panel + var background = document.createElement('div'); + background.className = 'background'; + frame.appendChild(background); + this.dom.background = background; + + // create foreground panel + var foreground = document.createElement('div'); + foreground.className = 'foreground'; + frame.appendChild(foreground); + this.dom.foreground = foreground; + + // create axis panel + var axis = document.createElement('div'); + axis.className = 'itemset-axis'; + //frame.appendChild(axis); + this.dom.axis = axis; + + this.frame = frame; + changed += 1; + } + + if (!this.parent) { + throw new Error('Cannot repaint itemset: no parent attached'); + } + var parentContainer = this.parent.getContainer(); + if (!parentContainer) { + throw new Error('Cannot repaint itemset: parent has no container element'); + } + if (!frame.parentNode) { + parentContainer.appendChild(frame); + changed += 1; + } + if (!this.dom.axis.parentNode) { + parentContainer.appendChild(this.dom.axis); + changed += 1; + } + + // reposition frame + changed += update(frame.style, 'left', asSize(options.left, '0px')); + changed += update(frame.style, 'top', asSize(options.top, '0px')); + changed += update(frame.style, 'width', asSize(options.width, '100%')); + changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); + + // reposition axis + changed += update(this.dom.axis.style, 'left', asSize(options.left, '0px')); + changed += update(this.dom.axis.style, 'width', asSize(options.width, '100%')); + if (orientation == 'bottom') { + changed += update(this.dom.axis.style, 'top', (this.height + this.top) + 'px'); + } + else { // orientation == 'top' + changed += update(this.dom.axis.style, 'top', this.top + 'px'); + } + + this._updateConversion(); + + var me = this, + queue = this.queue, + itemsData = this.itemsData, + items = this.items, + dataOptions = { + // TODO: cleanup + // fields: [(itemsData && itemsData.fieldId || 'id'), 'start', 'end', 'content', 'type', 'className'] + }; + + // show/hide added/changed/removed items + Object.keys(queue).forEach(function (id) { + //var entry = queue[id]; + var action = queue[id]; + var item = items[id]; + //var item = entry.item; + //noinspection FallthroughInSwitchStatementJS + switch (action) { + case 'add': + case 'update': + var itemData = itemsData && itemsData.get(id, dataOptions); + + if (itemData) { + var type = itemData.type || + (itemData.start && itemData.end && 'range') || + options.type || + 'box'; + var constructor = ItemSet.types[type]; + + // TODO: how to handle items with invalid data? hide them and give a warning? or throw an error? + if (item) { + // update item + if (!constructor || !(item instanceof constructor)) { + // item type has changed, hide and delete the item + changed += item.hide(); + item = null; + } + else { + item.data = itemData; // TODO: create a method item.setData ? + changed++; + } + } + + if (!item) { + // create item + if (constructor) { + item = new constructor(me, itemData, options, defaultOptions); + changed++; + } + else { + throw new TypeError('Unknown item type "' + type + '"'); + } + } + + // force a repaint (not only a reposition) + item.repaint(); + + items[id] = item; + } + + // update queue + delete queue[id]; + break; + + case 'remove': + if (item) { + // remove DOM of the item + changed += item.hide(); + } + + // update lists + delete items[id]; + delete queue[id]; + break; + + default: + console.log('Error: unknown action "' + action + '"'); + } + }); + + // reposition all items. Show items only when in the visible area + util.forEach(this.items, function (item) { + if (item.visible) { + changed += item.show(); + item.reposition(); + } + else { + changed += item.hide(); + } + }); + + return (changed > 0); +}; + +/** + * Get the foreground container element + * @return {HTMLElement} foreground + */ +ItemSet.prototype.getForeground = function getForeground() { + return this.dom.foreground; +}; + +/** + * Get the background container element + * @return {HTMLElement} background + */ +ItemSet.prototype.getBackground = function getBackground() { + return this.dom.background; +}; + +/** + * Get the axis container element + * @return {HTMLElement} axis + */ +ItemSet.prototype.getAxis = function getAxis() { + return this.dom.axis; +}; + +/** + * Reflow the component + * @return {Boolean} resized + */ +ItemSet.prototype.reflow = function reflow () { + var changed = 0, + options = this.options, + marginAxis = options.margin && options.margin.axis || this.defaultOptions.margin.axis, + marginItem = options.margin && options.margin.item || this.defaultOptions.margin.item, + update = util.updateProperty, + asNumber = util.option.asNumber, + asSize = util.option.asSize, + frame = this.frame; + + if (frame) { + this._updateConversion(); + + util.forEach(this.items, function (item) { + changed += item.reflow(); + }); + + // TODO: stack.update should be triggered via an event, in stack itself + // TODO: only update the stack when there are changed items + this.stack.update(); + + var maxHeight = asNumber(options.maxHeight); + var fixedHeight = (asSize(options.height) != null); + var height; + if (fixedHeight) { + height = frame.offsetHeight; + } + else { + // height is not specified, determine the height from the height and positioned items + var visibleItems = this.stack.ordered; // TODO: not so nice way to get the filtered items + if (visibleItems.length) { + var min = visibleItems[0].top; + var max = visibleItems[0].top + visibleItems[0].height; + util.forEach(visibleItems, function (item) { + min = Math.min(min, item.top); + max = Math.max(max, (item.top + item.height)); + }); + height = (max - min) + marginAxis + marginItem; + } + else { + height = marginAxis + marginItem; + } + } + if (maxHeight != null) { + height = Math.min(height, maxHeight); + } + changed += update(this, 'height', height); + + // calculate height from items + changed += update(this, 'top', frame.offsetTop); + changed += update(this, 'left', frame.offsetLeft); + changed += update(this, 'width', frame.offsetWidth); + } + else { + changed += 1; + } + + return (changed > 0); +}; + +/** + * Hide this component from the DOM + * @return {Boolean} changed + */ +ItemSet.prototype.hide = function hide() { + var changed = false; + + // remove the DOM + if (this.frame && this.frame.parentNode) { + this.frame.parentNode.removeChild(this.frame); + changed = true; + } + if (this.dom.axis && this.dom.axis.parentNode) { + this.dom.axis.parentNode.removeChild(this.dom.axis); + changed = true; + } + + return changed; +}; + +/** + * Set items + * @param {vis.DataSet | null} items + */ +ItemSet.prototype.setItems = function setItems(items) { + var me = this, + ids, + oldItemsData = this.itemsData; + + // replace the dataset + if (!items) { + this.itemsData = null; + } + else if (items instanceof DataSet || items instanceof DataView) { + this.itemsData = items; + } + else { + throw new TypeError('Data must be an instance of DataSet'); + } + + if (oldItemsData) { + // unsubscribe from old dataset + util.forEach(this.listeners, function (callback, event) { + oldItemsData.unsubscribe(event, callback); + }); + + // remove all drawn items + ids = oldItemsData.getIds(); + this._onRemove(ids); + } + + if (this.itemsData) { + // subscribe to new dataset + var id = this.id; + util.forEach(this.listeners, function (callback, event) { + me.itemsData.subscribe(event, callback, id); + }); + + // draw all new items + ids = this.itemsData.getIds(); + this._onAdd(ids); + } +}; + +/** + * Get the current items items + * @returns {vis.DataSet | null} + */ +ItemSet.prototype.getItems = function getItems() { + return this.itemsData; +}; + +/** + * Handle updated items + * @param {Number[]} ids + * @private + */ +ItemSet.prototype._onUpdate = function _onUpdate(ids) { + this._toQueue('update', ids); +}; + +/** + * Handle changed items + * @param {Number[]} ids + * @private + */ +ItemSet.prototype._onAdd = function _onAdd(ids) { + this._toQueue('add', ids); +}; + +/** + * Handle removed items + * @param {Number[]} ids + * @private + */ +ItemSet.prototype._onRemove = function _onRemove(ids) { + this._toQueue('remove', ids); +}; + +/** + * Put items in the queue to be added/updated/remove + * @param {String} action can be 'add', 'update', 'remove' + * @param {Number[]} ids + */ +ItemSet.prototype._toQueue = function _toQueue(action, ids) { + var queue = this.queue; + ids.forEach(function (id) { + queue[id] = action; + }); + + if (this.controller) { + //this.requestReflow(); + this.requestRepaint(); + } +}; + +/** + * Calculate the scale and offset to convert a position on screen to the + * corresponding date and vice versa. + * After the method _updateConversion is executed once, the methods toTime + * and toScreen can be used. + * @private + */ +ItemSet.prototype._updateConversion = function _updateConversion() { + var range = this.range; + if (!range) { + throw new Error('No range configured'); + } + + if (range.conversion) { + this.conversion = range.conversion(this.width); + } + else { + this.conversion = Range.conversion(range.start, range.end, this.width); + } +}; + +/** + * Convert a position on screen (pixels) to a datetime + * Before this method can be used, the method _updateConversion must be + * executed once. + * @param {int} x Position on the screen in pixels + * @return {Date} time The datetime the corresponds with given position x + */ +ItemSet.prototype.toTime = function toTime(x) { + var conversion = this.conversion; + return new Date(x / conversion.scale + conversion.offset); +}; + +/** + * Convert a datetime (Date object) into a position on the screen + * Before this method can be used, the method _updateConversion must be + * executed once. + * @param {Date} time A date + * @return {int} x The position on the screen in pixels which corresponds + * with the given date. + */ +ItemSet.prototype.toScreen = function toScreen(time) { + var conversion = this.conversion; + return (time.valueOf() - conversion.offset) * conversion.scale; +}; + +/** + * @constructor Item + * @param {ItemSet} parent + * @param {Object} data Object containing (optional) parameters type, + * start, end, content, group, className. + * @param {Object} [options] Options to set initial property values + * @param {Object} [defaultOptions] default options + * // TODO: describe available options + */ +function Item (parent, data, options, defaultOptions) { + this.parent = parent; + this.data = data; + this.dom = null; + this.options = options || {}; + this.defaultOptions = defaultOptions || {}; + + this.selected = false; + this.visible = false; + this.top = 0; + this.left = 0; + this.width = 0; + this.height = 0; +} + +/** + * Select current item + */ +Item.prototype.select = function select() { + this.selected = true; +}; + +/** + * Unselect current item + */ +Item.prototype.unselect = function unselect() { + this.selected = false; +}; + +/** + * Show the Item in the DOM (when not already visible) + * @return {Boolean} changed + */ +Item.prototype.show = function show() { + return false; +}; + +/** + * Hide the Item from the DOM (when visible) + * @return {Boolean} changed + */ +Item.prototype.hide = function hide() { + return false; +}; + +/** + * Repaint the item + * @return {Boolean} changed + */ +Item.prototype.repaint = function repaint() { + // should be implemented by the item + return false; +}; + +/** + * Reflow the item + * @return {Boolean} resized + */ +Item.prototype.reflow = function reflow() { + // should be implemented by the item + return false; +}; + +/** + * Return the items width + * @return {Integer} width + */ +Item.prototype.getWidth = function getWidth() { + return this.width; +} + +/** + * @constructor ItemBox + * @extends Item + * @param {ItemSet} parent + * @param {Object} data Object containing parameters start + * content, className. + * @param {Object} [options] Options to set initial property values + * @param {Object} [defaultOptions] default options + * // TODO: describe available options + */ +function ItemBox (parent, data, options, defaultOptions) { + this.props = { + dot: { + left: 0, + top: 0, + width: 0, + height: 0 + }, + line: { + top: 0, + left: 0, + width: 0, + height: 0 + } + }; + + Item.call(this, parent, data, options, defaultOptions); +} + +ItemBox.prototype = new Item (null, null); + +/** + * Select the item + * @override + */ +ItemBox.prototype.select = function select() { + this.selected = true; + // TODO: select and unselect +}; + +/** + * Unselect the item + * @override + */ +ItemBox.prototype.unselect = function unselect() { + this.selected = false; + // TODO: select and unselect +}; + +/** + * Repaint the item + * @return {Boolean} changed + */ +ItemBox.prototype.repaint = function repaint() { + // TODO: make an efficient repaint + var changed = false; + var dom = this.dom; + + if (!dom) { + this._create(); + dom = this.dom; + changed = true; + } + + if (dom) { + if (!this.parent) { + throw new Error('Cannot repaint item: no parent attached'); + } + + if (!dom.box.parentNode) { + var foreground = this.parent.getForeground(); + if (!foreground) { + throw new Error('Cannot repaint time axis: ' + + 'parent has no foreground container element'); + } + foreground.appendChild(dom.box); + changed = true; + } + + if (!dom.line.parentNode) { + var background = this.parent.getBackground(); + if (!background) { + throw new Error('Cannot repaint time axis: ' + + 'parent has no background container element'); + } + background.appendChild(dom.line); + changed = true; + } + + if (!dom.dot.parentNode) { + var axis = this.parent.getAxis(); + if (!background) { + throw new Error('Cannot repaint time axis: ' + + 'parent has no axis container element'); + } + axis.appendChild(dom.dot); + changed = true; + } + + // update contents + if (this.data.content != this.content) { + this.content = this.data.content; + if (this.content instanceof Element) { + dom.content.innerHTML = ''; + dom.content.appendChild(this.content); + } + else if (this.data.content != undefined) { + dom.content.innerHTML = this.content; + } + else { + throw new Error('Property "content" missing in item ' + this.data.id); + } + changed = true; + } + + // update class + var className = (this.data.className? ' ' + this.data.className : '') + + (this.selected ? ' selected' : ''); + if (this.className != className) { + this.className = className; + dom.box.className = 'item box' + className; + dom.line.className = 'item line' + className; + dom.dot.className = 'item dot' + className; + changed = true; + } + } + + return changed; +}; + +/** + * Show the item in the DOM (when not already visible). The items DOM will + * be created when needed. + * @return {Boolean} changed + */ +ItemBox.prototype.show = function show() { + if (!this.dom || !this.dom.box.parentNode) { + return this.repaint(); + } + else { + return false; + } +}; + +/** + * Hide the item from the DOM (when visible) + * @return {Boolean} changed + */ +ItemBox.prototype.hide = function hide() { + var changed = false, + dom = this.dom; + if (dom) { + if (dom.box.parentNode) { + dom.box.parentNode.removeChild(dom.box); + changed = true; + } + if (dom.line.parentNode) { + dom.line.parentNode.removeChild(dom.line); + } + if (dom.dot.parentNode) { + dom.dot.parentNode.removeChild(dom.dot); + } + } + return changed; +}; + +/** + * Reflow the item: calculate its actual size and position from the DOM + * @return {boolean} resized returns true if the axis is resized + * @override + */ +ItemBox.prototype.reflow = function reflow() { + var changed = 0, + update, + dom, + props, + options, + margin, + start, + align, + orientation, + top, + left, + data, + range; + + if (this.data.start == undefined) { + throw new Error('Property "start" missing in item ' + this.data.id); + } + + data = this.data; + range = this.parent && this.parent.range; + if (data && range) { + // TODO: account for the width of the item + var interval = (range.end - range.start); + this.visible = (data.start > range.start - interval) && (data.start < range.end + interval); + } + else { + this.visible = false; + } + + if (this.visible) { + dom = this.dom; + if (dom) { + update = util.updateProperty; + props = this.props; + options = this.options; + start = this.parent.toScreen(this.data.start); + align = options.align || this.defaultOptions.align; + margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; + orientation = options.orientation || this.defaultOptions.orientation; + + changed += update(props.dot, 'height', dom.dot.offsetHeight); + changed += update(props.dot, 'width', dom.dot.offsetWidth); + changed += update(props.line, 'width', dom.line.offsetWidth); + changed += update(props.line, 'height', dom.line.offsetHeight); + changed += update(props.line, 'top', dom.line.offsetTop); + changed += update(this, 'width', dom.box.offsetWidth); + changed += update(this, 'height', dom.box.offsetHeight); + if (align == 'right') { + left = start - this.width; + } + else if (align == 'left') { + left = start; + } + else { + // default or 'center' + left = start - this.width / 2; + } + changed += update(this, 'left', left); + + changed += update(props.line, 'left', start - props.line.width / 2); + changed += update(props.dot, 'left', start - props.dot.width / 2); + changed += update(props.dot, 'top', -props.dot.height / 2); + if (orientation == 'top') { + top = margin; + + changed += update(this, 'top', top); + } + else { + // default or 'bottom' + var parentHeight = this.parent.height; + top = parentHeight - this.height - margin; + + changed += update(this, 'top', top); + } + } + else { + changed += 1; + } + } + + return (changed > 0); +}; + +/** + * Create an items DOM + * @private + */ +ItemBox.prototype._create = function _create() { + var dom = this.dom; + if (!dom) { + this.dom = dom = {}; + + // create the box + dom.box = document.createElement('DIV'); + // className is updated in repaint() + + // contents box (inside the background box). used for making margins + dom.content = document.createElement('DIV'); + dom.content.className = 'content'; + dom.box.appendChild(dom.content); + + // line to axis + dom.line = document.createElement('DIV'); + dom.line.className = 'line'; + + // dot on axis + dom.dot = document.createElement('DIV'); + dom.dot.className = 'dot'; + } +}; + +/** + * Reposition the item, recalculate its left, top, and width, using the current + * range and size of the items itemset + * @override + */ +ItemBox.prototype.reposition = function reposition() { + var dom = this.dom, + props = this.props, + orientation = this.options.orientation || this.defaultOptions.orientation; + + if (dom) { + var box = dom.box, + line = dom.line, + dot = dom.dot; + + box.style.left = this.left + 'px'; + box.style.top = this.top + 'px'; + + line.style.left = props.line.left + 'px'; + if (orientation == 'top') { + line.style.top = 0 + 'px'; + line.style.height = this.top + 'px'; + } + else { + // orientation 'bottom' + line.style.top = (this.top + this.height) + 'px'; + line.style.height = Math.max(this.parent.height - this.top - this.height + + this.props.dot.height / 2, 0) + 'px'; + } + + dot.style.left = props.dot.left + 'px'; + dot.style.top = props.dot.top + 'px'; + } +}; + +/** + * @constructor ItemPoint + * @extends Item + * @param {ItemSet} parent + * @param {Object} data Object containing parameters start + * content, className. + * @param {Object} [options] Options to set initial property values + * @param {Object} [defaultOptions] default options + * // TODO: describe available options + */ +function ItemPoint (parent, data, options, defaultOptions) { + this.props = { + dot: { + top: 0, + width: 0, + height: 0 + }, + content: { + height: 0, + marginLeft: 0 + } + }; + + Item.call(this, parent, data, options, defaultOptions); +} + +ItemPoint.prototype = new Item (null, null); + +/** + * Select the item + * @override + */ +ItemPoint.prototype.select = function select() { + this.selected = true; + // TODO: select and unselect +}; + +/** + * Unselect the item + * @override + */ +ItemPoint.prototype.unselect = function unselect() { + this.selected = false; + // TODO: select and unselect +}; + +/** + * Repaint the item + * @return {Boolean} changed + */ +ItemPoint.prototype.repaint = function repaint() { + // TODO: make an efficient repaint + var changed = false; + var dom = this.dom; + + if (!dom) { + this._create(); + dom = this.dom; + changed = true; + } + + if (dom) { + if (!this.parent) { + throw new Error('Cannot repaint item: no parent attached'); + } + var foreground = this.parent.getForeground(); + if (!foreground) { + throw new Error('Cannot repaint time axis: ' + + 'parent has no foreground container element'); + } + + if (!dom.point.parentNode) { + foreground.appendChild(dom.point); + foreground.appendChild(dom.point); + changed = true; + } + + // update contents + if (this.data.content != this.content) { + this.content = this.data.content; + if (this.content instanceof Element) { + dom.content.innerHTML = ''; + dom.content.appendChild(this.content); + } + else if (this.data.content != undefined) { + dom.content.innerHTML = this.content; + } + else { + throw new Error('Property "content" missing in item ' + this.data.id); + } + changed = true; + } + + // update class + var className = (this.data.className? ' ' + this.data.className : '') + + (this.selected ? ' selected' : ''); + if (this.className != className) { + this.className = className; + dom.point.className = 'item point' + className; + changed = true; + } + } + + return changed; +}; + +/** + * Show the item in the DOM (when not already visible). The items DOM will + * be created when needed. + * @return {Boolean} changed + */ +ItemPoint.prototype.show = function show() { + if (!this.dom || !this.dom.point.parentNode) { + return this.repaint(); + } + else { + return false; + } +}; + +/** + * Hide the item from the DOM (when visible) + * @return {Boolean} changed + */ +ItemPoint.prototype.hide = function hide() { + var changed = false, + dom = this.dom; + if (dom) { + if (dom.point.parentNode) { + dom.point.parentNode.removeChild(dom.point); + changed = true; + } + } + return changed; +}; + +/** + * Reflow the item: calculate its actual size from the DOM + * @return {boolean} resized returns true if the axis is resized + * @override + */ +ItemPoint.prototype.reflow = function reflow() { + var changed = 0, + update, + dom, + props, + options, + margin, + orientation, + start, + top, + data, + range; + + if (this.data.start == undefined) { + throw new Error('Property "start" missing in item ' + this.data.id); + } + + data = this.data; + range = this.parent && this.parent.range; + if (data && range) { + // TODO: account for the width of the item + var interval = (range.end - range.start); + this.visible = (data.start > range.start - interval) && (data.start < range.end); + } + else { + this.visible = false; + } + + if (this.visible) { + dom = this.dom; + if (dom) { + update = util.updateProperty; + props = this.props; + options = this.options; + orientation = options.orientation || this.defaultOptions.orientation; + margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; + start = this.parent.toScreen(this.data.start); + + changed += update(this, 'width', dom.point.offsetWidth); + changed += update(this, 'height', dom.point.offsetHeight); + changed += update(props.dot, 'width', dom.dot.offsetWidth); + changed += update(props.dot, 'height', dom.dot.offsetHeight); + changed += update(props.content, 'height', dom.content.offsetHeight); + + if (orientation == 'top') { + top = margin; + } + else { + // default or 'bottom' + var parentHeight = this.parent.height; + top = Math.max(parentHeight - this.height - margin, 0); + } + changed += update(this, 'top', top); + changed += update(this, 'left', start - props.dot.width / 2); + changed += update(props.content, 'marginLeft', 1.5 * props.dot.width); + //changed += update(props.content, 'marginRight', 0.5 * props.dot.width); // TODO + + changed += update(props.dot, 'top', (this.height - props.dot.height) / 2); + } + else { + changed += 1; + } + } + + return (changed > 0); +}; + +/** + * Create an items DOM + * @private + */ +ItemPoint.prototype._create = function _create() { + var dom = this.dom; + if (!dom) { + this.dom = dom = {}; + + // background box + dom.point = document.createElement('div'); + // className is updated in repaint() + + // contents box, right from the dot + dom.content = document.createElement('div'); + dom.content.className = 'content'; + dom.point.appendChild(dom.content); + + // dot at start + dom.dot = document.createElement('div'); + dom.dot.className = 'dot'; + dom.point.appendChild(dom.dot); + } +}; + +/** + * Reposition the item, recalculate its left, top, and width, using the current + * range and size of the items itemset + * @override + */ +ItemPoint.prototype.reposition = function reposition() { + var dom = this.dom, + props = this.props; + + if (dom) { + dom.point.style.top = this.top + 'px'; + dom.point.style.left = this.left + 'px'; + + dom.content.style.marginLeft = props.content.marginLeft + 'px'; + //dom.content.style.marginRight = props.content.marginRight + 'px'; // TODO + + dom.dot.style.top = props.dot.top + 'px'; + } +}; + +/** + * @constructor ItemRange + * @extends Item + * @param {ItemSet} parent + * @param {Object} data Object containing parameters start, end + * content, className. + * @param {Object} [options] Options to set initial property values + * @param {Object} [defaultOptions] default options + * // TODO: describe available options + */ +function ItemRange (parent, data, options, defaultOptions) { + this.props = { + content: { + left: 0, + width: 0 + } + }; + + Item.call(this, parent, data, options, defaultOptions); +} + +ItemRange.prototype = new Item (null, null); + +/** + * Select the item + * @override + */ +ItemRange.prototype.select = function select() { + this.selected = true; + // TODO: select and unselect +}; + +/** + * Unselect the item + * @override + */ +ItemRange.prototype.unselect = function unselect() { + this.selected = false; + // TODO: select and unselect +}; + +/** + * Repaint the item + * @return {Boolean} changed + */ +ItemRange.prototype.repaint = function repaint() { + // TODO: make an efficient repaint + var changed = false; + var dom = this.dom; + + if (!dom) { + this._create(); + dom = this.dom; + changed = true; + } + + if (dom) { + if (!this.parent) { + throw new Error('Cannot repaint item: no parent attached'); + } + var foreground = this.parent.getForeground(); + if (!foreground) { + throw new Error('Cannot repaint time axis: ' + + 'parent has no foreground container element'); + } + + if (!dom.box.parentNode) { + foreground.appendChild(dom.box); + changed = true; + } + + // update content + if (this.data.content != this.content) { + this.content = this.data.content; + if (this.content instanceof Element) { + dom.content.innerHTML = ''; + dom.content.appendChild(this.content); + } + else if (this.data.content != undefined) { + dom.content.innerHTML = this.content; + } + else { + throw new Error('Property "content" missing in item ' + this.data.id); + } + changed = true; + } + + // update class + var className = this.data.className ? (' ' + this.data.className) : ''; + if (this.className != className) { + this.className = className; + dom.box.className = 'item range' + className; + changed = true; + } + } + + return changed; +}; + +/** + * Show the item in the DOM (when not already visible). The items DOM will + * be created when needed. + * @return {Boolean} changed + */ +ItemRange.prototype.show = function show() { + if (!this.dom || !this.dom.box.parentNode) { + return this.repaint(); + } + else { + return false; + } +}; + +/** + * Hide the item from the DOM (when visible) + * @return {Boolean} changed + */ +ItemRange.prototype.hide = function hide() { + var changed = false, + dom = this.dom; + if (dom) { + if (dom.box.parentNode) { + dom.box.parentNode.removeChild(dom.box); + changed = true; + } + } + return changed; +}; + +/** + * Reflow the item: calculate its actual size from the DOM + * @return {boolean} resized returns true if the axis is resized + * @override + */ +ItemRange.prototype.reflow = function reflow() { + var changed = 0, + dom, + props, + options, + margin, + padding, + parent, + start, + end, + data, + range, + update, + box, + parentWidth, + contentLeft, + orientation, + top; + + if (this.data.start == undefined) { + throw new Error('Property "start" missing in item ' + this.data.id); + } + if (this.data.end == undefined) { + throw new Error('Property "end" missing in item ' + this.data.id); + } + + data = this.data; + range = this.parent && this.parent.range; + if (data && range) { + // TODO: account for the width of the item. Take some margin + this.visible = (data.start < range.end) && (data.end > range.start); + } + else { + this.visible = false; + } + + if (this.visible) { + dom = this.dom; + if (dom) { + props = this.props; + options = this.options; + parent = this.parent; + start = parent.toScreen(this.data.start); + end = parent.toScreen(this.data.end); + update = util.updateProperty; + box = dom.box; + parentWidth = parent.width; + orientation = options.orientation || this.defaultOptions.orientation; + margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; + padding = options.padding || this.defaultOptions.padding; + + changed += update(props.content, 'width', dom.content.offsetWidth); + + changed += update(this, 'height', box.offsetHeight); + + // limit the width of the this, as browsers cannot draw very wide divs + if (start < -parentWidth) { + start = -parentWidth; + } + if (end > 2 * parentWidth) { + end = 2 * parentWidth; + } + + // when range exceeds left of the window, position the contents at the left of the visible area + if (start < 0) { + contentLeft = Math.min(-start, + (end - start - props.content.width - 2 * padding)); + // TODO: remove the need for options.padding. it's terrible. + } + else { + contentLeft = 0; + } + changed += update(props.content, 'left', contentLeft); + + if (orientation == 'top') { + top = margin; + changed += update(this, 'top', top); + } + else { + // default or 'bottom' + top = parent.height - this.height - margin; + changed += update(this, 'top', top); + } + + changed += update(this, 'left', start); + changed += update(this, 'width', Math.max(end - start, 1)); // TODO: reckon with border width; + } + else { + changed += 1; + } + } + + return (changed > 0); +}; + +/** + * Create an items DOM + * @private + */ +ItemRange.prototype._create = function _create() { + var dom = this.dom; + if (!dom) { + this.dom = dom = {}; + // background box + dom.box = document.createElement('div'); + // className is updated in repaint() + + // contents box + dom.content = document.createElement('div'); + dom.content.className = 'content'; + dom.box.appendChild(dom.content); + } +}; + +/** + * Reposition the item, recalculate its left, top, and width, using the current + * range and size of the items itemset + * @override + */ +ItemRange.prototype.reposition = function reposition() { + var dom = this.dom, + props = this.props; + + if (dom) { + dom.box.style.top = this.top + 'px'; + dom.box.style.left = this.left + 'px'; + dom.box.style.width = this.width + 'px'; + + dom.content.style.left = props.content.left + 'px'; + } +}; + +/** + * @constructor ItemRangeOverflow + * @extends ItemRange + * @param {ItemSet} parent + * @param {Object} data Object containing parameters start, end + * content, className. + * @param {Object} [options] Options to set initial property values + * @param {Object} [defaultOptions] default options + * // TODO: describe available options + */ +function ItemRangeOverflow (parent, data, options, defaultOptions) { + this.props = { + content: { + left: 0, + width: 0 + } + }; + + ItemRange.call(this, parent, data, options, defaultOptions); +} + +ItemRangeOverflow.prototype = new ItemRange (null, null); + +/** + * Repaint the item + * @return {Boolean} changed + */ +ItemRangeOverflow.prototype.repaint = function repaint() { + // TODO: make an efficient repaint + var changed = false; + var dom = this.dom; + + if (!dom) { + this._create(); + dom = this.dom; + changed = true; + } + + if (dom) { + if (!this.parent) { + throw new Error('Cannot repaint item: no parent attached'); + } + var foreground = this.parent.getForeground(); + if (!foreground) { + throw new Error('Cannot repaint time axis: ' + + 'parent has no foreground container element'); + } + + if (!dom.box.parentNode) { + foreground.appendChild(dom.box); + changed = true; + } + + // update content + if (this.data.content != this.content) { + this.content = this.data.content; + if (this.content instanceof Element) { + dom.content.innerHTML = ''; + dom.content.appendChild(this.content); + } + else if (this.data.content != undefined) { + dom.content.innerHTML = this.content; + } + else { + throw new Error('Property "content" missing in item ' + this.data.id); + } + changed = true; + } + + // update class + var className = this.data.className ? (' ' + this.data.className) : ''; + if (this.className != className) { + this.className = className; + dom.box.className = 'item rangeoverflow' + className; + changed = true; + } + } + + return changed; +}; + +/** + * Return the items width + * @return {Number} width + */ +ItemRangeOverflow.prototype.getWidth = function getWidth() { + if (this.props.content !== undefined && this.width < this.props.content.width) + return this.props.content.width; + else + return this.width; +}; + +/** + * @constructor Group + * @param {GroupSet} parent + * @param {Number | String} groupId + * @param {Object} [options] Options to set initial property values + * // TODO: describe available options + * @extends Component + */ +function Group (parent, groupId, options) { + this.id = util.randomUUID(); + this.parent = parent; + + this.groupId = groupId; + this.itemset = null; // ItemSet + this.options = options || {}; + this.options.top = 0; + + this.props = { + label: { + width: 0, + height: 0 + } + }; + + this.top = 0; + this.left = 0; + this.width = 0; + this.height = 0; +} + +Group.prototype = new Component(); + +// TODO: comment +Group.prototype.setOptions = Component.prototype.setOptions; + +/** + * Get the container element of the panel, which can be used by a child to + * add its own widgets. + * @returns {HTMLElement} container + */ +Group.prototype.getContainer = function () { + return this.parent.getContainer(); +}; + +/** + * Set item set for the group. The group will create a view on the itemset, + * filtered by the groups id. + * @param {DataSet | DataView} items + */ +Group.prototype.setItems = function setItems(items) { + if (this.itemset) { + // remove current item set + this.itemset.hide(); + this.itemset.setItems(); + + this.parent.controller.remove(this.itemset); + this.itemset = null; + } + + if (items) { + var groupId = this.groupId; + + var itemsetOptions = Object.create(this.options); + this.itemset = new ItemSet(this, null, itemsetOptions); + this.itemset.setRange(this.parent.range); + + this.view = new DataView(items, { + filter: function (item) { + return item.group == groupId; + } + }); + this.itemset.setItems(this.view); + + this.parent.controller.add(this.itemset); + } +}; + +/** + * Repaint the item + * @return {Boolean} changed + */ +Group.prototype.repaint = function repaint() { + return false; +}; + +/** + * Reflow the item + * @return {Boolean} resized + */ +Group.prototype.reflow = function reflow() { + var changed = 0, + update = util.updateProperty; + + changed += update(this, 'top', this.itemset ? this.itemset.top : 0); + changed += update(this, 'height', this.itemset ? this.itemset.height : 0); + + // TODO: reckon with the height of the group label + + if (this.label) { + var inner = this.label.firstChild; + changed += update(this.props.label, 'width', inner.clientWidth); + changed += update(this.props.label, 'height', inner.clientHeight); + } + else { + changed += update(this.props.label, 'width', 0); + changed += update(this.props.label, 'height', 0); + } + + return (changed > 0); +}; + +/** + * An GroupSet holds a set of groups + * @param {Component} parent + * @param {Component[]} [depends] Components on which this components depends + * (except for the parent) + * @param {Object} [options] See GroupSet.setOptions for the available + * options. + * @constructor GroupSet + * @extends Panel + */ +function GroupSet(parent, depends, options) { + this.id = util.randomUUID(); + this.parent = parent; + this.depends = depends; + + this.options = options || {}; + + this.range = null; // Range or Object {start: number, end: number} + this.itemsData = null; // DataSet with items + this.groupsData = null; // DataSet with groups + + this.groups = {}; // map with groups + + this.dom = {}; + this.props = { + labels: { + width: 0 + } + }; + + // TODO: implement right orientation of the labels + + // changes in groups are queued key/value map containing id/action + this.queue = {}; + + var me = this; + this.listeners = { + 'add': function (event, params) { + me._onAdd(params.items); + }, + 'update': function (event, params) { + me._onUpdate(params.items); + }, + 'remove': function (event, params) { + me._onRemove(params.items); + } + }; +} + +GroupSet.prototype = new Panel(); + +/** + * Set options for the GroupSet. Existing options will be extended/overwritten. + * @param {Object} [options] The following options are available: + * {String | function} groupsOrder + * TODO: describe options + */ +GroupSet.prototype.setOptions = Component.prototype.setOptions; + +GroupSet.prototype.setRange = function (range) { + // TODO: implement setRange +}; + +/** + * Set items + * @param {vis.DataSet | null} items + */ +GroupSet.prototype.setItems = function setItems(items) { + this.itemsData = items; + + for (var id in this.groups) { + if (this.groups.hasOwnProperty(id)) { + var group = this.groups[id]; + group.setItems(items); + } + } +}; + +/** + * Get items + * @return {vis.DataSet | null} items + */ +GroupSet.prototype.getItems = function getItems() { + return this.itemsData; +}; + +/** + * Set range (start and end). + * @param {Range | Object} range A Range or an object containing start and end. + */ +GroupSet.prototype.setRange = function setRange(range) { + this.range = range; +}; + +/** + * Set groups + * @param {vis.DataSet} groups + */ +GroupSet.prototype.setGroups = function setGroups(groups) { + var me = this, + ids; + + // unsubscribe from current dataset + if (this.groupsData) { + util.forEach(this.listeners, function (callback, event) { + me.groupsData.unsubscribe(event, callback); + }); + + // remove all drawn groups + ids = this.groupsData.getIds(); + this._onRemove(ids); + } + + // replace the dataset + if (!groups) { + this.groupsData = null; + } + else if (groups instanceof DataSet) { + this.groupsData = groups; + } + else { + this.groupsData = new DataSet({ + convert: { + start: 'Date', + end: 'Date' + } + }); + this.groupsData.add(groups); + } + + if (this.groupsData) { + // subscribe to new dataset + var id = this.id; + util.forEach(this.listeners, function (callback, event) { + me.groupsData.subscribe(event, callback, id); + }); + + // draw all new groups + ids = this.groupsData.getIds(); + this._onAdd(ids); + } +}; + +/** + * Get groups + * @return {vis.DataSet | null} groups + */ +GroupSet.prototype.getGroups = function getGroups() { + return this.groupsData; +}; + +/** + * Repaint the component + * @return {Boolean} changed + */ +GroupSet.prototype.repaint = function repaint() { + var changed = 0, + i, id, group, label, + update = util.updateProperty, + asSize = util.option.asSize, + asElement = util.option.asElement, + options = this.options, + frame = this.dom.frame, + labels = this.dom.labels, + labelSet = this.dom.labelSet; + + // create frame + if (!this.parent) { + throw new Error('Cannot repaint groupset: no parent attached'); + } + var parentContainer = this.parent.getContainer(); + if (!parentContainer) { + throw new Error('Cannot repaint groupset: parent has no container element'); + } + if (!frame) { + frame = document.createElement('div'); + frame.className = 'groupset'; + this.dom.frame = frame; + + var className = options.className; + if (className) { + util.addClassName(frame, util.option.asString(className)); + } + + changed += 1; + } + if (!frame.parentNode) { + parentContainer.appendChild(frame); + changed += 1; + } + + // create labels + var labelContainer = asElement(options.labelContainer); + if (!labelContainer) { + throw new Error('Cannot repaint groupset: option "labelContainer" not defined'); + } + if (!labels) { + labels = document.createElement('div'); + labels.className = 'labels'; + this.dom.labels = labels; + } + if (!labelSet) { + labelSet = document.createElement('div'); + labelSet.className = 'label-set'; + labels.appendChild(labelSet); + this.dom.labelSet = labelSet; + } + if (!labels.parentNode || labels.parentNode != labelContainer) { + if (labels.parentNode) { + labels.parentNode.removeChild(labels.parentNode); + } + labelContainer.appendChild(labels); + } + + // reposition frame + changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); + changed += update(frame.style, 'top', asSize(options.top, '0px')); + changed += update(frame.style, 'left', asSize(options.left, '0px')); + changed += update(frame.style, 'width', asSize(options.width, '100%')); + + // reposition labels + changed += update(labelSet.style, 'top', asSize(options.top, '0px')); + changed += update(labelSet.style, 'height', asSize(options.height, this.height + 'px')); + + var me = this, + queue = this.queue, + groups = this.groups, + groupsData = this.groupsData; + + // show/hide added/changed/removed groups + var ids = Object.keys(queue); + if (ids.length) { + ids.forEach(function (id) { + var action = queue[id]; + var group = groups[id]; + + //noinspection FallthroughInSwitchStatementJS + switch (action) { + case 'add': + case 'update': + if (!group) { + var groupOptions = Object.create(me.options); + util.extend(groupOptions, { + height: null, + maxHeight: null + }); + + group = new Group(me, id, groupOptions); + group.setItems(me.itemsData); // attach items data + groups[id] = group; + + me.controller.add(group); + } + + // TODO: update group data + group.data = groupsData.get(id); + + delete queue[id]; + break; + + case 'remove': + if (group) { + group.setItems(); // detach items data + delete groups[id]; + + me.controller.remove(group); + } + + // update lists + delete queue[id]; + break; + + default: + console.log('Error: unknown action "' + action + '"'); + } + }); + + // the groupset depends on each of the groups + //this.depends = this.groups; // TODO: gives a circular reference through the parent + + // TODO: apply dependencies of the groupset + + // update the top positions of the groups in the correct order + var orderedGroups = this.groupsData.getIds({ + order: this.options.groupOrder + }); + for (i = 0; i < orderedGroups.length; i++) { + (function (group, prevGroup) { + var top = 0; + if (prevGroup) { + top = function () { + // TODO: top must reckon with options.maxHeight + return prevGroup.top + prevGroup.height; + } + } + group.setOptions({ + top: top + }); + })(groups[orderedGroups[i]], groups[orderedGroups[i - 1]]); + } + + // (re)create the labels + while (labelSet.firstChild) { + labelSet.removeChild(labelSet.firstChild); + } + for (i = 0; i < orderedGroups.length; i++) { + id = orderedGroups[i]; + label = this._createLabel(id); + labelSet.appendChild(label); + } + + changed++; + } + + // reposition the labels + // TODO: labels are not displayed correctly when orientation=='top' + // TODO: width of labelPanel is not immediately updated on a change in groups + for (id in groups) { + if (groups.hasOwnProperty(id)) { + group = groups[id]; + label = group.label; + if (label) { + label.style.top = group.top + 'px'; + label.style.height = group.height + 'px'; + } + } + } + + return (changed > 0); +}; + +/** + * Create a label for group with given id + * @param {Number} id + * @return {Element} label + * @private + */ +GroupSet.prototype._createLabel = function(id) { + var group = this.groups[id]; + var label = document.createElement('div'); + label.className = 'label'; + var inner = document.createElement('div'); + inner.className = 'inner'; + label.appendChild(inner); + + var content = group.data && group.data.content; + if (content instanceof Element) { + inner.appendChild(content); + } + else if (content != undefined) { + inner.innerHTML = content; + } + + var className = group.data && group.data.className; + if (className) { + util.addClassName(label, className); + } + + group.label = label; // TODO: not so nice, parking labels in the group this way!!! + + return label; +}; + +/** + * Get container element + * @return {HTMLElement} container + */ +GroupSet.prototype.getContainer = function getContainer() { + return this.dom.frame; +}; + +/** + * Get the width of the group labels + * @return {Number} width + */ +GroupSet.prototype.getLabelsWidth = function getContainer() { + return this.props.labels.width; +}; + +/** + * Reflow the component + * @return {Boolean} resized + */ +GroupSet.prototype.reflow = function reflow() { + var changed = 0, + id, group, + options = this.options, + update = util.updateProperty, + asNumber = util.option.asNumber, + asSize = util.option.asSize, + frame = this.dom.frame; + + if (frame) { + var maxHeight = asNumber(options.maxHeight); + var fixedHeight = (asSize(options.height) != null); + var height; + if (fixedHeight) { + height = frame.offsetHeight; + } + else { + // height is not specified, calculate the sum of the height of all groups + height = 0; + + for (id in this.groups) { + if (this.groups.hasOwnProperty(id)) { + group = this.groups[id]; + height += group.height; + } + } + } + if (maxHeight != null) { + height = Math.min(height, maxHeight); + } + changed += update(this, 'height', height); + + changed += update(this, 'top', frame.offsetTop); + changed += update(this, 'left', frame.offsetLeft); + changed += update(this, 'width', frame.offsetWidth); + } + + // calculate the maximum width of the labels + var width = 0; + for (id in this.groups) { + if (this.groups.hasOwnProperty(id)) { + group = this.groups[id]; + var labelWidth = group.props && group.props.label && group.props.label.width || 0; + width = Math.max(width, labelWidth); + } + } + changed += update(this.props.labels, 'width', width); + + return (changed > 0); +}; + +/** + * Hide the component from the DOM + * @return {Boolean} changed + */ +GroupSet.prototype.hide = function hide() { + if (this.dom.frame && this.dom.frame.parentNode) { + this.dom.frame.parentNode.removeChild(this.dom.frame); + return true; + } + else { + return false; + } +}; + +/** + * Show the component in the DOM (when not already visible). + * A repaint will be executed when the component is not visible + * @return {Boolean} changed + */ +GroupSet.prototype.show = function show() { + if (!this.dom.frame || !this.dom.frame.parentNode) { + return this.repaint(); + } + else { + return false; + } +}; + +/** + * Handle updated groups + * @param {Number[]} ids + * @private + */ +GroupSet.prototype._onUpdate = function _onUpdate(ids) { + this._toQueue(ids, 'update'); +}; + +/** + * Handle changed groups + * @param {Number[]} ids + * @private + */ +GroupSet.prototype._onAdd = function _onAdd(ids) { + this._toQueue(ids, 'add'); +}; + +/** + * Handle removed groups + * @param {Number[]} ids + * @private + */ +GroupSet.prototype._onRemove = function _onRemove(ids) { + this._toQueue(ids, 'remove'); +}; + +/** + * Put groups in the queue to be added/updated/remove + * @param {Number[]} ids + * @param {String} action can be 'add', 'update', 'remove' + */ +GroupSet.prototype._toQueue = function _toQueue(ids, action) { + var queue = this.queue; + ids.forEach(function (id) { + queue[id] = action; + }); + + if (this.controller) { + //this.requestReflow(); + this.requestRepaint(); + } +}; + +/** + * Create a timeline visualization + * @param {HTMLElement} container + * @param {vis.DataSet | Array | DataTable} [items] + * @param {Object} [options] See Timeline.setOptions for the available options. + * @constructor + */ +function Timeline (container, items, options) { + var me = this; + var now = moment().hours(0).minutes(0).seconds(0).milliseconds(0); + this.options = { + orientation: 'bottom', + min: null, + max: null, + zoomMin: 10, // milliseconds + zoomMax: 1000 * 60 * 60 * 24 * 365 * 10000, // milliseconds + // moveable: true, // TODO: option moveable + // zoomable: true, // TODO: option zoomable + showMinorLabels: true, + showMajorLabels: true, + showCurrentTime: false, + showCustomTime: false, + autoResize: false + }; + + // controller + this.controller = new Controller(); + + // root panel + if (!container) { + throw new Error('No container element provided'); + } + var rootOptions = Object.create(this.options); + rootOptions.height = function () { + // TODO: change to height + if (me.options.height) { + // fixed height + return me.options.height; + } + else { + // auto height + return (me.timeaxis.height + me.content.height) + 'px'; + } + }; + this.rootPanel = new RootPanel(container, rootOptions); + this.controller.add(this.rootPanel); + + // item panel + var itemOptions = Object.create(this.options); + itemOptions.left = function () { + return me.labelPanel.width; + }; + itemOptions.width = function () { + return me.rootPanel.width - me.labelPanel.width; + }; + itemOptions.top = null; + itemOptions.height = null; + this.itemPanel = new Panel(this.rootPanel, [], itemOptions); + this.controller.add(this.itemPanel); + + // label panel + var labelOptions = Object.create(this.options); + labelOptions.top = null; + labelOptions.left = null; + labelOptions.height = null; + labelOptions.width = function () { + if (me.content && typeof me.content.getLabelsWidth === 'function') { + return me.content.getLabelsWidth(); + } + else { + return 0; + } + }; + this.labelPanel = new Panel(this.rootPanel, [], labelOptions); + this.controller.add(this.labelPanel); + + // range + var rangeOptions = Object.create(this.options); + this.range = new Range(rangeOptions); + this.range.setRange( + now.clone().add('days', -3).valueOf(), + now.clone().add('days', 4).valueOf() + ); + + // TODO: reckon with options moveable and zoomable + this.range.subscribe(this.rootPanel, 'move', 'horizontal'); + this.range.subscribe(this.rootPanel, 'zoom', 'horizontal'); + this.range.on('rangechange', function () { + var force = true; + me.controller.requestReflow(force); + }); + this.range.on('rangechanged', function () { + var force = true; + me.controller.requestReflow(force); + }); + + // TODO: put the listeners in setOptions, be able to dynamically change with options moveable and zoomable + + // time axis + var timeaxisOptions = Object.create(rootOptions); + timeaxisOptions.range = this.range; + timeaxisOptions.left = null; + timeaxisOptions.top = null; + timeaxisOptions.width = '100%'; + timeaxisOptions.height = null; + this.timeaxis = new TimeAxis(this.itemPanel, [], timeaxisOptions); + this.timeaxis.setRange(this.range); + this.controller.add(this.timeaxis); + + // current time bar + this.currenttime = new CurrentTime(this.timeaxis, [], rootOptions); + this.controller.add(this.currenttime); + + // custom time bar + this.customtime = new CustomTime(this.timeaxis, [], rootOptions); + this.controller.add(this.customtime); + + // create groupset + this.setGroups(null); + + this.itemsData = null; // DataSet + this.groupsData = null; // DataSet + + // apply options + if (options) { + this.setOptions(options); + } + + // create itemset and groupset + if (items) { + this.setItems(items); + } +} + +/** + * Set options + * @param {Object} options TODO: describe the available options + */ +Timeline.prototype.setOptions = function (options) { + util.extend(this.options, options); + + // force update of range + // options.start and options.end can be undefined + //this.range.setRange(options.start, options.end); + this.range.setRange(); + + this.controller.reflow(); + this.controller.repaint(); +}; + +/** + * Set a custom time bar + * @param {Date} time + */ +Timeline.prototype.setCustomTime = function (time) { + this.customtime._setCustomTime(time); +}; + +/** + * Retrieve the current custom time. + * @return {Date} customTime + */ +Timeline.prototype.getCustomTime = function() { + return new Date(this.customtime.customTime.valueOf()); +}; + +/** + * Set items + * @param {vis.DataSet | Array | DataTable | null} items + */ +Timeline.prototype.setItems = function(items) { + var initialLoad = (this.itemsData == null); + + // convert to type DataSet when needed + var newItemSet; + if (!items) { + newItemSet = null; + } + else if (items instanceof DataSet) { + newItemSet = items; + } + if (!(items instanceof DataSet)) { + newItemSet = new DataSet({ + convert: { + start: 'Date', + end: 'Date' + } + }); + newItemSet.add(items); + } + + // set items + this.itemsData = newItemSet; + this.content.setItems(newItemSet); + + if (initialLoad && (this.options.start == undefined || this.options.end == undefined)) { + // apply the data range as range + var dataRange = this.getItemRange(); + + // add 5% space on both sides + var min = dataRange.min; + var max = dataRange.max; + if (min != null && max != null) { + var interval = (max.valueOf() - min.valueOf()); + if (interval <= 0) { + // prevent an empty interval + interval = 24 * 60 * 60 * 1000; // 1 day + } + min = new Date(min.valueOf() - interval * 0.05); + max = new Date(max.valueOf() + interval * 0.05); + } + + // override specified start and/or end date + if (this.options.start != undefined) { + min = util.convert(this.options.start, 'Date'); + } + if (this.options.end != undefined) { + max = util.convert(this.options.end, 'Date'); + } + + // apply range if there is a min or max available + if (min != null || max != null) { + this.range.setRange(min, max); + } + } +}; + +/** + * Set groups + * @param {vis.DataSet | Array | DataTable} groups + */ +Timeline.prototype.setGroups = function(groups) { + var me = this; + this.groupsData = groups; + + // switch content type between ItemSet or GroupSet when needed + var Type = this.groupsData ? GroupSet : ItemSet; + if (!(this.content instanceof Type)) { + // remove old content set + if (this.content) { + this.content.hide(); + if (this.content.setItems) { + this.content.setItems(); // disconnect from items + } + if (this.content.setGroups) { + this.content.setGroups(); // disconnect from groups + } + this.controller.remove(this.content); + } + + // create new content set + var options = Object.create(this.options); + util.extend(options, { + top: function () { + if (me.options.orientation == 'top') { + return me.timeaxis.height; + } + else { + return me.itemPanel.height - me.timeaxis.height - me.content.height; + } + }, + left: null, + width: '100%', + height: function () { + if (me.options.height) { + // fixed height + return me.itemPanel.height - me.timeaxis.height; + } + else { + // auto height + return null; + } + }, + maxHeight: function () { + // TODO: change maxHeight to be a css string like '100%' or '300px' + if (me.options.maxHeight) { + if (!util.isNumber(me.options.maxHeight)) { + throw new TypeError('Number expected for property maxHeight'); + } + return me.options.maxHeight - me.timeaxis.height; + } + else { + return null; + } + }, + labelContainer: function () { + return me.labelPanel.getContainer(); + } + }); + + this.content = new Type(this.itemPanel, [this.timeaxis], options); + if (this.content.setRange) { + this.content.setRange(this.range); + } + if (this.content.setItems) { + this.content.setItems(this.itemsData); + } + if (this.content.setGroups) { + this.content.setGroups(this.groupsData); + } + this.controller.add(this.content); + } +}; + +/** + * Get the data range of the item set. + * @returns {{min: Date, max: Date}} range A range with a start and end Date. + * When no minimum is found, min==null + * When no maximum is found, max==null + */ +Timeline.prototype.getItemRange = function getItemRange() { + // calculate min from start filed + var itemsData = this.itemsData, + min = null, + max = null; + + if (itemsData) { + // calculate the minimum value of the field 'start' + var minItem = itemsData.min('start'); + min = minItem ? minItem.start.valueOf() : null; + + // calculate maximum value of fields 'start' and 'end' + var maxStartItem = itemsData.max('start'); + if (maxStartItem) { + max = maxStartItem.start.valueOf(); + } + var maxEndItem = itemsData.max('end'); + if (maxEndItem) { + if (max == null) { + max = maxEndItem.end.valueOf(); + } + else { + max = Math.max(max, maxEndItem.end.valueOf()); + } + } + } + + return { + min: (min != null) ? new Date(min) : null, + max: (max != null) ? new Date(max) : null + }; +}; + +(function(exports) { + /** + * Parse a text source containing data in DOT language into a JSON object. + * The object contains two lists: one with nodes and one with edges. + * + * DOT language reference: http://www.graphviz.org/doc/info/lang.html + * + * @param {String} data Text containing a graph in DOT-notation + * @return {Object} graph An object containing two parameters: + * {Object[]} nodes + * {Object[]} edges + */ + function parseDOT (data) { + dot = data; + return parseGraph(); + } + + // token types enumeration + var TOKENTYPE = { + NULL : 0, + DELIMITER : 1, + IDENTIFIER: 2, + UNKNOWN : 3 + }; + + // map with all delimiters + var DELIMITERS = { + '{': true, + '}': true, + '[': true, + ']': true, + ';': true, + '=': true, + ',': true, + + '->': true, + '--': true + }; + + var dot = ''; // current dot file + var index = 0; // current index in dot file + var c = ''; // current token character in expr + var token = ''; // current token + var tokenType = TOKENTYPE.NULL; // type of the token + + /** + * Get the first character from the dot file. + * The character is stored into the char c. If the end of the dot file is + * reached, the function puts an empty string in c. + */ + function first() { + index = 0; + c = dot.charAt(0); + } + + /** + * Get the next character from the dot file. + * The character is stored into the char c. If the end of the dot file is + * reached, the function puts an empty string in c. + */ + function next() { + index++; + c = dot.charAt(index); + } + + /** + * Preview the next character from the dot file. + * @return {String} cNext + */ + function nextPreview() { + return dot.charAt(index + 1); + } + + /** + * Test whether given character is alphabetic or numeric + * @param {String} c + * @return {Boolean} isAlphaNumeric + */ + var regexAlphaNumeric = /[a-zA-Z_0-9.:#]/; + function isAlphaNumeric(c) { + return regexAlphaNumeric.test(c); + } + + /** + * Merge all properties of object b into object b + * @param {Object} a + * @param {Object} b + * @return {Object} a + */ + function merge (a, b) { + if (!a) { + a = {}; + } + + if (b) { + for (var name in b) { + if (b.hasOwnProperty(name)) { + a[name] = b[name]; + } + } + } + return a; + } + + /** + * Set a value in an object, where the provided parameter name can be a + * path with nested parameters. For example: + * + * var obj = {a: 2}; + * setValue(obj, 'b.c', 3); // obj = {a: 2, b: {c: 3}} + * + * @param {Object} obj + * @param {String} path A parameter name or dot-separated parameter path, + * like "color.highlight.border". + * @param {*} value + */ + function setValue(obj, path, value) { + var keys = path.split('.'); + var o = obj; + while (keys.length) { + var key = keys.shift(); + if (keys.length) { + // this isn't the end point + if (!o[key]) { + o[key] = {}; + } + o = o[key]; + } + else { + // this is the end point + o[key] = value; + } + } + } + + /** + * Add a node to a graph object. If there is already a node with + * the same id, their attributes will be merged. + * @param {Object} graph + * @param {Object} node + */ + function addNode(graph, node) { + var i, len; + var current = null; + + // find root graph (in case of subgraph) + var graphs = [graph]; // list with all graphs from current graph to root graph + var root = graph; + while (root.parent) { + graphs.push(root.parent); + root = root.parent; + } + + // find existing node (at root level) by its id + if (root.nodes) { + for (i = 0, len = root.nodes.length; i < len; i++) { + if (node.id === root.nodes[i].id) { + current = root.nodes[i]; + break; + } + } + } + + if (!current) { + // this is a new node + current = { + id: node.id + }; + if (graph.node) { + // clone default attributes + current.attr = merge(current.attr, graph.node); + } + } + + // add node to this (sub)graph and all its parent graphs + for (i = graphs.length - 1; i >= 0; i--) { + var g = graphs[i]; + + if (!g.nodes) { + g.nodes = []; + } + if (g.nodes.indexOf(current) == -1) { + g.nodes.push(current); + } + } + + // merge attributes + if (node.attr) { + current.attr = merge(current.attr, node.attr); + } + } + + /** + * Add an edge to a graph object + * @param {Object} graph + * @param {Object} edge + */ + function addEdge(graph, edge) { + if (!graph.edges) { + graph.edges = []; + } + graph.edges.push(edge); + if (graph.edge) { + var attr = merge({}, graph.edge); // clone default attributes + edge.attr = merge(attr, edge.attr); // merge attributes + } + } + + /** + * Create an edge to a graph object + * @param {Object} graph + * @param {String | Number | Object} from + * @param {String | Number | Object} to + * @param {String} type + * @param {Object | null} attr + * @return {Object} edge + */ + function createEdge(graph, from, to, type, attr) { + var edge = { + from: from, + to: to, + type: type + }; + + if (graph.edge) { + edge.attr = merge({}, graph.edge); // clone default attributes + } + edge.attr = merge(edge.attr || {}, attr); // merge attributes + + return edge; + } + + /** + * Get next token in the current dot file. + * The token and token type are available as token and tokenType + */ + function getToken() { + tokenType = TOKENTYPE.NULL; + token = ''; + + // skip over whitespaces + while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter + next(); + } + + do { + var isComment = false; + + // skip comment + if (c == '#') { + // find the previous non-space character + var i = index - 1; + while (dot.charAt(i) == ' ' || dot.charAt(i) == '\t') { + i--; + } + if (dot.charAt(i) == '\n' || dot.charAt(i) == '') { + // the # is at the start of a line, this is indeed a line comment + while (c != '' && c != '\n') { + next(); + } + isComment = true; + } + } + if (c == '/' && nextPreview() == '/') { + // skip line comment + while (c != '' && c != '\n') { + next(); + } + isComment = true; + } + if (c == '/' && nextPreview() == '*') { + // skip block comment + while (c != '') { + if (c == '*' && nextPreview() == '/') { + // end of block comment found. skip these last two characters + next(); + next(); + break; + } + else { + next(); + } + } + isComment = true; + } + + // skip over whitespaces + while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter + next(); + } + } + while (isComment); + + // check for end of dot file + if (c == '') { + // token is still empty + tokenType = TOKENTYPE.DELIMITER; + return; + } + + // check for delimiters consisting of 2 characters + var c2 = c + nextPreview(); + if (DELIMITERS[c2]) { + tokenType = TOKENTYPE.DELIMITER; + token = c2; + next(); + next(); + return; + } + + // check for delimiters consisting of 1 character + if (DELIMITERS[c]) { + tokenType = TOKENTYPE.DELIMITER; + token = c; + next(); + return; + } + + // check for an identifier (number or string) + // TODO: more precise parsing of numbers/strings (and the port separator ':') + if (isAlphaNumeric(c) || c == '-') { + token += c; + next(); + + while (isAlphaNumeric(c)) { + token += c; + next(); + } + if (token == 'false') { + token = false; // convert to boolean + } + else if (token == 'true') { + token = true; // convert to boolean + } + else if (!isNaN(Number(token))) { + token = Number(token); // convert to number + } + tokenType = TOKENTYPE.IDENTIFIER; + return; + } + + // check for a string enclosed by double quotes + if (c == '"') { + next(); + while (c != '' && (c != '"' || (c == '"' && nextPreview() == '"'))) { + token += c; + if (c == '"') { // skip the escape character + next(); + } + next(); + } + if (c != '"') { + throw newSyntaxError('End of string " expected'); + } + next(); + tokenType = TOKENTYPE.IDENTIFIER; + return; + } + + // something unknown is found, wrong characters, a syntax error + tokenType = TOKENTYPE.UNKNOWN; + while (c != '') { + token += c; + next(); + } + throw new SyntaxError('Syntax error in part "' + chop(token, 30) + '"'); + } + + /** + * Parse a graph. + * @returns {Object} graph + */ + function parseGraph() { + var graph = {}; + + first(); + getToken(); + + // optional strict keyword + if (token == 'strict') { + graph.strict = true; + getToken(); + } + + // graph or digraph keyword + if (token == 'graph' || token == 'digraph') { + graph.type = token; + getToken(); + } + + // optional graph id + if (tokenType == TOKENTYPE.IDENTIFIER) { + graph.id = token; + getToken(); + } + + // open angle bracket + if (token != '{') { + throw newSyntaxError('Angle bracket { expected'); + } + getToken(); + + // statements + parseStatements(graph); + + // close angle bracket + if (token != '}') { + throw newSyntaxError('Angle bracket } expected'); + } + getToken(); + + // end of file + if (token !== '') { + throw newSyntaxError('End of file expected'); + } + getToken(); + + // remove temporary default properties + delete graph.node; + delete graph.edge; + delete graph.graph; + + return graph; + } + + /** + * Parse a list with statements. + * @param {Object} graph + */ + function parseStatements (graph) { + while (token !== '' && token != '}') { + parseStatement(graph); + if (token == ';') { + getToken(); + } + } + } + + /** + * Parse a single statement. Can be a an attribute statement, node + * statement, a series of node statements and edge statements, or a + * parameter. + * @param {Object} graph + */ + function parseStatement(graph) { + // parse subgraph + var subgraph = parseSubgraph(graph); + if (subgraph) { + // edge statements + parseEdge(graph, subgraph); + + return; + } + + // parse an attribute statement + var attr = parseAttributeStatement(graph); + if (attr) { + return; + } + + // parse node + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Identifier expected'); + } + var id = token; // id can be a string or a number + getToken(); + + if (token == '=') { + // id statement + getToken(); + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Identifier expected'); + } + graph[id] = token; + getToken(); + // TODO: implement comma separated list with "a_list: ID=ID [','] [a_list] " + } + else { + parseNodeStatement(graph, id); + } + } + + /** + * Parse a subgraph + * @param {Object} graph parent graph object + * @return {Object | null} subgraph + */ + function parseSubgraph (graph) { + var subgraph = null; + + // optional subgraph keyword + if (token == 'subgraph') { + subgraph = {}; + subgraph.type = 'subgraph'; + getToken(); + + // optional graph id + if (tokenType == TOKENTYPE.IDENTIFIER) { + subgraph.id = token; + getToken(); + } + } + + // open angle bracket + if (token == '{') { + getToken(); + + if (!subgraph) { + subgraph = {}; + } + subgraph.parent = graph; + subgraph.node = graph.node; + subgraph.edge = graph.edge; + subgraph.graph = graph.graph; + + // statements + parseStatements(subgraph); + + // close angle bracket + if (token != '}') { + throw newSyntaxError('Angle bracket } expected'); + } + getToken(); + + // remove temporary default properties + delete subgraph.node; + delete subgraph.edge; + delete subgraph.graph; + delete subgraph.parent; + + // register at the parent graph + if (!graph.subgraphs) { + graph.subgraphs = []; + } + graph.subgraphs.push(subgraph); + } + + return subgraph; + } + + /** + * parse an attribute statement like "node [shape=circle fontSize=16]". + * Available keywords are 'node', 'edge', 'graph'. + * The previous list with default attributes will be replaced + * @param {Object} graph + * @returns {String | null} keyword Returns the name of the parsed attribute + * (node, edge, graph), or null if nothing + * is parsed. + */ + function parseAttributeStatement (graph) { + // attribute statements + if (token == 'node') { + getToken(); + + // node attributes + graph.node = parseAttributeList(); + return 'node'; + } + else if (token == 'edge') { + getToken(); + + // edge attributes + graph.edge = parseAttributeList(); + return 'edge'; + } + else if (token == 'graph') { + getToken(); + + // graph attributes + graph.graph = parseAttributeList(); + return 'graph'; + } + + return null; + } + + /** + * parse a node statement + * @param {Object} graph + * @param {String | Number} id + */ + function parseNodeStatement(graph, id) { + // node statement + var node = { + id: id + }; + var attr = parseAttributeList(); + if (attr) { + node.attr = attr; + } + addNode(graph, node); + + // edge statements + parseEdge(graph, id); + } + + /** + * Parse an edge or a series of edges + * @param {Object} graph + * @param {String | Number} from Id of the from node + */ + function parseEdge(graph, from) { + while (token == '->' || token == '--') { + var to; + var type = token; + getToken(); + + var subgraph = parseSubgraph(graph); + if (subgraph) { + to = subgraph; + } + else { + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Identifier or subgraph expected'); + } + to = token; + addNode(graph, { + id: to + }); + getToken(); + } + + // parse edge attributes + var attr = parseAttributeList(); + + // create edge + var edge = createEdge(graph, from, to, type, attr); + addEdge(graph, edge); + + from = to; + } + } + + /** + * Parse a set with attributes, + * for example [label="1.000", shape=solid] + * @return {Object | null} attr + */ + function parseAttributeList() { + var attr = null; + + while (token == '[') { + getToken(); + attr = {}; + while (token !== '' && token != ']') { + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Attribute name expected'); + } + var name = token; + + getToken(); + if (token != '=') { + throw newSyntaxError('Equal sign = expected'); + } + getToken(); + + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Attribute value expected'); + } + var value = token; + setValue(attr, name, value); // name can be a path + + getToken(); + if (token ==',') { + getToken(); + } + } + + if (token != ']') { + throw newSyntaxError('Bracket ] expected'); + } + getToken(); + } + + return attr; + } + + /** + * Create a syntax error with extra information on current token and index. + * @param {String} message + * @returns {SyntaxError} err + */ + function newSyntaxError(message) { + return new SyntaxError(message + ', got "' + chop(token, 30) + '" (char ' + index + ')'); + } + + /** + * Chop off text after a maximum length + * @param {String} text + * @param {Number} maxLength + * @returns {String} + */ + function chop (text, maxLength) { + return (text.length <= maxLength) ? text : (text.substr(0, 27) + '...'); + } + + /** + * Execute a function fn for each pair of elements in two arrays + * @param {Array | *} array1 + * @param {Array | *} array2 + * @param {function} fn + */ + function forEach2(array1, array2, fn) { + if (array1 instanceof Array) { + array1.forEach(function (elem1) { + if (array2 instanceof Array) { + array2.forEach(function (elem2) { + fn(elem1, elem2); + }); + } + else { + fn(elem1, array2); + } + }); + } + else { + if (array2 instanceof Array) { + array2.forEach(function (elem2) { + fn(array1, elem2); + }); + } + else { + fn(array1, array2); + } + } + } + + /** + * Convert a string containing a graph in DOT language into a map containing + * with nodes and edges in the format of graph. + * @param {String} data Text containing a graph in DOT-notation + * @return {Object} graphData + */ + function DOTToGraph (data) { + // parse the DOT file + var dotData = parseDOT(data); + var graphData = { + nodes: [], + edges: [], + options: {} + }; + + // copy the nodes + if (dotData.nodes) { + dotData.nodes.forEach(function (dotNode) { + var graphNode = { + id: dotNode.id, + label: String(dotNode.label || dotNode.id) + }; + merge(graphNode, dotNode.attr); + if (graphNode.image) { + graphNode.shape = 'image'; + } + graphData.nodes.push(graphNode); + }); + } + + // copy the edges + if (dotData.edges) { + /** + * Convert an edge in DOT format to an edge with VisGraph format + * @param {Object} dotEdge + * @returns {Object} graphEdge + */ + function convertEdge(dotEdge) { + var graphEdge = { + from: dotEdge.from, + to: dotEdge.to + }; + merge(graphEdge, dotEdge.attr); + graphEdge.style = (dotEdge.type == '->') ? 'arrow' : 'line'; + return graphEdge; + } + + dotData.edges.forEach(function (dotEdge) { + var from, to; + if (dotEdge.from instanceof Object) { + from = dotEdge.from.nodes; + } + else { + from = { + id: dotEdge.from + } + } + + if (dotEdge.to instanceof Object) { + to = dotEdge.to.nodes; + } + else { + to = { + id: dotEdge.to + } + } + + if (dotEdge.from instanceof Object && dotEdge.from.edges) { + dotEdge.from.edges.forEach(function (subEdge) { + var graphEdge = convertEdge(subEdge); + graphData.edges.push(graphEdge); + }); + } + + forEach2(from, to, function (from, to) { + var subEdge = createEdge(graphData, from.id, to.id, dotEdge.type, dotEdge.attr); + var graphEdge = convertEdge(subEdge); + graphData.edges.push(graphEdge); + }); + + if (dotEdge.to instanceof Object && dotEdge.to.edges) { + dotEdge.to.edges.forEach(function (subEdge) { + var graphEdge = convertEdge(subEdge); + graphData.edges.push(graphEdge); + }); + } + }); + } + + // copy the options + if (dotData.attr) { + graphData.options = dotData.attr; + } + + return graphData; + } + + // exports + exports.parseDOT = parseDOT; + exports.DOTToGraph = DOTToGraph; + +})(typeof util !== 'undefined' ? util : exports); + +/** + * Canvas shapes used by the Graph + */ +if (typeof CanvasRenderingContext2D !== 'undefined') { + + /** + * Draw a circle shape + */ + CanvasRenderingContext2D.prototype.circle = function(x, y, r) { + this.beginPath(); + this.arc(x, y, r, 0, 2*Math.PI, false); + }; + + /** + * Draw a square shape + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r size, width and height of the square + */ + CanvasRenderingContext2D.prototype.square = function(x, y, r) { + this.beginPath(); + this.rect(x - r, y - r, r * 2, r * 2); + }; + + /** + * Draw a triangle shape + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r radius, half the length of the sides of the triangle + */ + CanvasRenderingContext2D.prototype.triangle = function(x, y, r) { + // http://en.wikipedia.org/wiki/Equilateral_triangle + this.beginPath(); + + var s = r * 2; + var s2 = s / 2; + var ir = Math.sqrt(3) / 6 * s; // radius of inner circle + var h = Math.sqrt(s * s - s2 * s2); // height + + this.moveTo(x, y - (h - ir)); + this.lineTo(x + s2, y + ir); + this.lineTo(x - s2, y + ir); + this.lineTo(x, y - (h - ir)); + this.closePath(); + }; + + /** + * Draw a triangle shape in downward orientation + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r radius + */ + CanvasRenderingContext2D.prototype.triangleDown = function(x, y, r) { + // http://en.wikipedia.org/wiki/Equilateral_triangle + this.beginPath(); + + var s = r * 2; + var s2 = s / 2; + var ir = Math.sqrt(3) / 6 * s; // radius of inner circle + var h = Math.sqrt(s * s - s2 * s2); // height + + this.moveTo(x, y + (h - ir)); + this.lineTo(x + s2, y - ir); + this.lineTo(x - s2, y - ir); + this.lineTo(x, y + (h - ir)); + this.closePath(); + }; + + /** + * Draw a star shape, a star with 5 points + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r radius, half the length of the sides of the triangle + */ + CanvasRenderingContext2D.prototype.star = function(x, y, r) { + // http://www.html5canvastutorials.com/labs/html5-canvas-star-spinner/ + this.beginPath(); + + for (var n = 0; n < 10; n++) { + var radius = (n % 2 === 0) ? r * 1.3 : r * 0.5; + this.lineTo( + x + radius * Math.sin(n * 2 * Math.PI / 10), + y - radius * Math.cos(n * 2 * Math.PI / 10) + ); + } + + this.closePath(); + }; + + /** + * http://stackoverflow.com/questions/1255512/how-to-draw-a-rounded-rectangle-on-html-canvas + */ + CanvasRenderingContext2D.prototype.roundRect = function(x, y, w, h, r) { + var r2d = Math.PI/180; + if( w - ( 2 * r ) < 0 ) { r = ( w / 2 ); } //ensure that the radius isn't too large for x + if( h - ( 2 * r ) < 0 ) { r = ( h / 2 ); } //ensure that the radius isn't too large for y + this.beginPath(); + this.moveTo(x+r,y); + this.lineTo(x+w-r,y); + this.arc(x+w-r,y+r,r,r2d*270,r2d*360,false); + this.lineTo(x+w,y+h-r); + this.arc(x+w-r,y+h-r,r,0,r2d*90,false); + this.lineTo(x+r,y+h); + this.arc(x+r,y+h-r,r,r2d*90,r2d*180,false); + this.lineTo(x,y+r); + this.arc(x+r,y+r,r,r2d*180,r2d*270,false); + }; + + /** + * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + */ + CanvasRenderingContext2D.prototype.ellipse = function(x, y, w, h) { + var kappa = .5522848, + ox = (w / 2) * kappa, // control point offset horizontal + oy = (h / 2) * kappa, // control point offset vertical + xe = x + w, // x-end + ye = y + h, // y-end + xm = x + w / 2, // x-middle + ym = y + h / 2; // y-middle + + this.beginPath(); + this.moveTo(x, ym); + this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); + this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); + this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); + this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); + }; + + + + /** + * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + */ + CanvasRenderingContext2D.prototype.database = function(x, y, w, h) { + var f = 1/3; + var wEllipse = w; + var hEllipse = h * f; + + var kappa = .5522848, + ox = (wEllipse / 2) * kappa, // control point offset horizontal + oy = (hEllipse / 2) * kappa, // control point offset vertical + xe = x + wEllipse, // x-end + ye = y + hEllipse, // y-end + xm = x + wEllipse / 2, // x-middle + ym = y + hEllipse / 2, // y-middle + ymb = y + (h - hEllipse/2), // y-midlle, bottom ellipse + yeb = y + h; // y-end, bottom ellipse + + this.beginPath(); + this.moveTo(xe, ym); + + this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); + this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); + + this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); + this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); + + this.lineTo(xe, ymb); + + this.bezierCurveTo(xe, ymb + oy, xm + ox, yeb, xm, yeb); + this.bezierCurveTo(xm - ox, yeb, x, ymb + oy, x, ymb); + + this.lineTo(x, ym); + }; + + + /** + * Draw an arrow point (no line) + */ + CanvasRenderingContext2D.prototype.arrow = function(x, y, angle, length) { + // tail + var xt = x - length * Math.cos(angle); + var yt = y - length * Math.sin(angle); + + // inner tail + // TODO: allow to customize different shapes + var xi = x - length * 0.9 * Math.cos(angle); + var yi = y - length * 0.9 * Math.sin(angle); + + // left + var xl = xt + length / 3 * Math.cos(angle + 0.5 * Math.PI); + var yl = yt + length / 3 * Math.sin(angle + 0.5 * Math.PI); + + // right + var xr = xt + length / 3 * Math.cos(angle - 0.5 * Math.PI); + var yr = yt + length / 3 * Math.sin(angle - 0.5 * Math.PI); + + this.beginPath(); + this.moveTo(x, y); + this.lineTo(xl, yl); + this.lineTo(xi, yi); + this.lineTo(xr, yr); + this.closePath(); + }; + + /** + * Sets up the dashedLine functionality for drawing + * Original code came from http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas + * @author David Jordan + * @date 2012-08-08 + */ + CanvasRenderingContext2D.prototype.dashedLine = function(x,y,x2,y2,dashArray){ + if (!dashArray) dashArray=[10,5]; + if (dashLength==0) dashLength = 0.001; // Hack for Safari + var dashCount = dashArray.length; + this.moveTo(x, y); + var dx = (x2-x), dy = (y2-y); + var slope = dy/dx; + var distRemaining = Math.sqrt( dx*dx + dy*dy ); + var dashIndex=0, draw=true; + while (distRemaining>=0.1){ + var dashLength = dashArray[dashIndex++%dashCount]; + if (dashLength > distRemaining) dashLength = distRemaining; + var xStep = Math.sqrt( dashLength*dashLength / (1 + slope*slope) ); + if (dx<0) xStep = -xStep; + x += xStep; + y += slope*xStep; + this[draw ? 'lineTo' : 'moveTo'](x,y); + distRemaining -= dashLength; + draw = !draw; + } + }; + + // TODO: add diamond shape +} + +/** + * @class Node + * A node. A node can be connected to other nodes via one or multiple edges. + * @param {object} properties An object containing properties for the node. All + * properties are optional, except for the id. + * {number} id Id of the node. Required + * {string} label Text label for the node + * {number} x Horizontal position of the node + * {number} y Vertical position of the node + * {string} shape Node shape, available: + * "database", "circle", "ellipse", + * "box", "image", "text", "dot", + * "star", "triangle", "triangleDown", + * "square" + * {string} image An image url + * {string} title An title text, can be HTML + * {anytype} group A group name or number + * @param {Graph.Images} imagelist A list with images. Only needed + * when the node has an image + * @param {Graph.Groups} grouplist A list with groups. Needed for + * retrieving group properties + * @param {Object} constants An object with default values for + * example for the color + */ +function Node(properties, imagelist, grouplist, constants) { + this.selected = false; + + this.edges = []; // all edges connected to this node + this.group = constants.nodes.group; + + this.fontSize = constants.nodes.fontSize; + this.fontFace = constants.nodes.fontFace; + this.fontColor = constants.nodes.fontColor; + + this.color = constants.nodes.color; + + // set defaults for the properties + this.id = undefined; + this.shape = constants.nodes.shape; + this.image = constants.nodes.image; + this.x = 0; + this.y = 0; + this.xFixed = false; + this.yFixed = false; + this.radius = constants.nodes.radius; + this.radiusFixed = false; + this.radiusMin = constants.nodes.radiusMin; + this.radiusMax = constants.nodes.radiusMax; + + this.imagelist = imagelist; + this.grouplist = grouplist; + + this.setProperties(properties, constants); + + // mass, force, velocity + this.mass = 50; // kg (mass is adjusted for the number of connected edges) + this.fx = 0.0; // external force x + this.fy = 0.0; // external force y + this.vx = 0.0; // velocity x + this.vy = 0.0; // velocity y + this.minForce = constants.minForce; + this.damping = 0.9; // damping factor +}; + +/** + * Attach a edge to the node + * @param {Edge} edge + */ +Node.prototype.attachEdge = function(edge) { + if (this.edges.indexOf(edge) == -1) { + this.edges.push(edge); + } + this._updateMass(); +}; + +/** + * Detach a edge from the node + * @param {Edge} edge + */ +Node.prototype.detachEdge = function(edge) { + var index = this.edges.indexOf(edge); + if (index != -1) { + this.edges.splice(index, 1); + } + this._updateMass(); +}; + +/** + * Update the nodes mass, which is determined by the number of edges connecting + * to it (more edges -> heavier node). + * @private + */ +Node.prototype._updateMass = function() { + this.mass = 50 + 20 * this.edges.length; // kg +}; + +/** + * Set or overwrite properties for the node + * @param {Object} properties an object with properties + * @param {Object} constants and object with default, global properties + */ +Node.prototype.setProperties = function(properties, constants) { + if (!properties) { + return; + } + + // basic properties + if (properties.id != undefined) {this.id = properties.id;} + if (properties.label != undefined) {this.label = properties.label;} + if (properties.title != undefined) {this.title = properties.title;} + if (properties.group != undefined) {this.group = properties.group;} + if (properties.x != undefined) {this.x = properties.x;} + if (properties.y != undefined) {this.y = properties.y;} + if (properties.value != undefined) {this.value = properties.value;} + + if (this.id === undefined) { + throw "Node must have an id"; + } + + // copy group properties + if (this.group) { + var groupObj = this.grouplist.get(this.group); + for (var prop in groupObj) { + if (groupObj.hasOwnProperty(prop)) { + this[prop] = groupObj[prop]; + } + } + } + + // individual shape properties + if (properties.shape != undefined) {this.shape = properties.shape;} + if (properties.image != undefined) {this.image = properties.image;} + if (properties.radius != undefined) {this.radius = properties.radius;} + if (properties.color != undefined) {this.color = Node.parseColor(properties.color);} + + if (properties.fontColor != undefined) {this.fontColor = properties.fontColor;} + if (properties.fontSize != undefined) {this.fontSize = properties.fontSize;} + if (properties.fontFace != undefined) {this.fontFace = properties.fontFace;} + + + if (this.image != undefined) { + if (this.imagelist) { + this.imageObj = this.imagelist.load(this.image); + } + else { + throw "No imagelist provided"; + } + } + + this.xFixed = this.xFixed || (properties.x != undefined); + this.yFixed = this.yFixed || (properties.y != undefined); + this.radiusFixed = this.radiusFixed || (properties.radius != undefined); + + if (this.shape == 'image') { + this.radiusMin = constants.nodes.widthMin; + this.radiusMax = constants.nodes.widthMax; + } + + // choose draw method depending on the shape + switch (this.shape) { + case 'database': this.draw = this._drawDatabase; this.resize = this._resizeDatabase; break; + case 'box': this.draw = this._drawBox; this.resize = this._resizeBox; break; + case 'circle': this.draw = this._drawCircle; this.resize = this._resizeCircle; break; + case 'ellipse': this.draw = this._drawEllipse; this.resize = this._resizeEllipse; break; + // TODO: add diamond shape + case 'image': this.draw = this._drawImage; this.resize = this._resizeImage; break; + case 'text': this.draw = this._drawText; this.resize = this._resizeText; break; + case 'dot': this.draw = this._drawDot; this.resize = this._resizeShape; break; + case 'square': this.draw = this._drawSquare; this.resize = this._resizeShape; break; + case 'triangle': this.draw = this._drawTriangle; this.resize = this._resizeShape; break; + case 'triangleDown': this.draw = this._drawTriangleDown; this.resize = this._resizeShape; break; + case 'star': this.draw = this._drawStar; this.resize = this._resizeShape; break; + default: this.draw = this._drawEllipse; this.resize = this._resizeEllipse; break; + } + + // reset the size of the node, this can be changed + this._reset(); +}; + +/** + * Parse a color property into an object with border, background, and + * hightlight colors + * @param {Object | String} color + * @return {Object} colorObject + */ +Node.parseColor = function(color) { + var c; + if (util.isString(color)) { + c = { + border: color, + background: color, + highlight: { + border: color, + background: color + } + }; + // TODO: automatically generate a nice highlight color + } + else { + c = {}; + c.background = color.background || 'white'; + c.border = color.border || c.background; + if (util.isString(color.highlight)) { + c.highlight = { + border: color.highlight, + background: color.highlight + } + } + else { + c.highlight = {}; + c.highlight.background = color.highlight && color.highlight.background || c.background; + c.highlight.border = color.highlight && color.highlight.border || c.border; + } + } + return c; +}; + +/** + * select this node + */ +Node.prototype.select = function() { + this.selected = true; + this._reset(); +}; + +/** + * unselect this node + */ +Node.prototype.unselect = function() { + this.selected = false; + this._reset(); +}; + +/** + * Reset the calculated size of the node, forces it to recalculate its size + * @private + */ +Node.prototype._reset = function() { + this.width = undefined; + this.height = undefined; +}; + +/** + * get the title of this node. + * @return {string} title The title of the node, or undefined when no title + * has been set. + */ +Node.prototype.getTitle = function() { + return this.title; +}; + +/** + * Calculate the distance to the border of the Node + * @param {CanvasRenderingContext2D} ctx + * @param {Number} angle Angle in radians + * @returns {number} distance Distance to the border in pixels + */ +Node.prototype.distanceToBorder = function (ctx, angle) { + var borderWidth = 1; + + if (!this.width) { + this.resize(ctx); + } + + //noinspection FallthroughInSwitchStatementJS + switch (this.shape) { + case 'circle': + case 'dot': + return this.radius + borderWidth; + + case 'ellipse': + var a = this.width / 2; + var b = this.height / 2; + var w = (Math.sin(angle) * a); + var h = (Math.cos(angle) * b); + return a * b / Math.sqrt(w * w + h * h); + + // TODO: implement distanceToBorder for database + // TODO: implement distanceToBorder for triangle + // TODO: implement distanceToBorder for triangleDown + + case 'box': + case 'image': + case 'text': + default: + if (this.width) { + return Math.min( + Math.abs(this.width / 2 / Math.cos(angle)), + Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth; + // TODO: reckon with border radius too in case of box + } + else { + return 0; + } + + } + + // TODO: implement calculation of distance to border for all shapes +}; + +/** + * Set forces acting on the node + * @param {number} fx Force in horizontal direction + * @param {number} fy Force in vertical direction + */ +Node.prototype._setForce = function(fx, fy) { + this.fx = fx; + this.fy = fy; +}; + +/** + * Add forces acting on the node + * @param {number} fx Force in horizontal direction + * @param {number} fy Force in vertical direction + * @private + */ +Node.prototype._addForce = function(fx, fy) { + this.fx += fx; + this.fy += fy; +}; + +/** + * Perform one discrete step for the node + * @param {number} interval Time interval in seconds + */ +Node.prototype.discreteStep = function(interval) { + if (!this.xFixed) { + var dx = -this.damping * this.vx; // damping force + var ax = (this.fx + dx) / this.mass; // acceleration + this.vx += ax / interval; // velocity + this.x += this.vx / interval; // position + } + + if (!this.yFixed) { + var dy = -this.damping * this.vy; // damping force + var ay = (this.fy + dy) / this.mass; // acceleration + this.vy += ay / interval; // velocity + this.y += this.vy / interval; // position + } +}; + + +/** + * Check if this node has a fixed x and y position + * @return {boolean} true if fixed, false if not + */ +Node.prototype.isFixed = function() { + return (this.xFixed && this.yFixed); +}; + +/** + * Check if this node is moving + * @param {number} vmin the minimum velocity considered as "moving" + * @return {boolean} true if moving, false if it has no velocity + */ +// TODO: replace this method with calculating the kinetic energy +Node.prototype.isMoving = function(vmin) { + return (Math.abs(this.vx) > vmin || Math.abs(this.vy) > vmin || + (!this.xFixed && Math.abs(this.fx) > this.minForce) || + (!this.yFixed && Math.abs(this.fy) > this.minForce)); +}; + +/** + * check if this node is selecte + * @return {boolean} selected True if node is selected, else false + */ +Node.prototype.isSelected = function() { + return this.selected; +}; + +/** + * Retrieve the value of the node. Can be undefined + * @return {Number} value + */ +Node.prototype.getValue = function() { + return this.value; +}; + +/** + * Calculate the distance from the nodes location to the given location (x,y) + * @param {Number} x + * @param {Number} y + * @return {Number} value + */ +Node.prototype.getDistance = function(x, y) { + var dx = this.x - x, + dy = this.y - y; + return Math.sqrt(dx * dx + dy * dy); +}; + + +/** + * Adjust the value range of the node. The node will adjust it's radius + * based on its value. + * @param {Number} min + * @param {Number} max + */ +Node.prototype.setValueRange = function(min, max) { + if (!this.radiusFixed && this.value !== undefined) { + if (max == min) { + this.radius = (this.radiusMin + this.radiusMax) / 2; + } + else { + var scale = (this.radiusMax - this.radiusMin) / (max - min); + this.radius = (this.value - min) * scale + this.radiusMin; + } + } +}; + +/** + * Draw this node in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + */ +Node.prototype.draw = function(ctx) { + throw "Draw method not initialized for node"; +}; + +/** + * Recalculate the size of this node in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + */ +Node.prototype.resize = function(ctx) { + throw "Resize method not initialized for node"; +}; + +/** + * Check if this object is overlapping with the provided object + * @param {Object} obj an object with parameters left, top, right, bottom + * @return {boolean} True if location is located on node + */ +Node.prototype.isOverlappingWith = function(obj) { + return (this.left < obj.right && + this.left + this.width > obj.left && + this.top < obj.bottom && + this.top + this.height > obj.top); +}; + +Node.prototype._resizeImage = function (ctx) { + // TODO: pre calculate the image size + if (!this.width) { // undefined or 0 + var width, height; + if (this.value) { + var scale = this.imageObj.height / this.imageObj.width; + width = this.radius || this.imageObj.width; + height = this.radius * scale || this.imageObj.height; + } + else { + width = this.imageObj.width; + height = this.imageObj.height; + } + this.width = width; + this.height = height; + } +}; + +Node.prototype._drawImage = function (ctx) { + this._resizeImage(ctx); + + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; + + var yLabel; + if (this.imageObj) { + ctx.drawImage(this.imageObj, this.left, this.top, this.width, this.height); + yLabel = this.y + this.height / 2; + } + else { + // image still loading... just draw the label for now + yLabel = this.y; + } + + this._label(ctx, this.label, this.x, yLabel, undefined, "top"); +}; + + +Node.prototype._resizeBox = function (ctx) { + if (!this.width) { + var margin = 5; + var textSize = this.getTextSize(ctx); + this.width = textSize.width + 2 * margin; + this.height = textSize.height + 2 * margin; + } +}; + +Node.prototype._drawBox = function (ctx) { + this._resizeBox(ctx); + + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; + + ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; + ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; + ctx.lineWidth = this.selected ? 2.0 : 1.0; + ctx.roundRect(this.left, this.top, this.width, this.height, this.radius); + ctx.fill(); + ctx.stroke(); + + this._label(ctx, this.label, this.x, this.y); +}; + + +Node.prototype._resizeDatabase = function (ctx) { + if (!this.width) { + var margin = 5; + var textSize = this.getTextSize(ctx); + var size = textSize.width + 2 * margin; + this.width = size; + this.height = size; + } +}; + +Node.prototype._drawDatabase = function (ctx) { + this._resizeDatabase(ctx); + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; + + ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; + ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; + ctx.lineWidth = this.selected ? 2.0 : 1.0; + ctx.database(this.x - this.width/2, this.y - this.height*0.5, this.width, this.height); + ctx.fill(); + ctx.stroke(); + + this._label(ctx, this.label, this.x, this.y); +}; + + +Node.prototype._resizeCircle = function (ctx) { + if (!this.width) { + var margin = 5; + var textSize = this.getTextSize(ctx); + var diameter = Math.max(textSize.width, textSize.height) + 2 * margin; + this.radius = diameter / 2; + + this.width = diameter; + this.height = diameter; + } +}; + +Node.prototype._drawCircle = function (ctx) { + this._resizeCircle(ctx); + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; + + ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; + ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; + ctx.lineWidth = this.selected ? 2.0 : 1.0; + ctx.circle(this.x, this.y, this.radius); + ctx.fill(); + ctx.stroke(); + + this._label(ctx, this.label, this.x, this.y); +}; + +Node.prototype._resizeEllipse = function (ctx) { + if (!this.width) { + var textSize = this.getTextSize(ctx); + + this.width = textSize.width * 1.5; + this.height = textSize.height * 2; + if (this.width < this.height) { + this.width = this.height; + } + } +}; + +Node.prototype._drawEllipse = function (ctx) { + this._resizeEllipse(ctx); + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; + + ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; + ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; + ctx.lineWidth = this.selected ? 2.0 : 1.0; + ctx.ellipse(this.left, this.top, this.width, this.height); + ctx.fill(); + ctx.stroke(); + + this._label(ctx, this.label, this.x, this.y); +}; + +Node.prototype._drawDot = function (ctx) { + this._drawShape(ctx, 'circle'); +}; + +Node.prototype._drawTriangle = function (ctx) { + this._drawShape(ctx, 'triangle'); +}; + +Node.prototype._drawTriangleDown = function (ctx) { + this._drawShape(ctx, 'triangleDown'); +}; + +Node.prototype._drawSquare = function (ctx) { + this._drawShape(ctx, 'square'); +}; + +Node.prototype._drawStar = function (ctx) { + this._drawShape(ctx, 'star'); +}; + +Node.prototype._resizeShape = function (ctx) { + if (!this.width) { + var size = 2 * this.radius; + this.width = size; + this.height = size; + } +}; + +Node.prototype._drawShape = function (ctx, shape) { + this._resizeShape(ctx); + + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; + + ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; + ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; + ctx.lineWidth = this.selected ? 2.0 : 1.0; + + ctx[shape](this.x, this.y, this.radius); + ctx.fill(); + ctx.stroke(); + + if (this.label) { + this._label(ctx, this.label, this.x, this.y + this.height / 2, undefined, 'top'); + } +}; + +Node.prototype._resizeText = function (ctx) { + if (!this.width) { + var margin = 5; + var textSize = this.getTextSize(ctx); + this.width = textSize.width + 2 * margin; + this.height = textSize.height + 2 * margin; + } +}; + +Node.prototype._drawText = function (ctx) { + this._resizeText(ctx); + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; + + this._label(ctx, this.label, this.x, this.y); +}; + + +Node.prototype._label = function (ctx, text, x, y, align, baseline) { + if (text) { + ctx.font = (this.selected ? "bold " : "") + this.fontSize + "px " + this.fontFace; + ctx.fillStyle = this.fontColor || "black"; + ctx.textAlign = align || "center"; + ctx.textBaseline = baseline || "middle"; + + var lines = text.split('\n'), + lineCount = lines.length, + fontSize = (this.fontSize + 4), + yLine = y + (1 - lineCount) / 2 * fontSize; + + for (var i = 0; i < lineCount; i++) { + ctx.fillText(lines[i], x, yLine); + yLine += fontSize; + } + } +}; + + +Node.prototype.getTextSize = function(ctx) { + if (this.label != undefined) { + ctx.font = (this.selected ? "bold " : "") + this.fontSize + "px " + this.fontFace; + + var lines = this.label.split('\n'), + height = (this.fontSize + 4) * lines.length, + width = 0; + + for (var i = 0, iMax = lines.length; i < iMax; i++) { + width = Math.max(width, ctx.measureText(lines[i]).width); + } + + return {"width": width, "height": height}; + } + else { + return {"width": 0, "height": 0}; + } +}; + +/** + * @class Edge + * + * A edge connects two nodes + * @param {Object} properties Object with properties. Must contain + * At least properties from and to. + * Available properties: from (number), + * to (number), label (string, color (string), + * width (number), style (string), + * length (number), title (string) + * @param {Graph} graph A graph object, used to find and edge to + * nodes. + * @param {Object} constants An object with default values for + * example for the color + */ +function Edge (properties, graph, constants) { + if (!graph) { + throw "No graph provided"; + } + this.graph = graph; + + // initialize constants + this.widthMin = constants.edges.widthMin; + this.widthMax = constants.edges.widthMax; + + // initialize variables + this.id = undefined; + this.fromId = undefined; + this.toId = undefined; + this.style = constants.edges.style; + this.title = undefined; + this.width = constants.edges.width; + this.value = undefined; + this.length = constants.edges.length; + + this.from = null; // a node + this.to = null; // a node + this.connected = false; + + // Added to support dashed lines + // David Jordan + // 2012-08-08 + this.dash = util.extend({}, constants.edges.dash); // contains properties length, gap, altLength + + this.stiffness = undefined; // depends on the length of the edge + this.color = constants.edges.color; + this.widthFixed = false; + this.lengthFixed = false; + + this.setProperties(properties, constants); +} + +/** + * Set or overwrite properties for the edge + * @param {Object} properties an object with properties + * @param {Object} constants and object with default, global properties + */ +Edge.prototype.setProperties = function(properties, constants) { + if (!properties) { + return; + } + + if (properties.from != undefined) {this.fromId = properties.from;} + if (properties.to != undefined) {this.toId = properties.to;} + + if (properties.id != undefined) {this.id = properties.id;} + if (properties.style != undefined) {this.style = properties.style;} + if (properties.label != undefined) {this.label = properties.label;} + if (this.label) { + this.fontSize = constants.edges.fontSize; + this.fontFace = constants.edges.fontFace; + this.fontColor = constants.edges.fontColor; + if (properties.fontColor != undefined) {this.fontColor = properties.fontColor;} + if (properties.fontSize != undefined) {this.fontSize = properties.fontSize;} + if (properties.fontFace != undefined) {this.fontFace = properties.fontFace;} + } + if (properties.title != undefined) {this.title = properties.title;} + if (properties.width != undefined) {this.width = properties.width;} + if (properties.value != undefined) {this.value = properties.value;} + if (properties.length != undefined) {this.length = properties.length;} + + // Added to support dashed lines + // David Jordan + // 2012-08-08 + if (properties.dash) { + if (properties.dash.length != undefined) {this.dash.length = properties.dash.length;} + if (properties.dash.gap != undefined) {this.dash.gap = properties.dash.gap;} + if (properties.dash.altLength != undefined) {this.dash.altLength = properties.dash.altLength;} + } + + if (properties.color != undefined) {this.color = properties.color;} + + // A node is connected when it has a from and to node. + this.connect(); + + this.widthFixed = this.widthFixed || (properties.width != undefined); + this.lengthFixed = this.lengthFixed || (properties.length != undefined); + this.stiffness = 1 / this.length; + + // set draw method based on style + switch (this.style) { + case 'line': this.draw = this._drawLine; break; + case 'arrow': this.draw = this._drawArrow; break; + case 'arrow-center': this.draw = this._drawArrowCenter; break; + case 'dash-line': this.draw = this._drawDashLine; break; + default: this.draw = this._drawLine; break; + } +}; + +/** + * Connect an edge to its nodes + */ +Edge.prototype.connect = function () { + this.disconnect(); + + this.from = this.graph.nodes[this.fromId] || null; + this.to = this.graph.nodes[this.toId] || null; + this.connected = (this.from && this.to); + + if (this.connected) { + this.from.attachEdge(this); + this.to.attachEdge(this); + } + else { + if (this.from) { + this.from.detachEdge(this); + } + if (this.to) { + this.to.detachEdge(this); + } + } +}; + +/** + * Disconnect an edge from its nodes + */ +Edge.prototype.disconnect = function () { + if (this.from) { + this.from.detachEdge(this); + this.from = null; + } + if (this.to) { + this.to.detachEdge(this); + this.to = null; + } + + this.connected = false; +}; + +/** + * get the title of this edge. + * @return {string} title The title of the edge, or undefined when no title + * has been set. + */ +Edge.prototype.getTitle = function() { + return this.title; +}; + + +/** + * Retrieve the value of the edge. Can be undefined + * @return {Number} value + */ +Edge.prototype.getValue = function() { + return this.value; +}; + +/** + * Adjust the value range of the edge. The edge will adjust it's width + * based on its value. + * @param {Number} min + * @param {Number} max + */ +Edge.prototype.setValueRange = function(min, max) { + if (!this.widthFixed && this.value !== undefined) { + var scale = (this.widthMax - this.widthMin) / (max - min); + this.width = (this.value - min) * scale + this.widthMin; + } +}; + +/** + * Redraw a edge + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + */ +Edge.prototype.draw = function(ctx) { + throw "Method draw not initialized in edge"; +}; + +/** + * Check if this object is overlapping with the provided object + * @param {Object} obj an object with parameters left, top + * @return {boolean} True if location is located on the edge + */ +Edge.prototype.isOverlappingWith = function(obj) { + var distMax = 10; + + var xFrom = this.from.x; + var yFrom = this.from.y; + var xTo = this.to.x; + var yTo = this.to.y; + var xObj = obj.left; + var yObj = obj.top; + + + var dist = Edge._dist(xFrom, yFrom, xTo, yTo, xObj, yObj); + + return (dist < distMax); +}; + + +/** + * Redraw a edge as a line + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private + */ +Edge.prototype._drawLine = function(ctx) { + // set style + ctx.strokeStyle = this.color; + ctx.lineWidth = this._getLineWidth(); + + var point; + if (this.from != this.to) { + // draw line + this._line(ctx); + + // draw label + if (this.label) { + point = this._pointOnLine(0.5); + this._label(ctx, this.label, point.x, point.y); + } + } + else { + var x, y; + var radius = this.length / 4; + var node = this.from; + if (!node.width) { + node.resize(ctx); + } + if (node.width > node.height) { + x = node.x + node.width / 2; + y = node.y - radius; + } + else { + x = node.x + radius; + y = node.y - node.height / 2; + } + this._circle(ctx, x, y, radius); + point = this._pointOnCircle(x, y, radius, 0.5); + this._label(ctx, this.label, point.x, point.y); + } +}; + +/** + * Get the line width of the edge. Depends on width and whether one of the + * connected nodes is selected. + * @return {Number} width + * @private + */ +Edge.prototype._getLineWidth = function() { + if (this.from.selected || this.to.selected) { + return Math.min(this.width * 2, this.widthMax); + } + else { + return this.width; + } +}; + +/** + * Draw a line between two nodes + * @param {CanvasRenderingContext2D} ctx + * @private + */ +Edge.prototype._line = function (ctx) { + // draw a straight line + ctx.beginPath(); + ctx.moveTo(this.from.x, this.from.y); + ctx.lineTo(this.to.x, this.to.y); + ctx.stroke(); +}; + +/** + * Draw a line from a node to itself, a circle + * @param {CanvasRenderingContext2D} ctx + * @param {Number} x + * @param {Number} y + * @param {Number} radius + * @private + */ +Edge.prototype._circle = function (ctx, x, y, radius) { + // draw a circle + ctx.beginPath(); + ctx.arc(x, y, radius, 0, 2 * Math.PI, false); + ctx.stroke(); +}; + +/** + * Draw label with white background and with the middle at (x, y) + * @param {CanvasRenderingContext2D} ctx + * @param {String} text + * @param {Number} x + * @param {Number} y + * @private + */ +Edge.prototype._label = function (ctx, text, x, y) { + if (text) { + // TODO: cache the calculated size + ctx.font = ((this.from.selected || this.to.selected) ? "bold " : "") + + this.fontSize + "px " + this.fontFace; + ctx.fillStyle = 'white'; + var width = ctx.measureText(text).width; + var height = this.fontSize; + var left = x - width / 2; + var top = y - height / 2; + + ctx.fillRect(left, top, width, height); + + // draw text + ctx.fillStyle = this.fontColor || "black"; + ctx.textAlign = "left"; + ctx.textBaseline = "top"; + ctx.fillText(text, left, top); + } +}; + +/** + * Redraw a edge as a dashed line + * Draw this edge in the given canvas + * @author David Jordan + * @date 2012-08-08 + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private + */ +Edge.prototype._drawDashLine = function(ctx) { + // set style + ctx.strokeStyle = this.color; + ctx.lineWidth = this._getLineWidth(); + + // draw dashed line + ctx.beginPath(); + ctx.lineCap = 'round'; + if (this.dash.altLength != undefined) //If an alt dash value has been set add to the array this value + { + ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, + [this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]); + } + else if (this.dash.length != undefined && this.dash.gap != undefined) //If a dash and gap value has been set add to the array this value + { + ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, + [this.dash.length,this.dash.gap]); + } + else //If all else fails draw a line + { + ctx.moveTo(this.from.x, this.from.y); + ctx.lineTo(this.to.x, this.to.y); + } + ctx.stroke(); + + // draw label + if (this.label) { + var point = this._pointOnLine(0.5); + this._label(ctx, this.label, point.x, point.y); + } +}; + +/** + * Get a point on a line + * @param {Number} percentage. Value between 0 (line start) and 1 (line end) + * @return {Object} point + * @private + */ +Edge.prototype._pointOnLine = function (percentage) { + return { + x: (1 - percentage) * this.from.x + percentage * this.to.x, + y: (1 - percentage) * this.from.y + percentage * this.to.y + } +}; + +/** + * Get a point on a circle + * @param {Number} x + * @param {Number} y + * @param {Number} radius + * @param {Number} percentage. Value between 0 (line start) and 1 (line end) + * @return {Object} point + * @private + */ +Edge.prototype._pointOnCircle = function (x, y, radius, percentage) { + var angle = (percentage - 3/8) * 2 * Math.PI; + return { + x: x + radius * Math.cos(angle), + y: y - radius * Math.sin(angle) + } +}; + +/** + * Redraw a edge as a line with an arrow halfway the line + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private + */ +Edge.prototype._drawArrowCenter = function(ctx) { + var point; + // set style + ctx.strokeStyle = this.color; + ctx.fillStyle = this.color; + ctx.lineWidth = this._getLineWidth(); + + if (this.from != this.to) { + // draw line + this._line(ctx); + + // draw an arrow halfway the line + var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); + var length = 10 + 5 * this.width; // TODO: make customizable? + point = this._pointOnLine(0.5); + ctx.arrow(point.x, point.y, angle, length); + ctx.fill(); + ctx.stroke(); + + // draw label + if (this.label) { + point = this._pointOnLine(0.5); + this._label(ctx, this.label, point.x, point.y); + } + } + else { + // draw circle + var x, y; + var radius = this.length / 4; + var node = this.from; + if (!node.width) { + node.resize(ctx); + } + if (node.width > node.height) { + x = node.x + node.width / 2; + y = node.y - radius; + } + else { + x = node.x + radius; + y = node.y - node.height / 2; + } + this._circle(ctx, x, y, radius); + + // draw all arrows + var angle = 0.2 * Math.PI; + var length = 10 + 5 * this.width; // TODO: make customizable? + point = this._pointOnCircle(x, y, radius, 0.5); + ctx.arrow(point.x, point.y, angle, length); + ctx.fill(); + ctx.stroke(); + + // draw label + if (this.label) { + point = this._pointOnCircle(x, y, radius, 0.5); + this._label(ctx, this.label, point.x, point.y); + } + } +}; + + + +/** + * Redraw a edge as a line with an arrow + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private + */ +Edge.prototype._drawArrow = function(ctx) { + // set style + ctx.strokeStyle = this.color; + ctx.fillStyle = this.color; + ctx.lineWidth = this._getLineWidth(); + + // draw line + var angle, length; + if (this.from != this.to) { + // calculate length and angle of the line + angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); + var dx = (this.to.x - this.from.x); + var dy = (this.to.y - this.from.y); + var lEdge = Math.sqrt(dx * dx + dy * dy); + + var lFrom = this.from.distanceToBorder(ctx, angle + Math.PI); + var pFrom = (lEdge - lFrom) / lEdge; + var xFrom = (pFrom) * this.from.x + (1 - pFrom) * this.to.x; + var yFrom = (pFrom) * this.from.y + (1 - pFrom) * this.to.y; + + var lTo = this.to.distanceToBorder(ctx, angle); + var pTo = (lEdge - lTo) / lEdge; + var xTo = (1 - pTo) * this.from.x + pTo * this.to.x; + var yTo = (1 - pTo) * this.from.y + pTo * this.to.y; + + ctx.beginPath(); + ctx.moveTo(xFrom, yFrom); + ctx.lineTo(xTo, yTo); + ctx.stroke(); + + // draw arrow at the end of the line + length = 10 + 5 * this.width; // TODO: make customizable? + ctx.arrow(xTo, yTo, angle, length); + ctx.fill(); + ctx.stroke(); + + // draw label + if (this.label) { + var point = this._pointOnLine(0.5); + this._label(ctx, this.label, point.x, point.y); + } + } + else { + // draw circle + var node = this.from; + var x, y, arrow; + var radius = this.length / 4; + if (!node.width) { + node.resize(ctx); + } + if (node.width > node.height) { + x = node.x + node.width / 2; + y = node.y - radius; + arrow = { + x: x, + y: node.y, + angle: 0.9 * Math.PI + }; + } + else { + x = node.x + radius; + y = node.y - node.height / 2; + arrow = { + x: node.x, + y: y, + angle: 0.6 * Math.PI + }; + } + ctx.beginPath(); + // TODO: do not draw a circle, but an arc + // TODO: similarly, for a line without arrows, draw to the border of the nodes instead of the center + ctx.arc(x, y, radius, 0, 2 * Math.PI, false); + ctx.stroke(); + + // draw all arrows + length = 10 + 5 * this.width; // TODO: make customizable? + ctx.arrow(arrow.x, arrow.y, arrow.angle, length); + ctx.fill(); + ctx.stroke(); + + // draw label + if (this.label) { + point = this._pointOnCircle(x, y, radius, 0.5); + this._label(ctx, this.label, point.x, point.y); + } + } +}; + + + +/** + * Calculate the distance between a point (x3,y3) and a line segment from + * (x1,y1) to (x2,y2). + * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment + * @param {number} x1 + * @param {number} y1 + * @param {number} x2 + * @param {number} y2 + * @param {number} x3 + * @param {number} y3 + * @private + */ +Edge._dist = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point + var px = x2-x1, + py = y2-y1, + something = px*px + py*py, + u = ((x3 - x1) * px + (y3 - y1) * py) / something; + + if (u > 1) { + u = 1; + } + else if (u < 0) { + u = 0; + } + + var x = x1 + u * px, + y = y1 + u * py, + dx = x - x3, + dy = y - y3; + + //# Note: If the actual distance does not matter, + //# if you only want to compare what this function + //# returns to other results of this function, you + //# can just return the squared distance instead + //# (i.e. remove the sqrt) to gain a little performance + + return Math.sqrt(dx*dx + dy*dy); +}; + +/** + * Popup is a class to create a popup window with some text + * @param {Element} container The container object. + * @param {Number} [x] + * @param {Number} [y] + * @param {String} [text] + */ +function Popup(container, x, y, text) { + if (container) { + this.container = container; + } + else { + this.container = document.body; + } + this.x = 0; + this.y = 0; + this.padding = 5; + + if (x !== undefined && y !== undefined ) { + this.setPosition(x, y); + } + if (text !== undefined) { + this.setText(text); + } + + // create the frame + this.frame = document.createElement("div"); + var style = this.frame.style; + style.position = "absolute"; + style.visibility = "hidden"; + style.border = "1px solid #666"; + style.color = "black"; + style.padding = this.padding + "px"; + style.backgroundColor = "#FFFFC6"; + style.borderRadius = "3px"; + style.MozBorderRadius = "3px"; + style.WebkitBorderRadius = "3px"; + style.boxShadow = "3px 3px 10px rgba(128, 128, 128, 0.5)"; + style.whiteSpace = "nowrap"; + this.container.appendChild(this.frame); +}; + +/** + * @param {number} x Horizontal position of the popup window + * @param {number} y Vertical position of the popup window + */ +Popup.prototype.setPosition = function(x, y) { + this.x = parseInt(x); + this.y = parseInt(y); +}; + +/** + * Set the text for the popup window. This can be HTML code + * @param {string} text + */ +Popup.prototype.setText = function(text) { + this.frame.innerHTML = text; +}; + +/** + * Show the popup window + * @param {boolean} show Optional. Show or hide the window + */ +Popup.prototype.show = function (show) { + if (show === undefined) { + show = true; + } + + if (show) { + var height = this.frame.clientHeight; + var width = this.frame.clientWidth; + var maxHeight = this.frame.parentNode.clientHeight; + var maxWidth = this.frame.parentNode.clientWidth; + + var top = (this.y - height); + if (top + height + this.padding > maxHeight) { + top = maxHeight - height - this.padding; + } + if (top < this.padding) { + top = this.padding; + } + + var left = this.x; + if (left + width + this.padding > maxWidth) { + left = maxWidth - width - this.padding; + } + if (left < this.padding) { + left = this.padding; + } + + this.frame.style.left = left + "px"; + this.frame.style.top = top + "px"; + this.frame.style.visibility = "visible"; + } + else { + this.hide(); + } +}; + +/** + * Hide the popup window + */ +Popup.prototype.hide = function () { + this.frame.style.visibility = "hidden"; +}; + +/** + * @class Groups + * This class can store groups and properties specific for groups. + */ +Groups = function () { + this.clear(); + this.defaultIndex = 0; +}; + + +/** + * default constants for group colors + */ +Groups.DEFAULT = [ + {border: "#2B7CE9", background: "#97C2FC", highlight: {border: "#2B7CE9", background: "#D2E5FF"}}, // blue + {border: "#FFA500", background: "#FFFF00", highlight: {border: "#FFA500", background: "#FFFFA3"}}, // yellow + {border: "#FA0A10", background: "#FB7E81", highlight: {border: "#FA0A10", background: "#FFAFB1"}}, // red + {border: "#41A906", background: "#7BE141", highlight: {border: "#41A906", background: "#A1EC76"}}, // green + {border: "#E129F0", background: "#EB7DF4", highlight: {border: "#E129F0", background: "#F0B3F5"}}, // magenta + {border: "#7C29F0", background: "#AD85E4", highlight: {border: "#7C29F0", background: "#D3BDF0"}}, // purple + {border: "#C37F00", background: "#FFA807", highlight: {border: "#C37F00", background: "#FFCA66"}}, // orange + {border: "#4220FB", background: "#6E6EFD", highlight: {border: "#4220FB", background: "#9B9BFD"}}, // darkblue + {border: "#FD5A77", background: "#FFC0CB", highlight: {border: "#FD5A77", background: "#FFD1D9"}}, // pink + {border: "#4AD63A", background: "#C2FABC", highlight: {border: "#4AD63A", background: "#E6FFE3"}} // mint +]; + + +/** + * Clear all groups + */ +Groups.prototype.clear = function () { + this.groups = {}; + this.groups.length = function() + { + var i = 0; + for ( var p in this ) { + if (this.hasOwnProperty(p)) { + i++; + } + } + return i; + } +}; + + +/** + * get group properties of a groupname. If groupname is not found, a new group + * is added. + * @param {*} groupname Can be a number, string, Date, etc. + * @return {Object} group The created group, containing all group properties + */ +Groups.prototype.get = function (groupname) { + var group = this.groups[groupname]; + + if (group == undefined) { + // create new group + var index = this.defaultIndex % Groups.DEFAULT.length; + this.defaultIndex++; + group = {}; + group.color = Groups.DEFAULT[index]; + this.groups[groupname] = group; + } + + return group; +}; + +/** + * Add a custom group style + * @param {String} groupname + * @param {Object} style An object containing borderColor, + * backgroundColor, etc. + * @return {Object} group The created group object + */ +Groups.prototype.add = function (groupname, style) { + this.groups[groupname] = style; + if (style.color) { + style.color = Node.parseColor(style.color); + } + return style; +}; + +/** + * @class Images + * This class loads images and keeps them stored. + */ +Images = function () { + this.images = {}; + + this.callback = undefined; +}; + +/** + * Set an onload callback function. This will be called each time an image + * is loaded + * @param {function} callback + */ +Images.prototype.setOnloadCallback = function(callback) { + this.callback = callback; +}; + +/** + * + * @param {string} url Url of the image + * @return {Image} img The image object + */ +Images.prototype.load = function(url) { + var img = this.images[url]; + if (img == undefined) { + // create the image + var images = this; + img = new Image(); + this.images[url] = img; + img.onload = function() { + if (images.callback) { + images.callback(this); + } + }; + img.src = url; + } + + return img; +}; + +/** + * @constructor Graph + * Create a graph visualization, displaying nodes and edges. + * + * @param {Element} container The DOM element in which the Graph will + * be created. Normally a div element. + * @param {Object} data An object containing parameters + * {Array} nodes + * {Array} edges + * @param {Object} options Options + */ +function Graph (container, data, options) { + // create variables and set default values + this.containerElement = container; + this.width = '100%'; + this.height = '100%'; + this.refreshRate = 50; // milliseconds + this.stabilize = true; // stabilize before displaying the graph + this.selectable = true; + + // set constant values + this.constants = { + nodes: { + radiusMin: 5, + radiusMax: 20, + radius: 5, + distance: 100, // px + shape: 'ellipse', + image: undefined, + widthMin: 16, // px + widthMax: 64, // px + fontColor: 'black', + fontSize: 14, // px + //fontFace: verdana, + fontFace: 'arial', + color: { + border: '#2B7CE9', + background: '#97C2FC', + highlight: { + border: '#2B7CE9', + background: '#D2E5FF' + } + }, + borderColor: '#2B7CE9', + backgroundColor: '#97C2FC', + highlightColor: '#D2E5FF', + group: undefined + }, + edges: { + widthMin: 1, + widthMax: 15, + width: 1, + style: 'line', + color: '#343434', + fontColor: '#343434', + fontSize: 14, // px + fontFace: 'arial', + //distance: 100, //px + length: 100, // px + dash: { + length: 10, + gap: 5, + altLength: undefined + } + }, + minForce: 0.05, + minVelocity: 0.02, // px/s + maxIterations: 1000 // maximum number of iteration to stabilize + }; + + var graph = this; + this.nodes = {}; // object with Node objects + this.edges = {}; // object with Edge objects + // TODO: create a counter to keep track on the number of nodes having values + // TODO: create a counter to keep track on the number of nodes currently moving + // TODO: create a counter to keep track on the number of edges having values + + this.nodesData = null; // A DataSet or DataView + this.edgesData = null; // A DataSet or DataView + + // create event listeners used to subscribe on the DataSets of the nodes and edges + var me = this; + this.nodesListeners = { + 'add': function (event, params) { + me._addNodes(params.items); + me.start(); + }, + 'update': function (event, params) { + me._updateNodes(params.items); + me.start(); + }, + 'remove': function (event, params) { + me._removeNodes(params.items); + me.start(); + } + }; + this.edgesListeners = { + 'add': function (event, params) { + me._addEdges(params.items); + me.start(); + }, + 'update': function (event, params) { + me._updateEdges(params.items); + me.start(); + }, + 'remove': function (event, params) { + me._removeEdges(params.items); + me.start(); + } + }; + + this.groups = new Groups(); // object with groups + this.images = new Images(); // object with images + this.images.setOnloadCallback(function () { + graph._redraw(); + }); + + // properties of the data + this.moving = false; // True if any of the nodes have an undefined position + + this.selection = []; + this.timer = undefined; + + // create a frame and canvas + this._create(); + + // apply options + this.setOptions(options); + + // draw data + this.setData(data); +} + +/** + * Set nodes and edges, and optionally options as well. + * + * @param {Object} data Object containing parameters: + * {Array | DataSet | DataView} [nodes] Array with nodes + * {Array | DataSet | DataView} [edges] Array with edges + * {String} [dot] String containing data in DOT format + * {Options} [options] Object with options + */ +Graph.prototype.setData = function(data) { + if (data && data.dot && (data.nodes || data.edges)) { + throw new SyntaxError('Data must contain either parameter "dot" or ' + + ' parameter pair "nodes" and "edges", but not both.'); + } + + // set options + this.setOptions(data && data.options); + + // set all data + if (data && data.dot) { + // parse DOT file + if(data && data.dot) { + var dotData = vis.util.DOTToGraph(data.dot); + this.setData(dotData); + return; + } + } + else { + this._setNodes(data && data.nodes); + this._setEdges(data && data.edges); + } + + // find a stable position or start animating to a stable position + if (this.stabilize) { + this._doStabilize(); + } + this.start(); +}; + +/** + * Set options + * @param {Object} options + */ +Graph.prototype.setOptions = function (options) { + if (options) { + // retrieve parameter values + if (options.width != undefined) {this.width = options.width;} + if (options.height != undefined) {this.height = options.height;} + if (options.stabilize != undefined) {this.stabilize = options.stabilize;} + if (options.selectable != undefined) {this.selectable = options.selectable;} + + // TODO: work out these options and document them + if (options.edges) { + for (var prop in options.edges) { + if (options.edges.hasOwnProperty(prop)) { + this.constants.edges[prop] = options.edges[prop]; + } + } + + if (options.edges.length != undefined && + options.nodes && options.nodes.distance == undefined) { + this.constants.edges.length = options.edges.length; + this.constants.nodes.distance = options.edges.length * 1.25; + } + + if (!options.edges.fontColor) { + this.constants.edges.fontColor = options.edges.color; + } + + // Added to support dashed lines + // David Jordan + // 2012-08-08 + if (options.edges.dash) { + if (options.edges.dash.length != undefined) { + this.constants.edges.dash.length = options.edges.dash.length; + } + if (options.edges.dash.gap != undefined) { + this.constants.edges.dash.gap = options.edges.dash.gap; + } + if (options.edges.dash.altLength != undefined) { + this.constants.edges.dash.altLength = options.edges.dash.altLength; + } + } + } + + if (options.nodes) { + for (prop in options.nodes) { + if (options.nodes.hasOwnProperty(prop)) { + this.constants.nodes[prop] = options.nodes[prop]; + } + } + + if (options.nodes.color) { + this.constants.nodes.color = Node.parseColor(options.nodes.color); + } + + /* + if (options.nodes.widthMin) this.constants.nodes.radiusMin = options.nodes.widthMin; + if (options.nodes.widthMax) this.constants.nodes.radiusMax = options.nodes.widthMax; + */ + } + + if (options.groups) { + for (var groupname in options.groups) { + if (options.groups.hasOwnProperty(groupname)) { + var group = options.groups[groupname]; + this.groups.add(groupname, group); + } + } + } + } + + this.setSize(this.width, this.height); + this._setTranslation(this.frame.clientWidth / 2, this.frame.clientHeight / 2); + this._setScale(1); +}; + +/** + * fire an event + * @param {String} event The name of an event, for example 'select' + * @param {Object} params Optional object with event parameters + * @private + */ +Graph.prototype._trigger = function (event, params) { + events.trigger(this, event, params); +}; + + +/** + * Create the main frame for the Graph. + * This function is executed once when a Graph object is created. The frame + * contains a canvas, and this canvas contains all objects like the axis and + * nodes. + * @private + */ +Graph.prototype._create = function () { + // remove all elements from the container element. + while (this.containerElement.hasChildNodes()) { + this.containerElement.removeChild(this.containerElement.firstChild); + } + + this.frame = document.createElement('div'); + this.frame.className = 'graph-frame'; + this.frame.style.position = 'relative'; + this.frame.style.overflow = 'hidden'; + + // create the graph canvas (HTML canvas element) + this.frame.canvas = document.createElement( 'canvas' ); + this.frame.canvas.style.position = 'relative'; + this.frame.appendChild(this.frame.canvas); + if (!this.frame.canvas.getContext) { + var noCanvas = document.createElement( 'DIV' ); + noCanvas.style.color = 'red'; + noCanvas.style.fontWeight = 'bold' ; + noCanvas.style.padding = '10px'; + noCanvas.innerHTML = 'Error: your browser does not support HTML canvas'; + this.frame.canvas.appendChild(noCanvas); + } + + var me = this; + this.drag = {}; + this.pinch = {}; + this.hammer = Hammer(this.frame.canvas, { + prevent_default: true + }); + this.hammer.on('tap', me._onTap.bind(me) ); + this.hammer.on('hold', me._onHold.bind(me) ); + this.hammer.on('pinch', me._onPinch.bind(me) ); + this.hammer.on('touch', me._onTouch.bind(me) ); + this.hammer.on('dragstart', me._onDragStart.bind(me) ); + this.hammer.on('drag', me._onDrag.bind(me) ); + this.hammer.on('dragend', me._onDragEnd.bind(me) ); + this.hammer.on('mousewheel',me._onMouseWheel.bind(me) ); + this.hammer.on('DOMMouseScroll',me._onMouseWheel.bind(me) ); // for FF + this.hammer.on('mousemove', me._onMouseMoveTitle.bind(me) ); + + // add the frame to the container element + this.containerElement.appendChild(this.frame); +}; + +/** + * + * @param {{x: Number, y: Number}} pointer + * @return {Number | null} node + * @private + */ +Graph.prototype._getNodeAt = function (pointer) { + var x = this._canvasToX(pointer.x); + var y = this._canvasToY(pointer.y); + + var obj = { + left: x, + top: y, + right: x, + bottom: y + }; + + // if there are overlapping nodes, select the last one, this is the + // one which is drawn on top of the others + var overlappingNodes = this._getNodesOverlappingWith(obj); + return (overlappingNodes.length > 0) ? + overlappingNodes[overlappingNodes.length - 1] : null; +}; + +/** + * Get the pointer location from a touch location + * @param {{pageX: Number, pageY: Number}} touch + * @return {{x: Number, y: Number}} pointer + * @private + */ +Graph.prototype._getPointer = function (touch) { + return { + x: touch.pageX - vis.util.getAbsoluteLeft(this.frame.canvas), + y: touch.pageY - vis.util.getAbsoluteTop(this.frame.canvas) + }; +}; + +/** + * On start of a touch gesture, store the pointer + * @param event + * @private + */ +Graph.prototype._onTouch = function (event) { + this.drag.pointer = this._getPointer(event.gesture.touches[0]); + this.drag.pinched = false; + this.pinch.scale = this._getScale(); +}; + +/** + * handle drag start event + * @private + */ +Graph.prototype._onDragStart = function () { + var drag = this.drag; + + drag.selection = []; + drag.translation = this._getTranslation(); + drag.nodeId = this._getNodeAt(drag.pointer); + // note: drag.pointer is set in _onTouch to get the initial touch location + + var node = this.nodes[drag.nodeId]; + if (node) { + // select the clicked node if not yet selected + if (!node.isSelected()) { + this._selectNodes([drag.nodeId]); + } + + // create an array with the selected nodes and their original location and status + var me = this; + this.selection.forEach(function (id) { + var node = me.nodes[id]; + if (node) { + var s = { + id: id, + node: node, + + // store original x, y, xFixed and yFixed, make the node temporarily Fixed + x: node.x, + y: node.y, + xFixed: node.xFixed, + yFixed: node.yFixed + }; + + node.xFixed = true; + node.yFixed = true; + + drag.selection.push(s); + } + }); + + } +}; + +/** + * handle drag event + * @private + */ +Graph.prototype._onDrag = function (event) { + if (this.drag.pinched) { + return; + } + + var pointer = this._getPointer(event.gesture.touches[0]); + + var me = this, + drag = this.drag, + selection = drag.selection; + if (selection && selection.length) { + // calculate delta's and new location + var deltaX = pointer.x - drag.pointer.x, + deltaY = pointer.y - drag.pointer.y; + + // update position of all selected nodes + selection.forEach(function (s) { + var node = s.node; + + if (!s.xFixed) { + node.x = me._canvasToX(me._xToCanvas(s.x) + deltaX); + } + + if (!s.yFixed) { + node.y = me._canvasToY(me._yToCanvas(s.y) + deltaY); + } + }); + + // start animation if not yet running + if (!this.moving) { + this.moving = true; + this.start(); + } + } + else { + // move the graph + var diffX = pointer.x - this.drag.pointer.x; + var diffY = pointer.y - this.drag.pointer.y; + + this._setTranslation( + this.drag.translation.x + diffX, + this.drag.translation.y + diffY); + this._redraw(); + + this.moved = true; + } +}; + +/** + * handle drag start event + * @private + */ +Graph.prototype._onDragEnd = function () { + var selection = this.drag.selection; + if (selection) { + selection.forEach(function (s) { + // restore original xFixed and yFixed + s.node.xFixed = s.xFixed; + s.node.yFixed = s.yFixed; + }); + } +}; + +/** + * handle tap/click event: select/unselect a node + * @private + */ +Graph.prototype._onTap = function (event) { + var pointer = this._getPointer(event.gesture.touches[0]); + + var nodeId = this._getNodeAt(pointer); + var node = this.nodes[nodeId]; + if (node) { + // select this node + this._selectNodes([nodeId]); + + if (!this.moving) { + this._redraw(); + } + } + else { + // remove selection + this._unselectNodes(); + this._redraw(); + } +}; + +/** + * handle long tap event: multi select nodes + * @private + */ +Graph.prototype._onHold = function (event) { + var pointer = this._getPointer(event.gesture.touches[0]); + var nodeId = this._getNodeAt(pointer); + var node = this.nodes[nodeId]; + if (node) { + if (!node.isSelected()) { + // select this node, keep previous selection + var append = true; + this._selectNodes([nodeId], append); + } + else { + this._unselectNodes([nodeId]); + } + + if (!this.moving) { + this._redraw(); + } + } + else { + // Do nothing + } +}; + +/** + * Handle pinch event + * @param event + * @private + */ +Graph.prototype._onPinch = function (event) { + var pointer = this._getPointer(event.gesture.center); + + this.drag.pinched = true; + if (!('scale' in this.pinch)) { + this.pinch.scale = 1; + } + + // TODO: enable moving while pinching? + var scale = this.pinch.scale * event.gesture.scale; + this._zoom(scale, pointer) +}; + +/** + * Zoom the graph in or out + * @param {Number} scale a number around 1, and between 0.01 and 10 + * @param {{x: Number, y: Number}} pointer + * @return {Number} appliedScale scale is limited within the boundaries + * @private + */ +Graph.prototype._zoom = function(scale, pointer) { + var scaleOld = this._getScale(); + if (scale < 0.01) { + scale = 0.01; + } + if (scale > 10) { + scale = 10; + } + + var translation = this._getTranslation(); + var scaleFrac = scale / scaleOld; + var tx = (1 - scaleFrac) * pointer.x + translation.x * scaleFrac; + var ty = (1 - scaleFrac) * pointer.y + translation.y * scaleFrac; + + this._setScale(scale); + this._setTranslation(tx, ty); + this._redraw(); + + return scale; +}; + +/** + * Event handler for mouse wheel event, used to zoom the timeline + * See http://adomas.org/javascript-mouse-wheel/ + * https://github.com/EightMedia/hammer.js/issues/256 + * @param {MouseEvent} event + * @private + */ +Graph.prototype._onMouseWheel = function(event) { + // retrieve delta + var delta = 0; + if (event.wheelDelta) { /* IE/Opera. */ + delta = event.wheelDelta/120; + } else if (event.detail) { /* Mozilla case. */ + // In Mozilla, sign of delta is different than in IE. + // Also, delta is multiple of 3. + delta = -event.detail/3; + } + + // If delta is nonzero, handle it. + // Basically, delta is now positive if wheel was scrolled up, + // and negative, if wheel was scrolled down. + if (delta) { + if (!('mouswheelScale' in this.pinch)) { + this.pinch.mouswheelScale = 1; + } + + // calculate the new scale + var scale = this.pinch.mouswheelScale; + var zoom = delta / 10; + if (delta < 0) { + zoom = zoom / (1 - zoom); + } + scale *= (1 + zoom); + + // calculate the pointer location + var gesture = util.fakeGesture(this, event); + var pointer = this._getPointer(gesture.center); + + // apply the new scale + scale = this._zoom(scale, pointer); + + // store the new, applied scale + this.pinch.mouswheelScale = scale; + } + + // Prevent default actions caused by mouse wheel. + event.preventDefault(); +}; + + +/** + * Mouse move handler for checking whether the title moves over a node with a title. + * @param {Event} event + * @private + */ +Graph.prototype._onMouseMoveTitle = function (event) { + var gesture = util.fakeGesture(this, event); + var pointer = this._getPointer(gesture.center); + + // check if the previously selected node is still selected + if (this.popupNode) { + this._checkHidePopup(pointer); + } + + // start a timeout that will check if the mouse is positioned above + // an element + var me = this; + var checkShow = function() { + me._checkShowPopup(pointer); + }; + if (this.popupTimer) { + clearInterval(this.popupTimer); // stop any running timer + } + if (!this.leftButtonDown) { + this.popupTimer = setTimeout(checkShow, 300); + } +}; + +/** + * Check if there is an element on the given position in the graph + * (a node or edge). If so, and if this element has a title, + * show a popup window with its title. + * + * @param {{x:Number, y:Number}} pointer + * @private + */ +Graph.prototype._checkShowPopup = function (pointer) { + var obj = { + left: this._canvasToX(pointer.x), + top: this._canvasToY(pointer.y), + right: this._canvasToX(pointer.x), + bottom: this._canvasToY(pointer.y) + }; + + var id; + var lastPopupNode = this.popupNode; + + if (this.popupNode == undefined) { + // search the nodes for overlap, select the top one in case of multiple nodes + var nodes = this.nodes; + for (id in nodes) { + if (nodes.hasOwnProperty(id)) { + var node = nodes[id]; + if (node.getTitle() != undefined && node.isOverlappingWith(obj)) { + this.popupNode = node; + break; + } + } + } + } + + if (this.popupNode == undefined) { + // search the edges for overlap + var edges = this.edges; + for (id in edges) { + if (edges.hasOwnProperty(id)) { + var edge = edges[id]; + if (edge.connected && (edge.getTitle() != undefined) && + edge.isOverlappingWith(obj)) { + this.popupNode = edge; + break; + } + } + } + } + + if (this.popupNode) { + // show popup message window + if (this.popupNode != lastPopupNode) { + var me = this; + if (!me.popup) { + me.popup = new Popup(me.frame); + } + + // adjust a small offset such that the mouse cursor is located in the + // bottom left location of the popup, and you can easily move over the + // popup area + me.popup.setPosition(pointer.x - 3, pointer.y - 3); + me.popup.setText(me.popupNode.getTitle()); + me.popup.show(); + } + } + else { + if (this.popup) { + this.popup.hide(); + } + } +}; + +/** + * Check if the popup must be hided, which is the case when the mouse is no + * longer hovering on the object + * @param {{x:Number, y:Number}} pointer + * @private + */ +Graph.prototype._checkHidePopup = function (pointer) { + if (!this.popupNode || !this._getNodeAt(pointer) ) { + this.popupNode = undefined; + if (this.popup) { + this.popup.hide(); + } + } +}; + +/** + * Unselect selected nodes. If no selection array is provided, all nodes + * are unselected + * @param {Object[]} selection Array with selection objects, each selection + * object has a parameter row. Optional + * @param {Boolean} triggerSelect If true (default), the select event + * is triggered when nodes are unselected + * @return {Boolean} changed True if the selection is changed + * @private + */ +Graph.prototype._unselectNodes = function(selection, triggerSelect) { + var changed = false; + var i, iMax, id; + + if (selection) { + // remove provided selections + for (i = 0, iMax = selection.length; i < iMax; i++) { + id = selection[i]; + this.nodes[id].unselect(); + + var j = 0; + while (j < this.selection.length) { + if (this.selection[j] == id) { + this.selection.splice(j, 1); + changed = true; + } + else { + j++; + } + } + } + } + else if (this.selection && this.selection.length) { + // remove all selections + for (i = 0, iMax = this.selection.length; i < iMax; i++) { + id = this.selection[i]; + this.nodes[id].unselect(); + changed = true; + } + this.selection = []; + } + + if (changed && (triggerSelect == true || triggerSelect == undefined)) { + // fire the select event + this._trigger('select'); + } + + return changed; +}; + +/** + * select all nodes on given location x, y + * @param {Array} selection an array with node ids + * @param {boolean} append If true, the new selection will be appended to the + * current selection (except for duplicate entries) + * @return {Boolean} changed True if the selection is changed + * @private + */ +Graph.prototype._selectNodes = function(selection, append) { + var changed = false; + var i, iMax; + + // TODO: the selectNodes method is a little messy, rework this + + // check if the current selection equals the desired selection + var selectionAlreadyThere = true; + if (selection.length != this.selection.length) { + selectionAlreadyThere = false; + } + else { + for (i = 0, iMax = Math.min(selection.length, this.selection.length); i < iMax; i++) { + if (selection[i] != this.selection[i]) { + selectionAlreadyThere = false; + break; + } + } + } + if (selectionAlreadyThere) { + return changed; + } + + if (append == undefined || append == false) { + // first deselect any selected node + var triggerSelect = false; + changed = this._unselectNodes(undefined, triggerSelect); + } + + for (i = 0, iMax = selection.length; i < iMax; i++) { + // add each of the new selections, but only when they are not duplicate + var id = selection[i]; + var isDuplicate = (this.selection.indexOf(id) != -1); + if (!isDuplicate) { + this.nodes[id].select(); + this.selection.push(id); + changed = true; + } + } + + if (changed) { + // fire the select event + this._trigger('select'); + } + + return changed; +}; + +/** + * retrieve all nodes overlapping with given object + * @param {Object} obj An object with parameters left, top, right, bottom + * @return {Number[]} An array with id's of the overlapping nodes + * @private + */ +Graph.prototype._getNodesOverlappingWith = function (obj) { + var nodes = this.nodes, + overlappingNodes = []; + + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + if (nodes[id].isOverlappingWith(obj)) { + overlappingNodes.push(id); + } + } + } + + return overlappingNodes; +}; + +/** + * retrieve the currently selected nodes + * @return {Number[] | String[]} selection An array with the ids of the + * selected nodes. + */ +Graph.prototype.getSelection = function() { + return this.selection.concat([]); +}; + +/** + * select zero or more nodes + * @param {Number[] | String[]} selection An array with the ids of the + * selected nodes. + */ +Graph.prototype.setSelection = function(selection) { + var i, iMax, id; + + if (!selection || (selection.length == undefined)) + throw 'Selection must be an array with ids'; + + // first unselect any selected node + for (i = 0, iMax = this.selection.length; i < iMax; i++) { + id = this.selection[i]; + this.nodes[id].unselect(); + } + + this.selection = []; + + for (i = 0, iMax = selection.length; i < iMax; i++) { + id = selection[i]; + + var node = this.nodes[id]; + if (!node) { + throw new RangeError('Node with id "' + id + '" not found'); + } + node.select(); + this.selection.push(id); + } + + this.redraw(); +}; + +/** + * Validate the selection: remove ids of nodes which no longer exist + * @private + */ +Graph.prototype._updateSelection = function () { + var i = 0; + while (i < this.selection.length) { + var id = this.selection[i]; + if (!this.nodes[id]) { + this.selection.splice(i, 1); + } + else { + i++; + } + } +}; + +/** + * Temporary method to test calculating a hub value for the nodes + * @param {number} level Maximum number edges between two nodes in order + * to call them connected. Optional, 1 by default + * @return {Number[]} connectioncount array with the connection count + * for each node + * @private + */ +Graph.prototype._getConnectionCount = function(level) { + if (level == undefined) { + level = 1; + } + + // get the nodes connected to given nodes + function getConnectedNodes(nodes) { + var connectedNodes = []; + + for (var j = 0, jMax = nodes.length; j < jMax; j++) { + var node = nodes[j]; + + // find all nodes connected to this node + var edges = node.edges; + for (var i = 0, iMax = edges.length; i < iMax; i++) { + var edge = edges[i]; + var other = null; + + // check if connected + if (edge.from == node) + other = edge.to; + else if (edge.to == node) + other = edge.from; + + // check if the other node is not already in the list with nodes + var k, kMax; + if (other) { + for (k = 0, kMax = nodes.length; k < kMax; k++) { + if (nodes[k] == other) { + other = null; + break; + } + } + } + if (other) { + for (k = 0, kMax = connectedNodes.length; k < kMax; k++) { + if (connectedNodes[k] == other) { + other = null; + break; + } + } + } + + if (other) + connectedNodes.push(other); + } + } + + return connectedNodes; + } + + var connections = []; + var nodes = this.nodes; + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + var c = [nodes[id]]; + for (var l = 0; l < level; l++) { + c = c.concat(getConnectedNodes(c)); + } + connections.push(c); + } + } + + var hubs = []; + for (var i = 0, len = connections.length; i < len; i++) { + hubs.push(connections[i].length); + } + + return hubs; +}; + + +/** + * Set a new size for the graph + * @param {string} width Width in pixels or percentage (for example '800px' + * or '50%') + * @param {string} height Height in pixels or percentage (for example '400px' + * or '30%') + */ +Graph.prototype.setSize = function(width, height) { + this.frame.style.width = width; + this.frame.style.height = height; + + this.frame.canvas.style.width = '100%'; + this.frame.canvas.style.height = '100%'; + + this.frame.canvas.width = this.frame.canvas.clientWidth; + this.frame.canvas.height = this.frame.canvas.clientHeight; +}; + +/** + * Set a data set with nodes for the graph + * @param {Array | DataSet | DataView} nodes The data containing the nodes. + * @private + */ +Graph.prototype._setNodes = function(nodes) { + var oldNodesData = this.nodesData; + + if (nodes instanceof DataSet || nodes instanceof DataView) { + this.nodesData = nodes; + } + else if (nodes instanceof Array) { + this.nodesData = new DataSet(); + this.nodesData.add(nodes); + } + else if (!nodes) { + this.nodesData = new DataSet(); + } + else { + throw new TypeError('Array or DataSet expected'); + } + + if (oldNodesData) { + // unsubscribe from old dataset + util.forEach(this.nodesListeners, function (callback, event) { + oldNodesData.unsubscribe(event, callback); + }); + } + + // remove drawn nodes + this.nodes = {}; + + if (this.nodesData) { + // subscribe to new dataset + var me = this; + util.forEach(this.nodesListeners, function (callback, event) { + me.nodesData.subscribe(event, callback); + }); + + // draw all new nodes + var ids = this.nodesData.getIds(); + this._addNodes(ids); + } + + this._updateSelection(); +}; + +/** + * Add nodes + * @param {Number[] | String[]} ids + * @private + */ +Graph.prototype._addNodes = function(ids) { + var id; + for (var i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + var data = this.nodesData.get(id); + var node = new Node(data, this.images, this.groups, this.constants); + this.nodes[id] = node; // note: this may replace an existing node + + if (!node.isFixed()) { + // TODO: position new nodes in a smarter way! + var radius = this.constants.edges.length * 2; + var count = ids.length; + var angle = 2 * Math.PI * (i / count); + node.x = radius * Math.cos(angle); + node.y = radius * Math.sin(angle); + + // note: no not use node.isMoving() here, as that gives the current + // velocity of the node, which is zero after creation of the node. + this.moving = true; + } + } + + this._reconnectEdges(); + this._updateValueRange(this.nodes); +}; + +/** + * Update existing nodes, or create them when not yet existing + * @param {Number[] | String[]} ids + * @private + */ +Graph.prototype._updateNodes = function(ids) { + var nodes = this.nodes, + nodesData = this.nodesData; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + var node = nodes[id]; + var data = nodesData.get(id); + if (node) { + // update node + node.setProperties(data, this.constants); + } + else { + // create node + node = new Node(properties, this.images, this.groups, this.constants); + nodes[id] = node; + + if (!node.isFixed()) { + this.moving = true; + } + } + } + + this._reconnectEdges(); + this._updateValueRange(nodes); +}; + +/** + * Remove existing nodes. If nodes do not exist, the method will just ignore it. + * @param {Number[] | String[]} ids + * @private + */ +Graph.prototype._removeNodes = function(ids) { + var nodes = this.nodes; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + delete nodes[id]; + } + + this._reconnectEdges(); + this._updateSelection(); + this._updateValueRange(nodes); +}; + +/** + * Load edges by reading the data table + * @param {Array | DataSet | DataView} edges The data containing the edges. + * @private + * @private + */ +Graph.prototype._setEdges = function(edges) { + var oldEdgesData = this.edgesData; + + if (edges instanceof DataSet || edges instanceof DataView) { + this.edgesData = edges; + } + else if (edges instanceof Array) { + this.edgesData = new DataSet(); + this.edgesData.add(edges); + } + else if (!edges) { + this.edgesData = new DataSet(); + } + else { + throw new TypeError('Array or DataSet expected'); + } + + if (oldEdgesData) { + // unsubscribe from old dataset + util.forEach(this.edgesListeners, function (callback, event) { + oldEdgesData.unsubscribe(event, callback); + }); + } + + // remove drawn edges + this.edges = {}; + + if (this.edgesData) { + // subscribe to new dataset + var me = this; + util.forEach(this.edgesListeners, function (callback, event) { + me.edgesData.subscribe(event, callback); + }); + + // draw all new nodes + var ids = this.edgesData.getIds(); + this._addEdges(ids); + } + + this._reconnectEdges(); +}; + +/** + * Add edges + * @param {Number[] | String[]} ids + * @private + */ +Graph.prototype._addEdges = function (ids) { + var edges = this.edges, + edgesData = this.edgesData; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + + var oldEdge = edges[id]; + if (oldEdge) { + oldEdge.disconnect(); + } + + var data = edgesData.get(id); + edges[id] = new Edge(data, this, this.constants); + } + + this.moving = true; + this._updateValueRange(edges); +}; + +/** + * Update existing edges, or create them when not yet existing + * @param {Number[] | String[]} ids + * @private + */ +Graph.prototype._updateEdges = function (ids) { + var edges = this.edges, + edgesData = this.edgesData; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + + var data = edgesData.get(id); + var edge = edges[id]; + if (edge) { + // update edge + edge.disconnect(); + edge.setProperties(data, this.constants); + edge.connect(); + } + else { + // create edge + edge = new Edge(data, this, this.constants); + this.edges[id] = edge; + } + } + + this.moving = true; + this._updateValueRange(edges); +}; + +/** + * Remove existing edges. Non existing ids will be ignored + * @param {Number[] | String[]} ids + * @private + */ +Graph.prototype._removeEdges = function (ids) { + var edges = this.edges; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + var edge = edges[id]; + if (edge) { + edge.disconnect(); + delete edges[id]; + } + } + + this.moving = true; + this._updateValueRange(edges); +}; + +/** + * Reconnect all edges + * @private + */ +Graph.prototype._reconnectEdges = function() { + var id, + nodes = this.nodes, + edges = this.edges; + for (id in nodes) { + if (nodes.hasOwnProperty(id)) { + nodes[id].edges = []; + } + } + + for (id in edges) { + if (edges.hasOwnProperty(id)) { + var edge = edges[id]; + edge.from = null; + edge.to = null; + edge.connect(); + } + } +}; + +/** + * Update the values of all object in the given array according to the current + * value range of the objects in the array. + * @param {Object} obj An object containing a set of Edges or Nodes + * The objects must have a method getValue() and + * setValueRange(min, max). + * @private + */ +Graph.prototype._updateValueRange = function(obj) { + var id; + + // determine the range of the objects + var valueMin = undefined; + var valueMax = undefined; + for (id in obj) { + if (obj.hasOwnProperty(id)) { + var value = obj[id].getValue(); + if (value !== undefined) { + valueMin = (valueMin === undefined) ? value : Math.min(value, valueMin); + valueMax = (valueMax === undefined) ? value : Math.max(value, valueMax); + } + } + } + + // adjust the range of all objects + if (valueMin !== undefined && valueMax !== undefined) { + for (id in obj) { + if (obj.hasOwnProperty(id)) { + obj[id].setValueRange(valueMin, valueMax); + } + } + } +}; + +/** + * Redraw the graph with the current data + * chart will be resized too. + */ +Graph.prototype.redraw = function() { + this.setSize(this.width, this.height); + + this._redraw(); +}; + +/** + * Redraw the graph with the current data + * @private + */ +Graph.prototype._redraw = function() { + var ctx = this.frame.canvas.getContext('2d'); + + // clear the canvas + var w = this.frame.canvas.width; + var h = this.frame.canvas.height; + ctx.clearRect(0, 0, w, h); + + // set scaling and translation + ctx.save(); + ctx.translate(this.translation.x, this.translation.y); + ctx.scale(this.scale, this.scale); + + this._drawEdges(ctx); + this._drawNodes(ctx); + + // restore original scaling and translation + ctx.restore(); +}; + +/** + * Set the translation of the graph + * @param {Number} offsetX Horizontal offset + * @param {Number} offsetY Vertical offset + * @private + */ +Graph.prototype._setTranslation = function(offsetX, offsetY) { + if (this.translation === undefined) { + this.translation = { + x: 0, + y: 0 + }; + } + + if (offsetX !== undefined) { + this.translation.x = offsetX; + } + if (offsetY !== undefined) { + this.translation.y = offsetY; + } +}; + +/** + * Get the translation of the graph + * @return {Object} translation An object with parameters x and y, both a number + * @private + */ +Graph.prototype._getTranslation = function() { + return { + x: this.translation.x, + y: this.translation.y + }; +}; + +/** + * Scale the graph + * @param {Number} scale Scaling factor 1.0 is unscaled + * @private + */ +Graph.prototype._setScale = function(scale) { + this.scale = scale; +}; +/** + * Get the current scale of the graph + * @return {Number} scale Scaling factor 1.0 is unscaled + * @private + */ +Graph.prototype._getScale = function() { + return this.scale; +}; + +/** + * Convert a horizontal point on the HTML canvas to the x-value of the model + * @param {number} x + * @returns {number} + * @private + */ +Graph.prototype._canvasToX = function(x) { + return (x - this.translation.x) / this.scale; +}; + +/** + * Convert an x-value in the model to a horizontal point on the HTML canvas + * @param {number} x + * @returns {number} + * @private + */ +Graph.prototype._xToCanvas = function(x) { + return x * this.scale + this.translation.x; +}; + +/** + * Convert a vertical point on the HTML canvas to the y-value of the model + * @param {number} y + * @returns {number} + * @private + */ +Graph.prototype._canvasToY = function(y) { + return (y - this.translation.y) / this.scale; +}; + +/** + * Convert an y-value in the model to a vertical point on the HTML canvas + * @param {number} y + * @returns {number} + * @private + */ +Graph.prototype._yToCanvas = function(y) { + return y * this.scale + this.translation.y ; +}; + +/** + * Redraw all nodes + * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); + * @param {CanvasRenderingContext2D} ctx + * @private + */ +Graph.prototype._drawNodes = function(ctx) { + // first draw the unselected nodes + var nodes = this.nodes; + var selected = []; + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + if (nodes[id].isSelected()) { + selected.push(id); + } + else { + nodes[id].draw(ctx); + } + } + } + + // draw the selected nodes on top + for (var s = 0, sMax = selected.length; s < sMax; s++) { + nodes[selected[s]].draw(ctx); + } +}; + +/** + * Redraw all edges + * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); + * @param {CanvasRenderingContext2D} ctx + * @private + */ +Graph.prototype._drawEdges = function(ctx) { + var edges = this.edges; + for (var id in edges) { + if (edges.hasOwnProperty(id)) { + var edge = edges[id]; + if (edge.connected) { + edges[id].draw(ctx); + } + } + } +}; + +/** + * Find a stable position for all nodes + * @private + */ +Graph.prototype._doStabilize = function() { + var start = new Date(); + + // find stable position + var count = 0; + var vmin = this.constants.minVelocity; + var stable = false; + while (!stable && count < this.constants.maxIterations) { + this._calculateForces(); + this._discreteStepNodes(); + stable = !this._isMoving(vmin); + count++; + } + + var end = new Date(); + + // console.log('Stabilized in ' + (end-start) + ' ms, ' + count + ' iterations' ); // TODO: cleanup +}; + +/** + * Calculate the external forces acting on the nodes + * Forces are caused by: edges, repulsing forces between nodes, gravity + * @private + */ +Graph.prototype._calculateForces = function() { + // create a local edge to the nodes and edges, that is faster + var id, dx, dy, angle, distance, fx, fy, + repulsingForce, springForce, length, edgeLength, + nodes = this.nodes, + edges = this.edges; + + // gravity, add a small constant force to pull the nodes towards the center of + // the graph + // Also, the forces are reset to zero in this loop by using _setForce instead + // of _addForce + var gravity = 0.01, + gx = this.frame.canvas.clientWidth / 2, + gy = this.frame.canvas.clientHeight / 2; + for (id in nodes) { + if (nodes.hasOwnProperty(id)) { + var node = nodes[id]; + dx = gx - node.x; + dy = gy - node.y; + angle = Math.atan2(dy, dx); + fx = Math.cos(angle) * gravity; + fy = Math.sin(angle) * gravity; + + node._setForce(fx, fy); + } + } + + // repulsing forces between nodes + var minimumDistance = this.constants.nodes.distance, + steepness = 10; // higher value gives steeper slope of the force around the given minimumDistance + + for (var id1 in nodes) { + if (nodes.hasOwnProperty(id1)) { + var node1 = nodes[id1]; + for (var id2 in nodes) { + if (nodes.hasOwnProperty(id2)) { + var node2 = nodes[id2]; + // calculate normally distributed force + dx = node2.x - node1.x; + dy = node2.y - node1.y; + distance = Math.sqrt(dx * dx + dy * dy); + angle = Math.atan2(dy, dx); + + // TODO: correct factor for repulsing force + //repulsingForce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force + //repulsingForce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force + repulsingForce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)); // TODO: customize the repulsing force + fx = Math.cos(angle) * repulsingForce; + fy = Math.sin(angle) * repulsingForce; + + node1._addForce(-fx, -fy); + node2._addForce(fx, fy); + } + } + } + } + + /* TODO: re-implement repulsion of edges + for (var n = 0; n < nodes.length; n++) { + for (var l = 0; l < edges.length; l++) { + var lx = edges[l].from.x+(edges[l].to.x - edges[l].from.x)/2, + ly = edges[l].from.y+(edges[l].to.y - edges[l].from.y)/2, + + // calculate normally distributed force + dx = nodes[n].x - lx, + dy = nodes[n].y - ly, + distance = Math.sqrt(dx * dx + dy * dy), + angle = Math.atan2(dy, dx), + + + // TODO: correct factor for repulsing force + //var repulsingforce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force + //repulsingforce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ), // TODO: customize the repulsing force + repulsingforce = 1 / (1 + Math.exp((distance / (minimumDistance / 2) - 1) * steepness)), // TODO: customize the repulsing force + fx = Math.cos(angle) * repulsingforce, + fy = Math.sin(angle) * repulsingforce; + nodes[n]._addForce(fx, fy); + edges[l].from._addForce(-fx/2,-fy/2); + edges[l].to._addForce(-fx/2,-fy/2); + } + } + */ + + // forces caused by the edges, modelled as springs + for (id in edges) { + if (edges.hasOwnProperty(id)) { + var edge = edges[id]; + if (edge.connected) { + dx = (edge.to.x - edge.from.x); + dy = (edge.to.y - edge.from.y); + //edgeLength = (edge.from.width + edge.from.height + edge.to.width + edge.to.height)/2 || edge.length; // TODO: dmin + //edgeLength = (edge.from.width + edge.to.width)/2 || edge.length; // TODO: dmin + //edgeLength = 20 + ((edge.from.width + edge.to.width) || 0) / 2; + edgeLength = edge.length; + length = Math.sqrt(dx * dx + dy * dy); + angle = Math.atan2(dy, dx); + + springForce = edge.stiffness * (edgeLength - length); + + fx = Math.cos(angle) * springForce; + fy = Math.sin(angle) * springForce; + + edge.from._addForce(-fx, -fy); + edge.to._addForce(fx, fy); + } + } + } + + /* TODO: re-implement repulsion of edges + // repulsing forces between edges + var minimumDistance = this.constants.edges.distance, + steepness = 10; // higher value gives steeper slope of the force around the given minimumDistance + for (var l = 0; l < edges.length; l++) { + //Keep distance from other edge centers + for (var l2 = l + 1; l2 < this.edges.length; l2++) { + //var dmin = (nodes[n].width + nodes[n].height + nodes[n2].width + nodes[n2].height) / 1 || minimumDistance, // TODO: dmin + //var dmin = (nodes[n].width + nodes[n2].width)/2 || minimumDistance, // TODO: dmin + //dmin = 40 + ((nodes[n].width/2 + nodes[n2].width/2) || 0), + var lx = edges[l].from.x+(edges[l].to.x - edges[l].from.x)/2, + ly = edges[l].from.y+(edges[l].to.y - edges[l].from.y)/2, + l2x = edges[l2].from.x+(edges[l2].to.x - edges[l2].from.x)/2, + l2y = edges[l2].from.y+(edges[l2].to.y - edges[l2].from.y)/2, + + // calculate normally distributed force + dx = l2x - lx, + dy = l2y - ly, + distance = Math.sqrt(dx * dx + dy * dy), + angle = Math.atan2(dy, dx), + + + // TODO: correct factor for repulsing force + //var repulsingforce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force + //repulsingforce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ), // TODO: customize the repulsing force + repulsingforce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)), // TODO: customize the repulsing force + fx = Math.cos(angle) * repulsingforce, + fy = Math.sin(angle) * repulsingforce; + + edges[l].from._addForce(-fx, -fy); + edges[l].to._addForce(-fx, -fy); + edges[l2].from._addForce(fx, fy); + edges[l2].to._addForce(fx, fy); + } + } + */ +}; + + +/** + * Check if any of the nodes is still moving + * @param {number} vmin the minimum velocity considered as 'moving' + * @return {boolean} true if moving, false if non of the nodes is moving + * @private + */ +Graph.prototype._isMoving = function(vmin) { + // TODO: ismoving does not work well: should check the kinetic energy, not its velocity + var nodes = this.nodes; + for (var id in nodes) { + if (nodes.hasOwnProperty(id) && nodes[id].isMoving(vmin)) { + return true; + } + } + return false; +}; + + +/** + * Perform one discrete step for all nodes + * @private + */ +Graph.prototype._discreteStepNodes = function() { + var interval = this.refreshRate / 1000.0; // in seconds + var nodes = this.nodes; + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + nodes[id].discreteStep(interval); + } + } +}; + +/** + * Start animating nodes and edges + */ +Graph.prototype.start = function() { + if (this.moving) { + this._calculateForces(); + this._discreteStepNodes(); + + var vmin = this.constants.minVelocity; + this.moving = this._isMoving(vmin); + } + + if (this.moving) { + // start animation. only start timer if it is not already running + if (!this.timer) { + var graph = this; + this.timer = window.setTimeout(function () { + graph.timer = undefined; + graph.start(); + graph._redraw(); + }, this.refreshRate); + } + } + else { + this._redraw(); + } +}; + +/** + * Stop animating nodes and edges. + */ +Graph.prototype.stop = function () { + if (this.timer) { + window.clearInterval(this.timer); + this.timer = undefined; + } +}; + +/** + * vis.js module exports + */ +var vis = { + util: util, + events: events, + + Controller: Controller, + DataSet: DataSet, + DataView: DataView, + Range: Range, + Stack: Stack, + TimeStep: TimeStep, + EventBus: EventBus, + + components: { + items: { + Item: Item, + ItemBox: ItemBox, + ItemPoint: ItemPoint, + ItemRange: ItemRange + }, + + Component: Component, + Panel: Panel, + RootPanel: RootPanel, + ItemSet: ItemSet, + TimeAxis: TimeAxis + }, + + graph: { + Node: Node, + Edge: Edge, + Popup: Popup, + Groups: Groups, + Images: Images + }, + + Timeline: Timeline, + Graph: Graph +}; + +/** + * CommonJS module exports + */ +if (typeof exports !== 'undefined') { + exports = vis; +} +if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { + module.exports = vis; +} + +/** + * AMD module exports + */ +if (typeof(define) === 'function') { + define(function () { + return vis; + }); +} + +/** + * Window exports + */ +if (typeof window !== 'undefined') { + // attach the module to the window, load as a regular javascript file + window['vis'] = vis; +} + + +},{"hammerjs":2,"moment":3}],2:[function(require,module,exports){ +/*! Hammer.JS - v1.0.5 - 2013-04-07 + * http://eightmedia.github.com/hammer.js + * + * Copyright (c) 2013 Jorik Tangelder ; + * Licensed under the MIT license */ + +(function(window, undefined) { + 'use strict'; + +/** + * Hammer + * use this to create instances + * @param {HTMLElement} element + * @param {Object} options + * @returns {Hammer.Instance} + * @constructor + */ +var Hammer = function(element, options) { + return new Hammer.Instance(element, options || {}); +}; + +// default settings +Hammer.defaults = { + // add styles and attributes to the element to prevent the browser from doing + // its native behavior. this doesnt prevent the scrolling, but cancels + // the contextmenu, tap highlighting etc + // set to false to disable this + stop_browser_behavior: { + // this also triggers onselectstart=false for IE + userSelect: 'none', + // this makes the element blocking in IE10 >, you could experiment with the value + // see for more options this issue; https://github.com/EightMedia/hammer.js/issues/241 + touchAction: 'none', + touchCallout: 'none', + contentZooming: 'none', + userDrag: 'none', + tapHighlightColor: 'rgba(0,0,0,0)' + } + + // more settings are defined per gesture at gestures.js +}; + +// detect touchevents +Hammer.HAS_POINTEREVENTS = navigator.pointerEnabled || navigator.msPointerEnabled; +Hammer.HAS_TOUCHEVENTS = ('ontouchstart' in window); + +// dont use mouseevents on mobile devices +Hammer.MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i; +Hammer.NO_MOUSEEVENTS = Hammer.HAS_TOUCHEVENTS && navigator.userAgent.match(Hammer.MOBILE_REGEX); + +// eventtypes per touchevent (start, move, end) +// are filled by Hammer.event.determineEventTypes on setup +Hammer.EVENT_TYPES = {}; + +// direction defines +Hammer.DIRECTION_DOWN = 'down'; +Hammer.DIRECTION_LEFT = 'left'; +Hammer.DIRECTION_UP = 'up'; +Hammer.DIRECTION_RIGHT = 'right'; + +// pointer type +Hammer.POINTER_MOUSE = 'mouse'; +Hammer.POINTER_TOUCH = 'touch'; +Hammer.POINTER_PEN = 'pen'; + +// touch event defines +Hammer.EVENT_START = 'start'; +Hammer.EVENT_MOVE = 'move'; +Hammer.EVENT_END = 'end'; + +// hammer document where the base events are added at +Hammer.DOCUMENT = document; + +// plugins namespace +Hammer.plugins = {}; + +// if the window events are set... +Hammer.READY = false; + +/** + * setup events to detect gestures on the document + */ +function setup() { + if(Hammer.READY) { + return; + } + + // find what eventtypes we add listeners to + Hammer.event.determineEventTypes(); + + // Register all gestures inside Hammer.gestures + for(var name in Hammer.gestures) { + if(Hammer.gestures.hasOwnProperty(name)) { + Hammer.detection.register(Hammer.gestures[name]); + } + } + + // Add touch events on the document + Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_MOVE, Hammer.detection.detect); + Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_END, Hammer.detection.detect); + + // Hammer is ready...! + Hammer.READY = true; +} + +/** + * create new hammer instance + * all methods should return the instance itself, so it is chainable. + * @param {HTMLElement} element + * @param {Object} [options={}] + * @returns {Hammer.Instance} + * @constructor + */ +Hammer.Instance = function(element, options) { + var self = this; + + // setup HammerJS window events and register all gestures + // this also sets up the default options + setup(); + + this.element = element; + + // start/stop detection option + this.enabled = true; + + // merge options + this.options = Hammer.utils.extend( + Hammer.utils.extend({}, Hammer.defaults), + options || {}); + + // add some css to the element to prevent the browser from doing its native behavoir + if(this.options.stop_browser_behavior) { + Hammer.utils.stopDefaultBrowserBehavior(this.element, this.options.stop_browser_behavior); + } + + // start detection on touchstart + Hammer.event.onTouch(element, Hammer.EVENT_START, function(ev) { + if(self.enabled) { + Hammer.detection.startDetect(self, ev); + } + }); + + // return instance + return this; +}; + + +Hammer.Instance.prototype = { + /** + * bind events to the instance + * @param {String} gesture + * @param {Function} handler + * @returns {Hammer.Instance} + */ + on: function onEvent(gesture, handler){ + var gestures = gesture.split(' '); + for(var t=0; t 0 && eventType == Hammer.EVENT_END) { + eventType = Hammer.EVENT_MOVE; + } + // no touches, force the end event + else if(!count_touches) { + eventType = Hammer.EVENT_END; + } + + // because touchend has no touches, and we often want to use these in our gestures, + // we send the last move event as our eventData in touchend + if(!count_touches && last_move_event !== null) { + ev = last_move_event; + } + // store the last move event + else { + last_move_event = ev; + } + + // trigger the handler + handler.call(Hammer.detection, self.collectEventData(element, eventType, ev)); + + // remove pointerevent from list + if(Hammer.HAS_POINTEREVENTS && eventType == Hammer.EVENT_END) { + count_touches = Hammer.PointerEvent.updatePointer(eventType, ev); + } + } + + //debug(sourceEventType +" "+ eventType); + + // on the end we reset everything + if(!count_touches) { + last_move_event = null; + enable_detect = false; + touch_triggered = false; + Hammer.PointerEvent.reset(); + } + }); + }, + + + /** + * we have different events for each device/browser + * determine what we need and set them in the Hammer.EVENT_TYPES constant + */ + determineEventTypes: function determineEventTypes() { + // determine the eventtype we want to set + var types; + + // pointerEvents magic + if(Hammer.HAS_POINTEREVENTS) { + types = Hammer.PointerEvent.getEvents(); + } + // on Android, iOS, blackberry, windows mobile we dont want any mouseevents + else if(Hammer.NO_MOUSEEVENTS) { + types = [ + 'touchstart', + 'touchmove', + 'touchend touchcancel']; + } + // for non pointer events browsers and mixed browsers, + // like chrome on windows8 touch laptop + else { + types = [ + 'touchstart mousedown', + 'touchmove mousemove', + 'touchend touchcancel mouseup']; + } + + Hammer.EVENT_TYPES[Hammer.EVENT_START] = types[0]; + Hammer.EVENT_TYPES[Hammer.EVENT_MOVE] = types[1]; + Hammer.EVENT_TYPES[Hammer.EVENT_END] = types[2]; + }, + + + /** + * create touchlist depending on the event + * @param {Object} ev + * @param {String} eventType used by the fakemultitouch plugin + */ + getTouchList: function getTouchList(ev/*, eventType*/) { + // get the fake pointerEvent touchlist + if(Hammer.HAS_POINTEREVENTS) { + return Hammer.PointerEvent.getTouchList(); + } + // get the touchlist + else if(ev.touches) { + return ev.touches; + } + // make fake touchlist from mouse position + else { + return [{ + identifier: 1, + pageX: ev.pageX, + pageY: ev.pageY, + target: ev.target + }]; + } + }, + + + /** + * collect event data for Hammer js + * @param {HTMLElement} element + * @param {String} eventType like Hammer.EVENT_MOVE + * @param {Object} eventData + */ + collectEventData: function collectEventData(element, eventType, ev) { + var touches = this.getTouchList(ev, eventType); + + // find out pointerType + var pointerType = Hammer.POINTER_TOUCH; + if(ev.type.match(/mouse/) || Hammer.PointerEvent.matchType(Hammer.POINTER_MOUSE, ev)) { + pointerType = Hammer.POINTER_MOUSE; + } + + return { + center : Hammer.utils.getCenter(touches), + timeStamp : new Date().getTime(), + target : ev.target, + touches : touches, + eventType : eventType, + pointerType : pointerType, + srcEvent : ev, + + /** + * prevent the browser default actions + * mostly used to disable scrolling of the browser + */ + preventDefault: function() { + if(this.srcEvent.preventManipulation) { + this.srcEvent.preventManipulation(); + } + + if(this.srcEvent.preventDefault) { + this.srcEvent.preventDefault(); + } + }, + + /** + * stop bubbling the event up to its parents + */ + stopPropagation: function() { + this.srcEvent.stopPropagation(); + }, + + /** + * immediately stop gesture detection + * might be useful after a swipe was detected + * @return {*} + */ + stopDetect: function() { + return Hammer.detection.stopDetect(); + } + }; + } +}; + +Hammer.PointerEvent = { + /** + * holds all pointers + * @type {Object} + */ + pointers: {}, + + /** + * get a list of pointers + * @returns {Array} touchlist + */ + getTouchList: function() { + var self = this; + var touchlist = []; + + // we can use forEach since pointerEvents only is in IE10 + Object.keys(self.pointers).sort().forEach(function(id) { + touchlist.push(self.pointers[id]); + }); + return touchlist; + }, + + /** + * update the position of a pointer + * @param {String} type Hammer.EVENT_END + * @param {Object} pointerEvent + */ + updatePointer: function(type, pointerEvent) { + if(type == Hammer.EVENT_END) { + this.pointers = {}; + } + else { + pointerEvent.identifier = pointerEvent.pointerId; + this.pointers[pointerEvent.pointerId] = pointerEvent; + } + + return Object.keys(this.pointers).length; + }, + + /** + * check if ev matches pointertype + * @param {String} pointerType Hammer.POINTER_MOUSE + * @param {PointerEvent} ev + */ + matchType: function(pointerType, ev) { + if(!ev.pointerType) { + return false; + } + + var types = {}; + types[Hammer.POINTER_MOUSE] = (ev.pointerType == ev.MSPOINTER_TYPE_MOUSE || ev.pointerType == Hammer.POINTER_MOUSE); + types[Hammer.POINTER_TOUCH] = (ev.pointerType == ev.MSPOINTER_TYPE_TOUCH || ev.pointerType == Hammer.POINTER_TOUCH); + types[Hammer.POINTER_PEN] = (ev.pointerType == ev.MSPOINTER_TYPE_PEN || ev.pointerType == Hammer.POINTER_PEN); + return types[pointerType]; + }, + + + /** + * get events + */ + getEvents: function() { + return [ + 'pointerdown MSPointerDown', + 'pointermove MSPointerMove', + 'pointerup pointercancel MSPointerUp MSPointerCancel' + ]; + }, + + /** + * reset the list + */ + reset: function() { + this.pointers = {}; + } +}; + + +Hammer.utils = { + /** + * extend method, + * also used for cloning when dest is an empty object + * @param {Object} dest + * @param {Object} src + * @parm {Boolean} merge do a merge + * @returns {Object} dest + */ + extend: function extend(dest, src, merge) { + for (var key in src) { + if(dest[key] !== undefined && merge) { + continue; + } + dest[key] = src[key]; + } + return dest; + }, + + + /** + * find if a node is in the given parent + * used for event delegation tricks + * @param {HTMLElement} node + * @param {HTMLElement} parent + * @returns {boolean} has_parent + */ + hasParent: function(node, parent) { + while(node){ + if(node == parent) { + return true; + } + node = node.parentNode; + } + return false; + }, + + + /** + * get the center of all the touches + * @param {Array} touches + * @returns {Object} center + */ + getCenter: function getCenter(touches) { + var valuesX = [], valuesY = []; + + for(var t= 0,len=touches.length; t= y) { + return touch1.pageX - touch2.pageX > 0 ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT; + } + else { + return touch1.pageY - touch2.pageY > 0 ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN; + } + }, + + + /** + * calculate the distance between two touches + * @param {Touch} touch1 + * @param {Touch} touch2 + * @returns {Number} distance + */ + getDistance: function getDistance(touch1, touch2) { + var x = touch2.pageX - touch1.pageX, + y = touch2.pageY - touch1.pageY; + return Math.sqrt((x*x) + (y*y)); + }, + + + /** + * calculate the scale factor between two touchLists (fingers) + * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out + * @param {Array} start + * @param {Array} end + * @returns {Number} scale + */ + getScale: function getScale(start, end) { + // need two fingers... + if(start.length >= 2 && end.length >= 2) { + return this.getDistance(end[0], end[1]) / + this.getDistance(start[0], start[1]); + } + return 1; + }, + + + /** + * calculate the rotation degrees between two touchLists (fingers) + * @param {Array} start + * @param {Array} end + * @returns {Number} rotation + */ + getRotation: function getRotation(start, end) { + // need two fingers + if(start.length >= 2 && end.length >= 2) { + return this.getAngle(end[1], end[0]) - + this.getAngle(start[1], start[0]); + } + return 0; + }, + + + /** + * boolean if the direction is vertical + * @param {String} direction + * @returns {Boolean} is_vertical + */ + isVertical: function isVertical(direction) { + return (direction == Hammer.DIRECTION_UP || direction == Hammer.DIRECTION_DOWN); + }, + + + /** + * stop browser default behavior with css props + * @param {HtmlElement} element + * @param {Object} css_props + */ + stopDefaultBrowserBehavior: function stopDefaultBrowserBehavior(element, css_props) { + var prop, + vendors = ['webkit','khtml','moz','ms','o','']; + + if(!css_props || !element.style) { + return; + } + + // with css properties for modern browsers + for(var i = 0; i < vendors.length; i++) { + for(var p in css_props) { + if(css_props.hasOwnProperty(p)) { + prop = p; + + // vender prefix at the property + if(vendors[i]) { + prop = vendors[i] + prop.substring(0, 1).toUpperCase() + prop.substring(1); + } + + // set the style + element.style[prop] = css_props[p]; + } + } + } + + // also the disable onselectstart + if(css_props.userSelect == 'none') { + element.onselectstart = function() { + return false; + }; + } + } +}; + +Hammer.detection = { + // contains all registred Hammer.gestures in the correct order + gestures: [], + + // data of the current Hammer.gesture detection session + current: null, + + // the previous Hammer.gesture session data + // is a full clone of the previous gesture.current object + previous: null, + + // when this becomes true, no gestures are fired + stopped: false, + + + /** + * start Hammer.gesture detection + * @param {Hammer.Instance} inst + * @param {Object} eventData + */ + startDetect: function startDetect(inst, eventData) { + // already busy with a Hammer.gesture detection on an element + if(this.current) { + return; + } + + this.stopped = false; + + this.current = { + inst : inst, // reference to HammerInstance we're working for + startEvent : Hammer.utils.extend({}, eventData), // start eventData for distances, timing etc + lastEvent : false, // last eventData + name : '' // current gesture we're in/detected, can be 'tap', 'hold' etc + }; + + this.detect(eventData); + }, + + + /** + * Hammer.gesture detection + * @param {Object} eventData + * @param {Object} eventData + */ + detect: function detect(eventData) { + if(!this.current || this.stopped) { + return; + } + + // extend event data with calculations about scale, distance etc + eventData = this.extendEventData(eventData); + + // instance options + var inst_options = this.current.inst.options; + + // call Hammer.gesture handlers + for(var g=0,len=this.gestures.length; g b.index) { + return 1; + } + return 0; + }); + + return this.gestures; + } +}; + + +Hammer.gestures = Hammer.gestures || {}; + +/** + * Custom gestures + * ============================== + * + * Gesture object + * -------------------- + * The object structure of a gesture: + * + * { name: 'mygesture', + * index: 1337, + * defaults: { + * mygesture_option: true + * } + * handler: function(type, ev, inst) { + * // trigger gesture event + * inst.trigger(this.name, ev); + * } + * } + + * @param {String} name + * this should be the name of the gesture, lowercase + * it is also being used to disable/enable the gesture per instance config. + * + * @param {Number} [index=1000] + * the index of the gesture, where it is going to be in the stack of gestures detection + * like when you build an gesture that depends on the drag gesture, it is a good + * idea to place it after the index of the drag gesture. + * + * @param {Object} [defaults={}] + * the default settings of the gesture. these are added to the instance settings, + * and can be overruled per instance. you can also add the name of the gesture, + * but this is also added by default (and set to true). + * + * @param {Function} handler + * this handles the gesture detection of your custom gesture and receives the + * following arguments: + * + * @param {Object} eventData + * event data containing the following properties: + * timeStamp {Number} time the event occurred + * target {HTMLElement} target element + * touches {Array} touches (fingers, pointers, mouse) on the screen + * pointerType {String} kind of pointer that was used. matches Hammer.POINTER_MOUSE|TOUCH + * center {Object} center position of the touches. contains pageX and pageY + * deltaTime {Number} the total time of the touches in the screen + * deltaX {Number} the delta on x axis we haved moved + * deltaY {Number} the delta on y axis we haved moved + * velocityX {Number} the velocity on the x + * velocityY {Number} the velocity on y + * angle {Number} the angle we are moving + * direction {String} the direction we are moving. matches Hammer.DIRECTION_UP|DOWN|LEFT|RIGHT + * distance {Number} the distance we haved moved + * scale {Number} scaling of the touches, needs 2 touches + * rotation {Number} rotation of the touches, needs 2 touches * + * eventType {String} matches Hammer.EVENT_START|MOVE|END + * srcEvent {Object} the source event, like TouchStart or MouseDown * + * startEvent {Object} contains the same properties as above, + * but from the first touch. this is used to calculate + * distances, deltaTime, scaling etc + * + * @param {Hammer.Instance} inst + * the instance we are doing the detection for. you can get the options from + * the inst.options object and trigger the gesture event by calling inst.trigger + * + * + * Handle gestures + * -------------------- + * inside the handler you can get/set Hammer.detection.current. This is the current + * detection session. It has the following properties + * @param {String} name + * contains the name of the gesture we have detected. it has not a real function, + * only to check in other gestures if something is detected. + * like in the drag gesture we set it to 'drag' and in the swipe gesture we can + * check if the current gesture is 'drag' by accessing Hammer.detection.current.name + * + * @readonly + * @param {Hammer.Instance} inst + * the instance we do the detection for + * + * @readonly + * @param {Object} startEvent + * contains the properties of the first gesture detection in this session. + * Used for calculations about timing, distance, etc. + * + * @readonly + * @param {Object} lastEvent + * contains all the properties of the last gesture detect in this session. + * + * after the gesture detection session has been completed (user has released the screen) + * the Hammer.detection.current object is copied into Hammer.detection.previous, + * this is usefull for gestures like doubletap, where you need to know if the + * previous gesture was a tap + * + * options that have been set by the instance can be received by calling inst.options + * + * You can trigger a gesture event by calling inst.trigger("mygesture", event). + * The first param is the name of your gesture, the second the event argument + * + * + * Register gestures + * -------------------- + * When an gesture is added to the Hammer.gestures object, it is auto registered + * at the setup of the first Hammer instance. You can also call Hammer.detection.register + * manually and pass your gesture object as a param + * + */ + +/** + * Hold + * Touch stays at the same place for x time + * @events hold + */ +Hammer.gestures.Hold = { + name: 'hold', + index: 10, + defaults: { + hold_timeout : 500, + hold_threshold : 1 + }, + timer: null, + handler: function holdGesture(ev, inst) { + switch(ev.eventType) { + case Hammer.EVENT_START: + // clear any running timers + clearTimeout(this.timer); + + // set the gesture so we can check in the timeout if it still is + Hammer.detection.current.name = this.name; + + // set timer and if after the timeout it still is hold, + // we trigger the hold event + this.timer = setTimeout(function() { + if(Hammer.detection.current.name == 'hold') { + inst.trigger('hold', ev); + } + }, inst.options.hold_timeout); + break; + + // when you move or end we clear the timer + case Hammer.EVENT_MOVE: + if(ev.distance > inst.options.hold_threshold) { + clearTimeout(this.timer); + } + break; + + case Hammer.EVENT_END: + clearTimeout(this.timer); + break; + } + } +}; + + +/** + * Tap/DoubleTap + * Quick touch at a place or double at the same place + * @events tap, doubletap + */ +Hammer.gestures.Tap = { + name: 'tap', + index: 100, + defaults: { + tap_max_touchtime : 250, + tap_max_distance : 10, + tap_always : true, + doubletap_distance : 20, + doubletap_interval : 300 + }, + handler: function tapGesture(ev, inst) { + if(ev.eventType == Hammer.EVENT_END) { + // previous gesture, for the double tap since these are two different gesture detections + var prev = Hammer.detection.previous, + did_doubletap = false; + + // when the touchtime is higher then the max touch time + // or when the moving distance is too much + if(ev.deltaTime > inst.options.tap_max_touchtime || + ev.distance > inst.options.tap_max_distance) { + return; + } + + // check if double tap + if(prev && prev.name == 'tap' && + (ev.timeStamp - prev.lastEvent.timeStamp) < inst.options.doubletap_interval && + ev.distance < inst.options.doubletap_distance) { + inst.trigger('doubletap', ev); + did_doubletap = true; + } + + // do a single tap + if(!did_doubletap || inst.options.tap_always) { + Hammer.detection.current.name = 'tap'; + inst.trigger(Hammer.detection.current.name, ev); + } + } + } +}; + + +/** + * Swipe + * triggers swipe events when the end velocity is above the threshold + * @events swipe, swipeleft, swiperight, swipeup, swipedown + */ +Hammer.gestures.Swipe = { + name: 'swipe', + index: 40, + defaults: { + // set 0 for unlimited, but this can conflict with transform + swipe_max_touches : 1, + swipe_velocity : 0.7 + }, + handler: function swipeGesture(ev, inst) { + if(ev.eventType == Hammer.EVENT_END) { + // max touches + if(inst.options.swipe_max_touches > 0 && + ev.touches.length > inst.options.swipe_max_touches) { + return; + } + + // when the distance we moved is too small we skip this gesture + // or we can be already in dragging + if(ev.velocityX > inst.options.swipe_velocity || + ev.velocityY > inst.options.swipe_velocity) { + // trigger swipe events + inst.trigger(this.name, ev); + inst.trigger(this.name + ev.direction, ev); + } + } + } +}; + + +/** + * Drag + * Move with x fingers (default 1) around on the page. Blocking the scrolling when + * moving left and right is a good practice. When all the drag events are blocking + * you disable scrolling on that area. + * @events drag, drapleft, dragright, dragup, dragdown + */ +Hammer.gestures.Drag = { + name: 'drag', + index: 50, + defaults: { + drag_min_distance : 10, + // set 0 for unlimited, but this can conflict with transform + drag_max_touches : 1, + // prevent default browser behavior when dragging occurs + // be careful with it, it makes the element a blocking element + // when you are using the drag gesture, it is a good practice to set this true + drag_block_horizontal : false, + drag_block_vertical : false, + // drag_lock_to_axis keeps the drag gesture on the axis that it started on, + // It disallows vertical directions if the initial direction was horizontal, and vice versa. + drag_lock_to_axis : false, + // drag lock only kicks in when distance > drag_lock_min_distance + // This way, locking occurs only when the distance has become large enough to reliably determine the direction + drag_lock_min_distance : 25 + }, + triggered: false, + handler: function dragGesture(ev, inst) { + // current gesture isnt drag, but dragged is true + // this means an other gesture is busy. now call dragend + if(Hammer.detection.current.name != this.name && this.triggered) { + inst.trigger(this.name +'end', ev); + this.triggered = false; + return; + } + + // max touches + if(inst.options.drag_max_touches > 0 && + ev.touches.length > inst.options.drag_max_touches) { + return; + } + + switch(ev.eventType) { + case Hammer.EVENT_START: + this.triggered = false; + break; + + case Hammer.EVENT_MOVE: + // when the distance we moved is too small we skip this gesture + // or we can be already in dragging + if(ev.distance < inst.options.drag_min_distance && + Hammer.detection.current.name != this.name) { + return; + } + + // we are dragging! + Hammer.detection.current.name = this.name; + + // lock drag to axis? + if(Hammer.detection.current.lastEvent.drag_locked_to_axis || (inst.options.drag_lock_to_axis && inst.options.drag_lock_min_distance<=ev.distance)) { + ev.drag_locked_to_axis = true; + } + var last_direction = Hammer.detection.current.lastEvent.direction; + if(ev.drag_locked_to_axis && last_direction !== ev.direction) { + // keep direction on the axis that the drag gesture started on + if(Hammer.utils.isVertical(last_direction)) { + ev.direction = (ev.deltaY < 0) ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN; + } + else { + ev.direction = (ev.deltaX < 0) ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT; + } + } + + // first time, trigger dragstart event + if(!this.triggered) { + inst.trigger(this.name +'start', ev); + this.triggered = true; + } + + // trigger normal event + inst.trigger(this.name, ev); + + // direction event, like dragdown + inst.trigger(this.name + ev.direction, ev); + + // block the browser events + if( (inst.options.drag_block_vertical && Hammer.utils.isVertical(ev.direction)) || + (inst.options.drag_block_horizontal && !Hammer.utils.isVertical(ev.direction))) { + ev.preventDefault(); + } + break; + + case Hammer.EVENT_END: + // trigger dragend + if(this.triggered) { + inst.trigger(this.name +'end', ev); + } + + this.triggered = false; + break; + } + } +}; + + +/** + * Transform + * User want to scale or rotate with 2 fingers + * @events transform, pinch, pinchin, pinchout, rotate + */ +Hammer.gestures.Transform = { + name: 'transform', + index: 45, + defaults: { + // factor, no scale is 1, zoomin is to 0 and zoomout until higher then 1 + transform_min_scale : 0.01, + // rotation in degrees + transform_min_rotation : 1, + // prevent default browser behavior when two touches are on the screen + // but it makes the element a blocking element + // when you are using the transform gesture, it is a good practice to set this true + transform_always_block : false + }, + triggered: false, + handler: function transformGesture(ev, inst) { + // current gesture isnt drag, but dragged is true + // this means an other gesture is busy. now call dragend + if(Hammer.detection.current.name != this.name && this.triggered) { + inst.trigger(this.name +'end', ev); + this.triggered = false; + return; + } + + // atleast multitouch + if(ev.touches.length < 2) { + return; + } + + // prevent default when two fingers are on the screen + if(inst.options.transform_always_block) { + ev.preventDefault(); + } + + switch(ev.eventType) { + case Hammer.EVENT_START: + this.triggered = false; + break; + + case Hammer.EVENT_MOVE: + var scale_threshold = Math.abs(1-ev.scale); + var rotation_threshold = Math.abs(ev.rotation); + + // when the distance we moved is too small we skip this gesture + // or we can be already in dragging + if(scale_threshold < inst.options.transform_min_scale && + rotation_threshold < inst.options.transform_min_rotation) { + return; + } + + // we are transforming! + Hammer.detection.current.name = this.name; + + // first time, trigger dragstart event + if(!this.triggered) { + inst.trigger(this.name +'start', ev); + this.triggered = true; + } + + inst.trigger(this.name, ev); // basic transform event + + // trigger rotate event + if(rotation_threshold > inst.options.transform_min_rotation) { + inst.trigger('rotate', ev); + } + + // trigger pinch event + if(scale_threshold > inst.options.transform_min_scale) { + inst.trigger('pinch', ev); + inst.trigger('pinch'+ ((ev.scale < 1) ? 'in' : 'out'), ev); + } + break; + + case Hammer.EVENT_END: + // trigger dragend + if(this.triggered) { + inst.trigger(this.name +'end', ev); + } + + this.triggered = false; + break; + } + } +}; + + +/** + * Touch + * Called as first, tells the user has touched the screen + * @events touch + */ +Hammer.gestures.Touch = { + name: 'touch', + index: -Infinity, + defaults: { + // call preventDefault at touchstart, and makes the element blocking by + // disabling the scrolling of the page, but it improves gestures like + // transforming and dragging. + // be careful with using this, it can be very annoying for users to be stuck + // on the page + prevent_default: false, + + // disable mouse events, so only touch (or pen!) input triggers events + prevent_mouseevents: false + }, + handler: function touchGesture(ev, inst) { + if(inst.options.prevent_mouseevents && ev.pointerType == Hammer.POINTER_MOUSE) { + ev.stopDetect(); + return; + } + + if(inst.options.prevent_default) { + ev.preventDefault(); + } + + if(ev.eventType == Hammer.EVENT_START) { + inst.trigger(this.name, ev); + } + } +}; + + +/** + * Release + * Called as last, tells the user has released the screen + * @events release + */ +Hammer.gestures.Release = { + name: 'release', + index: Infinity, + handler: function releaseGesture(ev, inst) { + if(ev.eventType == Hammer.EVENT_END) { + inst.trigger(this.name, ev); + } + } +}; + +// node export +if(typeof module === 'object' && typeof module.exports === 'object'){ + module.exports = Hammer; +} +// just window export +else { + window.Hammer = Hammer; + + // requireJS module definition + if(typeof window.define === 'function' && window.define.amd) { + window.define('hammer', [], function() { + return Hammer; + }); + } +} +})(this); +},{}],3:[function(require,module,exports){ +//! moment.js +//! version : 2.5.0 +//! authors : Tim Wood, Iskren Chernev, Moment.js contributors +//! license : MIT +//! momentjs.com + +(function (undefined) { + + /************************************ + Constants + ************************************/ + + var moment, + VERSION = "2.5.0", + global = this, + round = Math.round, + i, + + YEAR = 0, + MONTH = 1, + DATE = 2, + HOUR = 3, + MINUTE = 4, + SECOND = 5, + MILLISECOND = 6, + + // internal storage for language config files + languages = {}, + + // check for nodeJS + hasModule = (typeof module !== 'undefined' && module.exports && typeof require !== 'undefined'), + + // ASP.NET json date format regex + aspNetJsonRegex = /^\/?Date\((\-?\d+)/i, + aspNetTimeSpanJsonRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/, + + // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html + // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere + isoDurationRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/, + + // format tokens + formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g, + localFormattingTokens = /(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g, + + // parsing token regexes + parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99 + parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999 + parseTokenOneToFourDigits = /\d{1,4}/, // 0 - 9999 + parseTokenOneToSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999 + parseTokenDigits = /\d+/, // nonzero number of digits + parseTokenWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, // any word (or two) characters or numbers including two/three word month in arabic. + parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z + parseTokenT = /T/i, // T (ISO separator) + parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123 + + //strict parsing regexes + parseTokenOneDigit = /\d/, // 0 - 9 + parseTokenTwoDigits = /\d\d/, // 00 - 99 + parseTokenThreeDigits = /\d{3}/, // 000 - 999 + parseTokenFourDigits = /\d{4}/, // 0000 - 9999 + parseTokenSixDigits = /[+\-]?\d{6}/, // -999,999 - 999,999 + + // iso 8601 regex + // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00) + isoRegex = /^\s*\d{4}-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/, + + isoFormat = 'YYYY-MM-DDTHH:mm:ssZ', + + isoDates = [ + 'YYYY-MM-DD', + 'GGGG-[W]WW', + 'GGGG-[W]WW-E', + 'YYYY-DDD' + ], + + // iso time formats and regexes + isoTimes = [ + ['HH:mm:ss.SSSS', /(T| )\d\d:\d\d:\d\d\.\d{1,3}/], + ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/], + ['HH:mm', /(T| )\d\d:\d\d/], + ['HH', /(T| )\d\d/] + ], + + // timezone chunker "+10:00" > ["10", "00"] or "-1530" > ["-15", "30"] + parseTimezoneChunker = /([\+\-]|\d\d)/gi, + + // getter and setter names + proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'), + unitMillisecondFactors = { + 'Milliseconds' : 1, + 'Seconds' : 1e3, + 'Minutes' : 6e4, + 'Hours' : 36e5, + 'Days' : 864e5, + 'Months' : 2592e6, + 'Years' : 31536e6 + }, + + unitAliases = { + ms : 'millisecond', + s : 'second', + m : 'minute', + h : 'hour', + d : 'day', + D : 'date', + w : 'week', + W : 'isoWeek', + M : 'month', + y : 'year', + DDD : 'dayOfYear', + e : 'weekday', + E : 'isoWeekday', + gg: 'weekYear', + GG: 'isoWeekYear' + }, + + camelFunctions = { + dayofyear : 'dayOfYear', + isoweekday : 'isoWeekday', + isoweek : 'isoWeek', + weekyear : 'weekYear', + isoweekyear : 'isoWeekYear' + }, + + // format function strings + formatFunctions = {}, + + // tokens to ordinalize and pad + ordinalizeTokens = 'DDD w W M D d'.split(' '), + paddedTokens = 'M D H h m s w W'.split(' '), + + formatTokenFunctions = { + M : function () { + return this.month() + 1; + }, + MMM : function (format) { + return this.lang().monthsShort(this, format); + }, + MMMM : function (format) { + return this.lang().months(this, format); + }, + D : function () { + return this.date(); + }, + DDD : function () { + return this.dayOfYear(); + }, + d : function () { + return this.day(); + }, + dd : function (format) { + return this.lang().weekdaysMin(this, format); + }, + ddd : function (format) { + return this.lang().weekdaysShort(this, format); + }, + dddd : function (format) { + return this.lang().weekdays(this, format); + }, + w : function () { + return this.week(); + }, + W : function () { + return this.isoWeek(); + }, + YY : function () { + return leftZeroFill(this.year() % 100, 2); + }, + YYYY : function () { + return leftZeroFill(this.year(), 4); + }, + YYYYY : function () { + return leftZeroFill(this.year(), 5); + }, + YYYYYY : function () { + var y = this.year(), sign = y >= 0 ? '+' : '-'; + return sign + leftZeroFill(Math.abs(y), 6); + }, + gg : function () { + return leftZeroFill(this.weekYear() % 100, 2); + }, + gggg : function () { + return this.weekYear(); + }, + ggggg : function () { + return leftZeroFill(this.weekYear(), 5); + }, + GG : function () { + return leftZeroFill(this.isoWeekYear() % 100, 2); + }, + GGGG : function () { + return this.isoWeekYear(); + }, + GGGGG : function () { + return leftZeroFill(this.isoWeekYear(), 5); + }, + e : function () { + return this.weekday(); + }, + E : function () { + return this.isoWeekday(); + }, + a : function () { + return this.lang().meridiem(this.hours(), this.minutes(), true); + }, + A : function () { + return this.lang().meridiem(this.hours(), this.minutes(), false); + }, + H : function () { + return this.hours(); + }, + h : function () { + return this.hours() % 12 || 12; + }, + m : function () { + return this.minutes(); + }, + s : function () { + return this.seconds(); + }, + S : function () { + return toInt(this.milliseconds() / 100); + }, + SS : function () { + return leftZeroFill(toInt(this.milliseconds() / 10), 2); + }, + SSS : function () { + return leftZeroFill(this.milliseconds(), 3); + }, + SSSS : function () { + return leftZeroFill(this.milliseconds(), 3); + }, + Z : function () { + var a = -this.zone(), + b = "+"; + if (a < 0) { + a = -a; + b = "-"; + } + return b + leftZeroFill(toInt(a / 60), 2) + ":" + leftZeroFill(toInt(a) % 60, 2); + }, + ZZ : function () { + var a = -this.zone(), + b = "+"; + if (a < 0) { + a = -a; + b = "-"; + } + return b + leftZeroFill(toInt(a / 60), 2) + leftZeroFill(toInt(a) % 60, 2); + }, + z : function () { + return this.zoneAbbr(); + }, + zz : function () { + return this.zoneName(); + }, + X : function () { + return this.unix(); + }, + Q : function () { + return this.quarter(); + } + }, + + lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin']; + + function padToken(func, count) { + return function (a) { + return leftZeroFill(func.call(this, a), count); + }; + } + function ordinalizeToken(func, period) { + return function (a) { + return this.lang().ordinal(func.call(this, a), period); + }; + } + + while (ordinalizeTokens.length) { + i = ordinalizeTokens.pop(); + formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i); + } + while (paddedTokens.length) { + i = paddedTokens.pop(); + formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2); + } + formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3); + + + /************************************ + Constructors + ************************************/ + + function Language() { + + } + + // Moment prototype object + function Moment(config) { + checkOverflow(config); + extend(this, config); + } + + // Duration Constructor + function Duration(duration) { + var normalizedInput = normalizeObjectUnits(duration), + years = normalizedInput.year || 0, + months = normalizedInput.month || 0, + weeks = normalizedInput.week || 0, + days = normalizedInput.day || 0, + hours = normalizedInput.hour || 0, + minutes = normalizedInput.minute || 0, + seconds = normalizedInput.second || 0, + milliseconds = normalizedInput.millisecond || 0; + + // representation for dateAddRemove + this._milliseconds = +milliseconds + + seconds * 1e3 + // 1000 + minutes * 6e4 + // 1000 * 60 + hours * 36e5; // 1000 * 60 * 60 + // Because of dateAddRemove treats 24 hours as different from a + // day when working around DST, we need to store them separately + this._days = +days + + weeks * 7; + // It is impossible translate months into days without knowing + // which months you are are talking about, so we have to store + // it separately. + this._months = +months + + years * 12; + + this._data = {}; + + this._bubble(); + } + + /************************************ + Helpers + ************************************/ + + + function extend(a, b) { + for (var i in b) { + if (b.hasOwnProperty(i)) { + a[i] = b[i]; + } + } + + if (b.hasOwnProperty("toString")) { + a.toString = b.toString; + } + + if (b.hasOwnProperty("valueOf")) { + a.valueOf = b.valueOf; + } + + return a; + } + + function absRound(number) { + if (number < 0) { + return Math.ceil(number); + } else { + return Math.floor(number); + } + } + + // left zero fill a number + // see http://jsperf.com/left-zero-filling for performance comparison + function leftZeroFill(number, targetLength, forceSign) { + var output = Math.abs(number) + '', + sign = number >= 0; + + while (output.length < targetLength) { + output = '0' + output; + } + return (sign ? (forceSign ? '+' : '') : '-') + output; + } + + // helper function for _.addTime and _.subtractTime + function addOrSubtractDurationFromMoment(mom, duration, isAdding, ignoreUpdateOffset) { + var milliseconds = duration._milliseconds, + days = duration._days, + months = duration._months, + minutes, + hours; + + if (milliseconds) { + mom._d.setTime(+mom._d + milliseconds * isAdding); + } + // store the minutes and hours so we can restore them + if (days || months) { + minutes = mom.minute(); + hours = mom.hour(); + } + if (days) { + mom.date(mom.date() + days * isAdding); + } + if (months) { + mom.month(mom.month() + months * isAdding); + } + if (milliseconds && !ignoreUpdateOffset) { + moment.updateOffset(mom); + } + // restore the minutes and hours after possibly changing dst + if (days || months) { + mom.minute(minutes); + mom.hour(hours); + } + } + + // check if is an array + function isArray(input) { + return Object.prototype.toString.call(input) === '[object Array]'; + } + + function isDate(input) { + return Object.prototype.toString.call(input) === '[object Date]' || + input instanceof Date; + } + + // compare two arrays, return the number of differences + function compareArrays(array1, array2, dontConvert) { + var len = Math.min(array1.length, array2.length), + lengthDiff = Math.abs(array1.length - array2.length), + diffs = 0, + i; + for (i = 0; i < len; i++) { + if ((dontConvert && array1[i] !== array2[i]) || + (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) { + diffs++; + } + } + return diffs + lengthDiff; + } + + function normalizeUnits(units) { + if (units) { + var lowered = units.toLowerCase().replace(/(.)s$/, '$1'); + units = unitAliases[units] || camelFunctions[lowered] || lowered; + } + return units; + } + + function normalizeObjectUnits(inputObject) { + var normalizedInput = {}, + normalizedProp, + prop; + + for (prop in inputObject) { + if (inputObject.hasOwnProperty(prop)) { + normalizedProp = normalizeUnits(prop); + if (normalizedProp) { + normalizedInput[normalizedProp] = inputObject[prop]; + } + } + } + + return normalizedInput; + } + + function makeList(field) { + var count, setter; + + if (field.indexOf('week') === 0) { + count = 7; + setter = 'day'; + } + else if (field.indexOf('month') === 0) { + count = 12; + setter = 'month'; + } + else { + return; + } + + moment[field] = function (format, index) { + var i, getter, + method = moment.fn._lang[field], + results = []; + + if (typeof format === 'number') { + index = format; + format = undefined; + } + + getter = function (i) { + var m = moment().utc().set(setter, i); + return method.call(moment.fn._lang, m, format || ''); + }; + + if (index != null) { + return getter(index); + } + else { + for (i = 0; i < count; i++) { + results.push(getter(i)); + } + return results; + } + }; + } + + function toInt(argumentForCoercion) { + var coercedNumber = +argumentForCoercion, + value = 0; + + if (coercedNumber !== 0 && isFinite(coercedNumber)) { + if (coercedNumber >= 0) { + value = Math.floor(coercedNumber); + } else { + value = Math.ceil(coercedNumber); + } + } + + return value; + } + + function daysInMonth(year, month) { + return new Date(Date.UTC(year, month + 1, 0)).getUTCDate(); + } + + function daysInYear(year) { + return isLeapYear(year) ? 366 : 365; + } + + function isLeapYear(year) { + return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; + } + + function checkOverflow(m) { + var overflow; + if (m._a && m._pf.overflow === -2) { + overflow = + m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH : + m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE : + m._a[HOUR] < 0 || m._a[HOUR] > 23 ? HOUR : + m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE : + m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND : + m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND : + -1; + + if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) { + overflow = DATE; + } + + m._pf.overflow = overflow; + } + } + + function initializeParsingFlags(config) { + config._pf = { + empty : false, + unusedTokens : [], + unusedInput : [], + overflow : -2, + charsLeftOver : 0, + nullInput : false, + invalidMonth : null, + invalidFormat : false, + userInvalidated : false, + iso: false + }; + } + + function isValid(m) { + if (m._isValid == null) { + m._isValid = !isNaN(m._d.getTime()) && + m._pf.overflow < 0 && + !m._pf.empty && + !m._pf.invalidMonth && + !m._pf.nullInput && + !m._pf.invalidFormat && + !m._pf.userInvalidated; + + if (m._strict) { + m._isValid = m._isValid && + m._pf.charsLeftOver === 0 && + m._pf.unusedTokens.length === 0; + } + } + return m._isValid; + } + + function normalizeLanguage(key) { + return key ? key.toLowerCase().replace('_', '-') : key; + } + + // Return a moment from input, that is local/utc/zone equivalent to model. + function makeAs(input, model) { + return model._isUTC ? moment(input).zone(model._offset || 0) : + moment(input).local(); + } + + /************************************ + Languages + ************************************/ + + + extend(Language.prototype, { + + set : function (config) { + var prop, i; + for (i in config) { + prop = config[i]; + if (typeof prop === 'function') { + this[i] = prop; + } else { + this['_' + i] = prop; + } + } + }, + + _months : "January_February_March_April_May_June_July_August_September_October_November_December".split("_"), + months : function (m) { + return this._months[m.month()]; + }, + + _monthsShort : "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"), + monthsShort : function (m) { + return this._monthsShort[m.month()]; + }, + + monthsParse : function (monthName) { + var i, mom, regex; + + if (!this._monthsParse) { + this._monthsParse = []; + } + + for (i = 0; i < 12; i++) { + // make the regex if we don't have it already + if (!this._monthsParse[i]) { + mom = moment.utc([2000, i]); + regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); + this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (this._monthsParse[i].test(monthName)) { + return i; + } + } + }, + + _weekdays : "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), + weekdays : function (m) { + return this._weekdays[m.day()]; + }, + + _weekdaysShort : "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"), + weekdaysShort : function (m) { + return this._weekdaysShort[m.day()]; + }, + + _weekdaysMin : "Su_Mo_Tu_We_Th_Fr_Sa".split("_"), + weekdaysMin : function (m) { + return this._weekdaysMin[m.day()]; + }, + + weekdaysParse : function (weekdayName) { + var i, mom, regex; + + if (!this._weekdaysParse) { + this._weekdaysParse = []; + } + + for (i = 0; i < 7; i++) { + // make the regex if we don't have it already + if (!this._weekdaysParse[i]) { + mom = moment([2000, 1]).day(i); + regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); + this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (this._weekdaysParse[i].test(weekdayName)) { + return i; + } + } + }, + + _longDateFormat : { + LT : "h:mm A", + L : "MM/DD/YYYY", + LL : "MMMM D YYYY", + LLL : "MMMM D YYYY LT", + LLLL : "dddd, MMMM D YYYY LT" + }, + longDateFormat : function (key) { + var output = this._longDateFormat[key]; + if (!output && this._longDateFormat[key.toUpperCase()]) { + output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) { + return val.slice(1); + }); + this._longDateFormat[key] = output; + } + return output; + }, + + isPM : function (input) { + // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays + // Using charAt should be more compatible. + return ((input + '').toLowerCase().charAt(0) === 'p'); + }, + + _meridiemParse : /[ap]\.?m?\.?/i, + meridiem : function (hours, minutes, isLower) { + if (hours > 11) { + return isLower ? 'pm' : 'PM'; + } else { + return isLower ? 'am' : 'AM'; + } + }, + + _calendar : { + sameDay : '[Today at] LT', + nextDay : '[Tomorrow at] LT', + nextWeek : 'dddd [at] LT', + lastDay : '[Yesterday at] LT', + lastWeek : '[Last] dddd [at] LT', + sameElse : 'L' + }, + calendar : function (key, mom) { + var output = this._calendar[key]; + return typeof output === 'function' ? output.apply(mom) : output; + }, + + _relativeTime : { + future : "in %s", + past : "%s ago", + s : "a few seconds", + m : "a minute", + mm : "%d minutes", + h : "an hour", + hh : "%d hours", + d : "a day", + dd : "%d days", + M : "a month", + MM : "%d months", + y : "a year", + yy : "%d years" + }, + relativeTime : function (number, withoutSuffix, string, isFuture) { + var output = this._relativeTime[string]; + return (typeof output === 'function') ? + output(number, withoutSuffix, string, isFuture) : + output.replace(/%d/i, number); + }, + pastFuture : function (diff, output) { + var format = this._relativeTime[diff > 0 ? 'future' : 'past']; + return typeof format === 'function' ? format(output) : format.replace(/%s/i, output); + }, + + ordinal : function (number) { + return this._ordinal.replace("%d", number); + }, + _ordinal : "%d", + + preparse : function (string) { + return string; + }, + + postformat : function (string) { + return string; + }, + + week : function (mom) { + return weekOfYear(mom, this._week.dow, this._week.doy).week; + }, + + _week : { + dow : 0, // Sunday is the first day of the week. + doy : 6 // The week that contains Jan 1st is the first week of the year. + }, + + _invalidDate: 'Invalid date', + invalidDate: function () { + return this._invalidDate; + } + }); + + // Loads a language definition into the `languages` cache. The function + // takes a key and optionally values. If not in the browser and no values + // are provided, it will load the language file module. As a convenience, + // this function also returns the language values. + function loadLang(key, values) { + values.abbr = key; + if (!languages[key]) { + languages[key] = new Language(); + } + languages[key].set(values); + return languages[key]; + } + + // Remove a language from the `languages` cache. Mostly useful in tests. + function unloadLang(key) { + delete languages[key]; + } + + // Determines which language definition to use and returns it. + // + // With no parameters, it will return the global language. If you + // pass in a language key, such as 'en', it will return the + // definition for 'en', so long as 'en' has already been loaded using + // moment.lang. + function getLangDefinition(key) { + var i = 0, j, lang, next, split, + get = function (k) { + if (!languages[k] && hasModule) { + try { + require('./lang/' + k); + } catch (e) { } + } + return languages[k]; + }; + + if (!key) { + return moment.fn._lang; + } + + if (!isArray(key)) { + //short-circuit everything else + lang = get(key); + if (lang) { + return lang; + } + key = [key]; + } + + //pick the language from the array + //try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each + //substring from most specific to least, but move to the next array item if it's a more specific variant than the current root + while (i < key.length) { + split = normalizeLanguage(key[i]).split('-'); + j = split.length; + next = normalizeLanguage(key[i + 1]); + next = next ? next.split('-') : null; + while (j > 0) { + lang = get(split.slice(0, j).join('-')); + if (lang) { + return lang; + } + if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) { + //the next array item is better than a shallower substring of this one + break; + } + j--; + } + i++; + } + return moment.fn._lang; + } + + /************************************ + Formatting + ************************************/ + + + function removeFormattingTokens(input) { + if (input.match(/\[[\s\S]/)) { + return input.replace(/^\[|\]$/g, ""); + } + return input.replace(/\\/g, ""); + } + + function makeFormatFunction(format) { + var array = format.match(formattingTokens), i, length; + + for (i = 0, length = array.length; i < length; i++) { + if (formatTokenFunctions[array[i]]) { + array[i] = formatTokenFunctions[array[i]]; + } else { + array[i] = removeFormattingTokens(array[i]); + } + } + + return function (mom) { + var output = ""; + for (i = 0; i < length; i++) { + output += array[i] instanceof Function ? array[i].call(mom, format) : array[i]; + } + return output; + }; + } + + // format date using native date object + function formatMoment(m, format) { + + if (!m.isValid()) { + return m.lang().invalidDate(); + } + + format = expandFormat(format, m.lang()); + + if (!formatFunctions[format]) { + formatFunctions[format] = makeFormatFunction(format); + } + + return formatFunctions[format](m); + } + + function expandFormat(format, lang) { + var i = 5; + + function replaceLongDateFormatTokens(input) { + return lang.longDateFormat(input) || input; + } + + localFormattingTokens.lastIndex = 0; + while (i >= 0 && localFormattingTokens.test(format)) { + format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); + localFormattingTokens.lastIndex = 0; + i -= 1; + } + + return format; + } + + + /************************************ + Parsing + ************************************/ + + + // get the regex to find the next token + function getParseRegexForToken(token, config) { + var a, strict = config._strict; + switch (token) { + case 'DDDD': + return parseTokenThreeDigits; + case 'YYYY': + case 'GGGG': + case 'gggg': + return strict ? parseTokenFourDigits : parseTokenOneToFourDigits; + case 'YYYYYY': + case 'YYYYY': + case 'GGGGG': + case 'ggggg': + return strict ? parseTokenSixDigits : parseTokenOneToSixDigits; + case 'S': + if (strict) { return parseTokenOneDigit; } + /* falls through */ + case 'SS': + if (strict) { return parseTokenTwoDigits; } + /* falls through */ + case 'SSS': + case 'DDD': + return strict ? parseTokenThreeDigits : parseTokenOneToThreeDigits; + case 'MMM': + case 'MMMM': + case 'dd': + case 'ddd': + case 'dddd': + return parseTokenWord; + case 'a': + case 'A': + return getLangDefinition(config._l)._meridiemParse; + case 'X': + return parseTokenTimestampMs; + case 'Z': + case 'ZZ': + return parseTokenTimezone; + case 'T': + return parseTokenT; + case 'SSSS': + return parseTokenDigits; + case 'MM': + case 'DD': + case 'YY': + case 'GG': + case 'gg': + case 'HH': + case 'hh': + case 'mm': + case 'ss': + case 'ww': + case 'WW': + return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits; + case 'M': + case 'D': + case 'd': + case 'H': + case 'h': + case 'm': + case 's': + case 'w': + case 'W': + case 'e': + case 'E': + return strict ? parseTokenOneDigit : parseTokenOneOrTwoDigits; + default : + a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), "i")); + return a; + } + } + + function timezoneMinutesFromString(string) { + string = string || ""; + var possibleTzMatches = (string.match(parseTokenTimezone) || []), + tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [], + parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0], + minutes = +(parts[1] * 60) + toInt(parts[2]); + + return parts[0] === '+' ? -minutes : minutes; + } + + // function to convert string input to date + function addTimeToArrayFromToken(token, input, config) { + var a, datePartArray = config._a; + + switch (token) { + // MONTH + case 'M' : // fall through to MM + case 'MM' : + if (input != null) { + datePartArray[MONTH] = toInt(input) - 1; + } + break; + case 'MMM' : // fall through to MMMM + case 'MMMM' : + a = getLangDefinition(config._l).monthsParse(input); + // if we didn't find a month name, mark the date as invalid. + if (a != null) { + datePartArray[MONTH] = a; + } else { + config._pf.invalidMonth = input; + } + break; + // DAY OF MONTH + case 'D' : // fall through to DD + case 'DD' : + if (input != null) { + datePartArray[DATE] = toInt(input); + } + break; + // DAY OF YEAR + case 'DDD' : // fall through to DDDD + case 'DDDD' : + if (input != null) { + config._dayOfYear = toInt(input); + } + + break; + // YEAR + case 'YY' : + datePartArray[YEAR] = toInt(input) + (toInt(input) > 68 ? 1900 : 2000); + break; + case 'YYYY' : + case 'YYYYY' : + case 'YYYYYY' : + datePartArray[YEAR] = toInt(input); + break; + // AM / PM + case 'a' : // fall through to A + case 'A' : + config._isPm = getLangDefinition(config._l).isPM(input); + break; + // 24 HOUR + case 'H' : // fall through to hh + case 'HH' : // fall through to hh + case 'h' : // fall through to hh + case 'hh' : + datePartArray[HOUR] = toInt(input); + break; + // MINUTE + case 'm' : // fall through to mm + case 'mm' : + datePartArray[MINUTE] = toInt(input); + break; + // SECOND + case 's' : // fall through to ss + case 'ss' : + datePartArray[SECOND] = toInt(input); + break; + // MILLISECOND + case 'S' : + case 'SS' : + case 'SSS' : + case 'SSSS' : + datePartArray[MILLISECOND] = toInt(('0.' + input) * 1000); + break; + // UNIX TIMESTAMP WITH MS + case 'X': + config._d = new Date(parseFloat(input) * 1000); + break; + // TIMEZONE + case 'Z' : // fall through to ZZ + case 'ZZ' : + config._useUTC = true; + config._tzm = timezoneMinutesFromString(input); + break; + case 'w': + case 'ww': + case 'W': + case 'WW': + case 'd': + case 'dd': + case 'ddd': + case 'dddd': + case 'e': + case 'E': + token = token.substr(0, 1); + /* falls through */ + case 'gg': + case 'gggg': + case 'GG': + case 'GGGG': + case 'GGGGG': + token = token.substr(0, 2); + if (input) { + config._w = config._w || {}; + config._w[token] = input; + } + break; + } + } + + // convert an array to a date. + // the array should mirror the parameters below + // note: all values past the year are optional and will default to the lowest possible value. + // [year, month, day , hour, minute, second, millisecond] + function dateFromConfig(config) { + var i, date, input = [], currentDate, + yearToUse, fixYear, w, temp, lang, weekday, week; + + if (config._d) { + return; + } + + currentDate = currentDateArray(config); + + //compute day of the year from weeks and weekdays + if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { + fixYear = function (val) { + var int_val = parseInt(val, 10); + return val ? + (val.length < 3 ? (int_val > 68 ? 1900 + int_val : 2000 + int_val) : int_val) : + (config._a[YEAR] == null ? moment().weekYear() : config._a[YEAR]); + }; + + w = config._w; + if (w.GG != null || w.W != null || w.E != null) { + temp = dayOfYearFromWeeks(fixYear(w.GG), w.W || 1, w.E, 4, 1); + } + else { + lang = getLangDefinition(config._l); + weekday = w.d != null ? parseWeekday(w.d, lang) : + (w.e != null ? parseInt(w.e, 10) + lang._week.dow : 0); + + week = parseInt(w.w, 10) || 1; + + //if we're parsing 'd', then the low day numbers may be next week + if (w.d != null && weekday < lang._week.dow) { + week++; + } + + temp = dayOfYearFromWeeks(fixYear(w.gg), week, weekday, lang._week.doy, lang._week.dow); + } + + config._a[YEAR] = temp.year; + config._dayOfYear = temp.dayOfYear; + } + + //if the day of the year is set, figure out what it is + if (config._dayOfYear) { + yearToUse = config._a[YEAR] == null ? currentDate[YEAR] : config._a[YEAR]; + + if (config._dayOfYear > daysInYear(yearToUse)) { + config._pf._overflowDayOfYear = true; + } + + date = makeUTCDate(yearToUse, 0, config._dayOfYear); + config._a[MONTH] = date.getUTCMonth(); + config._a[DATE] = date.getUTCDate(); + } + + // Default to current date. + // * if no year, month, day of month are given, default to today + // * if day of month is given, default month and year + // * if month is given, default only year + // * if year is given, don't default anything + for (i = 0; i < 3 && config._a[i] == null; ++i) { + config._a[i] = input[i] = currentDate[i]; + } + + // Zero out whatever was not defaulted, including time + for (; i < 7; i++) { + config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; + } + + // add the offsets to the time to be parsed so that we can have a clean array for checking isValid + input[HOUR] += toInt((config._tzm || 0) / 60); + input[MINUTE] += toInt((config._tzm || 0) % 60); + + config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input); + } + + function dateFromObject(config) { + var normalizedInput; + + if (config._d) { + return; + } + + normalizedInput = normalizeObjectUnits(config._i); + config._a = [ + normalizedInput.year, + normalizedInput.month, + normalizedInput.day, + normalizedInput.hour, + normalizedInput.minute, + normalizedInput.second, + normalizedInput.millisecond + ]; + + dateFromConfig(config); + } + + function currentDateArray(config) { + var now = new Date(); + if (config._useUTC) { + return [ + now.getUTCFullYear(), + now.getUTCMonth(), + now.getUTCDate() + ]; + } else { + return [now.getFullYear(), now.getMonth(), now.getDate()]; + } + } + + // date from string and format string + function makeDateFromStringAndFormat(config) { + + config._a = []; + config._pf.empty = true; + + // This array is used to make a Date, either with `new Date` or `Date.UTC` + var lang = getLangDefinition(config._l), + string = '' + config._i, + i, parsedInput, tokens, token, skipped, + stringLength = string.length, + totalParsedInputLength = 0; + + tokens = expandFormat(config._f, lang).match(formattingTokens) || []; + + for (i = 0; i < tokens.length; i++) { + token = tokens[i]; + parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; + if (parsedInput) { + skipped = string.substr(0, string.indexOf(parsedInput)); + if (skipped.length > 0) { + config._pf.unusedInput.push(skipped); + } + string = string.slice(string.indexOf(parsedInput) + parsedInput.length); + totalParsedInputLength += parsedInput.length; + } + // don't parse if it's not a known token + if (formatTokenFunctions[token]) { + if (parsedInput) { + config._pf.empty = false; + } + else { + config._pf.unusedTokens.push(token); + } + addTimeToArrayFromToken(token, parsedInput, config); + } + else if (config._strict && !parsedInput) { + config._pf.unusedTokens.push(token); + } + } + + // add remaining unparsed input length to the string + config._pf.charsLeftOver = stringLength - totalParsedInputLength; + if (string.length > 0) { + config._pf.unusedInput.push(string); + } + + // handle am pm + if (config._isPm && config._a[HOUR] < 12) { + config._a[HOUR] += 12; + } + // if is 12 am, change hours to 0 + if (config._isPm === false && config._a[HOUR] === 12) { + config._a[HOUR] = 0; + } + + dateFromConfig(config); + checkOverflow(config); + } + + function unescapeFormat(s) { + return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) { + return p1 || p2 || p3 || p4; + }); + } + + // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript + function regexpEscape(s) { + return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + } + + // date from string and array of format strings + function makeDateFromStringAndArray(config) { + var tempConfig, + bestMoment, + + scoreToBeat, + i, + currentScore; + + if (config._f.length === 0) { + config._pf.invalidFormat = true; + config._d = new Date(NaN); + return; + } + + for (i = 0; i < config._f.length; i++) { + currentScore = 0; + tempConfig = extend({}, config); + initializeParsingFlags(tempConfig); + tempConfig._f = config._f[i]; + makeDateFromStringAndFormat(tempConfig); + + if (!isValid(tempConfig)) { + continue; + } + + // if there is any input that was not parsed add a penalty for that format + currentScore += tempConfig._pf.charsLeftOver; + + //or tokens + currentScore += tempConfig._pf.unusedTokens.length * 10; + + tempConfig._pf.score = currentScore; + + if (scoreToBeat == null || currentScore < scoreToBeat) { + scoreToBeat = currentScore; + bestMoment = tempConfig; + } + } + + extend(config, bestMoment || tempConfig); + } + + // date from iso format + function makeDateFromString(config) { + var i, + string = config._i, + match = isoRegex.exec(string); + + if (match) { + config._pf.iso = true; + for (i = 4; i > 0; i--) { + if (match[i]) { + // match[5] should be "T" or undefined + config._f = isoDates[i - 1] + (match[6] || " "); + break; + } + } + for (i = 0; i < 4; i++) { + if (isoTimes[i][1].exec(string)) { + config._f += isoTimes[i][0]; + break; + } + } + if (string.match(parseTokenTimezone)) { + config._f += "Z"; + } + makeDateFromStringAndFormat(config); + } + else { + config._d = new Date(string); + } + } + + function makeDateFromInput(config) { + var input = config._i, + matched = aspNetJsonRegex.exec(input); + + if (input === undefined) { + config._d = new Date(); + } else if (matched) { + config._d = new Date(+matched[1]); + } else if (typeof input === 'string') { + makeDateFromString(config); + } else if (isArray(input)) { + config._a = input.slice(0); + dateFromConfig(config); + } else if (isDate(input)) { + config._d = new Date(+input); + } else if (typeof(input) === 'object') { + dateFromObject(config); + } else { + config._d = new Date(input); + } + } + + function makeDate(y, m, d, h, M, s, ms) { + //can't just apply() to create a date: + //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply + var date = new Date(y, m, d, h, M, s, ms); + + //the date constructor doesn't accept years < 1970 + if (y < 1970) { + date.setFullYear(y); + } + return date; + } + + function makeUTCDate(y) { + var date = new Date(Date.UTC.apply(null, arguments)); + if (y < 1970) { + date.setUTCFullYear(y); + } + return date; + } + + function parseWeekday(input, language) { + if (typeof input === 'string') { + if (!isNaN(input)) { + input = parseInt(input, 10); + } + else { + input = language.weekdaysParse(input); + if (typeof input !== 'number') { + return null; + } + } + } + return input; + } + + /************************************ + Relative Time + ************************************/ + + + // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize + function substituteTimeAgo(string, number, withoutSuffix, isFuture, lang) { + return lang.relativeTime(number || 1, !!withoutSuffix, string, isFuture); + } + + function relativeTime(milliseconds, withoutSuffix, lang) { + var seconds = round(Math.abs(milliseconds) / 1000), + minutes = round(seconds / 60), + hours = round(minutes / 60), + days = round(hours / 24), + years = round(days / 365), + args = seconds < 45 && ['s', seconds] || + minutes === 1 && ['m'] || + minutes < 45 && ['mm', minutes] || + hours === 1 && ['h'] || + hours < 22 && ['hh', hours] || + days === 1 && ['d'] || + days <= 25 && ['dd', days] || + days <= 45 && ['M'] || + days < 345 && ['MM', round(days / 30)] || + years === 1 && ['y'] || ['yy', years]; + args[2] = withoutSuffix; + args[3] = milliseconds > 0; + args[4] = lang; + return substituteTimeAgo.apply({}, args); + } + + + /************************************ + Week of Year + ************************************/ + + + // firstDayOfWeek 0 = sun, 6 = sat + // the day of the week that starts the week + // (usually sunday or monday) + // firstDayOfWeekOfYear 0 = sun, 6 = sat + // the first week is the week that contains the first + // of this day of the week + // (eg. ISO weeks use thursday (4)) + function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { + var end = firstDayOfWeekOfYear - firstDayOfWeek, + daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(), + adjustedMoment; + + + if (daysToDayOfWeek > end) { + daysToDayOfWeek -= 7; + } + + if (daysToDayOfWeek < end - 7) { + daysToDayOfWeek += 7; + } + + adjustedMoment = moment(mom).add('d', daysToDayOfWeek); + return { + week: Math.ceil(adjustedMoment.dayOfYear() / 7), + year: adjustedMoment.year() + }; + } + + //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday + function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) { + // The only solid way to create an iso date from year is to use + // a string format (Date.UTC handles only years > 1900). Don't ask why + // it doesn't need Z at the end. + var d = new Date(leftZeroFill(year, 6, true) + '-01-01').getUTCDay(), + daysToAdd, dayOfYear; + + weekday = weekday != null ? weekday : firstDayOfWeek; + daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0); + dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1; + + return { + year: dayOfYear > 0 ? year : year - 1, + dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear + }; + } + + /************************************ + Top Level Functions + ************************************/ + + function makeMoment(config) { + var input = config._i, + format = config._f; + + if (typeof config._pf === 'undefined') { + initializeParsingFlags(config); + } + + if (input === null) { + return moment.invalid({nullInput: true}); + } + + if (typeof input === 'string') { + config._i = input = getLangDefinition().preparse(input); + } + + if (moment.isMoment(input)) { + config = extend({}, input); + + config._d = new Date(+input._d); + } else if (format) { + if (isArray(format)) { + makeDateFromStringAndArray(config); + } else { + makeDateFromStringAndFormat(config); + } + } else { + makeDateFromInput(config); + } + + return new Moment(config); + } + + moment = function (input, format, lang, strict) { + if (typeof(lang) === "boolean") { + strict = lang; + lang = undefined; + } + return makeMoment({ + _i : input, + _f : format, + _l : lang, + _strict : strict, + _isUTC : false + }); + }; + + // creating with utc + moment.utc = function (input, format, lang, strict) { + var m; + + if (typeof(lang) === "boolean") { + strict = lang; + lang = undefined; + } + m = makeMoment({ + _useUTC : true, + _isUTC : true, + _l : lang, + _i : input, + _f : format, + _strict : strict + }).utc(); + + return m; + }; + + // creating with unix timestamp (in seconds) + moment.unix = function (input) { + return moment(input * 1000); + }; + + // duration + moment.duration = function (input, key) { + var duration = input, + // matching against regexp is expensive, do it on demand + match = null, + sign, + ret, + parseIso; + + if (moment.isDuration(input)) { + duration = { + ms: input._milliseconds, + d: input._days, + M: input._months + }; + } else if (typeof input === 'number') { + duration = {}; + if (key) { + duration[key] = input; + } else { + duration.milliseconds = input; + } + } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) { + sign = (match[1] === "-") ? -1 : 1; + duration = { + y: 0, + d: toInt(match[DATE]) * sign, + h: toInt(match[HOUR]) * sign, + m: toInt(match[MINUTE]) * sign, + s: toInt(match[SECOND]) * sign, + ms: toInt(match[MILLISECOND]) * sign + }; + } else if (!!(match = isoDurationRegex.exec(input))) { + sign = (match[1] === "-") ? -1 : 1; + parseIso = function (inp) { + // We'd normally use ~~inp for this, but unfortunately it also + // converts floats to ints. + // inp may be undefined, so careful calling replace on it. + var res = inp && parseFloat(inp.replace(',', '.')); + // apply sign while we're at it + return (isNaN(res) ? 0 : res) * sign; + }; + duration = { + y: parseIso(match[2]), + M: parseIso(match[3]), + d: parseIso(match[4]), + h: parseIso(match[5]), + m: parseIso(match[6]), + s: parseIso(match[7]), + w: parseIso(match[8]) + }; + } + + ret = new Duration(duration); + + if (moment.isDuration(input) && input.hasOwnProperty('_lang')) { + ret._lang = input._lang; + } + + return ret; + }; + + // version number + moment.version = VERSION; + + // default format + moment.defaultFormat = isoFormat; + + // This function will be called whenever a moment is mutated. + // It is intended to keep the offset in sync with the timezone. + moment.updateOffset = function () {}; + + // This function will load languages and then set the global language. If + // no arguments are passed in, it will simply return the current global + // language key. + moment.lang = function (key, values) { + var r; + if (!key) { + return moment.fn._lang._abbr; + } + if (values) { + loadLang(normalizeLanguage(key), values); + } else if (values === null) { + unloadLang(key); + key = 'en'; + } else if (!languages[key]) { + getLangDefinition(key); + } + r = moment.duration.fn._lang = moment.fn._lang = getLangDefinition(key); + return r._abbr; + }; + + // returns language data + moment.langData = function (key) { + if (key && key._lang && key._lang._abbr) { + key = key._lang._abbr; + } + return getLangDefinition(key); + }; + + // compare moment object + moment.isMoment = function (obj) { + return obj instanceof Moment; + }; + + // for typechecking Duration objects + moment.isDuration = function (obj) { + return obj instanceof Duration; + }; + + for (i = lists.length - 1; i >= 0; --i) { + makeList(lists[i]); + } + + moment.normalizeUnits = function (units) { + return normalizeUnits(units); + }; + + moment.invalid = function (flags) { + var m = moment.utc(NaN); + if (flags != null) { + extend(m._pf, flags); + } + else { + m._pf.userInvalidated = true; + } + + return m; + }; + + moment.parseZone = function (input) { + return moment(input).parseZone(); + }; + + /************************************ + Moment Prototype + ************************************/ + + + extend(moment.fn = Moment.prototype, { + + clone : function () { + return moment(this); + }, + + valueOf : function () { + return +this._d + ((this._offset || 0) * 60000); + }, + + unix : function () { + return Math.floor(+this / 1000); + }, + + toString : function () { + return this.clone().lang('en').format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ"); + }, + + toDate : function () { + return this._offset ? new Date(+this) : this._d; + }, + + toISOString : function () { + var m = moment(this).utc(); + if (0 < m.year() && m.year() <= 9999) { + return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); + } else { + return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); + } + }, + + toArray : function () { + var m = this; + return [ + m.year(), + m.month(), + m.date(), + m.hours(), + m.minutes(), + m.seconds(), + m.milliseconds() + ]; + }, + + isValid : function () { + return isValid(this); + }, + + isDSTShifted : function () { + + if (this._a) { + return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0; + } + + return false; + }, + + parsingFlags : function () { + return extend({}, this._pf); + }, + + invalidAt: function () { + return this._pf.overflow; + }, + + utc : function () { + return this.zone(0); + }, + + local : function () { + this.zone(0); + this._isUTC = false; + return this; + }, + + format : function (inputString) { + var output = formatMoment(this, inputString || moment.defaultFormat); + return this.lang().postformat(output); + }, + + add : function (input, val) { + var dur; + // switch args to support add('s', 1) and add(1, 's') + if (typeof input === 'string') { + dur = moment.duration(+val, input); + } else { + dur = moment.duration(input, val); + } + addOrSubtractDurationFromMoment(this, dur, 1); + return this; + }, + + subtract : function (input, val) { + var dur; + // switch args to support subtract('s', 1) and subtract(1, 's') + if (typeof input === 'string') { + dur = moment.duration(+val, input); + } else { + dur = moment.duration(input, val); + } + addOrSubtractDurationFromMoment(this, dur, -1); + return this; + }, + + diff : function (input, units, asFloat) { + var that = makeAs(input, this), + zoneDiff = (this.zone() - that.zone()) * 6e4, + diff, output; + + units = normalizeUnits(units); + + if (units === 'year' || units === 'month') { + // average number of days in the months in the given dates + diff = (this.daysInMonth() + that.daysInMonth()) * 432e5; // 24 * 60 * 60 * 1000 / 2 + // difference in months + output = ((this.year() - that.year()) * 12) + (this.month() - that.month()); + // adjust by taking difference in days, average number of days + // and dst in the given months. + output += ((this - moment(this).startOf('month')) - + (that - moment(that).startOf('month'))) / diff; + // same as above but with zones, to negate all dst + output -= ((this.zone() - moment(this).startOf('month').zone()) - + (that.zone() - moment(that).startOf('month').zone())) * 6e4 / diff; + if (units === 'year') { + output = output / 12; + } + } else { + diff = (this - that); + output = units === 'second' ? diff / 1e3 : // 1000 + units === 'minute' ? diff / 6e4 : // 1000 * 60 + units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60 + units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst + units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst + diff; + } + return asFloat ? output : absRound(output); + }, + + from : function (time, withoutSuffix) { + return moment.duration(this.diff(time)).lang(this.lang()._abbr).humanize(!withoutSuffix); + }, + + fromNow : function (withoutSuffix) { + return this.from(moment(), withoutSuffix); + }, + + calendar : function () { + // We want to compare the start of today, vs this. + // Getting start-of-today depends on whether we're zone'd or not. + var sod = makeAs(moment(), this).startOf('day'), + diff = this.diff(sod, 'days', true), + format = diff < -6 ? 'sameElse' : + diff < -1 ? 'lastWeek' : + diff < 0 ? 'lastDay' : + diff < 1 ? 'sameDay' : + diff < 2 ? 'nextDay' : + diff < 7 ? 'nextWeek' : 'sameElse'; + return this.format(this.lang().calendar(format, this)); + }, + + isLeapYear : function () { + return isLeapYear(this.year()); + }, + + isDST : function () { + return (this.zone() < this.clone().month(0).zone() || + this.zone() < this.clone().month(5).zone()); + }, + + day : function (input) { + var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); + if (input != null) { + input = parseWeekday(input, this.lang()); + return this.add({ d : input - day }); + } else { + return day; + } + }, + + month : function (input) { + var utc = this._isUTC ? 'UTC' : '', + dayOfMonth; + + if (input != null) { + if (typeof input === 'string') { + input = this.lang().monthsParse(input); + if (typeof input !== 'number') { + return this; + } + } + + dayOfMonth = this.date(); + this.date(1); + this._d['set' + utc + 'Month'](input); + this.date(Math.min(dayOfMonth, this.daysInMonth())); + + moment.updateOffset(this); + return this; + } else { + return this._d['get' + utc + 'Month'](); + } + }, + + startOf: function (units) { + units = normalizeUnits(units); + // the following switch intentionally omits break keywords + // to utilize falling through the cases. + switch (units) { + case 'year': + this.month(0); + /* falls through */ + case 'month': + this.date(1); + /* falls through */ + case 'week': + case 'isoWeek': + case 'day': + this.hours(0); + /* falls through */ + case 'hour': + this.minutes(0); + /* falls through */ + case 'minute': + this.seconds(0); + /* falls through */ + case 'second': + this.milliseconds(0); + /* falls through */ + } + + // weeks are a special case + if (units === 'week') { + this.weekday(0); + } else if (units === 'isoWeek') { + this.isoWeekday(1); + } + + return this; + }, + + endOf: function (units) { + units = normalizeUnits(units); + return this.startOf(units).add((units === 'isoWeek' ? 'week' : units), 1).subtract('ms', 1); + }, + + isAfter: function (input, units) { + units = typeof units !== 'undefined' ? units : 'millisecond'; + return +this.clone().startOf(units) > +moment(input).startOf(units); + }, + + isBefore: function (input, units) { + units = typeof units !== 'undefined' ? units : 'millisecond'; + return +this.clone().startOf(units) < +moment(input).startOf(units); + }, + + isSame: function (input, units) { + units = units || 'ms'; + return +this.clone().startOf(units) === +makeAs(input, this).startOf(units); + }, + + min: function (other) { + other = moment.apply(null, arguments); + return other < this ? this : other; + }, + + max: function (other) { + other = moment.apply(null, arguments); + return other > this ? this : other; + }, + + zone : function (input) { + var offset = this._offset || 0; + if (input != null) { + if (typeof input === "string") { + input = timezoneMinutesFromString(input); + } + if (Math.abs(input) < 16) { + input = input * 60; + } + this._offset = input; + this._isUTC = true; + if (offset !== input) { + addOrSubtractDurationFromMoment(this, moment.duration(offset - input, 'm'), 1, true); + } + } else { + return this._isUTC ? offset : this._d.getTimezoneOffset(); + } + return this; + }, + + zoneAbbr : function () { + return this._isUTC ? "UTC" : ""; + }, + + zoneName : function () { + return this._isUTC ? "Coordinated Universal Time" : ""; + }, + + parseZone : function () { + if (this._tzm) { + this.zone(this._tzm); + } else if (typeof this._i === 'string') { + this.zone(this._i); + } + return this; + }, + + hasAlignedHourOffset : function (input) { + if (!input) { + input = 0; + } + else { + input = moment(input).zone(); + } + + return (this.zone() - input) % 60 === 0; + }, + + daysInMonth : function () { + return daysInMonth(this.year(), this.month()); + }, + + dayOfYear : function (input) { + var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1; + return input == null ? dayOfYear : this.add("d", (input - dayOfYear)); + }, + + quarter : function () { + return Math.ceil((this.month() + 1.0) / 3.0); + }, + + weekYear : function (input) { + var year = weekOfYear(this, this.lang()._week.dow, this.lang()._week.doy).year; + return input == null ? year : this.add("y", (input - year)); + }, + + isoWeekYear : function (input) { + var year = weekOfYear(this, 1, 4).year; + return input == null ? year : this.add("y", (input - year)); + }, + + week : function (input) { + var week = this.lang().week(this); + return input == null ? week : this.add("d", (input - week) * 7); + }, + + isoWeek : function (input) { + var week = weekOfYear(this, 1, 4).week; + return input == null ? week : this.add("d", (input - week) * 7); + }, + + weekday : function (input) { + var weekday = (this.day() + 7 - this.lang()._week.dow) % 7; + return input == null ? weekday : this.add("d", input - weekday); + }, + + isoWeekday : function (input) { + // behaves the same as moment#day except + // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) + // as a setter, sunday should belong to the previous week. + return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7); + }, + + get : function (units) { + units = normalizeUnits(units); + return this[units](); + }, + + set : function (units, value) { + units = normalizeUnits(units); + if (typeof this[units] === 'function') { + this[units](value); + } + return this; + }, + + // If passed a language key, it will set the language for this + // instance. Otherwise, it will return the language configuration + // variables for this instance. + lang : function (key) { + if (key === undefined) { + return this._lang; + } else { + this._lang = getLangDefinition(key); + return this; + } + } + }); + + // helper for adding shortcuts + function makeGetterAndSetter(name, key) { + moment.fn[name] = moment.fn[name + 's'] = function (input) { + var utc = this._isUTC ? 'UTC' : ''; + if (input != null) { + this._d['set' + utc + key](input); + moment.updateOffset(this); + return this; + } else { + return this._d['get' + utc + key](); + } + }; + } + + // loop through and add shortcuts (Month, Date, Hours, Minutes, Seconds, Milliseconds) + for (i = 0; i < proxyGettersAndSetters.length; i ++) { + makeGetterAndSetter(proxyGettersAndSetters[i].toLowerCase().replace(/s$/, ''), proxyGettersAndSetters[i]); + } + + // add shortcut for year (uses different syntax than the getter/setter 'year' == 'FullYear') + makeGetterAndSetter('year', 'FullYear'); + + // add plural methods + moment.fn.days = moment.fn.day; + moment.fn.months = moment.fn.month; + moment.fn.weeks = moment.fn.week; + moment.fn.isoWeeks = moment.fn.isoWeek; + + // add aliased format methods + moment.fn.toJSON = moment.fn.toISOString; + + /************************************ + Duration Prototype + ************************************/ + + + extend(moment.duration.fn = Duration.prototype, { + + _bubble : function () { + var milliseconds = this._milliseconds, + days = this._days, + months = this._months, + data = this._data, + seconds, minutes, hours, years; + + // The following code bubbles up values, see the tests for + // examples of what that means. + data.milliseconds = milliseconds % 1000; + + seconds = absRound(milliseconds / 1000); + data.seconds = seconds % 60; + + minutes = absRound(seconds / 60); + data.minutes = minutes % 60; + + hours = absRound(minutes / 60); + data.hours = hours % 24; + + days += absRound(hours / 24); + data.days = days % 30; + + months += absRound(days / 30); + data.months = months % 12; + + years = absRound(months / 12); + data.years = years; + }, + + weeks : function () { + return absRound(this.days() / 7); + }, + + valueOf : function () { + return this._milliseconds + + this._days * 864e5 + + (this._months % 12) * 2592e6 + + toInt(this._months / 12) * 31536e6; + }, + + humanize : function (withSuffix) { + var difference = +this, + output = relativeTime(difference, !withSuffix, this.lang()); + + if (withSuffix) { + output = this.lang().pastFuture(difference, output); + } + + return this.lang().postformat(output); + }, + + add : function (input, val) { + // supports only 2.0-style add(1, 's') or add(moment) + var dur = moment.duration(input, val); + + this._milliseconds += dur._milliseconds; + this._days += dur._days; + this._months += dur._months; + + this._bubble(); + + return this; + }, + + subtract : function (input, val) { + var dur = moment.duration(input, val); + + this._milliseconds -= dur._milliseconds; + this._days -= dur._days; + this._months -= dur._months; + + this._bubble(); + + return this; + }, + + get : function (units) { + units = normalizeUnits(units); + return this[units.toLowerCase() + 's'](); + }, + + as : function (units) { + units = normalizeUnits(units); + return this['as' + units.charAt(0).toUpperCase() + units.slice(1) + 's'](); + }, + + lang : moment.fn.lang, + + toIsoString : function () { + // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js + var years = Math.abs(this.years()), + months = Math.abs(this.months()), + days = Math.abs(this.days()), + hours = Math.abs(this.hours()), + minutes = Math.abs(this.minutes()), + seconds = Math.abs(this.seconds() + this.milliseconds() / 1000); + + if (!this.asSeconds()) { + // this is the same as C#'s (Noda) and python (isodate)... + // but not other JS (goog.date) + return 'P0D'; + } + + return (this.asSeconds() < 0 ? '-' : '') + + 'P' + + (years ? years + 'Y' : '') + + (months ? months + 'M' : '') + + (days ? days + 'D' : '') + + ((hours || minutes || seconds) ? 'T' : '') + + (hours ? hours + 'H' : '') + + (minutes ? minutes + 'M' : '') + + (seconds ? seconds + 'S' : ''); + } + }); + + function makeDurationGetter(name) { + moment.duration.fn[name] = function () { + return this._data[name]; + }; + } + + function makeDurationAsGetter(name, factor) { + moment.duration.fn['as' + name] = function () { + return +this / factor; + }; + } + + for (i in unitMillisecondFactors) { + if (unitMillisecondFactors.hasOwnProperty(i)) { + makeDurationAsGetter(i, unitMillisecondFactors[i]); + makeDurationGetter(i.toLowerCase()); + } + } + + makeDurationAsGetter('Weeks', 6048e5); + moment.duration.fn.asMonths = function () { + return (+this - this.years() * 31536e6) / 2592e6 + this.years() * 12; + }; + + + /************************************ + Default Lang + ************************************/ + + + // Set default language, other languages will inherit from English. + moment.lang('en', { + ordinal : function (number) { + var b = number % 10, + output = (toInt(number % 100 / 10) === 1) ? 'th' : + (b === 1) ? 'st' : + (b === 2) ? 'nd' : + (b === 3) ? 'rd' : 'th'; + return number + output; + } + }); + + /* EMBED_LANGUAGES */ + + /************************************ + Exposing Moment + ************************************/ + + function makeGlobal(deprecate) { + var warned = false, local_moment = moment; + /*global ender:false */ + if (typeof ender !== 'undefined') { + return; + } + // here, `this` means `window` in the browser, or `global` on the server + // add `moment` as a global object via a string identifier, + // for Closure Compiler "advanced" mode + if (deprecate) { + global.moment = function () { + if (!warned && console && console.warn) { + warned = true; + console.warn( + "Accessing Moment through the global scope is " + + "deprecated, and will be removed in an upcoming " + + "release."); + } + return local_moment.apply(null, arguments); + }; + extend(global.moment, local_moment); + } else { + global['moment'] = moment; + } + } + + // CommonJS module is defined + if (hasModule) { + module.exports = moment; + makeGlobal(true); + } else if (typeof define === "function" && define.amd) { + define("moment", function (require, exports, module) { + if (module.config && module.config() && module.config().noGlobal !== true) { + // If user provided noGlobal, he is aware of global + makeGlobal(module.config().noGlobal === undefined); + } + + return moment; + }); + } else { + makeGlobal(); + } +}).call(this); + +},{}]},{},[1]) +(1) +}); \ No newline at end of file diff --git a/dist/vis.min.js b/dist/vis.min.js new file mode 100644 index 00000000..8ca53878 --- /dev/null +++ b/dist/vis.min.js @@ -0,0 +1,29 @@ +/** + * vis.js + * https://github.com/almende/vis + * + * A dynamic, browser-based visualization library. + * + * @version 0.3.0 + * @date 2014-01-14 + * + * @license + * Copyright (C) 2011-2013 Almende B.V, http://almende.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +!function(t){if("object"==typeof exports)module.exports=t();else if("function"==typeof define&&define.amd)define(t);else{var e;"undefined"!=typeof window?e=window:"undefined"!=typeof global?e=global:"undefined"!=typeof self&&(e=self),e.vis=t()}}(function(){var t;return function e(t,i,n){function s(o,a){if(!i[o]){if(!t[o]){var h="function"==typeof require&&require;if(!a&&h)return h(o,!0);if(r)return r(o,!0);throw new Error("Cannot find module '"+o+"'")}var d=i[o]={exports:{}};t[o][0].call(d.exports,function(e){var i=t[o][1][e];return s(i?i:e)},d,d.exports,e,t,i,n)}return i[o].exports}for(var r="function"==typeof require&&require,o=0;oi;++i)t.call(e||this,this[i],i,this)}),Array.prototype.map||(Array.prototype.map=function(t,e){var i,n,s;if(null==this)throw new TypeError(" this is null or not defined");var r=Object(this),o=r.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(e&&(i=e),n=new Array(o),s=0;o>s;){var a,h;s in r&&(a=r[s],h=t.call(i,a,s,r),n[s]=h),s++}return n}),Array.prototype.filter||(Array.prototype.filter=function(t){"use strict";if(null==this)throw new TypeError;var e=Object(this),i=e.length>>>0;if("function"!=typeof t)throw new TypeError;for(var n=[],s=arguments[1],r=0;i>r;r++)if(r in e){var o=e[r];t.call(s,o,r,e)&&n.push(o)}return n}),Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,e=!{toString:null}.propertyIsEnumerable("toString"),i=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],n=i.length;return function(s){if("object"!=typeof s&&"function"!=typeof s||null===s)throw new TypeError("Object.keys called on non-object");var r=[];for(var o in s)t.call(s,o)&&r.push(o);if(e)for(var a=0;n>a;a++)t.call(s,i[a])&&r.push(i[a]);return r}}()),Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s}),Object.create||(Object.create=function(t){function e(){}if(arguments.length>1)throw new Error("Object.create implementation only accepts the first parameter.");return e.prototype=t,new e}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s});var A={};A.isNumber=function(t){return t instanceof Number||"number"==typeof t},A.isString=function(t){return t instanceof String||"string"==typeof t},A.isDate=function(t){if(t instanceof Date)return!0;if(A.isString(t)){var e=P.exec(t);if(e)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},A.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},A.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},A.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var n=arguments[e];for(var s in n)n.hasOwnProperty(s)&&void 0!==n[s]&&(t[s]=n[s])}return t},A.convert=function(t,e){var i;if(void 0===t)return void 0;if(null===t)return null;if(!e)return t;if("string"!=typeof e&&!(e instanceof String))throw new Error("Type must be a string");switch(e){case"boolean":case"Boolean":return Boolean(t);case"number":case"Number":return Number(t.valueOf());case"string":case"String":return String(t);case"Date":if(A.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(I.isMoment(t))return new Date(t.valueOf());if(A.isString(t))return i=P.exec(t),i?new Date(Number(i[1])):I(t).toDate();throw new Error("Cannot convert object of type "+A.getType(t)+" to type Date");case"Moment":if(A.isNumber(t))return I(t);if(t instanceof Date)return I(t.valueOf());if(I.isMoment(t))return I(t);if(A.isString(t))return i=P.exec(t),i?I(Number(i[1])):I(t);throw new Error("Cannot convert object of type "+A.getType(t)+" to type Date");case"ISODate":if(A.isNumber(t))return new Date(t);if(t instanceof Date)return t.toISOString();if(I.isMoment(t))return t.toDate().toISOString();if(A.isString(t))return i=P.exec(t),i?new Date(Number(i[1])).toISOString():new Date(t).toISOString();throw new Error("Cannot convert object of type "+A.getType(t)+" to type ISODate");case"ASPDate":if(A.isNumber(t))return"/Date("+t+")/";if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(A.isString(t)){i=P.exec(t);var n;return n=i?new Date(Number(i[1])).valueOf():new Date(t).valueOf(),"/Date("+n+")/"}throw new Error("Cannot convert object of type "+A.getType(t)+" to type ASPDate");default:throw new Error("Cannot convert object of type "+A.getType(t)+' to type "'+e+'"')}};var P=/^\/?Date\((\-?\d+)/i;A.getType=function(t){var e=typeof t;return"object"==e?null==t?"null":t instanceof Boolean?"Boolean":t instanceof Number?"Number":t instanceof String?"String":t instanceof Array?"Array":t instanceof Date?"Date":"Object":"number"==e?"Number":"boolean"==e?"Boolean":"string"==e?"String":e},A.getAbsoluteLeft=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetLeft,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetLeft,n-=s.scrollLeft,s=s.offsetParent;return n},A.getAbsoluteTop=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetTop,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetTop,n-=s.scrollTop,s=s.offsetParent;return n},A.getPageY=function(t){if("pageY"in t)return t.pageY;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientY:t.clientY;var i=document.documentElement,n=document.body;return e+(i&&i.scrollTop||n&&n.scrollTop||0)-(i&&i.clientTop||n&&n.clientTop||0)},A.getPageX=function(t){if("pageY"in t)return t.pageX;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientX:t.clientX;var i=document.documentElement,n=document.body;return e+(i&&i.scrollLeft||n&&n.scrollLeft||0)-(i&&i.clientLeft||n&&n.clientLeft||0)},A.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},A.removeClassName=function(t,e){var i=t.className.split(" "),n=i.indexOf(e);-1!=n&&(i.splice(n,1),t.className=i.join(" "))},A.forEach=function(t,e){var i,n;if(t instanceof Array)for(i=0,n=t.length;n>i;i++)e(t[i],i,t);else for(i in t)t.hasOwnProperty(i)&&e(t[i],i,t)},A.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},A.addEventListener=function(t,e,i,n){t.addEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.addEventListener(e,i,n)):t.attachEvent("on"+e,i)},A.removeEventListener=function(t,e,i,n){t.removeEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.removeEventListener(e,i,n)):t.detachEvent("on"+e,i)},A.getTarget=function(t){t||(t=window.event);var e;return t.target?e=t.target:t.srcElement&&(e=t.srcElement),void 0!=e.nodeType&&3==e.nodeType&&(e=e.parentNode),e},A.stopPropagation=function(t){t||(t=window.event),t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},A.fakeGesture=function(t,e){var i=null;return L.event.collectEventData(this,i,e)},A.preventDefault=function(t){t||(t=window.event),t.preventDefault?t.preventDefault():t.returnValue=!1},A.option={},A.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},A.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},A.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?String(t):e||null},A.option.asSize=function(t,e){return"function"==typeof t&&(t=t()),A.isString(t)?t:A.isNumber(t)?t+"px":e||null},A.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null};var Y={listeners:[],indexOf:function(t){for(var e=this.listeners,i=0,n=this.listeners.length;n>i;i++){var s=e[i];if(s&&s.object==t)return i}return-1},addListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];s||(s={object:t,events:{}},this.listeners.push(s));var r=s.events[e];r||(r=[],s.events[e]=r),-1==r.indexOf(i)&&r.push(i)},removeListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var r=s.events[e];r&&(n=r.indexOf(i),-1!=n&&r.splice(n,1),0==r.length&&delete s.events[e]);var o=0,a=s.events;for(var h in a)a.hasOwnProperty(h)&&o++;0==o&&delete this.listeners[n]}},removeAllListeners:function(){this.listeners=[]},trigger:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var r=s.events[e];if(r)for(var o=0,a=r.length;a>o;o++)r[o](i)}}};s.prototype.on=function(t,e,i){var n=t instanceof RegExp?t:new RegExp(t.replace("*","\\w+")),s={id:A.randomUUID(),event:t,regexp:n,callback:"function"==typeof e?e:null,target:i};return this.subscriptions.push(s),s.id},s.prototype.off=function(t){for(var e=0;er;r++)i=s._addItem(t[r]),n.push(i);else if(A.isDataTable(t))for(var a=this._getColumnNames(t),h=0,d=t.getNumberOfRows();d>h;h++){for(var c={},u=0,l=a.length;l>u;u++){var p=a[u];c[p]=t.getValue(h,u)}i=s._addItem(c),n.push(i)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");i=s._addItem(t),n.push(i)}return n.length&&this._trigger("add",{items:n},e),n},r.prototype.update=function(t,e){var i=[],n=[],s=this,r=s.fieldId,o=function(t){var e=t[r];s.data[e]?(e=s._updateItem(t),n.push(e)):(e=s._addItem(t),i.push(e))};if(t instanceof Array)for(var a=0,h=t.length;h>a;a++)o(t[a]);else if(A.isDataTable(t))for(var d=this._getColumnNames(t),c=0,u=t.getNumberOfRows();u>c;c++){for(var l={},p=0,f=d.length;f>p;p++){var m=d[p];l[m]=t.getValue(c,p)}o(l)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");o(t)}return i.length&&this._trigger("add",{items:i},e),n.length&&this._trigger("update",{items:n},e),i.concat(n)},r.prototype.get=function(){var t,e,i,n,s=this,r=A.getType(arguments[0]);"String"==r||"Number"==r?(t=arguments[0],i=arguments[1],n=arguments[2]):"Array"==r?(e=arguments[0],i=arguments[1],n=arguments[2]):(i=arguments[0],n=arguments[1]);var o;if(i&&i.type){if(o="DataTable"==i.type?"DataTable":"Array",n&&o!=A.getType(n))throw new Error('Type of parameter "data" ('+A.getType(n)+") does not correspond with specified options.type ("+i.type+")");if("DataTable"==o&&!A.isDataTable(n))throw new Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else o=n?"DataTable"==A.getType(n)?"DataTable":"Array":"Array";var a,h,d,c,u=i&&i.convert||this.options.convert,l=i&&i.filter,p=[];if(void 0!=t)a=s._getItem(t,u),l&&!l(a)&&(a=null);else if(void 0!=e)for(d=0,c=e.length;c>d;d++)a=s._getItem(e[d],u),(!l||l(a))&&p.push(a);else for(h in this.data)this.data.hasOwnProperty(h)&&(a=s._getItem(h,u),(!l||l(a))&&p.push(a));if(i&&i.order&&void 0==t&&this._sort(p,i.order),i&&i.fields){var f=i.fields;if(void 0!=t)a=this._filterFields(a,f);else for(d=0,c=p.length;c>d;d++)p[d]=this._filterFields(p[d],f)}if("DataTable"==o){var m=this._getColumnNames(n);if(void 0!=t)s._appendRow(n,m,a);else for(d=0,c=p.length;c>d;d++)s._appendRow(n,m,p[d]);return n}if(void 0!=t)return a;if(n){for(d=0,c=p.length;c>d;d++)n.push(p[d]);return n}return p},r.prototype.getIds=function(t){var e,i,n,s,r,o=this.data,a=t&&t.filter,h=t&&t.order,d=t&&t.convert||this.options.convert,c=[];if(a)if(h){r=[];for(n in o)o.hasOwnProperty(n)&&(s=this._getItem(n,d),a(s)&&r.push(s));for(this._sort(r,h),e=0,i=r.length;i>e;e++)c[e]=r[e][this.fieldId]}else for(n in o)o.hasOwnProperty(n)&&(s=this._getItem(n,d),a(s)&&c.push(s[this.fieldId]));else if(h){r=[];for(n in o)o.hasOwnProperty(n)&&r.push(o[n]);for(this._sort(r,h),e=0,i=r.length;i>e;e++)c[e]=r[e][this.fieldId]}else for(n in o)o.hasOwnProperty(n)&&(s=o[n],c.push(s[this.fieldId]));return c},r.prototype.forEach=function(t,e){var i,n,s=e&&e.filter,r=e&&e.convert||this.options.convert,o=this.data;if(e&&e.order)for(var a=this.get(e),h=0,d=a.length;d>h;h++)i=a[h],n=i[this.fieldId],t(i,n);else for(n in o)o.hasOwnProperty(n)&&(i=this._getItem(n,r),(!s||s(i))&&t(i,n))},r.prototype.map=function(t,e){var i,n=e&&e.filter,s=e&&e.convert||this.options.convert,r=[],o=this.data;for(var a in o)o.hasOwnProperty(a)&&(i=this._getItem(a,s),(!n||n(i))&&r.push(t(i,a)));return e&&e.order&&this._sort(r,e.order),r},r.prototype._filterFields=function(t,e){var i={};for(var n in t)t.hasOwnProperty(n)&&-1!=e.indexOf(n)&&(i[n]=t[n]);return i},r.prototype._sort=function(t,e){if(A.isString(e)){var i=e;t.sort(function(t,e){var n=t[i],s=e[i];return n>s?1:s>n?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},r.prototype.remove=function(t,e){var i,n,s,r=[];if(t instanceof Array)for(i=0,n=t.length;n>i;i++)s=this._remove(t[i]),null!=s&&r.push(s);else s=this._remove(t),null!=s&&r.push(s);return r.length&&this._trigger("remove",{items:r},e),r},r.prototype._remove=function(t){if(A.isNumber(t)||A.isString(t)){if(this.data[t])return delete this.data[t],delete this.internalIds[t],t}else if(t instanceof Object){var e=t[this.fieldId];if(e&&this.data[e])return delete this.data[e],delete this.internalIds[e],e}return null},r.prototype.clear=function(t){var e=Object.keys(this.data);return this.data={},this.internalIds={},this._trigger("remove",{items:e},t),e},r.prototype.max=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var r=e[s],o=r[t];null!=o&&(!i||o>n)&&(i=r,n=o)}return i},r.prototype.min=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var r=e[s],o=r[t];null!=o&&(!i||n>o)&&(i=r,n=o)}return i},r.prototype.distinct=function(t){var e=this.data,i=[],n=this.options.convert[t],s=0;for(var r in e)if(e.hasOwnProperty(r)){for(var o=e[r],a=A.convert(o[t],n),h=!1,d=0;s>d;d++)if(i[d]==a){h=!0;break}h||(i[s]=a,s++)}return i},r.prototype._addItem=function(t){var e=t[this.fieldId];if(void 0!=e){if(this.data[e])throw new Error("Cannot add item: item with id "+e+" already exists")}else e=A.randomUUID(),t[this.fieldId]=e,this.internalIds[e]=t;var i={};for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=A.convert(t[n],s)}return this.data[e]=i,e},r.prototype._getItem=function(t,e){var i,n,s=this.data[t];if(!s)return null;var r={},o=this.fieldId,a=this.internalIds;if(e)for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==o&&n in a||(r[i]=A.convert(n,e[i])));else for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==o&&n in a||(r[i]=n));return r},r.prototype._updateItem=function(t){var e=t[this.fieldId];if(void 0==e)throw new Error("Cannot update item: item has no id (item: "+JSON.stringify(t)+")");var i=this.data[e];if(!i)throw new Error("Cannot update item: no item with id "+e+" found");for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=A.convert(t[n],s)}return e},r.prototype._getColumnNames=function(t){for(var e=[],i=0,n=t.getNumberOfColumns();n>i;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},r.prototype._appendRow=function(t,e,i){for(var n=t.addRow(),s=0,r=e.length;r>s;s++){var o=e[s];t.setValue(n,s,i[o])}},o.prototype.setData=function(t){var e,i,n;if(this.data){this.data.unsubscribe&&this.data.unsubscribe("*",this.listener),e=[];for(var s in this.ids)this.ids.hasOwnProperty(s)&&e.push(s);this.ids={},this._trigger("remove",{items:e})}if(this.data=t,this.data){for(this.fieldId=this.options.fieldId||this.data&&this.data.options&&this.data.options.fieldId||"id",e=this.data.getIds({filter:this.options&&this.options.filter}),i=0,n=e.length;n>i;i++)s=e[i],this.ids[s]=!0;this._trigger("add",{items:e}),this.data.subscribe&&this.data.subscribe("*",this.listener)}},o.prototype.get=function(){var t,e,i,n=this,s=A.getType(arguments[0]);"String"==s||"Number"==s||"Array"==s?(t=arguments[0],e=arguments[1],i=arguments[2]):(e=arguments[0],i=arguments[1]);var r=A.extend({},this.options,e);this.options.filter&&e&&e.filter&&(r.filter=function(t){return n.options.filter(t)&&e.filter(t)});var o=[];return void 0!=t&&o.push(t),o.push(r),o.push(i),this.data&&this.data.get.apply(this.data,o)},o.prototype.getIds=function(t){var e;if(this.data){var i,n=this.options.filter;i=t&&t.filter?n?function(e){return n(e)&&t.filter(e)}:t.filter:n,e=this.data.getIds({filter:i,order:t&&t.order})}else e=[];return e},o.prototype._onEvent=function(t,e,i){var n,s,r,o,a=e&&e.items,h=this.data,d=[],c=[],u=[];if(a&&h){switch(t){case"add":for(n=0,s=a.length;s>n;n++)r=a[n],o=this.get(r),o&&(this.ids[r]=!0,d.push(r));break;case"update":for(n=0,s=a.length;s>n;n++)r=a[n],o=this.get(r),o?this.ids[r]?c.push(r):(this.ids[r]=!0,d.push(r)):this.ids[r]&&(delete this.ids[r],u.push(r));break;case"remove":for(n=0,s=a.length;s>n;n++)r=a[n],this.ids[r]&&(delete this.ids[r],u.push(r))}d.length&&this._trigger("add",{items:d},i),c.length&&this._trigger("update",{items:c},i),u.length&&this._trigger("remove",{items:u},i)}},o.prototype.subscribe=r.prototype.subscribe,o.prototype.unsubscribe=r.prototype.unsubscribe,o.prototype._trigger=r.prototype._trigger,TimeStep=function(t,e,i){this.current=new Date,this._start=new Date,this._end=new Date,this.autoScale=!0,this.scale=TimeStep.SCALE.DAY,this.step=1,this.setRange(t,e,i)},TimeStep.SCALE={MILLISECOND:1,SECOND:2,MINUTE:3,HOUR:4,DAY:5,WEEKDAY:6,MONTH:7,YEAR:8},TimeStep.prototype.setRange=function(t,e,i){if(!(t instanceof Date&&e instanceof Date))throw"No legal start or end date in method setRange";this._start=void 0!=t?new Date(t.valueOf()):new Date,this._end=void 0!=e?new Date(e.valueOf()):new Date,this.autoScale&&this.setMinimumStep(i)},TimeStep.prototype.first=function(){this.current=new Date(this._start.valueOf()),this.roundToMinor()},TimeStep.prototype.roundToMinor=function(){switch(this.scale){case TimeStep.SCALE.YEAR:this.current.setFullYear(this.step*Math.floor(this.current.getFullYear()/this.step)),this.current.setMonth(0);case TimeStep.SCALE.MONTH:this.current.setDate(1);case TimeStep.SCALE.DAY:case TimeStep.SCALE.WEEKDAY:this.current.setHours(0);case TimeStep.SCALE.HOUR:this.current.setMinutes(0);case TimeStep.SCALE.MINUTE:this.current.setSeconds(0);case TimeStep.SCALE.SECOND:this.current.setMilliseconds(0)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.setMilliseconds(this.current.getMilliseconds()-this.current.getMilliseconds()%this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()-this.current.getSeconds()%this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()-this.current.getMinutes()%this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()-this.current.getHours()%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()-1-(this.current.getDate()-1)%this.step+1);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()-this.current.getMonth()%this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()-this.current.getFullYear()%this.step)}},TimeStep.prototype.hasNext=function(){return this.current.valueOf()<=this._end.valueOf()},TimeStep.prototype.next=function(){var t=this.current.valueOf();if(this.current.getMonth()<6)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current=new Date(this.current.valueOf()+1e3*this.step);break;case TimeStep.SCALE.MINUTE:this.current=new Date(this.current.valueOf()+1e3*this.step*60);break;case TimeStep.SCALE.HOUR:this.current=new Date(this.current.valueOf()+1e3*this.step*60*60);var e=this.current.getHours();this.current.setHours(e-e%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}else switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()+this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()+this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()+this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.getMilliseconds()0&&(this.step=e),this.autoScale=!1},TimeStep.prototype.setAutoScale=function(t){this.autoScale=t},TimeStep.prototype.setMinimumStep=function(t){if(void 0!=t){var e=31104e6,i=2592e6,n=864e5,s=36e5,r=6e4,o=1e3,a=1;1e3*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1e3),500*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=500),100*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=100),50*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=50),10*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=10),5*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=5),e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1),3*i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=3),i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=1),5*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=5),2*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=2),n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=1),n/2>t&&(this.scale=TimeStep.SCALE.WEEKDAY,this.step=1),4*s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=4),s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=1),15*r>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=15),10*r>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=10),5*r>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=5),r>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=1),15*o>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=15),10*o>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=10),5*o>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=5),o>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=1),200*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=200),100*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=100),50*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=50),10*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=10),5*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=5),a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=1)}},TimeStep.prototype.snap=function(t){if(this.scale==TimeStep.SCALE.YEAR){var e=t.getFullYear()+Math.round(t.getMonth()/12);t.setFullYear(Math.round(e/this.step)*this.step),t.setMonth(0),t.setDate(0),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MONTH)t.getDate()>15?(t.setDate(1),t.setMonth(t.getMonth()+1)):t.setDate(1),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0);else if(this.scale==TimeStep.SCALE.DAY||this.scale==TimeStep.SCALE.WEEKDAY){switch(this.step){case 5:case 2:t.setHours(24*Math.round(t.getHours()/24));break;default:t.setHours(12*Math.round(t.getHours()/12))}t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.HOUR){switch(this.step){case 4:t.setMinutes(60*Math.round(t.getMinutes()/60));break;default:t.setMinutes(30*Math.round(t.getMinutes()/30))}t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MINUTE){switch(this.step){case 15:case 10:t.setMinutes(5*Math.round(t.getMinutes()/5)),t.setSeconds(0);break;case 5:t.setSeconds(60*Math.round(t.getSeconds()/60));break;default:t.setSeconds(30*Math.round(t.getSeconds()/30))}t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.SECOND)switch(this.step){case 15:case 10:t.setSeconds(5*Math.round(t.getSeconds()/5)),t.setMilliseconds(0);break;case 5:t.setMilliseconds(1e3*Math.round(t.getMilliseconds()/1e3));break;default:t.setMilliseconds(500*Math.round(t.getMilliseconds()/500))}else if(this.scale==TimeStep.SCALE.MILLISECOND){var i=this.step>5?this.step/2:1;t.setMilliseconds(Math.round(t.getMilliseconds()/i)*i)}},TimeStep.prototype.isMajor=function(){switch(this.scale){case TimeStep.SCALE.MILLISECOND:return 0==this.current.getMilliseconds();case TimeStep.SCALE.SECOND:return 0==this.current.getSeconds();case TimeStep.SCALE.MINUTE:return 0==this.current.getHours()&&0==this.current.getMinutes();case TimeStep.SCALE.HOUR:return 0==this.current.getHours();case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return 1==this.current.getDate();case TimeStep.SCALE.MONTH:return 0==this.current.getMonth();case TimeStep.SCALE.YEAR:return!1;default:return!1}},TimeStep.prototype.getLabelMinor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return I(t).format("SSS");case TimeStep.SCALE.SECOND:return I(t).format("s");case TimeStep.SCALE.MINUTE:return I(t).format("HH:mm");case TimeStep.SCALE.HOUR:return I(t).format("HH:mm");case TimeStep.SCALE.WEEKDAY:return I(t).format("ddd D");case TimeStep.SCALE.DAY:return I(t).format("D");case TimeStep.SCALE.MONTH:return I(t).format("MMM");case TimeStep.SCALE.YEAR:return I(t).format("YYYY");default:return""}},TimeStep.prototype.getLabelMajor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return I(t).format("HH:mm:ss");case TimeStep.SCALE.SECOND:return I(t).format("D MMMM HH:mm");case TimeStep.SCALE.MINUTE:case TimeStep.SCALE.HOUR:return I(t).format("ddd D MMMM");case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return I(t).format("MMMM YYYY");case TimeStep.SCALE.MONTH:return I(t).format("YYYY");case TimeStep.SCALE.YEAR:return"";default:return""}},a.prototype.setOptions=function(t){A.extend(this.options,t)},a.prototype.update=function(){this._order(),this._stack()},a.prototype._order=function(){var t=this.parent.items;if(!t)throw new Error("Cannot stack items: parent does not contain items");var e=[],i=0;A.forEach(t,function(t){t.visible&&(e[i]=t,i++)});var n=this.options.order||this.defaultOptions.order;if("function"!=typeof n)throw new Error("Option order must be a function");e.sort(n),this.ordered=e},a.prototype._stack=function(){var t,e,i,n=this.ordered,s=this.options,r=s.orientation||this.defaultOptions.orientation,o="top"==r;for(i=s.margin&&void 0!==s.margin.item?s.margin.item:this.defaultOptions.margin.item,t=0,e=n.length;e>t;t++){var a=n[t],h=null;do h=this.checkOverlap(n,t,0,t-1,i),null!=h&&(a.top=o?h.top+h.height+i:h.top-a.height-i);while(h)}},a.prototype.checkOverlap=function(t,e,i,n,s){for(var r=this.collision,o=t[e],a=n;a>=i;a--){var h=t[a];if(r(o,h,s)&&a!=e)return h}return null},a.prototype.collision=function(t,e,i){return t.left-ie.left&&t.top-ie.top},h.prototype.setOptions=function(t){A.extend(this.options,t),null!==this.start&&null!==this.end&&this.setRange(this.start,this.end)},h.prototype.subscribe=function(t,e,i){function n(e){s._onMouseWheel(e,t,i)}var s=this;if("move"==e)t.on("dragstart",function(e){s._onDragStart(e,t)}),t.on("drag",function(e){s._onDrag(e,t,i)}),t.on("dragend",function(e){s._onDragEnd(e,t)});else{if("zoom"!=e)throw new TypeError('Unknown event "'+e+'". Choose "move" or "zoom".');t.on("mousewheel",n),t.on("DOMMouseScroll",n),t.on("touch",function(){s._onTouch()}),t.on("pinch",function(e){s._onPinch(e,t,i)})}},h.prototype.on=function(t,e){Y.addListener(this,t,e)},h.prototype._trigger=function(t){Y.trigger(this,t,{start:this.start,end:this.end})},h.prototype.setRange=function(t,e){var i=this._applyRange(t,e);i&&(this._trigger("rangechange"),this._trigger("rangechanged"))},h.prototype._applyRange=function(t,e){var i,n=null!=t?A.convert(t,"Number"):this.start,s=null!=e?A.convert(e,"Number"):this.end,r=null!=this.options.max?A.convert(this.options.max,"Date").valueOf():null,o=null!=this.options.min?A.convert(this.options.min,"Date").valueOf():null;if(isNaN(n)||null===n)throw new Error('Invalid start "'+t+'"');if(isNaN(s)||null===s)throw new Error('Invalid end "'+e+'"');if(n>s&&(s=n),null!==o&&o>n&&(i=o-n,n+=i,s+=i,null!=r&&s>r&&(s=r)),null!==r&&s>r&&(i=s-r,n-=i,s-=i,null!=o&&o>n&&(n=o)),null!==this.options.zoomMin){var a=parseFloat(this.options.zoomMin);0>a&&(a=0),a>s-n&&(this.end-this.start===a?(n=this.start,s=this.end):(i=a-(s-n),n-=i/2,s+=i/2))}if(null!==this.options.zoomMax){var h=parseFloat(this.options.zoomMax);0>h&&(h=0),s-n>h&&(this.end-this.start===h?(n=this.start,s=this.end):(i=s-n-h,n+=i/2,s-=i/2))}var d=this.start!=n||this.end!=s;return this.start=n,this.end=s,d},h.prototype.getRange=function(){return{start:this.start,end:this.end}},h.prototype.conversion=function(t){return h.conversion(this.start,this.end,t)},h.conversion=function(t,e,i){return 0!=i&&e-t!=0?{offset:t,scale:i/(e-t)}:{offset:0,scale:1}};var F={};h.prototype._onDragStart=function(t,e){if(!F.pinching){F.start=this.start,F.end=this.end;var i=e.frame;i&&(i.style.cursor="move")}},h.prototype._onDrag=function(t,e,i){if(d(i),!F.pinching){var n="horizontal"==i?t.gesture.deltaX:t.gesture.deltaY,s=F.end-F.start,r="horizontal"==i?e.width:e.height,o=-n/r*s;this._applyRange(F.start+o,F.end+o),this._trigger("rangechange")}},h.prototype._onDragEnd=function(t,e){F.pinching||(e.frame&&(e.frame.style.cursor="auto"),this._trigger("rangechanged"))},h.prototype._onMouseWheel=function(t,e,i){d(i);var n=0;if(t.wheelDelta?n=t.wheelDelta/120:t.detail&&(n=-t.detail/3),n){var s;s=0>n?1-n/5:1/(1+n/5);var r=A.fakeGesture(this,t),o=c(r.touches[0],e.frame),a=this._pointerToDate(e,i,o);this.zoom(s,a)}A.preventDefault(t)},h.prototype._onTouch=function(){F.start=this.start,F.end=this.end,F.pinching=!1,F.center=null},h.prototype._onPinch=function(t,e,i){if(F.pinching=!0,t.gesture.touches.length>1){F.center||(F.center=c(t.gesture.center,e.frame));var n=1/t.gesture.scale,s=this._pointerToDate(e,i,F.center),r=c(t.gesture.center,e.frame),o=(this._pointerToDate(e,i,r),parseInt(s+(F.start-s)*n)),a=parseInt(s+(F.end-s)*n);this.setRange(o,a)}},h.prototype._pointerToDate=function(t,e,i){var n;if("horizontal"==e){var s=t.width;return n=this.conversion(s),i.x/n.scale+n.offset}var r=t.height;return n=this.conversion(r),i.y/n.scale+n.offset},h.prototype.zoom=function(t,e){null==e&&(e=(this.start+this.end)/2);var i=e+(this.start-e)*t,n=e+(this.end-e)*t;this.setRange(i,n)},h.prototype.move=function(t){var e=this.end-this.start,i=this.start+e*t,n=this.end+e*t;this.start=i,this.end=n},h.prototype.moveTo=function(t){var e=(this.start+this.end)/2,i=e-t,n=this.start-i,s=this.end-i;this.setRange(n,s)},u.prototype.add=function(t){if(void 0==t.id)throw new Error("Component has no field id");if(!(t instanceof l||t instanceof u))throw new TypeError("Component must be an instance of prototype Component or Controller");t.controller=this,this.components[t.id]=t},u.prototype.remove=function(t){var e;for(e in this.components)if(this.components.hasOwnProperty(e)&&(e==t||this.components[e]==t))break;e&&delete this.components[e]},u.prototype.requestReflow=function(t){if(t)this.reflow();else if(!this.reflowTimer){var e=this;this.reflowTimer=setTimeout(function(){e.reflowTimer=void 0,e.reflow()},0)}},u.prototype.requestRepaint=function(t){if(t)this.repaint();else if(!this.repaintTimer){var e=this;this.repaintTimer=setTimeout(function(){e.repaintTimer=void 0,e.repaint()},0)}},u.prototype.repaint=function H(){function H(i,n){n in e||(i.depends&&i.depends.forEach(function(t){H(t,t.id)}),i.parent&&H(i.parent,i.parent.id),t=i.repaint()||t,e[n]=!0)}var t=!1;this.repaintTimer&&(clearTimeout(this.repaintTimer),this.repaintTimer=void 0);var e={};A.forEach(this.components,H),t&&this.reflow()},u.prototype.reflow=function z(){function z(i,n){n in e||(i.depends&&i.depends.forEach(function(t){z(t,t.id)}),i.parent&&z(i.parent,i.parent.id),t=i.reflow()||t,e[n]=!0)}var t=!1;this.reflowTimer&&(clearTimeout(this.reflowTimer),this.reflowTimer=void 0);var e={};A.forEach(this.components,z),t&&this.repaint()},l.prototype.setOptions=function(t){t&&(A.extend(this.options,t),this.controller&&(this.requestRepaint(),this.requestReflow()))},l.prototype.getOption=function(t){var e;return this.options&&(e=this.options[t]),void 0===e&&this.defaultOptions&&(e=this.defaultOptions[t]),e},l.prototype.getContainer=function(){return null},l.prototype.getFrame=function(){return this.frame},l.prototype.repaint=function(){return!1},l.prototype.reflow=function(){return!1},l.prototype.hide=function(){return this.frame&&this.frame.parentNode?(this.frame.parentNode.removeChild(this.frame),!0):!1},l.prototype.show=function(){return this.frame&&this.frame.parentNode?!1:this.repaint()},l.prototype.requestRepaint=function(){if(!this.controller)throw new Error("Cannot request a repaint: no controller configured");this.controller.requestRepaint()},l.prototype.requestReflow=function(){if(!this.controller)throw new Error("Cannot request a reflow: no controller configured");this.controller.requestReflow()},p.prototype=new l,p.prototype.setOptions=l.prototype.setOptions,p.prototype.getContainer=function(){return this.frame},p.prototype.repaint=function(){var t=0,e=A.updateProperty,i=A.option.asSize,n=this.options,s=this.frame;if(!s){s=document.createElement("div"),s.className="panel";var r=n.className;r&&("function"==typeof r?A.addClassName(s,String(r())):A.addClassName(s,String(r))),this.frame=s,t+=1}if(!s.parentNode){if(!this.parent)throw new Error("Cannot repaint panel: no parent attached");var o=this.parent.getContainer();if(!o)throw new Error("Cannot repaint panel: parent has no container element");o.appendChild(s),t+=1}return t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),t>0},p.prototype.reflow=function(){var t=0,e=A.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},f.prototype=new p,f.prototype.setOptions=l.prototype.setOptions,f.prototype.repaint=function(){var t=0,e=A.updateProperty,i=A.option.asSize,n=this.options,s=this.frame;if(s||(s=document.createElement("div"),this.frame=s,t+=1),!s.parentNode){if(!this.container)throw new Error("Cannot repaint root panel: no container attached");this.container.appendChild(s),t+=1}s.className="vis timeline rootpanel "+n.orientation;var r=n.className;return r&&A.addClassName(s,A.option.asString(r)),t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),this._updateEventEmitters(),this._updateWatch(),t>0},f.prototype.reflow=function(){var t=0,e=A.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},f.prototype._updateWatch=function(){var t=this.getOption("autoResize");t?this._watch():this._unwatch()},f.prototype._watch=function(){var t=this;this._unwatch();var e=function(){var e=t.getOption("autoResize");return e?(t.frame&&(t.frame.clientWidth!=t.width||t.frame.clientHeight!=t.height)&&t.requestReflow(),void 0):(t._unwatch(),void 0)};A.addEventListener(window,"resize",e),this.watchTimer=setInterval(e,1e3)},f.prototype._unwatch=function(){this.watchTimer&&(clearInterval(this.watchTimer),this.watchTimer=void 0)},f.prototype.on=function(t,e){var i=this.listeners[t];i||(i=[],this.listeners[t]=i),i.push(e),this._updateEventEmitters()},f.prototype._updateEventEmitters=function(){if(this.listeners){var t=this;A.forEach(this.listeners,function(e,i){if(t.emitters||(t.emitters={}),!(i in t.emitters)){var n=t.frame;if(n){var s=function(t){e.forEach(function(e){e(t)})};t.emitters[i]=s,t.hammer||(t.hammer=L(n,{prevent_default:!0})),t.hammer.on(i,s)}}})}},m.prototype=new l,m.prototype.setOptions=l.prototype.setOptions,m.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},m.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},m.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},m.prototype.repaint=function(){var t=0,e=A.updateProperty,i=A.option.asSize,n=this.options,s=this.getOption("orientation"),r=this.props,o=this.step,a=this.frame;if(a||(a=document.createElement("div"),this.frame=a,t+=1),a.className="axis",!a.parentNode){if(!this.parent)throw new Error("Cannot repaint time axis: no parent attached");var h=this.parent.getContainer();if(!h)throw new Error("Cannot repaint time axis: parent has no container element");h.appendChild(a),t+=1}var d=a.parentNode;if(d){var c=a.nextSibling;d.removeChild(a);var u="bottom"==s&&this.props.parentHeight&&this.height?this.props.parentHeight-this.height+"px":"0px";if(t+=e(a.style,"top",i(n.top,u)),t+=e(a.style,"left",i(n.left,"0px")),t+=e(a.style,"width",i(n.width,"100%")),t+=e(a.style,"height",i(n.height,this.height+"px")),this._repaintMeasureChars(),this.step){this._repaintStart(),o.first();for(var l=void 0,p=0;o.hasNext()&&1e3>p;){p++;var f=o.getCurrent(),m=this.toScreen(f),g=o.isMajor();this.getOption("showMinorLabels")&&this._repaintMinorText(m,o.getLabelMinor()),g&&this.getOption("showMajorLabels")?(m>0&&(void 0==l&&(l=m),this._repaintMajorText(m,o.getLabelMajor())),this._repaintMajorLine(m)):this._repaintMinorLine(m),o.next()}if(this.getOption("showMajorLabels")){var v=this.toTime(0),y=o.getLabelMajor(v),w=y.length*(r.majorCharWidth||10)+10;(void 0==l||l>w)&&this._repaintMajorText(0,y)}this._repaintEnd()}this._repaintLine(),c?d.insertBefore(a,c):d.appendChild(a)}return t>0},m.prototype._repaintStart=function(){var t=this.dom,e=t.redundant;e.majorLines=t.majorLines,e.majorTexts=t.majorTexts,e.minorLines=t.minorLines,e.minorTexts=t.minorTexts,t.majorLines=[],t.majorTexts=[],t.minorLines=[],t.minorTexts=[]},m.prototype._repaintEnd=function(){A.forEach(this.dom.redundant,function(t){for(;t.length;){var e=t.pop();e&&e.parentNode&&e.parentNode.removeChild(e)}})},m.prototype._repaintMinorText=function(t,e){var i=this.dom.redundant.minorTexts.shift();if(!i){var n=document.createTextNode("");i=document.createElement("div"),i.appendChild(n),i.className="text minor",this.frame.appendChild(i)}this.dom.minorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.left=t+"px",i.style.top=this.props.minorLabelTop+"px"},m.prototype._repaintMajorText=function(t,e){var i=this.dom.redundant.majorTexts.shift();if(!i){var n=document.createTextNode(e);i=document.createElement("div"),i.className="text major",i.appendChild(n),this.frame.appendChild(i)}this.dom.majorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.top=this.props.majorLabelTop+"px",i.style.left=t+"px"},m.prototype._repaintMinorLine=function(t){var e=this.dom.redundant.minorLines.shift();e||(e=document.createElement("div"),e.className="grid vertical minor",this.frame.appendChild(e)),this.dom.minorLines.push(e);var i=this.props;e.style.top=i.minorLineTop+"px",e.style.height=i.minorLineHeight+"px",e.style.left=t-i.minorLineWidth/2+"px"},m.prototype._repaintMajorLine=function(t){var e=this.dom.redundant.majorLines.shift();e||(e=document.createElement("DIV"),e.className="grid vertical major",this.frame.appendChild(e)),this.dom.majorLines.push(e);var i=this.props;e.style.top=i.majorLineTop+"px",e.style.left=t-i.majorLineWidth/2+"px",e.style.height=i.majorLineHeight+"px"},m.prototype._repaintLine=function(){{var t=this.dom.line,e=this.frame;this.options}this.getOption("showMinorLabels")||this.getOption("showMajorLabels")?(t?(e.removeChild(t),e.appendChild(t)):(t=document.createElement("div"),t.className="grid horizontal major",e.appendChild(t),this.dom.line=t),t.style.top=this.props.lineTop+"px"):t&&t.parentElement&&(e.removeChild(t.line),delete this.dom.line)},m.prototype._repaintMeasureChars=function(){var t,e=this.dom;if(!e.measureCharMinor){t=document.createTextNode("0");var i=document.createElement("DIV");i.className="text minor measure",i.appendChild(t),this.frame.appendChild(i),e.measureCharMinor=i}if(!e.measureCharMajor){t=document.createTextNode("0");var n=document.createElement("DIV");n.className="text major measure",n.appendChild(t),this.frame.appendChild(n),e.measureCharMajor=n}},m.prototype.reflow=function(){var t=0,e=A.updateProperty,i=this.frame,n=this.range;if(!n)throw new Error("Cannot repaint time axis: no range configured");if(i){t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft);var s=this.props,r=this.getOption("showMinorLabels"),o=this.getOption("showMajorLabels"),a=this.dom.measureCharMinor,h=this.dom.measureCharMajor;a&&(s.minorCharHeight=a.clientHeight,s.minorCharWidth=a.clientWidth),h&&(s.majorCharHeight=h.clientHeight,s.majorCharWidth=h.clientWidth);var d=i.parentNode?i.parentNode.offsetHeight:0;switch(d!=s.parentHeight&&(s.parentHeight=d,t+=1),this.getOption("orientation")){case"bottom":s.minorLabelHeight=r?s.minorCharHeight:0,s.majorLabelHeight=o?s.majorCharHeight:0,s.minorLabelTop=0,s.majorLabelTop=s.minorLabelTop+s.minorLabelHeight,s.minorLineTop=-this.top,s.minorLineHeight=Math.max(this.top+s.majorLabelHeight,0),s.minorLineWidth=1,s.majorLineTop=-this.top,s.majorLineHeight=Math.max(this.top+s.minorLabelHeight+s.majorLabelHeight,0),s.majorLineWidth=1,s.lineTop=0;break;case"top":s.minorLabelHeight=r?s.minorCharHeight:0,s.majorLabelHeight=o?s.majorCharHeight:0,s.majorLabelTop=0,s.minorLabelTop=s.majorLabelTop+s.majorLabelHeight,s.minorLineTop=s.minorLabelTop,s.minorLineHeight=Math.max(d-s.majorLabelHeight-this.top),s.minorLineWidth=1,s.majorLineTop=0,s.majorLineHeight=Math.max(d-this.top),s.majorLineWidth=1,s.lineTop=s.majorLabelHeight+s.minorLabelHeight;break;default:throw new Error('Unkown orientation "'+this.getOption("orientation")+'"')}var c=s.minorLabelHeight+s.majorLabelHeight;t+=e(this,"width",i.offsetWidth),t+=e(this,"height",c),this._updateConversion();var u=A.convert(n.start,"Number"),l=A.convert(n.end,"Number"),p=this.toTime(5*(s.minorCharWidth||10)).valueOf()-this.toTime(0).valueOf();this.step=new TimeStep(new Date(u),new Date(l),p),t+=e(s.range,"start",u),t+=e(s.range,"end",l),t+=e(s.range,"minimumStep",p.valueOf())}return t>0},m.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},g.prototype=new l,g.prototype.setOptions=l.prototype.setOptions,g.prototype.getContainer=function(){return this.frame},g.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCurrentTime"))return t&&(i.removeChild(t),delete this.frame),void 0;t||(t=document.createElement("div"),t.className="currenttime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t),this.frame=t),e.conversion||e._updateConversion();var n=new Date,s=e.toScreen(n);t.style.left=s+"px",t.title="Current time: "+n,void 0!==this.currentTimeTimer&&(clearTimeout(this.currentTimeTimer),delete this.currentTimeTimer);var r=this,o=1/e.conversion.scale/2;return 30>o&&(o=30),this.currentTimeTimer=setTimeout(function(){r.repaint()},o),!1},v.prototype=new l,v.prototype.setOptions=l.prototype.setOptions,v.prototype.getContainer=function(){return this.frame},v.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCustomTime"))return t&&(i.removeChild(t),delete this.frame),void 0;if(!t){t=document.createElement("div"),t.className="customtime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t);var n=document.createElement("div");n.style.position="relative",n.style.top="0px",n.style.left="-10px",n.style.height="100%",n.style.width="20px",t.appendChild(n),this.frame=t,this.subscribe(this,"movetime")}e.conversion||e._updateConversion();var s=e.toScreen(this.customTime);return t.style.left=s+"px",t.title="Time: "+this.customTime,!1},v.prototype._setCustomTime=function(t){this.customTime=new Date(t.valueOf()),this.repaint()},v.prototype._getCustomTime=function(){return new Date(this.customTime.valueOf())},v.prototype.subscribe=function(t,e){var i=this,n={component:t,event:e,callback:function(t){i._onMouseDown(t,n)},params:{}};t.on("mousedown",n.callback),i.listeners.push(n)},v.prototype.on=function(t,e){var i=this.frame;if(!i)throw new Error("Cannot add event listener: no parent attached");Y.addListener(this,t,e),A.addEventListener(i,t,e)},v.prototype._onMouseDown=function(t,e){t=t||window.event;var i=e.params,n=t.which?1==t.which:1==t.button;if(n){i.mouseX=A.getPageX(t),i.moved=!1,i.customTime=this.customTime;var s=this;i.onMouseMove||(i.onMouseMove=function(t){s._onMouseMove(t,e)},A.addEventListener(document,"mousemove",i.onMouseMove)),i.onMouseUp||(i.onMouseUp=function(t){s._onMouseUp(t,e)},A.addEventListener(document,"mouseup",i.onMouseUp)),A.stopPropagation(t),A.preventDefault(t)}},v.prototype._onMouseMove=function(t,e){t=t||window.event;var i=e.params,n=this.parent,s=A.getPageX(t);void 0===i.mouseX&&(i.mouseX=s);var r=s-i.mouseX;Math.abs(r)>=1&&(i.moved=!0);var o=n.toScreen(i.customTime),a=o+r,h=n.toTime(a);this._setCustomTime(h),Y.trigger(this,"timechange",{customTime:this.customTime}),A.preventDefault(t)},v.prototype._onMouseUp=function(t,e){t=t||window.event;var i=e.params;i.onMouseMove&&(A.removeEventListener(document,"mousemove",i.onMouseMove),i.onMouseMove=null),i.onMouseUp&&(A.removeEventListener(document,"mouseup",i.onMouseUp),i.onMouseUp=null),i.moved&&Y.trigger(this,"timechanged",{customTime:this.customTime})},y.prototype=new p,y.types={box:_,range:E,rangeoverflow:T,point:b},y.prototype.setOptions=l.prototype.setOptions,y.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},y.prototype.repaint=function(){var t=0,e=A.updateProperty,i=A.option.asSize,n=this.options,s=this.getOption("orientation"),r=this.defaultOptions,o=this.frame;if(!o){o=document.createElement("div"),o.className="itemset";var a=n.className;a&&A.addClassName(o,A.option.asString(a));var h=document.createElement("div");h.className="background",o.appendChild(h),this.dom.background=h;var d=document.createElement("div");d.className="foreground",o.appendChild(d),this.dom.foreground=d;var c=document.createElement("div");c.className="itemset-axis",this.dom.axis=c,this.frame=o,t+=1}if(!this.parent)throw new Error("Cannot repaint itemset: no parent attached");var u=this.parent.getContainer();if(!u)throw new Error("Cannot repaint itemset: parent has no container element");o.parentNode||(u.appendChild(o),t+=1),this.dom.axis.parentNode||(u.appendChild(this.dom.axis),t+=1),t+=e(o.style,"left",i(n.left,"0px")),t+=e(o.style,"top",i(n.top,"0px")),t+=e(o.style,"width",i(n.width,"100%")),t+=e(o.style,"height",i(n.height,this.height+"px")),t+=e(this.dom.axis.style,"left",i(n.left,"0px")),t+=e(this.dom.axis.style,"width",i(n.width,"100%")),t+="bottom"==s?e(this.dom.axis.style,"top",this.height+this.top+"px"):e(this.dom.axis.style,"top",this.top+"px"),this._updateConversion();var l=this,p=this.queue,f=this.itemsData,m=this.items,g={};return Object.keys(p).forEach(function(e){var i=p[e],s=m[e];switch(i){case"add":case"update":var o=f&&f.get(e,g);if(o){var a=o.type||o.start&&o.end&&"range"||n.type||"box",h=y.types[a];if(s&&(h&&s instanceof h?(s.data=o,t++):(t+=s.hide(),s=null)),!s){if(!h)throw new TypeError('Unknown item type "'+a+'"');s=new h(l,o,n,r),t++}s.repaint(),m[e]=s}delete p[e];break;case"remove":s&&(t+=s.hide()),delete m[e],delete p[e];break;default:console.log('Error: unknown action "'+i+'"')}}),A.forEach(this.items,function(e){e.visible?(t+=e.show(),e.reposition()):t+=e.hide()}),t>0},y.prototype.getForeground=function(){return this.dom.foreground},y.prototype.getBackground=function(){return this.dom.background},y.prototype.getAxis=function(){return this.dom.axis},y.prototype.reflow=function(){var t=0,e=this.options,i=e.margin&&e.margin.axis||this.defaultOptions.margin.axis,n=e.margin&&e.margin.item||this.defaultOptions.margin.item,s=A.updateProperty,r=A.option.asNumber,o=A.option.asSize,a=this.frame;if(a){this._updateConversion(),A.forEach(this.items,function(e){t+=e.reflow()}),this.stack.update();var h,d=r(e.maxHeight),c=null!=o(e.height);if(c)h=a.offsetHeight;else{var u=this.stack.ordered;if(u.length){var l=u[0].top,p=u[0].top+u[0].height;A.forEach(u,function(t){l=Math.min(l,t.top),p=Math.max(p,t.top+t.height)}),h=p-l+i+n}else h=i+n}null!=d&&(h=Math.min(h,d)),t+=s(this,"height",h),t+=s(this,"top",a.offsetTop),t+=s(this,"left",a.offsetLeft),t+=s(this,"width",a.offsetWidth)}else t+=1;return t>0},y.prototype.hide=function(){var t=!1;return this.frame&&this.frame.parentNode&&(this.frame.parentNode.removeChild(this.frame),t=!0),this.dom.axis&&this.dom.axis.parentNode&&(this.dom.axis.parentNode.removeChild(this.dom.axis),t=!0),t},y.prototype.setItems=function(t){var e,i=this,n=this.itemsData;if(t){if(!(t instanceof r||t instanceof o))throw new TypeError("Data must be an instance of DataSet");this.itemsData=t}else this.itemsData=null;if(n&&(A.forEach(this.listeners,function(t,e){n.unsubscribe(e,t)}),e=n.getIds(),this._onRemove(e)),this.itemsData){var s=this.id;A.forEach(this.listeners,function(t,e){i.itemsData.subscribe(e,t,s)}),e=this.itemsData.getIds(),this._onAdd(e)}},y.prototype.getItems=function(){return this.itemsData},y.prototype._onUpdate=function(t){this._toQueue("update",t)},y.prototype._onAdd=function(t){this._toQueue("add",t)},y.prototype._onRemove=function(t){this._toQueue("remove",t)},y.prototype._toQueue=function(t,e){var i=this.queue;e.forEach(function(e){i[e]=t}),this.controller&&this.requestRepaint()},y.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},y.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},y.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},w.prototype.select=function(){this.selected=!0},w.prototype.unselect=function(){this.selected=!1},w.prototype.show=function(){return!1},w.prototype.hide=function(){return!1},w.prototype.repaint=function(){return!1},w.prototype.reflow=function(){return!1},w.prototype.getWidth=function(){return this.width},_.prototype=new w(null,null),_.prototype.select=function(){this.selected=!0},_.prototype.unselect=function(){this.selected=!1},_.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");if(!e.box.parentNode){var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");i.appendChild(e.box),t=!0}if(!e.line.parentNode){var n=this.parent.getBackground();if(!n)throw new Error("Cannot repaint time axis: parent has no background container element");n.appendChild(e.line),t=!0}if(!e.dot.parentNode){var s=this.parent.getAxis();if(!n)throw new Error("Cannot repaint time axis: parent has no axis container element");s.appendChild(e.dot),t=!0}if(this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var r=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=r&&(this.className=r,e.box.className="item box"+r,e.line.className="item line"+r,e.dot.className="item dot"+r,t=!0)}return t},_.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint() +},_.prototype.hide=function(){var t=!1,e=this.dom;return e&&(e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),e.line.parentNode&&e.line.parentNode.removeChild(e.line),e.dot.parentNode&&e.dot.parentNode.removeChild(e.dot)),t},_.prototype.reflow=function(){var t,e,i,n,s,r,o,a,h,d,c,u,l=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(c=this.data,u=this.parent&&this.parent.range,c&&u){var p=u.end-u.start;this.visible=c.start>u.start-p&&c.start0},_.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("DIV"),t.content=document.createElement("DIV"),t.content.className="content",t.box.appendChild(t.content),t.line=document.createElement("DIV"),t.line.className="line",t.dot=document.createElement("DIV"),t.dot.className="dot")},_.prototype.reposition=function(){var t=this.dom,e=this.props,i=this.options.orientation||this.defaultOptions.orientation;if(t){var n=t.box,s=t.line,r=t.dot;n.style.left=this.left+"px",n.style.top=this.top+"px",s.style.left=e.line.left+"px","top"==i?(s.style.top="0px",s.style.height=this.top+"px"):(s.style.top=this.top+this.height+"px",s.style.height=Math.max(this.parent.height-this.top-this.height+this.props.dot.height/2,0)+"px"),r.style.left=e.dot.left+"px",r.style.top=e.dot.top+"px"}},b.prototype=new w(null,null),b.prototype.select=function(){this.selected=!0},b.prototype.unselect=function(){this.selected=!1},b.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.point.parentNode||(i.appendChild(e.point),i.appendChild(e.point),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.point.className="item point"+n,t=!0)}return t},b.prototype.show=function(){return this.dom&&this.dom.point.parentNode?!1:this.repaint()},b.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.point.parentNode&&(e.point.parentNode.removeChild(e.point),t=!0),t},b.prototype.reflow=function(){var t,e,i,n,s,r,o,a,h,d,c=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(h=this.data,d=this.parent&&this.parent.range,h&&d){var u=d.end-d.start;this.visible=h.start>d.start-u&&h.start0},b.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.point=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.point.appendChild(t.content),t.dot=document.createElement("div"),t.dot.className="dot",t.point.appendChild(t.dot))},b.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.point.style.top=this.top+"px",t.point.style.left=this.left+"px",t.content.style.marginLeft=e.content.marginLeft+"px",t.dot.style.top=e.dot.top+"px")},E.prototype=new w(null,null),E.prototype.select=function(){this.selected=!0},E.prototype.unselect=function(){this.selected=!1},E.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=this.data.className?" "+this.data.className:"";this.className!=n&&(this.className=n,e.box.className="item range"+n,t=!0)}return t},E.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},E.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),t},E.prototype.reflow=function(){var t,e,i,n,s,r,o,a,h,d,c,u,l,p,f,m,g=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(void 0==this.data.end)throw new Error('Property "end" missing in item '+this.data.id);return h=this.data,d=this.parent&&this.parent.range,this.visible=h&&d?h.startd.start:!1,this.visible&&(t=this.dom,t?(e=this.props,i=this.options,r=this.parent,o=r.toScreen(this.data.start),a=r.toScreen(this.data.end),c=A.updateProperty,u=t.box,l=r.width,f=i.orientation||this.defaultOptions.orientation,n=i.margin&&i.margin.axis||this.defaultOptions.margin.axis,s=i.padding||this.defaultOptions.padding,g+=c(e.content,"width",t.content.offsetWidth),g+=c(this,"height",u.offsetHeight),-l>o&&(o=-l),a>2*l&&(a=2*l),p=0>o?Math.min(-o,a-o-e.content.width-2*s):0,g+=c(e.content,"left",p),"top"==f?(m=n,g+=c(this,"top",m)):(m=r.height-this.height-n,g+=c(this,"top",m)),g+=c(this,"left",o),g+=c(this,"width",Math.max(a-o,1))):g+=1),g>0},E.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content))},E.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.box.style.top=this.top+"px",t.box.style.left=this.left+"px",t.box.style.width=this.width+"px",t.content.style.left=e.content.left+"px")},T.prototype=new E(null,null),T.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=this.data.className?" "+this.data.className:"";this.className!=n&&(this.className=n,e.box.className="item rangeoverflow"+n,t=!0)}return t},T.prototype.getWidth=function(){return void 0!==this.props.content&&this.width0},x.prototype=new p,x.prototype.setOptions=l.prototype.setOptions,x.prototype.setRange=function(){},x.prototype.setItems=function(t){this.itemsData=t;for(var e in this.groups)if(this.groups.hasOwnProperty(e)){var i=this.groups[e];i.setItems(t)}},x.prototype.getItems=function(){return this.itemsData},x.prototype.setRange=function(t){this.range=t},x.prototype.setGroups=function(t){var e,i=this;if(this.groupsData&&(A.forEach(this.listeners,function(t,e){i.groupsData.unsubscribe(e,t)}),e=this.groupsData.getIds(),this._onRemove(e)),t?t instanceof r?this.groupsData=t:(this.groupsData=new r({convert:{start:"Date",end:"Date"}}),this.groupsData.add(t)):this.groupsData=null,this.groupsData){var n=this.id;A.forEach(this.listeners,function(t,e){i.groupsData.subscribe(e,t,n)}),e=this.groupsData.getIds(),this._onAdd(e)}},x.prototype.getGroups=function(){return this.groupsData},x.prototype.repaint=function(){var t,e,i,n,s=0,r=A.updateProperty,o=A.option.asSize,a=A.option.asElement,h=this.options,d=this.dom.frame,c=this.dom.labels,u=this.dom.labelSet;if(!this.parent)throw new Error("Cannot repaint groupset: no parent attached");var l=this.parent.getContainer();if(!l)throw new Error("Cannot repaint groupset: parent has no container element");if(!d){d=document.createElement("div"),d.className="groupset",this.dom.frame=d;var p=h.className;p&&A.addClassName(d,A.option.asString(p)),s+=1}d.parentNode||(l.appendChild(d),s+=1);var f=a(h.labelContainer);if(!f)throw new Error('Cannot repaint groupset: option "labelContainer" not defined');c||(c=document.createElement("div"),c.className="labels",this.dom.labels=c),u||(u=document.createElement("div"),u.className="label-set",c.appendChild(u),this.dom.labelSet=u),c.parentNode&&c.parentNode==f||(c.parentNode&&c.parentNode.removeChild(c.parentNode),f.appendChild(c)),s+=r(d.style,"height",o(h.height,this.height+"px")),s+=r(d.style,"top",o(h.top,"0px")),s+=r(d.style,"left",o(h.left,"0px")),s+=r(d.style,"width",o(h.width,"100%")),s+=r(u.style,"top",o(h.top,"0px")),s+=r(u.style,"height",o(h.height,this.height+"px"));var m=this,g=this.queue,v=this.groups,y=this.groupsData,w=Object.keys(g);if(w.length){w.forEach(function(t){var e=g[t],i=v[t];switch(e){case"add":case"update":if(!i){var n=Object.create(m.options);A.extend(n,{height:null,maxHeight:null}),i=new S(m,t,n),i.setItems(m.itemsData),v[t]=i,m.controller.add(i)}i.data=y.get(t),delete g[t];break;case"remove":i&&(i.setItems(),delete v[t],m.controller.remove(i)),delete g[t];break;default:console.log('Error: unknown action "'+e+'"')}});var _=this.groupsData.getIds({order:this.options.groupOrder});for(t=0;t<_.length;t++)!function(t,e){var i=0;e&&(i=function(){return e.top+e.height}),t.setOptions({top:i})}(v[_[t]],v[_[t-1]]);for(;u.firstChild;)u.removeChild(u.firstChild);for(t=0;t<_.length;t++)e=_[t],n=this._createLabel(e),u.appendChild(n);s++}for(e in v)v.hasOwnProperty(e)&&(i=v[e],n=i.label,n&&(n.style.top=i.top+"px",n.style.height=i.height+"px"));return s>0},x.prototype._createLabel=function(t){var e=this.groups[t],i=document.createElement("div");i.className="label";var n=document.createElement("div");n.className="inner",i.appendChild(n);var s=e.data&&e.data.content;s instanceof Element?n.appendChild(s):void 0!=s&&(n.innerHTML=s);var r=e.data&&e.data.className;return r&&A.addClassName(i,r),e.label=i,i},x.prototype.getContainer=function(){return this.dom.frame},x.prototype.getLabelsWidth=function(){return this.props.labels.width},x.prototype.reflow=function(){var t,e,i=0,n=this.options,s=A.updateProperty,r=A.option.asNumber,o=A.option.asSize,a=this.dom.frame;if(a){var h,d=r(n.maxHeight),c=null!=o(n.height);if(c)h=a.offsetHeight;else{h=0;for(t in this.groups)this.groups.hasOwnProperty(t)&&(e=this.groups[t],h+=e.height)}null!=d&&(h=Math.min(h,d)),i+=s(this,"height",h),i+=s(this,"top",a.offsetTop),i+=s(this,"left",a.offsetLeft),i+=s(this,"width",a.offsetWidth)}var u=0;for(t in this.groups)if(this.groups.hasOwnProperty(t)){e=this.groups[t];var l=e.props&&e.props.label&&e.props.label.width||0;u=Math.max(u,l)}return i+=s(this.props.labels,"width",u),i>0},x.prototype.hide=function(){return this.dom.frame&&this.dom.frame.parentNode?(this.dom.frame.parentNode.removeChild(this.dom.frame),!0):!1},x.prototype.show=function(){return this.dom.frame&&this.dom.frame.parentNode?!1:this.repaint()},x.prototype._onUpdate=function(t){this._toQueue(t,"update")},x.prototype._onAdd=function(t){this._toQueue(t,"add")},x.prototype._onRemove=function(t){this._toQueue(t,"remove")},x.prototype._toQueue=function(t,e){var i=this.queue;t.forEach(function(t){i[t]=e}),this.controller&&this.requestRepaint()},D.prototype.setOptions=function(t){A.extend(this.options,t),this.range.setRange(),this.controller.reflow(),this.controller.repaint()},D.prototype.setCustomTime=function(t){this.customtime._setCustomTime(t)},D.prototype.getCustomTime=function(){return new Date(this.customtime.customTime.valueOf())},D.prototype.setItems=function(t){var e,i=null==this.itemsData;if(t?t instanceof r&&(e=t):e=null,t instanceof r||(e=new r({convert:{start:"Date",end:"Date"}}),e.add(t)),this.itemsData=e,this.content.setItems(e),i&&(void 0==this.options.start||void 0==this.options.end)){var n=this.getItemRange(),s=n.min,o=n.max;if(null!=s&&null!=o){var a=o.valueOf()-s.valueOf();0>=a&&(a=864e5),s=new Date(s.valueOf()-.05*a),o=new Date(o.valueOf()+.05*a)}void 0!=this.options.start&&(s=A.convert(this.options.start,"Date")),void 0!=this.options.end&&(o=A.convert(this.options.end,"Date")),(null!=s||null!=o)&&this.range.setRange(s,o)}},D.prototype.setGroups=function(t){var e=this;this.groupsData=t;var i=this.groupsData?x:y;if(!(this.content instanceof i)){this.content&&(this.content.hide(),this.content.setItems&&this.content.setItems(),this.content.setGroups&&this.content.setGroups(),this.controller.remove(this.content));var n=Object.create(this.options);A.extend(n,{top:function(){return"top"==e.options.orientation?e.timeaxis.height:e.itemPanel.height-e.timeaxis.height-e.content.height},left:null,width:"100%",height:function(){return e.options.height?e.itemPanel.height-e.timeaxis.height:null},maxHeight:function(){if(e.options.maxHeight){if(!A.isNumber(e.options.maxHeight))throw new TypeError("Number expected for property maxHeight");return e.options.maxHeight-e.timeaxis.height}return null},labelContainer:function(){return e.labelPanel.getContainer()}}),this.content=new i(this.itemPanel,[this.timeaxis],n),this.content.setRange&&this.content.setRange(this.range),this.content.setItems&&this.content.setItems(this.itemsData),this.content.setGroups&&this.content.setGroups(this.groupsData),this.controller.add(this.content)}},D.prototype.getItemRange=function(){var t=this.itemsData,e=null,i=null;if(t){var n=t.min("start");e=n?n.start.valueOf():null;var s=t.max("start");s&&(i=s.start.valueOf());var r=t.max("end");r&&(i=null==i?r.end.valueOf():Math.max(i,r.end.valueOf()))}return{min:null!=e?new Date(e):null,max:null!=i?new Date(i):null}},function(t){function e(t){return D=t,l()}function i(){M=0,C=D.charAt(0)}function n(){M++,C=D.charAt(M)}function s(){return D.charAt(M+1)}function r(t){return L.test(t)}function o(t,e){if(t||(t={}),e)for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function a(t,e,i){for(var n=e.split("."),s=t;n.length;){var r=n.shift();n.length?(s[r]||(s[r]={}),s=s[r]):s[r]=i}}function h(t,e){for(var i,n,s=null,r=[t],a=t;a.parent;)r.push(a.parent),a=a.parent;if(a.nodes)for(i=0,n=a.nodes.length;n>i;i++)if(e.id===a.nodes[i].id){s=a.nodes[i];break}for(s||(s={id:e.id},t.node&&(s.attr=o(s.attr,t.node))),i=r.length-1;i>=0;i--){var h=r[i];h.nodes||(h.nodes=[]),-1==h.nodes.indexOf(s)&&h.nodes.push(s)}e.attr&&(s.attr=o(s.attr,e.attr))}function d(t,e){if(t.edges||(t.edges=[]),t.edges.push(e),t.edge){var i=o({},t.edge);e.attr=o(i,e.attr)}}function c(t,e,i,n,s){var r={from:e,to:i,type:n};return t.edge&&(r.attr=o({},t.edge)),r.attr=o(r.attr||{},s),r}function u(){for(N=S.NULL,O="";" "==C||" "==C||"\n"==C||"\r"==C;)n();do{var t=!1;if("#"==C){for(var e=M-1;" "==D.charAt(e)||" "==D.charAt(e);)e--;if("\n"==D.charAt(e)||""==D.charAt(e)){for(;""!=C&&"\n"!=C;)n();t=!0}}if("/"==C&&"/"==s()){for(;""!=C&&"\n"!=C;)n();t=!0}if("/"==C&&"*"==s()){for(;""!=C;){if("*"==C&&"/"==s()){n(),n();break}n()}t=!0}for(;" "==C||" "==C||"\n"==C||"\r"==C;)n()}while(t);if(""==C)return N=S.DELIMITER,void 0;var i=C+s();if(x[i])return N=S.DELIMITER,O=i,n(),n(),void 0;if(x[C])return N=S.DELIMITER,O=C,n(),void 0;if(r(C)||"-"==C){for(O+=C,n();r(C);)O+=C,n();return"false"==O?O=!1:"true"==O?O=!0:isNaN(Number(O))||(O=Number(O)),N=S.IDENTIFIER,void 0}if('"'==C){for(n();""!=C&&('"'!=C||'"'==C&&'"'==s());)O+=C,'"'==C&&n(),n();if('"'!=C)throw _('End of string " expected');return n(),N=S.IDENTIFIER,void 0}for(N=S.UNKNOWN;""!=C;)O+=C,n();throw new SyntaxError('Syntax error in part "'+b(O,30)+'"')}function l(){var t={};if(i(),u(),"strict"==O&&(t.strict=!0,u()),("graph"==O||"digraph"==O)&&(t.type=O,u()),N==S.IDENTIFIER&&(t.id=O,u()),"{"!=O)throw _("Angle bracket { expected");if(u(),p(t),"}"!=O)throw _("Angle bracket } expected");if(u(),""!==O)throw _("End of file expected");return u(),delete t.node,delete t.edge,delete t.graph,t}function p(t){for(;""!==O&&"}"!=O;)f(t),";"==O&&u()}function f(t){var e=m(t);if(e)return y(t,e),void 0;var i=g(t);if(!i){if(N!=S.IDENTIFIER)throw _("Identifier expected");var n=O;if(u(),"="==O){if(u(),N!=S.IDENTIFIER)throw _("Identifier expected");t[n]=O,u()}else v(t,n)}}function m(t){var e=null;if("subgraph"==O&&(e={},e.type="subgraph",u(),N==S.IDENTIFIER&&(e.id=O,u())),"{"==O){if(u(),e||(e={}),e.parent=t,e.node=t.node,e.edge=t.edge,e.graph=t.graph,p(e),"}"!=O)throw _("Angle bracket } expected");u(),delete e.node,delete e.edge,delete e.graph,delete e.parent,t.subgraphs||(t.subgraphs=[]),t.subgraphs.push(e)}return e}function g(t){return"node"==O?(u(),t.node=w(),"node"):"edge"==O?(u(),t.edge=w(),"edge"):"graph"==O?(u(),t.graph=w(),"graph"):null}function v(t,e){var i={id:e},n=w();n&&(i.attr=n),h(t,i),y(t,e)}function y(t,e){for(;"->"==O||"--"==O;){var i,n=O;u();var s=m(t);if(s)i=s;else{if(N!=S.IDENTIFIER)throw _("Identifier or subgraph expected");i=O,h(t,{id:i}),u()}var r=w(),o=c(t,e,i,n,r);d(t,o),e=i}}function w(){for(var t=null;"["==O;){for(u(),t={};""!==O&&"]"!=O;){if(N!=S.IDENTIFIER)throw _("Attribute name expected");var e=O;if(u(),"="!=O)throw _("Equal sign = expected");if(u(),N!=S.IDENTIFIER)throw _("Attribute value expected");var i=O;a(t,e,i),u(),","==O&&u()}if("]"!=O)throw _("Bracket ] expected");u()}return t}function _(t){return new SyntaxError(t+', got "'+b(O,30)+'" (char '+M+")")}function b(t,e){return t.length<=e?t:t.substr(0,27)+"..."}function E(t,e,i){t instanceof Array?t.forEach(function(t){e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}):e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}function T(t){function i(t){var e={from:t.from,to:t.to};return o(e,t.attr),e.style="->"==t.type?"arrow":"line",e}var n=e(t),s={nodes:[],edges:[],options:{}};return n.nodes&&n.nodes.forEach(function(t){var e={id:t.id,label:String(t.label||t.id)};o(e,t.attr),e.image&&(e.shape="image"),s.nodes.push(e)}),n.edges&&n.edges.forEach(function(t){var e,n;e=t.from instanceof Object?t.from.nodes:{id:t.from},n=t.to instanceof Object?t.to.nodes:{id:t.to},t.from instanceof Object&&t.from.edges&&t.from.edges.forEach(function(t){var e=i(t);s.edges.push(e)}),E(e,n,function(e,n){var r=c(s,e.id,n.id,t.type,t.attr),o=i(r);s.edges.push(o)}),t.to instanceof Object&&t.to.edges&&t.to.edges.forEach(function(t){var e=i(t);s.edges.push(e)})}),n.attr&&(s.options=n.attr),s}var S={NULL:0,DELIMITER:1,IDENTIFIER:2,UNKNOWN:3},x={"{":!0,"}":!0,"[":!0,"]":!0,";":!0,"=":!0,",":!0,"->":!0,"--":!0},D="",M=0,C="",O="",N=S.NULL,L=/[a-zA-Z_0-9.:#]/;t.parseDOT=e,t.DOTToGraph=T}("undefined"!=typeof A?A:n),"undefined"!=typeof CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.circle=function(t,e,i){this.beginPath(),this.arc(t,e,i,0,2*Math.PI,!1)},CanvasRenderingContext2D.prototype.square=function(t,e,i){this.beginPath(),this.rect(t-i,e-i,2*i,2*i)},CanvasRenderingContext2D.prototype.triangle=function(t,e,i){this.beginPath();var n=2*i,s=n/2,r=Math.sqrt(3)/6*n,o=Math.sqrt(n*n-s*s);this.moveTo(t,e-(o-r)),this.lineTo(t+s,e+r),this.lineTo(t-s,e+r),this.lineTo(t,e-(o-r)),this.closePath()},CanvasRenderingContext2D.prototype.triangleDown=function(t,e,i){this.beginPath();var n=2*i,s=n/2,r=Math.sqrt(3)/6*n,o=Math.sqrt(n*n-s*s);this.moveTo(t,e+(o-r)),this.lineTo(t+s,e-r),this.lineTo(t-s,e-r),this.lineTo(t,e+(o-r)),this.closePath()},CanvasRenderingContext2D.prototype.star=function(t,e,i){this.beginPath();for(var n=0;10>n;n++){var s=n%2===0?1.3*i:.5*i;this.lineTo(t+s*Math.sin(2*n*Math.PI/10),e-s*Math.cos(2*n*Math.PI/10))}this.closePath()},CanvasRenderingContext2D.prototype.roundRect=function(t,e,i,n,s){var r=Math.PI/180;0>i-2*s&&(s=i/2),0>n-2*s&&(s=n/2),this.beginPath(),this.moveTo(t+s,e),this.lineTo(t+i-s,e),this.arc(t+i-s,e+s,s,270*r,360*r,!1),this.lineTo(t+i,e+n-s),this.arc(t+i-s,e+n-s,s,0,90*r,!1),this.lineTo(t+s,e+n),this.arc(t+s,e+n-s,s,90*r,180*r,!1),this.lineTo(t,e+s),this.arc(t+s,e+s,s,180*r,270*r,!1)},CanvasRenderingContext2D.prototype.ellipse=function(t,e,i,n){var s=.5522848,r=i/2*s,o=n/2*s,a=t+i,h=e+n,d=t+i/2,c=e+n/2;this.beginPath(),this.moveTo(t,c),this.bezierCurveTo(t,c-o,d-r,e,d,e),this.bezierCurveTo(d+r,e,a,c-o,a,c),this.bezierCurveTo(a,c+o,d+r,h,d,h),this.bezierCurveTo(d-r,h,t,c+o,t,c)},CanvasRenderingContext2D.prototype.database=function(t,e,i,n){var s=1/3,r=i,o=n*s,a=.5522848,h=r/2*a,d=o/2*a,c=t+r,u=e+o,l=t+r/2,p=e+o/2,f=e+(n-o/2),m=e+n;this.beginPath(),this.moveTo(c,p),this.bezierCurveTo(c,p+d,l+h,u,l,u),this.bezierCurveTo(l-h,u,t,p+d,t,p),this.bezierCurveTo(t,p-d,l-h,e,l,e),this.bezierCurveTo(l+h,e,c,p-d,c,p),this.lineTo(c,f),this.bezierCurveTo(c,f+d,l+h,m,l,m),this.bezierCurveTo(l-h,m,t,f+d,t,f),this.lineTo(t,p)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,n){var s=t-n*Math.cos(i),r=e-n*Math.sin(i),o=t-.9*n*Math.cos(i),a=e-.9*n*Math.sin(i),h=s+n/3*Math.cos(i+.5*Math.PI),d=r+n/3*Math.sin(i+.5*Math.PI),c=s+n/3*Math.cos(i-.5*Math.PI),u=r+n/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,d),this.lineTo(o,a),this.lineTo(c,u),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,n,s){s||(s=[10,5]),0==l&&(l=.001);var r=s.length;this.moveTo(t,e);for(var o=i-t,a=n-e,h=a/o,d=Math.sqrt(o*o+a*a),c=0,u=!0;d>=.1;){var l=s[c++%r];l>d&&(l=d);var p=Math.sqrt(l*l/(1+h*h));0>o&&(p=-p),t+=p,e+=h*p,this[u?"lineTo":"moveTo"](t,e),d-=l,u=!u}}),M.prototype.attachEdge=function(t){-1==this.edges.indexOf(t)&&this.edges.push(t),this._updateMass()},M.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&this.edges.splice(e,1),this._updateMass()},M.prototype._updateMass=function(){this.mass=50+20*this.edges.length},M.prototype.setProperties=function(t,e){if(t){if(void 0!=t.id&&(this.id=t.id),void 0!=t.label&&(this.label=t.label),void 0!=t.title&&(this.title=t.title),void 0!=t.group&&(this.group=t.group),void 0!=t.x&&(this.x=t.x),void 0!=t.y&&(this.y=t.y),void 0!=t.value&&(this.value=t.value),void 0===this.id)throw"Node must have an id";if(this.group){var i=this.grouplist.get(this.group);for(var n in i)i.hasOwnProperty(n)&&(this[n]=i[n])}if(void 0!=t.shape&&(this.shape=t.shape),void 0!=t.image&&(this.image=t.image),void 0!=t.radius&&(this.radius=t.radius),void 0!=t.color&&(this.color=M.parseColor(t.color)),void 0!=t.fontColor&&(this.fontColor=t.fontColor),void 0!=t.fontSize&&(this.fontSize=t.fontSize),void 0!=t.fontFace&&(this.fontFace=t.fontFace),void 0!=this.image){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.image)}switch(this.xFixed=this.xFixed||void 0!=t.x,this.yFixed=this.yFixed||void 0!=t.y,this.radiusFixed=this.radiusFixed||void 0!=t.radius,"image"==this.shape&&(this.radiusMin=e.nodes.widthMin,this.radiusMax=e.nodes.widthMax),this.shape){case"database":this.draw=this._drawDatabase,this.resize=this._resizeDatabase;break;case"box":this.draw=this._drawBox,this.resize=this._resizeBox;break;case"circle":this.draw=this._drawCircle,this.resize=this._resizeCircle;break;case"ellipse":this.draw=this._drawEllipse,this.resize=this._resizeEllipse;break;case"image":this.draw=this._drawImage,this.resize=this._resizeImage;break;case"text":this.draw=this._drawText,this.resize=this._resizeText;break;case"dot":this.draw=this._drawDot,this.resize=this._resizeShape;break;case"square":this.draw=this._drawSquare,this.resize=this._resizeShape;break;case"triangle":this.draw=this._drawTriangle,this.resize=this._resizeShape;break;case"triangleDown":this.draw=this._drawTriangleDown,this.resize=this._resizeShape;break;case"star":this.draw=this._drawStar,this.resize=this._resizeShape;break;default:this.draw=this._drawEllipse,this.resize=this._resizeEllipse}this._reset()}},M.parseColor=function(t){var e;return A.isString(t)?e={border:t,background:t,highlight:{border:t,background:t}}:(e={},e.background=t.background||"white",e.border=t.border||e.background,A.isString(t.highlight)?e.highlight={border:t.highlight,background:t.highlight}:(e.highlight={},e.highlight.background=t.highlight&&t.highlight.background||e.background,e.highlight.border=t.highlight&&t.highlight.border||e.border)),e},M.prototype.select=function(){this.selected=!0,this._reset()},M.prototype.unselect=function(){this.selected=!1,this._reset()},M.prototype._reset=function(){this.width=void 0,this.height=void 0},M.prototype.getTitle=function(){return this.title},M.prototype.distanceToBorder=function(t,e){var i=1;switch(this.width||this.resize(t),this.shape){case"circle":case"dot":return this.radius+i;case"ellipse":var n=this.width/2,s=this.height/2,r=Math.sin(e)*n,o=Math.cos(e)*s;return n*s/Math.sqrt(r*r+o*o);case"box":case"image":case"text":default:return this.width?Math.min(Math.abs(this.width/2/Math.cos(e)),Math.abs(this.height/2/Math.sin(e)))+i:0}},M.prototype._setForce=function(t,e){this.fx=t,this.fy=e},M.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},M.prototype.discreteStep=function(t){if(!this.xFixed){var e=-this.damping*this.vx,i=(this.fx+e)/this.mass;this.vx+=i/t,this.x+=this.vx/t}if(!this.yFixed){var n=-this.damping*this.vy,s=(this.fy+n)/this.mass;this.vy+=s/t,this.y+=this.vy/t}},M.prototype.isFixed=function(){return this.xFixed&&this.yFixed},M.prototype.isMoving=function(t){return Math.abs(this.vx)>t||Math.abs(this.vy)>t||!this.xFixed&&Math.abs(this.fx)>this.minForce||!this.yFixed&&Math.abs(this.fy)>this.minForce},M.prototype.isSelected=function(){return this.selected},M.prototype.getValue=function(){return this.value},M.prototype.getDistance=function(t,e){var i=this.x-t,n=this.y-e;return Math.sqrt(i*i+n*n)},M.prototype.setValueRange=function(t,e){if(!this.radiusFixed&&void 0!==this.value)if(e==t)this.radius=(this.radiusMin+this.radiusMax)/2;else{var i=(this.radiusMax-this.radiusMin)/(e-t);this.radius=(this.value-t)*i+this.radiusMin}},M.prototype.draw=function(){throw"Draw method not initialized for node"},M.prototype.resize=function(){throw"Resize method not initialized for node"},M.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},M.prototype._resizeImage=function(){if(!this.width){var t,e;if(this.value){var i=this.imageObj.height/this.imageObj.width;t=this.radius||this.imageObj.width,e=this.radius*i||this.imageObj.height}else t=this.imageObj.width,e=this.imageObj.height;this.width=t,this.height=e}},M.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e;this.imageObj?(t.drawImage(this.imageObj,this.left,this.top,this.width,this.height),e=this.y+this.height/2):e=this.y,this._label(t,this.label,this.x,e,void 0,"top")},M.prototype._resizeBox=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e}},M.prototype._drawBox=function(t){this._resizeBox(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,t.roundRect(this.left,this.top,this.width,this.height,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeDatabase=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=i.width+2*e;this.width=n,this.height=n}},M.prototype._drawDatabase=function(t){this._resizeDatabase(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,t.database(this.x-this.width/2,this.y-.5*this.height,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=Math.max(i.width,i.height)+2*e;this.radius=n/2,this.width=n,this.height=n}},M.prototype._drawCircle=function(t){this._resizeCircle(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,t.circle(this.x,this.y,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeEllipse=function(t){if(!this.width){var e=this.getTextSize(t);this.width=1.5*e.width,this.height=2*e.height,this.widthc;c++)t.fillText(o[c],i,d),d+=h}},M.prototype.getTextSize=function(t){if(void 0!=this.label){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace;for(var e=this.label.split("\n"),i=(this.fontSize+4)*e.length,n=0,s=0,r=e.length;r>s;s++)n=Math.max(n,t.measureText(e[s]).width);return{width:n,height:i}}return{width:0,height:0}},C.prototype.setProperties=function(t,e){if(t)switch(void 0!=t.from&&(this.fromId=t.from),void 0!=t.to&&(this.toId=t.to),void 0!=t.id&&(this.id=t.id),void 0!=t.style&&(this.style=t.style),void 0!=t.label&&(this.label=t.label),this.label&&(this.fontSize=e.edges.fontSize,this.fontFace=e.edges.fontFace,this.fontColor=e.edges.fontColor,void 0!=t.fontColor&&(this.fontColor=t.fontColor),void 0!=t.fontSize&&(this.fontSize=t.fontSize),void 0!=t.fontFace&&(this.fontFace=t.fontFace)),void 0!=t.title&&(this.title=t.title),void 0!=t.width&&(this.width=t.width),void 0!=t.value&&(this.value=t.value),void 0!=t.length&&(this.length=t.length),t.dash&&(void 0!=t.dash.length&&(this.dash.length=t.dash.length),void 0!=t.dash.gap&&(this.dash.gap=t.dash.gap),void 0!=t.dash.altLength&&(this.dash.altLength=t.dash.altLength)),void 0!=t.color&&(this.color=t.color),this.connect(),this.widthFixed=this.widthFixed||void 0!=t.width,this.lengthFixed=this.lengthFixed||void 0!=t.length,this.stiffness=1/this.length,this.style){case"line":this.draw=this._drawLine;break;case"arrow":this.draw=this._drawArrow;break;case"arrow-center":this.draw=this._drawArrowCenter;break;case"dash-line":this.draw=this._drawDashLine;break;default:this.draw=this._drawLine}},C.prototype.connect=function(){this.disconnect(),this.from=this.graph.nodes[this.fromId]||null,this.to=this.graph.nodes[this.toId]||null,this.connected=this.from&&this.to,this.connected?(this.from.attachEdge(this),this.to.attachEdge(this)):(this.from&&this.from.detachEdge(this),this.to&&this.to.detachEdge(this))},C.prototype.disconnect=function(){this.from&&(this.from.detachEdge(this),this.from=null),this.to&&(this.to.detachEdge(this),this.to=null),this.connected=!1},C.prototype.getTitle=function(){return this.title},C.prototype.getValue=function(){return this.value},C.prototype.setValueRange=function(t,e){if(!this.widthFixed&&void 0!==this.value){var i=(this.widthMax-this.widthMin)/(e-t);this.width=(this.value-t)*i+this.widthMin}},C.prototype.draw=function(){throw"Method draw not initialized in edge"},C.prototype.isOverlappingWith=function(t){var e=10,i=this.from.x,n=this.from.y,s=this.to.x,r=this.to.y,o=t.left,a=t.top,h=C._dist(i,n,s,r,o,a);return e>h},C.prototype._drawLine=function(t){t.strokeStyle=this.color,t.lineWidth=this._getLineWidth();var e;if(this.from!=this.to)this._line(t),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y));else{var i,n,s=this.length/4,r=this.from;r.width||r.resize(t),r.width>r.height?(i=r.x+r.width/2,n=r.y-s):(i=r.x+s,n=r.y-r.height/2),this._circle(t,i,n,s),e=this._pointOnCircle(i,n,s,.5),this._label(t,this.label,e.x,e.y)}},C.prototype._getLineWidth=function(){return this.from.selected||this.to.selected?Math.min(2*this.width,this.widthMax):this.width},C.prototype._line=function(t){t.beginPath(),t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y),t.stroke()},C.prototype._circle=function(t,e,i,n){t.beginPath(),t.arc(e,i,n,0,2*Math.PI,!1),t.stroke()},C.prototype._label=function(t,e,i,n){if(e){t.font=(this.from.selected||this.to.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle="white";var s=t.measureText(e).width,r=this.fontSize,o=i-s/2,a=n-r/2;t.fillRect(o,a,s,r),t.fillStyle=this.fontColor||"black",t.textAlign="left",t.textBaseline="top",t.fillText(e,o,a)}},C.prototype._drawDashLine=function(t){if(t.strokeStyle=this.color,t.lineWidth=this._getLineWidth(),t.beginPath(),t.lineCap="round",void 0!=this.dash.altLength?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]):void 0!=this.dash.length&&void 0!=this.dash.gap?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap]):(t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y)),t.stroke(),this.label){var e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}},C.prototype._pointOnLine=function(t){return{x:(1-t)*this.from.x+t*this.to.x,y:(1-t)*this.from.y+t*this.to.y}},C.prototype._pointOnCircle=function(t,e,i,n){var s=2*(n-3/8)*Math.PI;return{x:t+i*Math.cos(s),y:e-i*Math.sin(s)}},C.prototype._drawArrowCenter=function(t){var e;if(t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth(),this.from!=this.to){this._line(t);var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),n=10+5*this.width;e=this._pointOnLine(.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y))}else{var s,r,o=this.length/4,a=this.from;a.width||a.resize(t),a.width>a.height?(s=a.x+a.width/2,r=a.y-o):(s=a.x+o,r=a.y-a.height/2),this._circle(t,s,r,o);var i=.2*Math.PI,n=10+5*this.width;e=this._pointOnCircle(s,r,o,.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(s,r,o,.5),this._label(t,this.label,e.x,e.y))}},C.prototype._drawArrow=function(t){t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth();var e,i;if(this.from!=this.to){e=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x);var n=this.to.x-this.from.x,s=this.to.y-this.from.y,r=Math.sqrt(n*n+s*s),o=this.from.distanceToBorder(t,e+Math.PI),a=(r-o)/r,h=a*this.from.x+(1-a)*this.to.x,d=a*this.from.y+(1-a)*this.to.y,c=this.to.distanceToBorder(t,e),u=(r-c)/r,l=(1-u)*this.from.x+u*this.to.x,p=(1-u)*this.from.y+u*this.to.y;if(t.beginPath(),t.moveTo(h,d),t.lineTo(l,p),t.stroke(),i=10+5*this.width,t.arrow(l,p,e,i),t.fill(),t.stroke(),this.label){var f=this._pointOnLine(.5);this._label(t,this.label,f.x,f.y)}}else{var m,g,v,y=this.from,w=this.length/4;y.width||y.resize(t),y.width>y.height?(m=y.x+y.width/2,g=y.y-w,v={x:m,y:y.y,angle:.9*Math.PI}):(m=y.x+w,g=y.y-y.height/2,v={x:y.x,y:g,angle:.6*Math.PI}),t.beginPath(),t.arc(m,g,w,0,2*Math.PI,!1),t.stroke(),i=10+5*this.width,t.arrow(v.x,v.y,v.angle,i),t.fill(),t.stroke(),this.label&&(f=this._pointOnCircle(m,g,w,.5),this._label(t,this.label,f.x,f.y))}},C._dist=function(t,e,i,n,s,r){var o=i-t,a=n-e,h=o*o+a*a,d=((s-t)*o+(r-e)*a)/h;d>1?d=1:0>d&&(d=0);var c=t+d*o,u=e+d*a,l=c-s,p=u-r;return Math.sqrt(l*l+p*p)},O.prototype.setPosition=function(t,e){this.x=parseInt(t),this.y=parseInt(e)},O.prototype.setText=function(t){this.frame.innerHTML=t},O.prototype.show=function(t){if(void 0===t&&(t=!0),t){var e=this.frame.clientHeight,i=this.frame.clientWidth,n=this.frame.parentNode.clientHeight,s=this.frame.parentNode.clientWidth,r=this.y-e;r+e+this.padding>n&&(r=n-e-this.padding),rs&&(o=s-i-this.padding),o0?s[s.length-1]:null},N.prototype._getPointer=function(t){return{x:t.pageX-R.util.getAbsoluteLeft(this.frame.canvas),y:t.pageY-R.util.getAbsoluteTop(this.frame.canvas)}},N.prototype._onTouch=function(t){this.drag.pointer=this._getPointer(t.gesture.touches[0]),this.drag.pinched=!1,this.pinch.scale=this._getScale()},N.prototype._onDragStart=function(){var t=this.drag;t.selection=[],t.translation=this._getTranslation(),t.nodeId=this._getNodeAt(t.pointer);var e=this.nodes[t.nodeId];if(e){e.isSelected()||this._selectNodes([t.nodeId]);var i=this;this.selection.forEach(function(e){var n=i.nodes[e];if(n){var s={id:e,node:n,x:n.x,y:n.y,xFixed:n.xFixed,yFixed:n.yFixed};n.xFixed=!0,n.yFixed=!0,t.selection.push(s)}})}},N.prototype._onDrag=function(t){if(!this.drag.pinched){var e=this._getPointer(t.gesture.touches[0]),i=this,n=this.drag,s=n.selection;if(s&&s.length){var r=e.x-n.pointer.x,o=e.y-n.pointer.y;s.forEach(function(t){var e=t.node;t.xFixed||(e.x=i._canvasToX(i._xToCanvas(t.x)+r)),t.yFixed||(e.y=i._canvasToY(i._yToCanvas(t.y)+o))}),this.moving||(this.moving=!0,this.start())}else{var a=e.x-this.drag.pointer.x,h=e.y-this.drag.pointer.y;this._setTranslation(this.drag.translation.x+a,this.drag.translation.y+h),this._redraw(),this.moved=!0}}},N.prototype._onDragEnd=function(){var t=this.drag.selection;t&&t.forEach(function(t){t.node.xFixed=t.xFixed,t.node.yFixed=t.yFixed})},N.prototype._onTap=function(t){var e=this._getPointer(t.gesture.touches[0]),i=this._getNodeAt(e),n=this.nodes[i];n?(this._selectNodes([i]),this.moving||this._redraw()):(this._unselectNodes(),this._redraw())},N.prototype._onHold=function(t){var e=this._getPointer(t.gesture.touches[0]),i=this._getNodeAt(e),n=this.nodes[i];if(n){if(n.isSelected())this._unselectNodes([i]);else{var s=!0;this._selectNodes([i],s)}this.moving||this._redraw()}},N.prototype._onPinch=function(t){var e=this._getPointer(t.gesture.center);this.drag.pinched=!0,"scale"in this.pinch||(this.pinch.scale=1);var i=this.pinch.scale*t.gesture.scale;this._zoom(i,e)},N.prototype._zoom=function(t,e){var i=this._getScale();.01>t&&(t=.01),t>10&&(t=10);var n=this._getTranslation(),s=t/i,r=(1-s)*e.x+n.x*s,o=(1-s)*e.y+n.y*s;return this._setScale(t),this._setTranslation(r,o),this._redraw(),t},N.prototype._onMouseWheel=function(t){var e=0;if(t.wheelDelta?e=t.wheelDelta/120:t.detail&&(e=-t.detail/3),e){"mouswheelScale"in this.pinch||(this.pinch.mouswheelScale=1);var i=this.pinch.mouswheelScale,n=e/10;0>e&&(n/=1-n),i*=1+n;var s=A.fakeGesture(this,t),r=this._getPointer(s.center);i=this._zoom(i,r),this.pinch.mouswheelScale=i}t.preventDefault()},N.prototype._onMouseMoveTitle=function(t){var e=A.fakeGesture(this,t),i=this._getPointer(e.center);this.popupNode&&this._checkHidePopup(i);var n=this,s=function(){n._checkShowPopup(i)};this.popupTimer&&clearInterval(this.popupTimer),this.leftButtonDown||(this.popupTimer=setTimeout(s,300))},N.prototype._checkShowPopup=function(t){var e,i={left:this._canvasToX(t.x),top:this._canvasToY(t.y),right:this._canvasToX(t.x),bottom:this._canvasToY(t.y)},n=this.popupNode;if(void 0==this.popupNode){var s=this.nodes;for(e in s)if(s.hasOwnProperty(e)){var r=s[e];if(void 0!=r.getTitle()&&r.isOverlappingWith(i)){this.popupNode=r;break}}}if(void 0==this.popupNode){var o=this.edges;for(e in o)if(o.hasOwnProperty(e)){var a=o[e];if(a.connected&&void 0!=a.getTitle()&&a.isOverlappingWith(i)){this.popupNode=a;break}}}if(this.popupNode){if(this.popupNode!=n){var h=this;h.popup||(h.popup=new O(h.frame)),h.popup.setPosition(t.x-3,t.y-3),h.popup.setText(h.popupNode.getTitle()),h.popup.show()}}else this.popup&&this.popup.hide()},N.prototype._checkHidePopup=function(t){this.popupNode&&this._getNodeAt(t)||(this.popupNode=void 0,this.popup&&this.popup.hide())},N.prototype._unselectNodes=function(t,e){var i,n,s,r=!1;if(t)for(i=0,n=t.length;n>i;i++){s=t[i],this.nodes[s].unselect();for(var o=0;oi;i++)s=this.selection[i],this.nodes[s].unselect(),r=!0;this.selection=[]}return!r||1!=e&&void 0!=e||this._trigger("select"),r},N.prototype._selectNodes=function(t,e){var i,n,s=!1,r=!0;if(t.length!=this.selection.length)r=!1;else for(i=0,n=Math.min(t.length,this.selection.length);n>i;i++)if(t[i]!=this.selection[i]){r=!1;break}if(r)return s;if(void 0==e||0==e){var o=!1;s=this._unselectNodes(void 0,o)}for(i=0,n=t.length;n>i;i++){var a=t[i],h=-1!=this.selection.indexOf(a);h||(this.nodes[a].select(),this.selection.push(a),s=!0)}return s&&this._trigger("select"),s},N.prototype._getNodesOverlappingWith=function(t){var e=this.nodes,i=[];for(var n in e)e.hasOwnProperty(n)&&e[n].isOverlappingWith(t)&&i.push(n);return i},N.prototype.getSelection=function(){return this.selection.concat([])},N.prototype.setSelection=function(t){var e,i,n;if(!t||void 0==t.length)throw"Selection must be an array with ids";for(e=0,i=this.selection.length;i>e;e++)n=this.selection[e],this.nodes[n].unselect();for(this.selection=[],e=0,i=t.length;i>e;e++){n=t[e];var s=this.nodes[n];if(!s)throw new RangeError('Node with id "'+n+'" not found');s.select(),this.selection.push(n)}this.redraw()},N.prototype._updateSelection=function(){for(var t=0;ti;i++)for(var s=t[i],r=s.edges,o=0,a=r.length;a>o;o++){var h=r[o],d=null;h.from==s?d=h.to:h.to==s&&(d=h.from);var c,u;if(d)for(c=0,u=t.length;u>c;c++)if(t[c]==d){d=null;break}if(d)for(c=0,u=e.length;u>c;c++)if(e[c]==d){d=null;break}d&&e.push(d)}return e}void 0==t&&(t=1);var i=[],n=this.nodes;for(var s in n)if(n.hasOwnProperty(s)){for(var r=[n[s]],o=0;t>o;o++)r=r.concat(e(r));i.push(r)}for(var a=[],h=0,d=i.length;d>h;h++)a.push(i[h].length);return a},N.prototype.setSize=function(t,e){this.frame.style.width=t,this.frame.style.height=e,this.frame.canvas.style.width="100%",this.frame.canvas.style.height="100%",this.frame.canvas.width=this.frame.canvas.clientWidth,this.frame.canvas.height=this.frame.canvas.clientHeight},N.prototype._setNodes=function(t){var e=this.nodesData;if(t instanceof r||t instanceof o)this.nodesData=t;else if(t instanceof Array)this.nodesData=new r,this.nodesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.nodesData=new r}if(e&&A.forEach(this.nodesListeners,function(t,i){e.unsubscribe(i,t)}),this.nodes={},this.nodesData){var i=this;A.forEach(this.nodesListeners,function(t,e){i.nodesData.subscribe(e,t)});var n=this.nodesData.getIds();this._addNodes(n)}this._updateSelection()},N.prototype._addNodes=function(t){for(var e,i=0,n=t.length;n>i;i++){e=t[i];var s=this.nodesData.get(e),r=new M(s,this.images,this.groups,this.constants);if(this.nodes[e]=r,!r.isFixed()){var o=2*this.constants.edges.length,a=t.length,h=2*Math.PI*(i/a);r.x=o*Math.cos(h),r.y=o*Math.sin(h),this.moving=!0}}this._reconnectEdges(),this._updateValueRange(this.nodes)},N.prototype._updateNodes=function(t){for(var e=this.nodes,i=this.nodesData,n=0,s=t.length;s>n;n++){var r=t[n],o=e[r],a=i.get(r);o?o.setProperties(a,this.constants):(o=new M(properties,this.images,this.groups,this.constants),e[r]=o,o.isFixed()||(this.moving=!0))}this._reconnectEdges(),this._updateValueRange(e)},N.prototype._removeNodes=function(t){for(var e=this.nodes,i=0,n=t.length;n>i;i++){var s=t[i];delete e[s]}this._reconnectEdges(),this._updateSelection(),this._updateValueRange(e)},N.prototype._setEdges=function(t){var e=this.edgesData;if(t instanceof r||t instanceof o)this.edgesData=t;else if(t instanceof Array)this.edgesData=new r,this.edgesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.edgesData=new r}if(e&&A.forEach(this.edgesListeners,function(t,i){e.unsubscribe(i,t)}),this.edges={},this.edgesData){var i=this;A.forEach(this.edgesListeners,function(t,e){i.edgesData.subscribe(e,t)});var n=this.edgesData.getIds();this._addEdges(n)}this._reconnectEdges()},N.prototype._addEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var r=t[n],o=e[r];o&&o.disconnect();var a=i.get(r);e[r]=new C(a,this,this.constants)}this.moving=!0,this._updateValueRange(e)},N.prototype._updateEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var r=t[n],o=i.get(r),a=e[r];a?(a.disconnect(),a.setProperties(o,this.constants),a.connect()):(a=new C(o,this,this.constants),this.edges[r]=a)}this.moving=!0,this._updateValueRange(e)},N.prototype._removeEdges=function(t){for(var e=this.edges,i=0,n=t.length;n>i;i++){var s=t[i],r=e[s];r&&(r.disconnect(),delete e[s])}this.moving=!0,this._updateValueRange(e)},N.prototype._reconnectEdges=function(){var t,e=this.nodes,i=this.edges;for(t in e)e.hasOwnProperty(t)&&(e[t].edges=[]);for(t in i)if(i.hasOwnProperty(t)){var n=i[t];n.from=null,n.to=null,n.connect()}},N.prototype._updateValueRange=function(t){var e,i=void 0,n=void 0;for(e in t)if(t.hasOwnProperty(e)){var s=t[e].getValue();void 0!==s&&(i=void 0===i?s:Math.min(s,i),n=void 0===n?s:Math.max(s,n))}if(void 0!==i&&void 0!==n)for(e in t)t.hasOwnProperty(e)&&t[e].setValueRange(i,n)},N.prototype.redraw=function(){this.setSize(this.width,this.height),this._redraw()},N.prototype._redraw=function(){var t=this.frame.canvas.getContext("2d"),e=this.frame.canvas.width,i=this.frame.canvas.height;t.clearRect(0,0,e,i),t.save(),t.translate(this.translation.x,this.translation.y),t.scale(this.scale,this.scale),this._drawEdges(t),this._drawNodes(t),t.restore()},N.prototype._setTranslation=function(t,e){void 0===this.translation&&(this.translation={x:0,y:0}),void 0!==t&&(this.translation.x=t),void 0!==e&&(this.translation.y=e)},N.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},N.prototype._setScale=function(t){this.scale=t},N.prototype._getScale=function(){return this.scale},N.prototype._canvasToX=function(t){return(t-this.translation.x)/this.scale},N.prototype._xToCanvas=function(t){return t*this.scale+this.translation.x},N.prototype._canvasToY=function(t){return(t-this.translation.y)/this.scale},N.prototype._yToCanvas=function(t){return t*this.scale+this.translation.y},N.prototype._drawNodes=function(t){var e=this.nodes,i=[];for(var n in e)e.hasOwnProperty(n)&&(e[n].isSelected()?i.push(n):e[n].draw(t));for(var s=0,r=i.length;r>s;s++)e[i[s]].draw(t)},N.prototype._drawEdges=function(t){var e=this.edges;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];n.connected&&e[i].draw(t)}},N.prototype._doStabilize=function(){for(var t=(new Date,0),e=this.constants.minVelocity,i=!1;!i&&t0&&e==s.EVENT_END?e=s.EVENT_MOVE:c||(e=s.EVENT_END),c||null===r?r=h:h=r,i.call(s.detection,n.collectEventData(t,e,h)),s.HAS_POINTEREVENTS&&e==s.EVENT_END&&(c=s.PointerEvent.updatePointer(e,h))),c||(r=null,o=!1,a=!1,s.PointerEvent.reset())}})},determineEventTypes:function(){var t;t=s.HAS_POINTEREVENTS?s.PointerEvent.getEvents():s.NO_MOUSEEVENTS?["touchstart","touchmove","touchend touchcancel"]:["touchstart mousedown","touchmove mousemove","touchend touchcancel mouseup"],s.EVENT_TYPES[s.EVENT_START]=t[0],s.EVENT_TYPES[s.EVENT_MOVE]=t[1],s.EVENT_TYPES[s.EVENT_END]=t[2]},getTouchList:function(t){return s.HAS_POINTEREVENTS?s.PointerEvent.getTouchList():t.touches?t.touches:[{identifier:1,pageX:t.pageX,pageY:t.pageY,target:t.target}]},collectEventData:function(t,e,i){var n=this.getTouchList(i,e),r=s.POINTER_TOUCH;return(i.type.match(/mouse/)||s.PointerEvent.matchType(s.POINTER_MOUSE,i))&&(r=s.POINTER_MOUSE),{center:s.utils.getCenter(n),timeStamp:(new Date).getTime(),target:i.target,touches:n,eventType:e,pointerType:r,srcEvent:i,preventDefault:function(){this.srcEvent.preventManipulation&&this.srcEvent.preventManipulation(),this.srcEvent.preventDefault&&this.srcEvent.preventDefault()},stopPropagation:function(){this.srcEvent.stopPropagation()},stopDetect:function(){return s.detection.stopDetect()}}}},s.PointerEvent={pointers:{},getTouchList:function(){var t=this,e=[];return Object.keys(t.pointers).sort().forEach(function(i){e.push(t.pointers[i])}),e},updatePointer:function(t,e){return t==s.EVENT_END?this.pointers={}:(e.identifier=e.pointerId,this.pointers[e.pointerId]=e),Object.keys(this.pointers).length},matchType:function(t,e){if(!e.pointerType)return!1;var i={};return i[s.POINTER_MOUSE]=e.pointerType==e.MSPOINTER_TYPE_MOUSE||e.pointerType==s.POINTER_MOUSE,i[s.POINTER_TOUCH]=e.pointerType==e.MSPOINTER_TYPE_TOUCH||e.pointerType==s.POINTER_TOUCH,i[s.POINTER_PEN]=e.pointerType==e.MSPOINTER_TYPE_PEN||e.pointerType==s.POINTER_PEN,i[t]},getEvents:function(){return["pointerdown MSPointerDown","pointermove MSPointerMove","pointerup pointercancel MSPointerUp MSPointerCancel"]},reset:function(){this.pointers={}}},s.utils={extend:function(t,e,n){for(var s in e)t[s]!==i&&n||(t[s]=e[s]);return t},hasParent:function(t,e){for(;t;){if(t==e)return!0;t=t.parentNode}return!1},getCenter:function(t){for(var e=[],i=[],n=0,s=t.length;s>n;n++)e.push(t[n].pageX),i.push(t[n].pageY);return{pageX:(Math.min.apply(Math,e)+Math.max.apply(Math,e))/2,pageY:(Math.min.apply(Math,i)+Math.max.apply(Math,i))/2}},getVelocity:function(t,e,i){return{x:Math.abs(e/t)||0,y:Math.abs(i/t)||0}},getAngle:function(t,e){var i=e.pageY-t.pageY,n=e.pageX-t.pageX;return 180*Math.atan2(i,n)/Math.PI},getDirection:function(t,e){var i=Math.abs(t.pageX-e.pageX),n=Math.abs(t.pageY-e.pageY);return i>=n?t.pageX-e.pageX>0?s.DIRECTION_LEFT:s.DIRECTION_RIGHT:t.pageY-e.pageY>0?s.DIRECTION_UP:s.DIRECTION_DOWN},getDistance:function(t,e){var i=e.pageX-t.pageX,n=e.pageY-t.pageY;return Math.sqrt(i*i+n*n)},getScale:function(t,e){return t.length>=2&&e.length>=2?this.getDistance(e[0],e[1])/this.getDistance(t[0],t[1]):1},getRotation:function(t,e){return t.length>=2&&e.length>=2?this.getAngle(e[1],e[0])-this.getAngle(t[1],t[0]):0},isVertical:function(t){return t==s.DIRECTION_UP||t==s.DIRECTION_DOWN},stopDefaultBrowserBehavior:function(t,e){var i,n=["webkit","khtml","moz","ms","o",""];if(e&&t.style){for(var s=0;si;i++){var r=this.gestures[i];if(!this.stopped&&e[r.name]!==!1&&r.handler.call(r,t,this.current.inst)===!1){this.stopDetect();break}}return this.current&&(this.current.lastEvent=t),t.eventType==s.EVENT_END&&!t.touches.length-1&&this.stopDetect(),t}},stopDetect:function(){this.previous=s.utils.extend({},this.current),this.current=null,this.stopped=!0},extendEventData:function(t){var e=this.current.startEvent; +if(e&&(t.touches.length!=e.touches.length||t.touches===e.touches)){e.touches=[];for(var i=0,n=t.touches.length;n>i;i++)e.touches.push(s.utils.extend({},t.touches[i]))}var r=t.timeStamp-e.timeStamp,o=t.center.pageX-e.center.pageX,a=t.center.pageY-e.center.pageY,h=s.utils.getVelocity(r,o,a);return s.utils.extend(t,{deltaTime:r,deltaX:o,deltaY:a,velocityX:h.x,velocityY:h.y,distance:s.utils.getDistance(e.center,t.center),angle:s.utils.getAngle(e.center,t.center),direction:s.utils.getDirection(e.center,t.center),scale:s.utils.getScale(e.touches,t.touches),rotation:s.utils.getRotation(e.touches,t.touches),startEvent:e}),t},register:function(t){var e=t.defaults||{};return e[t.name]===i&&(e[t.name]=!0),s.utils.extend(s.defaults,e,!0),t.index=t.index||1e3,this.gestures.push(t),this.gestures.sort(function(t,e){return t.indexe.index?1:0}),this.gestures}},s.gestures=s.gestures||{},s.gestures.Hold={name:"hold",index:10,defaults:{hold_timeout:500,hold_threshold:1},timer:null,handler:function(t,e){switch(t.eventType){case s.EVENT_START:clearTimeout(this.timer),s.detection.current.name=this.name,this.timer=setTimeout(function(){"hold"==s.detection.current.name&&e.trigger("hold",t)},e.options.hold_timeout);break;case s.EVENT_MOVE:t.distance>e.options.hold_threshold&&clearTimeout(this.timer);break;case s.EVENT_END:clearTimeout(this.timer)}}},s.gestures.Tap={name:"tap",index:100,defaults:{tap_max_touchtime:250,tap_max_distance:10,tap_always:!0,doubletap_distance:20,doubletap_interval:300},handler:function(t,e){if(t.eventType==s.EVENT_END){var i=s.detection.previous,n=!1;if(t.deltaTime>e.options.tap_max_touchtime||t.distance>e.options.tap_max_distance)return;i&&"tap"==i.name&&t.timeStamp-i.lastEvent.timeStamp0&&t.touches.length>e.options.swipe_max_touches)return;(t.velocityX>e.options.swipe_velocity||t.velocityY>e.options.swipe_velocity)&&(e.trigger(this.name,t),e.trigger(this.name+t.direction,t))}}},s.gestures.Drag={name:"drag",index:50,defaults:{drag_min_distance:10,drag_max_touches:1,drag_block_horizontal:!1,drag_block_vertical:!1,drag_lock_to_axis:!1,drag_lock_min_distance:25},triggered:!1,handler:function(t,e){if(s.detection.current.name!=this.name&&this.triggered)return e.trigger(this.name+"end",t),this.triggered=!1,void 0;if(!(e.options.drag_max_touches>0&&t.touches.length>e.options.drag_max_touches))switch(t.eventType){case s.EVENT_START:this.triggered=!1;break;case s.EVENT_MOVE:if(t.distancee.options.transform_min_rotation&&e.trigger("rotate",t),i>e.options.transform_min_scale&&(e.trigger("pinch",t),e.trigger("pinch"+(t.scale<1?"in":"out"),t));break;case s.EVENT_END:this.triggered&&e.trigger(this.name+"end",t),this.triggered=!1}}},s.gestures.Touch={name:"touch",index:-1/0,defaults:{prevent_default:!1,prevent_mouseevents:!1},handler:function(t,e){return e.options.prevent_mouseevents&&t.pointerType==s.POINTER_MOUSE?(t.stopDetect(),void 0):(e.options.prevent_default&&t.preventDefault(),t.eventType==s.EVENT_START&&e.trigger(this.name,t),void 0)}},s.gestures.Release={name:"release",index:1/0,handler:function(t,e){t.eventType==s.EVENT_END&&e.trigger(this.name,t)}},"object"==typeof e&&"object"==typeof e.exports?e.exports=s:(t.Hammer=s,"function"==typeof t.define&&t.define.amd&&t.define("hammer",[],function(){return s}))}(this)},{}],3:[function(e,i){(function(n){function s(t,e){return function(i){return u(t.call(this,i),e)}}function r(t,e){return function(i){return this.lang().ordinal(t.call(this,i),e)}}function o(){}function a(t){T(t),d(this,t)}function h(t){var e=v(t),i=e.year||0,n=e.month||0,s=e.week||0,r=e.day||0,o=e.hour||0,a=e.minute||0,h=e.second||0,d=e.millisecond||0;this._milliseconds=+d+1e3*h+6e4*a+36e5*o,this._days=+r+7*s,this._months=+n+12*i,this._data={},this._bubble()}function d(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return e.hasOwnProperty("toString")&&(t.toString=e.toString),e.hasOwnProperty("valueOf")&&(t.valueOf=e.valueOf),t}function c(t){return 0>t?Math.ceil(t):Math.floor(t)}function u(t,e,i){for(var n=Math.abs(t)+"",s=t>=0;n.lengthn;n++)(i&&t[n]!==e[n]||!i&&w(t[n])!==w(e[n]))&&o++;return o+r}function g(t){if(t){var e=t.toLowerCase().replace(/(.)s$/,"$1");t=Ge[t]||Be[e]||e}return t}function v(t){var e,i,n={};for(i in t)t.hasOwnProperty(i)&&(e=g(i),e&&(n[e]=t[i]));return n}function y(t){var e,i;if(0===t.indexOf("week"))e=7,i="day";else{if(0!==t.indexOf("month"))return;e=12,i="month"}re[t]=function(s,r){var o,a,h=re.fn._lang[t],d=[];if("number"==typeof s&&(r=s,s=n),a=function(t){var e=re().utc().set(i,t);return h.call(re.fn._lang,e,s||"")},null!=r)return a(r);for(o=0;e>o;o++)d.push(a(o));return d}}function w(t){var e=+t,i=0;return 0!==e&&isFinite(e)&&(i=e>=0?Math.floor(e):Math.ceil(e)),i}function _(t,e){return new Date(Date.UTC(t,e+1,0)).getUTCDate()}function b(t){return E(t)?366:365}function E(t){return t%4===0&&t%100!==0||t%400===0}function T(t){var e;t._a&&-2===t._pf.overflow&&(e=t._a[ue]<0||t._a[ue]>11?ue:t._a[le]<1||t._a[le]>_(t._a[ce],t._a[ue])?le:t._a[pe]<0||t._a[pe]>23?pe:t._a[fe]<0||t._a[fe]>59?fe:t._a[me]<0||t._a[me]>59?me:t._a[ge]<0||t._a[ge]>999?ge:-1,t._pf._overflowDayOfYear&&(ce>e||e>le)&&(e=le),t._pf.overflow=e)}function S(t){t._pf={empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function x(t){return null==t._isValid&&(t._isValid=!isNaN(t._d.getTime())&&t._pf.overflow<0&&!t._pf.empty&&!t._pf.invalidMonth&&!t._pf.nullInput&&!t._pf.invalidFormat&&!t._pf.userInvalidated,t._strict&&(t._isValid=t._isValid&&0===t._pf.charsLeftOver&&0===t._pf.unusedTokens.length)),t._isValid}function D(t){return t?t.toLowerCase().replace("_","-"):t}function M(t,e){return e._isUTC?re(t).zone(e._offset||0):re(t).local()}function C(t,e){return e.abbr=t,ve[t]||(ve[t]=new o),ve[t].set(e),ve[t]}function O(t){delete ve[t]}function N(t){var i,n,s,r,o=0,a=function(t){if(!ve[t]&&ye)try{e("./lang/"+t)}catch(i){}return ve[t]};if(!t)return re.fn._lang;if(!p(t)){if(n=a(t))return n;t=[t]}for(;o0;){if(n=a(r.slice(0,i).join("-")))return n;if(s&&s.length>=i&&m(r,s,!0)>=i-1)break;i--}o++}return re.fn._lang}function L(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function I(t){var e,i,n=t.match(Ee);for(e=0,i=n.length;i>e;e++)n[e]=Ke[n[e]]?Ke[n[e]]:L(n[e]);return function(s){var r="";for(e=0;i>e;e++)r+=n[e]instanceof Function?n[e].call(s,t):n[e];return r}}function k(t,e){return t.isValid()?(e=A(e,t.lang()),qe[e]||(qe[e]=I(e)),qe[e](t)):t.lang().invalidDate()}function A(t,e){function i(t){return e.longDateFormat(t)||t}var n=5;for(Te.lastIndex=0;n>=0&&Te.test(t);)t=t.replace(Te,i),Te.lastIndex=0,n-=1;return t}function P(t,e){var i,n=e._strict;switch(t){case"DDDD":return Pe;case"YYYY":case"GGGG":case"gggg":return n?Ye:De;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return n?Fe:Me;case"S":if(n)return ke;case"SS":if(n)return Ae;case"SSS":case"DDD":return n?Pe:xe;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Oe;case"a":case"A":return N(e._l)._meridiemParse;case"X":return Ie;case"Z":case"ZZ":return Ne;case"T":return Le;case"SSSS":return Ce;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return n?Ae:Se;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return n?ke:Se;default:return i=new RegExp(j(W(t.replace("\\","")),"i"))}}function Y(t){t=t||"";var e=t.match(Ne)||[],i=e[e.length-1]||[],n=(i+"").match(We)||["-",0,0],s=+(60*n[1])+w(n[2]);return"+"===n[0]?-s:s}function F(t,e,i){var n,s=i._a;switch(t){case"M":case"MM":null!=e&&(s[ue]=w(e)-1);break;case"MMM":case"MMMM":n=N(i._l).monthsParse(e),null!=n?s[ue]=n:i._pf.invalidMonth=e;break;case"D":case"DD":null!=e&&(s[le]=w(e));break;case"DDD":case"DDDD":null!=e&&(i._dayOfYear=w(e));break;case"YY":s[ce]=w(e)+(w(e)>68?1900:2e3);break;case"YYYY":case"YYYYY":case"YYYYYY":s[ce]=w(e);break;case"a":case"A":i._isPm=N(i._l).isPM(e);break;case"H":case"HH":case"h":case"hh":s[pe]=w(e);break;case"m":case"mm":s[fe]=w(e);break;case"s":case"ss":s[me]=w(e);break;case"S":case"SS":case"SSS":case"SSSS":s[ge]=w(1e3*("0."+e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,i._tzm=Y(e);break;case"w":case"ww":case"W":case"WW":case"d":case"dd":case"ddd":case"dddd":case"e":case"E":t=t.substr(0,1);case"gg":case"gggg":case"GG":case"GGGG":case"GGGGG":t=t.substr(0,2),e&&(i._w=i._w||{},i._w[t]=e)}}function R(t){var e,i,n,s,r,o,a,h,d,c,u=[];if(!t._d){for(n=z(t),t._w&&null==t._a[le]&&null==t._a[ue]&&(r=function(e){var i=parseInt(e,10);return e?e.length<3?i>68?1900+i:2e3+i:i:null==t._a[ce]?re().weekYear():t._a[ce]},o=t._w,null!=o.GG||null!=o.W||null!=o.E?a=J(r(o.GG),o.W||1,o.E,4,1):(h=N(t._l),d=null!=o.d?Z(o.d,h):null!=o.e?parseInt(o.e,10)+h._week.dow:0,c=parseInt(o.w,10)||1,null!=o.d&&db(s)&&(t._pf._overflowDayOfYear=!0),i=X(s,0,t._dayOfYear),t._a[ue]=i.getUTCMonth(),t._a[le]=i.getUTCDate()),e=0;3>e&&null==t._a[e];++e)t._a[e]=u[e]=n[e];for(;7>e;e++)t._a[e]=u[e]=null==t._a[e]?2===e?1:0:t._a[e];u[pe]+=w((t._tzm||0)/60),u[fe]+=w((t._tzm||0)%60),t._d=(t._useUTC?X:q).apply(null,u)}}function H(t){var e;t._d||(e=v(t._i),t._a=[e.year,e.month,e.day,e.hour,e.minute,e.second,e.millisecond],R(t))}function z(t){var e=new Date;return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function U(t){t._a=[],t._pf.empty=!0;var e,i,n,s,r,o=N(t._l),a=""+t._i,h=a.length,d=0;for(n=A(t._f,o).match(Ee)||[],e=0;e0&&t._pf.unusedInput.push(r),a=a.slice(a.indexOf(i)+i.length),d+=i.length),Ke[s]?(i?t._pf.empty=!1:t._pf.unusedTokens.push(s),F(s,i,t)):t._strict&&!i&&t._pf.unusedTokens.push(s);t._pf.charsLeftOver=h-d,a.length>0&&t._pf.unusedInput.push(a),t._isPm&&t._a[pe]<12&&(t._a[pe]+=12),t._isPm===!1&&12===t._a[pe]&&(t._a[pe]=0),R(t),T(t)}function W(t){return t.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,i,n,s){return e||i||n||s})}function j(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function V(t){var e,i,n,s,r;if(0===t._f.length)return t._pf.invalidFormat=!0,t._d=new Date(0/0),void 0;for(s=0;sr)&&(n=r,i=e));d(t,i||e)}function G(t){var e,i=t._i,n=Re.exec(i);if(n){for(t._pf.iso=!0,e=4;e>0;e--)if(n[e]){t._f=ze[e-1]+(n[6]||" ");break}for(e=0;4>e;e++)if(Ue[e][1].exec(i)){t._f+=Ue[e][0];break}i.match(Ne)&&(t._f+="Z"),U(t)}else t._d=new Date(i)}function B(t){var e=t._i,i=we.exec(e);e===n?t._d=new Date:i?t._d=new Date(+i[1]):"string"==typeof e?G(t):p(e)?(t._a=e.slice(0),R(t)):f(e)?t._d=new Date(+e):"object"==typeof e?H(t):t._d=new Date(e)}function q(t,e,i,n,s,r,o){var a=new Date(t,e,i,n,s,r,o);return 1970>t&&a.setFullYear(t),a}function X(t){var e=new Date(Date.UTC.apply(null,arguments));return 1970>t&&e.setUTCFullYear(t),e}function Z(t,e){if("string"==typeof t)if(isNaN(t)){if(t=e.weekdaysParse(t),"number"!=typeof t)return null}else t=parseInt(t,10);return t}function K(t,e,i,n,s){return s.relativeTime(e||1,!!i,t,n)}function Q(t,e,i){var n=de(Math.abs(t)/1e3),s=de(n/60),r=de(s/60),o=de(r/24),a=de(o/365),h=45>n&&["s",n]||1===s&&["m"]||45>s&&["mm",s]||1===r&&["h"]||22>r&&["hh",r]||1===o&&["d"]||25>=o&&["dd",o]||45>=o&&["M"]||345>o&&["MM",de(o/30)]||1===a&&["y"]||["yy",a];return h[2]=e,h[3]=t>0,h[4]=i,K.apply({},h)}function $(t,e,i){var n,s=i-e,r=i-t.day();return r>s&&(r-=7),s-7>r&&(r+=7),n=re(t).add("d",r),{week:Math.ceil(n.dayOfYear()/7),year:n.year()}}function J(t,e,i,n,s){var r,o,a=new Date(u(t,6,!0)+"-01-01").getUTCDay();return i=null!=i?i:s,r=s-a+(a>n?7:0),o=7*(e-1)+(i-s)+r+1,{year:o>0?t:t-1,dayOfYear:o>0?o:b(t-1)+o}}function te(t){var e=t._i,i=t._f;return"undefined"==typeof t._pf&&S(t),null===e?re.invalid({nullInput:!0}):("string"==typeof e&&(t._i=e=N().preparse(e)),re.isMoment(e)?(t=d({},e),t._d=new Date(+e._d)):i?p(i)?V(t):U(t):B(t),new a(t))}function ee(t,e){re.fn[t]=re.fn[t+"s"]=function(t){var i=this._isUTC?"UTC":"";return null!=t?(this._d["set"+i+e](t),re.updateOffset(this),this):this._d["get"+i+e]()}}function ie(t){re.duration.fn[t]=function(){return this._data[t]}}function ne(t,e){re.duration.fn["as"+t]=function(){return+this/e}}function se(t){var e=!1,i=re;"undefined"==typeof ender&&(t?(he.moment=function(){return!e&&console&&console.warn&&(e=!0,console.warn("Accessing Moment through the global scope is deprecated, and will be removed in an upcoming release.")),i.apply(null,arguments)},d(he.moment,i)):he.moment=re)}for(var re,oe,ae="2.5.0",he=this,de=Math.round,ce=0,ue=1,le=2,pe=3,fe=4,me=5,ge=6,ve={},ye="undefined"!=typeof i&&i.exports&&"undefined"!=typeof e,we=/^\/?Date\((\-?\d+)/i,_e=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,be=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,Ee=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g,Te=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,Se=/\d\d?/,xe=/\d{1,3}/,De=/\d{1,4}/,Me=/[+\-]?\d{1,6}/,Ce=/\d+/,Oe=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Ne=/Z|[\+\-]\d\d:?\d\d/gi,Le=/T/i,Ie=/[\+\-]?\d+(\.\d{1,3})?/,ke=/\d/,Ae=/\d\d/,Pe=/\d{3}/,Ye=/\d{4}/,Fe=/[+\-]?\d{6}/,Re=/^\s*\d{4}-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,He="YYYY-MM-DDTHH:mm:ssZ",ze=["YYYY-MM-DD","GGGG-[W]WW","GGGG-[W]WW-E","YYYY-DDD"],Ue=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d{1,3}/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],We=/([\+\-]|\d\d)/gi,je="Date|Hours|Minutes|Seconds|Milliseconds".split("|"),Ve={Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6},Ge={ms:"millisecond",s:"second",m:"minute",h:"hour",d:"day",D:"date",w:"week",W:"isoWeek",M:"month",y:"year",DDD:"dayOfYear",e:"weekday",E:"isoWeekday",gg:"weekYear",GG:"isoWeekYear"},Be={dayofyear:"dayOfYear",isoweekday:"isoWeekday",isoweek:"isoWeek",weekyear:"weekYear",isoweekyear:"isoWeekYear"},qe={},Xe="DDD w W M D d".split(" "),Ze="M D H h m s w W".split(" "),Ke={M:function(){return this.month()+1},MMM:function(t){return this.lang().monthsShort(this,t)},MMMM:function(t){return this.lang().months(this,t)},D:function(){return this.date()},DDD:function(){return this.dayOfYear()},d:function(){return this.day()},dd:function(t){return this.lang().weekdaysMin(this,t)},ddd:function(t){return this.lang().weekdaysShort(this,t)},dddd:function(t){return this.lang().weekdays(this,t)},w:function(){return this.week()},W:function(){return this.isoWeek()},YY:function(){return u(this.year()%100,2)},YYYY:function(){return u(this.year(),4)},YYYYY:function(){return u(this.year(),5)},YYYYYY:function(){var t=this.year(),e=t>=0?"+":"-";return e+u(Math.abs(t),6)},gg:function(){return u(this.weekYear()%100,2)},gggg:function(){return this.weekYear()},ggggg:function(){return u(this.weekYear(),5)},GG:function(){return u(this.isoWeekYear()%100,2)},GGGG:function(){return this.isoWeekYear()},GGGGG:function(){return u(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.lang().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.lang().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return w(this.milliseconds()/100)},SS:function(){return u(w(this.milliseconds()/10),2)},SSS:function(){return u(this.milliseconds(),3)},SSSS:function(){return u(this.milliseconds(),3)},Z:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+u(w(t/60),2)+":"+u(w(t)%60,2)},ZZ:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+u(w(t/60),2)+u(w(t)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},X:function(){return this.unix()},Q:function(){return this.quarter()}},Qe=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"];Xe.length;)oe=Xe.pop(),Ke[oe+"o"]=r(Ke[oe],oe);for(;Ze.length;)oe=Ze.pop(),Ke[oe+oe]=s(Ke[oe],2);for(Ke.DDDD=s(Ke.DDD,3),d(o.prototype,{set:function(t){var e,i;for(i in t)e=t[i],"function"==typeof e?this[i]=e:this["_"+i]=e},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(t){return this._months[t.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(t){return this._monthsShort[t.month()]},monthsParse:function(t){var e,i,n;for(this._monthsParse||(this._monthsParse=[]),e=0;12>e;e++)if(this._monthsParse[e]||(i=re.utc([2e3,e]),n="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[e]=new RegExp(n.replace(".",""),"i")),this._monthsParse[e].test(t))return e},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(t){return this._weekdays[t.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(t){return this._weekdaysShort[t.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(t){return this._weekdaysMin[t.day()]},weekdaysParse:function(t){var e,i,n;for(this._weekdaysParse||(this._weekdaysParse=[]),e=0;7>e;e++)if(this._weekdaysParse[e]||(i=re([2e3,1]).day(e),n="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[e]=new RegExp(n.replace(".",""),"i")),this._weekdaysParse[e].test(t))return e},_longDateFormat:{LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D YYYY",LLL:"MMMM D YYYY LT",LLLL:"dddd, MMMM D YYYY LT"},longDateFormat:function(t){var e=this._longDateFormat[t];return!e&&this._longDateFormat[t.toUpperCase()]&&(e=this._longDateFormat[t.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t]=e),e},isPM:function(t){return"p"===(t+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(t,e,i){return t>11?i?"pm":"PM":i?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(t,e){var i=this._calendar[t];return"function"==typeof i?i.apply(e):i},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(t,e,i,n){var s=this._relativeTime[i];return"function"==typeof s?s(t,e,i,n):s.replace(/%d/i,t)},pastFuture:function(t,e){var i=this._relativeTime[t>0?"future":"past"];return"function"==typeof i?i(e):i.replace(/%s/i,e)},ordinal:function(t){return this._ordinal.replace("%d",t)},_ordinal:"%d",preparse:function(t){return t},postformat:function(t){return t},week:function(t){return $(t,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),re=function(t,e,i,s){return"boolean"==typeof i&&(s=i,i=n),te({_i:t,_f:e,_l:i,_strict:s,_isUTC:!1})},re.utc=function(t,e,i,s){var r;return"boolean"==typeof i&&(s=i,i=n),r=te({_useUTC:!0,_isUTC:!0,_l:i,_i:t,_f:e,_strict:s}).utc()},re.unix=function(t){return re(1e3*t)},re.duration=function(t,e){var i,n,s,r=t,o=null;return re.isDuration(t)?r={ms:t._milliseconds,d:t._days,M:t._months}:"number"==typeof t?(r={},e?r[e]=t:r.milliseconds=t):(o=_e.exec(t))?(i="-"===o[1]?-1:1,r={y:0,d:w(o[le])*i,h:w(o[pe])*i,m:w(o[fe])*i,s:w(o[me])*i,ms:w(o[ge])*i}):(o=be.exec(t))&&(i="-"===o[1]?-1:1,s=function(t){var e=t&&parseFloat(t.replace(",","."));return(isNaN(e)?0:e)*i},r={y:s(o[2]),M:s(o[3]),d:s(o[4]),h:s(o[5]),m:s(o[6]),s:s(o[7]),w:s(o[8])}),n=new h(r),re.isDuration(t)&&t.hasOwnProperty("_lang")&&(n._lang=t._lang),n},re.version=ae,re.defaultFormat=He,re.updateOffset=function(){},re.lang=function(t,e){var i;return t?(e?C(D(t),e):null===e?(O(t),t="en"):ve[t]||N(t),i=re.duration.fn._lang=re.fn._lang=N(t),i._abbr):re.fn._lang._abbr},re.langData=function(t){return t&&t._lang&&t._lang._abbr&&(t=t._lang._abbr),N(t)},re.isMoment=function(t){return t instanceof a},re.isDuration=function(t){return t instanceof h},oe=Qe.length-1;oe>=0;--oe)y(Qe[oe]);for(re.normalizeUnits=function(t){return g(t)},re.invalid=function(t){var e=re.utc(0/0);return null!=t?d(e._pf,t):e._pf.userInvalidated=!0,e},re.parseZone=function(t){return re(t).parseZone()},d(re.fn=a.prototype,{clone:function(){return re(this)},valueOf:function(){return+this._d+6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().lang("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){var t=re(this).utc();return 00:!1},parsingFlags:function(){return d({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(){return this.zone(0)},local:function(){return this.zone(0),this._isUTC=!1,this},format:function(t){var e=k(this,t||re.defaultFormat);return this.lang().postformat(e)},add:function(t,e){var i;return i="string"==typeof t?re.duration(+e,t):re.duration(t,e),l(this,i,1),this},subtract:function(t,e){var i;return i="string"==typeof t?re.duration(+e,t):re.duration(t,e),l(this,i,-1),this},diff:function(t,e,i){var n,s,r=M(t,this),o=6e4*(this.zone()-r.zone());return e=g(e),"year"===e||"month"===e?(n=432e5*(this.daysInMonth()+r.daysInMonth()),s=12*(this.year()-r.year())+(this.month()-r.month()),s+=(this-re(this).startOf("month")-(r-re(r).startOf("month")))/n,s-=6e4*(this.zone()-re(this).startOf("month").zone()-(r.zone()-re(r).startOf("month").zone()))/n,"year"===e&&(s/=12)):(n=this-r,s="second"===e?n/1e3:"minute"===e?n/6e4:"hour"===e?n/36e5:"day"===e?(n-o)/864e5:"week"===e?(n-o)/6048e5:n),i?s:c(s)},from:function(t,e){return re.duration(this.diff(t)).lang(this.lang()._abbr).humanize(!e)},fromNow:function(t){return this.from(re(),t)},calendar:function(){var t=M(re(),this).startOf("day"),e=this.diff(t,"days",!0),i=-6>e?"sameElse":-1>e?"lastWeek":0>e?"lastDay":1>e?"sameDay":2>e?"nextDay":7>e?"nextWeek":"sameElse";return this.format(this.lang().calendar(i,this))},isLeapYear:function(){return E(this.year())},isDST:function(){return this.zone()+re(t).startOf(e)},isBefore:function(t,e){return e="undefined"!=typeof e?e:"millisecond",+this.clone().startOf(e)<+re(t).startOf(e)},isSame:function(t,e){return e=e||"ms",+this.clone().startOf(e)===+M(t,this).startOf(e)},min:function(t){return t=re.apply(null,arguments),this>t?this:t},max:function(t){return t=re.apply(null,arguments),t>this?this:t},zone:function(t){var e=this._offset||0;return null==t?this._isUTC?e:this._d.getTimezoneOffset():("string"==typeof t&&(t=Y(t)),Math.abs(t)<16&&(t=60*t),this._offset=t,this._isUTC=!0,e!==t&&l(this,re.duration(e-t,"m"),1,!0),this)},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.zone(this._tzm):"string"==typeof this._i&&this.zone(this._i),this},hasAlignedHourOffset:function(t){return t=t?re(t).zone():0,(this.zone()-t)%60===0},daysInMonth:function(){return _(this.year(),this.month())},dayOfYear:function(t){var e=de((re(this).startOf("day")-re(this).startOf("year"))/864e5)+1;return null==t?e:this.add("d",t-e)},quarter:function(){return Math.ceil((this.month()+1)/3)},weekYear:function(t){var e=$(this,this.lang()._week.dow,this.lang()._week.doy).year;return null==t?e:this.add("y",t-e)},isoWeekYear:function(t){var e=$(this,1,4).year;return null==t?e:this.add("y",t-e)},week:function(t){var e=this.lang().week(this);return null==t?e:this.add("d",7*(t-e))},isoWeek:function(t){var e=$(this,1,4).week;return null==t?e:this.add("d",7*(t-e))},weekday:function(t){var e=(this.day()+7-this.lang()._week.dow)%7;return null==t?e:this.add("d",t-e)},isoWeekday:function(t){return null==t?this.day()||7:this.day(this.day()%7?t:t-7)},get:function(t){return t=g(t),this[t]()},set:function(t,e){return t=g(t),"function"==typeof this[t]&&this[t](e),this},lang:function(t){return t===n?this._lang:(this._lang=N(t),this)}}),oe=0;oe img { - border: none; + border: none; } a { - color: #2B7CE9; - text-decoration: none; + color: #2B7CE9; + text-decoration: none; } a:visited { - color: #2E60A4; + color: #2E60A4; } a:hover { - color: red; - text-decoration: underline; + color: red; + text-decoration: underline; } table { - border-collapse: collapse; + border-collapse: collapse; } th { - font-weight: bold; - border: 1px solid lightgray; - background-color: #E5E5E5; - text-align: left; - vertical-align: top; - padding: 5px; + font-weight: bold; + border: 1px solid lightgray; + background-color: #E5E5E5; + text-align: left; + vertical-align: top; + padding: 5px; } td { - border: 1px solid lightgray; - padding: 5px; - vertical-align: top; + border: 1px solid lightgray; + padding: 5px; + vertical-align: top; } diff --git a/docs/dataset.html b/docs/dataset.html index 1847a3b1..e6e8310b 100644 --- a/docs/dataset.html +++ b/docs/dataset.html @@ -2,50 +2,50 @@ - vis.js | DataSet documentation + vis.js | DataSet documentation - - + + - +
    -

    DataSet documentation

    +

    DataSet documentation

    -

    Contents

    - +

    Contents

    + -

    Overview

    +

    Overview

    -

    - Vis.js comes with a flexible DataSet, which can be used to hold and - manipulate unstructured data and listen for changes in the data. - The DataSet is key/value based. Data items can be added, updated and - removed from the DatSet, and one can subscribe to changes in the DataSet. - The data in the DataSet can be filtered and ordered, and fields (like - dates) can be converted to a specific type. Data can be normalized when - appending it to the DataSet as well. -

    +

    + Vis.js comes with a flexible DataSet, which can be used to hold and + manipulate unstructured data and listen for changes in the data. + The DataSet is key/value based. Data items can be added, updated and + removed from the DatSet, and one can subscribe to changes in the DataSet. + The data in the DataSet can be filtered and ordered, and fields (like + dates) can be converted to a specific type. Data can be normalized when + appending it to the DataSet as well. +

    -

    Example

    +

    Example

    -

    - The following example shows how to use a DataSet. -

    +

    + The following example shows how to use a DataSet. +

     // create a DataSet
    @@ -55,15 +55,15 @@ var data = new vis.DataSet(options);
     // add items
     // note that the data items can contain different properties and data formats
     data.add([
    -    {id: 1, text: 'item 1', date: new Date(2013, 6, 20), group: 1, first: true},
    -    {id: 2, text: 'item 2', date: '2013-06-23', group: 2},
    -    {id: 3, text: 'item 3', date: '2013-06-25', group: 2},
    -    {id: 4, text: 'item 4'}
    +  {id: 1, text: 'item 1', date: new Date(2013, 6, 20), group: 1, first: true},
    +  {id: 2, text: 'item 2', date: '2013-06-23', group: 2},
    +  {id: 3, text: 'item 3', date: '2013-06-25', group: 2},
    +  {id: 4, text: 'item 4'}
     ]);
     
     // subscribe to any change in the DataSet
     data.subscribe('*', function (event, params, senderId) {
    -    console.log('event', event, params);
    +  console.log('event', event, params);
     });
     
     // update an existing item
    @@ -82,94 +82,94 @@ console.log('item1', item1);
     
     // retrieve a filtered subset of the data
     var items = data.get({
    -    filter: function (item) {
    -        return item.group == 1;
    -    }
    +  filter: function (item) {
    +    return item.group == 1;
    +  }
     });
     console.log('filtered items', items);
     
     // retrieve formatted items
     var items = data.get({
    -    fields: ['id', 'date'],
    -    convert: {
    -        date: 'ISODate'
    -    }
    +  fields: ['id', 'date'],
    +  convert: {
    +    date: 'ISODate'
    +  }
     });
     console.log('formatted items', items);
     
    -

    Construction

    +

    Construction

    -

    - A DataSet can be constructed as: -

    +

    + A DataSet can be constructed as: +

     var data = new vis.DataSet(options)
     
    -

    - After construction, data can be added to the DataSet using the methods - add and update, as described in section - Data Manipulation. -

    - -

    - The parameter options is optional and is an object which can - contain the following properties: -

    - - - - - - - - - - - - - - - - - - - - -
    NameTypeDefault valueDescription
    fieldIdString"id" - The name of the field containing the id of the items. - - When data is fetched from a server which uses some specific - field to identify items, this field name can be specified - in the DataSet using the option fieldId. - For example CouchDB uses the field - "_id" to identify documents. -
    convertObject.<String, String>none - An object containing field names as key, and data types as - value. By default, the type of the properties of items are left - unchanged. Item properties can be normalized by specifying a - field type. This is useful for example to automatically convert - stringified dates coming from a server into JavaScript Date - objects. The available data types are listed in section - Data Types. -
    - - -

    Data Manipulation

    - -

    - The data in a DataSet can be manipulated using the methods - add, - update, - and remove. - The DataSet can be emptied using the method - clear. -

    +

    + After construction, data can be added to the DataSet using the methods + add and update, as described in section + Data Manipulation. +

    + +

    + The parameter options is optional and is an object which can + contain the following properties: +

    + + + + + + + + + + + + + + + + + + + + +
    NameTypeDefault valueDescription
    fieldIdString"id" + The name of the field containing the id of the items. + + When data is fetched from a server which uses some specific + field to identify items, this field name can be specified + in the DataSet using the option fieldId. + For example CouchDB uses the field + "_id" to identify documents. +
    convertObject.<String, String>none + An object containing field names as key, and data types as + value. By default, the type of the properties of items are left + unchanged. Item properties can be normalized by specifying a + field type. This is useful for example to automatically convert + stringified dates coming from a server into JavaScript Date + objects. The available data types are listed in section + Data Types. +
    + + +

    Data Manipulation

    + +

    + The data in a DataSet can be manipulated using the methods + add, + update, + and remove. + The DataSet can be emptied using the method + clear. +

     // create a DataSet
    @@ -177,9 +177,9 @@ var data = new vis.DataSet();
     
     // add items
     data.add([
    -    {id: 1, text: 'item 1'},
    -    {id: 2, text: 'item 2'},
    -    {id: 3, text: 'item 3'}
    +  {id: 1, text: 'item 1'},
    +  {id: 2, text: 'item 2'},
    +  {id: 3, text: 'item 3'}
     ]);
     
     // update an item
    @@ -189,193 +189,193 @@ data.update({id: 2, text: 'item 2 (updated)'});
     data.remove(3);
     
    -

    Add

    - -

    - Add a data item or an array with items. -

    - - Syntax: -
    var addedIds = DataSet.add(data [, senderId])
    - - The argument data can contain: -
      -
    • - An Object containing a single item to be - added. The item must contain an id. -
    • -
    • - An Array or - google.visualization.DataTable containing - a list with items to be added. Each item must contain - an id. -
    • -
    - -

    - After the items are added to the DataSet, the DataSet will - trigger an event add. When a senderId - is provided, this id will be passed with the triggered - event to all subscribers. -

    - -

    - The method will throw an Error when an item with the same id - as any of the added items already exists. -

    - -

    Update

    - -

    - Update a data item or an array with items. -

    - - Syntax: -
    var updatedIds = DataSet.update(data [, senderId])
    - - The argument data can contain: -
      -
    • - An Object containing a single item to be - updated. The item must contain an id. -
    • -
    • - An Array or - google.visualization.DataTable containing - a list with items to be updated. Each item must contain - an id. -
    • -
    - -

    - The provided properties will be merged in the existing item. - When an item does not exist, it will be created. -

    - -

    - After the items are updated, the DataSet will - trigger an event add for the added items, and - an event update. When a senderId - is provided, this id will be passed with the triggered - event to all subscribers. -

    - -

    Remove

    - -

    - Remove a data item or an array with items. -

    - - Syntax: -
    var removedIds = DataSet.remove(id [, senderId])
    - -

    - The argument id can be: -

    -
      -
    • - A Number or String containing the id - of a single item to be removed. -
    • -
    • - An Object containing the item to be deleted. - The item will be deleted by its id. -
    • -
    • - An Array containing ids or items to be removed. -
    • -
    - -

    - The method ignores removal of non-existing items, and returns an array - containing the ids of the items which are actually removed from the - DataSet. -

    - -

    - After the items are removed, the DataSet will - trigger an event remove for the removed items. - When a senderId is provided, this id will be passed with - the triggered event to all subscribers. -

    - - -

    Clear

    - -

    - Clear the complete DataSet. -

    - - Syntax: -
    var removedIds = DataSet.clear([senderId])
    - -

    - After the items are removed, the DataSet will - trigger an event remove for all removed items. - When a senderId is provided, this id will be passed with - the triggered event to all subscribers. -

    - - -

    Data Filtering

    - -

    - Data can be retrieved from the DataSet using the method get. - This method can return a single item or a list with items. -

    - -

    A single item can be retrieved by its id:

    +

    Add

    + +

    + Add a data item or an array with items. +

    + +Syntax: +
    var addedIds = DataSet.add(data [, senderId])
    + +The argument data can contain: +
      +
    • + An Object containing a single item to be + added. The item must contain an id. +
    • +
    • + An Array or + google.visualization.DataTable containing + a list with items to be added. Each item must contain + an id. +
    • +
    + +

    + After the items are added to the DataSet, the DataSet will + trigger an event add. When a senderId + is provided, this id will be passed with the triggered + event to all subscribers. +

    + +

    + The method will throw an Error when an item with the same id + as any of the added items already exists. +

    + +

    Update

    + +

    + Update a data item or an array with items. +

    + +Syntax: +
    var updatedIds = DataSet.update(data [, senderId])
    + +The argument data can contain: +
      +
    • + An Object containing a single item to be + updated. The item must contain an id. +
    • +
    • + An Array or + google.visualization.DataTable containing + a list with items to be updated. Each item must contain + an id. +
    • +
    + +

    + The provided properties will be merged in the existing item. + When an item does not exist, it will be created. +

    + +

    + After the items are updated, the DataSet will + trigger an event add for the added items, and + an event update. When a senderId + is provided, this id will be passed with the triggered + event to all subscribers. +

    + +

    Remove

    + +

    + Remove a data item or an array with items. +

    + +Syntax: +
    var removedIds = DataSet.remove(id [, senderId])
    + +

    + The argument id can be: +

    +
      +
    • + A Number or String containing the id + of a single item to be removed. +
    • +
    • + An Object containing the item to be deleted. + The item will be deleted by its id. +
    • +
    • + An Array containing ids or items to be removed. +
    • +
    + +

    + The method ignores removal of non-existing items, and returns an array + containing the ids of the items which are actually removed from the + DataSet. +

    + +

    + After the items are removed, the DataSet will + trigger an event remove for the removed items. + When a senderId is provided, this id will be passed with + the triggered event to all subscribers. +

    + + +

    Clear

    + +

    + Clear the complete DataSet. +

    + +Syntax: +
    var removedIds = DataSet.clear([senderId])
    + +

    + After the items are removed, the DataSet will + trigger an event remove for all removed items. + When a senderId is provided, this id will be passed with + the triggered event to all subscribers. +

    + + +

    Data Filtering

    + +

    + Data can be retrieved from the DataSet using the method get. + This method can return a single item or a list with items. +

    + +

    A single item can be retrieved by its id:

     var item1 = dataset.get(1);
     
    -

    A selection of items can be retrieved by providing an array with ids:

    +

    A selection of items can be retrieved by providing an array with ids:

     var items = dataset.get([1, 3, 4]); // retrieve items 1, 3, and 4
     
    -

    All items can be retrieved by simply calling get without - specifying an id:

    +

    All items can be retrieved by simply calling get without + specifying an id:

     var items = dataset.get();          // retrieve all items
     
    -

    - Items can be filtered on specific properties by providing a filter - function. A filter function is executed for each of the items in the - DataSet, and is called with the item as parameter. The function must - return a boolean. All items for which the filter function returns - true will be emitted. -

    +

    + Items can be filtered on specific properties by providing a filter + function. A filter function is executed for each of the items in the + DataSet, and is called with the item as parameter. The function must + return a boolean. All items for which the filter function returns + true will be emitted. +

     // retrieve all items having a property group with value 2
     var group2 = dataset.get({
    -    filter: function (item) {
    -        return (item.group == 2);
    -    }
    +  filter: function (item) {
    +    return (item.group == 2);
    +  }
     });
     
     // retrieve all items having a property balance with a value above zero
     var positiveBalance = dataset.get({
    -    filter: function (item) {
    -        return (item.balance > 0);
    -    }
    +  filter: function (item) {
    +    return (item.balance > 0);
    +  }
     });
     
     
    -

    Data Formatting

    +

    Data Formatting

    -

    - The DataSet contains functionality to format data retrieved via the - method get. The method get has the following - syntax: -

    +

    + The DataSet contains functionality to format data retrieved via the + method get. The method get has the following + syntax: +

     var item  = DataSet.get(id, options);   // retrieve a single item
    @@ -383,164 +383,171 @@ var items = DataSet.get(ids, options);  // retrieve a selection of items
     var items = DataSet.get(options);       // retrieve all items or a filtered set
     
    -

    - Where options is an Object which can have the following - properties: -

    - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    fieldsString[ ] - An array with field names. - By default, all properties of the items are emitted. - When fields is defined, only the properties - whose name is specified in fields will be included - in the returned items. -
    convertObject.<String, String> - An object containing field names as key, and data types as value. - By default, the type of the properties of an item are left - unchanged. When a field type is specified, this field in the - items will be converted to the specified type. This can be used - for example to convert ISO strings containing a date to a - JavaScript Date object, or convert strings to numbers or vice - versa. The available data types are listed in section - Data Types. -
    filterfunctionItems can be filtered on specific properties by providing a filter - function. A filter function is executed for each of the items in the - DataSet, and is called with the item as parameter. The function must - return a boolean. All items for which the filter function returns - true will be emitted. - See section Data Filtering.
    - -

    - The following example demonstrates formatting properties and filtering - properties from items. -

    +

    + Where options is an Object which can have the following + properties: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    fieldsString[ ] + An array with field names. + By default, all properties of the items are emitted. + When fields is defined, only the properties + whose name is specified in fields will be included + in the returned items. +
    convertObject.<String, String> + An object containing field names as key, and data types as value. + By default, the type of the properties of an item are left + unchanged. When a field type is specified, this field in the + items will be converted to the specified type. This can be used + for example to convert ISO strings containing a date to a + JavaScript Date object, or convert strings to numbers or vice + versa. The available data types are listed in section + Data Types. +
    filterFunctionItems can be filtered on specific properties by providing a filter + function. A filter function is executed for each of the items in the + DataSet, and is called with the item as parameter. The function must + return a boolean. All items for which the filter function returns + true will be emitted. + See section Data Filtering.
    orderString | FunctionOrder the items by a field name or custom sort function.
    + +

    + The following example demonstrates formatting properties and filtering + properties from items. +

     // create a DataSet
     var data = new vis.DataSet();
     data.add([
    -    {id: 1, text: 'item 1', date: '2013-06-20', group: 1, first: true},
    -    {id: 2, text: 'item 2', date: '2013-06-23', group: 2},
    -    {id: 3, text: 'item 3', date: '2013-06-25', group: 2},
    -    {id: 4, text: 'item 4'}
    +  {id: 1, text: 'item 1', date: '2013-06-20', group: 1, first: true},
    +  {id: 2, text: 'item 2', date: '2013-06-23', group: 2},
    +  {id: 3, text: 'item 3', date: '2013-06-25', group: 2},
    +  {id: 4, text: 'item 4'}
     ]);
     
     // retrieve formatted items
     var items = data.get({
    -    fields: ['id', 'date', 'group'],    // output the specified fields only
    -    convert: {
    -        date: 'Date',                   // convert the date fields to Date objects
    -        group: 'String'                 // convert the group fields to Strings
    -    }
    +  fields: ['id', 'date', 'group'],    // output the specified fields only
    +  convert: {
    +    date: 'Date',                   // convert the date fields to Date objects
    +    group: 'String'                 // convert the group fields to Strings
    +  }
     });
     
    -

    Data Types

    - -

    - DataSet supports the following data types: -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameDescriptionExamples
    BooleanA JavaScript Boolean - true
    - false -
    NumberA JavaScript Number - 32
    - 2.4 -
    StringA JavaScript String - "hello world"
    - "2013-06-28" -
    DateA JavaScript Date object - new Date()
    - new Date(2013, 5, 28)
    - new Date(1372370400000) -
    MomentA Moment object, created with - moment.js - moment()
    - moment('2013-06-28') -
    ISODateA string containing an ISO Date - new Date().toISOString()
    - "2013-06-27T22:00:00.000Z" -
    ASPDateA string containing an ASP Date - "/Date(1372370400000)/"
    - "/Date(1198908717056-0700)/" -
    - - -

    Subscriptions

    - -

    - One can subscribe on changes in a DataSet. - A subscription can be created using the method subscribe, - and removed with unsubscribe. -

    +

    Data Types

    + +

    + DataSet supports the following data types: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameDescriptionExamples
    BooleanA JavaScript Boolean + true
    + false +
    NumberA JavaScript Number + 32
    + 2.4 +
    StringA JavaScript String + "hello world"
    + "2013-06-28" +
    DateA JavaScript Date object + new Date()
    + new Date(2013, 5, 28)
    + new Date(1372370400000) +
    MomentA Moment object, created with + moment.js + moment()
    + moment('2013-06-28') +
    ISODateA string containing an ISO Date + new Date().toISOString()
    + "2013-06-27T22:00:00.000Z" +
    ASPDateA string containing an ASP Date + "/Date(1372370400000)/"
    + "/Date(1198908717056-0700)/" +
    + + +

    Subscriptions

    + +

    + One can subscribe on changes in a DataSet. + A subscription can be created using the method subscribe, + and removed with unsubscribe. +

     // create a DataSet
    @@ -548,7 +555,7 @@ var data = new vis.DataSet();
     
     // subscribe to any change in the DataSet
     data.subscribe('*', function (event, params, senderId) {
    -    console.log('event:', event, 'params:', params, 'senderId:', senderId);
    +  console.log('event:', event, 'params:', params, 'senderId:', senderId);
     });
     
     // add an item
    @@ -558,144 +565,144 @@ data.remove(1);                                 // triggers an 'remove' event
     
    -

    Subscribe

    - -

    - Subscribe to an event. -

    - - Syntax: -
    DataSet.subscribe(event, callback)
    - - Where: -
      -
    • - event is a String containing any of the events listed - in section Events. -
    • -
    • - callback is a callback function which will be called - each time the event occurs. The callback function is described in - section Callback. -
    • -
    - -

    Unsubscribe

    - -

    - Unsubscribe from an event. -

    - - Syntax: -
    DataSet.unsubscribe(event, callback)
    - - Where event and callback correspond with the - parameters used to subscribe to the event. - -

    Events

    - -

    - The following events are available for subscription: -

    - - - - - - - - - - - - - - - - - - - - - - -
    EventDescription
    add - The add event is triggered when an item - or a set of items is added, or when an item is updated while - not yet existing. -
    update - The update event is triggered when an existing item - or a set of existing items is updated. -
    remove - The remove event is triggered when an item - or a set of items is removed. -
    * - The * event is triggered when any of the events - add, update, and remove - occurs. -
    - -

    Callback

    - -

    - The callback functions of subscribers are called with the following - parameters: -

    +

    Subscribe

    + +

    + Subscribe to an event. +

    + +Syntax: +
    DataSet.subscribe(event, callback)
    + +Where: +
      +
    • + event is a String containing any of the events listed + in section Events. +
    • +
    • + callback is a callback function which will be called + each time the event occurs. The callback function is described in + section Callback. +
    • +
    + +

    Unsubscribe

    + +

    + Unsubscribe from an event. +

    + +Syntax: +
    DataSet.unsubscribe(event, callback)
    + +Where event and callback correspond with the +parameters used to subscribe to the event. + +

    Events

    + +

    + The following events are available for subscription: +

    + + + + + + + + + + + + + + + + + + + + + + +
    EventDescription
    add + The add event is triggered when an item + or a set of items is added, or when an item is updated while + not yet existing. +
    update + The update event is triggered when an existing item + or a set of existing items is updated. +
    remove + The remove event is triggered when an item + or a set of items is removed. +
    * + The * event is triggered when any of the events + add, update, and remove + occurs. +
    + +

    Callback

    + +

    + The callback functions of subscribers are called with the following + parameters: +

     function (event, params, senderId) {
    -    // handle the event
    +  // handle the event
     });
     
    -

    - where the parameters are defined as -

    - - - - - - - - - - - - - - - - - - - - - - -
    ParameterTypeDescription
    eventString - Any of the available events: add, - update, or remove. -
    paramsObject | null - Optional parameters providing more information on the event. - In case of the events add, - update, and remove, - params is always an object containing a property - items, which contains an array with the ids of the affected - items. -
    senderIdString | Number - An senderId, optionally provided by the application code - which triggered the event. If senderId is not provided, the - argument will be null. -
    - - - -

    Data Policy

    -

    - All code and data is processed and rendered in the browser. - No data is sent to any server. -

    +

    + where the parameters are defined as +

    + + + + + + + + + + + + + + + + + + + + + + +
    ParameterTypeDescription
    eventString + Any of the available events: add, + update, or remove. +
    paramsObject | null + Optional parameters providing more information on the event. + In case of the events add, + update, and remove, + params is always an object containing a property + items, which contains an array with the ids of the affected + items. +
    senderIdString | Number + An senderId, optionally provided by the application code + which triggered the event. If senderId is not provided, the + argument will be null. +
    + + + +

    Data Policy

    +

    + All code and data is processed and rendered in the browser. + No data is sent to any server. +

    diff --git a/docs/dataview.html b/docs/dataview.html index bb459d9c..1698ffb1 100644 --- a/docs/dataview.html +++ b/docs/dataview.html @@ -2,69 +2,69 @@ - vis.js | DataView documentation + vis.js | DataView documentation - - + + - +
    -

    DataView documentation

    +

    DataView documentation

    -

    Contents

    - +

    Contents

    + -

    Overview

    +

    Overview

    -

    - A DataView offers a filtered and/or formatted view on a - DataSet. - One can subscribe on changes in a DataView, and easily get filtered or - formatted data without having to specify filters and field types all - the time. -

    +

    + A DataView offers a filtered and/or formatted view on a + DataSet. + One can subscribe on changes in a DataView, and easily get filtered or + formatted data without having to specify filters and field types all + the time. +

    -

    Example

    +

    Example

    -

    - The following example shows how to use a DataView. -

    +

    + The following example shows how to use a DataView. +

     // create a DataSet
     var data = new vis.DataSet();
     data.add([
    -    {id: 1, text: 'item 1', date: new Date(2013, 6, 20), group: 1, first: true},
    -    {id: 2, text: 'item 2', date: '2013-06-23', group: 2},
    -    {id: 3, text: 'item 3', date: '2013-06-25', group: 2},
    -    {id: 4, text: 'item 4'}
    +  {id: 1, text: 'item 1', date: new Date(2013, 6, 20), group: 1, first: true},
    +  {id: 2, text: 'item 2', date: '2013-06-23', group: 2},
    +  {id: 3, text: 'item 3', date: '2013-06-25', group: 2},
    +  {id: 4, text: 'item 4'}
     ]);
     
     // create a DataView
     // the view will only contain items having a property group with value 1,
     // and will only output fields id, text, and date.
     var view = new vis.DataView(data, {
    -    filter: function (item) {
    -        return (item.group == 1);
    -    },
    -    fields: ['id', 'text', 'date']
    +  filter: function (item) {
    +    return (item.group == 1);
    +  },
    +  fields: ['id', 'text', 'date']
     });
     
     // subscribe to any change in the DataView
     view.subscribe('*', function (event, params, senderId) {
    -    console.log('event', event, params);
    +  console.log('event', event, params);
     });
     
     // update an item in the data set
    @@ -78,131 +78,131 @@ console.log('ids', ids); // will output [1, 2]
     var items = view.get();
     
    -

    Construction

    +

    Construction

    -

    - A DataView can be constructed as: -

    +

    + A DataView can be constructed as: +

     var data = new vis.DataView(dataset, options)
     
    -

    - where: -

    - -
      -
    • - dataset is a DataSet or DataView. -
    • -
    • - options is an object which can - contain the following properties. Note that these properties - are exactly the same as the properties available in methods - DataSet.get and DataView.get. - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      NameTypeDescription
      convertObject.<String, String> - An object containing field names as key, and data types as value. - By default, the type of the properties of an item are left - unchanged. When a field type is specified, this field in the - items will be converted to the specified type. This can be used - for example to convert ISO strings containing a date to a - JavaScript Date object, or convert strings to numbers or vice - versa. The available data types are listed in section - Data Types. -
      fieldsString[ ] - An array with field names. - By default, all properties of the items are emitted. - When fields is defined, only the properties - whose name is specified in fields will be included - in the returned items. -
      filterfunctionItems can be filtered on specific properties by providing a filter - function. A filter function is executed for each of the items in the - DataSet, and is called with the item as parameter. The function must - return a boolean. All items for which the filter function returns - true will be emitted. - See also section Data Filtering.
      -
    • -
    - -

    Getting Data

    - -

    - Data of the DataView can be retrieved using the method get. -

    +

    + where: +

    + +
      +
    • + dataset is a DataSet or DataView. +
    • +
    • + options is an object which can + contain the following properties. Note that these properties + are exactly the same as the properties available in methods + DataSet.get and DataView.get. + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      NameTypeDescription
      convertObject.<String, String> + An object containing field names as key, and data types as value. + By default, the type of the properties of an item are left + unchanged. When a field type is specified, this field in the + items will be converted to the specified type. This can be used + for example to convert ISO strings containing a date to a + JavaScript Date object, or convert strings to numbers or vice + versa. The available data types are listed in section + Data Types. +
      fieldsString[ ] + An array with field names. + By default, all properties of the items are emitted. + When fields is defined, only the properties + whose name is specified in fields will be included + in the returned items. +
      filterfunctionItems can be filtered on specific properties by providing a filter + function. A filter function is executed for each of the items in the + DataSet, and is called with the item as parameter. The function must + return a boolean. All items for which the filter function returns + true will be emitted. + See also section Data Filtering.
      +
    • +
    + +

    Getting Data

    + +

    + Data of the DataView can be retrieved using the method get. +

     var items = view.get();
     
    -

    - Data of a DataView can be filtered and formatted again, in exactly the - same way as in a DataSet. See sections - Data Filtering and - Data Formatting for more - information. -

    +

    + Data of a DataView can be filtered and formatted again, in exactly the + same way as in a DataSet. See sections + Data Filtering and + Data Formatting for more + information. +

     var items = view.get({
    -    fields: ['id', 'score'],
    -    filter: function (item) {
    -        return (item.score > 50);
    -    }
    +  fields: ['id', 'score'],
    +  filter: function (item) {
    +    return (item.score > 50);
    +  }
     });
     
    -

    Subscriptions

    -

    - One can subscribe on changes in the DataView. Subscription works exactly - the same as for DataSets. See the documentation on - subscriptions in a DataSet - for more information. -

    +

    Subscriptions

    +

    + One can subscribe on changes in the DataView. Subscription works exactly + the same as for DataSets. See the documentation on + subscriptions in a DataSet + for more information. +

     // create a DataSet and a view on the data set
     var data = new vis.DataSet();
     var view = new vis.DataView({
    -    filter: function (item) {
    -        return (item.group == 2);
    -    }
    +  filter: function (item) {
    +    return (item.group == 2);
    +  }
     });
     
     // subscribe to any change in the DataView
     view.subscribe('*', function (event, params, senderId) {
    -    console.log('event:', event, 'params:', params, 'senderId:', senderId);
    +  console.log('event:', event, 'params:', params, 'senderId:', senderId);
     });
     
     // add, update, and remove data in the DataSet...
    @@ -210,11 +210,11 @@ view.subscribe('*', function (event, params, senderId) {
     
     
     
    -    

    Data Policy

    -

    - All code and data is processed and rendered in the browser. - No data is sent to any server. -

    +

    Data Policy

    +

    + All code and data is processed and rendered in the browser. + No data is sent to any server. +

    diff --git a/docs/graph.html b/docs/graph.html index f196a732..2c679bc1 100644 --- a/docs/graph.html +++ b/docs/graph.html @@ -2,12 +2,12 @@ - vis.js | graph documentation + vis.js | graph documentation - - + + - + @@ -17,52 +17,58 @@

    Contents

    Overview

    - Graph is a visualization to display graphs and networks consisting of nodes - and edges. The visualization is easy to use and supports custom shapes, - styles, colors, sizes, images, and more. + Graph is a visualization to display graphs and networks consisting of nodes + and edges. The visualization is easy to use and supports custom shapes, + styles, colors, sizes, images, and more.

    - The graph visualization works smooth on any modern browser for up to a - few hundred nodes and edges. + The graph visualization works smooth on any modern browser for up to a + few hundred nodes and edges.

    - To get started with Graph, install or download the - vis.js library. + To get started with Graph, install or download the + vis.js library.

    Example

    - Here a basic graph example. More examples can be found in the - examples directory. + Here a basic graph example. Note that unlike the + Timeline, the Graph does not need the vis.css + file. +

    + +

    + More examples can be found in the + examples directory.

    <!doctype html>
     <html>
     <head>
    -    <title>Graph | Basic usage</title>
    +  <title>Graph | Basic usage</title>
     
    -    <script type="text/javascript" src="../../vis.js"></script>
    +  <script type="text/javascript" src="../../dist/vis.js"></script>
     </head>
     
     <body>
    @@ -70,34 +76,34 @@
     <div id="mygraph"></div>
     
     <script type="text/javascript">
    -    // create an array with nodes
    -    var nodes = [
    -        {id: 1, label: 'Node 1'},
    -        {id: 2, label: 'Node 2'},
    -        {id: 3, label: 'Node 3'},
    -        {id: 4, label: 'Node 4'},
    -        {id: 5, label: 'Node 5'}
    -    ];
    -
    -    // create an array with edges
    -    var edges = [
    -        {from: 1, to: 2},
    -        {from: 1, to: 3},
    -        {from: 2, to: 4},
    -        {from: 2, to: 5}
    -    ];
    -
    -    // create a graph
    -    var container = document.getElementById('mygraph');
    -    var data= {
    -        nodes: nodes,
    -        edges: edges,
    -    };
    -    var options = {
    -        width: '400px',
    -        height: '400px'
    -    };
    -    var graph = new vis.Graph(container, data, options);
    +  // create an array with nodes
    +  var nodes = [
    +    {id: 1, label: 'Node 1'},
    +    {id: 2, label: 'Node 2'},
    +    {id: 3, label: 'Node 3'},
    +    {id: 4, label: 'Node 4'},
    +    {id: 5, label: 'Node 5'}
    +  ];
    +
    +  // create an array with edges
    +  var edges = [
    +    {from: 1, to: 2},
    +    {from: 1, to: 3},
    +    {from: 2, to: 4},
    +    {from: 2, to: 5}
    +  ];
    +
    +  // create a graph
    +  var container = document.getElementById('mygraph');
    +  var data= {
    +    nodes: nodes,
    +    edges: edges,
    +  };
    +  var options = {
    +    width: '400px',
    +    height: '400px'
    +  };
    +  var graph = new vis.Graph(container, data, options);
     </script>
     
     </body>
    @@ -107,12 +113,12 @@
     
     

    Loading

    - Install or download the vis.js library. - in a subfolder of your project. Include the library script in the head of your html code: + Install or download the vis.js library. + in a subfolder of your project. Include the library script in the head of your html code:

    -<script type="text/javascript" src="vis/vis.js"></script>
    +<script type="text/javascript" src="vis/dist/vis.js"></script>
     
    @@ -121,278 +127,278 @@ The constructor of the Graph is vis.Graph. The constructor accepts three parameters:
      -
    • - container is the DOM element in which to create the graph. -
    • -
    • - data is an Object containing properties nodes and - edges, which both contain an array with objects. - Optionally, data may contain an options object. - The parameter data is optional, data can also be set using - the method setData. Section Data Format - describes the data object. -
    • -
    • - options is an optional Object containing a name-value map - with options. Options can also be set using the method - setOptions. - Section Configuration Options - describes the available options. -
    • +
    • + container is the DOM element in which to create the graph. +
    • +
    • + data is an Object containing properties nodes and + edges, which both contain an array with objects. + Optionally, data may contain an options object. + The parameter data is optional, data can also be set using + the method setData. Section Data Format + describes the data object. +
    • +
    • + options is an optional Object containing a name-value map + with options. Options can also be set using the method + setOptions. + Section Configuration Options + describes the available options. +

    Data Format

    - The data parameter of the Graph constructor is an object - which can contain different types of data. - The following properties are supported in the data object: + The data parameter of the Graph constructor is an object + which can contain different types of data. + The following properties are supported in the data object:

      -
    • - A property pair nodes and edges, - both containing an Array with objects. The data formats are described - in the sections Nodes and Edges. - Example: +
    • + A property pair nodes and edges, + both containing an Array with objects. The data formats are described + in the sections Nodes and Edges. + Example:
       var data = {
      -    nodes: [...],
      -    edges: [...]
      +  nodes: [...],
      +  edges: [...]
       };
       
      -
    • -
    • - A property dot, - containing a string with data in the - DOT language. - DOT support is described in section DOT_language. - - Example: +
    • +
    • + A property dot, + containing a string with data in the + DOT language. + DOT support is described in section DOT_language. + + Example:
       var data = {
      -    dot: '...'
      +  dot: '...'
       };
       
      -
    • -
    • - A property options, - containing an object with global options. - Options can be provided as third parameter in the graph constructor - as well. Section Configuration Options - describes the available options. - -
    • + +
    • + A property options, + containing an object with global options. + Options can be provided as third parameter in the graph constructor + as well. Section Configuration Options + describes the available options. + +

    Nodes

    - Nodes typically have an id and label. - A node must contain at least a property id. - Nodes can have extra properties, used to define the shape and style of the - nodes. + Nodes typically have an id and label. + A node must contain at least a property id. + Nodes can have extra properties, used to define the shape and style of the + nodes.

    - A JavaScript Array with nodes is constructed like: + A JavaScript Array with nodes is constructed like:

     var nodes = [
    -    {
    -        id: 1,
    -        label: 'Node 1'
    -    },
    -    // ... more nodes
    +  {
    +    id: 1,
    +    label: 'Node 1'
    +  },
    +  // ... more nodes
     ];
     

    - Nodes support the following properties: + Nodes support the following properties:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeRequiredDescription
    colorString | ObjectnoColor for the node.
    color.backgroundStringnoBackground color for the node.
    color.borderStringnoBorder color for the node.
    color.highlightString | ObjectnoColor of the node when selected.
    color.highlight.backgroundStringnoBackground color of the node when selected.
    color.highlight.borderStringnoBorder color of the node when selected.
    groupNumber | StringnoA group number or name. The type can be number, - string, or an other type. All nodes with the same group get - the same color schema.
    fontColorStringnoFont color for label in the node.
    fontFaceStringnoFont face for label in the node, for example "verdana" or "arial".
    fontSizeNumbernoFont size in pixels for label in the node.
    idNumber | StringyesA unique id for this node. - Nodes may not have duplicate id's. - Id's do not need to be consecutive. - An id is normally a number, but may be any type.
    imagestringnoUrl of an image. Only applicable when the shape of the node is - image.
    radiusnumbernoRadius for the node. Applicable for all shapes except box, - circle, ellipse and database. - The value of radius will override a value in - property value.
    shapestringnoDefine the shape for the node. - Choose from - ellipse (default), circle, box, - database, image, label, dot, - star, triangle, triangleDown, and square. -

    - - In case of image, a property with name image must - be provided, containing image urls. -

    - - The shapes dot, star, triangle, - triangleDown, and square, are scalable. - The size is determined by the properties radius or - value. -

    - - When a property label is provided, - this label will be displayed inside the shape in case of shapes - box, circle, ellipse, - and database. - For all other shapes, the label will be displayed right below the shape. - -
    labelstringnoText label to be displayed in the node or under the image of the node. - Multiple lines can be separated by a newline character \n .
    titlestringnoTitle to be displayed when the user hovers over the node. - The title can contain HTML code.
    valuenumbernoA value for the node. - The radius of the nodes will be scaled automatically from minimum to - maximum value. - Only applicable when the shape of the node is dot. - If a radius is provided for the node too, it will override the - radius calculated from the value.
    xnumbernoHorizontal position in pixels. - The horizontal position of the node will be fixed. - The vertical position y may remain undefined.
    ynumbernoVertical position in pixels. - The vertical position of the node will be fixed. - The horizontal position x may remain undefined.
    NameTypeRequiredDescription
    colorString | ObjectnoColor for the node.
    color.backgroundStringnoBackground color for the node.
    color.borderStringnoBorder color for the node.
    color.highlightString | ObjectnoColor of the node when selected.
    color.highlight.backgroundStringnoBackground color of the node when selected.
    color.highlight.borderStringnoBorder color of the node when selected.
    groupNumber | StringnoA group number or name. The type can be number, + string, or an other type. All nodes with the same group get + the same color schema.
    fontColorStringnoFont color for label in the node.
    fontFaceStringnoFont face for label in the node, for example "verdana" or "arial".
    fontSizeNumbernoFont size in pixels for label in the node.
    idNumber | StringyesA unique id for this node. + Nodes may not have duplicate id's. + Id's do not need to be consecutive. + An id is normally a number, but may be any type.
    imagestringnoUrl of an image. Only applicable when the shape of the node is + image.
    radiusnumbernoRadius for the node. Applicable for all shapes except box, + circle, ellipse and database. + The value of radius will override a value in + property value.
    shapestringnoDefine the shape for the node. + Choose from + ellipse (default), circle, box, + database, image, label, dot, + star, triangle, triangleDown, and square. +

    + + In case of image, a property with name image must + be provided, containing image urls. +

    + + The shapes dot, star, triangle, + triangleDown, and square, are scalable. + The size is determined by the properties radius or + value. +

    + + When a property label is provided, + this label will be displayed inside the shape in case of shapes + box, circle, ellipse, + and database. + For all other shapes, the label will be displayed right below the shape. + +
    labelstringnoText label to be displayed in the node or under the image of the node. + Multiple lines can be separated by a newline character \n .
    titlestringnoTitle to be displayed when the user hovers over the node. + The title can contain HTML code.
    valuenumbernoA value for the node. + The radius of the nodes will be scaled automatically from minimum to + maximum value. + Only applicable when the shape of the node is dot. + If a radius is provided for the node too, it will override the + radius calculated from the value.
    xnumbernoHorizontal position in pixels. + The horizontal position of the node will be fixed. + The vertical position y may remain undefined.
    ynumbernoVertical position in pixels. + The vertical position of the node will be fixed. + The horizontal position x may remain undefined.
    @@ -400,176 +406,176 @@ var nodes = [

    Edges

    - Edges are connections between nodes. - An edge must at least contain properties from and - to, both referring to the id of a node. - Edges can have extra properties, used to define the type and style. + Edges are connections between nodes. + An edge must at least contain properties from and + to, both referring to the id of a node. + Edges can have extra properties, used to define the type and style.

    - A JavaScript Array with edges is constructed as: + A JavaScript Array with edges is constructed as:

     var edges = [
    -    {
    -        from: 1,
    -        to: 3
    -    },
    -    // ... more edges
    +  {
    +    from: 1,
    +    to: 3
    +  },
    +  // ... more edges
     ];
     

    - Edges support the following properties: + Edges support the following properties:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeRequiredDescription
    colorstringnoA HTML color for the edge.
    dashObjectno - Object containing properties for dashed lines. - Available properties: length, gap, - altLength. -
    dash.altLengthnumbernoLength of the alternated dash in pixels on a dashed line. - Specifying dash.altLength allows for creating - a dashed line with a dash-dot style, for example when - dash.length=10 and dash.altLength=5. - See also the option dahs.length. - Only applicable when the line style is dash-line.
    dash.lengthnumbernoLength of a dash in pixels on a dashed line. - Only applicable when the line style is dash-line.
    dash.gapnumbernoLength of a gap in pixels on a dashed line. - Only applicable when the line style is dash-line.
    fontColorStringnoFont color for the text label of the edge. - Only applicable when property label is defined.
    fontFaceStringnoFont face for the text label of the edge, - for example "verdana" or "arial". - Only applicable when property label is defined.
    fontSizeNumbernoFont size in pixels for the text label of the edge. - Only applicable when property label is defined.
    fromNumber | StringyesThe id of a node where the edge starts. The type must correspond with - the type of the node id's. This is normally a number, but can be any - type.
    lengthnumbernoThe length of the edge in pixels.
    stylestringnoDefine a line style for the edge. - Choose from line (default), arrow, - arrow-center, or dash-line. -
    labelstringnoText label to be displayed halfway the edge.
    titlestringnoTitle to be displayed when the user hovers over the edge. - The title can contain HTML code.
    toNumber | StringyesThe id of a node where the edge ends. The type must correspond with - the type of the node id's. This is normally a number, but can be any - type.
    valuenumbernoA value for the edge. - The width of the edges will be scaled automatically from minimum to - maximum value. - If a width is provided for the edge too, it will override the - width calculated from the value.
    widthnumbernoWidth of the line in pixels. The width will - override a specified value, if a value is - specified too.
    NameTypeRequiredDescription
    colorstringnoA HTML color for the edge.
    dashObjectno + Object containing properties for dashed lines. + Available properties: length, gap, + altLength. +
    dash.altLengthnumbernoLength of the alternated dash in pixels on a dashed line. + Specifying dash.altLength allows for creating + a dashed line with a dash-dot style, for example when + dash.length=10 and dash.altLength=5. + See also the option dahs.length. + Only applicable when the line style is dash-line.
    dash.lengthnumbernoLength of a dash in pixels on a dashed line. + Only applicable when the line style is dash-line.
    dash.gapnumbernoLength of a gap in pixels on a dashed line. + Only applicable when the line style is dash-line.
    fontColorStringnoFont color for the text label of the edge. + Only applicable when property label is defined.
    fontFaceStringnoFont face for the text label of the edge, + for example "verdana" or "arial". + Only applicable when property label is defined.
    fontSizeNumbernoFont size in pixels for the text label of the edge. + Only applicable when property label is defined.
    fromNumber | StringyesThe id of a node where the edge starts. The type must correspond with + the type of the node id's. This is normally a number, but can be any + type.
    lengthnumbernoThe length of the edge in pixels.
    stylestringnoDefine a line style for the edge. + Choose from line (default), arrow, + arrow-center, or dash-line. +
    labelstringnoText label to be displayed halfway the edge.
    titlestringnoTitle to be displayed when the user hovers over the edge. + The title can contain HTML code.
    toNumber | StringyesThe id of a node where the edge ends. The type must correspond with + the type of the node id's. This is normally a number, but can be any + type.
    valuenumbernoA value for the edge. + The width of the edges will be scaled automatically from minimum to + maximum value. + If a width is provided for the edge too, it will override the + width calculated from the value.
    widthnumbernoWidth of the line in pixels. The width will + override a specified value, if a value is + specified too.
    @@ -577,20 +583,20 @@ var edges = [

    DOT language

    - Graph supports data in the - DOT language. - To provide data in the DOT language, the data object must contain - a property dot with a String containing the data. + Graph supports data in the + DOT language. + To provide data in the DOT language, the data object must contain + a property dot with a String containing the data.

    - Example usage: + Example usage:

     // provide data in the DOT language
     var data = {
    -    dot: 'digraph {1 -> 1 -> 2; 2 -> 3; 2 -- 4; 2 -> 1 }'
    +  dot: 'digraph {1 -> 1 -> 2; 2 -> 3; 2 -- 4; 2 -> 1 }'
     };
     
     // create a graph
    @@ -602,252 +608,252 @@ var graph = new vis.Graph(container, data);
     

    Configuration Options

    - Options can be used to customize the graph. Options are defined as a JSON object. - All options are optional. + Options can be used to customize the graph. Options are defined as a JSON object. + All options are optional.

     var options = {
    -    width:  '100%',
    -    height: '400px',
    -    edges: {
    -        color: 'red',
    -        width: 2
    -    }
    +  width:  '100%',
    +  height: '400px',
    +  edges: {
    +    color: 'red',
    +    width: 2
    +  }
     };
     

    - The following options are available. + The following options are available.

    - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + - - - - + + + + - - - - + + + + - - - - + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + +
    NameTypeDefaultDescriptionNameTypeDefaultDescription
    edges.colorString"#2B7CE9"The default color of a edge.edges.colorString"#2B7CE9"The default color of a edge.
    edges.dashObjectObject - Object containing default properties for dashed lines. - Available properties: length, gap, - altLength. - edges.dashObjectObject + Object containing default properties for dashed lines. + Available properties: length, gap, + altLength. +
    edges.dash.altLengthnumbernoneDefault length of the alternated dash in pixels on a dashed line. - Specifying dash.altLength allows for creating - a dashed line with a dash-dot style, for example when - dash.length=10 and dash.altLength=5. - See also the option dahs.length. - Only applicable when the line style is dash-line.edges.dash.altLengthnumbernoneDefault length of the alternated dash in pixels on a dashed line. + Specifying dash.altLength allows for creating + a dashed line with a dash-dot style, for example when + dash.length=10 and dash.altLength=5. + See also the option dahs.length. + Only applicable when the line style is dash-line.
    edges.dash.lengthnumber10Default length of a dash in pixels on a dashed line. - Only applicable when the line style is dash-line.edges.dash.lengthnumber10Default length of a dash in pixels on a dashed line. + Only applicable when the line style is dash-line.
    edges.dash.gapnumber5Default length of a gap in pixels on a dashed line. - Only applicable when the line style is dash-line.edges.dash.gapnumber5Default length of a gap in pixels on a dashed line. + Only applicable when the line style is dash-line.
    edges.lengthNumber100The default length of a edge.edges.lengthNumber100The default length of a edge.
    edges.styleString"line"The default style of a edge. - Choose from line (default), arrow, - arrow-center, dash-line.edges.styleString"line"The default style of a edge. + Choose from line (default), arrow, + arrow-center, dash-line.
    edges.widthNumber1The default width of a edge.edges.widthNumber1The default width of a edge.
    groupsObjectnoneIt is possible to specify custom styles for groups. - Each node assigned a group gets the specified style. - See Groups for an overview of the available styles - and an example. - groupsObjectnoneIt is possible to specify custom styles for groups. + Each node assigned a group gets the specified style. + See Groups for an overview of the available styles + and an example. +
    heightString"400px"The height of the graph in pixels or as a percentage.heightString"400px"The height of the graph in pixels or as a percentage.
    nodes.colorString | ObjectObjectDefault color of the nodes. When color is a string, the color is applied + nodes.colorString | ObjectObjectDefault color of the nodes. When color is a string, the color is applied to both background as well as the border of the node.
    nodes.color.backgroundString"#97C2FC"Default background color of the nodesnodes.color.backgroundString"#97C2FC"Default background color of the nodes
    nodes.color.borderString"#2B7CE9"Default border color of the nodesnodes.color.borderString"#2B7CE9"Default border color of the nodes
    nodes.color.highlightString | ObjectObjectDefault color of the node when the node is selected. Applied to + nodes.color.highlightString | ObjectObjectDefault color of the node when the node is selected. Applied to both border and background of the node.
    nodes.color.highlight.backgroundString"#D2E5FF"Default background color of the node when selected.nodes.color.highlight.backgroundString"#D2E5FF"Default background color of the node when selected.
    nodes.color.highlight.borderString"#2B7CE9"Default border color of the node when selected.nodes.color.highlight.borderString"#2B7CE9"Default border color of the node when selected.
    nodes.fontColorString"black"Default font color for the text label in the nodes.nodes.fontColorString"black"Default font color for the text label in the nodes.
    nodes.fontFaceString"sans"Default font face for the text label in the nodes, for example "verdana" or "arial".nodes.fontFaceString"sans"Default font face for the text label in the nodes, for example "verdana" or "arial".
    nodes.fontSizeNumber14Default font size in pixels for the text label in the nodes.nodes.fontSizeNumber14Default font size in pixels for the text label in the nodes.
    nodes.groupStringnoneDefault group for the nodes.nodes.groupStringnoneDefault group for the nodes.
    nodes.imageStringnoneDefault image url for the nodes. only applicable with shape image.nodes.imageStringnoneDefault image url for the nodes. only applicable with shape image.
    nodes.widthMinNumber16The minimum width for a scaled image. Only applicable with shape image.nodes.widthMinNumber16The minimum width for a scaled image. Only applicable with shape image.
    nodes.widthMaxNumber64The maximum width for a scaled image. Only applicable with shape image.nodes.widthMaxNumber64The maximum width for a scaled image. Only applicable with shape image.
    nodes.shapeString"ellipse"The default shape for all nodes. - Choose from - ellipse (default), circle, box, - database, image, label, dot, - star, triangle, triangleDown, and square. - This shape can be overridden by a group shape, or by a shape of an individual node.nodes.shapeString"ellipse"The default shape for all nodes. + Choose from + ellipse (default), circle, box, + database, image, label, dot, + star, triangle, triangleDown, and square. + This shape can be overridden by a group shape, or by a shape of an individual node.
    nodes.radiusNumber5The default radius for a node. Only applicable with shape dot.nodes.radiusNumber5The default radius for a node. Only applicable with shape dot.
    nodes.radiusMinNumber5The minimum radius for a scaled node. Only applicable with shape dot.nodes.radiusMinNumber5The minimum radius for a scaled node. Only applicable with shape dot.
    nodes.radiusMaxNumber20The maximum radius for a scaled node. Only applicable with shape dot.nodes.radiusMaxNumber20The maximum radius for a scaled node. Only applicable with shape dot.
    selectableBooleantrueIf true, nodes in the graph can be selected by clicking them. - Long press can be used to select multiple nodes.selectableBooleantrueIf true, nodes in the graph can be selected by clicking them. + Long press can be used to select multiple nodes.
    stabilizeBooleantrueIf true, the graph is stabilized before displaying it. If false, - the nodes move to a stabe position visibly in an animated way.stabilizeBooleantrueIf true, the graph is stabilized before displaying it. If false, + the nodes move to a stabe position visibly in an animated way.
    widthString"400px"The width of the graph in pixels or as a percentage.widthString"400px"The width of the graph in pixels or as a percentage.
    @@ -857,254 +863,254 @@ var options = {

    Groups

    It is possible to specify custom styles for groups of nodes. - Each node having assigned to this group gets the specified style. - The options groups is an object containing one or multiple groups, - identified by a unique string, the groupname. + Each node having assigned to this group gets the specified style. + The options groups is an object containing one or multiple groups, + identified by a unique string, the groupname.

    - A group can have the following styles: + A group can have the following styles:

     var options = {
    -    // ...
    -
    -    groups: {
    -        mygroup: {
    -            shape: 'circle',
    -            color: {
    -                border: 'black',
    -                background: 'white',
    -                highlight: {
    -                    border: 'yellow',
    -                    background: 'orange'
    -                }
    -            }
    -            fontColor: 'red',
    -            fontSize: 18
    +  // ...
    +
    +  groups: {
    +    mygroup: {
    +      shape: 'circle',
    +      color: {
    +        border: 'black',
    +        background: 'white',
    +        highlight: {
    +          border: 'yellow',
    +          background: 'orange'
             }
    -        // add more groups here
    +      }
    +      fontColor: 'red',
    +      fontSize: 18
         }
    +    // add more groups here
    +  }
     };
     
     var nodes = [
    -    {id: 1, label: 'Node 1'},                    // will get the default style
    -    {id: 2, label: 'Node 2', group: 'mygroup'},  // will get the style from 'mygroup'
    -    // ... more nodes
    +  {id: 1, label: 'Node 1'},                    // will get the default style
    +  {id: 2, label: 'Node 2', group: 'mygroup'},  // will get the style from 'mygroup'
    +  // ... more nodes
     ];
     

    The following styles are available for groups:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDefaultDescription
    colorString | ObjectObjectColor of the node
    color.borderString"#2B7CE9"Border color of the node
    color.backgroundString"#97C2FC"Background color of the node
    color.highlightString"#D2E5FF"Color of the node when selected.
    color.highlight.backgroundString"#D2E5FF"Background color of the node when selected.
    color.highlight.borderString"#D2E5FF"Border color of the node when selected.
    imageStringnoneDefault image for the nodes. Only applicable in combination with - shape image.
    fontColorString"black"Font color of the node.
    fontFaceString"sans"Font name of the node, for example "verdana" or "arial".
    fontSizeNumber14Font size for the node in pixels.
    shapeString"ellipse"Choose from - ellipse (default), circle, box, - database, image, label, dot, - star, triangle, triangleDown, and square. - In case of image, a property with name image must be provided, containing - image urls.
    radiusNumber5Default radius for the node. Only applicable in combination with - shapes box and dot.
    NameTypeDefaultDescription
    colorString | ObjectObjectColor of the node
    color.borderString"#2B7CE9"Border color of the node
    color.backgroundString"#97C2FC"Background color of the node
    color.highlightString"#D2E5FF"Color of the node when selected.
    color.highlight.backgroundString"#D2E5FF"Background color of the node when selected.
    color.highlight.borderString"#D2E5FF"Border color of the node when selected.
    imageStringnoneDefault image for the nodes. Only applicable in combination with + shape image.
    fontColorString"black"Font color of the node.
    fontFaceString"sans"Font name of the node, for example "verdana" or "arial".
    fontSizeNumber14Font size for the node in pixels.
    shapeString"ellipse"Choose from + ellipse (default), circle, box, + database, image, label, dot, + star, triangle, triangleDown, and square. + In case of image, a property with name image must be provided, containing + image urls.
    radiusNumber5Default radius for the node. Only applicable in combination with + shapes box and dot.

    Methods

    - Graph supports the following methods. + Graph supports the following methods.

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    MethodReturn TypeDescription
    setData(data)noneLoads data. Parameter data is an object containing - nodes, edges, and options. Parameters nodes, edges are an Array. - Options is a name-value map and is optional. -
    setOptions(options)noneSet options for the graph. The available options are described in - the section Configuration Options. -
    getSelection()Array of idsReturns an array with the ids of the selected nodes. - Returns an empty array if no nodes are selected. - The selections are not ordered. -
    redraw()noneRedraw the graph. Useful when the layout of the webpage changed.
    setSelection(selection)noneSelect nodes. - selection is an array with ids of nodes to be selected. - The array selection can contain zero or multiple ids. - Example usage: graph.setSelection([3, 5]); will select - nodes with id 3 and 5. -
    setSize(width, height)noneParameters width and height are strings, - containing a new size for the visualization. Size can be provided in pixels - or in percentages.
    MethodReturn TypeDescription
    setData(data)noneLoads data. Parameter data is an object containing + nodes, edges, and options. Parameters nodes, edges are an Array. + Options is a name-value map and is optional. +
    setOptions(options)noneSet options for the graph. The available options are described in + the section Configuration Options. +
    getSelection()Array of idsReturns an array with the ids of the selected nodes. + Returns an empty array if no nodes are selected. + The selections are not ordered. +
    redraw()noneRedraw the graph. Useful when the layout of the webpage changed.
    setSelection(selection)noneSelect nodes. + selection is an array with ids of nodes to be selected. + The array selection can contain zero or multiple ids. + Example usage: graph.setSelection([3, 5]); will select + nodes with id 3 and 5. +
    setSize(width, height)noneParameters width and height are strings, + containing a new size for the visualization. Size can be provided in pixels + or in percentages.

    Events

    - Graph fires events after one or multiple nodes are selected. - The event can be catched by creating a listener. + Graph fires events after one or multiple nodes are selected. + The event can be catched by creating a listener.

    - Here an example on how to catch a select event. + Here an example on how to catch a select event.

     function onSelect() {
    -    alert('selected nodes: ' + graph.getSelection());
    +  alert('selected nodes: ' + graph.getSelection());
     }
     
     vis.events.addListener(graph, 'select', onSelect);
     

    - The following events are available. + The following events are available.

    - - - - - - - - - - - - - - - + + + + + + + + + + + + + + +
    nameDescriptionProperties
    selectFired after the user selects or unselects a node by clicking it, - or when selecting a number of nodes by dragging a selection area - around them. Not fired when the method setSelection - is executed. The ids of the selected nodes can be retrieved via the - method getSelection. - none
    nameDescriptionProperties
    selectFired after the user selects or unselects a node by clicking it, + or when selecting a number of nodes by dragging a selection area + around them. Not fired when the method setSelection + is executed. The ids of the selected nodes can be retrieved via the + method getSelection. + none

    Data Policy

    - All code and data is processed and rendered in the browser. - No data is sent to any server. + All code and data is processed and rendered in the browser. + No data is sent to any server.

    diff --git a/docs/index.html b/docs/index.html index 6f907a0f..bbaf818b 100644 --- a/docs/index.html +++ b/docs/index.html @@ -2,201 +2,204 @@ - vis.js | documentation + vis.js | documentation - - + + - +
    -

    vis.js documentation

    - -

    - Vis.js is a dynamic, browser based visualization library. - The library is designed to be easy to use, handle large amounts - of dynamic data, and enable manipulation of the data. -

    - -

    - The library is developed by - Almende B.V. -

    - -

    Components

    - -

    - Vis.js contains of the following components: -

    - -
      -
    • - DataSet. - A flexible key/value based data set. - Add, update, and remove items. Subscribe on changes in the data set. - A DataSet can filter and order items, and convert fields of items. -
    • -
    • - DataView. - A filtered and/or formatted view on a DataSet. -
    • -
    • - Graph. - Display a graph or network with nodes and edges. -
    • -
    • - Timeline. - Display different types of data on a timeline. The timeline and the - items on the timeline can be interactively moved, zoomed, and - manipulated. -
    • -
    - - - - -

    Install

    - -

    npm

    +

    vis.js documentation

    + +

    + Vis.js is a dynamic, browser based visualization library. + The library is designed to be easy to use, handle large amounts + of dynamic data, and enable manipulation of the data. +

    + +

    + The library is developed by + Almende B.V. +

    + +

    Components

    + +

    + Vis.js contains of the following components: +

    + +
      +
    • + DataSet. + A flexible key/value based data set. + Add, update, and remove items. Subscribe on changes in the data set. + A DataSet can filter and order items, and convert fields of items. +
    • +
    • + DataView. + A filtered and/or formatted view on a DataSet. +
    • +
    • + Graph. + Display a graph or network with nodes and edges. +
    • +
    • + Timeline. + Display different types of data on a timeline. The timeline and the + items on the timeline can be interactively moved, zoomed, and + manipulated. +
    • +
    + + + + +

    Install

    + +

    npm

     npm install vis
     
    -

    bower

    +

    bower

     bower install vis
     
    -

    download

    - Download the library from the website: - http://visjs.org. +

    download

    + Download the library from the website: + http://visjs.org. -

    Load

    +

    Load

    -

    - To use a component, include the javascript file of vis in your web page: -

    +

    + To load vis.js, include the javascript and css files of vis in your web page: +

    <!DOCTYPE HTML>
     <html>
     <head>
    -    <script src="components/vis/vis.js"></script>
    +  <script src="components/vis/vis.js"></script>
    +  <link href="components/vis/vis.css" rel="stylesheet" type="text/css" />
     </head>
     <body>
     <script type="text/javascript">
    -    // ... load a visualization
    +  // ... load a visualization
     </script>
     </body>
     </html>
     
    -

    - or load vis.js using require.js: -

    +

    + or load vis.js using require.js: +

     require.config({
    -    paths: {
    -        vis: 'path/to/vis',
    -    }
    +  paths: {
    +    vis: 'path/to/vis',
    +  }
     });
     
     require(['vis'], function (math) {
    -    // ... load a visualization
    +  // ... load a visualization
     });
     
    -

    - A timeline can be instantiated as follows. Other components can be - created in a similar way. -

    +

    + A timeline can be instantiated as follows. Other components can be + created in a similar way. +

     var timeline = new vis.Timeline(container, data, options);
     
    -

    - Where container is an HTML element, data is - an Array with data or a DataSet, and options is an optional - object with configuration options for the component. -

    +

    + Where container is an HTML element, data is + an Array with data or a DataSet, and options is an optional + object with configuration options for the component. +

    -

    Use

    +

    Use

    -

    +

    A basic example on using a Timeline is shown below. More examples can be found in the examples directory of the project. -

    + target="_blank">examples directory of the project. +

     <!DOCTYPE HTML>
     <html>
     <head>
    -    <title>Timeline basic demo</title>
    -    <script src="components/vis/vis.js"></script>
    -
    -    <style type="text/css">
    -        body, html {
    -            font-family: sans-serif;
    -        }
    -    </style>
    +  <title>Timeline basic demo</title>
    +
    +  <script src="components/vis/vis.js"></script>
    +  <link href="components/vis/vis.css" rel="stylesheet" type="text/css" />
    +
    +  <style type="text/css">
    +    body, html {
    +      font-family: sans-serif;
    +    }
    +  </style>
     </head>
     <body>
     <div id="visualization"></div>
     
     <script type="text/javascript">
    -    var container = document.getElementById('visualization');
    -    var data = [
    -        {id: 1, content: 'item 1', start: '2013-04-20'},
    -        {id: 2, content: 'item 2', start: '2013-04-14'},
    -        {id: 3, content: 'item 3', start: '2013-04-18'},
    -        {id: 4, content: 'item 4', start: '2013-04-16', end: '2013-04-19'},
    -        {id: 5, content: 'item 5', start: '2013-04-25'},
    -        {id: 6, content: 'item 6', start: '2013-04-27'}
    -    ];
    -    var options = {};
    -    var timeline = new vis.Timeline(container, data, options);
    +  var container = document.getElementById('visualization');
    +  var data = [
    +    {id: 1, content: 'item 1', start: '2013-04-20'},
    +    {id: 2, content: 'item 2', start: '2013-04-14'},
    +    {id: 3, content: 'item 3', start: '2013-04-18'},
    +    {id: 4, content: 'item 4', start: '2013-04-16', end: '2013-04-19'},
    +    {id: 5, content: 'item 5', start: '2013-04-25'},
    +    {id: 6, content: 'item 6', start: '2013-04-27'}
    +  ];
    +  var options = {};
    +  var timeline = new vis.Timeline(container, data, options);
     </script>
     </body>
     </html>
     
    -

    License

    +

    License

    -

    - Copyright (C) 2010-2013 Almende B.V. -

    +

    + Copyright (C) 2010-2013 Almende B.V. +

    -

    - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at -

    +

    + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at +

    -

    - http://www.apache.org/licenses/LICENSE-2.0 -

    +

    + http://www.apache.org/licenses/LICENSE-2.0 +

    -

    - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -

    +

    + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +

    diff --git a/docs/timeline.html b/docs/timeline.html index 4bdd9ee7..c2335c60 100644 --- a/docs/timeline.html +++ b/docs/timeline.html @@ -1,12 +1,12 @@ - vis.js | timeline documentation + vis.js | timeline documentation - - + + - + @@ -17,65 +17,66 @@

    Contents

    Overview

    - The Timeline is an interactive visualization chart to visualize data in time. - The data items can take place on a single date, or have a start and end date (a range). - You can freely move and zoom in the timeline by dragging and scrolling in the - Timeline. Items can be created, edited, and deleted in the timeline. - The time scale on the axis is adjusted automatically, and supports scales ranging - from milliseconds to years. + The Timeline is an interactive visualization chart to visualize data in time. + The data items can take place on a single date, or have a start and end date (a range). + You can freely move and zoom in the timeline by dragging and scrolling in the + Timeline. Items can be created, edited, and deleted in the timeline. + The time scale on the axis is adjusted automatically, and supports scales ranging + from milliseconds to years.

    Example

    - The following code shows how to create a Timeline and provide it with data. - More examples can be found in the examples directory. + The following code shows how to create a Timeline and provide it with data. + More examples can be found in the examples directory.

    <!DOCTYPE HTML>
     <html>
     <head>
    -    <title>Timeline | Basic demo</title>
    +  <title>Timeline | Basic demo</title>
     
    -    <style type="text/css">
    -        body, html {
    -            font-family: sans-serif;
    -        }
    -    </style>
    +  <style type="text/css">
    +    body, html {
    +      font-family: sans-serif;
    +    }
    +  </style>
     
    -    <script src="../../vis.js"></script>
    +  <script src="../../dist/vis.js"></script>
    +  <link href="../../dist/vis.css" rel="stylesheet" type="text/css" />
     </head>
     <body>
     <div id="visualization"></div>
     
     <script type="text/javascript">
    -    var container = document.getElementById('visualization');
    -    var items = [
    -        {id: 1, content: 'item 1', start: '2013-04-20'},
    -        {id: 2, content: 'item 2', start: '2013-04-14'},
    -        {id: 3, content: 'item 3', start: '2013-04-18'},
    -        {id: 4, content: 'item 4', start: '2013-04-16', end: '2013-04-19'},
    -        {id: 5, content: 'item 5', start: '2013-04-25'},
    -        {id: 6, content: 'item 6', start: '2013-04-27'}
    -    ];
    -    var options = {};
    -    var timeline = new vis.Timeline(container, items, options);
    +  var container = document.getElementById('visualization');
    +  var items = [
    +    {id: 1, content: 'item 1', start: '2013-04-20'},
    +    {id: 2, content: 'item 2', start: '2013-04-14'},
    +    {id: 3, content: 'item 3', start: '2013-04-18'},
    +    {id: 4, content: 'item 4', start: '2013-04-16', end: '2013-04-19'},
    +    {id: 5, content: 'item 5', start: '2013-04-25'},
    +    {id: 6, content: 'item 6', start: '2013-04-27'}
    +  ];
    +  var options = {};
    +  var timeline = new vis.Timeline(container, items, options);
     </script>
     </body>
     </html>
    @@ -84,12 +85,14 @@
     
     

    Loading

    - Install or download the vis.js library. - in a subfolder of your project. Include the library script in the head of your html code: + Install or download the vis.js library. + in a subfolder of your project. Include the libraries script and css files in the + head of your html code:

    -<script type="text/javascript" src="vis/vis.js"></script>
    +<script src="vis/dist/vis.js"></script>
    +<link href="vis/dist/vis.css" rel="stylesheet" type="text/css" />
     
    The constructor of the Timeline is vis.Timeline @@ -98,197 +101,199 @@ The constructor of the Timeline is vis.Timeline The constructor accepts three parameters:
      -
    • - container is the DOM element in which to create the graph. -
    • -
    • - items is an Array containing items. The properties of an - item are described in section Data Format. -
    • -
    • - options is an optional Object containing a name-value map - with options. Options can also be set using the method - setOptions. -
    • +
    • + container is the DOM element in which to create the graph. +
    • +
    • + items is an Array containing items. The properties of an + item are described in section Data Format. +
    • +
    • + options is an optional Object containing a name-value map + with options. Options can also be set using the method + setOptions. +

    Data Format

    - The timeline can be provided with two types of data: + The timeline can be provided with two types of data:

      -
    • Items containing a set of items to be displayed in time.
    • -
    • Groups containing a set of groups used to group items +
    • Items containing a set of items to be displayed in time.
    • +
    • Groups containing a set of groups used to group items together.

    Items

    - The Timeline uses regular Arrays and Objects as data format. - Data items can contain the properties start, - end (optional), content, - group (optional), and className (optional). + The Timeline uses regular Arrays and Objects as data format. + Data items can contain the properties start, + end (optional), content, + group (optional), and className (optional).

    - A table is constructed as: + A table is constructed as:

     var items = [
    -    {
    -        start: new Date(2010, 7, 15),
    -        end: new Date(2010, 8, 2),  // end is optional
    -        content: 'Trajectory A'
    -        // Optional: fields 'id', 'type', 'group', 'className'
    -    }
    -    // more items...
    +  {
    +    start: new Date(2010, 7, 15),
    +    end: new Date(2010, 8, 2),  // end is optional
    +    content: 'Trajectory A'
    +    // Optional: fields 'id', 'type', 'group', 'className'
    +  }
    +  // more items...
     ]);
     

    - The item properties are defined as: + The item properties are defined as:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeRequiredDescription
    idString | NumbernoAn id for the item. Using an id is not required but highly - recommended. An id is needed when dynamically adding, updating, - and removing items in a DataSet.
    startDateyesThe start date of the item, for example new Date(2010,09,23).
    endDatenoThe end date of the item. The end date is optional, and can be left null. - If end date is provided, the item is displayed as a range. - If not, the item is displayed as a box.
    contentStringyesThe contents of the item. This can be plain text or html code.
    typeString'box'The type of the item. Can be 'box' (default), 'range', or 'point'.
    groupany typenoThis field is optional. When the group column is provided, - all items with the same group are placed on one line. - A vertical axis is displayed showing the groups. - Grouping items can be useful for example when showing availability of multiple - people, rooms, or other resources next to each other.
    -
    classNameStringnoThis field is optional. A className can be used to give items - an individual css style. For example, when an item has className - 'red', one can define a css style - - .red { - background-color: red; - border-color: dark-red; - } - . - More details on how to style items can be found in the section - Styles. -
    NameTypeRequiredDescription
    idString | NumbernoAn id for the item. Using an id is not required but highly + recommended. An id is needed when dynamically adding, updating, + and removing items in a DataSet.
    startDateyesThe start date of the item, for example new Date(2010,09,23).
    endDatenoThe end date of the item. The end date is optional, and can be left null. + If end date is provided, the item is displayed as a range. + If not, the item is displayed as a box.
    contentStringyesThe contents of the item. This can be plain text or html code.
    typeString'box'The type of the item. Can be 'box' (default), 'range', or 'point'. + +
    groupany typenoThis field is optional. When the group column is provided, + all items with the same group are placed on one line. + A vertical axis is displayed showing the groups. + Grouping items can be useful for example when showing availability of multiple + people, rooms, or other resources next to each other.
    +
    classNameStringnoThis field is optional. A className can be used to give items + an individual css style. For example, when an item has className + 'red', one can define a css style + + .red { + background-color: red; + border-color: dark-red; + } + . + More details on how to style items can be found in the section + Styles. +

    Groups

    - Like the items, groups are regular JavaScript Arrays and Objects. - Using groups, items can be grouped together. - Items are filtered per group, and displayed as + Like the items, groups are regular JavaScript Arrays and Objects. + Using groups, items can be grouped together. + Items are filtered per group, and displayed as - Group items can contain the properties id, - content, and className (optional). + Group items can contain the properties id, + content, and className (optional).

    - Groups can be applied to a timeline using the method setGroups. - A table with groups can be created like: + Groups can be applied to a timeline using the method setGroups. + A table with groups can be created like:

     var groups = [
    -    {
    -        id: 1,
    -        content: 'Group 1'
    -        // Optional: a field 'className'
    -    }
    -    // more groups...
    +  {
    +    id: 1,
    +    content: 'Group 1'
    +    // Optional: a field 'className'
    +  }
    +  // more groups...
     ]);
     

    - Groups can have the following properties: + Groups can have the following properties:

    - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeRequiredDescription
    idString | NumberyesAn id for the group. The group will display all items having a - property group which matches the id - of the group.
    contentStringyesThe contents of the group. This can be plain text or html code.
    classNameStringnoThis field is optional. A className can be used to give groups - an individual css style. For example, when a group has className - 'red', one can define a css style - - .red { - color: red; - } - . - More details on how to style groups can be found in the section - Styles. -
    NameTypeRequiredDescription
    idString | NumberyesAn id for the group. The group will display all items having a + property group which matches the id + of the group.
    contentStringyesThe contents of the group. This can be plain text or html code.
    classNameStringnoThis field is optional. A className can be used to give groups + an individual css style. For example, when a group has className + 'red', one can define a css style + + .red { + color: red; + } + . + More details on how to style groups can be found in the section + Styles. +
    @@ -296,269 +301,309 @@ var groups = [

    Configuration Options

    - Options can be used to customize the timeline. - Options are defined as a JSON object. All options are optional. + Options can be used to customize the timeline. + Options are defined as a JSON object. All options are optional.

     var options = {
    -    width: '100%',
    -    height: '30px'
    +  width: '100%',
    +  height: '30px'
     };
     

    - The following options are available. + The following options are available.

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDefaultDescription
    alignString"center"Alignment of items with type 'box'. Available values are - 'center' (default), 'left', or 'right').
    autoResizebooleanfalseIf true, the Timeline will automatically detect when its - container is resized, and redraw itself accordingly.
    endDatenoneThe initial end date for the axis of the timeline. - If not provided, the latest date present in the items set is taken as - end date.
    heightStringnoneThe height of the timeline in pixels or as a percentage. - When height is undefined or null, the height of the timeline is automatically - adjusted to fit the contents. - It is possible to set a maximum height using option maxHeight - to prevent the timeline from getting too high in case of automatically - calculated height. -
    margin.axisNumber20The minimal margin in pixels between items and the time axis.
    margin.itemNumber10The minimal margin in pixels between items.
    maxDatenoneSet a maximum Date for the visible range. - It will not be possible to move beyond this maximum. -
    maxHeightNumbernoneSpecifies a maximum height for the Timeline in pixels. -
    minDatenoneSet a minimum Date for the visible range. - It will not be possible to move beyond this minimum. -
    orderfunctionnoneProvide a custom sort function to order the items. The order of the - items is determining the way they are stacked. The function - order is called with two parameters, both of type - `vis.components.items.Item`. -
    orientationString'bottom'Orientation of the timeline: 'top' or 'bottom' (default). - If orientation is 'bottom', the time axis is drawn at the bottom, - and if 'top', the axis is drawn on top.
    paddingNumber5The padding of items, needed to correctly calculate the size - of item ranges. Must correspond with the css of item ranges.
    showMajorLabelsbooleantrueBy default, the timeline shows both minor and major date labels on the - time axis. - For example the minor labels show minutes and the major labels show hours. - When showMajorLabels is false, no major labels - are shown.
    showMinorLabelsbooleantrueBy default, the timeline shows both minor and major date labels on the - time axis. - For example the minor labels show minutes and the major labels show hours. - When showMinorLabels is false, no minor labels - are shown. When both showMajorLabels and - showMinorLabels are false, no horizontal axis will be - visible.
    startDatenoneThe initial start date for the axis of the timeline. - If not provided, the earliest date present in the events is taken as start date.
    typeString'box'Specifies the type for the timeline items. Choose from 'dot' or 'point'. - Note that individual items can override this global type. -
    widthString'100%'The width of the timeline in pixels or as a percentage.
    zoomMaxNumber315360000000000Set a maximum zoom interval for the visible range in milliseconds. - It will not be possible to zoom out further than this maximum. - Default value equals about 10000 years. -
    zoomMinNumber10Set a minimum zoom interval for the visible range in milliseconds. - It will not be possible to zoom in further than this minimum. -
    NameTypeDefaultDescription
    alignString"center"Alignment of items with type 'box'. Available values are + 'center' (default), 'left', or 'right').
    autoResizebooleanfalseIf true, the Timeline will automatically detect when its + container is resized, and redraw itself accordingly.
    endDatenoneThe initial end date for the axis of the timeline. + If not provided, the latest date present in the items set is taken as + end date.
    groupOrderString | FunctionnoneOrder the groups by a field name or custom sort function. + By default, groups are not ordered. +
    heightStringnoneThe height of the timeline in pixels or as a percentage. + When height is undefined or null, the height of the timeline is automatically + adjusted to fit the contents. + It is possible to set a maximum height using option maxHeight + to prevent the timeline from getting too high in case of automatically + calculated height. +
    margin.axisNumber20The minimal margin in pixels between items and the time axis.
    margin.itemNumber10The minimal margin in pixels between items.
    maxDatenoneSet a maximum Date for the visible range. + It will not be possible to move beyond this maximum. +
    maxHeightNumbernoneSpecifies a maximum height for the Timeline in pixels. +
    minDatenoneSet a minimum Date for the visible range. + It will not be possible to move beyond this minimum. +
    orderFunctionnoneProvide a custom sort function to order the items. The order of the + items is determining the way they are stacked. The function + order is called with two parameters, both of type + `vis.components.items.Item`. +
    orientationString'bottom'Orientation of the timeline: 'top' or 'bottom' (default). + If orientation is 'bottom', the time axis is drawn at the bottom, + and if 'top', the axis is drawn on top.
    paddingNumber5The padding of items, needed to correctly calculate the size + of item ranges. Must correspond with the css of item ranges.
    showCurrentTimebooleanfalseShow a vertical bar at the current time.
    showCustomTimebooleanfalseShow a vertical bar displaying a custom time. This line can be dragged by the user. The custom time can be utilized to show a state in the past or in the future. +
    showMajorLabelsbooleantrueBy default, the timeline shows both minor and major date labels on the + time axis. + For example the minor labels show minutes and the major labels show hours. + When showMajorLabels is false, no major labels + are shown.
    showMinorLabelsbooleantrueBy default, the timeline shows both minor and major date labels on the + time axis. + For example the minor labels show minutes and the major labels show hours. + When showMinorLabels is false, no minor labels + are shown. When both showMajorLabels and + showMinorLabels are false, no horizontal axis will be + visible.
    startDatenoneThe initial start date for the axis of the timeline. + If not provided, the earliest date present in the events is taken as start date.
    typeString'box'Specifies the type for the timeline items. Choose from 'dot' or 'point'. + Note that individual items can override this global type. +
    widthString'100%'The width of the timeline in pixels or as a percentage.
    zoomMaxNumber315360000000000Set a maximum zoom interval for the visible range in milliseconds. + It will not be possible to zoom out further than this maximum. + Default value equals about 10000 years. +
    zoomMinNumber10Set a minimum zoom interval for the visible range in milliseconds. + It will not be possible to zoom in further than this minimum. +

    Methods

    - The Timeline supports the following methods. + The Timeline supports the following methods.

    - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    MethodReturn TypeDescription
    setGroups(groups)noneSet a data set with groups for the Timeline. - groups can be an Array with Objects, - a DataSet, or a DataView. For each of the groups, the items of the - timeline are filtered on the property group, which - must correspond with the id of the group. -
    setItems(items)noneSet a data set with items for the Timeline. - items can be an Array with Objects, - a DataSet, or a DataView. -
    setOptions(options)noneSet or update options. It is possible to change any option - of the timeline at any time. You can for example switch orientation - on the fly. -
    MethodReturn TypeDescription
    getCustomTime()DateRetrieve the custom time. Only applicable when the option showCustomTime is true. +
    setCustomTime(time)noneAdjust the custom time bar. Only applicable when the option showCustomTime is true. time is a Date object. +
    setGroups(groups)noneSet a data set with groups for the Timeline. + groups can be an Array with Objects, + a DataSet, or a DataView. For each of the groups, the items of the + timeline are filtered on the property group, which + must correspond with the id of the group. +
    setItems(items)noneSet a data set with items for the Timeline. + items can be an Array with Objects, + a DataSet, or a DataView. +
    setOptions(options)noneSet or update options. It is possible to change any option + of the timeline at any time. You can for example switch orientation + on the fly. +

    Styles

    - All parts of the Timeline have a class name and a default css style. - The styles can be overwritten, which enables full customization of the layout - of the Timeline. + All parts of the Timeline have a class name and a default css style. + The styles can be overwritten, which enables full customization of the layout + of the Timeline.

    For example, to change the border and background color of all items, include the - following code inside the head of your html code or in a separate stylesheet.

    + following code inside the head of your html code or in a separate stylesheet.

    <style>
    -    .graph .item {
    -      border-color: orange;
    -      background-color: yellow;
    -    }
    +  .graph .item {
    +    border-color: orange;
    +    background-color: yellow;
    +  }
     </style>
     

    Data Policy

    - All code and data is processed and rendered in the browser. - No data is sent to any server. + All code and data is processed and rendered in the browser. + No data is sent to any server.

    diff --git a/download/vis.zip b/download/vis.zip new file mode 100644 index 0000000000000000000000000000000000000000..687e8b81a0b7339e38cf01ba138e178b604a5700 GIT binary patch literal 941597 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

    @kYT3AR3>F2juVCv*V%(rHzoC+2?P%RXa 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

    czY*mO3{(6 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%0DZz*S*K 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

    oz^ZM>Z3_ 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

    C9M0*l*)1&vXYY5o{O8ek@|p zXL`_GGK`;dUxdSchyEh?+geA^lCUo-OJBX~MFJKzUIzB?2WEX=-@&#)midQ|QB$Q9 z8OEyY;m_pW9aW$wdZYI^H9XBKjD23r@H=|2p(hfS2d`b{tY4os!jwDe;uIvAXE_%z zjOw^4qA8Y5LqS4vcztwKQJKxxy9t0o?C9w5eZ7)UP*AV{0YcudbDR6Tp*TtL-E9?d z0Y?5;=LwX025o`uGYT(XD=VwGknh#3^z^ntk&zcPXc$%GMS%>i=j{SSKU0t_$3`ig z#qTUN$jnVNmy7| zia#PFacX!*A#3awT1IWcHf_2MjwiWqM%K!;RUcW6mc*Rwd=9f=Vql)!gG(01c@gWzA2Ap?D(|VAs34tN`f|B$Mj(O;XbSH^g0$)Um_4F(f8PoY&7eh z)|=nCzHfIVts}U+kJIB1M7bxWlC*CcWT(LdvV%{H^6x8DGV^kgk%QHponkgOzgZoX zZ4Zdr$FCTxyFZt%_ZHht3M!n9A;j3Y!*EEvyUJKdYbtHBDr31d%i zq%oe5ot2P0E^?a{LYyI7#FGD7bi&zCFt?%BE7l|aMqo4T#%ek~bCuT4b`PU3d57YR z423s>0GKFir!Neea;_T;Sv`C*T94J^lhk0UVnO~x<{Ijo$nuIN++1v}m#}YdC;&I4b9E#I-X;a9l zwg3T9?76%r5H{eNX!Cm5+8Y((wAb(Ud1))NG_|(ov9|WY#f7pyIYy^RMIRjK@WRB$ zxF=&v^a=`s==R0eYp!nbeG8tLh&rAtOKYukSo#5S8^nM`#Ug#80wr_!P_EYw>4Ti# z_HtCA%Ixfvzn~6EFarK}mhjIn*Z&ii`d6EOK6~zrr#&(t_i-r3J{JNUAczU~uQ|Nm zTu`|TO$h+_)B8Wl@_!a8`sv?i#7qJKph6P67Zv4=NB@^!0{n}y6?uDADW9{JOZZ)S zdcU`3ibLP<;j$&ja~P&l8U3tNsAI%vt?j%SgBtw4{Os9U!*fMpyqNU9`4sBPOf&XS zYn&=N6KIM^h4N&ep8i;wXS|8KB{XvKO%$L=3&!$;a@VrQ(TYd-I?S2yQ@fC~*(XVF zG&v1it-~sqM@v8s7O#uJBY#ZIlhKD>dom4`O0JmpD!ZRlIhv;iq$EC{2Ilj>W7z_288zH-OP=b!B8k6qp-&fJ|x35q- z5YD5WU$7`LO_MOY>uj4AYfez%$|tn_97JWD(@}AMAALTQ{c`wrl%)+BSU9%fv(auz z9ts0c!&1!1=_bW&w(EE)dpK`(xlW;m<)}I7dhA|0Qb=)5z^575%v32j(T)ppZV%79 z31;JYlK8!4=!AHzUXqj{aRK#m|6r>)&Y4ZWA-&hTIe&XsfK0(cmC9t+iQeR~D)dQVM(;v#*L{8Yfn2D5 z#ye$B1=t!H=r|IL>&7GgsKE3Iye1=-H;(DU*63R!-*0WN%4Uh3nV>1$g zSXye4h#ysc39bR|5N|c)0u^adD(wWFLkVE@e8=u^=Jbxd@BnnISpBT&K%4c>&?|ze@hg(kOPcY2U&;KZ1Fn)*E&lcQ;WIO&k zRLR{&wuNK7S#Z%%@sPqX+|~GTTXZf$Q1{CernS{pOt{nTR%e!Dq696!LX115mDdFp zH%-(kM#s4GQj)2x&UO`&Tm`P=oV1ivU}P~t9=>KGb7?`~%8yRKc`ELA5d7VSyN8nX z?p_9AQ8ESSA&kEfCsDqsPzFxe;K61g$81(x@KgoL@~guU!bB$b3_HKhZL5*=aC<$(6 z<#zncL6ep`OrdAfS~bPIg@8+5Bnk5k1SA&}jKn0BOAG(bpNHT!g4KsmpkR34QDX08v%0|6%N4ztvE{;7_$~OE>>fi-!*aJ!b4zEFu+C392f{tT zY-GgybN|7kUUbn#u{N1JN9&HbO#+5ESsc%idY*3<9%o|`{nG{YI)Sp3q&%FX=3`!5 zjRN8^|GCb^$86Ku>>fiEW>Bcf0Q&Hh z9zf}WzqqW;56^A*^g~9TYo*~cPL^s|Iaz}Jp+-hG#PaC_gHdh0Zq&iE&u?bE%?uecrG3pD7vd%eXo2!Mj|9O8Ft)p#L-8ja^nnC?&tbu#x0`~1ob`WVgHHJ5q zcbVT!Q%_w}$j42yN+!6BXJ2FJSTOBfNCRdBgbG=$m;R8ay*OWUj68nJrR0s!%{|?% zGTMrl!nH((nK0=ISjq&~@oq;M$t=TGGeWC7w#$K|%ZX68t-+8Uxr1A)d&t#^27ZP2 zMXfzORI?bR!Ns9n+s^fK+r-92V6vrj#AIiW+j`^WOB(IQv3gqj)8Ukv8W9els}=+~ zV4rT3Ms5}%<(jN)_mtXWyDZa~`IL=Eb|I<_Io;KkJ34J~;A(xV^rGd%64f-JYOu<1 zuxeOYJXdA!ahz!{^Y`r?IBk{UXv6fCbxcwOm*-gYW$JhdI$@RZ^q!%71kXc`XT`^y zEFbG4efSfk+=tn6cODr))dH9bb3q`<#x_3Zr+VU<@?GA5{9kis>4ra37Z%_+h9+c7 zx$Lh$V==(|x0LxmPP_lNod2(FiD}4sdeVC_N~*mW#QaZTlXa$}+6@+QI%&KEKMG`~ zO<`+^hMkA1U{EP^+g!?!U}uUB>k3T}ywphGC6mBP%HnmVVM1fl`%0#m>2AM!q-t*{ zitGwBlx~B8{q2pw|HlogdS_~Xtj_i08uXX2JAU}Sq^Eg)7p|ssGWI$s*jWlVCufG< zI$7a(c~eT3z1UG$aIf~|39r)pol3?k+bBV2Evk$?P^V}OV9K3Q$cHyhFD7`Mj|dD}+=6;jwloUx8qcbRnviuVwA2%M`;ajB@zSCIy6gm#?!OFPIkG!(P}E^wHnj!1j9ES4tS63{SkoG3*7B^NL<0sBRbE^93At zd~TCTiB%9aZ*9MNGf-Po3Uq$GNE;@_)->U`t%t3u&XXwSVk4Xe%rQu`UFA< zMvsyse9s$crLTT@z1slU+r-l3W+VBd_tN&=dF2abAc!U0Ow4W7w>WQ_b7R@^#G3k` z0n^sCOP>_Y zBKl36^uoN-g(NrSGC1BAQkwkwh85R8!eOiKoM!2`y9Xic z#6+a**TMUlfg|UkOUB1Bu(;cr(f$q^`iYh4ezQq@3DHmx=X)Lmv0rA4)@(4(#uj4* zkT$t%a_BPT)L0LFbT|I&x818aiop12x}Q?8)@g(#3HJ%6X4$x_Cp$A60i z6Hh~=DM4ZJ9ZVy%O}tCU?8RxgW9g@lVlcnBxQM|=v?vCNV-4xVZ(GFkWfa!c_nq4A z6IiXo%xGXSSxfsd&HmY0t7A_~+x2Oqk&EmJO2@XXzAB8QM0X_q45vIJXXPXctNutr zz&_pA-OR;y@=NmF+qQCk`FWr$tQ-Z$N+#~S37zjJxQC{mehVg|aZAuJbA$EL^}=LR z@#O5Cs>=$k@Tzp}W?P<1ko{cbDynol7kC!u>am*KppiGB|ph4n(FqaYU)rn z?=xDmbW7#cYwc!S?G}YJaRKmXm!XWu}QY=~)Cixnsbx$g$Ybp0O_ ziyzm*<*6*DoOA;RPg0)rgQ64&D(G+TfBH)!=AfYFFH81;{B_QwoZ@s?AR0=Ax8SA{}8t!XAe}E7UyqgMGD^{ z)!F_!?$M?7f?Z|t*GUkc`g>OG=}<%<#w$}V%v;l4E+>(r9t(LR5n{!LGqG2M6aBT; z|2k7WgZho9mey|iY_D}AiLi$e!$E_Bh7$jGM?WDZIWpHC+FY@S=^ zHWe6fun7r0z3o+l;|Q197`@+{byaqkP+STKa5PKYI#Hw?joC0=Im@5-=;~u*^aTYZ zXbEkep8XnsJCSnRy%2r2sx@to!*3~ml>`FZy3<+E-hw?%`JbaGg4LZRyw7rf9XJtG zcTpiw^;=b@dUF}2(>L}q^mxb!FNXteT8ne*<8&QDSLFm3>eBt!kdm@ADG5ftY(HpF zg+2t2qD_rYZ9sRGM$J;#y60Z{V&A~ef#oQY@3NMK;7NmOkBPLv1hIwKP<(0+M(OKqiS5abs^2$^aVp`JV zgl8>I-vF}}m?H^|!Vr|6SXT&ZEX!+Q#s(B0W&Ruk^5)+O4#Zux(1J-Y0gBQvjCWw2 zElP`;*f4>LP89jQvDK9-R8$(_LSi6-02-L^nRl0|%RM-)HELBHV#7N5AS4;##9dis zk!zyhWw?0=07$8YbXd*Fn$08%d9n=$_b)&3P)K4|6S;c4NYd4Q)lt1^0JI?asJB&T zW))^b-Ysk>qH9ml`;UA zb1DtVnMJ{SqK@#Dhpq`l4FcpoLlQMg`bGG62~-(MNXDLC@)AEwjgrpsDp>-M{Oi~v z*$koHc2OaWVUVRF%FSjBpap?~lx0b3VGg7p#zfyUZGB5d~ zdvDvOgZpWvOn`ZQfR+TO3QFgQCo$DL2^9%4sx@LJ>iXpa6=gA9eY4tm?xN` z99XRF*JvG`FjFscX%zSEY?^+4H44@2Sdp?tg?Y>59x5^vF-fpk-{&}{{^?Rqz&sN` zscFlq6|ykp%YGq}TOa!!s5lFXKJ{!?v`>7nD+sJy{JWCOnmCd_pj-!F#LR-@GrV|D zeLr8kwWyXLK!d@hb<5XS_}is-LdvP0vP}gAB7X*;S_9}y7G;lQOJF5w)T|%mRbr68 z9o9Ahr`!%s?=n^f*w1I$wa%1qaqBOT)f7zz%T`^$Du65`hrK2xU_j2qLGO7DUb zs;gCi*uudFbl;t%uG(^YH$)j4{^H)d(b?06$cZO33>ke|2a);6HE#K5(Rvd`@?R^KGl4Kl_3Xm-!-gomnWQ>W@kxF8E97sv>-a&Gn4YMgcjz`iSnHNHKlwuu}8jwycs31Ag^K! z3mfuILmrIRQNUsQU>nb=t!aY&-!q)|>~$ciV8r`J&#e7yZ)o6>ItQ z^AGo@#;d5C81iy@{Tu_O8s|auI*3NM9QUt#n%oI(T)!yB3_E{Hq+^R^&ZfR@mMh4lm@dHIy*B8Y8aL_q?RVXx z-xZy)J!Q#w-J7TsSx-(Z`Qy0|1iWBW?|e89H9koT`DfhFB6XMj{Cl0rLR!k*$f*wu ze-v+Mccr8%WNe|^91Pv-zR_R(JWdngNw7^>nRVk=&HlP7!}#qjRnsTSjNaTb3X3cj zb6e^|P$D7`4q><6cT)Ts?+rhVzvf+^g3&Oj2r(t*t{Rw3D#`U z536yHxf?p1AYZRdP0c85ET!8GQoQRd_6#w38CJXo9L{|BT+o7vIE(b|VLx6y z%qfieEOXtxPr>QEaqgnp`+x*eYUEK&Xo|j*8-Mjfv+4(TU`L#Qa<^RkZ`}n5Jj;t4 zGwJ1NO4KYUsaXQ0g}o|n`uOhdApN8&kY@1f3(7BiSGo(tbZK{KA85zWU2=@(bi~<| znnJ&38aB*kPaMbG3FK5Vat`azNab=-+q^9JcFDL z|7UD1UHDOg`AV&NC`5wY^v}mCBw6P_$X8qdBz3*7u8LBCaz{YESXpF2yKXbdXbi12 z?QpwJ@RNTHA%cYpif~b}_tR!<`slqmLJp_>#{PH)qi%~}A*Cd%{JZj2U6*J+Z z8h5&wq%l`YMp)WVD4^U9;EDNRF&yx5=6G+);*@0}$vHUJH%VV`3Y)2tfMo5#Q;6MX zBx!Rfbr)GQAW&Wfm46wQ8|&1K!0N++a($M z7+x?5UT}o&ZmN&yAYn#^8Rw)ybJ~+LB+V5?9;E^qKiGIQqD@WfyB$&~qXv|U8eU~M2ML>`gIGLdpokff4M-xpun7|%NAh)>B%yXY1GMGr8= zV%T+kWzlW#p78iRT$m#R3BB<)_K;6HXOSmwh}ttZN%Y%mbF&lsS!vM}>@du+e5|A- z_8g*vIQ=+AZL@X5j)&P3wN|qc49{%6aMIX!kh$SdM3#j_V-Sr+3|k9Mxvp4ryF;*fqlah=k9=-8m6RR zprsffRI`dFQZAfF`~K$BAWwthMS=F-_lx3|j9HgR@X38be75<9EHSjt1i@&gFiLXq z?wfLD)n%nd?xbKqrnmCk^fBYNnp3LxXmVw=pZ3|bZIm@rj7sCIL4L&&pIyb8D$$Ja zdKs&Ke5>3Y^>bZudS%w&m#4d*A}oM%A;5@BRmrUxa<#c_0xOCPTR|$5d_T>!9(ML3 zU7iCwr=aU6L9OA?6Vx{L`2+8Y)VU#pb_x>dA+yq491zt409o(ng(rqLd!?U&ClGvv zTL-I8PQ6RPA0q6arFI}xqu=*&F=L|);zdH9-m)3wX%E~HWj=}HgO+xIP^rkNB}A<2 zPxFDqVe;9>Fg8Ez9W@F8`_4hAbeuco(|F45eY@B`-dl3s+}7zK^ASLZ0DJRI>VspF zqN|rK(_x4&qp$Rdnlx~0nQ%Zt>wt>OnA<+~9(cPHVBg8;cO4}Y@g8T&f<1P#o?QS6 zoSo#)E#akG@Z^%>{H6RevlyD+`OZV4(MHK)}x-jf)6I#5OQ!oKa9^`C7!S7P+YF6-eT7)xcX+gL{1Hg0Xj4*jl0$$zIgY-@roN6oFLqDQN1@Wnh z=AG-#{pzgmP#SswAXK={hpAyBVxkykABF{7q5J|1?<1!|v~WoNPDZ!5e0f7e>|cA} zY~BfN{7fN;8hUb9Ac>Tw2F~r8eV#%NeQDn7DrQkOLo`@3zDV11-VwA+{OpkbddZ_6 zP*(B~Gr9?`LS=(P)%F&oj-`46=&R<7R>aNk6HO7bn@Bg=-pb&!3K?w6hBAn3P$wg^ zz3v%A5i|>q^A$~p`?oOjKVb%JU zP@o%@2Qv2Itnj;rc50K>2YI|;$UeF0kVKHpSrpiNtUf{+jWJFLgti(b2g{3DXI^vy z>&A(CStSN#_w3ijpZn7wuV>jygM|O+S|%9R;}nKxBRs?TH)IZVr``!ZTXn+yQI=wD zD_fmOhjZRl)(|xsQ;m#QU z3|aWw5F$*17!A7%bQBb2JNuA9ZeoBCxx+qOSLy%p%>T7Ez}3>IY$|+Wcpo0NHuk!e zhzbQJFMZCD#}_)5w|^#)@!4%muzTg+6K@hF_?oDZyWWxrk#3Spzokpl(wH&;;2wRdlp;7+L$xC`=yiA21wFG11L5OPTJ$P%nkm6&u{wxi8QiYUUVRNTO)CM1$? z_j|sOBOFfdq_4xVpdJ>^qw?wq55Lt9us)4_cbllD;sVZ5hTXb? zV|^LZx#e=D9a9X8dzv|j5$ESBZlAy`Mb4l1#G!5DDWjgbTk2k9-+`t$Q zQ(eHVboK8nTPR)w7yC|?zN<~WiRk@{BemBev0`Mt(=(F zVuej`-R1TH7E;3F!@p)Y7om=P;9mYCOi{E+7qP<8ZbV1;J&h+3nA|GjKu0iv0%Pw} zZfU}|A;LwupEJ7|W7(_vsyrwddBIm)zHS-Tubr*nF}R%%&zc5TeY6YRu%HM>cFv2=*Xy+-4FxD|Ca{8?YWuWP zV%xTFQgZPGVQEuhx?LFBms%U4qvH%U;O*G;z0=u$s~QVUsTk(FXr?`zSM2zs{ln&K z!)|Y|afyu%%9H5}pKqHw80EU0H+q~0nZ?Pgrd>Mfe)lG%(JxJAgps!C?U`uPDU0Mp~C+qnE&UfKhm>vrKk*0BI(r7gb2B8AiqnXa)%D=kGjYG zoWGzbH{YC|Rmg6Wg=^Iw^)r{~C-joH)i-D1UD!y64oyuZo;6JF)ejyqov}CNl&p=k z;FB;VblIloz%QZ1RvWxr~t2jHUEv!v1+L%aj<|oO3%V zpgZYHCE#E&u?GwOop<(!6+9X=WU>oG>E}SHM7{sOJ*Y zZVX2KNEToKKSKN;jAiyek{Z*$4{@TNJZK3D3`|^IRqGrSfq?XVeY{eUm6gp@l@;z; zTv|#kECd(El9CF$1yA!sMLi-8991j%C@*tl{ZK{|`yTmIpQns@4c)rYdzSGN`o?Z@|$e-q<`(whO+xO|pxGO=Wq{()5 zb$QwSWTBZ?Lr_g^e4v?iX5W(qYs_q1duBb6x}G%z9K2(t-Q8MPxaamr#n#pqh^jORav5%2 zU$0z-;~Q}~PRk=t44UnH7;E5NVl?UAZzhL89De|=F+QxH`$ z8B2Yah{h8FfR-NKpY!?MpHd5S*VC%oY&+0A)DIt3n%|#>*{--Ob-v&cO925(6?9@^ z{fGf*{j(JhquQ^JmyS_5%j)@ee($f#8=X3bWOgHoK)=|~ey0Uu_GJMZyEUD516TdW zR_|a}m&Eyc`*OA3AcyTrqs4T3zmZz(9a>l)2#CAgdYjwZbJ6~|PJ2rWyTz2t)i!;% zLlRIWBg&nga)%5rrcO=+36#w_0tW(K_m?|^M9$7K&Ntl2$?8B8SLv;?+#HA3CB?>G zZuP$8<~Cn!LIEuci{NW-roK8bP_0C&zcX;()MR@!(QE7rLCpX(an2KjG41771Q$wo zo3CGWWo1QeY+P(?Ok7+{bah=!Ouh;W^Tz2zBny6O$BN&STu6U^W$)0!DqA6ibS4BtDx zDjjg*%Qbe@*UJf7zwbFW?onWq%98^vg#^9U$% z-L`qT>o65}$^kyazInOyZH=FvF+f2#bjdMS>Qq_V_b7S(893t0Z*bLMX@5~d$%`|~ zIGeDIirQ^12$x)*9{%gma|~e|o|1uUZF%DM{YVWK(Ragh9YX96U4~@eUCBGDdUl7w zrOh?K!&%=|oQQ*8xO`}h`g~co9#zGfjIfDB%4RinbbIzgJABXm+v8{o<6smnCE6#y z0s0dU-t4lnqxZL$t3zTSkxBXQ>G$hcOTv?~hQ$#&Cy+Eo0#vhJpfNY zu)nFm=7n!nQFf$UX*vCUGf4~pNvsei5X3-7SF?+uEFhi!{VPC3L}c{xNkzKI%`3UIvn1-Q68Haa|rS-2#o<$l~8jK1HGd3;Y#OG}H6 zjt&nW+3t@xf;${d$+>1$!X-qHJCw%T5jz51mvi~~u{{3QC+_Vef zcF}h{on6#31NJHI(0mBh-Pc#j`B3*zB!BlLodGgnA}5Q^M|A=$<2|!4VJZ(RvP$K?yn`}aRjF*S;uvY1!<_>p{YU$O}*ZIy#GlMs7 zXmj&}vNJ9qK*Xaz%SIKFI9+;7T_z`6D&n(O-^=|tY|4c=b4JlYX6a=u&`pX$d+tL+ z=Yx^U-Ue+C2yrs(442)H=Hc7Njq0-E$|PyeQW?@T^_UHv6%!SLFue;}=PCKl|%79e(zQJDK@L+CK>!ErmJ$1`{R-(#^;3Oaa9 zvfLBmk#I2wDH1i)2a){P4s!8uQ> zgBHTU4t!Sc7mrYAP^3TaT+F!kIs9bLrHz@>CUayzZFp??O8$=i4)$Mid#bKE)x3D+ z`SwSStlljk+g5ck9=u;}f6!HX7L}#I{ycRzk|YBy2tZ%&k2ttLziah+IPdT{(WFx^ zdZ&X6-mU2_URhpFGQS1p$VcMd;MUnJ!OQ+x=jd`8_n}yU@v%yp>1SB*Z|&~(@{*ws z*Uw%z`>uQ4pg@rVBU3;2-`~>Q$%#4b*0`K@4{r`)GBev6?AE&sd-u_)$B7vY_*;Bl z(sMSSg5hmn?oLh)m%;~i9$+fG zR3Ti?Mk?ZSP8Qelo(4_Iu(9#6v9SpVu<_*{0tfpT_TF#a#CnAC(b(LO@ z4t*D^I@SgK@7_fHH@E*uPd63d>ML&|8X!^9kpQuup#lN~kP8F(-wRQM2SpN7qJjVb z0D`c8{%I=!2IYZc0(NT=;<6i_K-Rxjx$~>${vM!XA=!0U_|FM;0bD z+3UC54h8_IMuCSS?NOjoXnwRywl!0}?>?Wv>bOiBkv)ENawu}Bf5f1+vlq8iK1oWR zcFRmm@J?&Qq+PolWFw}rE@B|W@^xTO2MyuBmKF~V{A z4308P9`Tpe=+Ei-U04wsAN5HoEIv5uJ?X|Dc26zuZ*)QN_|4K0L5)DKO>N#Vlk2qa zTf5)Z^c%vjb)K8l4?i3lJpG{eDQ@ujF&vlSxBv4^!p1z?hcyo-MT+d|LF4wg^9ug% zZsY?G=jp=l$GTR4(s3AU!n;{g!p+Ksq^*cArRk{4KJhL!fdMkJ_jae+>uU;)|jd!W}IhA&H#7llQUajU{ z?HXVnYEf1TlGMY3&FGjf&_&m03zuVVXUpeu9Efd% zCty5gAF?y#i^RG*eC`I)k8lYEwr{`+x-XiM2MQ&nTjWsfC$clr-jGh77Ud(EM=KR% z?E(zF>`&U*34AgLu-hzG;_?oHvG!>y2mGoCjgndsqfMs_8xqPlwT`08=7y;90!s}E zfv~HZ1|CYqj>lSbB|ll>VqfaM$(#nJRdwLO7LR|a^aHQ!$LN62L7=FMv+hHN7VEM+ zen#t!e|~AD5G1L*?y~_H*9)0u_*3{uPi@#$ z->XX4h1}7B?Fr|wH1R_=siBa)1lCx`g?fHi1SLIJ)X0-o9}47&4hwM@KWEc8)u!mO zS@R*&*t*X~pzHWCvx18?^GOh$?N;KW9=5F8x7JU0J`v0}jGAH+XI{d6U#Pd~tO0=1 zau_7T`Q!7W>y&o;XlKR90lLG)PR!s{w~2r=A(Nm6;u0g%tP0x~l@ZZ&vlhzc)8LTm7t57~oEu9xtz!Z5y;i(Oi9` zHpgb|p{LI|tFkg9TKbU(#o-?0MpnFBZr`8PJrD*9`3%vmaU(;DeOF+ zu^6YgOSaeVU13VTrrXer=9kiwG_R_b^RX4ZN$0{>2 zF>;fsenu2z4ju!Xf(6g>$Y)FpnTyYt`!)BS@jmymiTI#0o~}O&E>3yUcoOM~E6+4w zVGw|hunHdfeq_t#T3B}R9BY4Z&g7>%QL(yg7Vv)DG;!u)v|t_KsG{vHBd8f1Am44* z;wYK32SWWF3=9{4sL{Es^&kuk)n@McUAX>~0#1JYbiu;9I?q#YF=u6IP?UJ{IE>%M zJtb?OG|OV>-L&dDCo+G@VqrSyy$VCx@20>9GSU%lX>;#IGbmW^HX7cpj&hNXTTeY_ zWo|Pv!Ci?wy@d(y|Qv1QH>Ss;My z8Nu?)t!;-V7_RFz-M8}>mkV1^(<)MWktV|up{9s^X@zHb-Xk*~<@9g@pO#j&_h)1N zdnbp353@Ff&(F+nTgUty70%J7+VIP6mo*HHXqRGOK%SBXnC_luy?{2usN*acPv-ni z4-skNU`v_(RiO3|(Uf<)?u+RC=*OGh>C6wT14=B7Inm+*23YYuETXXI?9h2^$IESm z`Rz^}W{L^FWe*U{eAf94dEWQx%lxf5Y@g$uL!;!tBL{iS*?lwj^F~|9O_u-FQO!<0)4!Xky4t&ULN%-o%85W~McF zr;_Oiy~@Sb)6VuPutA0-WGfJ$idJJ&;^Qrv{L8DX0r-91na1V;+RwArdYmHPj z>q|xhs6S7ZBr)&;&oFZuvU>OPjb0w-Iv%&_Tf{@wEQN|28HfB+Ce^gEx$mZkqWQwS zUnQbkY8NX}c#-Yf%NRZ`lnxb=V^0MuPt()mvw$xywU<$CUAF5@^xL33&aombYv;&H zqw%TZbn{@v{LKP>J8rzJW_qJe8$u4Zu>)*Y$6d5EVt1o!fBM@2m@o=8C0*u$U2l@;=K9-1xLy~C;jrlP z)P(EpD@3n{c4cM;&tAdi#NBGNp6?|;L%Ai?@X!VVBI&E;-Y(APYdiOD%_&}q7AED>^a#!qr`yuXpz+;7ma;A1>X4jm+`kIxZ z0;_jG?ff9G`gE~{~y2VLcvN3VT; zQBU)-fQNe>*Np8Mb9cA(Y&ZLMi+@z_%Yzkf%CyBs6sxhdxq>+80K4l^ox^OgwY3#Z ze8Z1XnYEC~6ITcQ0`i9m1Ws}Ms#N|;mvZ;Q$r1VwaGPnfB41wqY14S~gMjQ?tb{IW z_lx#=^(^XF2P3l!7}z$#I|A?h^Sa`ZnYL>~uSvHEf(WgJUd{`c&qjGYM5@|L^Yg~< z7L9ZPvsOVL-C#05`b8GFbnxBuI!r4*wD};UW?oqR;IX@NCk0?_QlK&kOonJqn!$ka zqbQ|Vrj(OVn4z`mKRUuLe(PvGxDc_qpY_Y)mHdMX-U$y-#&x__6%>_J*m=ep(sJs9 zo0%#**OGY}C@oa8x72SO?XrS&eRV!KhX;dHo9*|qja6T%JuqX%|I|l%@~g>DSBLj! z#ohQ*R96-1dTcj;FZan(X1>xO1XRjebI!~4Q<#5?;Xs>3v4*Vp4x@g?EK_|QRodPC z^9$jo03lL9T-PGT@`x3jQte@*$?z}Kf(xUx7jNlk$U49?PUuZLN9di!mtB zNy>xrrdtxwx1hoa-X6$~nwzY+I69V>D!$h)Gxl%s>z$eLj(3CCW0*;|hJ=#Xdnjad z?U(yM^G8|_)GLL@n(3m@95e(+S6S^>8^JZURgDif3jPXczKR!L(Gt0*OU9L|3U2Z*($2fJ^>5--P+uNImHF{G`aQ?V(Sc9o2^PMS zFj4ln4BZ{yilZ`(*2|E}$#glEN>3L3;|vIEz@5`H`;1Fm=sT2;=VO*UyEF59o%_kn zNoUIKW`2A2bd;P$)|g!yPg(C|T_Te>L*B?)JH5|P4IfDYz?=)jpmUa|86PB&ori6D zJ$HM&h-=H*Pk}<{2`W_U3WjW{AF@}3!Tt**eWMo(&$18C(cDL9= z0TDJ=x>yi1VCCYe;6&Gcv28>2*VweJ;Kk-ymE2vcs&L;RrhCofyZhXQUbu_4ntsiF zBig5zeq$Oc>3Zzx1I}MpMhQ4GzBKHo1I5Dyi)(VpU6N9gaj_Q~vjSY2k|H-L+~qHron1-Q@Kkqm)aCh1qPHjC+m}wnQ;>qJ z4j}4#(uS3~ulra#myA5Sp)c)^XV6})MC?3Dc%O?(wZOl?xji>2aD522CK!5wpyVFQ zl}%g**axH1oH_rL${{tMth(1kzfQ69?4y;5qYt*`KeS z*I%VrNfVuoP%K+6RWpBZ%+QxN%RC;;aJiV?FZjjxUioJGyq{r5FS)|8Zn?4^YtmF) zrdRR{>Kx8Groz75QO}0yrtOR8_Ua7}#~Jpb)kH`O+!3`^^0?p4lDm0geHluDa<^X4 ze22%)NG3pR<5ItEpLF_gcI?axG|@hHZJ6fl-V=pEv;~*}OoQ_@D}q*C+GyqbhrDu9 zZDj4u*rFZFc2TG5Uc1Knwday- zBG7QiuUj@l%!cDpxwHIRR{njkPyvc__&*~GyFEKskKX(vc__9uKq8}r@V}uy|JF`Z zw(0uN;2n}!}<#j;O#lZ`p}Gjbo|3; zk{JyFIQJOwe?bHPD~tSx_Sn@rJqdljtpdFA40h*|eLuDbMz)!G!{d1NC5HL&8T^lY zB;XpaINZ;WE+J0-2Gw2kh(Z6^BLDA6>u(LuE2b~&-;bU`Vq9E@So^F8yMfA}9d-I^ zg5Wot6?RT078pcWdXx0xDm*eH$E{^?F&%`zR-hWoWM8GYch4h3X*IUSN$c>vcIe+Q zPO{_rYtdZ65t{PO;7I;1_lmVzoE2^cJCQ?6n)ScSHspSA?DpByeFsxWgUUEvb+0TO z1^H`hLBoE(%Uqx`XjcBQjcdZMH0!^L!<+E_(i~=hqK$aC__fg6Zqg^CZ)=v>^Rn@Z zaEWTJu{S?wWAJRsE&dXvSoQyu^3_3ceapH@2q9>K6C?z84;~=6y9IX!2DiZ>2_ys$ z4uiWxaAy)6g1ZmyE`!6H;df8fdsXkA`%b+o{-E}(UaNO^ukP>bz1L=l_83?r;|^@% zU-`K*H1V$Os9_NhYsektxg=X|SxWw4T4N+036Z87jbF>rt=fiPUdd&-2dd;6V#(te zvGr}#9B|=TyZ!WCvRJvAg-5wIo&*` z7%6?I{2i0oE{Ah`cTZ7W3TMaaF(~a^x&;}oy9k*$v#FXGNVnQ_RB%0zFhtgYzwI?h zms&oy1IIU4+G2mj#Ai1#kp6WWg+%ac{6;bs@80NeM*NmQekZvF^~8;7f=8eF>2`?+ zZ@Wr!Z{$gJ@J}S(>{UDFQJ0!aSB{>rX=qVtppH;W7N~?^{qy2;9 z@k31I0_O{M8%0SpSKf}^S+w|walX7_+~q8MohAJvz9bJX4ugXsQ_^_{bMLu ze3qrL4osbRrC&zvqf9S*)xwc#>Kp5Z7D)6ui)xpFi1)6Mz!P73$1LV4BGBlCaszp} zq0B0g&HX=f?)uJq-mS%ys8e(V4!WYvQ@21^lGr9j zoo{+A+lS<;o8*7}sZ7a!-nuirJ>Z|^H^~fY&GDe|J{-mED#U$dc z+JB&;#-IBLa)D)OxC%8;#ZgI!ANQ>4yI!rRaC~Z`O2d5Ylh$Z}ND_6W;ENGAIVzja zlDEGuz(Kz{pCTx5jb#d7vD8VIenJi4H4bG{K@srvUtuMK8MhORtmuuPa4dv@iWrck zyzbb%!fxpDkxTI|7jZj1p` zBqvmAsKL}7GP8ek0%x;qD)wLnNQihVATFesH%nPkU9!Taz!q8O3Br>sz=*yy4(wawR0{HH4kleA)rPYi$mpS^F(xXid8gaQ?av-2=uFx)k+#ur;s`=j?{JnrKOK=o`UIRMp{hzU(Wj)IX^2`pFSCRCX*yD)<58V+01cqRlvv!!DPFKGODQmBtBE{+h70(wb$t>0S?iMY&e|LSv#L+oD}>pUaQ z@cqB^3qn3bqk_-wtYB0WMr8$gKCDi#_VI#DW8EM#U1>@MnTJbOD(asf z5)LKV`+io~7&BwzZ$w=2KdG_P<$BQFvDdhTUo03;(eLP!hRE@`(*w7kZ>Qyc1rMX{ zO?UTk@1gnX7t0O40%v{4zszlazF|1N6J_U)CPcT zPmj<2Z+X<{$udd+3(aN^6*1oh#`_eyzg^HCdy$7GoQtHI05}82N!{)z#Yl2Z`bQq(uwEE#axFG~LJa?}E7~!ZCsqQweflOf?-j zjW6Vir#Iq%ew@u8tzn>{s?cEKNG&|rasc-3#&??z=|Ecrtidp{5$7`timE^9C=Zy9 z!wLJ`eLtF;towg|L%P@bGqFZhp^W_C<8hN_xaQD6a=n?9@+Q%QjqsILS%S0A?F z2OTF;rSb&&G~aNX>*2&G2X9zRIO_UI|4J#d>&<+1$7dG-V+BbwtzK!)pF;tgA@ z?2p#HkYlw}%+%vJ#e!$J@9?Fkz=k(|)qY!(@0;*$E7a|_XQUeZ@zk@?WIk_k7ctCL z#c@5wF{J3rRtaUyAI~6R%hj8$*SzZwP|fPmTO7+PZ(!`HK>7K|e&3Crj-m9to2{~}qxL1C-o3U;i5!o+a5OQxf@~?vaS4svq;TCf=1}m2U7rFi|S1Yte{+`pqw!1J(&}C_=3;Of?$B6v&8G= zyWRnNh-@yJuy@Jx(~$OueS6+J4%O}Y)5Wqu?vqrfa^t;~<&E{GI~Q9O4>ZZx|APb9 zI8O+x_E&v&mw?XCYoI6N!V_%V8sX=k`7cntw!49ySP2G;29x|hTleCJD`?WV;eCf>1brn=R~pYH0iJeY5ggT`mf)^eFt{-Exj`i+X zf7p*k5ceZQqas)xXLWV8DneM6Gw>LjJRK@fQV7f@I?t{9hYNM}Y zI`nyWs3K72rf~chNiuDup$o6hH6;y&q*#4r?6*Ivo1+|3cs~2~pDqTyY>TE(D=}V> zo`&wsm|W#X@pN_cIBgBL8qB`uoKUBdT|Oj-@-^6uRcxM-a-)zh?q@0b2anH|2nlby zb)Qd3@l+o+m`;t}V@~AePjx=GB@yx1E~U;|bh{`WNL?$5{#r??^!yndQhoceb{718 ztKB3=NAgo8O@&2+mB2mtFK2N%O^R}q)wq1HKh5TvX{}#r+oqzjGP$sihiTSr^V&=m z;O_d|X0CQW>iuk8_YLW}Ps6(w${O^>+Vn4s8WqUp?$*u1+GJ|H zB{p-wt?R3HulFMZ*!1J6pjO}0ooQgX9qztD7T4B*VU=p};K3?SOG-cAL?rL_V)lS^ zfcLGA9uNAI^;`o)h_3v@_Q($Da;=W<`O+Nkm(CRJUayraWn7xzFA1*>M7-{Yv$Ey0 z14qduY%#~a!yum5dqi8tC1)*$4BUyH2JAw|`&VSiurM3$O>xo|kJ?&`Q|JfS!kcwl zu#m;Q=8h4%6N2*KQKYK*WL^Xxj3`}oQ~N3CY5QpjbkHA}w? zye9;PrK$Ingc7hY(%NwV1s02)59wLgPTUpANIq)?aeM2jId^%LyHOPy=Wz~&?ZYa zgFJi3B;Bnk+6Ts`2w+?GXwKYW{X47 z30USseb-(*t{oY>!^>jTwY9ai!Yo25<^=?HWF3l#V9;93vaudksoLO}Ca&5uJI8Q8 zQZvnfz+a0t>Dk_V7@3l>?UBM)DN65L&3RF-Wn{!E0H(NOen#y|#rggNHQdNlf<*gG znV<4A=Nmo<3DGI1>0d^_!H`NAOchafk@xixba^Q+X*(;J7Im6}Y9YpK?n#1Rff+lr zscN3t?FklQy>67rj6d4t8Z!Fl#PzVFWn>(k(&PJ#aaP}=T08asssi(~X`z$s^i))G zEPAs%FcT0EbVraSzqgM5`0i&@zi7aV^Zf;;ox((jAu+O8+-x!)iP0ePkN77%)vP>$3=tj>5n0~|F`(Xo& zt}ZE|7CO>VDJD*tJ;$uOSw8Hd|cD*V{8Oc{wJ(_E4Nv&~;)o}_|Ck&YV7*3}@2k!AXhll(|C zT4}|Qz7wLAXI>Yg^vVl=eneluP%?aOMsebgWZ@Sw^{bmNOk6B(zR^EDOqI_b$}Ce! zJ95T%^Q`C4bodXU*|hS$jH*%KYG$vk`b_!y0cS>7H7iTun$);30n zp@Q1Tkg|odOn6?QtMmv{YKKg?c{fB|AyO?PP!_e@eIzwyK3LYNT0($jEcRRyZ6{iv z(6jKh>AR*DisD!R*Q#v6Bi^qxeGLoCGjx@{FnTG}db`|Ds)L0eeR+R~QuQ(^4p62< z+tS4gPEEqkRS)?Ce(;mGr6#CIofvh%KW)jKlarsso)ONpnrXou3zhj!gpu_-7q9-! z{OlW=GU7Au?Y_}+^435mqADTP!@Vb@9_xP;}Q#}1ShYs7GhYj%RKnz*!C2hHm*}h8&}um8vhC< z4)S5V$G4ew)GV11WvOq|+Sz`Q@>Th^S3!lZQt5Q=qg*^vu!TRDxdBX`Qr?D>iv)Q_ zzl2oWZ#LD78Y2$l11iQNt&kzlXS-HJGfln*8HEd{vBNif8paB z)G~YIkT3s&u|`$zAFee%x>Uzi78!gt9lLfGIlKU>%%8no?6wP z+AN@Wj2=d_*Ou;~6s`$z{yBbNkd3*_$_-HO9RuZZ%$8uSK&cAvpG1>gLkfblq>^H%N~yhMy*{ zrPLQdO(}C0uViuQM8X;yZsOckZg-2$WC5q~rY=a2qm-j^XZx1mGjW8;Vbi2uIu6r0 z+Bi#@THLB+6Zac)jsJ2&Q0v!tKnjiU(xNySw^}@7Lz)zL3NYPU&a7A2!6YQ|M$L zWBuFLh;G71%{s5a*#5WpniB@a2_F5YVo8s!zk)s;ctcOC=+Ew3<>(Yw!}Kq|ileOq}H zde-o%u|@eB#u~s<27L%~@QSX_e7-LdViLy zBmF$u<9WnHNBR=+Ol~4PtMgKb%HDncZu<049meE6c^m&s^;kRq)|VxT$eTHB^i$Li zmw~ef*Z~qNu3t+_Wa72`xl(hta;c z^UK5vpSJHpHs!l_c#;<6^CZ71(FWDVS1;~5xICjj^a}C2_#ZaNb7sBr;?ectsB&e4 zApgM(tHLtt8ha=`hLP?x=`xa~JE&6tNN3Y%|E<_i%cGP&!2okjH*c*IfP56#`=DLJ=Oi{Jqf+i8`l)!rWq#xys|K?`=aazOi^94l#4o~RE0|Kf#~+~ zl!i3c2u&+3R=_}*w6?p$6_>Djolp1VImZUaEx2L_k2Nv1z7{+katBS@Z zG!vTLgb;^dk7VT_Z--0ACcU?3>YVDVgbLzW?ViCW6YaE)KO}L@W!r!9&p}zlf!W7* zkssere>@iYcpdSI^5eVeaG^VtHD`Wl!plov%Rk(`PZyO@|NZ!<|NZrUEf-QXJUkpl zCB4Ds?&RcIXb#78T3TAwL~y~+%7zP#Zg#e|ZEbCaRbk1=dQws^wo%}-ecpNb^5ttP zB}+@oFD`a=cFO6(Ee=p&VzkHKhR4Q8gnjDE%N@SB$j38pFE3NDii9fveSLkG3aDTR;XWiMb?%&<~|J8Q? zy55;WX=-s8u~=usp$#-&Rp~6%ERQk(>aL|J;zik9yC(YWV&cmKS(_WPGX2t6gc|+$ zjBoDm{PpVz?x+>@KMqy<dg-Fa%a>bGX~_B;v=Ng^Uk3kI;C!!&s}>7VsZ@!I$99H_aJ93J_RH*Cco&UBdDsN8;u zT0p@dQ}r;GUjpvBZH-*;x4eS`4s2>R)+$>v2-5>2vyjjOdbicl|lF80%wJtV^# zxo~c2?HVtbQ>6WVAxgWn0jB=S=|V_3xV)z+vDR)N-Uzl0El4Gci|Hp5Ei0_tJq zI8(w(YjNHFD~2S&f769oYq*rtyllvPDjGRWw&dDgU_(>s8gyRV%Lq$bnevvi7qxWW z3tyFfWjl+vB?Jtrd#6EM>sc+*$oS19xj6y5jc@yJ@(9P%awfU&C;Zbl=8YTpS$9{QQMOC}E4M?ApKc78( z5}ZPCzXNT_0XOP2+0p4omJ^HocKB{{6!tZ~+DgRkE(?q2wuJ1_3n^43-)-YxdG6!X z3f&!^_v;z+9|5j@yU&I+R_y+&nF?wdx}P~;z?n%{eg5C1pc7SzyH=m+>d#}!=wJqy zw>K?AiNxReA?nHxHj1ldOovwE(AUlNPO$YfF4NjNYp%m+mClO{C?V}PKUF|yK+JB} zfIguJpOv<>x?2Q3B14Jw5Mt{!fs*`nDTv-D`j{^gt{XP9NJ`CD9Q$^$lFpl(@RyrC z_5DlWs;kO-cw5|j>R;pEM@Oes{(+Q9V^sx_l;~4jk1sF2EL4pudzKqv!DDHPf)q`^33yn+<&Hawj7hZ%9GE?SGd4D{k^VWi z9@3!cozA3%^vZ4rr_OGsZC`pVN}20D23bn755KV^gqWs-g(fxmfYZuB40b{YsH;q4 ziQTDLzMKxxe~-w7zrFv432j{H6?s$^h^(XUYNv5j+csgse1dfGFSK6m37q=B*}+4ZP<}U&Kt~_Ub$P z15t1X`^=VC<(~F40i;kct$0?HGiRr6+{ch#AmR;*lCjp^tK+|$v_+^}DI+YD4@vZM zC1w%6@bwJ*wp`nh^gW_f?j^^LKKtbi2ovReRJ)v(;_U-HW)fuZro^ZNx9DHd01?($m z0N^0&a6vNoSr+|JXuvOY$UiXLU$5FqxbSjeVv@16zC`SlC8Kmk+a~6w8ObCZH_OwF zj8u}mEAMU^i*w;^T|Nz$(?rOxVm;)fS;28SmWv6ktIPbl3kTgpk%snhZ`AD-o-kV* z?yWjM>2g}FQTM&cXzqI+W5< zE^k6F0@#iOJ_0K%?OqH3xwaejNH+r;k52sGs^))EP2s~r z_#5=gyp(}$fvD0Eq)FU1TDy~_{Due-4e0vcgw8Xni2h{Wa@A}pFE6iZ)JGV=>$)|Z zg6->jXFZn3qF?`$=P7)qj6Pb0#GkRTv0V2{e~`$?QW2jdFqB4sl_wu!=C0zHn3=;6 z5E~92nCniN*aX@T+7*;Ery6;VU?al(Blr5haQM3?j0L|3%bT}eA|d8hvtMjZij6fl zF^Q^U7ZAA4jW+9!kd%=4q@y!picnVAGa@45syuRUWu+1@^p+Uqe})$S)<~a=P%>^W zJmE~9UjJJh?4yC(i(7`1p?%;)r?w z5l~rHqg@cHJnqI6j7Vv~fw8j`OEd+hs+V@{d%xPcYY2}Bq=FCDV0e;y>);nkAaB3U zbbnJ`bu$&x?kY;ZTl4U{qey_10KOW|Q~G`IVFqA3KX&tem8%H2IoS8(wopAa7{G<*)`OIlwIoCR%H(>* z(EE-O*=|`1NVw~;Ppx0yH;0`%9gD-cchk-Sx=_AqdDNFQ^KAmEgXvv02qkM*ID_H@{WU_9qQ%IPPw?3|-#*7}@t00{G!lepkI8zbWCJ zt9E6pi5{5|5R+1UI#tMuk1N}CY8_J<-+1LGnPU;a^171ai@MHZy;BnYy@P!rUlkHUJ#pEUy9cs+>%}#T z%%PQU2AfzGHP1^!?pji`l|InX##lkHg%$l$ZyJKZ848Vj5FHz6lg?l3Mpk~Z=^5rj z^(Y`gtSmKcsh0h=cKJdhiddL`dM5uj{MJRD?CUCF7VBj@bi^(?8D$iKP47n}cb}6s zQHiPO&+s+eboH{an2uY`=4l2LZv!OJ-QZDKrUl!dv$)@0>%nX(w(V)k0F?%dl1ORA z1*2QG4%E7(0PZ>WbBZr&Qe+jUa=!%Zr;D75E&OBIk8`azmFf!#E$gE=cSFrz?LAve z9{zgV5^NuDUh!y&cj>NaAK@R7}NcFxcevHD?4LJiBI8W@W7mrtp)$ z^i<6U8v#+neziocLt*a|fiv=Jrk8UUl zchT=|dQMK*)`%J0O|4$%m5I)zqve00?dCuPD8%`WveZD+ul-n2ibmkLv^3Dxa4#-h#P>i_PF^<6DoZkDW%ne7 zPDqM0yrSUMjODYjd}5#K>G9Ya<}hf2VWZ5hA&riYJ3AFpVP#7x_AxZLYz~Itqnnv# zNrw~96{rd!D%L}M!W17}ev!yMk&L=ewXN+Q(n*&d$#H4mW<#d^8-gQ~{K4 zuQsraDVJ@2(&0p{+W3 zVRjQmgPO&YMH+=(=R264CTl&W?k}J#J>pKBEG*nNFhVc*#;gTR8n8Pb`bK#J!cyi;WvIV?`J$>+0|Ww1 zm#gZA{O!L{upW(;va6}1*W*i>u8j5f_xnfBXYWOK#2oDOCI)3%b)xPGu7{it^S5a>MdV~F8M%23G1eP8Iwl#Zce$V33R}Ol zW)esvBT_!LOlzx?yq0?c*vvQR;-*J3-)D%HRxe=XRoI@e@m76BDzQM)8b6oyw3l6i z_sHO5ch4}<=#?Nudw_Z7wm4V5NnlIXkUsq7mIe7yktVQ&zp-edD$?84Mp=kRcn7$I zlYXe>GjaRPCemtd()P+C{r+x82Pn_?@^P+sw}SMI{yrpOD7 z;v3frAQqjaq>iG)JTt@f90zR(xWx33!LKEMjli6?dy&uY?025xm&I(52fA3UN%DnP zY;NRZAsdO38RwRm$;VVjsT)CGXiiH>nz!5P8)4BVt~r5nRy73AdTXY5IXMmSkQ`W# zA2%%RTAtmSz2znwLmOxeX)hQjX$|)(g;e@X!a(;ziW7VUkBowd`wo11@zyo@y7My> zcHzK!*aY02C$4lq%#YSOn1LuQ^$*A35-X)uxM-0GmJ;r&NE{lp2 zq4Du?C=}Y(wz3L+Nal6$@)UY-O9O*-lQ=DA>l~oD@`RMwh!1gScadpECndchAlOLW zj|r6s5e#hv>Ak)O(@?|6Ht#+Z7OvkkTQI&&(dV__XuSL*+9UvWrqhPkhk|NUT-pN1 z`KyGeEwcrSpyj!Mn>nji4e;?r=GEQxJ!j!07W$Bz9zbK#vraBfS*gU(lTWLlO9Txe zEX>PW7Zw)A1sF_BN}{2o6Y)68nCAIbT3VW#x&SXCWri(4Gcz+F@Y;GG;uTD*{#8lf ztoU@Hh8#t?@L{*j@|qtyHss;Mb=jQ`+7mj5>^k-8AkWe;`Aq)mPC%NsN#69qW!;{4 zO%V0Qt?XtSw6_ovydZFMFeHTM)ywBKgYkk%iHSrwI5?!FB_~nz4)cX@B0QF-NWu*~ zQzM+_h5DQpwrJ|sIF{cntf?1f`fcJSbH`eAk)Ld_AJ>_4)44-`3)Ku%LFL9)2U(Nf zJ9ix!Sx#f1&+IK{P;3bdH9K3n4u7_!y2mT>ZSi*p5hm8#L+U;umQN>M&-Trp^GK5! zAWo>6t_FazZy^!>r**8)|FljG6-)E7_g!r_Q8M2|n0@t3Hwuu_zFNDFWTt%*7bf9= z>#p%t!a$q0)rb*KIX%Z5jgvcuc2`U+of?%h$?_mnugW}}0{7Z>d!LZN31%M>6i~8M zbU)At2Y;7V7V}Vk%b$sUDXrIqusmTulxvTP59emxqve+;fIrYi71};Rx5Ho7>WI%G z?i);21Tq@l=l_<$BPV~5y?w5rkt-LMk?{@}H)iEHxjgn)OalH2GOiLS{A!D^I}h4?ho*+TFIVg&=AF&`N{>f z8K*?iP6l08CkakFO-M_(J88|RuRoP??r!W{)t>O05zZuIRnJp6_RwU)W%G(e46)9WKD@A7P($;w^VsO%PQ95RDsK9eWD@4u1;>Q*5?$;;Jm#E^r+y;N; z@;=Yp8x|8QH=cPPZm!8diQUs^hWwdH3VDzT5wH=DkUALcn9 z6g^JXW;Uaewq=!94h)4_T&fQf1%!AJcGpA zc~aj>(mAZoXF5uPW4mX_EM}|?$KExa?v;xSO1*dI8dGU)fAj_(^*x9Cat5UHXQCGvF;h{XEonzgAh}jvb1*U4 zdW2Gt1S-*|9Gc55sZj2zN%n>qHI5W(?(=TRRXOS>y2%b_Bx?=8`?eAYn2>_K$zLrHM2!KGH%~)5EnsRa+HHq!bE;!^C!v? zmMI62F=WOwWYOz!!g0>Gdpjb>9w8Z8HrI=G`-ZLar6(h*k+rL@q>x?HHhix2w8c>| zAG@OJ`So?qId%FBTYmQ~{&UY*VQd`NKAlB|We3SwSm6gXc2k38x%{UHR(6?_YoIG& zdtfKZzFqC4g_N!B)0n-#cK%nJaL3Pmz0GHcKh8htK<2R*cNu7{`KE==`7BwPXL8{g zWz)J+>uw$Edt0wN(wWf77yn~RNu^%jfW%?0wpE_c9lWyYzVzFYE*}UdA&;23@0Ey; z`{tk!TY1{|?_EeQ!YXRk8xzS>r>C3#Ca{Htho=d;8$$dRG*9>u@L6(TanWmc@}mo^mBlL(xMlAW7-)k$dANl`~lu`Fw~1*cVM%^t@-`ubtnW|D9Pv9R#>_xh5-@p+w# z$r6+uoeQtfo8V}7ok^Q@q24K10<{V_Q3R(kP4)|5MesNdifG~|AL76#&!1fWAR^wW zvz_@wdNSm7wsl-%!wU!IZkvOtM@Qbv%kDAJI4mrs@(HYFCaSaZ&9QJ8&sC*nsx&$} z$|}r~r;^jrwHO&3>~*x{=jy7V(0_M>pqB^RJ3G2MGoSS4rsw7oSZog0G%}snM^}dP z6si6T{I>V>WGImlI(e){2M5cJj8q^nuhVfwg;V5Pp)lO;l~r<~kcXSYPflv`^72N| zk9v9-sEsSxX=w_iuC8gyJ3ApUE7fUvc^Zm}iUtPiDH@Dbj8lD-_}!hNj1!aN<9!gM z?QLsoYli5(WTgDu+z?#;RR)G$G|5J_BnARnIy(3t9gPrvZVq*DhqRMEb1&myn$ImC zg^&;&>rcb+a)lEryiBR9t2>R3SDW`n(^9&eMsp?^CUL^P8V@nS%~wF&psz&b*n9*# zJ9GUTUxOW#H4kS6U=1+I_v%U%M3kvmdyc;PPrHr(AI(Z~#wWe&&bqiyp4{f6F*zI| z4yVzB{?iuokDgOc4>28Z+2yJc4=jIE^lOKRa6N815F@2QZF0TQgwI> z009K(0{{R7=mP)%o&5uxB}=w84wr4K%eHOXW|wW-R+qc%F59+k+qU)fIWzO#Idf<3 zcke&y7klr_SkJRoL`JTRl^GQ&F9i&O0ssI30AOy;B$N$I+fM}m0Psity$itF+}ha5 z-OgCw&d$o*P~XYi)`rf-#)#Hd-_hKW*4ED0#>m#t+1l8~iPqFX-_Fe3&{6&`gahq_ zHNo!|g8ZIv@1`CA+^;-m1LR?t!_xCFR03ZMa z(C=TU*YCLi0E7e*!UD=}85f!0>c|qhh(2gd!Blb^2V?rW{lOD5!|2 z=K)aa)!%o7XSO!wBeD+8)!BJO%E`$UL4-XZXb$8cg3ttI#MiI9omMi(Cnrg5S?jhY zCwDPnz<>ab0k$?!0RVacTY<@eoWSKlj^T13roZtcYCAPmS0i}w0QljxyWQmN5I*I5 zCP)L|M=!@eT%SOr2p+aPack;cpE2@X;_H@pT^G>CDmqxpzpy zg0k{`b^;s|8GK*LY<@a(kJ&}~Q^yMrmBg-jEUK~H(F6yH_~2vU0LJFdVYr!dC$}K6 z+_}t$;^FbMr`~PZ8jsf*CiUkijuyMQ1BK|&dn!Q1nz!>D5(Y|qRwUW%h;pT*4v@@X zo;zu(u;dG{!hi*SuVJxdYNDkjr6HTlnaRC^pT=r;8XCrkIu2YP;DBRRU`b~G92^w{ zrL%2X{qT(>ec%(E&hoeoDFLcuNbnvQ_yjVj`ONbNnR_f>Q`oYG>*QtYd|fAQ8}_X& zM_hdxgTA2s4sP2%K7QTea}(9`WGYVLDdo_o+LGn!%*b8Le&aT-4ZV?V`j|!kiO(3>RKg+5cOCm{HCW=@c|v#7`VJSEJY=gv=LXQnil~Ja$dBJY zfeS#y?-C#aU;_|k#(pE040Af#sa#8~DCQE;9-ga?6Tm4-WG~d&O2lj&;IAie4woMx zzw3X&|8jT>V&jR9kE2#PZ;W+&!j!W*Avr)>1N~ z3Sln8zA9~OC90^L>@b+WFLTVmW&i51G&m^a8`Pzai^s(BvC9kwsghCgfpuI}MA{~5 zu!rZMkCHO6m^>Nbt@?-w`suyJL=onR>jM~#nPYs773ed^?fkLz-ZOB+_ZnMEx)EtL~i^0YK6vA|XDXx1!Nd@?zAS2J_x-M1NkGWy{Zf%%HToh93sOhS!ae`byt zP0H%_g}h`XrwRtu5;01>YG`~dKu5>~-*|o?`?XLsTee`e7{WzDcij>}px|I^lCjz_ zUoh4Mmc!Kz++MojHZUx8(?sRqA(NW_+(l-5fa!XPYR17KSFPgHz|+7>Cc8OnY@+{O zW*HZ|Md0vyE2^bgxlL1U`r9_Bu4Pa~?P96Uy0cbcT$ewUa`w1`$&%@DEa_5MoLk} zn#-;`sIK?;Jf=ZSPi3bB29*EGWy&o5B1NmmajUZZN9+Civv-jrR9uH_AnsKsM-eNq zMr#+x&DKGgU>^^pbcY0Kr0L)bCrwW2%4@}(_zQN)_MT0^C4g%igfy;9$S>tH?ok%iI^;I0q+d7!->aZqJOfddtRtpshA5W7FR@%#ELHj!j;5M}(EDsY?;ed5lYDFy z1y<*t_Hi?+4RccyJ_Da{E0ZiAQ#d)~Fc^fB=uBMlFYDV)m%1Ktxzr(-=o>hRY+U=X z8AM7-0~9y-)MTy(9;jqLkXjy3t}E*5+p0h7*F#hI&c1BQ6xFgz>wg-m>G6h3En=FQ zvYM2?9%Yy`SZindDQwxYZV@4hX=})_Ud>d{)v-w6*%tl4j1CL|u{Vdrk%gg?C8n3O z9KlRki_KRSoi2VF*U7&#;DbV?Ab%!eo>d)PCC!L=>67( zB2m&-L&<}xjH7b|ACEkjxqWC(nDqICAlKCSlP)eUn?;oJn+8InVP5K8OrBx+HB(Y$ z(Lgb=L<))|!m)6W?kho7f>_%&_Dr!DhlXftfm64^6(S|!>$e~07f9?jgh>13S%YhbJ0el*{H`g)Uzl^U$n%4E>ax4#VPu$^Bf)KL zyu$rS%3-H5d!Dz2hW_2oLqDjC%qt^1)6+~ia;JQ^5ZVK>SP62&6rb9Gz%m6)J1rrP zrZ#*&67tNh4w)#=44fE~u1{``4AMw+t&ef!j^cTkJ|al*uG2Cw5i(T#k6m`@{o?RA z)z;3|w?-(0ir~Y1sWk7&vHVu5*(>B%%_joH|)$AWiSHJUJ)y$2S5KGHSnl$+A zaVIdU#b_h(nWQp7CS)t{iwLW@f)wpHKR?$EI7hm`W%LZM2=vXNYxG?cA=;O3GD;f4 z<2|yWnvy&>qUf%>%q3X9?vOd}{k)5|F&hti%Cth;Pd;|=l7>=xI_=Gnl+XwduubJl z$hw?L+pQbE$==Z7E2EM!u<&7v8!ac3>-r8hT!Z%@FcHn?j9=H@KPniP)IC0Z5^0MB z#uQqf`RV08z90JpRZFQX5zp7<^>(w{^BASE=A(Ad3ia!;g-8($Im#S#0ObU?V_!1O zIG#1*d#{hPAC9k1m7AlT+H2y$s)Fa~FU!Fa$oDgn%{o?kx^^eAwQp4~Lth48-zQ;U z7Y$__QXb1ZjVmY|8O?R33q)VMd!;RpiuJBb8|!#Z)6ZAa8=VBa>(K{!bcQo9?G5At z_qTh>OD411HZ0IQC*Us!-utpFz?X1#Sw-M%w3YL@{e3l@t3@wh$HXyOs#pv@t=X;d z%#J@I!!(V+^v-YqoFHaqzX5Q9{&@w~!9e^~R@#N~?=QpXqCv;H3wqE3$F%ja1t_Z# zB!}|LOxmHGmc=GzhPgMBQAlGP*E&ydUAgZuAg;gc{6$K%HY5{Z+NnZVThf7}F#$v% z8ZLX?ORCxi6|GTS27>NnkdcBkT>*|Ye}C?9OEOrJWPrQ(5PPW7Sw_sSK39S|p5#7d!TRymYaL`DC@zhT^aoFPt<;jX9S5q*UDT`Q1mNk;X; zEsQsG5c&5JbvI-j!(`Cf7M~m0np+O{?I%aEpAnBmgT!570tJf47hi73;yzL05c<(T zzn&Fyz3U74a}G1In(dy*KoFH`9<>`L8oFQ_X}xQwEW3yZ78SiJ{pF80_Z}1nY{gpI zyAwB?eI!yH=;cOrzBd3p`!}Ct<$E$$(WP~~C2oi&UHItRj-WW8CcQ)qjc)gqd4yJ& z{+ebHyW*~M`$7GytZ8$ib+7Ce#`d`J*#R`*JrbW2B5zc4mih*CLj(^-x3w!N`Zme6 zMVKrlHTb5gGSe+XHU-P)`_XAnv$V_TNfCV41fCJ`;=pDR{{$gou)-hQ@>*As-D0qT|!tGex75&%=J-l&V$a&iW=QK@43&mZXHk z-L#c3ev}{;p4QAfNou&9NzS4%18kNZDt9G{0BRPyA-Td;%}Rl~BgrApq&l=y~A;kOzl+$;)&X+n21?!oUl@I(Ab@vqJk}_ zZHafe!6;weKY6%9Lp*~XpD+UE%ehQ-@~iiLk1`!;tX9S{Kg;9_)yh`NVO=G4x0SRG zOLU}UTHh`4**DH~Y?$N;2vgeLsZdc+?vV=^?IMI3_~`%OW5Mzj{e zp)Lk$9QuGq#nVPId2RVu0?uFPgZiG^& zbr(j;I2{h}fZkkN{#yQQ(a1pv9Ed~?BL)gw#kU&HNm4Rnmtf#ll%Oq|E52Xd4=@Gf zjqZ)X`8mW01J+|;8DpNoX#O513?=yVtMaa0Rdo6!-}@2MlXpQgjz_3!@H-?+8(nzu z4_D`o%ldMuvptxPP(D}>Vxi}ZyLW+>b|h89(OL=4ayIeuqkfXIK?;;D-Ijw{hJ$m) znqB4)i9g1a)vHhM8(Fd~mtw-o z$TBK^yU|AfBeA%vinYo2?J%qg5GZrLs1Rv(t5(5`|V)~l~2Uk z*6&S@4m?LFwekHgiV`42Hnv}T`wy0dtjJ=Wqur-t9ll!Bm5MUfw_y78?3f}NV1XHT z3aiam+qfPJ2QZR{YZ;WSHrX7!G4YsBE}R!(det*JzwlY28CzYqeBwp(&Ny|gRo6LO z*5y|Tu5*Dce<>Vas}fsUc-#Uxp7KOFOGYSRc{X1rGUF2xzVW(INL}HBLH&&`)!t~SsYVKie)*J=GdazHmRV9# zM7y`g0Kc=e7N@9?M5cQLZD7dP6{Cs(g(ra%s$*Nf;41C7pSygr-Z>5sjo1nrbHLN1 z*7yPd=#*q|3!YG+BC74i1Y$OaDKEkqlcPc5D-05uwA$3bz~HA+s;){oD2>lT0;K35 z>#@NE-Ti6~0qm?N<5yMNy_$Ex1N&jYp%#a$xeU-7Hm9-DaH2`@XNxbBuLTu9rD9BF zG{F=^OP$|6123EXQA9TrY(9DI0blr`5HW8*y2iz=D%1+XP|Ub+c~fhXx6GZ}*a&~< z^K^H!6{C#lPS45KhHC9x(Q`WYhkD{6>zb%+vUp+mLq;{5L#b|xYwC`#VMyD}avGY~ z#s~!1(x`d(s668tyc6Lu7^M#}I^|mQVnPC`x~7l)oh6RQO6vsi@>#&fCjNkP`mW>o z86i^{VI{BcAju|@%UyO8SwiW(X9Co0RwvohcE3K_X}w9L`aP;bQB z!^wCbUIo_DnDJ7tsjKaU=A#0KPkyvh$`y>SGhGF3GC}pOodhL^_}#DfZI8VHl;Y7v zW4-fv=St!o6_yq2pH=xD2E-?;UFbxIUKOO>z$2Tq{(GvgRZh#1bD5_XFGFYixC$t; zMu+o8Jkd=Pdo&m={+F~8pG?0pNsFWTs@r*mBmesl{6Lb**V(l7(oQ6nBVTMb)~Q;AZO3nabXwEU#5R|YSwiH1^oRtdhPodn67htNOJ=+)H9RIdbsp+j`vXk7fOrE2 zT@>#vY{G!)T}}c4;5tn`bhafZE;CKQKLT{~wZ7c4775JiUYS1a9r5UP(?wL@ADYb~ z_&$Fe4hEqOEq5DKLxYzezl+ZB3?pJ8qHUzpOYgDyWQV($TytUos0i;gU9MjllzVh- zSUQI<1z&{3!!p&`TEJY#tu}|Y_lVgjiGRSx08E2k3%FW{p0`WL9erM?Y`5;-1h9A? zGgA|>4SH&+0|jr)$uwQh^gyQ;!oh&CkPW&Lk##ga#PrnJc=a11XzuhaL>kme)WuK> zyf5jYCnV9QpJn(^@6x1JuFDnSbI7F<|1u{|eKvF%uSJSgp-aJC-NEm>%IdwqltM*d zea_+1-7u&>e8Ik&<2Z&qlj08aO+qrWSdPqr>b9&vqKjsbA0T4F)G{kHq&H zb$b?~kIr~Vn{!W+1H2;iTE$m$WR#+(^_tuE`}^jsBWCm$GzFQ18IE~2QHaP z+BSK9G$yo6qe_$3TsQ4NRW@wzYn|0gP@!n3s`T^_fr=@Umw;lH+AtSKuyRf61z)%M z9k;spN#$?598Z!CjQXe{%V#@G(M1mjPv1xUj{CBeR0Oj%)cESI9F&VMSdFGyQe0I> zb*oN>iu0c=C5A`9H#ydF7@fVNmgl%?GO`>SD8#Q!`pOxGud+eA9Lu2llG+Jbkcko;A@q6{as(* z|8N6cCx-#}KZO-d@XZ}61%MlCLy_oo-EK3Wf3j`bYy;4>{vpL*b(zU6=<4QtY&931 zqvlFlQxm{CH3F$AumM@>3_cC^?;{p>{;_D?>W2h#UrjLk-NUVT9^iPH@kEkD8dDgG zurO)jVdPT!wB%Ef@R6^9LW>w|17@GoV_q-!SDNYH6x=(<0!0d` z)5r6*=gd&{K^289HJvfclZ(QPA6cnK8M;A>&>*d-)0t%V?*+vbXI(qLuH^eRlo%a# z8;flx=1`*^E5^OvNN>gu&Bh*l=z&6q0b1{Z+?}#(O|TC3dkh(f7H*NNaM%Ye#@V0b zV#3~NNrTJgnWy9W@kuJsK_EbLxZv$dW!uneOthDNG8QR~b5vnG)7k!z8*_ic0aSxM zM)9?>kISr*zZey7i{K|fks$St$f!>tX2j|UA z&S~d(GV2bQj+0bRo<`r?C%Ugqe6A|(GUtKgN~abeMvox6ipKzEfz~bh816&YJwM=H z(1zTU%LU`jO8!oN>_nO3bQ@|pbwZkNOwVDy5+QU*`$6N`mv*P9y4T~32=H46KGp;V z+T&6qjPcE=g$hyXtJ84ykwE4 zYL_AuNa(~}kG-5G2x6Ny6(u(F5f2!I@gvk+%*;YRu=>WyOuOpUw18*sGbKy$2DhRA z&DGP~R?z#`=+m0mINhcv->`J8O+)?qD{5GZu{6b&a4YK*jhFYl6zp_WU;Yb zMpJzp_iwoxM+_Meg29r71Ew!hitNKaJu;#(1v9q<1zy9@P(Ls~X>q~H8TVC)hyd{@b zw^zdcD~4y;=Zprm+7{aism~*eA}PkY84}=_((NQBjsar^yd}~R$1Kl++WtK{DHuw3 z)289=3r*(KHzs9Jjg-wQ>C9e@tS>MEP8Yg?kUd@Aw(tfXz&gaV52J|X zNpx{NZDn|#+9fThVO5^P_nnt#wKjaq_0q|xOY=4UT~ZHN`Hc3|4&>tJmW){m!lbGX;FW-@ zLa@1hiuxvHMn!c8y7`HKE27D>U9vCGkE{*?lQp^dY$mwYNcwX}_)f_w#7w+kXxwR? zeRFc2^q7*Z>LAkKFGj!1E(q9;eM*})$!8V7|E~@nX+y^xtOA$mp=$N>3oe75KB?|dLx z*NQB1r2w2RD(Jg;SzSMmH&stGOxL8)9tVtdHC+f#6Qmhh$dNHGxVng0Ufg%w4}22k zCi3cSq3NexGGb!~@05;aZUKW6(+CmTc zrhMR-D#B$aOCeU03o7T9q^mwEp;0`16rG+KR(1))Az2fD4mAVTVwh0I6o_~^zL-(G zIA_&L$Uss4rUB}>9yp*YH4?!OU8E+5U30*pWeES5JGcIggr}~T1UYTTvv%}Moi27q>Yvc} z3xFFU7%{#woG4D?pUH5WU492R@)d7%*JtCu!sF;8)TMINp7fsQK7w5<68?U1`d{9E z?a^^{lcv3v>J@Q4{toh9`rocc&wQI0dx5EB!>j$@NCg1^ z_#^*0!Nu4~pVrOVikt8E2fmB3gQK~v4G$p$Ej=N=v5ldvk-3d2521>(C=ELyA1@TQ zt%-@bp)uz_X1&n-fye(1wQ=P9TM-YTvx5!ipYvllZS<{;9XXv0IsbX04Cg;fbN;F5 zZ+qOV%xx@r2+f?F>^SM@TwPshU72WY9ZcyMI5;@y{w)26sFC6Sle2Snu=-QV$dJz1 z%J>frj&uyP40QjH{lmiltxZF6PFrM1+6o2LE$yIsT=#Mh^O}|09Bdp6(ABLj1pXn}6!4jD)=Z z=#_sQK3?uW52Cq^xs$p6?`Cl@)_1aX;FYv>#Fwweq_mfQB?Ye6E;xut z(iGuRLW%xEeO}bar3_}=<1qcU<9-O%+eZ|QdUgI5M_f2Wh+rSVhoA^qS9_~dg~JED{td)M2&SyM}l<&*0ZzQ>@mI}8~CP#VYVpo$ziJh3=q}A!DnYoKfU(R2@F3c|Ry=c|wSq&A2 zl33+#=sJNwIF5Qj4B=Hf8c*vlf_c`g!QK;?m|3u+6lht~+mIDG3hSe@t(OyRSSPi8 zjeq#bA}FD!kM*S4ph~EFiA?)OvXWSARyl@*fy2#Vf{;2VUC7ip9LNX0H*MF22`}Al-D(;c!IQ(!K(J^ywJL*{n^9%ok`fugScl4jqsX$fUNn%{uPKu!SvSPlv;-} zJJ$(qZUDCnxPS1+*)n+9Qyv?l#&HEDa9yX@?Dfq>I36HN6ppZ;pH75Y?waOpz%+1c zaeaYK8AF|J0-i%*jY#^3nSWBb*W0sSAKgnWb3jF+;^X;L)0$hOlW_>jwrkBVkqXfI zEjE%jUggkJ!CznISlG+Cs1YZ*;Uj??*Yrjdi|P1ke8Y_GdgMomBVuHSj&q^vCd_8w z+u2a-`}*YdC7A(KY3-6cC;L#Mi@iZo3UxCxgc(7k#Kq%)sRDtOa%dF&MtDTnx3orJ z5BY2acuZfCO(0y;=(WE98u2*wC!<@sw2t9W!ISow>;fspJH&6&v|Yb!r(i~QV=y=7c&Bx?H?Lk za1m+7a}!tU*gm3KWEEkB9p7{zwdr6fA#x@n{uy0`AKvz)+wBYDJRMsi3m~+eGtwx) zv&XIx!Xz93rfe02RUmomzNJ}qW6xt>w54K1c&2&mTG-BgqfTRIEcOo2e>`W|M615NFs*eWCu4wKO ziUa6DRzd1C{GAYH?ja#uv4(FrhcRwYmdxIqq8b*$O7hxA|20abfnXaq5ZGbbZ*{o1 z>ZZ;6wwozfdeIkLI1Ap;CAd{lbR5I($a~6uR7a@*BT z16k|4^D^10DDp2KQ7D~=j_;}A?wAApRZ1p5RSBJ?u+I(wI z9c&Il$~u{pwM=Xm7#_AB=jK8>df=OQaGk3g>}qrr79PjCV=-O}&a5}S+>1(<$beru zem**NT%r7!DK6XV>@5Fr3&pKdmY`7go%NKDH2*Dhq?n9z;n(8ghT2$fP#u;OOxb0Ad&~pYV|iOH=P-@lMX6S!*kGA1-4t0%E~F@}kG6Ox7qAwSPSwPy ziqe8dNA8W)d?-&HD^9F(h2=aLyvGCvoW1}^YsT-n$BtyZW0kWX!p;iKYHX_gKP3gzwboD}CKzS)}2!@QQ z3N{C@1!18bryMY#r4eeC)clz zGoQ0DPS4Dwj1JR7caz8QjE34hr~1U3YKj^_fNmufg=t^_gzGIogB%+Z+=Itr?0zNL z1%QZG5P=H=g{_)(Wod3eztYz(z}g(?e9;f_okFwo!Yhlb1IvpWsOyIZ@7LFgx}u7P zwX&j0TsU`dq(lII_+rXotmlI(^yi~Btj@0U)!M4c;!=9{rS!%7%pea)F6_49AFX3Q z$-l=>leh5Ac)RXeKPD8!_GZ4KK6r{?IZK`5H1h@Dj(QSpkSz^}=k|-f?EXPk9gJVzSb+@apgkgtfuMlY2j95MwWkDRmv8R-=__~n zB8NiU)=7E}%ne+Lx9I2Q&|l?hKv;1SZkQP@8cbz~h50za|L!6WmcEYBvL4LP+rN9p zLbx{y-ng2a@f}3z>y)-xEeB6+ThrKhhex2Ebd4W@#kG{(ZgeYo@bl%E4^0QAhfW3D z5KZSbn)w=$1*sJB2yEB&6Jj#M;+5XKKFK+jHI0`K-$Q8;1--qn$v2tol2yikf9|fj zzkId-HGJ@BVDM#Ctvs(X3}4Uu%nmw8S!gyKGA*k1gwUiGq_{^_L~+Bwxe+LxzKs2yv+A}_LJnN&eVD1)}sJVKKVta zHXlVXF=3#YVddEYhiq)_l9Yt?kCPLSC0mr!VMqk=&85pIF)<9Yd=HC=hC^#>@HUVFl1RN9a!(1p705oVRX3U!e=R_a0Tc(A+ zcsqp=iKr-%ov7!Kz8o^CI4=I#ZaY`m2=LWClPOKgxZ=;oC ze}QXnv>=>5kPj+#x7oqt&jm)Ip9f47i56i<I#NSG8x9kv+wPmJ@W%{8j;ST(h} z;J_r%i`>uP6Gh+fao-nPF-%wMbK%ipf5C8R3Syp6sM-1)#|1`V=WZOu?T_<#naPnS z&Qf($wyOk5hHl>Xr4A_`?~GrA;nthXh=qqgSz2%9I%!Oly%PH4%G) zl)1LLm~GA0DQD9S`s@NPDI+EV!;E-G~?#Na*TK7g;Fa!Bie@l^Sk@igV$8NwTH^ z!@Yw(MXrzTmvU>^a1UGSVd-X`U21wwLG=#&pi&}Lc`dGDW~FX z!GokQix-fMZenBxQQpH}ni=Hg^pOSN0t~oPZ$GOCb;J&m(c<1Ah>c21Up|lOsfqz; z8VkT>8MVK)!1infCz_F~P4KG|$cL@R9JQc$ZQSDifo$w+ zC;SpGotKQ~mK0rhe7#El1kOB;G-@YeJrQPk7M|{dB?{IqJNv);#W{4Z6poz4bM|oEvkp`4lgV6-6 zph!7Ubu|d`0k_C+IWu~q5b1JTKZ1Jhv%Zybbk!*2?RAJk$}RH5;fwzO)8a2laJ_6r zE#m;2269$2G7I+HA+%AM+``)Z&flPime_?pnn!Xay7S1qj-6H`gfCF$cS84MI!)T`dxKoMgQ$3vmp{knk4fg5%W+-sk0U!{<2 zbfsK_5RH^LO$OGZsW@=qmLL`(!?D{FRx!D-1!RGVTa>`1U{WPr)jjT_U&XJFkK&4x z>@(H&U8u*8`&1Aev=o6J$wx%ZPubtI^PO>#Rs>COo8A*5Lr!1;(P1K&#Ir9*u+(kKbG* z$~h9avm@WD!<8^3*(j*(P2URO(pumjk@EB(Gz(J4>)3j!--ynEDO$M!)cM@-q)q!v zB<5(DQ{oGEwk`wi2|lqM-pwQfM^HeLbfYA_8;BFC2p9#OL4hIX8=kJ6Sdv2PLBxRQ z$NVrrq8K3Cu;hE6cBUb;9uO3hq6^=oxU4&2Z^&Z;JoFZgsF|)B>}awVOQdBbaCZ?y zu}^$Tc|FW?oUme1co^i8SUhd~VGtqSD~Szwpp-?xRA`fuv~<9kJpghPupAd@Ng~N# z+2B?z`g!43gc*}ocGIKHp?AabQ@;Tm!Hoshn%z;y!YD%kI#xi0+dp0^fBs4uvw@GkjcnFF@ zjWt-dd=5WACFs~7_QILQvDFg7c5qf#Eo|>v@&HjluD>%XL{5^`Yd{T19MfGlr$P|- z8v8a~b1UNjT|~*R;mO+y$O1oF*25$7y*r!{D(wy+<+gkE_ zzHFplNX;$1&$$+8mBF}tc4`2K?dqu+V};iJSFSBPZ&Lz!@$U#r%O8mG*Zi@ok(gYj zSX^hY&op1SQtTFz?=$xM73`#BA+Q?@1O-e25)IU|f z#upJ|MQsZ9{V1M8?W>oSaspxAYo@Y!il~gBm99y}h8Vv-3hlhPc@vHtc_8twEtf}n z#pVEvySqK=0TtwFA1iFVs?SVQxoqm+(Pd0F;cN}B*KI;8_5HZ%^?^HPMSXtM417u+ z-r0CLpHuh@lvK+VB{|qGlhR$U>g+TIO6>D}EX)ndd zP8s?)21)SnG_*1;Id@w5qkm(l#Pd;7?};3Jj!_PoOTiJJrC5F2B5{tb3W3L^_ZqtI zTZpEILY3}#EY%H>4(X^QK|Q}yQG~Ck^t>;BT36vS+RyWZCs3wnGlyrW{t>tT*?S$v4M$r$1;VuS{3rG8er;#;@F=-3J zf8K5=Bf?vDY^XAfGEWZ%o^7&T5CKz;29L?p$E`4iQ^Qij76t?3v(j>YDd5yM-X*!UJ&? z@Kah`C$loN(Ez86rjkmIl7miY3IYAzT_{LYdkd0Z2*;)RexE~*aaBv&Yb(Tk{ulGdC`Hvi+v}@ZilkVrxKnw_@1Td`{E{45r6Djf zcsx+)yFmy1O@&wJaFdIvY38KS(P>`im4LhV^NxADAL4+$Fm=BGl{2cz$KuXLEa>27 zimzd+FD!$A)X@Nh(`xy*KzBs>AgdO4Kjw@mbzEOIebeN~aP_tM$zve{7%LoPPCXTPN4Y!)0mndr6Yn*gj4lQ=esKnHRd4HVMztH2@P zZ7Can<>F7DrcS$=#ngNSsNoE*!gc>uf8IF~Zc8M2_K`&PEHn=Sg9q^*VB&JlX_!2L z0wG5UPsC2KEx7}181C2}iK;wCjxHnc2-xW9Ow)43_Q$>b3I@07N0{@KHpe35Y1Qv| zB3qvC%Yfp9Ei8!y_m1_9zmjg>ko{kb>-Lgs(n9B0Es%iQdu4Wj@wC}91#a>o4>9CS7sK1GU zry49niuEc#1{;dm`sgWxZtoHfc6)(bxN52!3q0wWDA6!oB4^r=kr{x)zmrLe{1wZ16 zG9h=@(}ADEiIW3UJF5K!pf@NfaQYJk9XG&GN3ex%Jg5a{o~n70$!>(Ucui~)^{b27{Xa2b}Pdq z+}-?oHLg*SNDtkXV)oAXC#RyO=pp_?)@xr`7E(u z(G&MQwcIJjd87ew1cbzx8qQ({Xr#BoaOf>LGa;-yFje$ib$>PfdLF<3aK9sTsOE zvtgZ>GCWP061ocRNUzH@u!N7uqAoL_uy<_ybPNr&Z&0WIS+cz|?m5rwwH1z4c6KCA7QA&B-7nBYsMUg}v|{w;>ya8JCj#AxC%i*#kYOavi)v~c zqBnIPV1DK@GDHL6y8UznL2~P3qdjG(RM(_B3#@GRKzGI#oyMj)Aw*(iDpZM}(c)eY zsc_B@+@fJ{Qbqq+#u{6fiIr!qm%3k$qLJaAQr{xuC0H@2+=Nknnnn@L+6%gbDarlTRa^hV-17>qX)8{R;xQRWb~ z9OS8{%R30l7W}>Xo6nq-cmvm1V%Tt>hW$?Nfc$Jv)cz$qj(4srqm*U)FR}iiz})ns zGs6}ZODq2EC~VQjC@#RYYX$PG{`iQ<`nB0)p6{S`tj?VJT6^1gF8;K2U$;Q;sVmKH0YV9R%{M(1MDIY{yJ_&wooJNq-ksc!LoweQ*yx$oHqda3V z=X3Nue$9@Ap73Bd5(*)Fg_(8jBR#s5FqWSYa8v$9s*R!;Qs_yy1hwIBa5mSdyp50+ zB$|w>oVq;}^QEP6Mr_FJwBC*x(}lnRU*-u%2vI(sIH_M6d?1Cnw1Q&)HWKG3ih53wb;?tcz}d>bc*k`)t=`~ zbZEQsu*@B)?5;8yzus>95J(JO$8>n#FR5LPbmr5q3nEEAeuito1UbP?vTfL%qm9^T z{@13<%&+isGhsg1_w8yt46^4*8_w%oi>*-1^{)#fR|5RKDsP`@8rk>h$2sn>QXVwnA&u1WYbG~@8mTNX9fMl2H*^$;F6Fp7ist*=2((g$qq$rY7o zG~{PVFvv_45OgUZ%Z+A;AYZr{1O8W%hu9e#*Y19~#9K`F$;fC==LJ@c#x>en1R{j#LFFHBCg_-+X-~hp$Bm9B z0+AaEwbh}XwTg!v+R^&OvQ!7ZOYnsfn(<2Mhdkov&;)Jmy`v=`7UPZ%41ihZ0LqDU zNihOtVDO37)U4dKlBYHXzDEoX+hwyAAAago`YuEoxs#{8jJ1+tB#=7DZaiom&HhLO zeU3(+GVv!DFkYvzn|W!CZsB$hjAx%sP?eM2-=<;B7B<{*(R^|c3*C{K*?S!ijDdOE z@-XkUu8B(Rt9n-V(-;>XfRftnB|~FDAz8dGpDzt=nT8$!7EpXmpIN+>;i7sB^pJun zi+5oe8CuBc?$w8Q&{-D~A?%W6tksdEbLfTF#?4`-7|)#I?=-dkj^uH^3~=P(yVJWu ziB?QJOOmJ@>c@0~(65$w4i3Tb(pW{_z_BGnY^N0c!mvd86C30Og}6PxWizM9_zA#r z=jXs_ZvO+&fKL>_;VD#T@voE2{kXVbje{iyCrX_%BPvZv(O0h~3$M5zg>*F~xi`J> z@m+L}=v7r>LSi7IBp&d|YnxrZw$`TT9K4lO`;4JxUUlRS)9>I|NuI?X(&ZPc6D69R z<3*jNowm=oU7MPV8TY>wuxJ-Of6i`Nv1nN>i_-fIBE7B!A>8*y#jQ!B=|WsS|y7rkp~vupYT113?nwpR)*av$Lz#n6}SOoq8{;a}=PkSA?EP zz28RSql`R91s^n6ka3r35U5T+J~PaaZe(y0aMk=tjke2C1o6lv?UBj3O#{h3TC6X+ zc%Q(~G*s}b`mMZ$ZfgCet6ndC;w?IIqKIghhD=C1FV?k4na$b|Se96+cgT(!hohW2 zbO~DBP&t<`C#idW2WhB*R?*hNm&LZN9s}qrL`5iQs}CtOdp{r4EBh#`0b>6~=f-uK z?s#-_#hu2Pr}!hAwWs7*9hADg;HU?bv(QaJV&Emk=ZhIO=Dbq+(nJ{?eJ9~sh3{#P z^7R?pE(ije>m#9FJl|wW@XEv;3^TWV;-C*<2c;z4q4MM4$Jz%;7oWrwj}PUk78$U1 zxqWl0`|5To;-cg7`umXF$4IKcG)Gk71e$=x3oBcB362A(uCSY_5K&5S)LxNPHJs_< zf_B&ZRI5UXudMZ~+6IW4kZ9%>n~kG>9?X3MU(%_omT3ZByf)sTGsW8GF;5>uq;_|S zIiV3*E>%|_$(01(+aQq^u5?cNx3BqT-Tqq>!lTo6O+_c7*FsA%G}4Ofh37)awVS(ssECqWOLmc`C_Eb@tU`tjcpQjudR?u=7M+&;c%{)9ER zzwJU{|H%|aK?OB}%4c?2(e|8(>6G!^{PA5Px@ud0oh)BlJM^Pw|w;7e;RQZ znqp-2l{K*~-1_K69rmW2OCtfa0y08pi8NXD)06$mji;Z)O)0P3uIh&0rXoyUk(pBX zUGa++=({=idg4+x<0!$n8e7q%>~G2#)V5iNjT;qSO*UoNgjRHY-X2C~cK650?Dwx%3*T zx5YhMuvQPQP3p(bDXzHIU-Mq<4VmrCtEM%{&Zq%01#e4m^!vkE&c+IhstnBhg;?i- zj8Wm6vP&Qu6%a*h&&AaSIai@j@d&(cuPBjqF(#Ybl4~xY-CfqrU1?(~28$S%l7(f} zHdRwL4Edi{@dA^ZWm&+-oWR~c7kJok*DM-H zn}O*bWB6#nmlr0+&<{64b084{Fo|?K>~>JnQ2C%MLDis*cQgcEA{ft9!0CG0@oUzI z^$15gB`$VFX?|XABl3Bm#TaVV|D>E8Ea`geO|SElD~p{ut8^kI3r%8ivFR#aI``&B zhKV;?ALEBs0Ih*jv>DH*L{1uSU{s*a zDAEsagd7~pZKt=i)hNlE-fTGjq@Yit9_QSt{z5D0wUy?RSR zBY+6qO@Sw=qepS6tJ9Hlj|#;JX3Vp?DKozvg7=9#N7z-v0+$b+ z@Xc{v3g6qQjo7!um&H4`c@%r(MdPBSbCPTa`*wDn>=|N&VLgCdIkbdjVDw&nkogUM zwv`ah7S#O%6)dPPr*tN|ulo5HdOebVXfKZIna&|B*F%CqXJ((FVGtd*j&LkoN@V5G ztPt5$W0?Y@FL4+zX>5}lMd?Zz+$7qb(gfYoC$u=_Ca4|)nV@1H*lxBx$r0yUdaF({ zk1U1>bEl4OaT5P|A}UGB*AE+aE1BjtIgABK{C?*h(mW5P1nQ$V0LJAs9SRFgy=Vje zVefUfzRQS$yb}xJ^w(hbB=tU=+;^^tW$jAd2co9_q)whi))i;~{FvvfE`U&)v3UQu zVMu4)E8A~?gDc*r$!s1+ARmhZbA$diDPkpf<3KwDb8ZOmzs;aXAWD-yEJdEi(swl#kqsKB-lxnJeJ5^yVp}J z#ht_^VhsfE(mz7kn}3n|SZ?e#GA;96eUMGJ$3!!Z>@{suH>@4k@|5aMHh!UkWTCut zF!{CzY&FLtkw!9|y;b?D$Qig_r%l6MgoZ0<-5z>Ik|#j9#p|c*4iE<3Ch? za3-!tze$awdMS|!lzn+xi(08)2u#Wq%8$_zVu}?=E(NO%;_aI0PTFKPUS+=&iQXoX zWwEA+9P^y~Mua_2Oa09@IcBTltb-B6)j~WZHE+{fUNVTR)BANMXLW*G29mP$LSk!M ztSgmZWUg1$@{NFh370RoYQu_;)7mIJZ_LU8NO@0R13&sH;& zr0XHq*HzVEQ;kYb!_{xFbwQ{_O`Rq$Ro zc~lv;5=%gkC~pjct|eSzvpVUno*vBT*LN4FsnHIIjB2PVDl1=VJ*@6RM@6dn`xse` zcq2R)t#@HDF|yuCWG`-mb~n{#P3xeBW*Cnf1qd|8tv~I;RxcW2-~uZL z7D87$CR%yUDJ{6p$EjMk9G9=n%y|m(@@jRgyzcP!!X@;$?eDH+psJ9A=4`;}T=AfC zPK76FC5z4S-7Oykdz{4_ay%KI2}TVQ!w+tjIu$|a0NO)xE54_d%;|l8pxtaglOnek zVUPhkaw(s@rkjWidfQiJcI8_ov?NKvL=<${B)Ke$b2@e6F2fJMKSV700;?W>rSzKm z=GxlEriX`9Ffh~%wz6T#@R7S_{^Z|oPq1wIlD*W5sAUen-xYJuFE)KmX`(Ec$L!{wV(PKu@X>(}?bMr$V zdUS4DN0pt?+k@=!srC$IA~>sXxXk(;86;fk6O17Jeiq#d@|2nyqnT0A=m!>RS57hK z%eRj_Fxd*QmT5A;8Icj{peG3RxAvJujT}$Ugi>fJ1a|D#(pC4H!JksnrYVsJ9=;1Z z4trkex3sy=XK>I(;1@~pkK!RUaasCdtxufUbJ)h6wdrO_J?V4WxI9GoJbP2Qv!4Rr z2sn}W61c-8xG$h}I=b>GXjcgiBQ%wWIcE+h%qaRJY}gEKmv=un#I6*{^uCL;e&j>H zv}c0)<;;tBjhP``r%e$_Q*{*vo5D$L7VCk0Tx>uX+p8iPARL{wepm4tJeWQxKo;?Xd z8Zf{V8ist!m0l7EX_*R}kfCYem&AMf)mwtYV?;CdSWb>`w%LR8FzMGL{-KGSa(6rT zvAKWU7nkf^tR)?6&_Y+QeT0{ZvxrYABTSw!sM>0b_l}=Am=N`;2=PNXqHA)ZfR{=~ zNMjf32{l6xQh>AWPS5;>{*)`av96TZ%0IXVuG6#SZFmZGn*R*x z?ffL0$~0)OLmCzFiZGTc#qE*1Z!NBAtVvMoRjC+b2LpAkRW@0>N#vkc+1gk<)KZEs zbQC4dvc$qiDgw;)@sYdiz7drSt6dU_Ood>efUueOjt-nq=@<_|ebxPG zyLNQ^m>fk3Yu%N(&s)ZHbc6*44l$8k{!=)l`J(LAQtm})hED6d_QNPQrMXwDbT-`) z0b?*|CCZOWR0yj6Cw0--ltlZFq}+)~#?D$bDP+*&gNs{{>hmAl^AA$T4Lt95ngK5S zV>agW73HxD-8bSe+Hbu{k0FslU4DC+iuC!@_Z-5itQl`-&4n1vFtwPtg?f9B=(~pg zIIO96Db_Uxei&y44m<;=*|-Y~L=ot*+H$NPm%V^w+J@FBm2i#ki=-8fG!$eRPIGo- zBlaD}H(ut0%vOeblmHUoQ|2{Gu$=(358{M0*k)PDN+DclnwG61sA2~BYmS8=){PnU zdU;|ZUiRMoLjg zSpZ952Q=*!PISs%eGUX15ASkxa!RBWNipk)gY&#`APxTZ4EBi>^Ptj#CrOz6b0Tcs zR%eA-m!ma#rD)s!;x3<1qr=aE!6;1ZvV~N3{U}C1#Eiq`A6xF+%UOOKqI{KLQy!wj)Z%gsX8a?2&Oy{Cdj7Pa@<}%6vMHLvgr|b zyc#ZJ3-n0mAocnENY~GCbvUYIbnv?B2XqqZ@%K9HgUnpwTOuQW-2gh%t`jrj<=%A3 z-Mw(A=Q88We(z1LnnZ2>OwR7712kb3g|af9 zhhv40qk}x%x|$vE2W0jDOz}>P^r1KaUWY=IT*PS%IpcVr?|2{BP!4dPmo^vkh3HB< z^5x{%VU=OAa$Y8HKb9SjOjidaJ-%r>l(?=QGF^RR5;ENJJZx@R{oc2vQf&|&F)hu= zy@hWLLK!BU5fteY4zB)I8wlx?TK&yV;zaXnT;g{0C7*7Sr^>@)6}tsN2x`|q3^Or% zkIP+9&eKpD-nd0>)eO6R%p|*!?8|bvtkG-a^X2*p0`P(tO!$<>#fG!&`x;A=3pE4^=Z!xL1 zb+elS$zRio|GheSDe4CY;%=XCp~W@#{!aAKvbz-D7JVSx<=Gd;M&->j#2+ zyacX?)sM!H_svdR6%QU?Rkjr32nui4!rCyiV#&)3w#&hdpxRfCbVJvu*8w zA9xzYS0oDG?xYNIKgUE)RmL95ezfzkSv1GF#y&r@66~m;Yq_QNXd*AlYYAK-rHk;Rc%DD=qN25N#NW?U(oQRh2jc38 ze(`*vP9{1_G-)gmB(RX1q=BT76|Y@2)pL(tckRobD)Y?xnSGn>>_RQcwKznQvvhwr zAj5+H5$RBB^8&j*{L2ZSbCUSO>m75UmB35(DAvlD+f@nA&0X0dPNB;OKjF=hyKhY- zeu!XeESvYz#>xrLLSP8?)SglF3m7BdqJGS@eZ{JBF+n$#cyK+E&i0$3>3h`cfZ>97 zHN?}s*=ck^$5S!!O+tc^hj$RK zHUFs1X7SyxrTIwdIFdZ)0jut&JkR9tIT0hymMwRoQ`S%qOOC>#HtvK9-t-M{Jruo8 z95iTnoBC4xCdf=%k9O5-eeO*7?S~f-{Oz%u_S?Cj`E=*J84MPElAC>~xbbmL5T#H$ zAH2&~p&IFTn#;0?G!#}fSk-1;2dMV+1~mo@!Z53EJP&AV&Ml%AsL!vAdPdZXh+R{u zkmb&zhi|!(lpA{u<7gi7G%0x{~Mb}HnajHJRP%=Bnr0{Bqysbhj zGl1+qWInbbwGnubnTiIYbhBQfxSMmXHZ|Tt>e7*t`f~@wfR*J3k$@=8pq6`{P>&l& zKlJGQj*7*I4>p@Z?_<7buk*y#FXR~yFP9ydb2%xBH4Jvmmk^5d$a-@UsZ#E3h)HFc zk5fRey?A8<@gBtULWJp?-B$>J*)-2Q8M?it%m${yE8UhY`6W|ncsTIb#;PGd z&DZ44w+lxQ&hLZI3PWDVF%Max zh?y7P{95;n!BF@{%xre>lf|b(2F^iRq{LVR(&CmY0;;tWwiD0qG}3Uj z4T(j!Mvdrc?BKvIKhj!E$dh?m6IEUlA1rv-9K`sT&BtLjS_oyMlSy$Ai65@CIJ5v2 zW<8wK9=9$LIoV1L+u(jwu_|yg6@Vj9(}h-?GKe0EPpJhUm&Cun+y$E!tmByojbWJz ztwBZ?zrpzvakoqEkPKZYC%^uUGuKKWFBj(y+{TE1&G#Z+n=nK3vjY1IBm+X*+zL(% z1F-!gP8}oEXMETE4k@-&8X!zTxgL36ELW8MHt>aI)4z>#G!}YkH4&ejOEMmR7n!RI zLgPG1$zsF+nkd45}6eh};E_@_3Qso+lh*EZBTs1P3+DZ%@YO?7v=f1n;+cPm5{gD{AK2OU_;krQo29H;B}ih3R5F~CLbRx$5Y z#_#kHfrp3GKHVbWVWI!XEnLbpyO@$Mue6zq3w(axS3gYG-!y5;4i!aLWf57-Ld&f< zo+wKEbbTf&7Ov71OV=F!MW#E#bMA0@wjyOkimxdOkH!^ERtTag_4_&<(-}Z`Sa}Az z;5)<)#LhO_CRH>VvpP#tQZg zGFvb!EB)6Fm;zD^6 zQ`FBdfIt3E#~MerQ-%ou0Ezj3`ad1$-`UXC#_5l@Hn>?^UFfXDuQj83PpMV2GpURa zuTxl1xVmz;Dvf`68yd%4he;r5#1VfY4=FOir&L`s%BQ~Rt z@qj-8;gff?dO`r3!`ese9*eRn>m+~QAHR>m1rZHilupd5X?2rKvkvSzl~$jh+!kV0 zP90rz>hW@$_`Ur|zYL@DtG2&5uN4no#YY@?AU1rV55&l<2o)YMf_H0pj9SVht#QR_ zKDuzwEf;g{MA@*#IB-LeR%6Fc!o3m5#oPYZB#k&t#hAX=}xerGUpARc8-*pgMx9=YS4E zbK$^V^@N%5<0e)VHI2Vd^v}sCj$&$u>*Jjt-F|9rXrGCAhx`0BOe{roe zR^E4dDB;GydVIma5`JTBA#f!|Crz&c{h$5pRDidk;DCye8mnfh!2(Ut`7Oc6K%Tl~ z;!&U-P$88Hsk4~~rK~_Gtp&$mrb^P7)CJjgyh@d?=c1*?})&oD1DfK1Q#YELI#z8JT{Cao#s&|jWB6xh8 z`oCT6{whgo@OS;H6TL&h%9a2bwM053`Q@c0E!aFK(ZC2;Ui*`ANktt+!dCCbtap>- zGn4gI^btvD64{GibRwDfrn#K>JD_oema{*0DKtzxi9_T*$ahW_19T|0Ji}Gs<%CEF zM^q95)&O=P`Xn=8ac}ldX_P#6!YHJ86!?Pvm#-kg=dzNo*JN#h*!gB%6d>&Vnd_Xg zRt|?g&17tFhVb64-!3o(8|WR=U{)F_m(q9+OUYOvAZq2&3lG!?YbUCI@vczGVnW(2!N1 zey>ST|3((d=ktbaDB39XpI2l;VPR*XDdJ#f=EHVi!>%6wRQEU@ZJ1U zhSAOi*c?$OO1J0%H4xQ53u7SHJI1C8} z$CUc#;S>8BJ(R+T8#E*)uem6(j4-p(;+lT+AZ)d{DHIqU2D~BkNR>xDlyq_3J78hm z5fT_59hV`#@fNne!z}U;X!7C6+j&-6^Zl@xgh+FCHrc@Z%=c9__VO?!nH_MNYsgxN z%%eB@2u*ev*3m?)i*RY%8KHfirG>KxQ}$6u%T#RzBnnGE+AhmChw-pB1FC`P@1ikbu0UB`%^ijbP5x_pN-N_seTGa8x2M5dQ!>$u9r$x6b$L8{A2^WednTSkN^atv`2F#La zc==%XBE*qF{n&&3Q*@2o1i2nMNsBvH{@eUv%XO~T7RE>iSl-(;7uOu!1b*~|zc-k> zyTDCnP2yJ?tD6fLv+DlQ?Asl@(z$&lK;cV=f11t~W-U2FHw(el@e9PsKwYUcX-tGej*5fhw;zQ>o&a}#1aiv2h zGaxMm$}7XKCP|gh%hNg>4|sY2$2_IYWxMCj&jXEN&eUL-1+O@?S~;`ak;wY#VIgVBJKvYR-(N=^xGZ6R6Z$cI+g*--lwx&gwyD_y5+kaf(3$l&V&5zYlsQtQVHZB`OmcaKo;0qUoT zaf3bQfoTyVfRP8O0y)7C+mQGHShK8nVQ$!H6tz&pZb?D~D@815zabQKgG;!4d%?G( z?U6|g$UygDokrF9?Ky_?=36*icR2^Z9R-e`ep$??I6VKY@8{Uin@c^O(rG$C&oOou zd%uFPMT9+eaE2_@gETlEOlwLm)`DO->Ce(jWhn|rwSE+J#rh!Lw%#<#Nj~>mLUjR> zaD~L0Ht`n!c1dk%lwfCFyd4j-<9_jY{dkv(iMWc$GLQNl$;pjhvLqxKGu4ZsUh`6Aj)hPB$WnwgW?3)z&) zrj~n!P$@R56kd{vxZ^cV2GY3^#Tx5$pKPo{fU8gLxN7}6QT%fj%_pSt1+z(?{2TV+ z3YRo?c3jpAoF&mOx2t13`it`9s-jHSSuX6@bV6BDvO8kbn3HI$wb{%o@%_L>gJa}f zf?-fs)B?q1!d(I1Pl7`0JPYCN$tDZjQBZ}Muw^0MfS=+CNiCZPHR=nt#0j3ixVDV0 z<|Ak1B8_I`(xI+ZlO`NVRk%t(Y+)6Q^vrV4BPBqcb>Z#36kU_?Z*}8x1_u+S@XKeO`#z8Q|0ao8!8c3h`tnk{ftw4AmkRKl1Z2MZ2@IO5tdz^i$|E39?II4SijU5 zt5VFN=?-S@446aH>5NeeLC~?97Z}AanU!RiMB2`p*R1L^nA3Dh%OUAeFVwz1X2!I| zm6o151MkkyRo>M5R$4?U&*5@krPa^)t_pmuo=4ORWhCG-k~}b+Sf%Uy8d@$aXt6`f z*>EW{(C*;?=g2;9f942)lr@bguRiU9lZ<7gA$!bR!hI_Vdyn8?Fociy{e#c?iIEjVG*8NpDVk zXe*BuEaTX+L#)HG+TjV!xutE(Fv}uy);HmmsNZtmrwtq-1`}xTQwxAFU;)8SS_&q) zfkzLG`r$@DFvlT&BYzt`v6A1f^BzaoP5H%kmp+{6^-6vyruuiJ-?*S6qfYIunO!42 z#3E)R10VQ(YlpAM*8RQMU@H)U#3;`frW!cHm%IAjOo^&e>|21zUGgfXqapY{IInN^ zd}E|$Os=KzSqSdxglap!J59Yqi<${ln}IH?>NbHgQ6$@*E9-cr6ZN%C zdG#Tvw9ZXXENW*03<-`1H&t~WxaK-Tny;p3iQ>TMlWW_C6I-@J&4cOK!7SUn=uYtt zm1GZ$8qP})Vn^z|>0GMbor&;H&8xYtT4DP*t8i2Z7?qb(X)r#LdbjpP%AW52sMGtI z3)gC!O%pJ^7zJAX$2h&KjxlbmYm)o&*LqvRIhOz`BAlmFJWnsR1;UXAo>@2Boj-7#*2Qh~ z2BvX-1=uDaSr5lI*p5RU2bJ6&y!z`=^nz_c7C+*>1ln^XRth2&Ol(=qG|f625uB&m z08U4|S#S`#)+7D1-_f4aiXipuq8sJItd&NQbPsEI zz@hP5sKRp6f>IH+oHwUOAQdN7@Yt_>pIBf|Jb*D9DBWdKVLMWsWf}_a51=b(`dgoc z`}^Ou%IY3{&;kNcfBaO%I@EjKScN9-A%-En>#h_s88N92G4Y^*4V=o->yV@D;X_0* zOl_s}mT|ll!+5`eT9i1~P?R?AxyEgvPJrv6oC^>xP2QHA?8bRQWQezQ?uGiL)+3Y1 zQC~fV1y`e3VpmCr^1!KX2rVp)q+NUZ%1~no8RE8H)ltzcB1u$rSdpbb(9IT|T)TonVl%cl|mn7we_ChC*V9ODcvff;#tp%+P>JVaQ~FD3cn|&+O*y+o2}} zCWqVPbJDImm?M`OL;nLYt#~0n0aEm|sy+pIRDZs80|D#mB`t|pOnyl8U`9)rqctR3 z{qTJgf&g+=Ag7n>N?WPnSoSJZZxPy9X;DO<+;MpxV9?BqPTC _RCHf~UrMbWEr^`d`&$Ox@CS~Q9 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
    UazUn~^pMaL_%4IclH*y@W6V70xacT|r$)Zf^ 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�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�O1 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�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

    Rs=Z?bkK)T=S><`$ZUN zLouqU(b3h8tKg;v$=+9=*+53=FooXpy1qtn{b?Am%9%_5p_$ZvEz~-K_Lv2D$8p#Y zE}UU(5+dt+#ZlR4kaX2UFpn34TDoZ!TRwTzs(+Cs<>vi$$Dy|Z z&J9|Bei9*gMZy6JJ z_;33T?(S0D-QC^YU5gYM++lEcr%>FATX8FH#ogVC756*;+;i^DIoZih_9V~n1`=M( z@0qWxwLXv>Mxzg``i*o%`{p2-83DZy1&Kc}w5YTm?fd<;s}7zOH8tVjOE;t`wFOB*S1+A_*?ttb`+87dt5NfcHAeEav_9U6wQ!Q9 zna{G1^RnprcHsF1ZL`1yEy_L014K)bLMi4x;u|W9t(PK|MVsS?KiEx)XhqyEA&%P# zl7Y&mVPb*biP0=azw@y@Zw4^OhCLl{$q^<)jLYGOlHWMv7-)vF6p3S6k+7S-L717x z#?mTCc@VlR<#dqQw0$|Sn3Ri5%xQI8eV|Ku+PN+qs0IP-6iPXqAO5a(&I&b-j>@(1 z^WsHODO2Iz`00|{niAgY|E#M+yX^ghusxms-R2V%VQ5o!eb|D$Nv2S`%UvshBFm5t zpRyOsp@q(cB?B5IiG)-5$!r$IA=$ivP&Q0+6_NSTG3C@+BM{iNKu%VmMpsl%;w!@V z?alT3)bQw`YZkvHEV8T@McL9xbN|^~=BLYcpR;?M4CRhf^fazMR-;%78%$4SYy>TC zLTI6+mcQNaC$VR1x@$FxkX!f9J)g2!lxnO^1^b9U52%-yf}h@`u#bX#q_h<%Y#ygA z1{dSi)zz=Fn3(^7Uyp3FIIIyr4?$MY$TZMK)1f@sN^f}38atZ}*Qi-8@6COkKMlL< z@4@ySw-j@$E($p^rc!iqHdYea7rx{`P4ppibkB_kGYHhu* zaa14MOG~hNq1S6PAZZGWWA}EZyf0s5s;8%Sxhb7w@s750@^gg)7_L4`lBaaU)A8vl zQJu02AhM$f7qs7Y-a*+PMVZbA^YJKH<*WTJ+T6pn5oNUjH2dKrOTw-;6V|-FA zla#r>*PmK8_K_e6NnBvYM8(e<^nDS{s`4U1_MR=!M7a4oi=FG zub;x1nQrJ&{^W%)asUaWBtRH083a7D7$mv@2%4-JfFNcIfeD&{qyqf^zrc15K!y!9 zDmQd7tkJQF2!sn2hlhpSx%VN698jNKUF8?3f&gQJOgucMWN$xQ38uXJ_CHWb5{X`3 ze0TOrkp$^u&TL@g-&<@zyOP=$v11@bUss&7sT-(>EL7&iML~sB| zfDnkM0T9&=nTa6Qo&_PbEm2elI{DAfWWy*L011Y!*d#O69>I+L9OBP!KP3U`oZw_s zeV#MIJYmlI-n%5D;VI$tTrOH=7FF1c+x{8&7O~#;r%^;>2w6>fGcmY@5alVxuu$g(yOQQ zGZ>#rwsv+eOB)+$-&)s;8E~+~if1QzvmaLN?Q0KIkJu@4X)*i2ROqtvFW!-MS6raM zhX7U+^MEnew7g92WE!pnfkVX}=8SJ~L$1Z3u32>ih@|Cyw!T%)^p2CW{jrtm%uqNF zRq@_$c#~H5>kevN%y=9bEPL|VF{0+*9Gd4mJUqg&4}nz3W?Y1hBZ>Kwq;-5bxcpsw z`J}=fw}f?E4&QA(CeI;0;H9+5tXhMfK)i&F@<^pamAD~GORsVF8R-DEXo#dv|DG}1 zM)0D;;b*u7L=wS??Pb5uIj{7%=nW}}bA)I!IyW1L*J(=ZG<&VB=S$*x*2~Mw@7>+q zK>#>B{RjsKXVdtXL%WCxQqsaWE=}E%RgHmQ@wvCv4C=z@`js9De(dqFyFl;V!^2;f z&P`J+NVQ5Wd6PP?FWKv*=*K_P3rmKq4N&z6#H6_4kk$fC2K3ra~*^ZY8p9v`FhK~F-mXF+}znA}w);ZTg zHNkI3@4voOBEbVDi|vcdA~18{KS%7p74Q6iiI~bh|0`oe&Cb%@!}b5VVT{2;rvF(y zCbHfCd&4a1BdMh=z|FOd2B0{Hgof-&IawZSBR>hs({^M{}t9fY%3FC`ibJ58DR^QLoz=SUe#4_#hdybr6$`{X7N z^J@gW+?|Gj8Feg)P~a7+=F8jjZDKqjcg)-Sd+9t*J}){}XA zX;o1nPtuX4qvRqetlF-l;K>uh>nXF1hKW%Hr$@bWz@)tH+nUxb-{z*K+by8?&R*l) zU3R^suQNPqSyB@E@6*|Db=@kV5ekM(F8M|*#eIEZh)77qQBgobephT5=%@MM*6lL- zM3usnls%`JN&s+qAK=R4^ydC2x4r4!x0@}FoV1N#cVT{hz+@|X;uWHAdO9;aBEmJ5 zJ`LR-8PJY63B^}kRTaz2#gm#}$13Qu2dxTjfN^j#w!ob2%Ih`dL?}J*fb4aZQO63| z7X(hfbqT{D|Do@6$?_v3L*eGeGHE*w3L8x64s*&~?i>lhs$T{zdsp+R?m{RM~l-SP2q+3sdW4+Ji&^YpN4w0$|Uf!9qE8Z~IE}lu9o@{qmpBr^<2KMg*mcV>A z2k;xI$`7Gz0Rchvid<|QoNzUbnFhtlN{WygSMEk$#@`YHXZkoAU z%7{jprmQ7p_81`wa>(hg;08PZ5g~ACACLrYg$YN(?g+AohMoz$uk(L8eLal>_4p0(@@} z%1YB%Cne;~=(Wo@mHkL?#l_`_hkKHdf6VW&ILwT#PP6`L=BE6mtEC0Ue^9#UPAbaDv!=xRZ3EkCOFF13rjRz>%g)k>_mY)H z&VKyQACvfzUYn-X2&&3nlz5JcnYr*vyJAB_gIOrs_En~4Wx&Eo02o_jog)yyAh^&G znVDuVy0rGEERvv&bS0YK*x}D0Le~_AQf4i_p07I_D-)d+I1tGt>_|rF!_3g|yA4EC zc-X7!?B3A)W`L92o`{HmKnx@V;AV0H6?LzRE};$*?X4qfQlYLv7%9gC759 z&yy-%aDyU*W(E#=x%z7LwYFY=J)4LmDmoUY(clasfmBpwBBQiv6K2|N0N(kZc4f9n z<*qk1t49698AR=AB30@q-_d@}@$++jeMyN_0`@C_g!KkxxOH5^0i>0;2C@y0r(T#M1=5MB%A2?XREO?{W`{W#E$VGC2w z{iITeQ!E<)$-uzWrNC#d&N+%rNO6~Hn@>-yjQZml*7k1b;lZ;N{MZ<@*gvOGE254J z4zdAuX4Q(zX4EQa{2x|r!WgF1h@Rq!c;Vk!znw;uizx_p}+LljcQoYhC&QH2Hs-!7T}A%vY-IekI%9u$4-gqD}OiAeX^!y z&wZDoLf9$<4f=z^U%v;4`{cJ>xCP9tsD1}W>fo?vS5(#(HtY{81T@%Qg3+2Y1uG;% z#Hx{cP=c%BdsN_gRsZZnXg;nb0eCodKLRFN^g^A)j|Ph*LIErXmA~`U@G&q%Y}VBr z%45-@OGNbZ1=ih>v~cn6x5uG{JPo(7ZLF_Ht~y+tq%Y1$!2Zb2zJUYiEpKf6B}7FF zBjd79Nugn=VyyDE(4YX1$|HV&bhWi9)QQ65{jYE4=t?UaAQTp-AfZBi_}1jiz2)T_ zX4EG|`|@ps-tW}CowO}2i|6+NGYj6}=;KCu{%03QW(m4L2O)wuSaa;f#Z6kS)45`6 z+Yza&?WHw|vU=cPH{$LBxxBN>rr$eb3T3rKN-8}VHZmRc$yBdZHv$or{{6cluk%)F z8KNQ#X{Z31iUzXN`kDcPIY=`TGtI!zAj_og*w|Ard#boF)4ufJva)m9_j2oSI1L+D z$R69Y4Y(`607G8s7Xj0^RMXqmWWPAxU~KGpd0v(I0>K{c$wzF}pjBU`Tla5pP|Chl zU%jHJ9lymZH2eUOUw8NJ3#wpjT-?DmtR%$#Ns}sAvr_^k_E--9q?@dPwQlchR;H19C;XxYda-uX7h=(WyX2F?l*TU*?e#L0wDHduaEy=#dze?>V z?n$xe<_{_q?L=ct4p7TnfGdXw$w<@-Kt(8v%RUg$7wrg{cZroF3t6DX2Bx@VVJZn2 zpTd0%wAh+FT&yp&>2ypI*vW_DBgO_ufD0L15k@|M(}?*CwBHaMDjX6)kOSHn=`2g(YoXf%9=} z(PKinzrUy6@niqQ!#ctIOWqJK3y6ZjO`(iXHv3Lbr{;zsGt1W8+tk!VP=^wAJ}w?Q zQUAR@l4?l^b!S(CWYnyBbdRhHC)$j3Lt-77pFi?T-(ySQHQ)o{vzrSXu6I8BU-w3` zU}M7|)XC8;1_1D%^WP6#{#Oi#tb?<~|J4q`{EwXs7#;ts9Wp=w5-(wC#B&uJ z7Ed%ftTtL3#z2Ik@UZur)i=ZnW*y2w64~>622-OK^bH>AkzpsHYcSPM42M|-qYy12 zV3WJ_;o&>@!z+qV88+6=$`RUe*?9GCeRf|G$cu!SH!V12ntG^uO@F_7{k#(0N~L}i z6)ovKvI_19$NVR2bufZMGnC6@Jt{|+gvqa@@}#M;<|wA4S8}0x^hp5u;nReTn^Hxb z64WqoD!QrvLvY>g+p^Xwv(Mn0QpipI{iN*;%D0Ao%2V%85@GhX^wVfjc~qP7>b85i z^@uv96Gn_{)+~CWf53E`+N)OayL)lY`tz8LzHS@K1Oo1a%NS8C3# zD)YBrB9Lz9R3*h(lo~C+AJgKyI)#(i$VC$PQa zA5ptoZ$*xXKdc=LRnO`q$egXiOCHN;4u5Fgr&Nu%u4tEwrQ_g7Q{Az^+286E^&Hrn z2ZY+K5Wb_jZZ1}E2ZBmgLlcS?xnko|`VDvDxDoq8!u~`j;Vr0yO_<6kT+mL>ROLW5 z#6$HG1$Lg(aGzWd`m}DojYGR;rYriY7F9kyye!|k(k}A&_9R}^l8PsfZE>jC=SI^X z-2;EK!UNHoA9`SW{Rk1elur^b`+7b+?wnZ4a5j{>ug$g&etSuScP-6g|9CK1R#;U z&|QM?ek{EG`jgINce*>RiBkKSChMoE{Zu{{i0xJd{-@zNKcWvsde`&`D@P|6R(;F_ zbx75s8F;ncFtPYJ!hIQRTSXN)G21ORbeEn`tLHidw(jL$$WU9`YQ*#*V$HIY*T}9v zuxQ@Nn!=0GN?#=sd02Hreq7AnZyw2G0H;P7DJMQ>`RU7l_$`RN zO1p{;Rga&m5%9?Zc=>@CC1oB*&{?I=@4G=T4BL@)gTY#Du(BOF>Uvi)2AW9@RiU^W zP%@%l@wEiQsF;OLDQ}<(X&+crxY4`<$RVcbpPjb%8Z-Z8z}D^MC&FG)Tw~|SJ)X14 zzUv8H5VUCr@gT8_gPJExIZY&l9PQa1u6ocSs^GZ$V++!|Bb)8WY6O$Yyq?fqE&Szl z)YfJ1-nV#*uI^1TpRCwiBp|n7q#LQ^bu(&zydyUc8gM-6O6dS6!M;K@3EZ;=!AC8Q0W z0JN)T7USAjNBD+)OrXjidZzB6C7P5!TpxqxSm+tYbL29ieq2T~*P7T*_NO=qqaaao z2tg1(1ZRY#q%$Sk>*EF{q!%H~SNR94TiIk9wW!H`Jtn+a_n~DzwrBlt88|an>7PP6Ilk z1Yttf68je-G=%tIy-?DhlzIz@eF@&X{ftgJLE$gkm^?J-YKYxFrByag!0FL%d-*=s z3ga(Cs03I-Gd%aj zK8e(-yvXH`9$~emWZl^^2Pn)^*=T80o6bo^x}%!kUk?(<=P7nj`8JT49?+{$ zf@iG^{4m`Ovx>ZBP;vQwNVquVRs0^g1>pbXGh5|jbAW`^Uj$yta(p5jKqIFhVwuRz zyh{<{uXrJ%ez6ay&DZ$(2=Ey~KuN)YOVe0YUky50l$;*ndEEYCA72K8s(=52RBrs_ z`(9&{w=R6&DwY{{`!l}~L1uTFzJKH|YHn?9=|e%ro>j@xPy!DC*Q6@yc*$Xl)T!2%@&5MjknIIEHp5^fuXu~akx{_*l{sEX4CR=|= z4LfBg#|mEkM-H;zk)#V29dQ35lfy2k#}Dy6>Z>s=mtKk7=NK1^uyWNGTCAJUq4<^E zZ@jz>QJ!ik*u15I&&@A~XaQ|c8RrY}$)tUEUzxR8%QXh@2r z6s?bYpf_UIF0INC7(mFx&w$rUM>W=O6;tVicuu}22lC}v*Q_kvfa#;4(QuN0{Er`+z^ zBx~&e(=5Riil$PrzWaiId>RVdJpgzNuzvQ)B6=%KN`!VZ5)b_{%B8qPhz;vk3DSQ@ z&s2*MD~sEglPA?(hyqMYoI+1YI*QRCoeEH2C?98H)8QWMc|*PBIl_e z>l$#fraPFfu4r6=ep5*CjML?PE%4V4O`PwRC6zZhmtDl+|Cq8C6kgS=OVueT45tRA zAj?XZ(|AJk`i1G3C>e9gu0hhER+NZEC~L!LWb*T-ia}3A<>n!BB8WB$Mluv$vfUTv zl2gN(&!?^Rl$u#Qx>CBIXQ)O(=Z!6OQ{5Ke=JqEe{3w1L?|#z(MPR;h+bb?-#Zw}<|vEy4jH4fa6T(3F{AP~ z;Ua~8M0sq(xboi2;)L#=$xVH zm4H~4P1g@GbT7qpEzwvQ){$htO}Gack4EeV$i;)C_Fq=Jh>%SEB`+&o{`P34^A>m%izd6igkZxUhQ7@v^3O%~t zB97*Dr_O4$Mok)xDhjBP3o<8}hZ@VfCBG1ywpVTDYEE2!Bwf9m#FTfr_=Q8Jjkj3m zZN0U<<>9$|Aa6-R1_?FJ)6AD&`o^mMnyjDf0-4=}l`e_aSE>E)PN=Z5X$@fu@6>9O zuV`%GdQ_7RNO_XF)W1Gs;WJP#2i&}6SzxPy>7h$1B&1`mf^W0GphrQY_;s^5_3pRb zkrVj0URo>#ik}+gak}SUk6;;74r^`-Il7LhMAf-X5$9n5x@mUwVzzQr;@%TAd>qTP zfvFsw?wTX1BNny}ueSRPR^3)V_OD zr6g(S-003A2^#6Y+sn@E60%vGvcXoVX+h9Cb;a|8j}AfI#ZdW8{t*6GJh<}uH6X<3>ug#KRzO?6FTUwLV8S7%%u7qpVd+kOcS^MZL6_b z_(b5bqY6pNWsGzzh*|OfgJo^j`Fga18osj7vOFfg6x|=jkuyhzGdWID z@Jvxp>1Ku+fxi8)bUAZrx+%7_ExxpzsJ}2j0y%`$_S1LQQFXHIj-z$Y69G-`!4S@s zRCdD)`1iu4rbRoCoUpd&V`5h|&n+%)r7hiH@Ci_?xefZONh?8iI+|Y_Hd{|JCxl_`GdnCjnSMq zK#qriQ(^UV23zZRgX$OI2-c3tPChfFmd`2%vX%%!sZ=)Kau3YRZ~Bv9N8sb8bd{vR zN^?*`zhhkw|6IE@w+AXS73uyHbhRM~q@Rq-fVHaf%MwofP?HS;@XfYPFSL2hFKuY_ z5aA1r_S)NZJ6$?!YsjohDb_Co4kA+uLF!puZ`RyYX2>_;N=sa9h3`tx9x;2PFipp7 zd!1XWSZnX+>tLLX1n<5q(G_2$78(Bn(s<6tSI5OYoK#2;k0Qr&mJj|tAHSs2ZKd&m zjqD#Eum(@M1*0Ain_9!Z6mCM-(N^9vgzg{E8Ub)|Z4m7?JVx)C@H0zZwmyVsGL1e1 z$vx9cnSmY4cN`lNwZnXoFBr$97?nOq2BP}3XCOv{P*6vd zjx>D=rJNtF-vBSbv8Uveu7DBoefo9$5m*Y%pW{so$Chw z@~|OXu2-1K?|(m2qhxMqgELKh!@Yjr_Rc*W^K!Tzc2SP+^#@{>a`o#6=ScJ7a5EVnd}H$BLwX0w zFY52;%bOR$DS1+;)+0dtpvH>_eRMG}cXAcJg`Et=#?7 zdSc@>*DM)?@HU1yO8j=!qkWe??{D3t`$C)7vZ6b$c2Zd#kzy)Us>fee`h%<#c_ofl zj={kSUZw)+^m3_xci{Vn&|2p?vu|5`;6B?_3Lk-*>BH5akwze4s=SVy&~qx@^EjdE zBN$@S7Q-kMBbtw>$zs)-d4^$4N#9g#rZ%jgsiF#smoZP$y6gX8MX}&(+w65L8{Pka zc2a80d|Z!{C)LzJ5B<8{HB98M<}d&Nd2L6JrC ztIu{y2}bw~x3|b~=R`5rTvmPX$2}(BOOoRZs-M--F#yF6$YJ`@i|ua=-Se>D3xP+n z-L@C&Q21ZZm!818ckb?KZZq)S{Xa+Wzumnn+qqdXYg(Fv(=uF{t*pPAdpNlNpNScq z|6?j8GVTBNcK89c770EtFS|Qe|9-tSlN`mO8U;`w(CNWK%eY%%GhW2i8MxDF#DEH9 zN(bo)(TJ$CoTN*(X6bse=3N0+!3GZ|`*r7fFrd2V#y9cigPDg>bL_|*hGE#^oG z>F9EooUMIWTcZwHmC4bSv~aihZ!Rr7_y!lBtintuM$9 z+bM`I$0b9X6Bj}psV!0oc0GdD7mwbiBvmJU&$}qDSKe7`vjr^I=7cLD?yUVf2Ml`3Dk2&2+4$ILhy z1A?~S|8~@Pc!2+AcE~Uyp{@EzO5H9!*?l23 zRli7nVa~g=8=%i|-SkF$8EAeF-_+9LPD6&3JZeRWL<6IVgY@z-y@3y@mQ^xFFFoD) zl25(Ur)exioS^t#dt{9=DwucjhqH`LDTsG1R?r+8o25?Efs2t7nvg zw6!O=l^KuyD3a+0N-dgJjZ#umH7BoPr6{K4QsHj8NmdeSjoLY$cS2;9IT(d}W-Dex zsp#`q-t$;^9vV3abvUKg?#I`eM%3j~`pGtA;27ICFRI%McUh;ej64hzp)*)bS+eUj zD%0|y`ulMJ9vE-SHMZ`227{33~DDD0g(%s9bn)r?8W& zK%P+u80Ly@7vZHDXbl`I$Z3aphqd~X2n&Uc6kcH_Mt?fU!I-Wvhldi0g{_#d-MpVn zxmn9%*s(wuJF*OTmFnCyu>-4IeSCPDm|0aDk5^&%kU)FBNBzXa^IUUJfw-pC(YHp`(X)B)Z%0S(f65MpJ3u1g zu^4gM?G2U=M4-`DO=Zk(ts+I)3Y+djSISB#X|d>i7a~bqSX%lcL_%tmKqXCYhU;BG zVOXlRGA&@J!igxGpN#!n$SkPS=mdS)wx6&zH#hf^^6`FwhejZg5cm#XE56hv6w>KF zZ{i%nck*n&szY&8{ylw0fNCs$ZDwl=HS;!UgupC@M)YHYQI%yv$2X!cj)2p|0KC#B zzU=gSybQNnuWT%mkgHu(_$5RHuP@E;S|)f`?Sg*VPZ&j6=-5;BlcqWY0xH%V+AP+H~XC8zY^X3`p$LmEyka`nA zhgY+--1pq+Y9a~-XFRwmD^LBI`p!E&8ai?Pw?8=W?Nqnfqc@hpkwH2yKRHiAOSnE{ z$DV+~f0~6&7-Mgzjd8GG$Xkd7U`NKUC4yElv+8RPJL7@*s8ro~PbKY~|#z*wn z>v`pI+GwjHf~e=l!Nc1I!{g3cz)=DikqjNU3I47*Cj2wfi;CbXPcu;eB%a4dydHx8d&!U|S88K!N3 zR%L$TRj{%IeMww7`G%2sk7n^51_xh4OGiT~9LTz>GehPTTQcJmM==`(AdMcXBaLHdDL%{sBdrC18*(uxeH(cY6O7w*nh5;fPe`e@T)s(AS^RtBYpwW&J&t8}ySQA#5CFIt^_L zD)%}FK#wZLm+luWBP5eiNKu*uFiNm(Cs8j+>`&%%sNUiQX)^tSnXWdxI7GG=MPMC?rI6vsOY9Mbll8YLkhI3u(%Tn}F3a`~)4MH$jY{j?m@~|?qz1hg z;4lYMo}dqZI5e$Go-Uc|zt>x`rgJ}1$vfJ(&~^~0xPI%;5YmWpNLbBL>Dy{>6kV|G z2_|5cG;Tx~{*LN>Dxs5<@^|4l<;Ad2-D@xJ6_D<&Qr3_haPd4_s1&8hW0k-nIE@F8 z)=z-l#gkypw=manZRcO3*Ia1YzUT!~LFFsna_~+cXNKa<_z1!Q{YqRT1ltQEz9{;R zB=qb4%Iti=fPxa;?xf9}Wo+sm6=Xk|wp@+-CR-C*!}M{nu;0Vme|+Liy{Tfj(ZObd zHkTXiu{IyRW#J=`Xr?N^Q!ER;#P`~!Wr}|)a(?7BeEX#cQ4o{&jq?XIeNyz9Aliu- zl}e8p^bmsrjZ}!Te2TG3@@C1LTBOn+j#4)4vX3U)c8Ym1x+Ez|p zer)p=yx#P?Rp!mcApMQmZp-M(#DBLnqTF1!DpnkUO2zp`=IFbL;?BX~FNhwkUM?yT z3`|?Ff>g<%3S-EoPJbyp$-v7RHP@t*WslOk@$C*v$O7vQq^n08)pL>Xie6s25f)No z;-?+mgRaD&P-T+vP1Mz0role{t1g#e!PGfxxy{E|r0rOv7oeecLSMKx zszZDYD|Y*Xdcq29vR8ea#w=^-7Nsl%DZzf`@z7jdhpn%-8O8PWfXlLfJhE9Fm;QkKQLzQrLqXxmZhK1bG zNjAywqiF5@4v=@w^hpCwl#BpmMu>=f5-E)$up+8r&X^6*07pw>m;OGz?guNg*j%DS zwawkjWFM%CS%tv}mLmzqJ>EBa^k6ZP??kmVx6@{M-JON6u-RUqGO0h8vb1J-fM3K8 zmk(uROdM=NNPWcg@(`hF?ny;m-F8T=J65Cm4jk4Db8;*ct+CHxdexrZpF-^X^TYwNzqm24I9Ak*L5XYKL{0_n%Ik+7xkL&z0Rf05`{5i#5sR;Gg~ z6>m}ReoP+X!27{ytW5J1BF+xa=CmJczOc-YSSdC^P1mH@E+tRH!l z7kyihj;)Yn&IEj;EXHlWLV+V}Kb9{<1p@EB;Uv`$m-UMfB_9gfIz;d8 zee&B)TCF_GSv%;B9{z5%L#&`~83r<-n+5&k+#^`bv+pAi>&SlX{9@doCVH%6xy1 z4vv5CU_AtJH{*-b#f^8LQ|ka&+_>_Wr{18N@~$HSprc5YqF}IWx9FW!UbUkXe9j1$ zl%0Lb3NLX8E~koMu<^6f{Cpapx&sh#Q#cQFfH~<5`e`m4q;Ww{|NkI_ok|qp!BEwP;8@7V0_6EN;oi`olk2XrGunY zU~V=9kDCd<`j%tgO_IKr5+14jR4-Hmi=a_4qd~c5O33h7^#6em*>VvMfK^=%`-q^n zeC23A&$Bf884r5WhmujLpTL)5F(cZ}eo??*{qy>Q#D=wBEHf}LyK{HYxW4!BW|9aU zV=AeNAr~qH-#i!#Q!DGGIm6qVA z#qqhk`44uDEX>Rpyp?mv=c220#6YkQ7k-btzTF?;E~V(RN2Z#ZHXkf(Z0M!d&wtaQ z!!vmxvndPVZQb?odlOnnw;^JAod>qR@ck)j(RkV_3mR~f-7?o#4^|5(CP{s*;xkY3 zIq`$ulgy2f#_w;tTXWzcCM0zKA(AIrRa{(bu>nB$kl-RzMyXVl({#k?5hzRzf0hSO zo7B1i66&0X^EzEun^@mz-|o`$cQfpCaPe`_!Zq{7ru|qOb5RU;p9I^V^s+(=M-+V{ zWkJg>s0PBA!{-tC`G}%VJASIie9ZMbXMu&27+E z?RUvRkx3JRg@MDGN&ct0=(vQ4-Ta1T+d=R6KMdLNJRg<9obeOHOLBV7Z!{_1#Ux+tYTAyCgk!HnU=%GNrKV#suGt=BADK?Bp~SYBs3$KsB^yTuq1MIXFZ0uD`{s52= z%P)e@+elG|(sR@8SVv1pJuwrsrPH4XVU3+F7^YgfoHZ%pQy{GB#Ebq)O-ll86LdKl zm|%8#mw}n(@E4-YEQfl+8Le=21IF*z)dzh3@kGYxk7HjSf~nz@Rf4{H@fDPp!;PH} zgolSCfWxzD_8~zrOS@p!YR!Z9hC{?I2MYoZCygW@g%5ON&ppSLdsg46Dxl)~*N{QK zseZW=Lg)zQc#rDaJYF#YeX;cB*izNxDC{$r6TKdOBw;7C^Rr7>(R9SI*AaOplJbN5 z4c`A~?!yrf5Xv$4_Nm{Mmv@KyVCQVYVr5{(&$mO(jI&0QIwBDH44-V&7_=8mrX!l0 zkqdb6`S4L|pSq#g+5!aIEG_#QT*;YGKG4(B?lPy)Bx0E{H(2l%c)8RtJI$}Qx<;Z! zuC`-uykNwl8ENw~n2bBPdWkTqUeUoi6i|F2aa%+N(p1~ z@{_yulFAnz7E!SoZRd~r-rY0?T zB>PvJF0|9rU0#0u+I@u;YkV%Qo}9ekq6w+$!Ox#>nXRWV%bp#s9d-zb6FlS=y{moES+wawT%XQ}7?=ZT-`U_eiU4zQs=M+cF>mz1Jc~-2Lo8;RReb-h0 z+L{3_Iy#`&=YDZ}&g|~@6nk@!5&$gfM7+7Ztukx_nzQM~wG|SToH-UqH&uw_@!(;5 zC5k2bbF@inkomtzUeEkxQmcFuQ?g~R?6$!^hPry5`B8Iy(f*|f()h#>L8qK_YD~-H z+qZr*wl-8!{uG(J$`0LqQ7izx%H_Yq3EsK8L0ORkLNODq20*=eNmXpPUk4d>hd7HH zMX^qi^$cu2SISmZIVZA8@X8>6R&MTi8e-{6=|8Efb51ei-T5}4Cp_mWML|~(I0sT$ zIbLo6`Sm^F3!XvFcRT`RnvnnqvToJHn3#^VFK7j=^8^| z8w3IbVbBaaWkjP2ZpfE{-n;T6X{8FU(Jmf``ZBS@P91kOWWy9RdL}%6`sMZL}K9VKmQ# z`$-5#&ZY+8GT)rm^`W-(s0^IvTUuX70(*{uH+#|(!J%-i8Y0Na1fHY-6S%u(nM(oy z_2oVR0YRjtg$3w}Bgv(@sVNl}$S3(%|A7#p=myzMo*_p zS3v_mv%DT#XuylKj87(3CM)X0y9k#lSB^Ttv}7lbBRjm8g2_Y9g>AahaW8cL=GV`= z|2nxVMrdc;OB5vtK!0onM=!p}ZoGoo!U)jXIs|ehm?ct{7hk@}P35-1a5%1Uv3;MC zGqK{xCMH&an|sv%IOUv~omI@M%5z-1!$Hyot$(8&hj(dK7W@2KB!!)7{ysT;U?2o}o+;91&OMjCoMkO5@XT#Epg!l*B z3y9tJcGkYF96l^84BqNa5uBnDWbNy~lyVa%8+CJ@UXd zDy$sB@Ab{i3&~)KbSz8eg!gyhRwDZX4}z|7E>F~_BJ>|Wewh67Uu|SNlMp{D#z6D4 z*2ba2`jSIPM9$5O!WVRU%NFqB&gc0ztL+?&rUe}6CzEIaKr~FrCU5t20U{z^sB}5k zsmz872yce@d&VDY3RQ7BoEy?ApRj;L$gw>|Fy!~$2Mkr*A0DMIq{ocQM@egrkLM-l z@f4tw%d@9z4|p4?sMK67iGoj3vpOM}gp;`YIqgjaV|fe@@cHs#x&Dh+9)5h+nKy*F z*}g(#qj}Y#^+7tbT95Mlft?ms?Q{JRy> z*r_#(cEK}B#%=s2N9-IIpwgrcaC-5VmJYA5@cZ{q3A-ipM0msz&{qC>D%euu`VtWV zdknU@$poac3>`lBzs7H0DR4ayd@NKtPj)f_0xPtB^4XW7v6^)8k<-z^gAKl;A&^kc zhvB-V-ZcfwZ#i*CW|si5<=>7NKmlX#f5oW|9MY$&q#xH*I1K}>>Je7~p6Dp&oE%^8 zOG~J}$*c89V!wmO7|F$rjrOlmn=VE5WS5Ja{$;_2RH=Lh6j?`yE(Mh!?L`2OIJP$47ns=)cS*uL2z%*gWo>W#{`zzR z<&wx#86@3deY9$D~)2V9hfDaMN($gwR;6qqQEbA z{x@D>GBrD8%89@wTSBNHMtjc*N4ZOC4x9d?h8v)vM$`_7TaJk)gSGOOLtYGHfjG!sLFnSMS;it zpT)(+G#~$atJ;Q!?>#r|As=ev9DW7_=Lo$=WQTM7kpy-!yRE^eX_tA_GrWCH{T-2< zauwI_K2Ar2NC}?}b2jHTZiNjEx7Oyz40xQj!GB`}eDwh9XRy;@avHV}c?IQs<{T*6 z)oFdLG@%M!WzFr!-JP!`5RtL*sXz242~%ZWtLLoqwj9|prw5y3<}0RIxi8y?2kQuh z+2I6%#WEG7zf3)cX0Mg+t@VV&zoA)>GJ;ybs_x*3k%V(4=|0Pu!h{5fvwi^7J zzCRuv)iNckg-ZmV8?@92kYTW(L+JM1Jh-4k&K2)_p4UbNv3mJ=^JagsWQj&L8d;69 zNu*il&RG3SDpo38Ny({Muu+wx{@Q0Hr}76$hiojrNaq{=cO4Gps#G;pRAOR4q?FqqLtc*2SFMapBfD#!a6d1nd!6o7=cOQ^UJj5cz@csVqX zaq^1Yr$sBZy{1MNw$Ip2R-80JD`uc(i3voAFcDy3IY1cmlBXNi*pl@{Qld5@fy+QJ z@;==7&-^c;B4vmY%%>;lJ_~}xwbfN00)msOjvs6Ez+$$b-tG336!vV=a`HZ*L}K16 z>{l58%I3RkoQ5q=qu=8K74_G!ay5MXRDcP~PXk4a;d%@z_}_{$?K6b1sL`b$bAVwA zx?`-0Vr(!IG-zu6vvP(R+Nj=FDZ!^pN{}d|*^_w_Gb>_ea6U#kE&NNhS~RJ&^6a70 zOl@tqmgydpuBxi4yZuJ{A1n6Aq~J;?S`$@Twb{p2(Q8=nwQjej&z8R@@zMz^8NT^s zaf)~RS|tEqI7Dv;7Y}y0oSxyUuypBpB;vXfo>U~6P-UbHlrkNhdNc!1C@j2)`OO+; zOmMY==FHwmW#921QqA#P+06S)HZfr#0DN$gndP<-2nq{*NlN&Shi}0jJGL**g%XvO zl_yBh&^A6q6ELs9kvdd+fJVFBBLs81o^*qrZ(3D&?>|zi}60nJCU_W3~h}UX1M15NSA5 z?2y^zbMUr{HyH0^;6zDD#8M>|*0&XaU4^EiI-Zzg5=vQwEWm#qcJs~m7xu1a+32D! z$rz)q_M)~Ld)Oc|L;~Si5!M~4q5w9M1)onCt@sV&ePi%2kd!o4X#SH3MlWnY0vahe z*A&^}PP8;W@eB%I$8ZVg?vAxznysmv#?i>|_0EHr-{paDOiHmV!_%rf3OCNDawak- zHyAc5@>ARAAR*L#<0wCuV)DjULrpy<*gq6ze}^LwH4U1}Jp+y*x+u}E|H9L})-QOX z0dhgbp(^{sLqN*Tsn}sQd9jEs3RXZ)U@yj0G5LN09nb2_A_@%3TaewR3!6DPIG!v5 zSz}tei5e|VL-7Dt(MN%Rj=T>%C;t*4m`W)p^|M^Q+@Nj%wtS4Bjs%|nx+qRIRc6B3 z<#};ru)n{*WuZ#*Kne}&<&6XHK1$&;rZ??gtxoPc)tTMA)mp=GhZ?zp<7kPKEVl z^`NXn0XY@|Rgat&hPNtyla2O%f8!4WQ=kILs`E&%C^un@T+6<=o{bhf&gB z5JP%mSJBE4j^GPPOv{oBhY-cw0?kAQOO<<#|23#f@ahsh63VQaOQIMd67=7lv~_-T zCG0)ZC3&Cdx<6l*G5@E$*crJMiy7!UsM!8Ie+$wCso8bql#B1={sSEgOVQ zMc2deb{XlKEDRY6uSyHn`#6(@xIW@zn^10`NeN0VkGdFud=!jfU43$rzB29LVAO088-MnT6liGExDL^8Lu6#ci}Xq zp6IMt>h1u|vJjsLGnbWE@;`rldTnNk$gQo(pVrBw$Rou}q{sy0OiJwS-4mA#p8Yoh zd!8KWnIS&EOfHz;2b|okIr#H3)xj=9B7zN{uJ1xr#Q;XLIm|EUe-K;o20&(2>-r|a z=wI;-d>*kfdW`UkDa)MI8`i!}Z{dJ5o2Z3R)oCf_5LMWr$x@W@u}CqajUh}6{ysO1 zBAK9+0IC*19iD>jcN4Am)rIVfxskmTn(I!lNO_9coFO>*@)!4D3e*lt2sm*Wv0$f) zeJF%3VlLu`=3q+lw0zXLOI}$yH|1z-17CZ=Og@fu3(Esm$t2T6+%{tp^#jSLjk5nWezj%C>$o~qdrP|W8y=t3o zn8E8=+l#r|J%C*98s5_qC$AKChlED36W+QZ{w zmWG^OH;ZU5nd>uI6t*EsK#YjcCfm->3*_9XM#us6zk4lA%*pcQNi$5m}*dK{Mur`iCi#w*&q=;JD zxbY&jYyN~ttX&PQX)HR=au1Q^YjLTC^7cYT@`FZK8o96#J?G3*kyn+`mY`1_5V zc``KUd_5MnE6Wo&ds>C1RoWA~Vf4vBPr_qJbW$oDHxg%%iB`pOQ|N{-HAiJd5|@NM zE@*H6mQ(u>YT$japl4vp&GC)jHHe|pg>zzDDk?k5QOb(hV}wm>gFVc5Y0jH5VD+KI=3K1jC{cb$z)Xak@E@Ht}Sio}I1Y2DAj2 zn?rsalyZJj#pe>lk27|TaXBLqUrPERB9&6D({vhU;QI;*Yh(rL{gaAvzS(j%3Delv zSTIBsev!)qXDWp>nt7YgoEuS^wnVnQAVP}@5xWiED~EMb02XV!A2#K)f9Bz{m4bg1F?zN6v(nXO%BDi4I=M{?4cl&&XzrUO zhvyGZJTCBQ>TOOoVMoOU7G~trH~L2N;(GWa8m5b04+Cf(_Vx9t`dhrVgpH z9rdqF4~5n+X0#}|A&kzlF7&%je-I!~~+R3(DPR_Ns5#Y z!bo8Z{>7ljQGF#G3tBYUspZeSkoZAE_}yKWDrWK2+#I#uP*=fby3NJ)%YkKE^k+Lo7d0l zt33o)&6>#SP&uBdghTMB(B5Abl$112yJR8EtfB7_?j5vy2XY z{sG<4FLUG$B|oJQu|m}pDN|JP(X6z#3z)GHuN<}^iUW;4*AW+z&AJs}>0 z&CuWdO#g|+wH8qnlCj?N9`!yyhV`QS#-?zQ!23C70EUisw7_&^-x!4{F$hR9@lye+ z%oPlJA*=kLXeEqK+Q+1S-Cp>Zm{^A3v7ICofZbWm@bsVFu_G@_zMp2uK#Xx)lj_+J z75w5dc)JPHBj{FeJZM^&Unz=ugAO2A6#QX&wyN%nE}etgz)eLZW?_3WC`=9g2F59u z61HR~=P)yZZg^Zakq&njU+Mki^p?TSt+@f>>4Nt4f(nLrUidj7D}m+OAkSjwkGX6> zGZ5sN0A5K!9-1qQE61P~Y}0e#cKzLXGucr$uc=P*W#7%+FB)(H5?+Y%SMpMeVP_~o zdAY;s@v}oX5nR@gphYdlndAz_L`IF_h{9GRNJzo7MtwXL52#vzE?j_P-%g)FWvi&N zFR@dMIQ!A=q?O5MPN<**EJRJgqzF?W9X!0BTkm9tHGVUY-e#-?q-9L_w zL;bZ96-6NAerVX6-f30va98&a9hk%;{Khja#s$%~&lN5U&=WA7p)^%l{fa@O@Qu&( z<)QO*-E5TpCrq4zs9!fN2j#JI^!4=kxZ4f45drA9Hk3ym!v|}+=A1+?BNz%c-+k;|D zez!uC*h8hCIk`;44$MVw4(*f7=n0Rov)8wp3imV|$|q>KW+$ zcqnc5?B=zfw2K=mj9@XXz8u1F=Z;MXi$!Gnz|?F~p<&K(RR+Vu(Owuyl9O*b6HK5g zP$+s4&7bpm2Dy=a&6kv$3P8>b!f z6s2hL8G_`trOXItX}NV=#hbUcfK@$1n1$55`$aA_;y)fOJ*DUiWl+MWk^?;}34Vqi z`xcnAFTxkGv&S(3-c$F)x!K?H;Ks(FRaEEX{$Br8{>!1YxH6d=934E`rogV{90If+ zv|2O(g&3=4qn@3(3d#Bt)$qB0e|rgIGC&OVcdSauLQXHcn4`To>vf8?OmvHt00dFg@j%@swc)6#6I zS{^n`S(?vb*7l_Iv%7oJY8I1#<0x9QF0?MmBn?&XE8CtmiaCgF=-!v@K}C?ETx z%vMD}Xo}8T_I|(r)z!&wE#h5`PoACjyZh{Db>zP9Npa14lfe2y0BIzt z;gbtTxop7d+9xk6D!Q|HHw-_Lc*ZaHTc%m&m({f;!t}?Dc@$@{fz;>_fan9!r$pB% z67Sj)@A`lj!!K_z5E+kx%QC7G|G=;RJ0OesaSaP_`XIA?cyrw8`M7ch0swUXpMb2L zwW+y-t2v{amz%m88~_rN`#&X^jEk3dfM7ukyB7#!N;JzOf^ZMh%D)3p?~$QB3O7WQ zw=$^~M^~yZlx&sVKN5MLGoZENsaj!$VUboEbh(-$c7)H1%5k+6V9_)nEs;=RG-|hJ z%yrD1xMgb1wy*xQDN1`ukN82Ye6NeZnK!<7LUi6udaAnp>GZ0EZEu}tQDZ`1qb))V z562k6DZgLvhvP`sNZFUI_x|4!baQlq-;L4ip(Iam5+a~^bFIgs-wEpdyN}1KM3P(_ zLTJD!{|mAvbT1J4csT#_MfIOQAy-EWx6iJoF2+u-{{p97nf~>3mR9l<`2Y(l?p_E0 zAm|^u;D5dSubeBBe6Mw1_1ss&j0GqOE}t@eL&&Xrj8Dr?2Jwhmj7CBMK|%k zNcSo9u_Gbaj}-xx*3O#%0CeNOLE&fFaCVsLxFhdPF#LAbK_%kwji}0n8KkH}RVrxx zXnnYGYLp<#NStV8Q$AR@3?ueWUZg+eW5F{S`9LJB1{rQOlVDo>*t6NQX8SLv4KPh7 z?-QpBtT9TSzp+l!U)Jt7+5dK5+@EJw1i!b_H4-J-Zvf1AN!NY=M?FZ#;L91lp8IF< zEMNg6^Ycp1%cA9KPdsfPZ#fqhu>f*~Eh_#DwfEc{Ay4wu;Oz1)HIyVex&ld0h_362 zig8^?yLVh}7fJ&)#kf+1QNVU_ys~JHoV@`|%49x)u`4}NQ?$9GSpDgN*9@c0>LVcX z%G(^@A6AIOxA3`(3SOgDslI&P*kOOn0uq}6&UhfrYb-Jz;8HO(?`M;k+1;jh8tBWq z6RWib$4{e64 zedjrcB9$;J7n`!*3w+-@hhmkV?P54H|XULpzi z53@kLVMw|Qpyb!_ULnUcvOuKeX&BL($@wm&h|-i$=w{dnR3+KoDY z8vXs7Hbyr@t|J)H#Tnk2+5($1yU`y)vZ|E`(-n<4~jw%Y%EcQB?*H?OWAXbgLc< z4z`C))Z)?%BQn=0H8iwQ7;(vJ*soX`SfJI@a^9?{-!^3$ef}r@<@}}~Av>iACMxje zZ^&sM2rd`_gQZkT6|>9a~O_UM%>5wwK!@b0lzl>C;5J zV=v5n8n9q*`C@G721jRRc@|A*ixymv;5>aW1~jU4-l$s-$6kQEhZGWZH6cj^)MwG% z^FbWZt?9Z}*T7!}L<=XlP8D6a@dCUODuULLd0fpqvH~#v%Kmkp{BqzV*gv_=25~8% z`g*aOMd6s2yP3Z-@oM*HQKsv5fUIV@ix~^tEQh7=TZQZ}B`r6fLeB(GpFk6^6xRa+irx5&gKN&}SP-8G0k;wWFI*AF+%WshMv5QI2v?zaW|Tosfk;1y zz>gJxNVO@nQ=mR3_-NAxA;e)G3(n&Yr%3@DbbVAs&dD<5>JU6g#UcvGN1$&~hX7bm7ZM;}uqQY^sz*3JlFvYZv zE&?|>Z)pr9^8hSBvj_glM$PR#1wcNdW!h($^*dJqz##$fh-NL?X4)`90?NrkZOg9I zYJ-fT(ZFw@%T&811_e9b#7(7@;rm-s;1 z^s_8+fP*Y>yY6C;SJ-xILD%sU^wz2wzz6_5ovk(89KIvsOXbi12@o0*UfI+(J#TOZ z=z_o~ep%v!U5^pOwol32oXWGJ`K<^noj+^dX?NqN;nNFTM8QVFEwGj$28rC1xH!|Pn(@%6Ump*6g!#lxAJ$I|CNp^+p zpo9;Jzx4~xi!X<~o|G?#)Du|Xr~>834d-F0Vt_9mRqO%To$s$v6So%xqYlb~u5CGn5*6a}gzqKVA0TFxs^Nh_RB? z7%dLk2)OFSI4k~*pc4fO&RRqirI|k>2De%X08B;&a7~jNFpWVT`ld9~H{n*4*gj;W zBJ5O|_dZzHyaU4#)8C5h=i`TVHOzhVy+E<#=OG361}iu4 zh)yx+%P)@zHad-0to4wG*`)B_8YsJ6I+Ww-^@$;PRq00Cq4SaSwj7B!ej+{!EF1If zm_=blwwURwSiNKr@V}P(a98aS{lRrTcp;*OnM%1*pG1;VZi%=vpCJAA@NWXRwtw2g zHP?khg4G~g5MY@@IdT)Vbu|1V-#qD*~KC!CxiE65vo!ZCp|EUvwy3 z97qB6sEOU#01hhB@!xy9?su#Lu2{EyZ%Ps^qCi55-o{Ko>VcfQ3e!akiPP<4LL=WJ zlP^J{ejQ*IR*J*5Pz*r&JH!+A5|KFoMD=a+6a}_i6>tnHW}pxvIInR@ATZxGCLWTY znOYtQNC4|VB?|WjiGxB_7BU78P5N1gzf~qf19jlqDgmr;%RK=$dqQB0z?9((1M#lgz>D~)WCEsp`=N>=5Z6eH~A{3wj}$%p8y#(%EZC& zEFjKz46l#28~Gve87R!<2LZ#dbcjSWOOXjSjZ%)P!mpiG1j{W67ikqH~$2k70Nwc`Uv9;a5a_0Zdv1|YPj?MhDm-_rePXUYpVI&At*@(jhWo!cCCWNjf zH0o@)wV`t2-BG-4?oyYRgPyzm(g9^4ApxL9I{^nfaFzD=6^v0ewHUUdDTz*JI`5(e zAZfh)CrP~@;P)SBK$|2W1Tad`E29aCph(ouds5~miGVP61E`TdROTo`(wkZ+}hzY_8dDV?>3Dov{m(?A8?e zOVu~WRzQmv=b8f;5cg-m9V+Qi`}Et__R@k2(u*+sZZRGU2-)Q}wJw=uI-4KzM;fFy zJG}w=v7vD=2x_&>eerX(~x=QP84f>75BGL?8d+S*D) zpI5x9e3s2QIv1}gAabw(ykz#$7Fym5e&J|11M5?&3MKM8hTO#`3`QE-b_(X{TMZqlk?_ z>6ijORVw|N)*IB$%#6&pTMT-q)jhY8g!yaO|B@~Mvqq3SSfD*ciV+F8&F~~yG13H} z^=9lH2wrImAYBGRzCaYyyn%V;@joO~|Fej_=4T@iBmmnlj{*SvWB-q#wg0=;R<*ab zGxz>1`JuJ?A6vr$cD>}ku>W86ca)NXBoaLSKY0R@w3L|2$0zeY_OGC=3Go;K0H9$0 zyKn2jd0`&l1z28CWFtwFlF6crs3MFa4Uubsnw3&i91~UO%fmG2<_oo~Y}KP>bd@o! z(UJ;b;Wh00LVgxRVu`>}!qSRB?2|8@Q+KRvtZW=VPmS+VGZ@ShPtAGfre}^{P2C5) zdv?Avpudf99Shp`zQesBjQpgLKz)reAy2PAUJ?=ee1)bgb4sf4!i9RIur8%1dxO3A z^V3 z54iRF)2K;Fxk1Rm(>{MAt#;U>wU}IY1BJbwqKGJg*+a6#2i+*Pp;kc6 ziSk`H3fBbiE+vHKikT%nG8X}eHgSRrwHL^Tr!}}^S4%9k`oXNeu;~PM_O8%OC;e;| z`I(q9N)z?^Vkjr9cWU%tAQiZE4ccp&nnI6 z%q)bT1|dxkMeckuaTiHwo2YsNcPORZret-HEW^rX=t&Ng=6p%Q_>RSVX7gr#0ynf9 zB;qNS^%^-1F7FA`5H}`Ok6DA4)qsv&(M~*)r$j>=9tlQ!xFZa^a3aFblCz4-Kr5n& zO@@degU+UdZ>5i}hJe)L|IwSG3Om;O6N_Oe8p(P6+BUvu8)Z8ASrsmF`1|#FMI!e2 zK2n+K( z_X(fo(|nw(H-}DBj6As$XU_bVXL(qHve9ZkhxK<2;fl7EIix>LeVZ9HVF zzeNXT_{({3uw97cABM$&ZIhNLQm&Pbh~Mml&vb8T>zoFX)513Q4#{k{)yv7fF)TlA zS%;Bf2Rpv=%sb}Bc;zF1;}c4MQ;>3q$FL11yfz+BSO&=U=GJn~m|9ZQvus2;Kj#$@ zUP`fdvyp#x_S(ANEuz3CY)u#_nF|PEP-MB|gu3+jMq=Nu|N(yZR-ua;vxA znRQ$oZyX0w=V#Y)>jXHz1SWj_&5}=yrh4-`9uzd5G4?BU2Z5)-7i_lfw3v*0+&{U5 zK~AzrE*0fDQ1j#-FxdwDpQ=obxS|><^M4NZ;uR9y< z>Dk7788Nk&R;i~}s~z6#YSC-QSyWH}JUBSWX!7Pd&w7`A=?oMQf#K|JJ;xVg15O!H zY`d@kGdgAf*mcHiI@JoNUOT5|5adQ%^mj(1K%cGt&0<`lMBTkh5+vjMZU(>CGDnJz ze4N@XAJ~##*v4zS&&I854Yo^+p##PYhOZ1BhF(ZA)R+b48_YL^mf&6H{#LF~e)BHl zjBcW$3;keA#!tf^LbG(2FIvquSij5=3ApV0&t(I^t9kOFnLG0>v^a4M*qBOdGK|?e z2HJ3_aP-`HO-{w|^Av4D#ah9=RD-{6I*0s>FLg02vas5V2mR0?M!<$VQ0$<`! zw`vBEUrvx&?`;Jr( z-+12}CD&kKP|NiuQAj#HTpFi-=-R^xJe=Ee-&X1FB=0iw8^mTU+IZ0-BPo2fK@nT| z-KE&jEblAy4N8G)Qw~*Yi3)OwsHn|-8689^<{$em1Lb=nvAfH=C8Vk*yfj3R*ki{y z9E&HqL0;6*pv)nHdt^y#T!p z>=3JKqU#oXC&xN)Dk^4&VSdEqfiso9e99Z5CpCOex}a$3a{-ikr^22Ove?snNBv!N z!O?(4j)o7(_`$E4;ajo8O`jA5^I{R@sFzUl+Zm+%J0Z=hX!7_fGJrgHp&)1wxTbuAnp)S(vGN2vpBF&k74|g z(>q3;Pac-jstMAc!F`{pXjg-MBgIC*XhpdQaXj}b7L}JlRbod0wG&qeQ1;P$izq*2 z9o$I4q2|nXqBz}A*|+QoAAfNy0iX|XV{;lcTBj;rgmz` z9wO*W(c53SHt;@`7wq!HGA30&@%Qh=JqhHldIe<%!c==q0>A6s7T6Ot5k00MvIxS9hu_Zu$XPY5g{oy#6JwlY`<|tR=#!RUE6OW5p^OL zFTTJP|KPF?l)x-u7MZbB=a+|&Q4=Il4P%u3{0Qf~_K`0(f%U!LKApKIwJ$aBZ50zN z^f6Pdlw%GLxuZnc?v{K6)|fHr5wtU%T|d2^;Y%EN;a96ZiK@36V##tXUs|b)Nq0{a z`ERY+XuA%Ry^vF)*y*3T1>wW0&Zk8wDq^F%#)o$fS+j>kd>ay}80=3UY@*^?@VpGZ z`(TWCIz{D7emV#?qh{c1QNfQfwViEfb2wx%=g3hQwC5b1mmt&mW2tJl*#Ifd;Ys$@ zT%T4oRY(O3eaC~sbz4zanU1k*wTE~3++VD^I@v;)2DPA|On~xNI-AmxBWtRa0L(2Z zKNn8?sogRwtC7571l?yO=&#cHsTK51O(g&VLx{qV7ze_gYgSBnYyHf|!TVjGo5=tG zBO@Fko)7GhV0cDXP_@YOr^_s_IVM{C3;rv~#jWaMZDt#gSo4(zBn{^mC67nbQKnBK z>5Tf@9vwURFf|(Va_o9iA)!}!so-gq3fR$KhecCVb^U*)vocfmy@Pl(DqeK)uvlJH zI;H)7G5GId*Dehog%b!;lbdwJk?rvg{vgPR8JA@eRZxhR=^Z=1kP<3jVfi$nC5uoP z${iowqpREODv;-qn`m9#MjhkpWw4k>|KkUCt~1MLSRP!a`crqKVV4CGNc3Z!*&aa1 z9YgU(8Zrn`=P2p(&)iAN`#qJ!O*WNxsXkIoCE%d@9tcx=xZO^n7A}IXpib(bczPxd zN8AV%=jl0NkA#nnl4YqdQs9{|-5w)Cv}!_{jZ7+X7{kPtDYI|zHg5y41HR!aB;chd z$f1(25-J2jKl<5zF2D(kCm`U3RxYm)VP4-nfvesC%IQ>Y3S?@1B_)*$;9`Ol{fQ08 zJhn_$>dQLi7rGN%`e|@&VbN*PxbI#Fqir_-WY2DkC59Rq&QWBZ_ESoTVy1r`zV!(D zGBcp3AmylpfGN+~598akCoxr=rv9{&ooyUL0}{E10xsYreC>OB9(9tGjdOf*>jACP zw!v?SRBW)do^M&xy7rN|C;rn=T7NVS%`{QARFeeKKulSz=!{mjQvnD>$RyYbMa5ZV%rmCM({J zDUBLYLHz<7&GW^JQd+MHZ;3JI#t)TpaOp2>T!nu~mkIs15j-?Q*a?NW$i8AE+E~R< z6dZM_JrSx1g#Jm2+f3~67^Ud#*l3Ec({{C8#9OuaQ+Hus#)eDDNhceKcP3f7NNckC z)6I)vY4~ZjXGdWjC1~4qS8jqwyw}U!ZKI|#Ge$LP>vM+K->UrP3kYaqv9kp8y`OIS z#qa&Tr4xB_Ts{deJVZox%m`cfCwp{eda*A-Jzun2WOHk=l@dh_8sMfB3{*_W@%Fj>JEsd*8n8En+kmbt>FO=}QCk6_!{MI8V!Bwu&grH7>Awj5Zbd!dzd1D7-O( zuKBG}D@ks@vZqY^K_9+lo>bVX)hjEt&2thshCwc%uy^mt~KSA8lKI(UJj`95sWB}kF6Zx;=a_X)hN7>?D z=BDm$)*j{`b-cOx|53<8?EH5NdF0}ME957%5!}=cnm2tX$8$2rDA~L*u6K=L$!Ncm zfgiNaa7Yx0uCz}(K1{lyTi z+|16n+9X3RIyiIXao_DQcq21RBm0|Nv^D_+T7ohqX6Ofx!0V;~{-v8JIdOW!UhGEf zZS3&-X9)PcwOF0-4I5V>1LrSoe`5gh@LDz4qaN*~^m7%rCF11DM*yB?mZGPSyb9#3vF8BTGBW^>}KGeH_K1(|!|`af{JkW5d#6k11y!QD2g4 zlLqeZq5Bk!EBME0CCM;&?n7D{0+_?GiD2k%&gvpPm=Ii~qoynjjs*Yx+5eY_0z83pWN)xYwl1!7NdcU5aD@D!VUcF)CJ8xOxF?KU_vt(}q z^e;2gMKfiX5UYWA)ndVkG>ZE6Brf?hg?|2Id#{QjLfu;YW`DWV7 zDci&TK8$ad9ZxOa@1=giB0uE!)X55*TUJYHgW)jRg08Ym8nV`*#6zDN=OPbB%!86& zkoqtFGu}=l8*EV;ASmytRw}we4gpcu?t+}pK6aEF4L8(lE|El z5Y^=maq4-cNVe%B@pG{$k!XVy)AO@&tqzq%jEc->u1QX)uiXO2@3~h)zsQtEt#*Xe z*_vF93n%O}j1G2fymrsC^L=!HiZM8BXr^NBg9FoUEg0Pzx-gcjUDjJH+sEdvl$3?P zaP={$oM`s8Ca_a)H-jjfIi~{CMdK+fQwi8YwIC+Rttf3|~!va)WLVaMY+V%t55T6j15Vi;LuI zE>CNV9t>|S$MzDe>J*(yf;J@7E`61M7j=F%}0icW9#OmtA22@j{9FnnP%xzt%2jF8f>qRby?S?}QhMACUK+FiEqvOIk1%d^i@^`yG zqYk>4jYI2zUtHO)G{$ed}$3pIq$HBxATAC$#tU!hZ(zH z2QtQu%MIEoHh{500ZlBO+(Qt%-qHxnz(}gky;O>B)AhlIO%P&FJAIa$;W!4iLHCBQ zEOvqBBz7y^lADw>jAJ#{3=mm%4hEhScAfVUr$?uyv$`$4@gvyVMD!NuI!%eycEC8H zSqNl^u+K&o2pJ5NjDusy94zU;@7)Hy&HyJt50*$%LdYvMgoiK0++55--yGR@v&uFL z7WGdG%9%-Q4ZXf`^1uJ+EJeOCal{Ogj%}$B*Dh7<=_XJ^EGoO@#@e{YCVYIfZ1_<) zNSY|UE7164g|{O@JrL%#YNqyW;JNq^*a9&uk_C_CSwI;C-dGP;di!sz;QD)*%<>(oqwRn{p8{<3`36i`O8~Nqi}tS??H|vG z?WhC&jK#%miEUF_2jSS`4Kc!mve3@6VIasXgxgyW(S@yUXrdmSNr{8|sxOy-j)kVc zX-)@2qZen&AST(%fcN-JwGIpHn8+|q1iXRA>$=;-K1k!W`2f@pce2EfKBK}UDkA#}wrGW+U zm($1Af|@lHw)Zz?kce{~THTJ@r<;UWdD$vGrTcFy8P=Mxr{3H5Fw0>sa71B0;I(hY zidH7E>-E2bOGQk8RPw}9N8Up8RLc-i#ZV$y_;A2jd~8^^Mugi!wyzr;%aD+L+_eGM z+(dj-Wi0h88J0SDsq)XZu_vFXS1zw~Wsca`^b-#~OcWdh3S3!}v&6>$5>0U%60qes z`n0LwQejinNJ&I2R#+!yTTuV2+%_MKGs>M8q}%p)lz<;qNZCxGgGle=ZEz}_ugCi$ z$YsTM4>s5R{qQ*R?`C)-;sTCmF>VJeG)ZnGRXZXQD%F>cmKVP;oW#2Q%E45SBn3{hl5B z2iGFc488b;VNtL@aMOh0Dc!endncQIWvmonCO?CbuJMk`F`f8~`-%N$m`V!mv4jfF zSm2g6QctyQXwUP~+;s{eM9g;@0Xm@dLhL{#9^0morjFW#b0R;+H2mw9UXYpQiYIpIeNR!8BiXh<*l<*9Q&~jz_Ou$ z4>~zpZXzsJP}E`Yvek8UzYWo?&-buj>6u6PLI^Y&a6|UJrG!Ly0Fw+n!X)c<0}y6}8w84cGN`L?R-hqrZ=%^}U|BJ)!J}qQ|hK4q}t9 zJvFrO>gwu!AMj=KQ!I_(cbfPSjI1@k`y|JiSTD$Z7(vvLnZ3T;7_(mszwF3*@o+@C z^yY4CettF5KWfpBlm88M^R>)ydRGLyF9U@IZbf1DL;d#ngE^Eh?M^qCuRAHe$dS9y;RNjup-L39(mXZTD|{rCs3obzVMVAVqn|=kieB z_Rv_H|H0W?2F2Aj%GwMJ?(Q(Sy9NvH5IhhhxVsbFZ3ync-QC?Gcp!N2;O@?u=RLdj zcjW!5_Srw~s`*3Bswrx%>eW|w1FGA8$o z_Qi#GOUuh|g~`xKggi04Y}@t;hpE_KOii`D6}2|D9DB<(D?m(4HV4s=g201w@)SZI zw;!6q#MU-8V)#T|Cn!$Rf8N&Nw3fIwO`1?pw0d`ph$2eXMUaGp~ zfHM;lxo&iZ|8#ltp`cmQof(Jb6j6bC+`5MBjdi-d@$ByHp$T%>*w|3@YH&{Z7LHd}k#)zt-g#S5=`$reBZ_E19{jnxS!xVE;o4hVMBF#I9tfwlxLsE)>E zWMbMH!v8wYd|^HySlje!p`u9;1kIY9TqfEM!|M6jwKoC+-;t1J_w3-%JU0v1j6}Os}Hrqa4{P_JE zk2$}u5A-9NZ|ib%ocoVH!W+G@gauvI=o^woIqreu(&3-5Z%g%mOETEOBr;FDnW$0G z(R119-H&^jOLKEnuRP$5+{>bwcK5CR(9v$bC+?sD&p*;BIh=0v!M(Y;v#m#;^Cj55s<`zeZV1)?DJ)seQT;A6n90*5G+!E)x z3V6}`#z{przzu0OCaCc0T5n`cT9I`2I9URGB3p&if9=Qqfb&q{~g}fvOVIauHa5JUXW}8=$&)Kqvfs5Cv+9&JfA?ehRrPQ^w zvLA)UG6d}sPChl^^y7C7qwfXekj9w-x$(-XBW*m{-TdYo zv?_45o9KjSb&0eWik?$2;(`u|7G5!wQ&SJ= zAbV>3ZZfdh`;o3_PJ4b26KDfU^NhqxzCc5O)$K}R{6hZMsm;Jg6X}RWqcmBoQ!8F8 z`bHks;Wwj}Jd2bFJ8*zXyp6{v?DO_tRRoIjkqJ`+i>Y>-92eSjIXGgBw*BX~i7Bs> zhWD<8r^S_LkY3xs6ulYPNN;4+Vvs9t%jkz0iP?#T2H}49Rp95`*h~U+E^|&SswW!B zDsO5L%4seELS2Fy4zxFaOoA!Tc#dEr&h*IxMP)h}HO3_pM9avA_%UXya}^0BSRaFn z_Kul9v+~t<<|+~tmuDC|RKwU{?9b5w>2(ox2}TWrLlR%kc;b?>Q7t)xhbSeSjVY=5 zNx$flK*}oG^;j*>PkyZwhUFHt0lpkfi}o(E*k5v{a4irNcJo5>4oeT~TXKqhJHt?% znxJW*7W*R4X>L}m?yQ#2F0-WBe?GHPPSk&Qr)+I$9k$Tyj>3S{#J6DL^2$J|iQCdS zoo0j4z73QV^&3rN*4+VlTT*D-xi^lCs9Vcp$tFzrhWe7e8$tL3Q>@*?yZnvgys*R( zii7*e%OtKdL)Wiz(EWD29OgPZr*S-<1Zgyc+jh-ld~ItItr{(h$P_dP_{xhxJ-XN> zli+1`C=Vj~KyofEc|0a_eRWaei+biupA6&npES*?G|5SZadPyYTZ*I%fS%Sj?wvL! zvD^@+0AGWtQQ|1YAVuS~FiC@>+*wO?AmB7rSV0rf>tf#Zj2gb3X!p8>y}Snr;M5hw z!9hU-V>>0u-uPONR$&{qzn|2bO%+qycBD7qE&21JT_CTbO75j2ljDOiG;4Y<&M;bo zEeDO6DfZEvvTrtd9PHJvtlGOvP7+}uNT(55TKfr=kXxTr-IHd#A`XrB|1nvC_qngZ$8S zaAu2r`jPAHuQP%v=ageEWIwCSu`HZA-RLQeQk&PG2nTg?)9BK)9EqxwYBzjkF6N>u zS$8Y?>3f=Q>x%9&NqNM97`Rx0#*uA@MXtGieS|7s*{r18mU=Sr2#7JMV5lx&E0kT*TzY)$Inlq5yAZRAA4Fdf6J*CJ`#^AU)a3Lp%icL{K0A zy+!}UfeuHg6?eMXbL?mO`aXJu6ED}9sfHh6pb;1bTu8U49NxCU5**K!+8;azH?T4? ze3hF8#W}FO`IR+>nwD~zlGzX-7O+fUKw<>g@-l*GX_bDw%>=q7JMF$I9RRfc#YM&Q z)-9<;?zeHqr3W$C&Q_<613AeKS^Fk@s@$=?hIbL%6t=V|)R@U6|B>j6yM#=qyIpZ{ z1?YrOmRw8(T~K!K1YX<{G;MkavQxc;(!>yQWAneXwC*9Qai|Fh#|pqV0<#ZCTWht5 z*y(Wl_3$M8lc>A7K(&uAUDZQPR(@txF246Gf+@!o>XWSId2|j_vb+kR@qo7G{T1&|7 z_!NuGVd_rd5`v6)-=^J`2ix$Aco33i9$=;3{H0e~)kG*QR1ZV6kXonO=5K=}G-%&+ z#y08c;ko(Ly!)` zfe@ENmp+@;0DO*ts073P4UHkL-`@x>I#O>h?%kqmkjrrI zer2cjSHvOMM<^$T6HYV)?3uMuW{uJEjyQ%N@W!q2^fZlnxi@1l97&^#a6E4Q`$&#h zdO4HR*&FEl8GlqB24FTXLj}N|w4*Ut zp1S49LTA9~hltV}md1$%1nW?3o*P5&e~8enEgFzW9ueHaC(j;eM;6%%dnT9z8PAd{ zunz7el?tCB=Cl@pFw5UuC`Y6O*iIYV{>Jwsbi@uhQc%U;GSO)02lnGy#S%Zd(I8dC z??bD2U?;uF(2$fKN0BUcfJ1W~qWV%X5y<(t&dewFGOrl3yFzJGP{id)TB!) z74`sZd`H@{9@s`}jhNa16^fx+(E#l9Y;;NH+#ckz9sjbc3mtl0Cl!Q1?dHhIko!$a zK~ESRa_cLBX7)(;cUzJSQbM5Id*LKROv3^`1OYOg>m%buvtSNCH z9=_I|OUfka8JrLx0PbLy#_3;w_k0f+u_vEW<|P0b)n>OgK8=(Hep?$+$@62y$&)nV z!*Yv%I2EeeO0J^Ygzph%&Bn^?6<_&XBQHuK1%}Z=JndLYmXGE~OF#xBhTSZDq*V>f zKt)b#q$a2me_@Ld!l1-N-f9A{`NRu+!fMP4D5pZ@f24yStBG5h$C6r&_vfw+#MnIi z9V9dQ+1NZkl+o`CQfRO`R3dWRuc#OT_G926r8EWxjY<-7yy`^R@R8!I9=xt~+=|WN zLm4l<_Z}3lJ6y<0#DPAbJq_566zIUdz$Gsk=#%*eF>(8J#^4*akgLDI?kG#8ydIU= zAK>OFPtu5}XM9;(+-1o~48hqq`8K1;PzT8j7*xv#sh zfh%jmsh11&j}gip`T5|ByPv&f$%P08`EPxV0uqzGH?KR+!iZ@Y%HKO#Nhbu^qGxE!vp^o|@ZxF~xnY;8t`>OMf4LCNHc7ZsT3bp7r~m8`dIp;$nT37eB@vPE;3Vk`ihb zgKy8DeC=3P%qNeQ>nf_>z_g#TQCL$IY@fcHyznFhm&S=lpm}jl=ee*+?pklr!0meMOYn>x60L7`+1Gg0X+t^p#~`3?e$?y6I;F zX`>S98LB2{p|PM3aRz&{T<;mJ zmG9^C`D)_Yci6#cX=z1W-*foI4oh)7^Z7RV3VtW#YW`~Rb09YNY2;% zpMIbEi#c1A))sn*B-a*8Sg195Mxz5W!FJKz_Zi*Sq)7{J?Hk&6=d0md=8AL!q0-UF z+b)N*`T54`Lv%S%!zx;HFOP;RZP?X&dCHkcM-CeY9tM@lr%o=%E$tNT+@Wmk#gD+c7Ef_rYEf0i4ZOeXdX3|_IS{NxH5J@xdKMjzfXd%TI| z6-Fda(ZW{`-6#UH|}eBjiXJicn;TW7H&+N6HOzHU3SN1x1g6ATg08`$o*0LRxe6Vsk-5QgET z5Z{(#Vc=4x7exz={KUsufhPjgX_LJ*J@hU5|9JQ)(vh_Ey_dk_-^*!TNPdL>d;@VC z77FU0^WRB^ar6IYGVITPIY9D%Lguh#{{fln*g!(pI3gZ*v+%xB0|gXVMWAK*FA*X1 zV(N;uxKR{V;@nz@lo+a!m^32!92~<>0R-agQBrcgGDMYzv$VM!eGdbYLnm;3aLrYX zqbo(tjepK2E<3n7PETf78&*&4GaVCay!R%u(y#wqXQgwIimCfVD8f6&h!(@7ApujM zD+1DYgwSE^dOrv7kphtd?gNSD+$5(M4qDST>vzPkqK~a zi_eVqlG~#t;r08&n(q?xn3S6JME(52n7nu=*PxS4nwn1@Sj2QreR(7?n0=`2=cGB7 zV5WN%0{?e83OCPv-_g$j?}sx3Kc@xvv-NXLWZfyusOTG>8I!?SSd!X{Q#qGnv_Us$vLHc}OXaYN>Zrh;2&@YXAwPeQl=3cA9IaBoKnBc)2 zeIo<4#ScFK!M(>I6?L{H{Ujo2J0+hn{{RsOEy)?C2LT)xqh^dp`)#YzM3Qg}`#2{? zI80$M`}Z!`uNkQPeFeJ`2`2WFX^LtdoiT z(J_@I9Ft66lgYMzvQGNekr8g3q^VY&7>6C5wN-hTGuF$kRM<|p_fh@P(Oy;z?Mvzu z2DZOasqKNhrLP#Tj#ns}Cj|ATn|2u5-I#=*h-hdZY6Gmt@14GQhCpOqonW=OE0WaT~>eC?xkfssXJz4qUX z6rGfwKU0DN1Yd#LTxV)|0h=lTe}9e$PA$Sg$9|!?VMRz{9kl=4eiOLRgnuyX{hLOD zl@}gCS50WrSo8%AFF#Ud%jc>>ThXd$;+@&b2;J>YFi{@eDRo$F*eO_qoK_f zn$$}YjnNbjrw(kap!k586&kYeg=U^Qdg;yDj2otEw6_a#QR&7&EnP&CEMs7~F`|Z- zE--sAU8|*Q>lvA+R&C#;JaFJcqv3a^`1kx69y(RQ%lC=L@YcrmjfB8+iaf7$1KmtQ z{$Lc18TLSF!_&wC$(9WP9_!7LuMw%5#}p(9z-+knr5n(!cSkW?;N&OFbDJ3nPid@H z19R9<>xVU6vW=u{umY+Vl{9fP#Yl_8+v9mXam5D#n}nwfbsf#%Mi*R%KkSlqK#bT=X~5T>2mb zl&Ehrx(?qgaaA#JXC>-9oA|_3tm@z|F$S|wR9_hKW5TUKR!R;} zV7G#DD~Q_V&5D zTNmKfKxHt+coqQA@S8MR&hMuRy8pISZF~RxJ%w%;55(Cp!7e|W6X1+T8|ommpxpKh(hAE(cRy4w=UYAiYA`I!JVbIem zDWDAw+YnBBmGvpHj}nH2ov@PwYE%|$!M*J(!$@NRBHWS%w4%WHmwAFn8Xo$tN8@Ob z$*!R(_o6zMj94h$yUhkNAJ1DX*0oMGX_pwNmzgHP-ct(jff)KRRZUR0)@PHmgCett zPy~Z|uVSBm-X!}LX@ng4LRXVN?~Hx`7aHRWxQUd1(scg@4n%=?7=$SU2*QwH-#gkHf8w>pSrrftOhMGIz9(BD?zHK!PB0>wf=mb&?( z)HoEVyC23(Il0mo(;LoK_J7EkCm;fgVqbmzo%bd_c;ERi^t^T5i6HD(|K&92Fy|^} zXC!oo_iRzVv z#Pux*X%m;h%AY7ctic+(?B?-|NYgeHzJ_IJ(38c8QqM={WwRnZ35qGv4mr>f)^KXE ze}8E}NF&@ZtTbDy{NR3(5)0>H#E?6NqE!Ja#EQTBfpn$L^3oIfTd>##{I@0(wZxgZ zWu$I(C5+g+NCir;CYYSK@XZKl3$`Fsm@y6Nzhb<>NlnyA=*>LuOV}2_YSpJCVJIu~ zlMvMUP5tx=us%HqskZ+}iyQiKT2gyG?*wr(QaeXm$3U)Ah!G)c6WWIHF1fBJ)Nyug zX*MnDV%@~lWBtBGjo&SVv~Xb4fuYZo1koX7w*}}Fn9)&}wibGm2ZE`<5L;f3H}&Ry z@v$^S!xU!2mgOh2E2qpjjjz#EkXt9SUL{R zXsPXetDlU?4MNh%8fsXGw0VZQbE<0F9G9>1!}n9Lf!4z!3!O!!#>||EoRLn%cwWuH z(mQFt5G>zybjsyNgG;_Ak~`&BAd2{N?DW!6fVwyO(lS%O0(nc2Q5@d2m73GG;K$3i zP9;t+I=bi@45*61vg}Y@e@M4?l!t>F;T;!%tR}WRx|OsZstkE=OI9!v_-r6*qPhkHHFsk3T+piA+uNoxQUUiwZ%hVJMz>3$1En&YM;iR&3zwvDWOkF zJqIkNOOnS~1AW3n3K@Z8{M@{5+dLI5D&Zd!Zo561gYraM_}{2@uF1niISL}NHQm1< zZQ5p1r*B;?t8cyOS{ofLQIg?(RMa%0cBM9%@ysW!{@MZi=3Y)`LoVizA1;AQC>%BG z)C}yNct|#lUp_yT&2PqZQ~Cn@^|9dc27<8nHZ|q+5m#p@QQOLPzH!pWoal6#Y=WKX~CLX^?4w=CF(tZ5%&ij@c^@oc2Tv7PMlunjYDFhwo12HT?k!Y97nCPg_EF*($*>2J_nI{c8-ql%6J zG#Wg9t{U1WH_l)>9&DJlh@C!(pLK(~s$DPE1T`g zG6LV*gYaa$C&bX;4zQ=MqM~qQ*l7XxlPt?~WHT^z@d`c7YnnE7#51EoBd5MC=#kMW zC~WUS42_id39W6%%T^jHXiLf7IE=cG1ZiMMNKz?Tpd>jW76JOTQ`|>5!xuZ<+GTu- zbc-iTX4c{5vDTEjV^<(8`yIy`lYKjh{ZqeBn$x7mX7dWi#h^ZqkR{zeaNq?54*bW^ z_(f?5`;Vc)s2m-jV!#Nk2$iG(Y~7W+Ayh@MQVsBA^Etf~@U*spbU!{mUz{ii8ooBv zL}p7iM~_uG@k3|WRk!(KR<^rgHaB~y{r!Dxv~v}G(GHu4P~|17^*ulugbNT1Os4`l z0TuDEu(ly^AQ%3}T+(A$5;`byCK$O&M>Og=DvWKP&9*>9+i%whtgl-g^POI>NqG3% zD<$i>zu)h}4$P4chSo8lX~2n^MP9{W`}P1rlLH44*`k)yuzSBojFRs)>$DrMfPw&d4VOGc#3BUX*34|;L;By@U? zo0_yWMgqHFM4#`MKS@6;hUBb|jjw3)y({C$JNyBleqs)LfxdIL$!5**L*!s)rf|s! z3GoSI;%hY3f^@UX(KyMALyIYi|IyE4f9z=yKc3!mQEBu4K>ikOcDu_2aWs&IbKtNa zf@Ig>t1~5SQk9Lc>n;){zO*{Sclx|5y0&(fK;|y-0M{VIzFsGPU`PxS;?NBOy%nZx z2!b&H0oKQJ^8S9V8GfJmp2qU`@W91PG5W0RUMd`RtEA~eQ-i$a+?93jnlW`|>Vn8U z+L~87yzn}u__8BKOn`4dz=yx$KVV8zmtV2f1OV|cD?)Ljt`szXLV;b(*!Zm$zFa6(ITOhzoRQwRgjZPFM%4y#U z@iP*2s4$Mrpjmzlirn0WSS^MFJWa3VgjVoyIoAeCLmQ?1c{?yN)${Kj)Q$#+cJyoS zx7vQ-hjuoy{mzn+r=TIPprA0JBvz9zZHFmh{N+bDy3XRxRNPS zjZfea(9Hl>LKSC?&(S^F`kk$Oscz3WLsuASj3-5OYR>$tFmyfHzw8VvOCZF~P>K$4 zq!@}2{Xxg+D}vD$P-jq>ZPHlLO}JOH&IT4`UL7>=cQ8yN?ToKP=kcye-!0BUpAu^* zi0Bno_I`RgVM5UU1^F2)fw3Rb`!qM zT8GG7ssCCCl+66OM5mDUOsinEpfLqAO)cv2TlCcg3%7JRB0w$^$fY0gF(?f_f!dj( ziFY%UO>L7Z=!~lNUWJMEA?FoGUDnn*GXHcY9gY_Z`o*(p7xV5fqx<;H-pU8|Hcs>z zF0wJf$x%RqvM94L5TFWeCK~}ZR_4*Nh@vIEA(g!1Qd7WSU|QD#mW$m zQtF-%GtYtB*8tK-WCo*KV{aKcx2G4!H*ndjjr|^&t^0xaX+78`x2ERP4}9J8ZDH{% zSK#1&4*MB114Exh_A`xAjtG@ocaCUk5B!_+Cd@-DlMP3vg`YZkz;|x>Vz})@clfK>q}g7?&dVepuX-6NC+pW=#{R%#S4%g!}x} z4YskdF#t1ErU4VIR*T;;sQ1 zblWvJ!7hA@KX#e>tKsM@`m#e(2B)0~iod-5g(EZznCLflezt1K(s#u^J$){ z%U!z38t~-H3h+$7McWBNCFbp&rH76KuXb$8#oaa!^6UvN*DC*lR(z_wdPh6D*YV(s>CA>iTTsW6j; zmw1r%hsUm386syNbeAKnae5&A)M9G#a2K;@P2H~iKpTV?&20)JDhV3nO(v5{KJ{?2 zW9hzK(A|Df8?KpsP!oDZZn0YpyJ+z6S>Q!Zis0rd&_n70M=auLJEI^7g$!rr_jFPku`R7!G6+8^8QSMMPMiT9>TBH>hgxO-go zHP1`a`yw7Vf@AV<02H^-Qqh?HyCO~PgGutMD27!BB(E!Z_Tz=uCz*xWb~p6sosJ>= zX-@l>-`8yH4H=bLUTdsLX2%f-H_n`&JSzjo?Y-dwB^?mZHaGw}*Hn}k(L=Kv*rW2f z)%NJVf5%t89pi5!*R|(d|2$sJD=p=>;a7-4YUE3>uof?_dK2M)FDuw|6y&7FIYH|0 z&MeQJFj-XSMILPxCl%U z0E~RXR|^~mQg|oa_SFmmVVI?{!qW%mqPzIp=)+NV0YM2Jm*3&xTLP(=o!kQcEaA>icbE3c%U}lx2@5;)-XHpSPY7rBH6Q0m$DAnm96hRAq zmvGkZp*=he7UubP_GXT3(|KQAAQ(JCI8Mmhz=OznB_k?t&YIhYVBUbJrq3$tE->HB zFP_JK^G#^x^h|TLP%^iqi%=kg2!wNh-SR*<&1JAC=W7BH>~3K4+&-xE#{za9!5nY` zkkG0uEip^3jDgkYd#OhLxyou3R^ORDA5Tk@gvDn*Y18y}-OSpqLzMXZ2;H}Ej<0mC zLx>3BYZIm1I+byP?F7ucf-8v$^ujE#)MJCbQcd5#E~l6grUM_JUI=cUOCO^XG0@-! zJSfzkP6&S}TRwdr9zhb8(oh0gDuFAB0e@fz zen3s`bpiiPSPuF?g(QcvZkpgJf{Iw=9BHQ^OYwok9E-D=dp?l_De72(@ZFCFA&CR6 zZcj;PK$(av3LFcjZJ?lG zN>#~pC%SlvV`gWbL#!arjQT5eIDdTEcVp4Am5zr_(+b3jxjrb=1>i7~Vv znxJ1{T+a7w>kyvI*llw3A4T>KvZn?Rl5|1*h-e0Bm;!qgX3}XmDveF=KD4dK(M^mt z&CcCXAdy0l2^HzerFUx+TBF{%yn&s+jF4bdiUgf3A5($)Yctem$95m_@(>W#X3~VF zL|Wo!*_ZpPLxZK-XB?r6Z!tvi{Cp8)$^m#P8R6oa=ELL!=~~h0K|dIfIc>Gy7nnKe zia_ZkKw8$-NVH^d|WSWxbr=P}2PGHCpZOxGpa2sElq4u)SuK zp|A%|HsAG#5dt9cq($SG+EoRZz;8DD^hKK81!cAlXBAWrKI%W~uQ z_)9n6`Y1O#IW_p#;WXE*XPu&b8R<(MUxX;y&RXf3=|H3hIW#g{UB@NCUy)99Yl9A4 z1?2EU;1B9uDsyrr7;4iQn!y3ut|PERVha2c5%L$4W^$(n<$4L-p z)5A1cP%U#>K6bzx%{FQ%PL5JG9;nLF#JL6ra1ezq!K*MeJY%ad1GZqS$q+_lC_eBa zAwmn!{82wzLhfkIMMK@@V(wQ5}Wki4*eHTlBjqFnSFrPJWuxE^KTFB4NBAhrAA8smFTnbZQYPO63 zoq~)NMUy+68;ubWazkH;ZD^r|2=q?x^>W`vJ2|+V%}%s`c-(W*-oV1(T$^r1HO705 z>pEUO;Eh=-LKW`QesazW8txLby zaEvGI%&SEIeIZcCAL`!2j~MfvIVh=OetEIJ24omTVW=n?0Eey8F91;0g6BbW%aLAQ zm2P3K3VU@EcG|i!9#KK4#WN%~>1Xrf#v{wp9Hb;hj1y8*(6fFmScFLS*@77m;*ey1 zDOggU`mJNS{Ne9{z{8<~a#YD6Z7ss-&qW&0ceP=P=#aZC<|4$R6Zo>B0EPnA`Hyg_ zfkbY|1oPAcq z`cs+4&GJac>H2sE5&`PS@tnhlB8Kw_5mI0fNIsVzG2UQ;;ps?Gt0{ntT zcHd<`TNik#M$GjNltx3WCjnr!MI~$<-yoL_V$hgLr$;-aau~CJ!M9$GZ7uBFnjT2t%=zG;dzTDXkHzd|}PTs-plOT zTAY=11WGvO9|F-NE5dD<_@M5i58NLU+OnZzDymnN>$~Vy-)Hw^q7D; zBFyKv*i{IE*yc?04}!RFZdarg392D|Noq)iDS^h$ zxzuu|ymFo!Y;UqW3l+VF9%ZkBlW-3=Zyc71C>rYOFbx*d!`J)M(aT?lJW;kiq_@A* z4W8`p?@MTE;zF`w5QCs2h}}lvMaytgk)_lBGom6RVcwV?=3!KBUJ*8#rv+c5Ic^}! zSh>OVJuIlA3T@r{0*@d*5e<%lCHU^hw+Yp8WB5z$cgDzL|M5yAl>~Fu)!W-!cDogB z$Y>e#AEX*uN>I1ksf$2Xah9NmxX$v%twWyeYbJV*z!G6g71rf#|A7j;{oAZ5mUs5{ z7hf0r$@f1-mY*0zgZ~h=tQJ2A#VyZ89G`W?Be~4YU-vnNoV`pMy!8JNllJBuynDaC za_ux}?dpl8l6ezPPEOvu^c*Zcryi!O0}hT<22&nY>NLQS`CR0+Ek)oE9Ic3u;>y{6%5cQ2>yD*%*s zn_I&0IM2tT6Vls_5WJrfbQtIlrOdBTE&D+sgSa-X?SDO~eldXlk^1tH-ksM#;AnWm zf1S_LB$|?wD9HC_?bhnzn-cOjW>)brAk0~`O(F>`T}>-q?DP=+$5ZN|gu&!+?t^u5 zgXEBDz5S?-8%>FBvBc4M(w)x z)vkK2=Vd}j@z=%{_zGR|)TSdFH@Ir@is_C_U^>wJllCs;VYjbHyCSjAvjVm2|=73Mz4ns9J(> z-iNPm8&GEsDLtBqN)yQ!78`Z6KGikTGA?Hsu<^3HrL7nE!)~;Ra(r8xQ{75_s5)ZGVTM_KaQPprW7t_llYw0*qMXp?#Z!bkP2D z`2VYlTGGM9&Cbl;^!^8F&8Y~~B~q5P#@ofH(J+dVJyMf~47 z%PK0KK~M=}h3(&N%ex)7f(XgUEuLxSbCv)XT=PAUz_QApb~gpPKkb^h(L=aQ{yCx1 z&io`tlbL)+5Ul!WERoLk?ZeUHF{~rZZKBO$bvoouSFSCTw~udJYzc-#Qs?o0>|Qw5 zTp>ZLqC}-2MS`2SJzo6X=Ca>9m06lo4IhB-2B(Iuq@*+!Ojly@S-nN=d>JmI#UcJ! zzr)?ik}7Q6t~A{PfKbrA-s9hMemGacm^D`3cF=FmKHzR;ZL1*~}i>b7pLB)renMTdN%Vdu5DmQ1jWMfv}({_{VSimQ`jJ7KW0!vRR9( zwBx=s4Mr;!_Te&#yl(_n@_*}fPWvBR1*$HYv5`VG*a?!n7FLJ`Zijc=nU?b50&rH` zSKxYwSci9Tp-fCnhX1-Uu+n3o94s&ENF4o=@bWbP1bD}YU`G!@ZvBbhr)0+5LcO3c zIA=pk0~AYs4WBw4>#!=St^Zc|k&k*I*$lQK6@2U5NCn zn1?^Y;i;uS`g^%4$*DQp8*{u!p%l+gCvhaw0F+aQ(e4cFW3Uwaq^O8s*T2P1oy8en zOdB*mW*XF}+Hrp}%f-c2+}&+3f`|V%z0maY=g(3wfdU^JPuB=S>C;UG8v0Efjgo%2 zO>-26teCQCz{?BR09EoZc;b{(h4AtH4u8=!L2i~!wY4Dbt!+8LFA59@$alrIV-kts;ns*ps^F4tw2Zfx!TtkL17OWeYsnzm=O(iixRjZ->?| zS6+DvIrizmR2|;k-Dv_m*QzrB8uS`aP^^QDTwHVFfYfo88wNb&Z5_k7Tu}s`((TJu zW82Ly;(4|Cvv{IRdad^HNk-NZ z$%hylDDEd^Fu_fk4$L@|qdIj!ea~@+?<)HjJcToLDz!`jOF-x1OxSXyD6fD(xzTG_ zH71+%7fkMXEWHwg22zHiOPyo zA+c^Vg#NYE7)U09>u7FnHbb(CymdxZT9Bqdh8j^l@XYsnd->qw+a;-I5=GR=4#|cL zu)tBX6hET?kK(Qi!6Q`FTG$_GQ1~jaBM`wbk3QAVQ1N8z;{_s5rA5#I=W4`IDpGmL zdtvzHC@Skphw#3>Xspslz4wBsDZ)x zi$;P?!|rFOam49+d*+hIUXg=7LJX3*C$W;0(wbd~d|6FumW~&748&@%qL1lnwNRHh zz+QXV4He=A{$(bRLerijivOs+8nSP3d)3n;E>!FBNoBnFOaM3k%~kDqDx1Q>s4bQn zjywl)k=D|bHxYBgOjsD)C9fiJv%^L;92^|Zbh<&OXWkcG-M^`DlNvDRJA1xE;!$Qg zZYgVZzDTGjC>g)LBmT-wvYgNitbBspVw;|}uq9!`(LGj5RNxu7*;Sx>C*?oH{poa) z;3Y&+9F-r6QKp!NkD&(fh#&3j?0h?4?+U|$yB~_-Jhim4`;EQfXER729_9*PuduUv78GgBO$?I8;lV^6L;0F*Tm(AGfe5H88XbbPzMWV&Td*s3R=d1)@A(K<00xl?71S^V&zSi zs=kx5oeQ0=v`qbnXClSnb}*Lb7w^aG!hp?tFD9s`rzaE`>_3!6l1+8g+_`$1v&qJu=iH6aYbpnX1UCaF*7G- zJ7#8PW;GxbR}rV?1ZPP84Y%IYy>6!0Wmrs4ZiDg zave-dGHN~_k4)#g^KbF7qI@;JS9|LFJK2PvijgfR!~Y-*m9b7H^K^^LK&wH@C~ z_!^$D&_sD3uD4XkzCD#x#8ZlpQ)%%X7N)-uj_l0?B!4twH#(c3x1+)5Q(%#6$Z9 zs>Tkb5`h4&Kry%kxP%M90)YR*Ijlr5XtNv#+ysiZLB;8GE{s!D^DUWCp6J5?&E36- z6p~VovC>nU%>2JUs61@*fTzR)@F+yeN&LU_!$jEYb7NV_R{K`J7(?}%^X(FFcjFWi zoj`}a5EsJ`YnRFa5C~Z?VdPN@%G9VxUVi%bA>3v|9Y^}pmQAY%NP=%t`0GINodZiV zT+pf?03nblEHiN_^1zrmlp`)FaUhC_1W4hg`IPRa|2G!F2o z+6d@JWdwh_wWC1B4bdk&@Eas5u&;*{w|HQ?VbnFq;0xsdSvRLJe$i^f%N|e~+X2}7Vyx@OGabTXYd;M!SzgaCEAzmHrB|r{>}N^4v5q=5rQq^NgrX zMzLee=6ExDeGN%|Tc9WOvjjl8K2PnHSGwJq5j!vSnD$eiz~pidg-$+<-A@r`Fvpr& zeKoMr40<8z&?<{i${M1&kQ@%&mU*%~MZt_55SC@r_-T-xel_OVRFkZkI1-oSf~?NE z$Ed!~M_i*Y6$V#(=^PvLTuj$G_sx1Au2d1g1NygY*~7|KYDl05u~SgOS705!V`{kZ z2U-10oO#9S6_QxG^+Alzg08Ovjx1C(9Um%fu|b#BfuyEtn4$keVHs zIcDt3E_yH8{7#)GuIRnMVSi4Joa@W-=!|5Tb8a*1=mRg3O>xhHb0{4NRvg7Ef4YcUwCl_X9MhRt&0 z3^Mm$Xn&J5Z#wVQ@(Xozj1Sm;>vgo1e63UgQ+P#PkC46(0c7qiy6zBHuGg~x z5WWklITw;-ssmal95!`*=LpK8W)7v6x@W~G$It{o6nb)GIPmoEU3 z6YV%x zETzFE>VAP0EWbk&t=7>{PQAzf>rW37&``q*i(=vdsEz3F;`w(Yn14u>gzXHS{{@FY z_#clnAeR5%F^ndtaOm!npPk#ilxt0fu@fpV0M|BoK1v$3w}f!-rjzu`Y@RAj9bLT| z8fCH#yvuxCEx3U|b zj#Fb-v;B{Z2d|EY_YXl1S8X;US|fZTi2UgIJ^?Z4{2x_ORq<6rJomrYd7u_JLLAVI zzVu|c>I%&=#P(`GJBY%)D?i{Re@`^ zK{^#!jy$$L`t|NSU}w1~wNNW}KGO-4^D4*z&21>LuEX-A(NEFhvP$|mU|2?XLGPmuQ;=ArZYUVxQ zdupd<^qgA8+BOX>$yY+|JB|){)I2tZIdv*|8^S5q{y zBH!`2(tzmc!d&{m+wl??&IzwdL7&?i8Ve&^!{~!Mh{1z()A2%z#@89_*$yiziVhAi zMkuzt@3{>r*_>&vk6wVOV{_v8I&=sY-A_hgPq72pw{OrfA(XH#_MBb|Q}7YHKZB=` zfSi)$#H{Bt#ldAO5dVayD5~TM_gz3J7C>nvF+>fy66pRib8^_nn*0|)=+L8`9y%}J zo>q;RP7 zk@}}wqD-dx$6~#c!X9;EVqi1SFS2DEDKrj7Z@rWe#v3~c*ej+H2Mj93r^+` z8g(Fjyv}Pxj_{cV&_aX9lZ{XPWi+UI`kQ@A6PRkI&M`g$y(K1;Bl@DD_xzPpl2HWU(Q^}qbVj`cU4ehoirpfI*JcDuG&7IY1L76g@C z8$mh$AAHOSoQa@&z#_IQyPu;~0V8T(GA0-|44A1=F$WzmuT=#i6;N0NV?UC3_%$D8 zJ|A%9+ISQZQ)zssw|KwoQ+batVZDLz=1z!#t<1c*cEMy*_wAn)x%a$!lqJA4rXAAs$AISwFK(~m+z1$t+DT}GQ^vP3T z_M$u0^QPb3t4UdLLU?kP3^z1_)tn(GzdkBkn@rT?jqA1i5}}NS7VHdL_m#ctlBgo| z*^J6T;pzE1Ph-5v-R#M8?-{Uv!waoZCE;P*qQ`tI8r7PV&DT*vdA}@V;T${2w&DW? z)xJQqb6Hr(-k^g9_${9_Hx(6(l@1ueC`b#lWdQiI-jKZBY?k1m7r4)`0@{(y%#Bj`#!sW;Gnb0X=D6(*g&g z4~D?nkjR@`;?mEBgmMtIGVrbZY7ZT_zN_Y|Qw)SnA>jo2xSF{^{LV8`rp zRK%Al@>91&KC>U21CFhOs~XC}=;qFjcAi;wpcpaxHWeV0R*Ir&uxB2{-xk(=aAom% z0YluWo$>kV`eZ;PG9aeyChaijO}8l0(E+!Gig5xsu$c1+CFl)G35w46Ykj@wWV9+( zqXmB3RHt5|-Bt%Kq&(%?R_ug5nXiGYz{m9Dmp;;d&ti9cL?!$KjanUl07I$g>ng zGa*O`3hC&-jLCiCy`ij}X|+^g`JdjX9DmRPqw1{mfB0LI;b`N-nRbjR;c_S35W8XL z*i8n!50DZR&PDr+G6b&ahJQd7flDUnNQ@!6Z%1LQ3QsD*X1LDp?CRV7N|mZEq>x=1 z??EhOfOxz*9wNKnqr2s5e8|GEK+FRdl(q z7XxOsM7jBpdy<~;Dw(j+8{$uO0ikKV9S8x5*b{-Jh?<`+qkqDkD>L{zXwmWT{f2s8 z0-j2(l70FK+@xpC8W6EeD3Tt0ouMETYy3V!d0-+==AHYzMU?^FB_@p%+|Z7c>!xp{ zd4!ImiJm_8xG4cUc*PkFO%5za9~bzDelosb*GLJnTET7nScSt*_eO>mWj}`3J^aj) zw?)uPCwAY3_6^uP5v2p<1_;*;IvG5VauU*%{h6##Qx`snFgvnQd5z*l(WpluBPyd} z0d^SE1|pmYr@;(bi_E|IMSiCp&hUkHr<9v%*`6imt2e{q;aNu>K&BSa<`D>?vm*X; z=0jL+x*J48G?ZpnyX1(Zt`pAYBtKKi4H{us_MtK~TE~!De0#h)h`GIS1K-5w+3w5( z`}lHO@oBdDRj=LfPqgxn^*s=Hpa8M^F@Vjk?GvKGcpzDw5-UY;kv?m+MeO}2ANSq) zrVm@bu;99NE-!RysX7MVhMNSlP=sPih`!`E`k{=LMBQFM4?l)cdpyP%0b=@COk`f% z+V9Od`O*SEGj;#IGhXu;YP}lpbj-Ezp?WdScZeO#!*=Frn+zKHjboa?z$R(I&$Jh! zhO3P8r=fc(M9Ao3NMFC3E0x1o;sWjOYOHd*_#rYi<=$G%%`hT?s+ZlTk_vjK&`}a2 z-&Q?)#@iU*_F}sf`C8RQOJZ0jZzpLb>d&BA;E+v7i7%Sja#&V=eAFCt>9M`$XsSM+ zMsf++t-Fm>S-&)FG07D>vmEGM0cmg6c!=fGa&NFpsplGzX>e+m=q&do+$y%90@h zo68&YHv5$)s?PFe%*Jm=rsmF<=&q(FJfcyqLWZ;ehA}Qgv84T;H#=_#WINI zT6&u(YtK*1DH{|m+fqj497Q$1S$-^i=f-Jc=MxS^G}RlCUm(&Z(Avpzo=E#;|MA?m zXz7Cf<+>Z3C5whAa}st~Hgv0=1!}w1#U-iMj6~acmkr2Qmeg;lzLH6ER0;Qsmco-%-`cV=>MItiAsS?ugJ#<5Cn|oUdGYm5 zDlf!;&SheD_t0$~QPMHI8r5`lKYAsy&J|@5uqymPXdzN;z-yZE6%QZ1g7@@<*gxNk ze{#U;-h#jWoKvba5em#Up5X^`d6oVhwZ^dgvlz;xC11`X{B<$zJGK7csc)d;%*ZOz zV@G-_(N2sIm;#nQeG6W2C!1}6eCNpz>4lq^a6m7ai1hCftrOR$ZQ=fi=jq4zwbK(a z;upyxvmEreq3g*C%0>MrwI_Y#D*nY^tff8w`fy1HiY7ZF-wPBV0D!;iKYPCaKa>!m z|8_e0e<~p$u>N_lEK^&P!&67euKA$c|1kuh-h;W!FMub2FEy)l(E8 z7A{2SzW)z%HFsSAeU}uWVm^h>($ylSTiK6UNDvQ}f%qy7p6vuT%1|a-U|((z z9N2(WyPZc1C9)B;dr~C9&`AZzV@yegVEzu5mjei`88E{_EnRuvTet9v=DS@8p@d2R zA_*pGJhQ1TlEhsjlZbvpAquPW^75iwoQgOWe3cD4`y;=i{FRLji6r!~`Bv*Fbo^Oh zhIy{DQ^4yJlmE1Vl~oO|=*|v;zrC~bt$glfgDC7S3~o#)4+ST-W9=pf((S`Tkl0B^ zMn;Nq(!{|U10|(96=8=*KEfLDz;A_K4}*bTeza7}gz0cJ#rU2t&91W6zSNjZS#tVt zaajfcTnJ*9oZc!ZnG`@AfFs>>CM6i!5U`66!g!4Jt2BaL0q2|mLLwsRZzp$L2}XS( zeUhbfmS|vYWMGAA+bu0E6zShuU>uuTxj8wzs(aDq1fy&9%Ty#Tz8~_!co&09&+fc{ zv7?LjK?MZ`85_ZN_V+`XGN+mQ-|39Y%E~c+au;AW;o839NSN;{PX_N{#Fz^c>8A@J z?S81xS6A6qAoedB0nE=Y)D!>|d%C&;Ffb`J;NT{1n7)36NI_J?`;7Yg&+k02?9#F( z3n*gWhlht>_Ki6(5=R^AaFdRzLU3{!!MsPB7Nn zUGEu-SphEz%Z%h1O5-re5Fr&roKl(XA^yp*c{w zOi}lY^7BUrPSQ2GD}sPfK+{Xj6hL}|p(Tm9vZ!%*uR3^ih}DBZbYw*qBU_nY@Tuw>YFnotrUrga{;JTunns?x=y-#> zajN-q=Sg=xeQ?$BVebq_~(ES$kp+8iT%Hd$NqO;$G<4_ zqWq78GGy3)-p@dVUZ7^~ruTMGsrIR9#n67XJ>7$V(iIxauxPkipOJPQR!QMqPM!Oy zN2fI1B%eVYDQ}rLAFDXl_=E4o!`laOW(!>gQxH=kQ<`FbB~#qgh`BNTw^?S_lL5Ym(1T4v zEXH$VogVvNt0^dRD`ZzcJTteqdBUZ&CWAWesZ0}! zAVnoVVaY*^s9+L&ID^7JQGxA93TUubE3p0g*dy3sADSTe=YmO%rF5Sb&s|z9kh=nA z(g31n34$;MJ`<^>nW0{T7Ae30#rxgASzZe0$)%NZV+`I)>a(51Xau=)z*Xdj4Mwwr z)9+%=D4;iFev6S5rwFoj>~wVp^8CZrAz4K3C%mSf1o7p&`s`Uhm|(4_jOtz$6NtlC&`DmB8O%G9WSOst91HjW&9gQm!ZXQ!QZWRSeDfgyUz zo}teB8nrhcl_|R{x&+7PAi+Ow460w9w%(c=pOr8=0oGd0szZkFgpzy?3rSe$yYNW_ z8OoXR*pUgS{0@N=F{Kk3yM&?!5?=f}8IyaWBuLjWNS$1>DjtH7u;V~UVr12$m|&!M z_2$?wd=Mx=VT5e8o}|wOl?H*++vpO-vm%(^F8>)~_M?^H3@?R=;=g z!2>4zqJhbj+v&RN*goL=?59OdYV>8IX!7NF7n{3>n{vOC$Pf(l8_J%{w8Hqxt`KCx62TzlIeFizs)^(clW`MSp!EmbgUtNc&X)h~z zp8c)}p108*<>RBVe7_fjk1jrvsPQd~*vk^yBjt`;!ce!boiJKk%%PPMY1}i;-5>Tm zYOL}yP9i%Uj>LAxJOO?X{zLLNEz^ksQ07TQz&v@qKEBonu;1S_bvcw5-4=VjHCEK$1(5mq|t; zC)G)4vI=*)ij4Rm;luYwT#4wjiketEx{6^;3jC{$!ag@)*GFRabD>w!x$)7^ zVS&qTEJ=qx128g;y1q}8#rKMkTS-BT62ma!>Gpj_MH!YB^N01%j0QCDT=DV3k+8y{ zz;|YyfWpNw#LA20u&uO|`mSX&JuEl0CHlyfcx6-t8>hK5c!NG0_{v{pLBr*G@Dp@x zC>1~1<0nr=n4KV0fI~2gFwyv65o898@o^|v+$v)_ul~&ytoE6JRt9A9s!`53i5P+K zn*b|t^u^10!`3ao_5A*rk(@$eWOe>K%CgrE_C6c7fcaCzzrAv}y1QRz`Mqc~7$e*J z!BuMAsaij3o;XZ&isU*4h4{9Q@-58Ejz=omr)d;xXktDLL}#~-bUf0 z*CZ}+M9)aiLUUO9?ooj~h$vt0O&h z@`c?{z(r+gwzq6nqwdh-jR8>q)6h%M3Dxv59%W5L>f;c}n0`B=o<|Pc8U2L?sexpK zze8NGfk6j9uv;u7I8O^=HwmU!7($Uh_%+LYtjEh@B*^LRWV?2|N%(RHktjENlmU^_ zzH0E&$_!&V^jEU~5~PG0Lz(Zru7+a~$kyR46m>521#ATXW;6}T%M`3?Uf`9!fNUL> z1mS;L;xdng0tJvCo0lEd)cDIZR3Nd>MUHLqPv*~qQr2xm*FJCH$aIoAn@lh_pZKXk z{_@}%+)k_fnS~{P?tkrI0?_27#o;E0Eo5ef!>Tq%V+XwAYuYQ+c%R=&TU~p~es_)JB`D zBcvU${}1{{lM|>3j;f$5A<~(ei$twOpr8%=-9I5(K*WVi5U}G3;klwAq-*Y0sne5% zf6jFBXj8#$-us zGW~OizIQw6kheXX$9{?f>(tkn?Ld@J{w(V2L41P5@Ia}w1cR}#7ObdKj?dckv~!-2BQN0p=b)*Twqgb;;gVwd}5rl za!x-My32cbEnGc{Z8#t_;42fEcKkYcVb8TV0z}#1Iyt3ibSyveAO4a*x*%DHQYQ6h zvMG?P;~o7A;f6Ez`-wVHL`g4cWu@!h4I0V{Mn7Rx@RD6slBvuV&!r56b1dPZA3`2D z>oF>0p(x{8$Rk-eR~&IX{7@5^ym$QTPZVdO&^2gn`*q|8B^Ao5LW=bIAT!)Wdzi}| z)kN{dl#))H+y=FYKuHrhfe8+ByQXY#u^9iG002J7L(An$4w}#vxY4 z9n8N?#Ep<(Nb>g=k~jH|XzbiX9X3t|ua#WQ`|f5Rinz1u?s5Wc!BBy=mG z1|~iZZQ%B!ZZsSVVlO{%pZSEr?p0OR7R1HnW3Shj^v=od)Q_eA z3eJ1G`Q`BB1bv`yy2U*WQg8p}Ski`*~?&y4K>;(9Rn~vp4VMg3rs=i29rX zEq&tXjam?Xcj>v0@ewCXRk^TvLd#H|IB|D=gfyqYcviIH14g9#7eS^a#RPKZ4D#2R z-(${tdn$u>jbWvzK97b3tJQ~M);2bu1{RpkLvNGgYi)|$pZogyDzD}i3{DrT{wQE~ ztt0aVE0ReWkPGwXg*%GcSLeg3*|s1zm+4yG2bBk8+S8Y&KfolpOLq~6l zG|=JjS^oUV=X8;&(Q_+#5>%7siQ$_b;qSgsH?w7*%GU8jsiLA%z%UHDo8uqeKW({# zPo%eN$R$h_X3xy8OP=WI!B4?@v6RnLbb>J& zM-}Q_0Ofm@dGPOj%tbp-IHAz_+M6>e5}B9}Dv+nDOM`D?&$*MzyM4?Q(ykmD0ZQ2O zuc^axobTS91snTK3+xyuR$vjjb5-9C^L3|W z+{qcDk)R&Es1cL<)f)d+|N5VyLe9^TRkWk+kmY61%vz(SmM4dSr`EQ8nocqhvXmBs zK>u)oK$|bDk#H*)CakQFATvnR4m+c7>~qTYk$$Dg2xe({w&*hj%(G0SAK(cVk%V}B zTO!VV~Ja?L4dYiBUUS69>KoV-SBJ6Unlt~cSnMhGix zDR%bF?1J-wr#dk6sMVoG!rz3s5NXN@kmHVBBL0=uZ*{)E<%y?f(rU!6d2PH^S}*b9 zBu>~)$b~*dkDO$k9>6!O#$X!3A3@l6Ob7(HqqZ_0Fpb{qBY5;B9kGY-cu=M~9QmH* zTbYlgi}${-ZAY15v%j4`VWn!i^k;x{9km*xJ)|g`#(aJ|vK-Tdl4O?-#PId{SK7{8 z1fXBU^iMAAOi1L^yJGpAWE^{+uy4aNwfwwW#?vO@?;tkffWL8?0|`5pgJrbAbr}!t z`WU-JEzp)XjQrIZbdg2nD(1Jd4AJfAwO3l0eHYf}q15&0=RFPoG|uqZ&i;NoW@qr9 zvmAMpOF>7@LVCd=BaW_EfB3xm)FsTZF8Os%IJ0+9GTJ#DmPg5fU(Pv}IIGiw3p?Z`F-{>wudzorj?wc)6Tv$-mB7Mcxo}tbzdpf>fig&ufCu4BkdXH8 z`VYn<|3?5>`yU68K%;*i*w<7itk4B9-q-gJD63?Rq+Q{E^HM8*`Gy>Lr*K6c84k_s zP80c&9J20tsU#)H<6h}b{iT2yj7ErI3fo$1Mz&^%ZRpX|uk!PmnsSCTbf^!@%e~LV z%l?>lw?A|itUpfn6j)yaxxmvqqIo=u2y#Agiv%Tp+7zhqu|`0Q-Jq=>WIq}GyI-VjUqCq$Iep$Y@Kn(s)Ch`S0v*ZZ@~8}n zovd7mw>cH8h!pMl` zyU)t~g^r!%C~_PpKOh>9ByYzJH%)3)1I(#u7j`?C3ak8T5tU}%y)wFNV!QBu2C&1O z_`80ZWWfLVWD9Cq3XoPuI$uFJ_e4EQ3G{j>mVgi4pcwXny|g05w}4B<5q0K$e?wFWmFkqftaU%TE z0ceWG^7yMGfhU$wb3p_rWy7JO{NxL~j(yrug!Ttlw7?^|C^aLBv3mf zX{2x|gOv63HZMo5t8~b?NZAP~=mLb=Csu7DKc9)-UcikBmW$`cdL45 z+t-}Ny3zOnNTeM*S>n0wIXr5%{O;e};3jZY2t653+?xW?S zW3T;K;xUV8+Rmnv2*S6kN()s|L_LoeRrImBy#`gZ*R24ya6cCY)p zufU0U4$c@d(!AZ5&tP)XuYpAV*KlVEQoCqY5uZffKhgz&Oj(VpY(3L2mIi|YITx$~ z*0d>EDHlDOi;Zp-xRs^JkT{{bZ7&D zkS`HpQTsZe0<DN=U{wRqCWk)~B=+cd@H@7<#;kH;0xdA3tE47Y=n z+7OjH7mfCUSoFhg4fp6(>ArG;fw9vQX25>!q&A=ryFs*shgg@?QlI^*BQ(~*OHjNu z1LHuwM_z?mpTKY>fqQu^byo85G-jW-{RahxoGpFq@P)L;MJZB(Nj-jA-?@VgcO4tJ zE}@ct%{V(PL#wsdYaCiP6JgUjTqb5=1fvmtH_FJ~CV7D4P_qb+dolA~9q`*T`e9#a zU4lB)iQCC`38{2_xAU+_>-TeUTH&r>&DMf%u(zA#DgM+lBY)NqE$)ri4PvHa*m3oUBJ>0OADuHpEJp@z zAqAGLmR0xp%Pu`AP=xUhSHQb6u%=_Zv3vOFtnk)Qfc;avCOOT~?AhvBp=++F;OAzb zK81PbvT(vXF#~0LfGyW8+nxZtuZiIr^9XB?k~-vVr<9|x!%|U z+RroFTc+~L;ZYY889)m-7NpTxLsR~>&1SWY;O8KX>q>Yr=5nWy&;ugnN{W>LdAH^G zrj_r4l4`W+lsywVp|`5EVn@s9L4Duw{-Bzk+HL@O+qaLkMQxa0Zi=1L{9lk}>&UWU zI$2=V^iJQEy87vmte1~PY_ow6JL$HRtr@>bXZ8D%S3_Eb6k<0mtJLR&AE@eSGvJPF zyT)WnWU8}e#^_b>PHdoga4skYm>P^0d_R@2Q)_fAMeK-PdVYn?W3wBQlFH@tDUDp< zH!$@U%l8Anvbe*rA{Amfr3MWH@eYur#qsF&wUd2G4+WwcqUB*D(Pe;5MaN)&`M767 z(_(2Kn-4`taeTgGg;Oh6j#pP$S-iZozdc<-|MbKO^MyO~mMOEQ0rrQ&P_kAQwV4^J z@Rjd#AZ1@z#OGj3eohbS*8>)t;#Ov>rti;4M7SG8h?7m|%ED%w#qO}Mx{a2y<}E{e zq^g|*KLJte3RO=mYZF%Zv>ZyqL63|s__h*_2`xLlW+f>GJ()x9<`8&D@lK>V5E!a2 z-f4FLlQJlcSsD#l(?!U3>(`Ks;eo?Nv+|uYUB@wUNzz6f$1W=KpNp(}j!)W@ ze)hCpkuhn?rq|E$v` zhXF7QkahTCfjwTXDTH+==x5{5?=KB~=%QrN`~Kkah5boAtE&Km5B#$k!e%#?A< zV`V2N^IqL>Fqh!zrlnl8X3OMA4dG>h&gaL<5fwj-$ZO^k;FtG|BUm#uhD(GWKo+_I zRU`owC4Ms-95G9|G|`22G{Xl31XOC!Vkf^5tV{Y~x@j@w8igUHvY376Gnc`qjs0z8 z6DyJFb?v#zSB#yDaGhrtPN3FUJlLWd=bK)u$-%1SW*AH zx3~9b+ozJ`-H!jZ^mXXRazFg)4G-@wS?1(uRy^>j$e}PzGWEE=725lwF535q8#BOc!xOpc70XnbDc<%|R_E-!9oc^j%b!3-(+5 zT>EXpxVj0ZQQa0TeXN+rD8$xsZq~4}AVzphsBcKscEeX~KPrT|d!T@<;DwG~j+W^y zBBHN2!p6=1gEBQ}>)It}TKTaeE z#sYkenC(@r!3nLBlxB^8IM{RHm&1dAa>Pe#vqcadSbG^R-~NkXoCNe$_=6X}Ms zxX4ZySB#LsZxRB#Hb>rIqnbA)Sl+?Zm^k`VBTa7Av~h5T+@nl=cqI3?Xm>v(i}H-s z4Qz$8Pt%OAn0KN_+;@iYOxV`EXpJ^wY^YIw`_9%OLiuv)BZQ|fi@(YmWy(|>)YRI_ zXQ}%mPHp7&2qL##x!Y3f-c4y`t-h zLN0=Zv$oMyK~Ikw2se#=(NwW*KoLE|#SqIkBiFqx%H~i9rHGQg*GMs`Z`;3H+v?1{ z!{NJ06hF4gzh%)kvOg25>1|>d70-#B7of|Blk~QXf=6j&P$G7kTm{|t#6Uv0Fi{Zh1qiCQw{5;D{Oh}&Kq-63_pL@{ zE)8m_faB>JS%}d(g}j`R8mhc?j2>n;3b%u4vS(T5N1Qi%A!op``TJ{A`U4;CT_YQiMp2@Rk!A%^$G-Yd8S~IzX7BJH+WmPTFud6KO(qF?KXv@PBE%8sJ^BD&Mp%fL~3m$Eb6t9pl~uv{}=2^k_?I zcK6Yc`6t836Lde#9m>%I2hy0;&!C|ySEgc z#D=+i#lW&S&FI`GTPB!5n_2ylKVIO5Tt)l^#+RY81-FZt!DBIkt0s{OxW3-a$>3M~ z)tA-nfuwjVPkK4Sf~`g4*kbUxnvGkhl15-+-NxS!3F6shR$pVbaQ<9`Cq_p%n~G0>Q8hI?lG`I$kxro@3ji&kn|n zQ9lX&m911DI_PhreAC?#`EQ_+c1T2ebthR=dF~Qtqq2o81c0hp(cUaE?kj+PhILN+I@*cuNB!jD?_vn@tc^1 zB-&QMbCb@SWeB~}@T}HoC%@bdgX*!JL=JcCqe+5X5W+&!vWAiGxu7^uSSKpQHCUq9 zaMEv!iBM>(hArr%>}`|oH9faD;_#>U>s19*$K6#6)un!aehP=cPY(G1^YnuOdI1I? z;%~`!gUL^F3;IbH3;$-W(k=@>85Dvqbh5cIxx;?|dIU_|XSo z_0UuU&JiXwE`yI(bGXigG#2WHD8=N2^(rO5LgAPr3PImF!bWvq_qv&FY)p^k7&(mB zm1;Ua=)+~GKU2C7EYH}jcK_D>Mqfn(1N}{+hB~Ga?PvWt9aU){_u@sa>fY*DdeJj- zaVR6{AN(lY`7w`($je2Z)gp8wm7X>Y#4-}TP)DmIgG|<^WoT)LgZl@rR0_f~6K%M% zMZAsDpn$rW-rCghM;0@-KK?HCAEhW2@P;|4R3mzBw}oud^)XI<3ew;ZAa4ukiwYF8 z{C`)uurU9xJ~@wnJ8Ai^%H_W*m;b6<{;P8Nugc}WDwqGNT>h(a`LD|5zbcpif2v$W zKo4jbFoZ~NKp_6##ry9bQT`to|6dFl>;K0?#)!@Td`2^;3G1w~_o>}&e=I%Cn9_?_ zFen%zkQL@jRAf%xeBGy_`C|N&T(zo3RT{KqG#$&ey-h9TWlK8M5)3QkNCg!X(GW6i zm_Te|k`)=|#L;_G+Y6ry*;I0L8I+SFzwwmUi!tr@i;fN5_YV^MwjW)ogQ>mPW7LKm zID?1Avn=&Y^Gx%22kkCB`Ipg&*zAn-hQ_~mQc&s!$Q-13C(O-SyWA75t{y~lGOvht zctVGa+45I1#OdXcICRp?>$nGv)oR_yx4($?kibB4GalOg@~^-_yJ~FZ9(T`h;LgAI z6YU&rOjGQ!*Eo|KB=AIVzm5dRnpSGjZH^5G$}~uyNJohoO`^j1SF{PAD3c<+??ag{ zbztRf(KnIz7Mk){#yyY2a9~U0q~s1kcnC{RX)`8`Mgp6b^k``Z$ttL%N8^*Et_igG zA)8;|SC| zuH>no;5i7s+os`LfKdDpAry6^$;UalaA%9IBbR;|Z2wFssZCq4m~VB4TTCY8K@A!h z+49O-MF`cguu^fjQB1I(@E+#labpHAZg3t55rL}Fh@~FVzE}3fXvPT+cqERML1Ou! z;o{nl(o&JYIB0p<7uTA6s&C%!82!KPgav%{$5Ip0vXGJ7FtMxN!qdmTg}zi21wJ$o z1}`jJNPEQ;L@VSFa4o0r+9Mii4MQNLccw)rn?}v;4l$6<{>k!O<0pp4IA}5)S}o$p z;wFi!TXIAVPy{(*LjtIXfE{jCMNlF`-gAUV5pnnk?L7) zq+=cXUk6=3OTZ=*6NY4YWn3jd(i9G1NqOmiMe8>3%DDX)YJ8M{!C<_v&R^B)4U6NzH0`%MNmvPY=3EoRUoi3c~2urj;_f%zObwnmPJ;f)Y-5G*P>oK{; z=cyPik?mDt`9&m80Sj!HfEiH9=JhEXjVOomk6o_H^CkG9<6B})9SBVNw=x_axgS5e z$HyQht%aGjBgXo6)DYlv48eqjdeI{BFi~KO4A+2F^k`_UwmM|oZ zB04|BqDrPav2%5*5kew(YE5I@?~qty9cVdoe+2qNLG zEBBY&%)3}F294DG^-k|Vqs5ErT1ghm@7;99ZnEx^;Dr%b{H=rLBeVz zPD~r@YuwfR-9buEqLaHOp2f~XaPDFAT&2$tXIxfK)oOat$RBMX1bFGeOj43~dB45T z{n29*Dz!wp%%nKt9Ld76IvlaJMl{^)jA608gO%#76xxzM>(iLF2Q2S%8J)kjTiqr~ zbJA(VolvSSM@h0+{a9O>?10VHj>tw}+L4f>ZR8MP&uf@*j9<_q4>1*#X;I+OM3zYw z*8@{lADG%&%!?iLql@*Ip&n>g0zz3j<}*4iwzpU)F{i6niUBNearjLtH{Ifl2Qmzv zPB*YNVi?mf9LT7QRQV_`fMXL^Hz6qsV!oWc0F4Rig5P2!B%9FsR_OG4b8>SFG5~}+ zVi&@K5yDl73ZL0$W7cCd`YVH0+*dVXfG$Q$=KVahHnd=G~YEo@~qpuvRcP$RLV zKw`XRUYu-7+~+jt=|Kr8SURl2wrhcO2@KmHIv0H>NOvfF{oV&c4d|EjAO(jJs6&K- zx6lr;Y0=ybCd^E>FYs!sOi*h`ECFO#fn9Px6p(Uj1Y(6SeJ%?*7J>J|n3H*N8l9Px z$mF*?Imu|&0V2~tLpoeouxK32L!Lo2OVN~!JzUEG0qXBqJe48q8}uzqm6ODXB z(!{9z>PLHw;?-NlJV}rMkWl?&1xT9kKt+z?1tz6dxWWAMIDry7h8s7qJ;Pu(+uBe> zSK_o)&rk>PwHOO8R@UWs>2`4XtKER~-lAjEg7l&SH?c2uCVD&ah6CvF~0z4j|nuJz6u1=xh zi?rP66V*N-Q;w_WXDjMZ8cI-Ub4YnzU?@z%0m%!BQ|W|!ne2lT3y;m0CG*5g_nReqw46=0_MArpcf352&Z<4*E77s8PJjf=`EHdJu@3Lwtu_n z0MzAC<6pm(6)?zoozfRtpovTTT4!4p8{Zb_0foFPXx-swms+s>ciCvj0g&P7r(JB0 zXd?SaRMYfEd;Gr2NZ35yE@bKcf4Kmr9xskiAE1yH)P$r3U>u3j(`f^NK75-BtQzM= zHyz$Ix_k&z=8*Al2zI?9RchA5KH1$T7zXlS$qQzD{B{8|VIz6_Ml~0$v)eOV@f$P}{y+Me_CHaWgIgSC6M zy@MStyJD_5o)P8x)-oHVZJk%UzR-DSHraY{A+Gf_P9Iwf&BdU7b&F5z#|h%}j%6H6 zy7tqY9!sRn)Q+>UqVfyTy>y$86XdenjY-^?y6oFOpiHQ-#g-(~pGH)>`L~!Yc_u)A zKHRh1_?J!Xp_ zcxVm}Dc|b%Bt|SAjZ9|=40AZ=+^IC$j1p$Zmb^dOP-<>vuC!!3NvXgy+qkzW{d6r5 zXZ9*4&hhDP?MoBxWyiZCB^4!blH^!nx0mq+#Ph|dHc`v?!d0{Ba3H;g@6!*cCaX_c zH4jRB;FraRz+Fb|9}GCKIZEoM7*e^mDHaN$>(fX+uct-4QEC?%8!_I;lj=vpoF$-D z*iv!c1=-Zg+AKGL*l~)MhGlO2I8n3bnC6BRdq7JOQm5Xp_aELt_dD-XTw8;tb5ANm z6lGxhmvLBo;`;gsgXRc<_BLcR-B>#O@6>60rtIfd>)p1$HbNSggd%m z=bl!(e7Rop%}|@|@5Wweu>Hl1%S|5TsdEJ|HgxU^S%?c)(m`z#2IXU&vyIIZGaE04 z`=x}UO0>ihwiEw~z8-G$bTfguJ=eL-9GOU31icgGO1G>?=@jo-$>GFPbuSH>J=edY zM$AJNiQ{C;XvBHa(}Q1$6>U9pm9~IGuy})d90t609e9s?9TJ>Or4W8E<3Db4V^pHA zXcaFo^ml#CJAdf1EPo=eV{XidcZCb27GQ=3R9?!vZt1I*x`vj&Df6Gh^Z%VRl}t_k<18Tj z|9{TR{XfgB(BJO!==?{W9NNqPvwBDrFe{X1YIG!pWU=*Aar9a%E6z)Q70a?|ygowtRt;4ejf(|~MNq;6UjIf2-jxL+CW(zPwn- zt(frc&S~Uo49S_SFwrA?g(I310z_6tQyKOF9yt1p8@!yRw%Ldx!El89n@(3kVmW~w zM_RCz@#s0w;0QqI<*AE{3l-Fg5m_gCr=%?K5m%R7@zcSYnnM{;tcphQ*N8Bn$2`;+ zCrumi0U#uqS09MZ?ZB!H4VWyAU?X<5rx6|R+o#>~^I>Q0@k7e> zbiV&+(!d&dTgsDY4_xM*zbo~+>p_`@rmnQu5kFYXI3Izz9JcVWjD%A?xC{t1Y#~yq z4R8!y9_P2%+h2qU19}F=H#Oj4gdX3{{z%uyK#zLxpnvnOON<-6P89GJ^4{t~hPice z=xrdJ{$tJ`KTHc*vAh;1$Zx!r7vy4k7L^(dONzDJkq&cM83-RIGq^Jt${xu2E%tU^ zP!JV@rY+2CQ(rMT>05sbqz(K~iyg`>O(~QI-fXiKUT{>MH(Ejw&}{)GJ|ZS!-VMY< zlS$r&&RpL9Pd#L#Vv;(PqUONVwlHuDH7tlmy>BtJM8phZ*vY(|Jl74H36GYT4IoUC zn==YO_w6N2v4|>{6(65Bn5-b;O9%Jy@TTyxZo*D2u$2O>-cXt2wWQOUJ@_o44uTnR zx5?xTMb~PA1&Itfg*Q9Tqu!U<5+`CW{s>IFEma?|DkeNVW8V@GqL`pCP#=(E5~vYR zGz->S%$?mW5yys>WX})UEKnkOnyQc=SxoSDO$UGL(yV#E+uKpYzse&~=KoYPYXlFuJ6p{{mPw$zR`Hh$X6KhWn;GEEYIz3N*9T<-b5QZc6 zOCr{sn-*`@g&mal-a~(q!pwSZGbIc%B*?E#L>QMxQASB*{x;;t_v7$d5i|#M^n;k8 zp}>}I>;w0Yf|^nFVlbj$KxNKILK%!V3tF>DmlAYZ(k?0BH-_wbJc4GPBvsXat4?1y zy5WkO&V2Ik4ea`GY`WMHXY-PQ*8A#>kB<`HKZ-aNDfa~`Iycya1XPH8yD^Pp&4UJd z%*P6|1G||e2^OY9`;5uyguBL6HF{~I@;*QEuj`>>VEc`7!Y5*UY=pwDWF@Zd9Yul~ zN3j@ee4wr{IC)s=8;B9m1%~)!HHVywHtSOvY9Lc8CNz&x8j0nLvRYMvSXBhxv{Z&Y ztYsz*KX44G8rc5q4TK_Fy@`g!W_ii)OSv1K9Y_F;XNEv+ot-$h*6cCW6x;!kn|W*r z(2T(WV8l}vu3`L(s4IqsSScL~(%?&_qfR@z6uOmZyhIlZ5mu+{Z^U+#drqX$w z_Yw(c0ZvC;8`Kf zfKQ{sbL3{kQVd|t0VrUqKyE<9xzS{;x_LVle&t#;8f8g6K0M>eQ?8+_vrK-B#}#jF z5a8YcD%yy57>nv{9Fqzrs~`0Ja2~+;b_+Z`r8uk@X{mYhR>Z=~1PfbBoK{==Bc=-^jNcq-9{ zjk6V=FO1viN52P_1A_akCt~PjXzD8ym?EU3=Re2?z{WWloXXbVmg_M+;bnL>D2&>e zGakp=K35rOtil(PWPrKJ{8>mH(@%o=X-m|`jnNEyUmZY-FW2? zKj~u#P0GiLNHoSe;i?IG?Ll-6)xP&8h3-$*kJ=FTU}N?@=*-P$CWIG3Omrz~Bypt} zP1;m`oa&=}9+)z!oh+B5eRQHNognC;wrF0ZRJp&zA_*V?zkFcrt@`9#q;62TRF?mU zZ9y$P!hSXC1LL$mL5Uu6nf2T#KNfP~upv|5!-!C~7cy_mQ4X;}nI?7o$;~1(vDd!I zk=6H^V8HpO)DnjaAE%4W_(#mQ2U~sZ+)(<;7Ft|?r30>-W>h`}){@9kc7mL3^*BEw zfu6iP@hUZ>#e}7O2S>6?HvwzrfqYafmhYMBwVg;7J1VDgO;P_l$3iX3t z8-@!MGKgeWsZ#yw-Gj~MYvqMeOVxY+4x#xOyoyf2v?^)<2GLzYu*DHVNvR)nHDYtA3pv0`V=_ zTw3TeP+&08>!vLs4z((KMT6)TD8wz@H~B+7`6AmDSeJLF=rceAYi`JUSoau=C?Z}( z?YS>lc>=sPbMR+%Nx|5i+PTbDdQc=4ljYv-bl)J~_#G%eMA~X%tP4*%MvID<$-ugd z@Xn4m)Q1T}5G4i7OihylXn#p}+iT(((Yz5x9t$j6H*fy^&oKFKla&s^^rFYcLW(D2;pOF74<<|Qdfuiy&}%eboqj8_AjCReD#DyNQ)740=5A*9 z@G0qKG$DP-@9zfl1d_)uz&#_3{WtH~B&xt)J%wakr-~?rka9wq8Kj(;d$GOVNhVtE zSyVkLvpD>3xj-yb<4Cb{qdN3Yd;VNfx$GI~U)c zew$yezD#X(KZm!9wAJ0a^;U7+ckC0vHjyS1`sxLNiv^!!PPlf??TymV92|Loivy*F z6COJ!Z0MQ&CD1k95Y?yleW=JF0)fcG0*IBh;iS!e3U+N#Hm5)DO+gHfHD^W2)2y-U z<2LuYvn`1|u@pQ$c=!B8dqK*#?h~B{J%n*Ro^uDAfzK#X$=%gfGaP58dQBOr`b95k z+C)-=&xeK>D?(-Mln{vUbKP}W{N>!x zqkhg|VIQWw`Z3M7c8y?XaI^N}FGL<#`VGo9?ZJVl2;9);#HsGv9h_F;^M(L-kd4v}#6sr!)fkrb z;bHyoo5I0XT|NE2R>hAU9!YfVbGv#P_qTEcDB>^NkvX=JNN>47GuR#7D)?VFam}Hr zkEFPWdXcyHu#|)kYece{vABi9T}K8}#T_(}%&NqLZj&5qmyf3;a!>j9!oKHgPHy}r z7e3cwGb8xguszFHywqc>mkf6(p(jTc--03n3}?_6;uCVnRXRM<0+vJa4a{&7S4^*l zoLUB%b|wcyzy0LEtL`G-`(A^93DHm10W0ht@>ckP z8vPCQvz(F{YehW%RhJAl)8r8JON0FuMyhpQLiawPD^4y`SOc~B{l6ESYWsF5=DWJj zrq}xa6n*|ZPW#Jv&49k87(c)FKS}>`gQnuG?b z+%U%IMmaMmQ_Vy3lCF4St+2df*n$BD47aQ=U*DiUTk2yw&>=G&j2nbag0ZZ zL~LAY2>(6?&JqNnzuRWVZzDcX$~c{j2mZ{TSm?3eTMZ+={@-G?LZv~t5z2b4)@8{d z_$mp@g-s`(I#T7Nq+qb)T;%a$tPuE$&oO0a&W{|;QrjIR5(Y4>Js~Jte=BD>9k3EO zdAK*hSC3)H1~U$aFy?2k1){cq?4#3&;sW-}N6okSobi0zd^SgxDQ64Gyw((TPxpz+ z=7I|+AC+bYN|epO0=I<^Y3bmPyy2T8GN@^*$ekSn#ydbw=n>=FR>x}D5G<7`qtc4$ z%1-tf>!d=F+WV-M+6RV(IkYKRW$MQx5$rmuGy<%gT@VQ%Jdsy^X^JJkP*iT#7@X$3ed@7vb-U@{j-Ka$(kY zHa4^|G_o=Mzs&}+)otzf*x^2N^m|kmenI!T_gVmWhHzpDJZb-6LMV*KlS$pj|oCQsk%x~R46Te{rt0vtm^h3*pjvh}2 zM4ovM7e@$BDx|xPO}dD}K$es5#0BKl(NMP*qxmjoQRK%Tad_O5)ur*C@L>kV&|-~A z&85P?EG0gy0Y?=@!dqpgeiX#SePEM%p96%%HxJX1FX+li%Gi|CCX9v{w#KL z_x*~DNzcg1(u~Q@U*0zFStHS#fWuxQ0;tK_fy4X^cva>Dsqdecb?{7`Ytng85)>o* zYcu*OiVuAl0L;)gSc`j(WLTKs2{VCnx6otep=Q(ET{N3tnEMNx46s-IpqshVl8Uk4 zf4+Ew<+ESPo%4C1KD-L!Fv?}@VW#EhIV8+k!+aI<27HYib_FA;lJ*;;vc-El|` z!&+d|S~+ImFTnieZ@whlmX;LTSGcL|A>Q(P+w`GR&r|;t9Urs&+GMzH`XahDW|JdX zU#p0lpT+A0wrq|ca2xY&LIkA4Ol<4q3AFOjg*ndmuG*1o%;l#+DBqE2FBN#T(34y8 zJTv)a8rWSKNLc(F<#xh9cJuN287`*O8TYlY_Ru}&kI^mEpvS{UWQW=C-bbuUQlpv^EIGEJhFO9@tYDyB`cA9MmAF_5F%kYzfs`0 z!8Vb7LnYUi=0V?oTl*2;s;o@W{_^$C4A`fmP&Y0LSCZS|3x9T1tnH$IaZ=s4ed)y9 z_LWSs+Y|@&3q4DpEJ!i1$J6jk!{9kZJOv;x1DkIYH)(efDjIyA@teY+&(Y@g+>w{&| zQ{g zrYdE70lGrIyP5mWsoz-^9Flg%j?t#EtPXL9U^~=^v=<9Y3yD3Htc2N|3_G~~;3qr{ z6?+j=>sg$y6P7#i5?u(RxHP)5))?3L8%A(~IPCn6Xt8r%CPpLDTg1-Q=PH4l066q- zMIIDus=?LJ(op3Iw(vkAs=;d1z^6aAIUH3K;^nOd$w~g+`h<=QPJL_%6eNuc`lO>* zb!n89A=d;|IC78=Bgn&XIy3sB*~r5niTw`W;vg)QoX{An=aTbN@QKaz zk?gsY`gN19Nz0B$MF}!FMkq~nTay_Kx_v#JJp-l$Iuq~I!MNQxF{^gfYg+@yXn7us zyj&Q8Lm(PPAf%A*_NPtCnLZX#f{(5h;LU@uGttDDGLpkWDZOFJCs^V)7W2t0Qn?@p zLi?Qh4TjL5_PJ=1z8g38O39+9R)XQWQ*$^r$ZPSIBfL<%o{0BlGbHs{3ww<}Vi45O zUak1FWLMurt~^{z(WR9~$b~Y1Zifx#HQKOoiWx;SCK-dR8rbz`OvLWZ#m{ezUE?4D zSOkEQwhLlo_D+{f%TtCuJ5rgCA_Ur@h*^T(auMc_?!0j_zEEx0PtMueWl znU)I8Y$_Eq>QD^O^#@1;%ZyWZlUfPm8gZRkGsO$p`y^C#`p`lEIJap$?s~%)#HNrD zdR-?KBEl$SD*JuqE`?0V<5-6vzIKB(T-(5tUWg-bO;n?LYZ)kPKHqhc;qiJ5zh57X; zdCE@>`ON*Fcp#EAC2bN+;GqH{pzW$S4|7hOOkhk_W#$e#Olrc8Yv2{CJ3HbAD5`R@aa%S+M=*?Jc_P1}@#H)aHAV@T`Z}79+ z)MxQ_S~`~a__=aK3r=VS*U4+Zl-}-Z`5{C*o2X&+{c*1P2uSxZD0T?yoQJqm@|h#z z5Co`s6#iI&9iozX?~8I{p(yE|fZr6waGLYd4IlUUQJi+tot)n27m@#oMqCQpGgMZx zYz1#-aSlyf+Z;Qhsd-|A@)Ot+Fg-BVGdwrRNnt&T`fP=Ux&}~ZIW6bTNkm9`^h9U| z`H11IO*x`a5VEtD>WrF>0%OGh@@i5{)_XB>A{sV8SX;g*p;~u&f~V(lgl4~zto!M* zZbX<`z~Hzqgo5arLmic&vA?9kSkv-I*6Z#+f*w53%`Kt}5ss(Tp_ZCjLxa7d?1|7t zwbXd%z*SfaEm#PLUR~KIe|_hZXUqcPs>5mDnmj7eET0^iZK9aJBT5S=;=UZXp`bJT zieTK?GMIjZvDxVy0BbJq&#*m2KL;$(vGAv)^-THI=Voza^<#>ZW_;X%7OPHE&O^;H z^Vl}!@|T6;#gfKKop|ozxtjXs{3nqVyGNm%j>gLDOhYp+BK!WEq6(6)KazejZ5i`0 z0OLXAI23@m0)tw@a6eQPM!c-GK>(~dkJyyj1^QZv{28FtOkwO!EM3bnA|89tsE2XF z3a)4We&35#CeI#EsUGa4C*fN~2w~C+nhM@~@;<$ZM(=&3r+|M7uba(|=9+kGgOi4HGW$dve< zrAB=hOf#VW+d>Q@v%Zs|oym70#?Id4|011PP?L@OzI!|0)MZqOei;utf!H9vUjG(L zz>xH^aDsgllx`FY{sEp?za;yy#Y09ewP+Xgs9~^Ff3%ly<;dFq9xnCka8;pnBGTU6 z^DD1#brQ&_AFgEW=_f1OJG?)N;$KuKO~q`AO^yb`RUIyHSQXJQ{`A6m?)vZHAx+(# ziZ__r)V{)Nw>hk7(c|%S`^&rGxrgmvC&mnw%&ss3w(Jwiiz`;62u6SqY-IMHW(Bw?0{DsZE0tFZvC8Pq{>s;M_~x!+W2i?j zzH2%pl4l13tks$nAY|8Isq}_*|`l5$_;Hvw&Ki#5u}zHycq|Zb44+ykD?%rbHD~!r$x*F zMwz&)R-z@G7-;aA^;(J<7|aF0>D!>5+;tP~OuQ7|`-nuE1hN_1auK>p<0B7aurgp* zsP9(WzK}Bq2AR-4wUE6rg7zixW6b%Pjob>DAa(326w4FS0d|XWsj;BVH?jy^m_G-k zWY@sT1OBSG&^EzvS;FY_AxFB*=xJez0OP?LvN5gL&{KA>{%~*JqYRrp_c>yL)o}6Z zWPt|qS4Z~x9MF*_#*`=*znQz?us6JY!8bAn2&>cPHFL9{O!7v=)G-lUN?{E;B}Q*0bUu9B$`MVHO07##V)* zcRn7ou>Ro9BmI*SF3#dj!h6*aFzTxgk8 z|MK?6pay#eYQX$OH|)<7b3Gm%xX)$sfpT4gcAYo!`311-;vA( zz<-Q$u8hSs{%>Fb{?4$7|7%Tzkwf3v)W+1<#nRsHf6lOclV#&F8Ii)SUeM?64W>z! zCx*#^5mL&VXPZ+Wn^%K_v$rFbp}ZS}*503DZHb^)tI?pDuRPxWJi?t&6vNCd;z>D| z-U3zyI89%`h}im6c)u2>+e5mqGu8hv3Ino#=%p`{>9Xdt8=RRa_sjoSnInCep*k)e zDR#`-j)S&MESSF0lfPrV!PbSJQ+sb0{mlf49xxT|b_BG!t{@CJF|8DJg zTmth-JoTzCprafiPhnPp*fSVu`Gf(IUiQ!4q4nU!S?VJstfYGfnT~q}78@Govzzl$ z-7TX0j!qRs!I58j`G!Tb`lD`zw3ajP-x%(M-!JP%TN~JtpD=FR>#g9R-unUhU4F|v z#nHe5`S9mfwwz{0K5rx&Awh|LTEVrX&o%yQ17y*m129`(?>-?Nl_C&C?S!6W;XH9x zG;p~=MA1)DBLSjSH#nMK3>vPxsyaEHnu)iM^?R&%it9j%Y{E+ zZF8(CWTCbmn%XNRp_C1H^L^vwk-|$w4GB4}FjS~=_t2tb(oEo{#8RpYp3_jmkh(IB zRcs4Is*5YJM#XnJH7Z=g0L2p};Ryg5{w%tN#H=U$AHSM?>SEvtrx&rhuBm#!FOnKl zYvwZ&8eKeO`1(qD*HAiaMjXxKBC-P$Lt~r;2!-_(oVKd@i*5 zl6L!=Fl6u|?jG&j;{1IcWpbpS^JPWjxJIN6{9wKd?LDJo8v4=WSey3ZDp3+PNDain zhdwahjRU))33Dx~mOLd=l|EDRYgN1#9^Ej`br{N?X>>c|)#(i)29tC^d&HLisy?TB zHd!Q;HR;2lUBqI0=(_7#Jg<^Hn zYB2{>NLMqL9gf4=>KrB0`%ak+fXgr=okJLC*ou(cvW^X;vY*Uc`Xj{8I-IwxKHVDQ zKZseDdi`9{yLzFq6ib>OJQm#3WGX*+kZ{!9mEK-KMzhHo!)Qs zm+s%5<2a6HsIG1WsOp_t4;oXfWxW=?Wtbo`Oe6=$bd0XvS)r42pphTbF~lc7c@PC3 zI3XBlhAm#?5UyxHa1Ewl*bWH)@}W#b>~4`lX<#J$y3Y(?xK){Dy_z zYAiZ5HShCD6hxg~w{MsD4e9D$+XH>NAG?Qm4PwLXd*eiH5<_vPYR3TzwvfPisrM7Oi>5*S?_pYM{w?4L_ zjI1IYJhFW=Ph6h@6py)MW;L;ZE&*P9YllSxw*X{YH>BzsmvEMGI8SF`wd6-6nVQ>jMVu4!i7JN){Ka6nA)rJrp7=X58sSVz#B-JtGq_Vl9SDIwGjI(bopkWt zkTu$Rgk$C|N5B1)SD^XMyaNqHC!LLp&Aokv32-(!`MnB5H`qut zeCT&1ik8kMiU#?0c{ynQV!}q%GaL?CdV()ib;l?ke#L$roEOFTT%p-OP+xpjrIG3B z1Oz zqOZq025-TE?)lqC=eQCgUO`j=%d@%gqggpDa6x(CR=Oyrfq-wk2ki}gudQ;q!L+;& zt9%KR@XId8OOdB#okBU4bp?x>!nQ3gdNJ0Gnr+MF)I9R4MA5&()SpIjbrEk~SUK`X zBhzsGr6rV5>`-0f22u3TxQiab;Irk@>tiRSC9eqUKWTvg- zyd-6#YdpePTWtuNk@EVYqY$#B2AD4c-n^^9&SB;Pypste2(^K|Mpv#RPRdX0DvC&U z{*>ANsaC7d@QCM!y%jV`;^-ec%ba;24iKN|K-rjdoBQqG5&^@g^i@1DI6B4b?Be<* z6?U4Uh|uzLwAkE^JUY5HYL`v3gYL^E?^&}^sK>r5(JL4kUV^V3D>|&e@7|E}^W$+N zjUR5a3x7R2e2KK(S30$YL%sjz`Vm6Edv^Pf^uyW1Idm5ON)Y(F8WL$Ouu0SMq*e-?wY~n_R6)z{GkUqJo3x?D@Uk80OQX$2CJhI^b`O^L~8*>mD zWA_j0Wq-f6FyAk&BtTh3UP<%+JhlHXgD|10vT@(7uWzD5T0R@t8((sJTD;5`LsUk~ z7V>VgVX8AT`5V9Qv97-*u?EP>>&Zb`BYD}}BXwnD@{gKNOY^~M_)&Cuc5%@=(3196 zJ5_%^N6}8xjF@TEvBJMT9Vo)OshF^JB=*bpc!f|y*(&YvoU=59!n!=KPx9~Fr1nJM z=(}2hcw~S*lafrq!7?L-)mvJrQN5mJ$gPCAtZgFx-xuQHm#wu)r!hH{H~QZmh0N@J z&x_#!OEtv@iOF-rEqSwY49;G*$=-2|ETNA(+?uz(8w%$gli^@_fn=jN!%nyAcY!Rb z*H`Cqgp)v8d%yClUMZ)5Ct-2-9t)|*@&k|x`YRh8IrFgn?~)pyGIz%gt2Ly(Iix!v zI=)5V2nV{s7ub$Yhtf@w$?ZB=l@#ozl$6_@^8=2w#1vK%@}UX?EKypHXnFcE2COQK z-bEtY`>d{abUgr?T>gNalb?NV#n%nLimQ?R)d8J(R|;kj0$-9XWpQ}K)Ywpn5l{m{ z+h`L;;z^s8Pqe~A1JkY~$Vl9|>cpkUgs6}umH5tHhw~ozhLiVwzpO2D_l25U{X#{} z@ye^)q(^LaG;w6CfKKu$rNohKVwoIaV7pLQDmoLBU}q;mV~-*FCOhE$iAs3o3+*f{ zWHx|g;WxXg-vlf313zwnvu6sFtI9&*sH%`Xa9bb3mBSh+mp;SDio2%$2z|B&ttIwL z_$~FHP%6y;>t&isBA;Kj9-MDv)eD)uL`_Ri z2y+B8%Y-PkSb(mNL4|+^=rP_P6*+oee4f}M3++k8GM(XbFAh*zQ=m5!8-%M8uI=|z zG*83h-MiIku}|{Mv~Z7{&^_~O%;G3qEo7Z?$St|6I?y;C#cAK}cum<^X>V%8g6u;T zR{bGw@H0o{b^X3qfWgOKU~H`et6#4q#VQf{Gh&>ODzZ)ETzIHywOn$1a+lJ0h9?;tjKpu+qUZ1+vLDe;k-0(Tvs@*i{pm=V&JO|b9Jv)$q-1>uZ z4KwS%1#ySI%8=lY*wH5l&Q2`kYJ6$}D%r!PU5X*wG$66=vyH|Bm3QQ#89WJn3#3B) z$w;HhJX$s0Jop55WHN3;jj(-nCKg#Vs6 z=PSeuYd$a8oqTt=J1BsFAiu*|1|T9Pr!4lbw3z|IR&nsZ4z+D)X*;j6WB5(g^jMgg zpJR&yIxa4oeU*$$R5?;u5#z`j`-rpO#6t*g zE3`cvy4+;_lj3~`gSoj??Y|W2k_12J<=xYAyr`pS-Ab7wDT zvt85fa%n7=@ERKW*^J&!rHY3yz{&1&)SBgvA_KZ5RhCqXoQJ6g0BNdCVWJ*6>w;eM z-Fz`}DMwO!SX42NjDux>*{W*9t=x=#){&&3URP2z@|)!qWAH;N4nxG* zWI0$ax8qzGTV@%Qnj@^*ynr-B$gT%b2@3V%gyBN)Hh%E85MVf({b|Sm37mOZ84|h? zt9R=*f~LT;5}}RaTRgD50}SvcHvuRGVHiMoEJZP02dOL23~L7qL0V@BOIGxShb7Zr zvp&0=Q){SYG_z%=?(3sL@||lU*mGiD#gOy8&OAbp{Lp0M=6$v}EE+$il+!t}*0Vww z#n|SD)e|On8Sch3V$4t8cJY~#-VsOuue30waEHkbe`~K>_a20CT&CgX_sD%rA>(No z7cyoIOs0X)i1%LCd!j5`WYcI+Zx)?V-|GGtW3x5y;k9`tvcOvhQj;JI$gFe{B8gZp zM~GIiaySt6DmHg|F=v?^K(8F!IzQ)r;(iy&y7bE_fDCgoK{m&tVEh={5Tt*AyQ#A+r1P1h_Lg$yj*x9tU+a-sv-q zCjyKUls5;DQ-Xo>gtVYVge$9~s=N`cziuk-@J6Wd0GPqt zi*Zvu2$5%Ud&1g}eg80N@O&x=11ew2zY(y&8$EE>P9Yr4Xn!jIRytwTHphnsHR}za z;|cQpZ4S>iBo^ce;bIuz!1S##IHHg&9>S|mLbpp^h%*?JAfG0(bHf2{9X7>%p7RFS z1m``gal7bAlxge`V0|F*MXR==x4}B^)Gi(HgMvCNe%pdD&y`EaRu51@%sulW!_eB; zJcE(^$-J|)r#R7%P`>j#Gi3GNO7PHU ztF$VLeJS&@q*9uucZpWhT)-nnY-ccOr4xl60#InX;%8L@N7&FwQ=^EfkrpUUB@3TX zDpS;Si%>qXedZ6#I};V#H0!hG$+s#<7Z6a|?4thM8D&Wz`de#jf&Tu%br3~M1tIDS zs?7o1ywM7Ne!Y$C0V#%QDR=s!k{1ItJY^wv{hh>NR*1=|Af;G(M?Y187%v+9Jo-Df zr0UHSWuD=wsdGh2+fT9}2%-gQpp%E$T>qPsTSI3F`2~x|-ZxM)9#@xK){?Je|=KU5RDH-x2&I{d&=&U==Gc=X7E@6?ZG1FuB)f9_R6a{!*S!pd|dw6q!Hy zC>vCfUYvZM6l)pnY%c5gr%P%;yu zD&iKRCS-n@aZ%HhCX%qk3qk>BM-C!0069UGfQ2np0MnxOA?DSTA>g!$o3}6RdqPqS z#nl8pEaS7w9a3iQJhwN)@LLkO#TAPZ2~-?*ef7hOw1CqP4SPlJu@p)>Y{qG8z^a7^ zUf@Cp666L<>R93P-3*XitvO{7)}@WyuEb)Fav8$%9M_}=^Gktke1Tr+^fE6XrWs5- z!3B~82F2p$ThH8SvRnb{LK=F%ltvtYhnB{%yT3Vvv8Qafi39JxQ*K0P^pVB&jGdErIO|Z0&zoz?e5rQ+m2cUw_K)Bg9G217}PpQ`psp#F={N_tc(VNHy^krbA1f{ zOM+f#6)H0Z$O%ni#A5sFhuXg7+Bo?;HW`f)jVJ`*_X72xUbQSJAM(;ufUZCow>Nps zOChP~D#C-Y@Fe+$VLt+piDmuWABqKOhp$&!>Y zHB(KdnQ3O)vkbyT_O0t$OQ>{3)+-W9*>B{RJtA8Q*Nsy5_nh9DX5Lxena1aQ@Xzx- z&vTyboOg@6oE$fPWpz@&8_##gF727|w9+*pmf4Fp$p6lm=`CfGQ!4yd^khzP3F|s8 z=6;UuG=rLpX?=P|uIirLYaI29L+tHqL1*fx{59)@XoH8>n%dc}ha0BPI-_l~!h2cw z$g%^WCu2_D8O{kUJ-SN~wkf(Dh08yU=@pUvDE>z1Ki+G;IY;c?5-_5R_q*nOe_3DqQ(za~GVE*NaiQr~ zx1L*mpT`*CACt_{4;e80)XxA%#+<4;lcv2BEbKl-dlX}bLKj{l6o9o7ue*+C1AIWkDk9FK7Oa=pje8oc0O$+(~D@M^f+H4FNM^=P^EXdu%i^Dl*b!)7^ZF zpF+z_gVL+VPq7xxdim*0+YTBJlInHz>qyVlD*6;B-YKKrhkdQNm`FnCv7TDrDtFJC%UBEP0zm|%5_N#EzoY} zsj0WeEDGr8|7g@x*RPE``ttlP794Cm>F{(r{qg6c1y^mUS?Bf3ME*Notv8>s^48F$ zgTs1HFz+1{jfcK9UqT-LjO?DC>XlT3?3 ziql8C-*C2mbBD9)UVRHS_5Jj7#hWR2Zd;^ZIkxNMCa3a-fo{VGUj4<_eS9E#?e+(m zf!|AxHrMK#2s^u8+3I7NQp63sxX&Z1u&i+WG^Yb`Q`qBpvyvS5_oy`b^)~xTib3Jd z#-^aB5uV2l7e20dWmrG+#7&!FZnI;Os&#gb5E@%1Yh)Y^ai{2ldKK%Zw(Q_P!dH0EGuX&=Kb1AVPsDNfQ@AA`@rSJ{tYjtNo#$8^qbN&8Z19vv;AGzweRo%R^{aYFf zi*Ein7qIfGnd_K}SFf)&!acD&vnel39OF-6jSVM`WiIG^A+0Kx*U$2$^WwzpE&Iwv zi`QBvr@XQn#BsEG!%7zv{#JiZEBEwZMqK8DJnt~yhK3yb)Z12pclXTSSg`C?mB4zW zW#fT2bH@r3E?p}dy}U)(;r$icmwxV7eeUUxt7Shh;G8sHzB-w4?^tlUXvvNb7uKGA zcAc@k|L}>+`qj;wVZ_UP@s6TDZWd?Fx3%$H{WGTZ{dG5TN~~%+r`Kd8zw{k;F6VxJ z-hSQ9ie0GPrRnhsivIfk>EFHvUDr}*L(N51X_gCbBplQ_82wf!@%6dK zU-vrC{SuJW6wPJv6@VR`+?|e!KE;ecUUz(Gy}rofgFv&+h!J`qWh` z-|gNnrvG7JF}#o8m%tBU`9Y}+|4qRbV`q1?N;d4s)v}HkB-Iy}xxHLuYT-66?BuokN)DJcZ#0U_s;$o+$}%qw zi(2uyh~0l;ipBG%|s9d~3M z46ZUR+>qTZUBFsEJv1pd-PnKJri#obwiBIoW~|ON-80ARkV%c;b?yCaslo$;1I;V# zxBhfDN$nf8;Q|kPk;^%eyRfm})9nAWr8~tEzs*#wz~wWA@Tz%Vxc;XDJ4K(Fvth5; zx>1~?t8}Bt+~PL#wYAZzx@P0_eI~~;I&pYi50AF+9p!M?*mG=x*NahkskOZt>k{;) zXh-S&_GzryGP}yWnJqs{|Nh^$*Khmq3eE)vm3`DkI4_iPUYVs5~F)ld@?%i56{04JEg6z1L zS1oP%gEB86?}AbFmmBLjrAbbSA1l57ceP7dSKniLD=M?JirpMGGE8Q4G&Aj7al8BT z2Xx6JsM<#Ak2K$~&{-U2kgCrOg))Z(VFT z^mk6;!(RQq`S?t?2;dKB`r%oC&Ap%bX5-4PuPc_F-{ce<9gSqJ`o9k&{P{&7zqp&;8Ucknj&sObZrqCO7bI`@Y6t$$PE?XCPY^m<*qQw znh+hH+7~Y0mJ0``=S(onfH1ky=3-F{x{w~rV#bM|R)VEb@?4?3-19W%x0@jM7_1g? zX@-sv%VlvG%yXqR#*Zq_iL33xwuu0!~3(vi2+7e|!@K{UG^ zO1NLN^_&lgJh%x(cER&SJ;tj<#6~dM!??WZ!QMZ>P=|m+T<}Y9|4VDkBi|=3IOLRe zs8M(0hQUz~-vpK-u0`G?m5A7ob`ZLpo_^K`lz^p`Gt{4xRTAP@i&^bpbnf!(<5-Yi z1ey@tc8-TiM(cx9?SMq|@N6jVhhdYv+0?7n#uP=evPGUA#)2~$alYLDagUf8$33DU?hSa)J@6tYwj66oz> zto7%0zX$S-!B#|u;bN5xHcP~Mdg-%NcB`vv7!UuHcrMB}5x3{)uvOrZuf z4Nv5#mK$Hb)F-JohE+w%7s`iA#bU$xbY6s1s0LO2wezBW?_sWZ2meh9mFSLdavSdW#k728oi(BA3-QHcIJ^GtyfvY)UxvZ#g+ydU_ z6O^}KxH#h+)h$S^o6d0=agxQt<<75D(SqP|yCsWU^~PV#>W`ft*ubxv9A+R*1iQ{j9Ji&%hx(Iq=I#L!u!FmXIdNvwW} znyB1yG>N1>7dm3hczP6%%@pSn4Hoh6vmy&{5zHB)+)zAOJm43|ij&)Ps1%IPQ$FWO zG6}wX3;&Xtr^K%{PJZ3KA36F7Cfoz6uWaSb5M?QqD>riuavxo(28fAc9Fg zT~s!6cqpR16$}~Z)~@a&eup%>0JeLwjY@`SOrcVY1M!JBveJVGDWY)CvrJ8aqOXe{ z=)j#3UtjZUN-6d<^e&uMjij|x1FH%5t+L$(l2K8T?H@BlX(dWQHnb4BfEB6%1a~U; zWe=z*R3$%?w$MU5+22Z)LE35xr|VU+ZS6eRejcgy5mo>Sjgf7#F|1issZuswD5Qr* zL@_x+nU~I@0-$OqimTFN+9sD>1_zIh0}n%Em<%poWbjaxDzHmr#DvPR<|pWqV$OFZn>ZH+`0$~JG$O@%XZ1L}Qf~#oYnOzK5*R6qDd(g0#v1q>Na3@vF zsdPRgj?QONytyGPHk0BT!R0WC+NyL?skSK{*L0Z+Wu~+iY(EV&kW-; z1rd}`c6)T4cAoj`6}TxHl6-|CzF9QgL=`cL&SGn*8XkYhP0yIVGN!{vScNG33UTY|d_)ezcPG;s%}aaohsOq#w> zS=;MDu9+Z|&*BL+)6gM(F?E1R)O;`4HkUfdr>`arNn%YUCje)xT$LAAX$!*iTX(Mq zSTqO{$!LOAa~5i*9RzsWr3jU+h;m0E?i|b($pB?{4vIHN%Ad@q4H>Z+E|+1Q;e3FY z_`?;2+Bnb{Tp%I6SoOhAAl0 z{ziA~PX3zRuqf|9{7{*NsTDnpP!Mlp4Pna`ve4lNO~{Pb{I~{r_?Cy`2kwKZ?}kKS zA%n^g-CC@GvKF_7v={*xuU!^9bJn_&3aiuzMkFSq;wS}<%~%?TDU9Rt7t>grFs=q5 zn9LS<7SE$!DWvB)`wuq%Zf zJh8Ov#i&-G6(L}SfER=dEW=~fmv)?JLMx`;JonYE1Gw7?@Bw0WEnTaIDCE<_!dRg+ zHY+?rNZ>vRIzg6y5|$KG?Wt4j&w}q2ft!yY_@2{xHC*UP<7Krp*-A>wPrpumXq>Hg z3u;INXe#No@tE~XRYMCCM9IRoul$otwLTfwsf)S_yIq-vVK?E*z$k)hOE;>4f#363 zwz53mRVsM6U;580rdC&BJcBjCZFf)kn`OJ&VcLB;*1WOfM^4BGZ1HaHvJs-{A7!(?&<5nM@w^Y0$g zHT>jXLJcsg`H|Q`3rjQ7YFk5u&Jcajkc6U8avm4-J1G#UcEBaG#2ileeLbXWhyzPM z=twt&c(c(~2xL{mBSV5zqhll>zlDI9$=4;Xsvk|W$j`X$atPxV`Jrb-ZxoQ2u zw29ft7pGQZ*y;Be=19Q)vg@W1RxXW8*e+?LR!059jF6<6V>)8kb9gU_WM6|vN`9a2 zD%lcq)57U&Hj|&AL4}t#U;V!>3_`aetc3t2wi2EL6p%J{u%8h`Fd0yyIBhRR(d>xM z`PQ@0AgE1Na4!iF)XQ8EmTSIAAMNXU z7>0(EOoGT4C8}k#omb7E^MqU;#fEsGV>UL9?2z+1&?}9n{^ktF9<75w&!ei-u#N7W zK=GaIMzOXh;_o|>;>!W=W^^L)CLGYA;Y`2>`?ni!OT>RB$J+zm_sF|VKj6#^4dNN$ z9=bZb555VaOy;v<<<1DNIgl#ecN)vp{jtLx7g%vL>q+-MLT{^)vjGw@Fk2$@k74>+NUgX%<) zTk_|rq=u&hebnpj+h2miqd_I;KX;!xx@5_{I6@{LHo+8kE{B7^?}xY!jvGnmA%u1K z*L28xU0fjg0}{0~syq2R8=B2XQT@dWiZRjC7e zvjm|O|4=%(9iPHrhSA}0iKw|9x&80J1U??#_V-|Le>8|mm+@KM1PJy=Ip2YZuO>Hq zZ@@n~mTT0{7{kzTA?V)-UovRB7LWJ-s9MVuRav|{H;Na7yx)#Eg^jARueeJE*ZmTXx|o5l?yhL^%B9rzVwZMFA|ao z8bo&ZfcCTPY}?qc$l30|4y0C}X8{)t2ZB?%4bqT3rR|EC3_6z_{RF73}xOJBv4SzRCS77n+npFtOa2C<-3+G~iP1DB5}Q{tJS zF+$YKc%lOY;ykqBd$3CHo5Fi#Ettpitxs?M59WXdF|2JTw`U%{d?t^VKp}pT7WRZy zFG;7c0Gz<7?nReZuqQ-==zt=B4W}UE{Ps?54)~1R3+TYUd{MCH6l{FaAhOHnx1Vh* z4ZOGH?CxOtzB{k#x`6kgF@@m#{|0HuZgl}S20Xn2&&2TQLawr=;s^N>jE1QM2c&L% z3?6`nD`6@p+3lH%*b5XJ8yj*@glEZI!w>2umV;xWL2NKPCTlo{$=uMGwi{Gr9AQ2A zVz>a^H=!x`E;t|>#7yJ`w<0JhZ;HuYnu%o4ndIm}VEiUKzil;R`2DXb??by+^|t5KJ!<2dl~T9}4<-d#;z9_jkcWa6NIpt}l&?n?HwJYN)Ds3Bjz$*Qj* zP5#44qyFv{4XFgzlW77H$Zb9uY;I*lwfF{MhX%3w8Qs>9E)6{;9!DehIK^+k<2Nm$ zQ?Y!}(kJbnf(>P!6OnG}&B64WXn zlz#wCGZ69fN3x)MUlc*AK8BOC2g-`8>8?k3jiCDJDZaT(R^FLjdeZlpfiUzQGm^+ve7Id!*h@3LwnyDT7JAfO XK~^W&Yhu_o_#<$^u - Graph | Basic usage + Graph | Basic usage - + - + @@ -19,31 +19,31 @@

    diff --git a/examples/graph/02_random_nodes.html b/examples/graph/02_random_nodes.html index b048a69d..24e5926a 100755 --- a/examples/graph/02_random_nodes.html +++ b/examples/graph/02_random_nodes.html @@ -1,105 +1,105 @@ - Graph | Random nodes + Graph | Random nodes - + - + - + // add event listeners + vis.events.addListener(graph, 'select', function(params) { + document.getElementById('selection').innerHTML = + 'Selection: ' + graph.getSelection(); + }); + } +
    - - - + + +

    diff --git a/examples/graph/03_images.html b/examples/graph/03_images.html index f0235fb6..f1a16db1 100755 --- a/examples/graph/03_images.html +++ b/examples/graph/03_images.html @@ -1,78 +1,78 @@ - Graph | Images - - - - - - + Graph | Images + + + + + + diff --git a/examples/graph/04_shapes.html b/examples/graph/04_shapes.html index 25b3f3ea..b6db4dd9 100755 --- a/examples/graph/04_shapes.html +++ b/examples/graph/04_shapes.html @@ -1,71 +1,71 @@ - Graph | Shapes + Graph | Shapes - + - + - + } + + // create a graph + var container = document.getElementById('mygraph'); + var data = { + nodes: nodes, + edges: edges + }; + var options = { + stabilize: false + }; + graph = new vis.Graph(container, data, options); + } + diff --git a/examples/graph/05_social_network.html b/examples/graph/05_social_network.html index 480eca6b..2a19aed0 100644 --- a/examples/graph/05_social_network.html +++ b/examples/graph/05_social_network.html @@ -1,76 +1,76 @@ - Graph | Social Network + Graph | Social Network - + - + - + // create a graph + var container = document.getElementById('mygraph'); + var data = { + nodes: nodes, + edges: edges + }; + var options = {}; + graph = new vis.Graph(container, data, options); + } +

    - Icons: Scrap Icons by Deleket + Icons: Scrap Icons by Deleket

    diff --git a/examples/graph/06_groups.html b/examples/graph/06_groups.html index 59adfb51..546b0c66 100644 --- a/examples/graph/06_groups.html +++ b/examples/graph/06_groups.html @@ -1,156 +1,156 @@ - Graph | Groups + Graph | Groups + + + + + + + - - - + }; + graph = new vis.Graph(container, data, options); + } +
    - Number of groups: - - Number of nodes per group: - - + Number of groups: + + Number of nodes per group: + +

    diff --git a/examples/graph/07_selections.html b/examples/graph/07_selections.html index 421c3794..25faf4c9 100644 --- a/examples/graph/07_selections.html +++ b/examples/graph/07_selections.html @@ -1,17 +1,17 @@ - Graph | Selections + Graph | Selections - + - + @@ -20,45 +20,45 @@
    diff --git a/examples/graph/08_mobile_friendly.html b/examples/graph/08_mobile_friendly.html index de44f4a8..f94ca61e 100755 --- a/examples/graph/08_mobile_friendly.html +++ b/examples/graph/08_mobile_friendly.html @@ -1,105 +1,105 @@ - Graph | Mobile friendly + Graph | Mobile friendly - + #mygraph { + width: 100%; + height: 100%; + } + - - + + - + - + }; + graph = new vis.Graph(container, data, options); + } + diff --git a/examples/graph/09_sizing.html b/examples/graph/09_sizing.html index 67a48f8e..302d5282 100644 --- a/examples/graph/09_sizing.html +++ b/examples/graph/09_sizing.html @@ -1,77 +1,77 @@ - Graph | Sizing + Graph | Sizing - + - + - + }; + graph = new vis.Graph(container, data, options); + } + diff --git a/examples/graph/10_multiline_text.html b/examples/graph/10_multiline_text.html index 695d5fba..1d8a96b2 100755 --- a/examples/graph/10_multiline_text.html +++ b/examples/graph/10_multiline_text.html @@ -1,47 +1,47 @@ - Graph | Multiline text + Graph | Multiline text - + - + - + // create a graph + var container = document.getElementById('mygraph'); + var data = { + nodes: nodes, + edges: edges + }; + var options = {}; + var graph = new vis.Graph(container, data, options); + } + diff --git a/examples/graph/11_custom_style.html b/examples/graph/11_custom_style.html index 20e9dd59..811c1754 100644 --- a/examples/graph/11_custom_style.html +++ b/examples/graph/11_custom_style.html @@ -1,128 +1,128 @@ - Graph | Custom style + Graph | Custom style - + - + - + }; + + // create the graph + var container = document.getElementById('mygraph'); + var data = { + nodes: nodes, + edges: edges + }; + graph = new vis.Graph(container, data, options); + } + diff --git a/examples/graph/12_scalable_images.html b/examples/graph/12_scalable_images.html index 8a3da963..a9890f64 100644 --- a/examples/graph/12_scalable_images.html +++ b/examples/graph/12_scalable_images.html @@ -1,80 +1,80 @@ - Graph | Scalable images + Graph | Scalable images - + - + - + }; + graph = new vis.Graph(container, data, options); + } + diff --git a/examples/graph/13_dashed_lines.html b/examples/graph/13_dashed_lines.html index 6f954672..e69c773a 100644 --- a/examples/graph/13_dashed_lines.html +++ b/examples/graph/13_dashed_lines.html @@ -1,65 +1,65 @@ - Graph | Dashed lines + Graph | Dashed lines - + - + - + // create the graph + var container = document.getElementById('mygraph'); + var data = { + nodes: nodes, + edges: edges + }; + var options = { + nodes: { + shape: 'box' + }, + edges: { + length: 180 + }, + stabilize: false + }; + var graph = new vis.Graph(container, data, options); + } + -

    - This example shows the different options for dashed lines. -

    +

    + This example shows the different options for dashed lines. +

    -
    +
    diff --git a/examples/graph/14_dot_language.html b/examples/graph/14_dot_language.html index 7d86df95..11bf5763 100644 --- a/examples/graph/14_dot_language.html +++ b/examples/graph/14_dot_language.html @@ -1,18 +1,18 @@ - Graph | DOT Language + Graph | DOT Language - + -
    +
    - + diff --git a/examples/graph/15_dot_language_playground.html b/examples/graph/15_dot_language_playground.html index bf757cd8..d0c5912b 100644 --- a/examples/graph/15_dot_language_playground.html +++ b/examples/graph/15_dot_language_playground.html @@ -1,201 +1,201 @@ - Graph | DOT language playground - - - - + textarea.example { + display: none; + } + - - - - - - - - - + + + + + + + + +
    -

    DOT language playground

    - -
    -
    - - -
    -
    - - -
    -
    +

    DOT language playground

    + +
    +
    + + +
    +
    + + +
    +
    diff --git a/examples/graph/16_dynamic_data.html b/examples/graph/16_dynamic_data.html index b4ccb596..d8536f97 100644 --- a/examples/graph/16_dynamic_data.html +++ b/examples/graph/16_dynamic_data.html @@ -1,264 +1,264 @@ - Graph | DataSet + Graph | DataSet - + #graph { + width: 100%; + height: 400px; + border: 1px solid lightgray; + } + - - + + - + // create a graph + var container = $('#graph').get(0); + var data = { + nodes: nodes, + edges: edges + }; + var options = {}; + graph = new vis.Graph(container, data, options); + }); +

    - This example demonstrates dynamically adding, updating and removing nodes - and edges using a DataSet. + This example demonstrates dynamically adding, updating and removing nodes + and edges using a DataSet.

    Adjust

    - - - - + + + +
    -

    Node

    - - - - - - - - - - - - - - - - -
    Action - - - -
    -
    -

    Edge

    - - - - - - - - - - - - - - - - - - - - - -
    Action - - - -
    -
    +

    Node

    + + + + + + + + + + + + + + + + +
    Action + + + +
    +
    +

    Edge

    + + + + + + + + + + + + + + + + + + + + + +
    Action + + + +
    +

    View

    - - - - - - - + + + + + + + - + - - + +
    -

    Nodes

    -
    
    -        
    +

    Nodes

    +
    
    +    
    -

    Edges

    -
    
    -        
    +

    Edges

    +
    
    +    
    -

    Graph

    -
    -
    +

    Graph

    +
    +
    diff --git a/examples/graph/17_network_info.html b/examples/graph/17_network_info.html index 62cd9eef..ec4379e2 100644 --- a/examples/graph/17_network_info.html +++ b/examples/graph/17_network_info.html @@ -1,149 +1,149 @@ - Graph | Images - - + + + + - - + }; + graph = new vis.Graph(container, data, options); + } + diff --git a/examples/graph/graphviz/graphviz_gallery.html b/examples/graph/graphviz/graphviz_gallery.html index 3260187d..280ba6c5 100644 --- a/examples/graph/graphviz/graphviz_gallery.html +++ b/examples/graph/graphviz/graphviz_gallery.html @@ -1,86 +1,86 @@ - Graph | Graphviz Gallery + Graph | Graphviz Gallery - - + + - +

    - The following examples are unmodified copies from the - Graphviz Gallery. + The following examples are unmodified copies from the + Graphviz Gallery.

    - Note that some style attributes of Graphviz are not supported by vis.js, - and that vis.js offers options not supported by Graphviz (which could make - some examples look much nicer). + Note that some style attributes of Graphviz are not supported by vis.js, + and that vis.js offers options not supported by Graphviz (which could make + some examples look much nicer).

    - - + +

    diff --git a/examples/graph/index.html b/examples/graph/index.html index 0fd44cfb..7cb11657 100644 --- a/examples/graph/index.html +++ b/examples/graph/index.html @@ -2,34 +2,34 @@ - vis.js | graph examples + vis.js | graph examples - + diff --git a/examples/timeline/01_basic.html b/examples/timeline/01_basic.html index d8a5f50e..514eefd1 100644 --- a/examples/timeline/01_basic.html +++ b/examples/timeline/01_basic.html @@ -1,31 +1,32 @@ - Timeline | Basic demo + Timeline | Basic demo - + - + +
    \ No newline at end of file diff --git a/examples/timeline/02_dataset.html b/examples/timeline/02_dataset.html index 36575945..e493663d 100644 --- a/examples/timeline/02_dataset.html +++ b/examples/timeline/02_dataset.html @@ -1,60 +1,62 @@ - Timeline | Dataset example - - - - - - - + Timeline | Dataset example + + + + + + + +
    diff --git a/examples/timeline/03_much_data.html b/examples/timeline/03_much_data.html index 45c4f40e..60005819 100644 --- a/examples/timeline/03_much_data.html +++ b/examples/timeline/03_much_data.html @@ -13,7 +13,8 @@ - + +

    diff --git a/examples/timeline/04_html_data.html b/examples/timeline/04_html_data.html index c01dbfcc..47997fd3 100644 --- a/examples/timeline/04_html_data.html +++ b/examples/timeline/04_html_data.html @@ -1,69 +1,74 @@ - Timeline | HTML data + Timeline | HTML data - + + + + -

    - Load HTML contents in the Timeline + Load HTML contents in the Timeline

    \ No newline at end of file diff --git a/examples/timeline/05_groups.html b/examples/timeline/05_groups.html index d6c9ced4..a103d1a3 100644 --- a/examples/timeline/05_groups.html +++ b/examples/timeline/05_groups.html @@ -1,71 +1,72 @@ - Timeline | Group example + Timeline | Group example - + #visualization { + box-sizing: border-box; + width: 100%; + height: 300px; + } + - - + + - + +

    - This example demonstrate using groups. Note that a DataSet is used for both - items and groups, allowing to dynamically add, update or remove both items - and groups via the DataSet. + This example demonstrate using groups. Note that a DataSet is used for both + items and groups, allowing to dynamically add, update or remove both items + and groups via the DataSet.

    diff --git a/examples/timeline/index.html b/examples/timeline/index.html index 937d5dab..91b28ffe 100644 --- a/examples/timeline/index.html +++ b/examples/timeline/index.html @@ -2,21 +2,21 @@ - vis.js | timeline examples + vis.js | timeline examples - + diff --git a/examples/timeline/requirejs/requirejs_example.html b/examples/timeline/requirejs/requirejs_example.html index 764a75ba..d4e85f08 100644 --- a/examples/timeline/requirejs/requirejs_example.html +++ b/examples/timeline/requirejs/requirejs_example.html @@ -1,11 +1,13 @@ - Timeline requirejs demo + Timeline requirejs demo - + + + -
    +
    diff --git a/examples/timeline/requirejs/scripts/main.js b/examples/timeline/requirejs/scripts/main.js index 15e1d872..ff6d5108 100644 --- a/examples/timeline/requirejs/scripts/main.js +++ b/examples/timeline/requirejs/scripts/main.js @@ -1,19 +1,19 @@ require.config({ - paths: { - vis: '../../../../vis' - } + paths: { + vis: '../../../../dist/vis' + } }); require(['vis'], function (vis) { - var container = document.getElementById('visualization'); - var data = [ - {id: 1, content: 'item 1', start: '2013-04-20'}, - {id: 2, content: 'item 2', start: '2013-04-14'}, - {id: 3, content: 'item 3', start: '2013-04-18'}, - {id: 4, content: 'item 4', start: '2013-04-16', end: '2013-04-19'}, - {id: 5, content: 'item 5', start: '2013-04-25'}, - {id: 6, content: 'item 6', start: '2013-04-27'} - ]; - var options = {}; - var timeline = new vis.Timeline(container, data, options); + var container = document.getElementById('visualization'); + var data = [ + {id: 1, content: 'item 1', start: '2013-04-20'}, + {id: 2, content: 'item 2', start: '2013-04-14'}, + {id: 3, content: 'item 3', start: '2013-04-18'}, + {id: 4, content: 'item 4', start: '2013-04-16', end: '2013-04-19'}, + {id: 5, content: 'item 5', start: '2013-04-25'}, + {id: 6, content: 'item 6', start: '2013-04-27'} + ]; + var options = {}; + var timeline = new vis.Timeline(container, data, options); }); diff --git a/index.html b/index.html index 4ba37bae..ae57caf3 100644 --- a/index.html +++ b/index.html @@ -72,26 +72,8 @@ bower install vis

    download

    - - - - - - - - - -
    - Development - (version 0.2.0) - - 441 kB, uncompressed with comments -
    - Production - (version 0.2.0) - - 39 kB, minified and gzipped -
    +Click here to download vis.js +(version 0.3.0)

    Example

    @@ -104,30 +86,31 @@ bower install vis
    <!doctype html>
     <html>
     <head>
    -    <title>Timeline | Basic demo</title>
    -    <script src="http://visjs.org/vis.js"></script>
    -
    -    <style type="text/css">
    -        body, html {
    -            font-family: sans-serif;
    -        }
    -    </style>
    +  <title>Timeline | Basic demo</title>
    +  <script src="http://visjs.org/dist/vis.js"></script>
    +  <link href="http://visjs.org/dist/vis.css" rel="stylesheet" type="text/css" />
    +
    +  <style type="text/css">
    +    body, html {
    +      font-family: sans-serif;
    +    }
    +  </style>
     </head>
     <body>
     <div id="mytimeline"></div>
     
     <script type="text/javascript">
    -    var container = document.getElementById('mytimeline');
    -    var data = [
    -        {id: 1, content: 'item 1', start: '2013-04-20'},
    -        {id: 2, content: 'item 2', start: '2013-04-14'},
    -        {id: 3, content: 'item 3', start: '2013-04-18'},
    -        {id: 4, content: 'item 4', start: '2013-04-16', end: '2013-04-19'},
    -        {id: 5, content: 'item 5', start: '2013-04-25'},
    -        {id: 6, content: 'item 6', start: '2013-04-27'}
    -    ];
    -    var options = {};
    -    var timeline = new vis.Timeline(container, data, options);
    +  var container = document.getElementById('mytimeline');
    +  var data = [
    +    {id: 1, content: 'item 1', start: '2013-04-20'},
    +    {id: 2, content: 'item 2', start: '2013-04-14'},
    +    {id: 3, content: 'item 3', start: '2013-04-18'},
    +    {id: 4, content: 'item 4', start: '2013-04-16', end: '2013-04-19'},
    +    {id: 5, content: 'item 5', start: '2013-04-25'},
    +    {id: 6, content: 'item 6', start: '2013-04-27'}
    +  ];
    +  var options = {};
    +  var timeline = new vis.Timeline(container, data, options);
     </script>
     </body>
     </html>
    @@ -304,7 +287,7 @@ The source code of the examples can be found in the
     

    License

    - Copyright (C) 2010-2013 Almende B.V. + Copyright (C) 2010-2014 Almende B.V.

    diff --git a/package.js b/package.js new file mode 100644 index 00000000..e69de29b diff --git a/updateversion.js b/updateversion.js index 094dfd16..18878b6c 100644 --- a/updateversion.js +++ b/updateversion.js @@ -1,48 +1,14 @@ -// Update the version numbers and library sizes in index.md +// Update the version numbers and library sizes in index.html var fs = require('fs'), zlib = require('zlib'); -var VIS = 'vis.js', - VIS_MIN = 'vis.min.js', +var VIS_ZIP = './dist/vis.js', INDEX = 'index.html'; -// get development size -function developmentSize(callback) { - fs.readFile(VIS, function (err, data) { - if (!err) { - var size = Math.round(data.length / 1024) + ' kB'; - callback(null, size); - } - else { - callback(err); - } - }); -} - -// get (gzipped) production size -function productionSize(callback) { - fs.readFile(VIS_MIN, function (err, data) { - if (!err) { - zlib.gzip(data, function (err, data) { - if (!err) { - var size = Math.round(data.length / 1024) + ' kB'; - callback(null, size) - } - else { - callback(err); - } - }); - } - else { - callback(err); - } - }); -} - -// get version +// read version from dist/vis.js function version(callback) { - fs.readFile(VIS_MIN, function (err, data) { + fs.readFile(VIS_ZIP, function (err, data) { if (!err) { var match = /@version\s*([\w\.-]*)/i.exec(data); var version = undefined; @@ -58,15 +24,10 @@ function version(callback) { } // update version and library sizes in index.md -function updateVersion(developmentSize, productionSize, version, callback) { +function updateVersion(version, callback) { fs.readFile(INDEX, function (err, data) { if (!err) { data = String(data); - data = data.replace(/([\w\s]*)<\/span>/g, - '' + developmentSize + ''); - - data = data.replace(/([\w\s]*)<\/span>/g, - '' + productionSize + ''); data = data.replace(/([\w\.-]*)<\/span>/g, '' + version + ''); @@ -79,24 +40,19 @@ function updateVersion(developmentSize, productionSize, version, callback) { }); } -developmentSize(function (err, devSize) { - console.log('development size: ' + devSize); - productionSize(function (err, prodSize) { - console.log('production size: ' + prodSize); - version(function (err, version) { - console.log('version: ' + version); - if (devSize && prodSize && version) { - updateVersion(devSize, prodSize, version, function (err, res) { - if (err) { - console.log(err); - } - else { - console.log('done'); - } - }); + +version(function (err, version) { + console.log('version: ' + version); + if (version) { + updateVersion(version, function (err, res) { + if (err) { + console.log(err); } else { + console.log('done'); } }); - }); -}); + } + else { + } +}); \ No newline at end of file diff --git a/vis.js b/vis.js deleted file mode 100644 index eeb9980b..00000000 --- a/vis.js +++ /dev/null @@ -1,14667 +0,0 @@ -/** - * vis.js - * https://github.com/almende/vis - * - * A dynamic, browser-based visualization library. - * - * @version 0.2.0 - * @date 2013-09-20 - * - * @license - * Copyright (C) 2011-2013 Almende B.V, http://almende.com - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -(function(e){if("function"==typeof bootstrap)bootstrap("vis",e);else if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeVis=e}else"undefined"!=typeof window?window.vis=e():global.vis=e()})(function(){var define,ses,bootstrap,module,exports; -return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o; - * Licensed under the MIT license */ - -(function(window, undefined) { - 'use strict'; - -/** - * Hammer - * use this to create instances - * @param {HTMLElement} element - * @param {Object} options - * @returns {Hammer.Instance} - * @constructor - */ -var Hammer = function(element, options) { - return new Hammer.Instance(element, options || {}); -}; - -// default settings -Hammer.defaults = { - // add styles and attributes to the element to prevent the browser from doing - // its native behavior. this doesnt prevent the scrolling, but cancels - // the contextmenu, tap highlighting etc - // set to false to disable this - stop_browser_behavior: { - // this also triggers onselectstart=false for IE - userSelect: 'none', - // this makes the element blocking in IE10 >, you could experiment with the value - // see for more options this issue; https://github.com/EightMedia/hammer.js/issues/241 - touchAction: 'none', - touchCallout: 'none', - contentZooming: 'none', - userDrag: 'none', - tapHighlightColor: 'rgba(0,0,0,0)' - } - - // more settings are defined per gesture at gestures.js -}; - -// detect touchevents -Hammer.HAS_POINTEREVENTS = navigator.pointerEnabled || navigator.msPointerEnabled; -Hammer.HAS_TOUCHEVENTS = ('ontouchstart' in window); - -// dont use mouseevents on mobile devices -Hammer.MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i; -Hammer.NO_MOUSEEVENTS = Hammer.HAS_TOUCHEVENTS && navigator.userAgent.match(Hammer.MOBILE_REGEX); - -// eventtypes per touchevent (start, move, end) -// are filled by Hammer.event.determineEventTypes on setup -Hammer.EVENT_TYPES = {}; - -// direction defines -Hammer.DIRECTION_DOWN = 'down'; -Hammer.DIRECTION_LEFT = 'left'; -Hammer.DIRECTION_UP = 'up'; -Hammer.DIRECTION_RIGHT = 'right'; - -// pointer type -Hammer.POINTER_MOUSE = 'mouse'; -Hammer.POINTER_TOUCH = 'touch'; -Hammer.POINTER_PEN = 'pen'; - -// touch event defines -Hammer.EVENT_START = 'start'; -Hammer.EVENT_MOVE = 'move'; -Hammer.EVENT_END = 'end'; - -// hammer document where the base events are added at -Hammer.DOCUMENT = document; - -// plugins namespace -Hammer.plugins = {}; - -// if the window events are set... -Hammer.READY = false; - -/** - * setup events to detect gestures on the document - */ -function setup() { - if(Hammer.READY) { - return; - } - - // find what eventtypes we add listeners to - Hammer.event.determineEventTypes(); - - // Register all gestures inside Hammer.gestures - for(var name in Hammer.gestures) { - if(Hammer.gestures.hasOwnProperty(name)) { - Hammer.detection.register(Hammer.gestures[name]); - } - } - - // Add touch events on the document - Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_MOVE, Hammer.detection.detect); - Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_END, Hammer.detection.detect); - - // Hammer is ready...! - Hammer.READY = true; -} - -/** - * create new hammer instance - * all methods should return the instance itself, so it is chainable. - * @param {HTMLElement} element - * @param {Object} [options={}] - * @returns {Hammer.Instance} - * @constructor - */ -Hammer.Instance = function(element, options) { - var self = this; - - // setup HammerJS window events and register all gestures - // this also sets up the default options - setup(); - - this.element = element; - - // start/stop detection option - this.enabled = true; - - // merge options - this.options = Hammer.utils.extend( - Hammer.utils.extend({}, Hammer.defaults), - options || {}); - - // add some css to the element to prevent the browser from doing its native behavoir - if(this.options.stop_browser_behavior) { - Hammer.utils.stopDefaultBrowserBehavior(this.element, this.options.stop_browser_behavior); - } - - // start detection on touchstart - Hammer.event.onTouch(element, Hammer.EVENT_START, function(ev) { - if(self.enabled) { - Hammer.detection.startDetect(self, ev); - } - }); - - // return instance - return this; -}; - - -Hammer.Instance.prototype = { - /** - * bind events to the instance - * @param {String} gesture - * @param {Function} handler - * @returns {Hammer.Instance} - */ - on: function onEvent(gesture, handler){ - var gestures = gesture.split(' '); - for(var t=0; t 0 && eventType == Hammer.EVENT_END) { - eventType = Hammer.EVENT_MOVE; - } - // no touches, force the end event - else if(!count_touches) { - eventType = Hammer.EVENT_END; - } - - // because touchend has no touches, and we often want to use these in our gestures, - // we send the last move event as our eventData in touchend - if(!count_touches && last_move_event !== null) { - ev = last_move_event; - } - // store the last move event - else { - last_move_event = ev; - } - - // trigger the handler - handler.call(Hammer.detection, self.collectEventData(element, eventType, ev)); - - // remove pointerevent from list - if(Hammer.HAS_POINTEREVENTS && eventType == Hammer.EVENT_END) { - count_touches = Hammer.PointerEvent.updatePointer(eventType, ev); - } - } - - //debug(sourceEventType +" "+ eventType); - - // on the end we reset everything - if(!count_touches) { - last_move_event = null; - enable_detect = false; - touch_triggered = false; - Hammer.PointerEvent.reset(); - } - }); - }, - - - /** - * we have different events for each device/browser - * determine what we need and set them in the Hammer.EVENT_TYPES constant - */ - determineEventTypes: function determineEventTypes() { - // determine the eventtype we want to set - var types; - - // pointerEvents magic - if(Hammer.HAS_POINTEREVENTS) { - types = Hammer.PointerEvent.getEvents(); - } - // on Android, iOS, blackberry, windows mobile we dont want any mouseevents - else if(Hammer.NO_MOUSEEVENTS) { - types = [ - 'touchstart', - 'touchmove', - 'touchend touchcancel']; - } - // for non pointer events browsers and mixed browsers, - // like chrome on windows8 touch laptop - else { - types = [ - 'touchstart mousedown', - 'touchmove mousemove', - 'touchend touchcancel mouseup']; - } - - Hammer.EVENT_TYPES[Hammer.EVENT_START] = types[0]; - Hammer.EVENT_TYPES[Hammer.EVENT_MOVE] = types[1]; - Hammer.EVENT_TYPES[Hammer.EVENT_END] = types[2]; - }, - - - /** - * create touchlist depending on the event - * @param {Object} ev - * @param {String} eventType used by the fakemultitouch plugin - */ - getTouchList: function getTouchList(ev/*, eventType*/) { - // get the fake pointerEvent touchlist - if(Hammer.HAS_POINTEREVENTS) { - return Hammer.PointerEvent.getTouchList(); - } - // get the touchlist - else if(ev.touches) { - return ev.touches; - } - // make fake touchlist from mouse position - else { - return [{ - identifier: 1, - pageX: ev.pageX, - pageY: ev.pageY, - target: ev.target - }]; - } - }, - - - /** - * collect event data for Hammer js - * @param {HTMLElement} element - * @param {String} eventType like Hammer.EVENT_MOVE - * @param {Object} eventData - */ - collectEventData: function collectEventData(element, eventType, ev) { - var touches = this.getTouchList(ev, eventType); - - // find out pointerType - var pointerType = Hammer.POINTER_TOUCH; - if(ev.type.match(/mouse/) || Hammer.PointerEvent.matchType(Hammer.POINTER_MOUSE, ev)) { - pointerType = Hammer.POINTER_MOUSE; - } - - return { - center : Hammer.utils.getCenter(touches), - timeStamp : new Date().getTime(), - target : ev.target, - touches : touches, - eventType : eventType, - pointerType : pointerType, - srcEvent : ev, - - /** - * prevent the browser default actions - * mostly used to disable scrolling of the browser - */ - preventDefault: function() { - if(this.srcEvent.preventManipulation) { - this.srcEvent.preventManipulation(); - } - - if(this.srcEvent.preventDefault) { - this.srcEvent.preventDefault(); - } - }, - - /** - * stop bubbling the event up to its parents - */ - stopPropagation: function() { - this.srcEvent.stopPropagation(); - }, - - /** - * immediately stop gesture detection - * might be useful after a swipe was detected - * @return {*} - */ - stopDetect: function() { - return Hammer.detection.stopDetect(); - } - }; - } -}; - -Hammer.PointerEvent = { - /** - * holds all pointers - * @type {Object} - */ - pointers: {}, - - /** - * get a list of pointers - * @returns {Array} touchlist - */ - getTouchList: function() { - var self = this; - var touchlist = []; - - // we can use forEach since pointerEvents only is in IE10 - Object.keys(self.pointers).sort().forEach(function(id) { - touchlist.push(self.pointers[id]); - }); - return touchlist; - }, - - /** - * update the position of a pointer - * @param {String} type Hammer.EVENT_END - * @param {Object} pointerEvent - */ - updatePointer: function(type, pointerEvent) { - if(type == Hammer.EVENT_END) { - this.pointers = {}; - } - else { - pointerEvent.identifier = pointerEvent.pointerId; - this.pointers[pointerEvent.pointerId] = pointerEvent; - } - - return Object.keys(this.pointers).length; - }, - - /** - * check if ev matches pointertype - * @param {String} pointerType Hammer.POINTER_MOUSE - * @param {PointerEvent} ev - */ - matchType: function(pointerType, ev) { - if(!ev.pointerType) { - return false; - } - - var types = {}; - types[Hammer.POINTER_MOUSE] = (ev.pointerType == ev.MSPOINTER_TYPE_MOUSE || ev.pointerType == Hammer.POINTER_MOUSE); - types[Hammer.POINTER_TOUCH] = (ev.pointerType == ev.MSPOINTER_TYPE_TOUCH || ev.pointerType == Hammer.POINTER_TOUCH); - types[Hammer.POINTER_PEN] = (ev.pointerType == ev.MSPOINTER_TYPE_PEN || ev.pointerType == Hammer.POINTER_PEN); - return types[pointerType]; - }, - - - /** - * get events - */ - getEvents: function() { - return [ - 'pointerdown MSPointerDown', - 'pointermove MSPointerMove', - 'pointerup pointercancel MSPointerUp MSPointerCancel' - ]; - }, - - /** - * reset the list - */ - reset: function() { - this.pointers = {}; - } -}; - - -Hammer.utils = { - /** - * extend method, - * also used for cloning when dest is an empty object - * @param {Object} dest - * @param {Object} src - * @parm {Boolean} merge do a merge - * @returns {Object} dest - */ - extend: function extend(dest, src, merge) { - for (var key in src) { - if(dest[key] !== undefined && merge) { - continue; - } - dest[key] = src[key]; - } - return dest; - }, - - - /** - * find if a node is in the given parent - * used for event delegation tricks - * @param {HTMLElement} node - * @param {HTMLElement} parent - * @returns {boolean} has_parent - */ - hasParent: function(node, parent) { - while(node){ - if(node == parent) { - return true; - } - node = node.parentNode; - } - return false; - }, - - - /** - * get the center of all the touches - * @param {Array} touches - * @returns {Object} center - */ - getCenter: function getCenter(touches) { - var valuesX = [], valuesY = []; - - for(var t= 0,len=touches.length; t= y) { - return touch1.pageX - touch2.pageX > 0 ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT; - } - else { - return touch1.pageY - touch2.pageY > 0 ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN; - } - }, - - - /** - * calculate the distance between two touches - * @param {Touch} touch1 - * @param {Touch} touch2 - * @returns {Number} distance - */ - getDistance: function getDistance(touch1, touch2) { - var x = touch2.pageX - touch1.pageX, - y = touch2.pageY - touch1.pageY; - return Math.sqrt((x*x) + (y*y)); - }, - - - /** - * calculate the scale factor between two touchLists (fingers) - * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out - * @param {Array} start - * @param {Array} end - * @returns {Number} scale - */ - getScale: function getScale(start, end) { - // need two fingers... - if(start.length >= 2 && end.length >= 2) { - return this.getDistance(end[0], end[1]) / - this.getDistance(start[0], start[1]); - } - return 1; - }, - - - /** - * calculate the rotation degrees between two touchLists (fingers) - * @param {Array} start - * @param {Array} end - * @returns {Number} rotation - */ - getRotation: function getRotation(start, end) { - // need two fingers - if(start.length >= 2 && end.length >= 2) { - return this.getAngle(end[1], end[0]) - - this.getAngle(start[1], start[0]); - } - return 0; - }, - - - /** - * boolean if the direction is vertical - * @param {String} direction - * @returns {Boolean} is_vertical - */ - isVertical: function isVertical(direction) { - return (direction == Hammer.DIRECTION_UP || direction == Hammer.DIRECTION_DOWN); - }, - - - /** - * stop browser default behavior with css props - * @param {HtmlElement} element - * @param {Object} css_props - */ - stopDefaultBrowserBehavior: function stopDefaultBrowserBehavior(element, css_props) { - var prop, - vendors = ['webkit','khtml','moz','ms','o','']; - - if(!css_props || !element.style) { - return; - } - - // with css properties for modern browsers - for(var i = 0; i < vendors.length; i++) { - for(var p in css_props) { - if(css_props.hasOwnProperty(p)) { - prop = p; - - // vender prefix at the property - if(vendors[i]) { - prop = vendors[i] + prop.substring(0, 1).toUpperCase() + prop.substring(1); - } - - // set the style - element.style[prop] = css_props[p]; - } - } - } - - // also the disable onselectstart - if(css_props.userSelect == 'none') { - element.onselectstart = function() { - return false; - }; - } - } -}; - -Hammer.detection = { - // contains all registred Hammer.gestures in the correct order - gestures: [], - - // data of the current Hammer.gesture detection session - current: null, - - // the previous Hammer.gesture session data - // is a full clone of the previous gesture.current object - previous: null, - - // when this becomes true, no gestures are fired - stopped: false, - - - /** - * start Hammer.gesture detection - * @param {Hammer.Instance} inst - * @param {Object} eventData - */ - startDetect: function startDetect(inst, eventData) { - // already busy with a Hammer.gesture detection on an element - if(this.current) { - return; - } - - this.stopped = false; - - this.current = { - inst : inst, // reference to HammerInstance we're working for - startEvent : Hammer.utils.extend({}, eventData), // start eventData for distances, timing etc - lastEvent : false, // last eventData - name : '' // current gesture we're in/detected, can be 'tap', 'hold' etc - }; - - this.detect(eventData); - }, - - - /** - * Hammer.gesture detection - * @param {Object} eventData - * @param {Object} eventData - */ - detect: function detect(eventData) { - if(!this.current || this.stopped) { - return; - } - - // extend event data with calculations about scale, distance etc - eventData = this.extendEventData(eventData); - - // instance options - var inst_options = this.current.inst.options; - - // call Hammer.gesture handlers - for(var g=0,len=this.gestures.length; g b.index) { - return 1; - } - return 0; - }); - - return this.gestures; - } -}; - - -Hammer.gestures = Hammer.gestures || {}; - -/** - * Custom gestures - * ============================== - * - * Gesture object - * -------------------- - * The object structure of a gesture: - * - * { name: 'mygesture', - * index: 1337, - * defaults: { - * mygesture_option: true - * } - * handler: function(type, ev, inst) { - * // trigger gesture event - * inst.trigger(this.name, ev); - * } - * } - - * @param {String} name - * this should be the name of the gesture, lowercase - * it is also being used to disable/enable the gesture per instance config. - * - * @param {Number} [index=1000] - * the index of the gesture, where it is going to be in the stack of gestures detection - * like when you build an gesture that depends on the drag gesture, it is a good - * idea to place it after the index of the drag gesture. - * - * @param {Object} [defaults={}] - * the default settings of the gesture. these are added to the instance settings, - * and can be overruled per instance. you can also add the name of the gesture, - * but this is also added by default (and set to true). - * - * @param {Function} handler - * this handles the gesture detection of your custom gesture and receives the - * following arguments: - * - * @param {Object} eventData - * event data containing the following properties: - * timeStamp {Number} time the event occurred - * target {HTMLElement} target element - * touches {Array} touches (fingers, pointers, mouse) on the screen - * pointerType {String} kind of pointer that was used. matches Hammer.POINTER_MOUSE|TOUCH - * center {Object} center position of the touches. contains pageX and pageY - * deltaTime {Number} the total time of the touches in the screen - * deltaX {Number} the delta on x axis we haved moved - * deltaY {Number} the delta on y axis we haved moved - * velocityX {Number} the velocity on the x - * velocityY {Number} the velocity on y - * angle {Number} the angle we are moving - * direction {String} the direction we are moving. matches Hammer.DIRECTION_UP|DOWN|LEFT|RIGHT - * distance {Number} the distance we haved moved - * scale {Number} scaling of the touches, needs 2 touches - * rotation {Number} rotation of the touches, needs 2 touches * - * eventType {String} matches Hammer.EVENT_START|MOVE|END - * srcEvent {Object} the source event, like TouchStart or MouseDown * - * startEvent {Object} contains the same properties as above, - * but from the first touch. this is used to calculate - * distances, deltaTime, scaling etc - * - * @param {Hammer.Instance} inst - * the instance we are doing the detection for. you can get the options from - * the inst.options object and trigger the gesture event by calling inst.trigger - * - * - * Handle gestures - * -------------------- - * inside the handler you can get/set Hammer.detection.current. This is the current - * detection session. It has the following properties - * @param {String} name - * contains the name of the gesture we have detected. it has not a real function, - * only to check in other gestures if something is detected. - * like in the drag gesture we set it to 'drag' and in the swipe gesture we can - * check if the current gesture is 'drag' by accessing Hammer.detection.current.name - * - * @readonly - * @param {Hammer.Instance} inst - * the instance we do the detection for - * - * @readonly - * @param {Object} startEvent - * contains the properties of the first gesture detection in this session. - * Used for calculations about timing, distance, etc. - * - * @readonly - * @param {Object} lastEvent - * contains all the properties of the last gesture detect in this session. - * - * after the gesture detection session has been completed (user has released the screen) - * the Hammer.detection.current object is copied into Hammer.detection.previous, - * this is usefull for gestures like doubletap, where you need to know if the - * previous gesture was a tap - * - * options that have been set by the instance can be received by calling inst.options - * - * You can trigger a gesture event by calling inst.trigger("mygesture", event). - * The first param is the name of your gesture, the second the event argument - * - * - * Register gestures - * -------------------- - * When an gesture is added to the Hammer.gestures object, it is auto registered - * at the setup of the first Hammer instance. You can also call Hammer.detection.register - * manually and pass your gesture object as a param - * - */ - -/** - * Hold - * Touch stays at the same place for x time - * @events hold - */ -Hammer.gestures.Hold = { - name: 'hold', - index: 10, - defaults: { - hold_timeout : 500, - hold_threshold : 1 - }, - timer: null, - handler: function holdGesture(ev, inst) { - switch(ev.eventType) { - case Hammer.EVENT_START: - // clear any running timers - clearTimeout(this.timer); - - // set the gesture so we can check in the timeout if it still is - Hammer.detection.current.name = this.name; - - // set timer and if after the timeout it still is hold, - // we trigger the hold event - this.timer = setTimeout(function() { - if(Hammer.detection.current.name == 'hold') { - inst.trigger('hold', ev); - } - }, inst.options.hold_timeout); - break; - - // when you move or end we clear the timer - case Hammer.EVENT_MOVE: - if(ev.distance > inst.options.hold_threshold) { - clearTimeout(this.timer); - } - break; - - case Hammer.EVENT_END: - clearTimeout(this.timer); - break; - } - } -}; - - -/** - * Tap/DoubleTap - * Quick touch at a place or double at the same place - * @events tap, doubletap - */ -Hammer.gestures.Tap = { - name: 'tap', - index: 100, - defaults: { - tap_max_touchtime : 250, - tap_max_distance : 10, - tap_always : true, - doubletap_distance : 20, - doubletap_interval : 300 - }, - handler: function tapGesture(ev, inst) { - if(ev.eventType == Hammer.EVENT_END) { - // previous gesture, for the double tap since these are two different gesture detections - var prev = Hammer.detection.previous, - did_doubletap = false; - - // when the touchtime is higher then the max touch time - // or when the moving distance is too much - if(ev.deltaTime > inst.options.tap_max_touchtime || - ev.distance > inst.options.tap_max_distance) { - return; - } - - // check if double tap - if(prev && prev.name == 'tap' && - (ev.timeStamp - prev.lastEvent.timeStamp) < inst.options.doubletap_interval && - ev.distance < inst.options.doubletap_distance) { - inst.trigger('doubletap', ev); - did_doubletap = true; - } - - // do a single tap - if(!did_doubletap || inst.options.tap_always) { - Hammer.detection.current.name = 'tap'; - inst.trigger(Hammer.detection.current.name, ev); - } - } - } -}; - - -/** - * Swipe - * triggers swipe events when the end velocity is above the threshold - * @events swipe, swipeleft, swiperight, swipeup, swipedown - */ -Hammer.gestures.Swipe = { - name: 'swipe', - index: 40, - defaults: { - // set 0 for unlimited, but this can conflict with transform - swipe_max_touches : 1, - swipe_velocity : 0.7 - }, - handler: function swipeGesture(ev, inst) { - if(ev.eventType == Hammer.EVENT_END) { - // max touches - if(inst.options.swipe_max_touches > 0 && - ev.touches.length > inst.options.swipe_max_touches) { - return; - } - - // when the distance we moved is too small we skip this gesture - // or we can be already in dragging - if(ev.velocityX > inst.options.swipe_velocity || - ev.velocityY > inst.options.swipe_velocity) { - // trigger swipe events - inst.trigger(this.name, ev); - inst.trigger(this.name + ev.direction, ev); - } - } - } -}; - - -/** - * Drag - * Move with x fingers (default 1) around on the page. Blocking the scrolling when - * moving left and right is a good practice. When all the drag events are blocking - * you disable scrolling on that area. - * @events drag, drapleft, dragright, dragup, dragdown - */ -Hammer.gestures.Drag = { - name: 'drag', - index: 50, - defaults: { - drag_min_distance : 10, - // set 0 for unlimited, but this can conflict with transform - drag_max_touches : 1, - // prevent default browser behavior when dragging occurs - // be careful with it, it makes the element a blocking element - // when you are using the drag gesture, it is a good practice to set this true - drag_block_horizontal : false, - drag_block_vertical : false, - // drag_lock_to_axis keeps the drag gesture on the axis that it started on, - // It disallows vertical directions if the initial direction was horizontal, and vice versa. - drag_lock_to_axis : false, - // drag lock only kicks in when distance > drag_lock_min_distance - // This way, locking occurs only when the distance has become large enough to reliably determine the direction - drag_lock_min_distance : 25 - }, - triggered: false, - handler: function dragGesture(ev, inst) { - // current gesture isnt drag, but dragged is true - // this means an other gesture is busy. now call dragend - if(Hammer.detection.current.name != this.name && this.triggered) { - inst.trigger(this.name +'end', ev); - this.triggered = false; - return; - } - - // max touches - if(inst.options.drag_max_touches > 0 && - ev.touches.length > inst.options.drag_max_touches) { - return; - } - - switch(ev.eventType) { - case Hammer.EVENT_START: - this.triggered = false; - break; - - case Hammer.EVENT_MOVE: - // when the distance we moved is too small we skip this gesture - // or we can be already in dragging - if(ev.distance < inst.options.drag_min_distance && - Hammer.detection.current.name != this.name) { - return; - } - - // we are dragging! - Hammer.detection.current.name = this.name; - - // lock drag to axis? - if(Hammer.detection.current.lastEvent.drag_locked_to_axis || (inst.options.drag_lock_to_axis && inst.options.drag_lock_min_distance<=ev.distance)) { - ev.drag_locked_to_axis = true; - } - var last_direction = Hammer.detection.current.lastEvent.direction; - if(ev.drag_locked_to_axis && last_direction !== ev.direction) { - // keep direction on the axis that the drag gesture started on - if(Hammer.utils.isVertical(last_direction)) { - ev.direction = (ev.deltaY < 0) ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN; - } - else { - ev.direction = (ev.deltaX < 0) ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT; - } - } - - // first time, trigger dragstart event - if(!this.triggered) { - inst.trigger(this.name +'start', ev); - this.triggered = true; - } - - // trigger normal event - inst.trigger(this.name, ev); - - // direction event, like dragdown - inst.trigger(this.name + ev.direction, ev); - - // block the browser events - if( (inst.options.drag_block_vertical && Hammer.utils.isVertical(ev.direction)) || - (inst.options.drag_block_horizontal && !Hammer.utils.isVertical(ev.direction))) { - ev.preventDefault(); - } - break; - - case Hammer.EVENT_END: - // trigger dragend - if(this.triggered) { - inst.trigger(this.name +'end', ev); - } - - this.triggered = false; - break; - } - } -}; - - -/** - * Transform - * User want to scale or rotate with 2 fingers - * @events transform, pinch, pinchin, pinchout, rotate - */ -Hammer.gestures.Transform = { - name: 'transform', - index: 45, - defaults: { - // factor, no scale is 1, zoomin is to 0 and zoomout until higher then 1 - transform_min_scale : 0.01, - // rotation in degrees - transform_min_rotation : 1, - // prevent default browser behavior when two touches are on the screen - // but it makes the element a blocking element - // when you are using the transform gesture, it is a good practice to set this true - transform_always_block : false - }, - triggered: false, - handler: function transformGesture(ev, inst) { - // current gesture isnt drag, but dragged is true - // this means an other gesture is busy. now call dragend - if(Hammer.detection.current.name != this.name && this.triggered) { - inst.trigger(this.name +'end', ev); - this.triggered = false; - return; - } - - // atleast multitouch - if(ev.touches.length < 2) { - return; - } - - // prevent default when two fingers are on the screen - if(inst.options.transform_always_block) { - ev.preventDefault(); - } - - switch(ev.eventType) { - case Hammer.EVENT_START: - this.triggered = false; - break; - - case Hammer.EVENT_MOVE: - var scale_threshold = Math.abs(1-ev.scale); - var rotation_threshold = Math.abs(ev.rotation); - - // when the distance we moved is too small we skip this gesture - // or we can be already in dragging - if(scale_threshold < inst.options.transform_min_scale && - rotation_threshold < inst.options.transform_min_rotation) { - return; - } - - // we are transforming! - Hammer.detection.current.name = this.name; - - // first time, trigger dragstart event - if(!this.triggered) { - inst.trigger(this.name +'start', ev); - this.triggered = true; - } - - inst.trigger(this.name, ev); // basic transform event - - // trigger rotate event - if(rotation_threshold > inst.options.transform_min_rotation) { - inst.trigger('rotate', ev); - } - - // trigger pinch event - if(scale_threshold > inst.options.transform_min_scale) { - inst.trigger('pinch', ev); - inst.trigger('pinch'+ ((ev.scale < 1) ? 'in' : 'out'), ev); - } - break; - - case Hammer.EVENT_END: - // trigger dragend - if(this.triggered) { - inst.trigger(this.name +'end', ev); - } - - this.triggered = false; - break; - } - } -}; - - -/** - * Touch - * Called as first, tells the user has touched the screen - * @events touch - */ -Hammer.gestures.Touch = { - name: 'touch', - index: -Infinity, - defaults: { - // call preventDefault at touchstart, and makes the element blocking by - // disabling the scrolling of the page, but it improves gestures like - // transforming and dragging. - // be careful with using this, it can be very annoying for users to be stuck - // on the page - prevent_default: false, - - // disable mouse events, so only touch (or pen!) input triggers events - prevent_mouseevents: false - }, - handler: function touchGesture(ev, inst) { - if(inst.options.prevent_mouseevents && ev.pointerType == Hammer.POINTER_MOUSE) { - ev.stopDetect(); - return; - } - - if(inst.options.prevent_default) { - ev.preventDefault(); - } - - if(ev.eventType == Hammer.EVENT_START) { - inst.trigger(this.name, ev); - } - } -}; - - -/** - * Release - * Called as last, tells the user has released the screen - * @events release - */ -Hammer.gestures.Release = { - name: 'release', - index: Infinity, - handler: function releaseGesture(ev, inst) { - if(ev.eventType == Hammer.EVENT_END) { - inst.trigger(this.name, ev); - } - } -}; - -// node export -if(typeof module === 'object' && typeof module.exports === 'object'){ - module.exports = Hammer; -} -// just window export -else { - window.Hammer = Hammer; - - // requireJS module definition - if(typeof window.define === 'function' && window.define.amd) { - window.define('hammer', [], function() { - return Hammer; - }); - } -} -})(this); -},{}],2:[function(require,module,exports){ -//! moment.js -//! version : 2.2.1 -//! authors : Tim Wood, Iskren Chernev, Moment.js contributors -//! license : MIT -//! momentjs.com - -(function (undefined) { - - /************************************ - Constants - ************************************/ - - var moment, - VERSION = "2.2.1", - round = Math.round, i, - // internal storage for language config files - languages = {}, - - // check for nodeJS - hasModule = (typeof module !== 'undefined' && module.exports), - - // ASP.NET json date format regex - aspNetJsonRegex = /^\/?Date\((\-?\d+)/i, - aspNetTimeSpanJsonRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)\:(\d+)\.?(\d{3})?/, - - // format tokens - formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|SS?S?|X|zz?|ZZ?|.)/g, - localFormattingTokens = /(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g, - - // parsing token regexes - parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99 - parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999 - parseTokenThreeDigits = /\d{3}/, // 000 - 999 - parseTokenFourDigits = /\d{1,4}/, // 0 - 9999 - parseTokenSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999 - parseTokenWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, // any word (or two) characters or numbers including two/three word month in arabic. - parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/i, // +00:00 -00:00 +0000 -0000 or Z - parseTokenT = /T/i, // T (ISO seperator) - parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123 - - // preliminary iso regex - // 0000-00-00 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 - isoRegex = /^\s*\d{4}-\d\d-\d\d((T| )(\d\d(:\d\d(:\d\d(\.\d\d?\d?)?)?)?)?([\+\-]\d\d:?\d\d)?)?/, - isoFormat = 'YYYY-MM-DDTHH:mm:ssZ', - - // iso time formats and regexes - isoTimes = [ - ['HH:mm:ss.S', /(T| )\d\d:\d\d:\d\d\.\d{1,3}/], - ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/], - ['HH:mm', /(T| )\d\d:\d\d/], - ['HH', /(T| )\d\d/] - ], - - // timezone chunker "+10:00" > ["10", "00"] or "-1530" > ["-15", "30"] - parseTimezoneChunker = /([\+\-]|\d\d)/gi, - - // getter and setter names - proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'), - unitMillisecondFactors = { - 'Milliseconds' : 1, - 'Seconds' : 1e3, - 'Minutes' : 6e4, - 'Hours' : 36e5, - 'Days' : 864e5, - 'Months' : 2592e6, - 'Years' : 31536e6 - }, - - unitAliases = { - ms : 'millisecond', - s : 'second', - m : 'minute', - h : 'hour', - d : 'day', - w : 'week', - W : 'isoweek', - M : 'month', - y : 'year' - }, - - // format function strings - formatFunctions = {}, - - // tokens to ordinalize and pad - ordinalizeTokens = 'DDD w W M D d'.split(' '), - paddedTokens = 'M D H h m s w W'.split(' '), - - formatTokenFunctions = { - M : function () { - return this.month() + 1; - }, - MMM : function (format) { - return this.lang().monthsShort(this, format); - }, - MMMM : function (format) { - return this.lang().months(this, format); - }, - D : function () { - return this.date(); - }, - DDD : function () { - return this.dayOfYear(); - }, - d : function () { - return this.day(); - }, - dd : function (format) { - return this.lang().weekdaysMin(this, format); - }, - ddd : function (format) { - return this.lang().weekdaysShort(this, format); - }, - dddd : function (format) { - return this.lang().weekdays(this, format); - }, - w : function () { - return this.week(); - }, - W : function () { - return this.isoWeek(); - }, - YY : function () { - return leftZeroFill(this.year() % 100, 2); - }, - YYYY : function () { - return leftZeroFill(this.year(), 4); - }, - YYYYY : function () { - return leftZeroFill(this.year(), 5); - }, - gg : function () { - return leftZeroFill(this.weekYear() % 100, 2); - }, - gggg : function () { - return this.weekYear(); - }, - ggggg : function () { - return leftZeroFill(this.weekYear(), 5); - }, - GG : function () { - return leftZeroFill(this.isoWeekYear() % 100, 2); - }, - GGGG : function () { - return this.isoWeekYear(); - }, - GGGGG : function () { - return leftZeroFill(this.isoWeekYear(), 5); - }, - e : function () { - return this.weekday(); - }, - E : function () { - return this.isoWeekday(); - }, - a : function () { - return this.lang().meridiem(this.hours(), this.minutes(), true); - }, - A : function () { - return this.lang().meridiem(this.hours(), this.minutes(), false); - }, - H : function () { - return this.hours(); - }, - h : function () { - return this.hours() % 12 || 12; - }, - m : function () { - return this.minutes(); - }, - s : function () { - return this.seconds(); - }, - S : function () { - return ~~(this.milliseconds() / 100); - }, - SS : function () { - return leftZeroFill(~~(this.milliseconds() / 10), 2); - }, - SSS : function () { - return leftZeroFill(this.milliseconds(), 3); - }, - Z : function () { - var a = -this.zone(), - b = "+"; - if (a < 0) { - a = -a; - b = "-"; - } - return b + leftZeroFill(~~(a / 60), 2) + ":" + leftZeroFill(~~a % 60, 2); - }, - ZZ : function () { - var a = -this.zone(), - b = "+"; - if (a < 0) { - a = -a; - b = "-"; - } - return b + leftZeroFill(~~(10 * a / 6), 4); - }, - z : function () { - return this.zoneAbbr(); - }, - zz : function () { - return this.zoneName(); - }, - X : function () { - return this.unix(); - } - }; - - function padToken(func, count) { - return function (a) { - return leftZeroFill(func.call(this, a), count); - }; - } - function ordinalizeToken(func, period) { - return function (a) { - return this.lang().ordinal(func.call(this, a), period); - }; - } - - while (ordinalizeTokens.length) { - i = ordinalizeTokens.pop(); - formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i); - } - while (paddedTokens.length) { - i = paddedTokens.pop(); - formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2); - } - formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3); - - - /************************************ - Constructors - ************************************/ - - function Language() { - - } - - // Moment prototype object - function Moment(config) { - extend(this, config); - } - - // Duration Constructor - function Duration(duration) { - var years = duration.years || duration.year || duration.y || 0, - months = duration.months || duration.month || duration.M || 0, - weeks = duration.weeks || duration.week || duration.w || 0, - days = duration.days || duration.day || duration.d || 0, - hours = duration.hours || duration.hour || duration.h || 0, - minutes = duration.minutes || duration.minute || duration.m || 0, - seconds = duration.seconds || duration.second || duration.s || 0, - milliseconds = duration.milliseconds || duration.millisecond || duration.ms || 0; - - // store reference to input for deterministic cloning - this._input = duration; - - // representation for dateAddRemove - this._milliseconds = +milliseconds + - seconds * 1e3 + // 1000 - minutes * 6e4 + // 1000 * 60 - hours * 36e5; // 1000 * 60 * 60 - // Because of dateAddRemove treats 24 hours as different from a - // day when working around DST, we need to store them separately - this._days = +days + - weeks * 7; - // It is impossible translate months into days without knowing - // which months you are are talking about, so we have to store - // it separately. - this._months = +months + - years * 12; - - this._data = {}; - - this._bubble(); - } - - - /************************************ - Helpers - ************************************/ - - - function extend(a, b) { - for (var i in b) { - if (b.hasOwnProperty(i)) { - a[i] = b[i]; - } - } - return a; - } - - function absRound(number) { - if (number < 0) { - return Math.ceil(number); - } else { - return Math.floor(number); - } - } - - // left zero fill a number - // see http://jsperf.com/left-zero-filling for performance comparison - function leftZeroFill(number, targetLength) { - var output = number + ''; - while (output.length < targetLength) { - output = '0' + output; - } - return output; - } - - // helper function for _.addTime and _.subtractTime - function addOrSubtractDurationFromMoment(mom, duration, isAdding, ignoreUpdateOffset) { - var milliseconds = duration._milliseconds, - days = duration._days, - months = duration._months, - minutes, - hours; - - if (milliseconds) { - mom._d.setTime(+mom._d + milliseconds * isAdding); - } - // store the minutes and hours so we can restore them - if (days || months) { - minutes = mom.minute(); - hours = mom.hour(); - } - if (days) { - mom.date(mom.date() + days * isAdding); - } - if (months) { - mom.month(mom.month() + months * isAdding); - } - if (milliseconds && !ignoreUpdateOffset) { - moment.updateOffset(mom); - } - // restore the minutes and hours after possibly changing dst - if (days || months) { - mom.minute(minutes); - mom.hour(hours); - } - } - - // check if is an array - function isArray(input) { - return Object.prototype.toString.call(input) === '[object Array]'; - } - - // compare two arrays, return the number of differences - function compareArrays(array1, array2) { - var len = Math.min(array1.length, array2.length), - lengthDiff = Math.abs(array1.length - array2.length), - diffs = 0, - i; - for (i = 0; i < len; i++) { - if (~~array1[i] !== ~~array2[i]) { - diffs++; - } - } - return diffs + lengthDiff; - } - - function normalizeUnits(units) { - return units ? unitAliases[units] || units.toLowerCase().replace(/(.)s$/, '$1') : units; - } - - - /************************************ - Languages - ************************************/ - - - extend(Language.prototype, { - - set : function (config) { - var prop, i; - for (i in config) { - prop = config[i]; - if (typeof prop === 'function') { - this[i] = prop; - } else { - this['_' + i] = prop; - } - } - }, - - _months : "January_February_March_April_May_June_July_August_September_October_November_December".split("_"), - months : function (m) { - return this._months[m.month()]; - }, - - _monthsShort : "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"), - monthsShort : function (m) { - return this._monthsShort[m.month()]; - }, - - monthsParse : function (monthName) { - var i, mom, regex; - - if (!this._monthsParse) { - this._monthsParse = []; - } - - for (i = 0; i < 12; i++) { - // make the regex if we don't have it already - if (!this._monthsParse[i]) { - mom = moment.utc([2000, i]); - regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); - this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); - } - // test the regex - if (this._monthsParse[i].test(monthName)) { - return i; - } - } - }, - - _weekdays : "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), - weekdays : function (m) { - return this._weekdays[m.day()]; - }, - - _weekdaysShort : "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"), - weekdaysShort : function (m) { - return this._weekdaysShort[m.day()]; - }, - - _weekdaysMin : "Su_Mo_Tu_We_Th_Fr_Sa".split("_"), - weekdaysMin : function (m) { - return this._weekdaysMin[m.day()]; - }, - - weekdaysParse : function (weekdayName) { - var i, mom, regex; - - if (!this._weekdaysParse) { - this._weekdaysParse = []; - } - - for (i = 0; i < 7; i++) { - // make the regex if we don't have it already - if (!this._weekdaysParse[i]) { - mom = moment([2000, 1]).day(i); - regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); - this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); - } - // test the regex - if (this._weekdaysParse[i].test(weekdayName)) { - return i; - } - } - }, - - _longDateFormat : { - LT : "h:mm A", - L : "MM/DD/YYYY", - LL : "MMMM D YYYY", - LLL : "MMMM D YYYY LT", - LLLL : "dddd, MMMM D YYYY LT" - }, - longDateFormat : function (key) { - var output = this._longDateFormat[key]; - if (!output && this._longDateFormat[key.toUpperCase()]) { - output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) { - return val.slice(1); - }); - this._longDateFormat[key] = output; - } - return output; - }, - - isPM : function (input) { - // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays - // Using charAt should be more compatible. - return ((input + '').toLowerCase().charAt(0) === 'p'); - }, - - _meridiemParse : /[ap]\.?m?\.?/i, - meridiem : function (hours, minutes, isLower) { - if (hours > 11) { - return isLower ? 'pm' : 'PM'; - } else { - return isLower ? 'am' : 'AM'; - } - }, - - _calendar : { - sameDay : '[Today at] LT', - nextDay : '[Tomorrow at] LT', - nextWeek : 'dddd [at] LT', - lastDay : '[Yesterday at] LT', - lastWeek : '[Last] dddd [at] LT', - sameElse : 'L' - }, - calendar : function (key, mom) { - var output = this._calendar[key]; - return typeof output === 'function' ? output.apply(mom) : output; - }, - - _relativeTime : { - future : "in %s", - past : "%s ago", - s : "a few seconds", - m : "a minute", - mm : "%d minutes", - h : "an hour", - hh : "%d hours", - d : "a day", - dd : "%d days", - M : "a month", - MM : "%d months", - y : "a year", - yy : "%d years" - }, - relativeTime : function (number, withoutSuffix, string, isFuture) { - var output = this._relativeTime[string]; - return (typeof output === 'function') ? - output(number, withoutSuffix, string, isFuture) : - output.replace(/%d/i, number); - }, - pastFuture : function (diff, output) { - var format = this._relativeTime[diff > 0 ? 'future' : 'past']; - return typeof format === 'function' ? format(output) : format.replace(/%s/i, output); - }, - - ordinal : function (number) { - return this._ordinal.replace("%d", number); - }, - _ordinal : "%d", - - preparse : function (string) { - return string; - }, - - postformat : function (string) { - return string; - }, - - week : function (mom) { - return weekOfYear(mom, this._week.dow, this._week.doy).week; - }, - _week : { - dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. - } - }); - - // Loads a language definition into the `languages` cache. The function - // takes a key and optionally values. If not in the browser and no values - // are provided, it will load the language file module. As a convenience, - // this function also returns the language values. - function loadLang(key, values) { - values.abbr = key; - if (!languages[key]) { - languages[key] = new Language(); - } - languages[key].set(values); - return languages[key]; - } - - // Remove a language from the `languages` cache. Mostly useful in tests. - function unloadLang(key) { - delete languages[key]; - } - - // Determines which language definition to use and returns it. - // - // With no parameters, it will return the global language. If you - // pass in a language key, such as 'en', it will return the - // definition for 'en', so long as 'en' has already been loaded using - // moment.lang. - function getLangDefinition(key) { - if (!key) { - return moment.fn._lang; - } - if (!languages[key] && hasModule) { - try { - require('./lang/' + key); - } catch (e) { - // call with no params to set to default - return moment.fn._lang; - } - } - return languages[key] || moment.fn._lang; - } - - - /************************************ - Formatting - ************************************/ - - - function removeFormattingTokens(input) { - if (input.match(/\[.*\]/)) { - return input.replace(/^\[|\]$/g, ""); - } - return input.replace(/\\/g, ""); - } - - function makeFormatFunction(format) { - var array = format.match(formattingTokens), i, length; - - for (i = 0, length = array.length; i < length; i++) { - if (formatTokenFunctions[array[i]]) { - array[i] = formatTokenFunctions[array[i]]; - } else { - array[i] = removeFormattingTokens(array[i]); - } - } - - return function (mom) { - var output = ""; - for (i = 0; i < length; i++) { - output += array[i] instanceof Function ? array[i].call(mom, format) : array[i]; - } - return output; - }; - } - - // format date using native date object - function formatMoment(m, format) { - - format = expandFormat(format, m.lang()); - - if (!formatFunctions[format]) { - formatFunctions[format] = makeFormatFunction(format); - } - - return formatFunctions[format](m); - } - - function expandFormat(format, lang) { - var i = 5; - - function replaceLongDateFormatTokens(input) { - return lang.longDateFormat(input) || input; - } - - while (i-- && (localFormattingTokens.lastIndex = 0, - localFormattingTokens.test(format))) { - format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); - } - - return format; - } - - - /************************************ - Parsing - ************************************/ - - - // get the regex to find the next token - function getParseRegexForToken(token, config) { - switch (token) { - case 'DDDD': - return parseTokenThreeDigits; - case 'YYYY': - return parseTokenFourDigits; - case 'YYYYY': - return parseTokenSixDigits; - case 'S': - case 'SS': - case 'SSS': - case 'DDD': - return parseTokenOneToThreeDigits; - case 'MMM': - case 'MMMM': - case 'dd': - case 'ddd': - case 'dddd': - return parseTokenWord; - case 'a': - case 'A': - return getLangDefinition(config._l)._meridiemParse; - case 'X': - return parseTokenTimestampMs; - case 'Z': - case 'ZZ': - return parseTokenTimezone; - case 'T': - return parseTokenT; - case 'MM': - case 'DD': - case 'YY': - case 'HH': - case 'hh': - case 'mm': - case 'ss': - case 'M': - case 'D': - case 'd': - case 'H': - case 'h': - case 'm': - case 's': - return parseTokenOneOrTwoDigits; - default : - return new RegExp(token.replace('\\', '')); - } - } - - function timezoneMinutesFromString(string) { - var tzchunk = (parseTokenTimezone.exec(string) || [])[0], - parts = (tzchunk + '').match(parseTimezoneChunker) || ['-', 0, 0], - minutes = +(parts[1] * 60) + ~~parts[2]; - - return parts[0] === '+' ? -minutes : minutes; - } - - // function to convert string input to date - function addTimeToArrayFromToken(token, input, config) { - var a, datePartArray = config._a; - - switch (token) { - // MONTH - case 'M' : // fall through to MM - case 'MM' : - if (input != null) { - datePartArray[1] = ~~input - 1; - } - break; - case 'MMM' : // fall through to MMMM - case 'MMMM' : - a = getLangDefinition(config._l).monthsParse(input); - // if we didn't find a month name, mark the date as invalid. - if (a != null) { - datePartArray[1] = a; - } else { - config._isValid = false; - } - break; - // DAY OF MONTH - case 'D' : // fall through to DD - case 'DD' : - if (input != null) { - datePartArray[2] = ~~input; - } - break; - // DAY OF YEAR - case 'DDD' : // fall through to DDDD - case 'DDDD' : - if (input != null) { - datePartArray[1] = 0; - datePartArray[2] = ~~input; - } - break; - // YEAR - case 'YY' : - datePartArray[0] = ~~input + (~~input > 68 ? 1900 : 2000); - break; - case 'YYYY' : - case 'YYYYY' : - datePartArray[0] = ~~input; - break; - // AM / PM - case 'a' : // fall through to A - case 'A' : - config._isPm = getLangDefinition(config._l).isPM(input); - break; - // 24 HOUR - case 'H' : // fall through to hh - case 'HH' : // fall through to hh - case 'h' : // fall through to hh - case 'hh' : - datePartArray[3] = ~~input; - break; - // MINUTE - case 'm' : // fall through to mm - case 'mm' : - datePartArray[4] = ~~input; - break; - // SECOND - case 's' : // fall through to ss - case 'ss' : - datePartArray[5] = ~~input; - break; - // MILLISECOND - case 'S' : - case 'SS' : - case 'SSS' : - datePartArray[6] = ~~ (('0.' + input) * 1000); - break; - // UNIX TIMESTAMP WITH MS - case 'X': - config._d = new Date(parseFloat(input) * 1000); - break; - // TIMEZONE - case 'Z' : // fall through to ZZ - case 'ZZ' : - config._useUTC = true; - config._tzm = timezoneMinutesFromString(input); - break; - } - - // if the input is null, the date is not valid - if (input == null) { - config._isValid = false; - } - } - - // convert an array to a date. - // the array should mirror the parameters below - // note: all values past the year are optional and will default to the lowest possible value. - // [year, month, day , hour, minute, second, millisecond] - function dateFromArray(config) { - var i, date, input = [], currentDate; - - if (config._d) { - return; - } - - // Default to current date. - // * if no year, month, day of month are given, default to today - // * if day of month is given, default month and year - // * if month is given, default only year - // * if year is given, don't default anything - currentDate = currentDateArray(config); - for (i = 0; i < 3 && config._a[i] == null; ++i) { - config._a[i] = input[i] = currentDate[i]; - } - - // Zero out whatever was not defaulted, including time - for (; i < 7; i++) { - config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; - } - - // add the offsets to the time to be parsed so that we can have a clean array for checking isValid - input[3] += ~~((config._tzm || 0) / 60); - input[4] += ~~((config._tzm || 0) % 60); - - date = new Date(0); - - if (config._useUTC) { - date.setUTCFullYear(input[0], input[1], input[2]); - date.setUTCHours(input[3], input[4], input[5], input[6]); - } else { - date.setFullYear(input[0], input[1], input[2]); - date.setHours(input[3], input[4], input[5], input[6]); - } - - config._d = date; - } - - function dateFromObject(config) { - var o = config._i; - - if (config._d) { - return; - } - - config._a = [ - o.years || o.year || o.y, - o.months || o.month || o.M, - o.days || o.day || o.d, - o.hours || o.hour || o.h, - o.minutes || o.minute || o.m, - o.seconds || o.second || o.s, - o.milliseconds || o.millisecond || o.ms - ]; - - dateFromArray(config); - } - - function currentDateArray(config) { - var now = new Date(); - if (config._useUTC) { - return [ - now.getUTCFullYear(), - now.getUTCMonth(), - now.getUTCDate() - ]; - } else { - return [now.getFullYear(), now.getMonth(), now.getDate()]; - } - } - - // date from string and format string - function makeDateFromStringAndFormat(config) { - // This array is used to make a Date, either with `new Date` or `Date.UTC` - var lang = getLangDefinition(config._l), - string = '' + config._i, - i, parsedInput, tokens; - - tokens = expandFormat(config._f, lang).match(formattingTokens); - - config._a = []; - - for (i = 0; i < tokens.length; i++) { - parsedInput = (getParseRegexForToken(tokens[i], config).exec(string) || [])[0]; - if (parsedInput) { - string = string.slice(string.indexOf(parsedInput) + parsedInput.length); - } - // don't parse if its not a known token - if (formatTokenFunctions[tokens[i]]) { - addTimeToArrayFromToken(tokens[i], parsedInput, config); - } - } - - // add remaining unparsed input to the string - if (string) { - config._il = string; - } - - // handle am pm - if (config._isPm && config._a[3] < 12) { - config._a[3] += 12; - } - // if is 12 am, change hours to 0 - if (config._isPm === false && config._a[3] === 12) { - config._a[3] = 0; - } - // return - dateFromArray(config); - } - - // date from string and array of format strings - function makeDateFromStringAndArray(config) { - var tempConfig, - tempMoment, - bestMoment, - - scoreToBeat = 99, - i, - currentScore; - - for (i = 0; i < config._f.length; i++) { - tempConfig = extend({}, config); - tempConfig._f = config._f[i]; - makeDateFromStringAndFormat(tempConfig); - tempMoment = new Moment(tempConfig); - - currentScore = compareArrays(tempConfig._a, tempMoment.toArray()); - - // if there is any input that was not parsed - // add a penalty for that format - if (tempMoment._il) { - currentScore += tempMoment._il.length; - } - - if (currentScore < scoreToBeat) { - scoreToBeat = currentScore; - bestMoment = tempMoment; - } - } - - extend(config, bestMoment); - } - - // date from iso format - function makeDateFromString(config) { - var i, - string = config._i, - match = isoRegex.exec(string); - - if (match) { - // match[2] should be "T" or undefined - config._f = 'YYYY-MM-DD' + (match[2] || " "); - for (i = 0; i < 4; i++) { - if (isoTimes[i][1].exec(string)) { - config._f += isoTimes[i][0]; - break; - } - } - if (parseTokenTimezone.exec(string)) { - config._f += " Z"; - } - makeDateFromStringAndFormat(config); - } else { - config._d = new Date(string); - } - } - - function makeDateFromInput(config) { - var input = config._i, - matched = aspNetJsonRegex.exec(input); - - if (input === undefined) { - config._d = new Date(); - } else if (matched) { - config._d = new Date(+matched[1]); - } else if (typeof input === 'string') { - makeDateFromString(config); - } else if (isArray(input)) { - config._a = input.slice(0); - dateFromArray(config); - } else if (input instanceof Date) { - config._d = new Date(+input); - } else if (typeof(input) === 'object') { - dateFromObject(config); - } else { - config._d = new Date(input); - } - } - - - /************************************ - Relative Time - ************************************/ - - - // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize - function substituteTimeAgo(string, number, withoutSuffix, isFuture, lang) { - return lang.relativeTime(number || 1, !!withoutSuffix, string, isFuture); - } - - function relativeTime(milliseconds, withoutSuffix, lang) { - var seconds = round(Math.abs(milliseconds) / 1000), - minutes = round(seconds / 60), - hours = round(minutes / 60), - days = round(hours / 24), - years = round(days / 365), - args = seconds < 45 && ['s', seconds] || - minutes === 1 && ['m'] || - minutes < 45 && ['mm', minutes] || - hours === 1 && ['h'] || - hours < 22 && ['hh', hours] || - days === 1 && ['d'] || - days <= 25 && ['dd', days] || - days <= 45 && ['M'] || - days < 345 && ['MM', round(days / 30)] || - years === 1 && ['y'] || ['yy', years]; - args[2] = withoutSuffix; - args[3] = milliseconds > 0; - args[4] = lang; - return substituteTimeAgo.apply({}, args); - } - - - /************************************ - Week of Year - ************************************/ - - - // firstDayOfWeek 0 = sun, 6 = sat - // the day of the week that starts the week - // (usually sunday or monday) - // firstDayOfWeekOfYear 0 = sun, 6 = sat - // the first week is the week that contains the first - // of this day of the week - // (eg. ISO weeks use thursday (4)) - function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { - var end = firstDayOfWeekOfYear - firstDayOfWeek, - daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(), - adjustedMoment; - - - if (daysToDayOfWeek > end) { - daysToDayOfWeek -= 7; - } - - if (daysToDayOfWeek < end - 7) { - daysToDayOfWeek += 7; - } - - adjustedMoment = moment(mom).add('d', daysToDayOfWeek); - return { - week: Math.ceil(adjustedMoment.dayOfYear() / 7), - year: adjustedMoment.year() - }; - } - - - /************************************ - Top Level Functions - ************************************/ - - function makeMoment(config) { - var input = config._i, - format = config._f; - - if (input === null || input === '') { - return null; - } - - if (typeof input === 'string') { - config._i = input = getLangDefinition().preparse(input); - } - - if (moment.isMoment(input)) { - config = extend({}, input); - config._d = new Date(+input._d); - } else if (format) { - if (isArray(format)) { - makeDateFromStringAndArray(config); - } else { - makeDateFromStringAndFormat(config); - } - } else { - makeDateFromInput(config); - } - - return new Moment(config); - } - - moment = function (input, format, lang) { - return makeMoment({ - _i : input, - _f : format, - _l : lang, - _isUTC : false - }); - }; - - // creating with utc - moment.utc = function (input, format, lang) { - return makeMoment({ - _useUTC : true, - _isUTC : true, - _l : lang, - _i : input, - _f : format - }).utc(); - }; - - // creating with unix timestamp (in seconds) - moment.unix = function (input) { - return moment(input * 1000); - }; - - // duration - moment.duration = function (input, key) { - var isDuration = moment.isDuration(input), - isNumber = (typeof input === 'number'), - duration = (isDuration ? input._input : (isNumber ? {} : input)), - matched = aspNetTimeSpanJsonRegex.exec(input), - sign, - ret; - - if (isNumber) { - if (key) { - duration[key] = input; - } else { - duration.milliseconds = input; - } - } else if (matched) { - sign = (matched[1] === "-") ? -1 : 1; - duration = { - y: 0, - d: ~~matched[2] * sign, - h: ~~matched[3] * sign, - m: ~~matched[4] * sign, - s: ~~matched[5] * sign, - ms: ~~matched[6] * sign - }; - } - - ret = new Duration(duration); - - if (isDuration && input.hasOwnProperty('_lang')) { - ret._lang = input._lang; - } - - return ret; - }; - - // version number - moment.version = VERSION; - - // default format - moment.defaultFormat = isoFormat; - - // This function will be called whenever a moment is mutated. - // It is intended to keep the offset in sync with the timezone. - moment.updateOffset = function () {}; - - // This function will load languages and then set the global language. If - // no arguments are passed in, it will simply return the current global - // language key. - moment.lang = function (key, values) { - if (!key) { - return moment.fn._lang._abbr; - } - key = key.toLowerCase(); - key = key.replace('_', '-'); - if (values) { - loadLang(key, values); - } else if (values === null) { - unloadLang(key); - key = 'en'; - } else if (!languages[key]) { - getLangDefinition(key); - } - moment.duration.fn._lang = moment.fn._lang = getLangDefinition(key); - }; - - // returns language data - moment.langData = function (key) { - if (key && key._lang && key._lang._abbr) { - key = key._lang._abbr; - } - return getLangDefinition(key); - }; - - // compare moment object - moment.isMoment = function (obj) { - return obj instanceof Moment; - }; - - // for typechecking Duration objects - moment.isDuration = function (obj) { - return obj instanceof Duration; - }; - - - /************************************ - Moment Prototype - ************************************/ - - - extend(moment.fn = Moment.prototype, { - - clone : function () { - return moment(this); - }, - - valueOf : function () { - return +this._d + ((this._offset || 0) * 60000); - }, - - unix : function () { - return Math.floor(+this / 1000); - }, - - toString : function () { - return this.format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ"); - }, - - toDate : function () { - return this._offset ? new Date(+this) : this._d; - }, - - toISOString : function () { - return formatMoment(moment(this).utc(), 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); - }, - - toArray : function () { - var m = this; - return [ - m.year(), - m.month(), - m.date(), - m.hours(), - m.minutes(), - m.seconds(), - m.milliseconds() - ]; - }, - - isValid : function () { - if (this._isValid == null) { - if (this._a) { - this._isValid = !compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()); - } else { - this._isValid = !isNaN(this._d.getTime()); - } - } - return !!this._isValid; - }, - - invalidAt: function () { - var i, arr1 = this._a, arr2 = (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray(); - for (i = 6; i >= 0 && arr1[i] === arr2[i]; --i) { - // empty loop body - } - return i; - }, - - utc : function () { - return this.zone(0); - }, - - local : function () { - this.zone(0); - this._isUTC = false; - return this; - }, - - format : function (inputString) { - var output = formatMoment(this, inputString || moment.defaultFormat); - return this.lang().postformat(output); - }, - - add : function (input, val) { - var dur; - // switch args to support add('s', 1) and add(1, 's') - if (typeof input === 'string') { - dur = moment.duration(+val, input); - } else { - dur = moment.duration(input, val); - } - addOrSubtractDurationFromMoment(this, dur, 1); - return this; - }, - - subtract : function (input, val) { - var dur; - // switch args to support subtract('s', 1) and subtract(1, 's') - if (typeof input === 'string') { - dur = moment.duration(+val, input); - } else { - dur = moment.duration(input, val); - } - addOrSubtractDurationFromMoment(this, dur, -1); - return this; - }, - - diff : function (input, units, asFloat) { - var that = this._isUTC ? moment(input).zone(this._offset || 0) : moment(input).local(), - zoneDiff = (this.zone() - that.zone()) * 6e4, - diff, output; - - units = normalizeUnits(units); - - if (units === 'year' || units === 'month') { - // average number of days in the months in the given dates - diff = (this.daysInMonth() + that.daysInMonth()) * 432e5; // 24 * 60 * 60 * 1000 / 2 - // difference in months - output = ((this.year() - that.year()) * 12) + (this.month() - that.month()); - // adjust by taking difference in days, average number of days - // and dst in the given months. - output += ((this - moment(this).startOf('month')) - - (that - moment(that).startOf('month'))) / diff; - // same as above but with zones, to negate all dst - output -= ((this.zone() - moment(this).startOf('month').zone()) - - (that.zone() - moment(that).startOf('month').zone())) * 6e4 / diff; - if (units === 'year') { - output = output / 12; - } - } else { - diff = (this - that); - output = units === 'second' ? diff / 1e3 : // 1000 - units === 'minute' ? diff / 6e4 : // 1000 * 60 - units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60 - units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst - units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst - diff; - } - return asFloat ? output : absRound(output); - }, - - from : function (time, withoutSuffix) { - return moment.duration(this.diff(time)).lang(this.lang()._abbr).humanize(!withoutSuffix); - }, - - fromNow : function (withoutSuffix) { - return this.from(moment(), withoutSuffix); - }, - - calendar : function () { - var diff = this.diff(moment().zone(this.zone()).startOf('day'), 'days', true), - format = diff < -6 ? 'sameElse' : - diff < -1 ? 'lastWeek' : - diff < 0 ? 'lastDay' : - diff < 1 ? 'sameDay' : - diff < 2 ? 'nextDay' : - diff < 7 ? 'nextWeek' : 'sameElse'; - return this.format(this.lang().calendar(format, this)); - }, - - isLeapYear : function () { - var year = this.year(); - return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; - }, - - isDST : function () { - return (this.zone() < this.clone().month(0).zone() || - this.zone() < this.clone().month(5).zone()); - }, - - day : function (input) { - var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); - if (input != null) { - if (typeof input === 'string') { - input = this.lang().weekdaysParse(input); - if (typeof input !== 'number') { - return this; - } - } - return this.add({ d : input - day }); - } else { - return day; - } - }, - - month : function (input) { - var utc = this._isUTC ? 'UTC' : '', - dayOfMonth; - - if (input != null) { - if (typeof input === 'string') { - input = this.lang().monthsParse(input); - if (typeof input !== 'number') { - return this; - } - } - - dayOfMonth = this.date(); - this.date(1); - this._d['set' + utc + 'Month'](input); - this.date(Math.min(dayOfMonth, this.daysInMonth())); - - moment.updateOffset(this); - return this; - } else { - return this._d['get' + utc + 'Month'](); - } - }, - - startOf: function (units) { - units = normalizeUnits(units); - // the following switch intentionally omits break keywords - // to utilize falling through the cases. - switch (units) { - case 'year': - this.month(0); - /* falls through */ - case 'month': - this.date(1); - /* falls through */ - case 'week': - case 'isoweek': - case 'day': - this.hours(0); - /* falls through */ - case 'hour': - this.minutes(0); - /* falls through */ - case 'minute': - this.seconds(0); - /* falls through */ - case 'second': - this.milliseconds(0); - /* falls through */ - } - - // weeks are a special case - if (units === 'week') { - this.weekday(0); - } else if (units === 'isoweek') { - this.isoWeekday(1); - } - - return this; - }, - - endOf: function (units) { - units = normalizeUnits(units); - return this.startOf(units).add((units === 'isoweek' ? 'week' : units), 1).subtract('ms', 1); - }, - - isAfter: function (input, units) { - units = typeof units !== 'undefined' ? units : 'millisecond'; - return +this.clone().startOf(units) > +moment(input).startOf(units); - }, - - isBefore: function (input, units) { - units = typeof units !== 'undefined' ? units : 'millisecond'; - return +this.clone().startOf(units) < +moment(input).startOf(units); - }, - - isSame: function (input, units) { - units = typeof units !== 'undefined' ? units : 'millisecond'; - return +this.clone().startOf(units) === +moment(input).startOf(units); - }, - - min: function (other) { - other = moment.apply(null, arguments); - return other < this ? this : other; - }, - - max: function (other) { - other = moment.apply(null, arguments); - return other > this ? this : other; - }, - - zone : function (input) { - var offset = this._offset || 0; - if (input != null) { - if (typeof input === "string") { - input = timezoneMinutesFromString(input); - } - if (Math.abs(input) < 16) { - input = input * 60; - } - this._offset = input; - this._isUTC = true; - if (offset !== input) { - addOrSubtractDurationFromMoment(this, moment.duration(offset - input, 'm'), 1, true); - } - } else { - return this._isUTC ? offset : this._d.getTimezoneOffset(); - } - return this; - }, - - zoneAbbr : function () { - return this._isUTC ? "UTC" : ""; - }, - - zoneName : function () { - return this._isUTC ? "Coordinated Universal Time" : ""; - }, - - hasAlignedHourOffset : function (input) { - if (!input) { - input = 0; - } - else { - input = moment(input).zone(); - } - - return (this.zone() - input) % 60 === 0; - }, - - daysInMonth : function () { - return moment.utc([this.year(), this.month() + 1, 0]).date(); - }, - - dayOfYear : function (input) { - var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1; - return input == null ? dayOfYear : this.add("d", (input - dayOfYear)); - }, - - weekYear : function (input) { - var year = weekOfYear(this, this.lang()._week.dow, this.lang()._week.doy).year; - return input == null ? year : this.add("y", (input - year)); - }, - - isoWeekYear : function (input) { - var year = weekOfYear(this, 1, 4).year; - return input == null ? year : this.add("y", (input - year)); - }, - - week : function (input) { - var week = this.lang().week(this); - return input == null ? week : this.add("d", (input - week) * 7); - }, - - isoWeek : function (input) { - var week = weekOfYear(this, 1, 4).week; - return input == null ? week : this.add("d", (input - week) * 7); - }, - - weekday : function (input) { - var weekday = (this._d.getDay() + 7 - this.lang()._week.dow) % 7; - return input == null ? weekday : this.add("d", input - weekday); - }, - - isoWeekday : function (input) { - // behaves the same as moment#day except - // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) - // as a setter, sunday should belong to the previous week. - return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7); - }, - - get : function (units) { - units = normalizeUnits(units); - return this[units.toLowerCase()](); - }, - - set : function (units, value) { - units = normalizeUnits(units); - this[units.toLowerCase()](value); - }, - - // If passed a language key, it will set the language for this - // instance. Otherwise, it will return the language configuration - // variables for this instance. - lang : function (key) { - if (key === undefined) { - return this._lang; - } else { - this._lang = getLangDefinition(key); - return this; - } - } - }); - - // helper for adding shortcuts - function makeGetterAndSetter(name, key) { - moment.fn[name] = moment.fn[name + 's'] = function (input) { - var utc = this._isUTC ? 'UTC' : ''; - if (input != null) { - this._d['set' + utc + key](input); - moment.updateOffset(this); - return this; - } else { - return this._d['get' + utc + key](); - } - }; - } - - // loop through and add shortcuts (Month, Date, Hours, Minutes, Seconds, Milliseconds) - for (i = 0; i < proxyGettersAndSetters.length; i ++) { - makeGetterAndSetter(proxyGettersAndSetters[i].toLowerCase().replace(/s$/, ''), proxyGettersAndSetters[i]); - } - - // add shortcut for year (uses different syntax than the getter/setter 'year' == 'FullYear') - makeGetterAndSetter('year', 'FullYear'); - - // add plural methods - moment.fn.days = moment.fn.day; - moment.fn.months = moment.fn.month; - moment.fn.weeks = moment.fn.week; - moment.fn.isoWeeks = moment.fn.isoWeek; - - // add aliased format methods - moment.fn.toJSON = moment.fn.toISOString; - - /************************************ - Duration Prototype - ************************************/ - - - extend(moment.duration.fn = Duration.prototype, { - - _bubble : function () { - var milliseconds = this._milliseconds, - days = this._days, - months = this._months, - data = this._data, - seconds, minutes, hours, years; - - // The following code bubbles up values, see the tests for - // examples of what that means. - data.milliseconds = milliseconds % 1000; - - seconds = absRound(milliseconds / 1000); - data.seconds = seconds % 60; - - minutes = absRound(seconds / 60); - data.minutes = minutes % 60; - - hours = absRound(minutes / 60); - data.hours = hours % 24; - - days += absRound(hours / 24); - data.days = days % 30; - - months += absRound(days / 30); - data.months = months % 12; - - years = absRound(months / 12); - data.years = years; - }, - - weeks : function () { - return absRound(this.days() / 7); - }, - - valueOf : function () { - return this._milliseconds + - this._days * 864e5 + - (this._months % 12) * 2592e6 + - ~~(this._months / 12) * 31536e6; - }, - - humanize : function (withSuffix) { - var difference = +this, - output = relativeTime(difference, !withSuffix, this.lang()); - - if (withSuffix) { - output = this.lang().pastFuture(difference, output); - } - - return this.lang().postformat(output); - }, - - add : function (input, val) { - // supports only 2.0-style add(1, 's') or add(moment) - var dur = moment.duration(input, val); - - this._milliseconds += dur._milliseconds; - this._days += dur._days; - this._months += dur._months; - - this._bubble(); - - return this; - }, - - subtract : function (input, val) { - var dur = moment.duration(input, val); - - this._milliseconds -= dur._milliseconds; - this._days -= dur._days; - this._months -= dur._months; - - this._bubble(); - - return this; - }, - - get : function (units) { - units = normalizeUnits(units); - return this[units.toLowerCase() + 's'](); - }, - - as : function (units) { - units = normalizeUnits(units); - return this['as' + units.charAt(0).toUpperCase() + units.slice(1) + 's'](); - }, - - lang : moment.fn.lang - }); - - function makeDurationGetter(name) { - moment.duration.fn[name] = function () { - return this._data[name]; - }; - } - - function makeDurationAsGetter(name, factor) { - moment.duration.fn['as' + name] = function () { - return +this / factor; - }; - } - - for (i in unitMillisecondFactors) { - if (unitMillisecondFactors.hasOwnProperty(i)) { - makeDurationAsGetter(i, unitMillisecondFactors[i]); - makeDurationGetter(i.toLowerCase()); - } - } - - makeDurationAsGetter('Weeks', 6048e5); - moment.duration.fn.asMonths = function () { - return (+this - this.years() * 31536e6) / 2592e6 + this.years() * 12; - }; - - - /************************************ - Default Lang - ************************************/ - - - // Set default language, other languages will inherit from English. - moment.lang('en', { - ordinal : function (number) { - var b = number % 10, - output = (~~ (number % 100 / 10) === 1) ? 'th' : - (b === 1) ? 'st' : - (b === 2) ? 'nd' : - (b === 3) ? 'rd' : 'th'; - return number + output; - } - }); - - /* EMBED_LANGUAGES */ - - /************************************ - Exposing Moment - ************************************/ - - - // CommonJS module is defined - if (hasModule) { - module.exports = moment; - } - /*global ender:false */ - if (typeof ender === 'undefined') { - // here, `this` means `window` in the browser, or `global` on the server - // add `moment` as a global object via a string identifier, - // for Closure Compiler "advanced" mode - this['moment'] = moment; - } - /*global define:false */ - if (typeof define === "function" && define.amd) { - define("moment", [], function () { - return moment; - }); - } -}).call(this); - -},{}],3:[function(require,module,exports){ -/** - * vis.js module imports - */ - -// Try to load dependencies from the global window object. -// If not available there, load via require. -var moment = (typeof window !== 'undefined') && window['moment'] || require('moment'); -var Hammer = (typeof window !== 'undefined') && window['Hammer'] || require('hammerjs'); - - -// Internet Explorer 8 and older does not support Array.indexOf, so we define -// it here in that case. -// http://soledadpenades.com/2007/05/17/arrayindexof-in-internet-explorer/ -if(!Array.prototype.indexOf) { - Array.prototype.indexOf = function(obj){ - for(var i = 0; i < this.length; i++){ - if(this[i] == obj){ - return i; - } - } - return -1; - }; - - try { - console.log("Warning: Ancient browser detected. Please update your browser"); - } - catch (err) { - } -} - -// Internet Explorer 8 and older does not support Array.forEach, so we define -// it here in that case. -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach -if (!Array.prototype.forEach) { - Array.prototype.forEach = function(fn, scope) { - for(var i = 0, len = this.length; i < len; ++i) { - fn.call(scope || this, this[i], i, this); - } - } -} - -// Internet Explorer 8 and older does not support Array.map, so we define it -// here in that case. -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/map -// Production steps of ECMA-262, Edition 5, 15.4.4.19 -// Reference: http://es5.github.com/#x15.4.4.19 -if (!Array.prototype.map) { - Array.prototype.map = function(callback, thisArg) { - - var T, A, k; - - if (this == null) { - throw new TypeError(" this is null or not defined"); - } - - // 1. Let O be the result of calling ToObject passing the |this| value as the argument. - var O = Object(this); - - // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length". - // 3. Let len be ToUint32(lenValue). - var len = O.length >>> 0; - - // 4. If IsCallable(callback) is false, throw a TypeError exception. - // See: http://es5.github.com/#x9.11 - if (typeof callback !== "function") { - throw new TypeError(callback + " is not a function"); - } - - // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. - if (thisArg) { - T = thisArg; - } - - // 6. Let A be a new array created as if by the expression new Array(len) where Array is - // the standard built-in constructor with that name and len is the value of len. - A = new Array(len); - - // 7. Let k be 0 - k = 0; - - // 8. Repeat, while k < len - while(k < len) { - - var kValue, mappedValue; - - // a. Let Pk be ToString(k). - // This is implicit for LHS operands of the in operator - // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk. - // This step can be combined with c - // c. If kPresent is true, then - if (k in O) { - - // i. Let kValue be the result of calling the Get internal method of O with argument Pk. - kValue = O[ k ]; - - // ii. Let mappedValue be the result of calling the Call internal method of callback - // with T as the this value and argument list containing kValue, k, and O. - mappedValue = callback.call(T, kValue, k, O); - - // iii. Call the DefineOwnProperty internal method of A with arguments - // Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true}, - // and false. - - // In browsers that support Object.defineProperty, use the following: - // Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true }); - - // For best browser support, use the following: - A[ k ] = mappedValue; - } - // d. Increase k by 1. - k++; - } - - // 9. return A - return A; - }; -} - -// Internet Explorer 8 and older does not support Array.filter, so we define it -// here in that case. -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/filter -if (!Array.prototype.filter) { - Array.prototype.filter = function(fun /*, thisp */) { - "use strict"; - - if (this == null) { - throw new TypeError(); - } - - var t = Object(this); - var len = t.length >>> 0; - if (typeof fun != "function") { - throw new TypeError(); - } - - var res = []; - var thisp = arguments[1]; - for (var i = 0; i < len; i++) { - if (i in t) { - var val = t[i]; // in case fun mutates this - if (fun.call(thisp, val, i, t)) - res.push(val); - } - } - - return res; - }; -} - - -// Internet Explorer 8 and older does not support Object.keys, so we define it -// here in that case. -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys -if (!Object.keys) { - Object.keys = (function () { - var hasOwnProperty = Object.prototype.hasOwnProperty, - hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), - dontEnums = [ - 'toString', - 'toLocaleString', - 'valueOf', - 'hasOwnProperty', - 'isPrototypeOf', - 'propertyIsEnumerable', - 'constructor' - ], - dontEnumsLength = dontEnums.length; - - return function (obj) { - if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) { - throw new TypeError('Object.keys called on non-object'); - } - - var result = []; - - for (var prop in obj) { - if (hasOwnProperty.call(obj, prop)) result.push(prop); - } - - if (hasDontEnumBug) { - for (var i=0; i < dontEnumsLength; i++) { - if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]); - } - } - return result; - } - })() -} - -// Internet Explorer 8 and older does not support Array.isArray, -// so we define it here in that case. -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/isArray -if(!Array.isArray) { - Array.isArray = function (vArg) { - return Object.prototype.toString.call(vArg) === "[object Array]"; - }; -} - -// Internet Explorer 8 and older does not support Function.bind, -// so we define it here in that case. -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind -if (!Function.prototype.bind) { - Function.prototype.bind = function (oThis) { - if (typeof this !== "function") { - // closest thing possible to the ECMAScript 5 internal IsCallable function - throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); - } - - var aArgs = Array.prototype.slice.call(arguments, 1), - fToBind = this, - fNOP = function () {}, - fBound = function () { - return fToBind.apply(this instanceof fNOP && oThis - ? this - : oThis, - aArgs.concat(Array.prototype.slice.call(arguments))); - }; - - fNOP.prototype = this.prototype; - fBound.prototype = new fNOP(); - - return fBound; - }; -} - -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create -if (!Object.create) { - Object.create = function (o) { - if (arguments.length > 1) { - throw new Error('Object.create implementation only accepts the first parameter.'); - } - function F() {} - F.prototype = o; - return new F(); - }; -} - -// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind -if (!Function.prototype.bind) { - Function.prototype.bind = function (oThis) { - if (typeof this !== "function") { - // closest thing possible to the ECMAScript 5 internal IsCallable function - throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); - } - - var aArgs = Array.prototype.slice.call(arguments, 1), - fToBind = this, - fNOP = function () {}, - fBound = function () { - return fToBind.apply(this instanceof fNOP && oThis - ? this - : oThis, - aArgs.concat(Array.prototype.slice.call(arguments))); - }; - - fNOP.prototype = this.prototype; - fBound.prototype = new fNOP(); - - return fBound; - }; -} - -/** - * utility functions - */ -var util = {}; - -/** - * Test whether given object is a number - * @param {*} object - * @return {Boolean} isNumber - */ -util.isNumber = function isNumber(object) { - return (object instanceof Number || typeof object == 'number'); -}; - -/** - * Test whether given object is a string - * @param {*} object - * @return {Boolean} isString - */ -util.isString = function isString(object) { - return (object instanceof String || typeof object == 'string'); -}; - -/** - * Test whether given object is a Date, or a String containing a Date - * @param {Date | String} object - * @return {Boolean} isDate - */ -util.isDate = function isDate(object) { - if (object instanceof Date) { - return true; - } - else if (util.isString(object)) { - // test whether this string contains a date - var match = ASPDateRegex.exec(object); - if (match) { - return true; - } - else if (!isNaN(Date.parse(object))) { - return true; - } - } - - return false; -}; - -/** - * Test whether given object is an instance of google.visualization.DataTable - * @param {*} object - * @return {Boolean} isDataTable - */ -util.isDataTable = function isDataTable(object) { - return (typeof (google) !== 'undefined') && - (google.visualization) && - (google.visualization.DataTable) && - (object instanceof google.visualization.DataTable); -}; - -/** - * Create a semi UUID - * source: http://stackoverflow.com/a/105074/1262753 - * @return {String} uuid - */ -util.randomUUID = function randomUUID () { - var S4 = function () { - return Math.floor( - Math.random() * 0x10000 /* 65536 */ - ).toString(16); - }; - - return ( - S4() + S4() + '-' + - S4() + '-' + - S4() + '-' + - S4() + '-' + - S4() + S4() + S4() - ); -}; - -/** - * Extend object a with the properties of object b or a series of objects - * Only properties with defined values are copied - * @param {Object} a - * @param {... Object} b - * @return {Object} a - */ -util.extend = function (a, b) { - for (var i = 1, len = arguments.length; i < len; i++) { - var other = arguments[i]; - for (var prop in other) { - if (other.hasOwnProperty(prop) && other[prop] !== undefined) { - a[prop] = other[prop]; - } - } - } - - return a; -}; - -/** - * Convert an object to another type - * @param {Boolean | Number | String | Date | Moment | Null | undefined} object - * @param {String | undefined} type Name of the type. Available types: - * 'Boolean', 'Number', 'String', - * 'Date', 'Moment', ISODate', 'ASPDate'. - * @return {*} object - * @throws Error - */ -util.convert = function convert(object, type) { - var match; - - if (object === undefined) { - return undefined; - } - if (object === null) { - return null; - } - - if (!type) { - return object; - } - if (!(typeof type === 'string') && !(type instanceof String)) { - throw new Error('Type must be a string'); - } - - //noinspection FallthroughInSwitchStatementJS - switch (type) { - case 'boolean': - case 'Boolean': - return Boolean(object); - - case 'number': - case 'Number': - return Number(object.valueOf()); - - case 'string': - case 'String': - return String(object); - - case 'Date': - if (util.isNumber(object)) { - return new Date(object); - } - if (object instanceof Date) { - return new Date(object.valueOf()); - } - else if (moment.isMoment(object)) { - return new Date(object.valueOf()); - } - if (util.isString(object)) { - match = ASPDateRegex.exec(object); - if (match) { - // object is an ASP date - return new Date(Number(match[1])); // parse number - } - else { - return moment(object).toDate(); // parse string - } - } - else { - throw new Error( - 'Cannot convert object of type ' + util.getType(object) + - ' to type Date'); - } - - case 'Moment': - if (util.isNumber(object)) { - return moment(object); - } - if (object instanceof Date) { - return moment(object.valueOf()); - } - else if (moment.isMoment(object)) { - return moment.clone(); - } - if (util.isString(object)) { - match = ASPDateRegex.exec(object); - if (match) { - // object is an ASP date - return moment(Number(match[1])); // parse number - } - else { - return moment(object); // parse string - } - } - else { - throw new Error( - 'Cannot convert object of type ' + util.getType(object) + - ' to type Date'); - } - - case 'ISODate': - if (util.isNumber(object)) { - return new Date(object); - } - else if (object instanceof Date) { - return object.toISOString(); - } - else if (moment.isMoment(object)) { - return object.toDate().toISOString(); - } - else if (util.isString(object)) { - match = ASPDateRegex.exec(object); - if (match) { - // object is an ASP date - return new Date(Number(match[1])).toISOString(); // parse number - } - else { - return new Date(object).toISOString(); // parse string - } - } - else { - throw new Error( - 'Cannot convert object of type ' + util.getType(object) + - ' to type ISODate'); - } - - case 'ASPDate': - if (util.isNumber(object)) { - return '/Date(' + object + ')/'; - } - else if (object instanceof Date) { - return '/Date(' + object.valueOf() + ')/'; - } - else if (util.isString(object)) { - match = ASPDateRegex.exec(object); - var value; - if (match) { - // object is an ASP date - value = new Date(Number(match[1])).valueOf(); // parse number - } - else { - value = new Date(object).valueOf(); // parse string - } - return '/Date(' + value + ')/'; - } - else { - throw new Error( - 'Cannot convert object of type ' + util.getType(object) + - ' to type ASPDate'); - } - - default: - throw new Error('Cannot convert object of type ' + util.getType(object) + - ' to type "' + type + '"'); - } -}; - -// parse ASP.Net Date pattern, -// for example '/Date(1198908717056)/' or '/Date(1198908717056-0700)/' -// code from http://momentjs.com/ -var ASPDateRegex = /^\/?Date\((\-?\d+)/i; - -/** - * Get the type of an object, for example util.getType([]) returns 'Array' - * @param {*} object - * @return {String} type - */ -util.getType = function getType(object) { - var type = typeof object; - - if (type == 'object') { - if (object == null) { - return 'null'; - } - if (object instanceof Boolean) { - return 'Boolean'; - } - if (object instanceof Number) { - return 'Number'; - } - if (object instanceof String) { - return 'String'; - } - if (object instanceof Array) { - return 'Array'; - } - if (object instanceof Date) { - return 'Date'; - } - return 'Object'; - } - else if (type == 'number') { - return 'Number'; - } - else if (type == 'boolean') { - return 'Boolean'; - } - else if (type == 'string') { - return 'String'; - } - - return type; -}; - -/** - * Retrieve the absolute left value of a DOM element - * @param {Element} elem A dom element, for example a div - * @return {number} left The absolute left position of this element - * in the browser page. - */ -util.getAbsoluteLeft = function getAbsoluteLeft (elem) { - var doc = document.documentElement; - var body = document.body; - - var left = elem.offsetLeft; - var e = elem.offsetParent; - while (e != null && e != body && e != doc) { - left += e.offsetLeft; - left -= e.scrollLeft; - e = e.offsetParent; - } - return left; -}; - -/** - * Retrieve the absolute top value of a DOM element - * @param {Element} elem A dom element, for example a div - * @return {number} top The absolute top position of this element - * in the browser page. - */ -util.getAbsoluteTop = function getAbsoluteTop (elem) { - var doc = document.documentElement; - var body = document.body; - - var top = elem.offsetTop; - var e = elem.offsetParent; - while (e != null && e != body && e != doc) { - top += e.offsetTop; - top -= e.scrollTop; - e = e.offsetParent; - } - return top; -}; - -/** - * Get the absolute, vertical mouse position from an event. - * @param {Event} event - * @return {Number} pageY - */ -util.getPageY = function getPageY (event) { - if ('pageY' in event) { - return event.pageY; - } - else { - var clientY; - if (('targetTouches' in event) && event.targetTouches.length) { - clientY = event.targetTouches[0].clientY; - } - else { - clientY = event.clientY; - } - - var doc = document.documentElement; - var body = document.body; - return clientY + - ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - - ( doc && doc.clientTop || body && body.clientTop || 0 ); - } -}; - -/** - * Get the absolute, horizontal mouse position from an event. - * @param {Event} event - * @return {Number} pageX - */ -util.getPageX = function getPageX (event) { - if ('pageY' in event) { - return event.pageX; - } - else { - var clientX; - if (('targetTouches' in event) && event.targetTouches.length) { - clientX = event.targetTouches[0].clientX; - } - else { - clientX = event.clientX; - } - - var doc = document.documentElement; - var body = document.body; - return clientX + - ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); - } -}; - -/** - * add a className to the given elements style - * @param {Element} elem - * @param {String} className - */ -util.addClassName = function addClassName(elem, className) { - var classes = elem.className.split(' '); - if (classes.indexOf(className) == -1) { - classes.push(className); // add the class to the array - elem.className = classes.join(' '); - } -}; - -/** - * add a className to the given elements style - * @param {Element} elem - * @param {String} className - */ -util.removeClassName = function removeClassname(elem, className) { - var classes = elem.className.split(' '); - var index = classes.indexOf(className); - if (index != -1) { - classes.splice(index, 1); // remove the class from the array - elem.className = classes.join(' '); - } -}; - -/** - * For each method for both arrays and objects. - * In case of an array, the built-in Array.forEach() is applied. - * In case of an Object, the method loops over all properties of the object. - * @param {Object | Array} object An Object or Array - * @param {function} callback Callback method, called for each item in - * the object or array with three parameters: - * callback(value, index, object) - */ -util.forEach = function forEach (object, callback) { - var i, - len; - if (object instanceof Array) { - // array - for (i = 0, len = object.length; i < len; i++) { - callback(object[i], i, object); - } - } - else { - // object - for (i in object) { - if (object.hasOwnProperty(i)) { - callback(object[i], i, object); - } - } - } -}; - -/** - * Update a property in an object - * @param {Object} object - * @param {String} key - * @param {*} value - * @return {Boolean} changed - */ -util.updateProperty = function updateProp (object, key, value) { - if (object[key] !== value) { - object[key] = value; - return true; - } - else { - return false; - } -}; - -/** - * Add and event listener. Works for all browsers - * @param {Element} element An html element - * @param {string} action The action, for example "click", - * without the prefix "on" - * @param {function} listener The callback function to be executed - * @param {boolean} [useCapture] - */ -util.addEventListener = function addEventListener(element, action, listener, useCapture) { - if (element.addEventListener) { - if (useCapture === undefined) - useCapture = false; - - if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) { - action = "DOMMouseScroll"; // For Firefox - } - - element.addEventListener(action, listener, useCapture); - } else { - element.attachEvent("on" + action, listener); // IE browsers - } -}; - -/** - * Remove an event listener from an element - * @param {Element} element An html dom element - * @param {string} action The name of the event, for example "mousedown" - * @param {function} listener The listener function - * @param {boolean} [useCapture] - */ -util.removeEventListener = function removeEventListener(element, action, listener, useCapture) { - if (element.removeEventListener) { - // non-IE browsers - if (useCapture === undefined) - useCapture = false; - - if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) { - action = "DOMMouseScroll"; // For Firefox - } - - element.removeEventListener(action, listener, useCapture); - } else { - // IE browsers - element.detachEvent("on" + action, listener); - } -}; - - -/** - * Get HTML element which is the target of the event - * @param {Event} event - * @return {Element} target element - */ -util.getTarget = function getTarget(event) { - // code from http://www.quirksmode.org/js/events_properties.html - if (!event) { - event = window.event; - } - - var target; - - if (event.target) { - target = event.target; - } - else if (event.srcElement) { - target = event.srcElement; - } - - if (target.nodeType != undefined && target.nodeType == 3) { - // defeat Safari bug - target = target.parentNode; - } - - return target; -}; - -/** - * Stop event propagation - */ -util.stopPropagation = function stopPropagation(event) { - if (!event) - event = window.event; - - if (event.stopPropagation) { - event.stopPropagation(); // non-IE browsers - } - else { - event.cancelBubble = true; // IE browsers - } -}; - - -/** - * Cancels the event if it is cancelable, without stopping further propagation of the event. - */ -util.preventDefault = function preventDefault (event) { - if (!event) - event = window.event; - - if (event.preventDefault) { - event.preventDefault(); // non-IE browsers - } - else { - event.returnValue = false; // IE browsers - } -}; - - -util.option = {}; - -/** - * Convert a value into a boolean - * @param {Boolean | function | undefined} value - * @param {Boolean} [defaultValue] - * @returns {Boolean} bool - */ -util.option.asBoolean = function (value, defaultValue) { - if (typeof value == 'function') { - value = value(); - } - - if (value != null) { - return (value != false); - } - - return defaultValue || null; -}; - -/** - * Convert a value into a number - * @param {Boolean | function | undefined} value - * @param {Number} [defaultValue] - * @returns {Number} number - */ -util.option.asNumber = function (value, defaultValue) { - if (typeof value == 'function') { - value = value(); - } - - if (value != null) { - return Number(value) || defaultValue || null; - } - - return defaultValue || null; -}; - -/** - * Convert a value into a string - * @param {String | function | undefined} value - * @param {String} [defaultValue] - * @returns {String} str - */ -util.option.asString = function (value, defaultValue) { - if (typeof value == 'function') { - value = value(); - } - - if (value != null) { - return String(value); - } - - return defaultValue || null; -}; - -/** - * Convert a size or location into a string with pixels or a percentage - * @param {String | Number | function | undefined} value - * @param {String} [defaultValue] - * @returns {String} size - */ -util.option.asSize = function (value, defaultValue) { - if (typeof value == 'function') { - value = value(); - } - - if (util.isString(value)) { - return value; - } - else if (util.isNumber(value)) { - return value + 'px'; - } - else { - return defaultValue || null; - } -}; - -/** - * Convert a value into a DOM element - * @param {HTMLElement | function | undefined} value - * @param {HTMLElement} [defaultValue] - * @returns {HTMLElement | null} dom - */ -util.option.asElement = function (value, defaultValue) { - if (typeof value == 'function') { - value = value(); - } - - return value || defaultValue || null; -}; - -/** - * load css from text - * @param {String} css Text containing css - */ -util.loadCss = function (css) { - if (typeof document === 'undefined') { - return; - } - - // get the script location, and built the css file name from the js file name - // http://stackoverflow.com/a/2161748/1262753 - // var scripts = document.getElementsByTagName('script'); - // var jsFile = scripts[scripts.length-1].src.split('?')[0]; - // var cssFile = jsFile.substring(0, jsFile.length - 2) + 'css'; - - // inject css - // http://stackoverflow.com/questions/524696/how-to-create-a-style-tag-with-javascript - var style = document.createElement('style'); - style.type = 'text/css'; - if (style.styleSheet){ - style.styleSheet.cssText = css; - } else { - style.appendChild(document.createTextNode(css)); - } - - document.getElementsByTagName('head')[0].appendChild(style); -}; - -/** - * Event listener (singleton) - */ -// TODO: replace usage of the event listener for the EventBus -var events = { - 'listeners': [], - - /** - * Find a single listener by its object - * @param {Object} object - * @return {Number} index -1 when not found - */ - 'indexOf': function (object) { - var listeners = this.listeners; - for (var i = 0, iMax = this.listeners.length; i < iMax; i++) { - var listener = listeners[i]; - if (listener && listener.object == object) { - return i; - } - } - return -1; - }, - - /** - * Add an event listener - * @param {Object} object - * @param {String} event The name of an event, for example 'select' - * @param {function} callback The callback method, called when the - * event takes place - */ - 'addListener': function (object, event, callback) { - var index = this.indexOf(object); - var listener = this.listeners[index]; - if (!listener) { - listener = { - 'object': object, - 'events': {} - }; - this.listeners.push(listener); - } - - var callbacks = listener.events[event]; - if (!callbacks) { - callbacks = []; - listener.events[event] = callbacks; - } - - // add the callback if it does not yet exist - if (callbacks.indexOf(callback) == -1) { - callbacks.push(callback); - } - }, - - /** - * Remove an event listener - * @param {Object} object - * @param {String} event The name of an event, for example 'select' - * @param {function} callback The registered callback method - */ - 'removeListener': function (object, event, callback) { - var index = this.indexOf(object); - var listener = this.listeners[index]; - if (listener) { - var callbacks = listener.events[event]; - if (callbacks) { - index = callbacks.indexOf(callback); - if (index != -1) { - callbacks.splice(index, 1); - } - - // remove the array when empty - if (callbacks.length == 0) { - delete listener.events[event]; - } - } - - // count the number of registered events. remove listener when empty - var count = 0; - var events = listener.events; - for (var e in events) { - if (events.hasOwnProperty(e)) { - count++; - } - } - if (count == 0) { - delete this.listeners[index]; - } - } - }, - - /** - * Remove all registered event listeners - */ - 'removeAllListeners': function () { - this.listeners = []; - }, - - /** - * Trigger an event. All registered event handlers will be called - * @param {Object} object - * @param {String} event - * @param {Object} properties (optional) - */ - 'trigger': function (object, event, properties) { - var index = this.indexOf(object); - var listener = this.listeners[index]; - if (listener) { - var callbacks = listener.events[event]; - if (callbacks) { - for (var i = 0, iMax = callbacks.length; i < iMax; i++) { - callbacks[i](properties); - } - } - } - } -}; - -/** - * An event bus can be used to emit events, and to subscribe to events - * @constructor EventBus - */ -function EventBus() { - this.subscriptions = []; -} - -/** - * Subscribe to an event - * @param {String | RegExp} event The event can be a regular expression, or - * a string with wildcards, like 'server.*'. - * @param {function} callback. Callback are called with three parameters: - * {String} event, {*} [data], {*} [source] - * @param {*} [target] - * @returns {String} id A subscription id - */ -EventBus.prototype.on = function (event, callback, target) { - var regexp = (event instanceof RegExp) ? - event : - new RegExp(event.replace('*', '\\w+')); - - var subscription = { - id: util.randomUUID(), - event: event, - regexp: regexp, - callback: (typeof callback === 'function') ? callback : null, - target: target - }; - - this.subscriptions.push(subscription); - - return subscription.id; -}; - -/** - * Unsubscribe from an event - * @param {String | Object} filter Filter for subscriptions to be removed - * Filter can be a string containing a - * subscription id, or an object containing - * one or more of the fields id, event, - * callback, and target. - */ -EventBus.prototype.off = function (filter) { - var i = 0; - while (i < this.subscriptions.length) { - var subscription = this.subscriptions[i]; - - var match = true; - if (filter instanceof Object) { - // filter is an object. All fields must match - for (var prop in filter) { - if (filter.hasOwnProperty(prop)) { - if (filter[prop] !== subscription[prop]) { - match = false; - } - } - } - } - else { - // filter is a string, filter on id - match = (subscription.id == filter); - } - - if (match) { - this.subscriptions.splice(i, 1); - } - else { - i++; - } - } -}; - -/** - * Emit an event - * @param {String} event - * @param {*} [data] - * @param {*} [source] - */ -EventBus.prototype.emit = function (event, data, source) { - for (var i =0; i < this.subscriptions.length; i++) { - var subscription = this.subscriptions[i]; - if (subscription.regexp.test(event)) { - if (subscription.callback) { - subscription.callback(event, data, source); - } - } - } -}; - -/** - * DataSet - * - * Usage: - * var dataSet = new DataSet({ - * fieldId: '_id', - * convert: { - * // ... - * } - * }); - * - * dataSet.add(item); - * dataSet.add(data); - * dataSet.update(item); - * dataSet.update(data); - * dataSet.remove(id); - * dataSet.remove(ids); - * var data = dataSet.get(); - * var data = dataSet.get(id); - * var data = dataSet.get(ids); - * var data = dataSet.get(ids, options, data); - * dataSet.clear(); - * - * A data set can: - * - add/remove/update data - * - gives triggers upon changes in the data - * - can import/export data in various data formats - * - * @param {Object} [options] Available options: - * {String} fieldId Field name of the id in the - * items, 'id' by default. - * {Object.} [convert] - * {String[]} [fields] field names to be returned - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * {Array | DataTable} [data] If provided, items will be appended to this - * array or table. Required in case of Google - * DataTable. - * - * @throws Error - */ -DataSet.prototype.get = function (args) { - var me = this; - - // parse the arguments - var id, ids, options, data; - var firstType = util.getType(arguments[0]); - if (firstType == 'String' || firstType == 'Number') { - // get(id [, options] [, data]) - id = arguments[0]; - options = arguments[1]; - data = arguments[2]; - } - else if (firstType == 'Array') { - // get(ids [, options] [, data]) - ids = arguments[0]; - options = arguments[1]; - data = arguments[2]; - } - else { - // get([, options] [, data]) - options = arguments[0]; - data = arguments[1]; - } - - // determine the return type - var type; - if (options && options.type) { - type = (options.type == 'DataTable') ? 'DataTable' : 'Array'; - - if (data && (type != util.getType(data))) { - throw new Error('Type of parameter "data" (' + util.getType(data) + ') ' + - 'does not correspond with specified options.type (' + options.type + ')'); - } - if (type == 'DataTable' && !util.isDataTable(data)) { - throw new Error('Parameter "data" must be a DataTable ' + - 'when options.type is "DataTable"'); - } - } - else if (data) { - type = (util.getType(data) == 'DataTable') ? 'DataTable' : 'Array'; - } - else { - type = 'Array'; - } - - // build options - var convert = options && options.convert || this.options.convert; - var filter = options && options.filter; - var items = [], item, itemId, i, len; - - // convert items - if (id != undefined) { - // return a single item - item = me._getItem(id, convert); - if (filter && !filter(item)) { - item = null; - } - } - else if (ids != undefined) { - // return a subset of items - for (i = 0, len = ids.length; i < len; i++) { - item = me._getItem(ids[i], convert); - if (!filter || filter(item)) { - items.push(item); - } - } - } - else { - // return all items - for (itemId in this.data) { - if (this.data.hasOwnProperty(itemId)) { - item = me._getItem(itemId, convert); - if (!filter || filter(item)) { - items.push(item); - } - } - } - } - - // order the results - if (options && options.order && id == undefined) { - this._sort(items, options.order); - } - - // filter fields of the items - if (options && options.fields) { - var fields = options.fields; - if (id != undefined) { - item = this._filterFields(item, fields); - } - else { - for (i = 0, len = items.length; i < len; i++) { - items[i] = this._filterFields(items[i], fields); - } - } - } - - // return the results - if (type == 'DataTable') { - var columns = this._getColumnNames(data); - if (id != undefined) { - // append a single item to the data table - me._appendRow(data, columns, item); - } - else { - // copy the items to the provided data table - for (i = 0, len = items.length; i < len; i++) { - me._appendRow(data, columns, items[i]); - } - } - return data; - } - else { - // return an array - if (id != undefined) { - // a single item - return item; - } - else { - // multiple items - if (data) { - // copy the items to the provided array - for (i = 0, len = items.length; i < len; i++) { - data.push(items[i]); - } - return data; - } - else { - // just return our array - return items; - } - } - } -}; - -/** - * Get ids of all items or from a filtered set of items. - * @param {Object} [options] An Object with options. Available options: - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * @return {Array} ids - */ -DataSet.prototype.getIds = function (options) { - var data = this.data, - filter = options && options.filter, - order = options && options.order, - convert = options && options.convert || this.options.convert, - i, - len, - id, - item, - items, - ids = []; - - if (filter) { - // get filtered items - if (order) { - // create ordered list - items = []; - for (id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, convert); - if (filter(item)) { - items.push(item); - } - } - } - - this._sort(items, order); - - for (i = 0, len = items.length; i < len; i++) { - ids[i] = items[i][this.fieldId]; - } - } - else { - // create unordered list - for (id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, convert); - if (filter(item)) { - ids.push(item[this.fieldId]); - } - } - } - } - } - else { - // get all items - if (order) { - // create an ordered list - items = []; - for (id in data) { - if (data.hasOwnProperty(id)) { - items.push(data[id]); - } - } - - this._sort(items, order); - - for (i = 0, len = items.length; i < len; i++) { - ids[i] = items[i][this.fieldId]; - } - } - else { - // create unordered list - for (id in data) { - if (data.hasOwnProperty(id)) { - item = data[id]; - ids.push(item[this.fieldId]); - } - } - } - } - - return ids; -}; - -/** - * Execute a callback function for every item in the dataset. - * The order of the items is not determined. - * @param {function} callback - * @param {Object} [options] Available options: - * {Object.} [convert] - * {String[]} [fields] filter fields - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - */ -DataSet.prototype.forEach = function (callback, options) { - var filter = options && options.filter, - convert = options && options.convert || this.options.convert, - data = this.data, - item, - id; - - if (options && options.order) { - // execute forEach on ordered list - var items = this.get(options); - - for (var i = 0, len = items.length; i < len; i++) { - item = items[i]; - id = item[this.fieldId]; - callback(item, id); - } - } - else { - // unordered - for (id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, convert); - if (!filter || filter(item)) { - callback(item, id); - } - } - } - } -}; - -/** - * Map every item in the dataset. - * @param {function} callback - * @param {Object} [options] Available options: - * {Object.} [convert] - * {String[]} [fields] filter fields - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * @return {Object[]} mappedItems - */ -DataSet.prototype.map = function (callback, options) { - var filter = options && options.filter, - convert = options && options.convert || this.options.convert, - mappedItems = [], - data = this.data, - item; - - // convert and filter items - for (var id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, convert); - if (!filter || filter(item)) { - mappedItems.push(callback(item, id)); - } - } - } - - // order items - if (options && options.order) { - this._sort(mappedItems, options.order); - } - - return mappedItems; -}; - -/** - * Filter the fields of an item - * @param {Object} item - * @param {String[]} fields Field names - * @return {Object} filteredItem - * @private - */ -DataSet.prototype._filterFields = function (item, fields) { - var filteredItem = {}; - - for (var field in item) { - if (item.hasOwnProperty(field) && (fields.indexOf(field) != -1)) { - filteredItem[field] = item[field]; - } - } - - return filteredItem; -}; - -/** - * Sort the provided array with items - * @param {Object[]} items - * @param {String | function} order A field name or custom sort function. - * @private - */ -DataSet.prototype._sort = function (items, order) { - if (util.isString(order)) { - // order by provided field name - var name = order; // field name - items.sort(function (a, b) { - var av = a[name]; - var bv = b[name]; - return (av > bv) ? 1 : ((av < bv) ? -1 : 0); - }); - } - else if (typeof order === 'function') { - // order by sort function - items.sort(order); - } - // TODO: extend order by an Object {field:String, direction:String} - // where direction can be 'asc' or 'desc' - else { - throw new TypeError('Order must be a function or a string'); - } -}; - -/** - * Remove an object by pointer or by id - * @param {String | Number | Object | Array} id Object or id, or an array with - * objects or ids to be removed - * @param {String} [senderId] Optional sender id - * @return {Array} removedIds - */ -DataSet.prototype.remove = function (id, senderId) { - var removedIds = [], - i, len, removedId; - - if (id instanceof Array) { - for (i = 0, len = id.length; i < len; i++) { - removedId = this._remove(id[i]); - if (removedId != null) { - removedIds.push(removedId); - } - } - } - else { - removedId = this._remove(id); - if (removedId != null) { - removedIds.push(removedId); - } - } - - if (removedIds.length) { - this._trigger('remove', {items: removedIds}, senderId); - } - - return removedIds; -}; - -/** - * Remove an item by its id - * @param {Number | String | Object} id id or item - * @returns {Number | String | null} id - * @private - */ -DataSet.prototype._remove = function (id) { - if (util.isNumber(id) || util.isString(id)) { - if (this.data[id]) { - delete this.data[id]; - delete this.internalIds[id]; - return id; - } - } - else if (id instanceof Object) { - var itemId = id[this.fieldId]; - if (itemId && this.data[itemId]) { - delete this.data[itemId]; - delete this.internalIds[itemId]; - return itemId; - } - } - return null; -}; - -/** - * Clear the data - * @param {String} [senderId] Optional sender id - * @return {Array} removedIds The ids of all removed items - */ -DataSet.prototype.clear = function (senderId) { - var ids = Object.keys(this.data); - - this.data = {}; - this.internalIds = {}; - - this._trigger('remove', {items: ids}, senderId); - - return ids; -}; - -/** - * Find the item with maximum value of a specified field - * @param {String} field - * @return {Object | null} item Item containing max value, or null if no items - */ -DataSet.prototype.max = function (field) { - var data = this.data, - max = null, - maxField = null; - - for (var id in data) { - if (data.hasOwnProperty(id)) { - var item = data[id]; - var itemField = item[field]; - if (itemField != null && (!max || itemField > maxField)) { - max = item; - maxField = itemField; - } - } - } - - return max; -}; - -/** - * Find the item with minimum value of a specified field - * @param {String} field - * @return {Object | null} item Item containing max value, or null if no items - */ -DataSet.prototype.min = function (field) { - var data = this.data, - min = null, - minField = null; - - for (var id in data) { - if (data.hasOwnProperty(id)) { - var item = data[id]; - var itemField = item[field]; - if (itemField != null && (!min || itemField < minField)) { - min = item; - minField = itemField; - } - } - } - - return min; -}; - -/** - * Find all distinct values of a specified field - * @param {String} field - * @return {Array} values Array containing all distinct values. If the data - * items do not contain the specified field, an array - * containing a single value undefined is returned. - * The returned array is unordered. - */ -DataSet.prototype.distinct = function (field) { - var data = this.data, - values = [], - fieldType = this.options.convert[field], - count = 0; - - for (var prop in data) { - if (data.hasOwnProperty(prop)) { - var item = data[prop]; - var value = util.convert(item[field], fieldType); - var exists = false; - for (var i = 0; i < count; i++) { - if (values[i] == value) { - exists = true; - break; - } - } - if (!exists) { - values[count] = value; - count++; - } - } - } - - return values; -}; - -/** - * Add a single item. Will fail when an item with the same id already exists. - * @param {Object} item - * @return {String} id - * @private - */ -DataSet.prototype._addItem = function (item) { - var id = item[this.fieldId]; - - if (id != undefined) { - // check whether this id is already taken - if (this.data[id]) { - // item already exists - throw new Error('Cannot add item: item with id ' + id + ' already exists'); - } - } - else { - // generate an id - id = util.randomUUID(); - item[this.fieldId] = id; - this.internalIds[id] = item; - } - - var d = {}; - for (var field in item) { - if (item.hasOwnProperty(field)) { - var fieldType = this.convert[field]; // type may be undefined - d[field] = util.convert(item[field], fieldType); - } - } - this.data[id] = d; - - return id; -}; - -/** - * Get an item. Fields can be converted to a specific type - * @param {String} id - * @param {Object.} [convert] field types to convert - * @return {Object | null} item - * @private - */ -DataSet.prototype._getItem = function (id, convert) { - var field, value; - - // get the item from the dataset - var raw = this.data[id]; - if (!raw) { - return null; - } - - // convert the items field types - var converted = {}, - fieldId = this.fieldId, - internalIds = this.internalIds; - if (convert) { - for (field in raw) { - if (raw.hasOwnProperty(field)) { - value = raw[field]; - // output all fields, except internal ids - if ((field != fieldId) || !(value in internalIds)) { - converted[field] = util.convert(value, convert[field]); - } - } - } - } - else { - // no field types specified, no converting needed - for (field in raw) { - if (raw.hasOwnProperty(field)) { - value = raw[field]; - // output all fields, except internal ids - if ((field != fieldId) || !(value in internalIds)) { - converted[field] = value; - } - } - } - } - - return converted; -}; - -/** - * Update a single item: merge with existing item. - * Will fail when the item has no id, or when there does not exist an item - * with the same id. - * @param {Object} item - * @return {String} id - * @private - */ -DataSet.prototype._updateItem = function (item) { - var id = item[this.fieldId]; - if (id == undefined) { - throw new Error('Cannot update item: item has no id (item: ' + JSON.stringify(item) + ')'); - } - var d = this.data[id]; - if (!d) { - // item doesn't exist - throw new Error('Cannot update item: no item with id ' + id + ' found'); - } - - // merge with current item - for (var field in item) { - if (item.hasOwnProperty(field)) { - var fieldType = this.convert[field]; // type may be undefined - d[field] = util.convert(item[field], fieldType); - } - } - - return id; -}; - -/** - * Get an array with the column names of a Google DataTable - * @param {DataTable} dataTable - * @return {String[]} columnNames - * @private - */ -DataSet.prototype._getColumnNames = function (dataTable) { - var columns = []; - for (var col = 0, cols = dataTable.getNumberOfColumns(); col < cols; col++) { - columns[col] = dataTable.getColumnId(col) || dataTable.getColumnLabel(col); - } - return columns; -}; - -/** - * Append an item as a row to the dataTable - * @param dataTable - * @param columns - * @param item - * @private - */ -DataSet.prototype._appendRow = function (dataTable, columns, item) { - var row = dataTable.addRow(); - - for (var col = 0, cols = columns.length; col < cols; col++) { - var field = columns[col]; - dataTable.setValue(row, col, item[field]); - } -}; - -/** - * DataView - * - * a dataview offers a filtered view on a dataset or an other dataview. - * - * @param {DataSet | DataView} data - * @param {Object} [options] Available options: see method get - * - * @constructor DataView - */ -function DataView (data, options) { - this.id = util.randomUUID(); - - this.data = null; - this.ids = {}; // ids of the items currently in memory (just contains a boolean true) - this.options = options || {}; - this.fieldId = 'id'; // name of the field containing id - this.subscribers = {}; // event subscribers - - var me = this; - this.listener = function () { - me._onEvent.apply(me, arguments); - }; - - this.setData(data); -} - -/** - * Set a data source for the view - * @param {DataSet | DataView} data - */ -DataView.prototype.setData = function (data) { - var ids, dataItems, i, len; - - if (this.data) { - // unsubscribe from current dataset - if (this.data.unsubscribe) { - this.data.unsubscribe('*', this.listener); - } - - // trigger a remove of all items in memory - ids = []; - for (var id in this.ids) { - if (this.ids.hasOwnProperty(id)) { - ids.push(id); - } - } - this.ids = {}; - this._trigger('remove', {items: ids}); - } - - this.data = data; - - if (this.data) { - // update fieldId - this.fieldId = this.options.fieldId || - (this.data && this.data.options && this.data.options.fieldId) || - 'id'; - - // trigger an add of all added items - ids = this.data.getIds({filter: this.options && this.options.filter}); - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - this.ids[id] = true; - } - this._trigger('add', {items: ids}); - - // subscribe to new dataset - if (this.data.subscribe) { - this.data.subscribe('*', this.listener); - } - } -}; - -/** - * Get data from the data view - * - * Usage: - * - * get() - * get(options: Object) - * get(options: Object, data: Array | DataTable) - * - * get(id: Number) - * get(id: Number, options: Object) - * get(id: Number, options: Object, data: Array | DataTable) - * - * get(ids: Number[]) - * get(ids: Number[], options: Object) - * get(ids: Number[], options: Object, data: Array | DataTable) - * - * Where: - * - * {Number | String} id The id of an item - * {Number[] | String{}} ids An array with ids of items - * {Object} options An Object with options. Available options: - * {String} [type] Type of data to be returned. Can - * be 'DataTable' or 'Array' (default) - * {Object.} [convert] - * {String[]} [fields] field names to be returned - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * {Array | DataTable} [data] If provided, items will be appended to this - * array or table. Required in case of Google - * DataTable. - * @param args - */ -DataView.prototype.get = function (args) { - var me = this; - - // parse the arguments - var ids, options, data; - var firstType = util.getType(arguments[0]); - if (firstType == 'String' || firstType == 'Number' || firstType == 'Array') { - // get(id(s) [, options] [, data]) - ids = arguments[0]; // can be a single id or an array with ids - options = arguments[1]; - data = arguments[2]; - } - else { - // get([, options] [, data]) - options = arguments[0]; - data = arguments[1]; - } - - // extend the options with the default options and provided options - var viewOptions = util.extend({}, this.options, options); - - // create a combined filter method when needed - if (this.options.filter && options && options.filter) { - viewOptions.filter = function (item) { - return me.options.filter(item) && options.filter(item); - } - } - - // build up the call to the linked data set - var getArguments = []; - if (ids != undefined) { - getArguments.push(ids); - } - getArguments.push(viewOptions); - getArguments.push(data); - - return this.data && this.data.get.apply(this.data, getArguments); -}; - -/** - * Get ids of all items or from a filtered set of items. - * @param {Object} [options] An Object with options. Available options: - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * @return {Array} ids - */ -DataView.prototype.getIds = function (options) { - var ids; - - if (this.data) { - var defaultFilter = this.options.filter; - var filter; - - if (options && options.filter) { - if (defaultFilter) { - filter = function (item) { - return defaultFilter(item) && options.filter(item); - } - } - else { - filter = options.filter; - } - } - else { - filter = defaultFilter; - } - - ids = this.data.getIds({ - filter: filter, - order: options && options.order - }); - } - else { - ids = []; - } - - return ids; -}; - -/** - * Event listener. Will propagate all events from the connected data set to - * the subscribers of the DataView, but will filter the items and only trigger - * when there are changes in the filtered data set. - * @param {String} event - * @param {Object | null} params - * @param {String} senderId - * @private - */ -DataView.prototype._onEvent = function (event, params, senderId) { - var i, len, id, item, - ids = params && params.items, - data = this.data, - added = [], - updated = [], - removed = []; - - if (ids && data) { - switch (event) { - case 'add': - // filter the ids of the added items - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - item = this.get(id); - if (item) { - this.ids[id] = true; - added.push(id); - } - } - - break; - - case 'update': - // determine the event from the views viewpoint: an updated - // item can be added, updated, or removed from this view. - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - item = this.get(id); - - if (item) { - if (this.ids[id]) { - updated.push(id); - } - else { - this.ids[id] = true; - added.push(id); - } - } - else { - if (this.ids[id]) { - delete this.ids[id]; - removed.push(id); - } - else { - // nothing interesting for me :-( - } - } - } - - break; - - case 'remove': - // filter the ids of the removed items - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - if (this.ids[id]) { - delete this.ids[id]; - removed.push(id); - } - } - - break; - } - - if (added.length) { - this._trigger('add', {items: added}, senderId); - } - if (updated.length) { - this._trigger('update', {items: updated}, senderId); - } - if (removed.length) { - this._trigger('remove', {items: removed}, senderId); - } - } -}; - -// copy subscription functionality from DataSet -DataView.prototype.subscribe = DataSet.prototype.subscribe; -DataView.prototype.unsubscribe = DataSet.prototype.unsubscribe; -DataView.prototype._trigger = DataSet.prototype._trigger; - -/** - * @constructor TimeStep - * The class TimeStep is an iterator for dates. You provide a start date and an - * end date. The class itself determines the best scale (step size) based on the - * provided start Date, end Date, and minimumStep. - * - * If minimumStep is provided, the step size is chosen as close as possible - * to the minimumStep but larger than minimumStep. If minimumStep is not - * provided, the scale is set to 1 DAY. - * The minimumStep should correspond with the onscreen size of about 6 characters - * - * Alternatively, you can set a scale by hand. - * After creation, you can initialize the class by executing first(). Then you - * can iterate from the start date to the end date via next(). You can check if - * the end date is reached with the function hasNext(). After each step, you can - * retrieve the current date via getCurrent(). - * The TimeStep has scales ranging from milliseconds, seconds, minutes, hours, - * days, to years. - * - * Version: 1.2 - * - * @param {Date} [start] The start date, for example new Date(2010, 9, 21) - * or new Date(2010, 9, 21, 23, 45, 00) - * @param {Date} [end] The end date - * @param {Number} [minimumStep] Optional. Minimum step size in milliseconds - */ -TimeStep = function(start, end, minimumStep) { - // variables - this.current = new Date(); - this._start = new Date(); - this._end = new Date(); - - this.autoScale = true; - this.scale = TimeStep.SCALE.DAY; - this.step = 1; - - // initialize the range - this.setRange(start, end, minimumStep); -}; - -/// enum scale -TimeStep.SCALE = { - MILLISECOND: 1, - SECOND: 2, - MINUTE: 3, - HOUR: 4, - DAY: 5, - WEEKDAY: 6, - MONTH: 7, - YEAR: 8 -}; - - -/** - * Set a new range - * If minimumStep is provided, the step size is chosen as close as possible - * to the minimumStep but larger than minimumStep. If minimumStep is not - * provided, the scale is set to 1 DAY. - * The minimumStep should correspond with the onscreen size of about 6 characters - * @param {Date} [start] The start date and time. - * @param {Date} [end] The end date and time. - * @param {int} [minimumStep] Optional. Minimum step size in milliseconds - */ -TimeStep.prototype.setRange = function(start, end, minimumStep) { - if (!(start instanceof Date) || !(end instanceof Date)) { - //throw "No legal start or end date in method setRange"; - return; - } - - this._start = (start != undefined) ? new Date(start.valueOf()) : new Date(); - this._end = (end != undefined) ? new Date(end.valueOf()) : new Date(); - - if (this.autoScale) { - this.setMinimumStep(minimumStep); - } -}; - -/** - * Set the range iterator to the start date. - */ -TimeStep.prototype.first = function() { - this.current = new Date(this._start.valueOf()); - this.roundToMinor(); -}; - -/** - * Round the current date to the first minor date value - * This must be executed once when the current date is set to start Date - */ -TimeStep.prototype.roundToMinor = function() { - // round to floor - // IMPORTANT: we have no breaks in this switch! (this is no bug) - //noinspection FallthroughInSwitchStatementJS - switch (this.scale) { - case TimeStep.SCALE.YEAR: - this.current.setFullYear(this.step * Math.floor(this.current.getFullYear() / this.step)); - this.current.setMonth(0); - case TimeStep.SCALE.MONTH: this.current.setDate(1); - case TimeStep.SCALE.DAY: // intentional fall through - case TimeStep.SCALE.WEEKDAY: this.current.setHours(0); - case TimeStep.SCALE.HOUR: this.current.setMinutes(0); - case TimeStep.SCALE.MINUTE: this.current.setSeconds(0); - case TimeStep.SCALE.SECOND: this.current.setMilliseconds(0); - //case TimeStep.SCALE.MILLISECOND: // nothing to do for milliseconds - } - - if (this.step != 1) { - // round down to the first minor value that is a multiple of the current step size - switch (this.scale) { - case TimeStep.SCALE.MILLISECOND: this.current.setMilliseconds(this.current.getMilliseconds() - this.current.getMilliseconds() % this.step); break; - case TimeStep.SCALE.SECOND: this.current.setSeconds(this.current.getSeconds() - this.current.getSeconds() % this.step); break; - case TimeStep.SCALE.MINUTE: this.current.setMinutes(this.current.getMinutes() - this.current.getMinutes() % this.step); break; - case TimeStep.SCALE.HOUR: this.current.setHours(this.current.getHours() - this.current.getHours() % this.step); break; - case TimeStep.SCALE.WEEKDAY: // intentional fall through - case TimeStep.SCALE.DAY: this.current.setDate((this.current.getDate()-1) - (this.current.getDate()-1) % this.step + 1); break; - case TimeStep.SCALE.MONTH: this.current.setMonth(this.current.getMonth() - this.current.getMonth() % this.step); break; - case TimeStep.SCALE.YEAR: this.current.setFullYear(this.current.getFullYear() - this.current.getFullYear() % this.step); break; - default: break; - } - } -}; - -/** - * Check if the there is a next step - * @return {boolean} true if the current date has not passed the end date - */ -TimeStep.prototype.hasNext = function () { - return (this.current.valueOf() <= this._end.valueOf()); -}; - -/** - * Do the next step - */ -TimeStep.prototype.next = function() { - var prev = this.current.valueOf(); - - // Two cases, needed to prevent issues with switching daylight savings - // (end of March and end of October) - if (this.current.getMonth() < 6) { - switch (this.scale) { - case TimeStep.SCALE.MILLISECOND: - - this.current = new Date(this.current.valueOf() + this.step); break; - case TimeStep.SCALE.SECOND: this.current = new Date(this.current.valueOf() + this.step * 1000); break; - case TimeStep.SCALE.MINUTE: this.current = new Date(this.current.valueOf() + this.step * 1000 * 60); break; - case TimeStep.SCALE.HOUR: - this.current = new Date(this.current.valueOf() + this.step * 1000 * 60 * 60); - // in case of skipping an hour for daylight savings, adjust the hour again (else you get: 0h 5h 9h ... instead of 0h 4h 8h ...) - var h = this.current.getHours(); - this.current.setHours(h - (h % this.step)); - break; - case TimeStep.SCALE.WEEKDAY: // intentional fall through - case TimeStep.SCALE.DAY: this.current.setDate(this.current.getDate() + this.step); break; - case TimeStep.SCALE.MONTH: this.current.setMonth(this.current.getMonth() + this.step); break; - case TimeStep.SCALE.YEAR: this.current.setFullYear(this.current.getFullYear() + this.step); break; - default: break; - } - } - else { - switch (this.scale) { - case TimeStep.SCALE.MILLISECOND: this.current = new Date(this.current.valueOf() + this.step); break; - case TimeStep.SCALE.SECOND: this.current.setSeconds(this.current.getSeconds() + this.step); break; - case TimeStep.SCALE.MINUTE: this.current.setMinutes(this.current.getMinutes() + this.step); break; - case TimeStep.SCALE.HOUR: this.current.setHours(this.current.getHours() + this.step); break; - case TimeStep.SCALE.WEEKDAY: // intentional fall through - case TimeStep.SCALE.DAY: this.current.setDate(this.current.getDate() + this.step); break; - case TimeStep.SCALE.MONTH: this.current.setMonth(this.current.getMonth() + this.step); break; - case TimeStep.SCALE.YEAR: this.current.setFullYear(this.current.getFullYear() + this.step); break; - default: break; - } - } - - if (this.step != 1) { - // round down to the correct major value - switch (this.scale) { - case TimeStep.SCALE.MILLISECOND: if(this.current.getMilliseconds() < this.step) this.current.setMilliseconds(0); break; - case TimeStep.SCALE.SECOND: if(this.current.getSeconds() < this.step) this.current.setSeconds(0); break; - case TimeStep.SCALE.MINUTE: if(this.current.getMinutes() < this.step) this.current.setMinutes(0); break; - case TimeStep.SCALE.HOUR: if(this.current.getHours() < this.step) this.current.setHours(0); break; - case TimeStep.SCALE.WEEKDAY: // intentional fall through - case TimeStep.SCALE.DAY: if(this.current.getDate() < this.step+1) this.current.setDate(1); break; - case TimeStep.SCALE.MONTH: if(this.current.getMonth() < this.step) this.current.setMonth(0); break; - case TimeStep.SCALE.YEAR: break; // nothing to do for year - default: break; - } - } - - // safety mechanism: if current time is still unchanged, move to the end - if (this.current.valueOf() == prev) { - this.current = new Date(this._end.valueOf()); - } -}; - - -/** - * Get the current datetime - * @return {Date} current The current date - */ -TimeStep.prototype.getCurrent = function() { - return this.current; -}; - -/** - * Set a custom scale. Autoscaling will be disabled. - * For example setScale(SCALE.MINUTES, 5) will result - * in minor steps of 5 minutes, and major steps of an hour. - * - * @param {TimeStep.SCALE} newScale - * A scale. Choose from SCALE.MILLISECOND, - * SCALE.SECOND, SCALE.MINUTE, SCALE.HOUR, - * SCALE.WEEKDAY, SCALE.DAY, SCALE.MONTH, - * SCALE.YEAR. - * @param {Number} newStep A step size, by default 1. Choose for - * example 1, 2, 5, or 10. - */ -TimeStep.prototype.setScale = function(newScale, newStep) { - this.scale = newScale; - - if (newStep > 0) { - this.step = newStep; - } - - this.autoScale = false; -}; - -/** - * Enable or disable autoscaling - * @param {boolean} enable If true, autoascaling is set true - */ -TimeStep.prototype.setAutoScale = function (enable) { - this.autoScale = enable; -}; - - -/** - * Automatically determine the scale that bests fits the provided minimum step - * @param {Number} [minimumStep] The minimum step size in milliseconds - */ -TimeStep.prototype.setMinimumStep = function(minimumStep) { - if (minimumStep == undefined) { - return; - } - - var stepYear = (1000 * 60 * 60 * 24 * 30 * 12); - var stepMonth = (1000 * 60 * 60 * 24 * 30); - var stepDay = (1000 * 60 * 60 * 24); - var stepHour = (1000 * 60 * 60); - var stepMinute = (1000 * 60); - var stepSecond = (1000); - var stepMillisecond= (1); - - // find the smallest step that is larger than the provided minimumStep - if (stepYear*1000 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 1000;} - if (stepYear*500 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 500;} - if (stepYear*100 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 100;} - if (stepYear*50 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 50;} - if (stepYear*10 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 10;} - if (stepYear*5 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 5;} - if (stepYear > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 1;} - if (stepMonth*3 > minimumStep) {this.scale = TimeStep.SCALE.MONTH; this.step = 3;} - if (stepMonth > minimumStep) {this.scale = TimeStep.SCALE.MONTH; this.step = 1;} - if (stepDay*5 > minimumStep) {this.scale = TimeStep.SCALE.DAY; this.step = 5;} - if (stepDay*2 > minimumStep) {this.scale = TimeStep.SCALE.DAY; this.step = 2;} - if (stepDay > minimumStep) {this.scale = TimeStep.SCALE.DAY; this.step = 1;} - if (stepDay/2 > minimumStep) {this.scale = TimeStep.SCALE.WEEKDAY; this.step = 1;} - if (stepHour*4 > minimumStep) {this.scale = TimeStep.SCALE.HOUR; this.step = 4;} - if (stepHour > minimumStep) {this.scale = TimeStep.SCALE.HOUR; this.step = 1;} - if (stepMinute*15 > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 15;} - if (stepMinute*10 > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 10;} - if (stepMinute*5 > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 5;} - if (stepMinute > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 1;} - if (stepSecond*15 > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 15;} - if (stepSecond*10 > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 10;} - if (stepSecond*5 > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 5;} - if (stepSecond > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 1;} - if (stepMillisecond*200 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 200;} - if (stepMillisecond*100 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 100;} - if (stepMillisecond*50 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 50;} - if (stepMillisecond*10 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 10;} - if (stepMillisecond*5 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 5;} - if (stepMillisecond > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 1;} -}; - -/** - * Snap a date to a rounded value. The snap intervals are dependent on the - * current scale and step. - * @param {Date} date the date to be snapped - */ -TimeStep.prototype.snap = function(date) { - if (this.scale == TimeStep.SCALE.YEAR) { - var year = date.getFullYear() + Math.round(date.getMonth() / 12); - date.setFullYear(Math.round(year / this.step) * this.step); - date.setMonth(0); - date.setDate(0); - date.setHours(0); - date.setMinutes(0); - date.setSeconds(0); - date.setMilliseconds(0); - } - else if (this.scale == TimeStep.SCALE.MONTH) { - if (date.getDate() > 15) { - date.setDate(1); - date.setMonth(date.getMonth() + 1); - // important: first set Date to 1, after that change the month. - } - else { - date.setDate(1); - } - - date.setHours(0); - date.setMinutes(0); - date.setSeconds(0); - date.setMilliseconds(0); - } - else if (this.scale == TimeStep.SCALE.DAY || - this.scale == TimeStep.SCALE.WEEKDAY) { - //noinspection FallthroughInSwitchStatementJS - switch (this.step) { - case 5: - case 2: - date.setHours(Math.round(date.getHours() / 24) * 24); break; - default: - date.setHours(Math.round(date.getHours() / 12) * 12); break; - } - date.setMinutes(0); - date.setSeconds(0); - date.setMilliseconds(0); - } - else if (this.scale == TimeStep.SCALE.HOUR) { - switch (this.step) { - case 4: - date.setMinutes(Math.round(date.getMinutes() / 60) * 60); break; - default: - date.setMinutes(Math.round(date.getMinutes() / 30) * 30); break; - } - date.setSeconds(0); - date.setMilliseconds(0); - } else if (this.scale == TimeStep.SCALE.MINUTE) { - //noinspection FallthroughInSwitchStatementJS - switch (this.step) { - case 15: - case 10: - date.setMinutes(Math.round(date.getMinutes() / 5) * 5); - date.setSeconds(0); - break; - case 5: - date.setSeconds(Math.round(date.getSeconds() / 60) * 60); break; - default: - date.setSeconds(Math.round(date.getSeconds() / 30) * 30); break; - } - date.setMilliseconds(0); - } - else if (this.scale == TimeStep.SCALE.SECOND) { - //noinspection FallthroughInSwitchStatementJS - switch (this.step) { - case 15: - case 10: - date.setSeconds(Math.round(date.getSeconds() / 5) * 5); - date.setMilliseconds(0); - break; - case 5: - date.setMilliseconds(Math.round(date.getMilliseconds() / 1000) * 1000); break; - default: - date.setMilliseconds(Math.round(date.getMilliseconds() / 500) * 500); break; - } - } - else if (this.scale == TimeStep.SCALE.MILLISECOND) { - var step = this.step > 5 ? this.step / 2 : 1; - date.setMilliseconds(Math.round(date.getMilliseconds() / step) * step); - } -}; - -/** - * Check if the current value is a major value (for example when the step - * is DAY, a major value is each first day of the MONTH) - * @return {boolean} true if current date is major, else false. - */ -TimeStep.prototype.isMajor = function() { - switch (this.scale) { - case TimeStep.SCALE.MILLISECOND: - return (this.current.getMilliseconds() == 0); - case TimeStep.SCALE.SECOND: - return (this.current.getSeconds() == 0); - case TimeStep.SCALE.MINUTE: - return (this.current.getHours() == 0) && (this.current.getMinutes() == 0); - // Note: this is no bug. Major label is equal for both minute and hour scale - case TimeStep.SCALE.HOUR: - return (this.current.getHours() == 0); - case TimeStep.SCALE.WEEKDAY: // intentional fall through - case TimeStep.SCALE.DAY: - return (this.current.getDate() == 1); - case TimeStep.SCALE.MONTH: - return (this.current.getMonth() == 0); - case TimeStep.SCALE.YEAR: - return false; - default: - return false; - } -}; - - -/** - * Returns formatted text for the minor axislabel, depending on the current - * date and the scale. For example when scale is MINUTE, the current time is - * formatted as "hh:mm". - * @param {Date} [date] custom date. if not provided, current date is taken - */ -TimeStep.prototype.getLabelMinor = function(date) { - if (date == undefined) { - date = this.current; - } - - switch (this.scale) { - case TimeStep.SCALE.MILLISECOND: return moment(date).format('SSS'); - case TimeStep.SCALE.SECOND: return moment(date).format('s'); - case TimeStep.SCALE.MINUTE: return moment(date).format('HH:mm'); - case TimeStep.SCALE.HOUR: return moment(date).format('HH:mm'); - case TimeStep.SCALE.WEEKDAY: return moment(date).format('ddd D'); - case TimeStep.SCALE.DAY: return moment(date).format('D'); - case TimeStep.SCALE.MONTH: return moment(date).format('MMM'); - case TimeStep.SCALE.YEAR: return moment(date).format('YYYY'); - default: return ''; - } -}; - - -/** - * Returns formatted text for the major axis label, depending on the current - * date and the scale. For example when scale is MINUTE, the major scale is - * hours, and the hour will be formatted as "hh". - * @param {Date} [date] custom date. if not provided, current date is taken - */ -TimeStep.prototype.getLabelMajor = function(date) { - if (date == undefined) { - date = this.current; - } - - //noinspection FallthroughInSwitchStatementJS - switch (this.scale) { - case TimeStep.SCALE.MILLISECOND:return moment(date).format('HH:mm:ss'); - case TimeStep.SCALE.SECOND: return moment(date).format('D MMMM HH:mm'); - case TimeStep.SCALE.MINUTE: - case TimeStep.SCALE.HOUR: return moment(date).format('ddd D MMMM'); - case TimeStep.SCALE.WEEKDAY: - case TimeStep.SCALE.DAY: return moment(date).format('MMMM YYYY'); - case TimeStep.SCALE.MONTH: return moment(date).format('YYYY'); - case TimeStep.SCALE.YEAR: return ''; - default: return ''; - } -}; - -/** - * @constructor Stack - * Stacks items on top of each other. - * @param {ItemSet} parent - * @param {Object} [options] - */ -function Stack (parent, options) { - this.parent = parent; - - this.options = options || {}; - this.defaultOptions = { - order: function (a, b) { - //return (b.width - a.width) || (a.left - b.left); // TODO: cleanup - // Order: ranges over non-ranges, ranged ordered by width, and - // lastly ordered by start. - if (a instanceof ItemRange) { - if (b instanceof ItemRange) { - var aInt = (a.data.end - a.data.start); - var bInt = (b.data.end - b.data.start); - return (aInt - bInt) || (a.data.start - b.data.start); - } - else { - return -1; - } - } - else { - if (b instanceof ItemRange) { - return 1; - } - else { - return (a.data.start - b.data.start); - } - } - }, - margin: { - item: 10 - } - }; - - this.ordered = []; // ordered items -} - -/** - * Set options for the stack - * @param {Object} options Available options: - * {ItemSet} parent - * {Number} margin - * {function} order Stacking order - */ -Stack.prototype.setOptions = function setOptions (options) { - util.extend(this.options, options); - - // TODO: register on data changes at the connected parent itemset, and update the changed part only and immediately -}; - -/** - * Stack the items such that they don't overlap. The items will have a minimal - * distance equal to options.margin.item. - */ -Stack.prototype.update = function update() { - this._order(); - this._stack(); -}; - -/** - * Order the items. The items are ordered by width first, and by left position - * second. - * If a custom order function has been provided via the options, then this will - * be used. - * @private - */ -Stack.prototype._order = function _order () { - var items = this.parent.items; - if (!items) { - throw new Error('Cannot stack items: parent does not contain items'); - } - - // TODO: store the sorted items, to have less work later on - var ordered = []; - var index = 0; - // items is a map (no array) - util.forEach(items, function (item) { - if (item.visible) { - ordered[index] = item; - index++; - } - }); - - //if a customer stack order function exists, use it. - var order = this.options.order || this.defaultOptions.order; - if (!(typeof order === 'function')) { - throw new Error('Option order must be a function'); - } - - ordered.sort(order); - - this.ordered = ordered; -}; - -/** - * Adjust vertical positions of the events such that they don't overlap each - * other. - * @private - */ -Stack.prototype._stack = function _stack () { - var i, - iMax, - ordered = this.ordered, - options = this.options, - orientation = options.orientation || this.defaultOptions.orientation, - axisOnTop = (orientation == 'top'), - margin; - - if (options.margin && options.margin.item !== undefined) { - margin = options.margin.item; - } - else { - margin = this.defaultOptions.margin.item - } - - // calculate new, non-overlapping positions - for (i = 0, iMax = ordered.length; i < iMax; i++) { - var item = ordered[i]; - var collidingItem = null; - do { - // TODO: optimize checking for overlap. when there is a gap without items, - // you only need to check for items from the next item on, not from zero - collidingItem = this.checkOverlap(ordered, i, 0, i - 1, margin); - if (collidingItem != null) { - // There is a collision. Reposition the event above the colliding element - if (axisOnTop) { - item.top = collidingItem.top + collidingItem.height + margin; - } - else { - item.top = collidingItem.top - item.height - margin; - } - } - } while (collidingItem); - } -}; - -/** - * Check if the destiny position of given item overlaps with any - * of the other items from index itemStart to itemEnd. - * @param {Array} items Array with items - * @param {int} itemIndex Number of the item to be checked for overlap - * @param {int} itemStart First item to be checked. - * @param {int} itemEnd Last item to be checked. - * @return {Object | null} colliding item, or undefined when no collisions - * @param {Number} margin A minimum required margin. - * If margin is provided, the two items will be - * marked colliding when they overlap or - * when the margin between the two is smaller than - * the requested margin. - */ -Stack.prototype.checkOverlap = function checkOverlap (items, itemIndex, - itemStart, itemEnd, margin) { - var collision = this.collision; - - // we loop from end to start, as we suppose that the chance of a - // collision is larger for items at the end, so check these first. - var a = items[itemIndex]; - for (var i = itemEnd; i >= itemStart; i--) { - var b = items[i]; - if (collision(a, b, margin)) { - if (i != itemIndex) { - return b; - } - } - } - - return null; -}; - -/** - * Test if the two provided items collide - * The items must have parameters left, width, top, and height. - * @param {Component} a The first item - * @param {Component} b The second item - * @param {Number} margin A minimum required margin. - * If margin is provided, the two items will be - * marked colliding when they overlap or - * when the margin between the two is smaller than - * the requested margin. - * @return {boolean} true if a and b collide, else false - */ -Stack.prototype.collision = function collision (a, b, margin) { - return ((a.left - margin) < (b.left + b.width) && - (a.left + a.width + margin) > b.left && - (a.top - margin) < (b.top + b.height) && - (a.top + a.height + margin) > b.top); -}; - -/** - * @constructor Range - * A Range controls a numeric range with a start and end value. - * The Range adjusts the range based on mouse events or programmatic changes, - * and triggers events when the range is changing or has been changed. - * @param {Object} [options] See description at Range.setOptions - * @extends Controller - */ -function Range(options) { - this.id = util.randomUUID(); - this.start = 0; // Number - this.end = 0; // Number - - // this.options = options || {}; // TODO: fix range options - this.options = { - min: null, - max: null, - zoomMin: null, - zoomMax: null - }; - - this.listeners = []; - - this.setOptions(options); -} - -/** - * Set options for the range controller - * @param {Object} options Available options: - * {Number} start Set start value of the range - * {Number} end Set end value of the range - * {Number} min Minimum value for start - * {Number} max Maximum value for end - * {Number} zoomMin Set a minimum value for - * (end - start). - * {Number} zoomMax Set a maximum value for - * (end - start). - */ -Range.prototype.setOptions = function (options) { - util.extend(this.options, options); - - if (options.start != null || options.end != null) { - this.setRange(options.start, options.end); - } -}; - -/** - * Add listeners for mouse and touch events to the component - * @param {Component} component - * @param {String} event Available events: 'move', 'zoom' - * @param {String} direction Available directions: 'horizontal', 'vertical' - */ -Range.prototype.subscribe = function (component, event, direction) { - var me = this; - var listener; - - if (direction != 'horizontal' && direction != 'vertical') { - throw new TypeError('Unknown direction "' + direction + '". ' + - 'Choose "horizontal" or "vertical".'); - } - - //noinspection FallthroughInSwitchStatementJS - if (event == 'move') { - listener = { - component: component, - event: event, - direction: direction, - callback: function (event) { - me._onMouseDown(event, listener); - }, - params: {} - }; - - component.on('mousedown', listener.callback); - me.listeners.push(listener); - } - else if (event == 'zoom') { - listener = { - component: component, - event: event, - direction: direction, - callback: function (event) { - me._onMouseWheel(event, listener); - }, - params: {} - }; - - component.on('mousewheel', listener.callback); - me.listeners.push(listener); - } - else { - throw new TypeError('Unknown event "' + event + '". ' + - 'Choose "move" or "zoom".'); - } -}; - -/** - * Event handler - * @param {String} event name of the event, for example 'click', 'mousemove' - * @param {function} callback callback handler, invoked with the raw HTML Event - * as parameter. - */ -Range.prototype.on = function (event, callback) { - events.addListener(this, event, callback); -}; - -/** - * Trigger an event - * @param {String} event name of the event, available events: 'rangechange', - * 'rangechanged' - * @private - */ -Range.prototype._trigger = function (event) { - events.trigger(this, event, { - start: this.start, - end: this.end - }); -}; - -/** - * Set a new start and end range - * @param {Number} start - * @param {Number} end - */ -Range.prototype.setRange = function(start, end) { - var changed = this._applyRange(start, end); - if (changed) { - this._trigger('rangechange'); - this._trigger('rangechanged'); - } -}; - -/** - * Set a new start and end range. This method is the same as setRange, but - * does not trigger a range change and range changed event, and it returns - * true when the range is changed - * @param {Number} start - * @param {Number} end - * @return {Boolean} changed - * @private - */ -Range.prototype._applyRange = function(start, end) { - var newStart = (start != null) ? util.convert(start, 'Number') : this.start; - var newEnd = (end != null) ? util.convert(end, 'Number') : this.end; - var diff; - - // check for valid number - if (isNaN(newStart)) { - throw new Error('Invalid start "' + start + '"'); - } - if (isNaN(newEnd)) { - throw new Error('Invalid end "' + end + '"'); - } - - // prevent start < end - if (newEnd < newStart) { - newEnd = newStart; - } - - // prevent start < min - if (this.options.min != null) { - var min = this.options.min.valueOf(); - if (newStart < min) { - diff = (min - newStart); - newStart += diff; - newEnd += diff; - } - } - - // prevent end > max - if (this.options.max != null) { - var max = this.options.max.valueOf(); - if (newEnd > max) { - diff = (newEnd - max); - newStart -= diff; - newEnd -= diff; - } - } - - // prevent (end-start) > zoomMin - if (this.options.zoomMin != null) { - var zoomMin = this.options.zoomMin.valueOf(); - if (zoomMin < 0) { - zoomMin = 0; - } - if ((newEnd - newStart) < zoomMin) { - if ((this.end - this.start) > zoomMin) { - // zoom to the minimum - diff = (zoomMin - (newEnd - newStart)); - newStart -= diff / 2; - newEnd += diff / 2; - } - else { - // ingore this action, we are already zoomed to the minimum - newStart = this.start; - newEnd = this.end; - } - } - } - - // prevent (end-start) > zoomMin - if (this.options.zoomMax != null) { - var zoomMax = this.options.zoomMax.valueOf(); - if (zoomMax < 0) { - zoomMax = 0; - } - if ((newEnd - newStart) > zoomMax) { - if ((this.end - this.start) < zoomMax) { - // zoom to the maximum - diff = ((newEnd - newStart) - zoomMax); - newStart += diff / 2; - newEnd -= diff / 2; - } - else { - // ingore this action, we are already zoomed to the maximum - newStart = this.start; - newEnd = this.end; - } - } - } - - var changed = (this.start != newStart || this.end != newEnd); - - this.start = newStart; - this.end = newEnd; - - return changed; -}; - -/** - * Retrieve the current range. - * @return {Object} An object with start and end properties - */ -Range.prototype.getRange = function() { - return { - start: this.start, - end: this.end - }; -}; - -/** - * Calculate the conversion offset and factor for current range, based on - * the provided width - * @param {Number} width - * @returns {{offset: number, factor: number}} conversion - */ -Range.prototype.conversion = function (width) { - var start = this.start; - var end = this.end; - - return Range.conversion(this.start, this.end, width); -}; - -/** - * Static method to calculate the conversion offset and factor for a range, - * based on the provided start, end, and width - * @param {Number} start - * @param {Number} end - * @param {Number} width - * @returns {{offset: number, factor: number}} conversion - */ -Range.conversion = function (start, end, width) { - if (width != 0 && (end - start != 0)) { - return { - offset: start, - factor: width / (end - start) - } - } - else { - return { - offset: 0, - factor: 1 - }; - } -}; - -/** - * Start moving horizontally or vertically - * @param {Event} event - * @param {Object} listener Listener containing the component and params - * @private - */ -Range.prototype._onMouseDown = function(event, listener) { - event = event || window.event; - var params = listener.params; - - // only react on left mouse button down - var leftButtonDown = event.which ? (event.which == 1) : (event.button == 1); - if (!leftButtonDown) { - return; - } - - // get mouse position - params.mouseX = util.getPageX(event); - params.mouseY = util.getPageY(event); - params.previousLeft = 0; - params.previousOffset = 0; - - params.moved = false; - params.start = this.start; - params.end = this.end; - - var frame = listener.component.frame; - if (frame) { - frame.style.cursor = 'move'; - } - - // add event listeners to handle moving the contents - // we store the function onmousemove and onmouseup in the timeaxis, - // so we can remove the eventlisteners lateron in the function onmouseup - var me = this; - if (!params.onMouseMove) { - params.onMouseMove = function (event) { - me._onMouseMove(event, listener); - }; - util.addEventListener(document, "mousemove", params.onMouseMove); - } - if (!params.onMouseUp) { - params.onMouseUp = function (event) { - me._onMouseUp(event, listener); - }; - util.addEventListener(document, "mouseup", params.onMouseUp); - } - - util.preventDefault(event); -}; - -/** - * Perform moving operating. - * This function activated from within the funcion TimeAxis._onMouseDown(). - * @param {Event} event - * @param {Object} listener - * @private - */ -Range.prototype._onMouseMove = function (event, listener) { - event = event || window.event; - - var params = listener.params; - - // calculate change in mouse position - var mouseX = util.getPageX(event); - var mouseY = util.getPageY(event); - - if (params.mouseX == undefined) { - params.mouseX = mouseX; - } - if (params.mouseY == undefined) { - params.mouseY = mouseY; - } - - var diffX = mouseX - params.mouseX; - var diffY = mouseY - params.mouseY; - var diff = (listener.direction == 'horizontal') ? diffX : diffY; - - // if mouse movement is big enough, register it as a "moved" event - if (Math.abs(diff) >= 1) { - params.moved = true; - } - - var interval = (params.end - params.start); - var width = (listener.direction == 'horizontal') ? - listener.component.width : listener.component.height; - var diffRange = -diff / width * interval; - this._applyRange(params.start + diffRange, params.end + diffRange); - - // fire a rangechange event - this._trigger('rangechange'); - - util.preventDefault(event); -}; - -/** - * Stop moving operating. - * This function activated from within the function Range._onMouseDown(). - * @param {event} event - * @param {Object} listener - * @private - */ -Range.prototype._onMouseUp = function (event, listener) { - event = event || window.event; - - var params = listener.params; - - if (listener.component.frame) { - listener.component.frame.style.cursor = 'auto'; - } - - // remove event listeners here, important for Safari - if (params.onMouseMove) { - util.removeEventListener(document, "mousemove", params.onMouseMove); - params.onMouseMove = null; - } - if (params.onMouseUp) { - util.removeEventListener(document, "mouseup", params.onMouseUp); - params.onMouseUp = null; - } - //util.preventDefault(event); - - if (params.moved) { - // fire a rangechanged event - this._trigger('rangechanged'); - } -}; - -/** - * Event handler for mouse wheel event, used to zoom - * Code from http://adomas.org/javascript-mouse-wheel/ - * @param {Event} event - * @param {Object} listener - * @private - */ -Range.prototype._onMouseWheel = function(event, listener) { - event = event || window.event; - - // retrieve delta - var delta = 0; - if (event.wheelDelta) { /* IE/Opera. */ - delta = event.wheelDelta / 120; - } else if (event.detail) { /* Mozilla case. */ - // In Mozilla, sign of delta is different than in IE. - // Also, delta is multiple of 3. - delta = -event.detail / 3; - } - - // If delta is nonzero, handle it. - // Basically, delta is now positive if wheel was scrolled up, - // and negative, if wheel was scrolled down. - if (delta) { - var me = this; - var zoom = function () { - // perform the zoom action. Delta is normally 1 or -1 - var zoomFactor = delta / 5.0; - var zoomAround = null; - var frame = listener.component.frame; - if (frame) { - var size, conversion; - if (listener.direction == 'horizontal') { - size = listener.component.width; - conversion = me.conversion(size); - var frameLeft = util.getAbsoluteLeft(frame); - var mouseX = util.getPageX(event); - zoomAround = (mouseX - frameLeft) / conversion.factor + conversion.offset; - } - else { - size = listener.component.height; - conversion = me.conversion(size); - var frameTop = util.getAbsoluteTop(frame); - var mouseY = util.getPageY(event); - zoomAround = ((frameTop + size - mouseY) - frameTop) / conversion.factor + conversion.offset; - } - } - - me.zoom(zoomFactor, zoomAround); - }; - - zoom(); - } - - // Prevent default actions caused by mouse wheel. - // That might be ugly, but we handle scrolls somehow - // anyway, so don't bother here... - util.preventDefault(event); -}; - - -/** - * Zoom the range the given zoomfactor in or out. Start and end date will - * be adjusted, and the timeline will be redrawn. You can optionally give a - * date around which to zoom. - * For example, try zoomfactor = 0.1 or -0.1 - * @param {Number} zoomFactor Zooming amount. Positive value will zoom in, - * negative value will zoom out - * @param {Number} zoomAround Value around which will be zoomed. Optional - */ -Range.prototype.zoom = function(zoomFactor, zoomAround) { - // if zoomAroundDate is not provided, take it half between start Date and end Date - if (zoomAround == null) { - zoomAround = (this.start + this.end) / 2; - } - - // prevent zoom factor larger than 1 or smaller than -1 (larger than 1 will - // result in a start>=end ) - if (zoomFactor >= 1) { - zoomFactor = 0.9; - } - if (zoomFactor <= -1) { - zoomFactor = -0.9; - } - - // adjust a negative factor such that zooming in with 0.1 equals zooming - // out with a factor -0.1 - if (zoomFactor < 0) { - zoomFactor = zoomFactor / (1 + zoomFactor); - } - - // zoom start and end relative to the zoomAround value - var startDiff = (this.start - zoomAround); - var endDiff = (this.end - zoomAround); - - // calculate new start and end - var newStart = this.start - startDiff * zoomFactor; - var newEnd = this.end - endDiff * zoomFactor; - - this.setRange(newStart, newEnd); -}; - -/** - * Move the range with a given factor to the left or right. Start and end - * value will be adjusted. For example, try moveFactor = 0.1 or -0.1 - * @param {Number} moveFactor Moving amount. Positive value will move right, - * negative value will move left - */ -Range.prototype.move = function(moveFactor) { - // zoom start Date and end Date relative to the zoomAroundDate - var diff = (this.end - this.start); - - // apply new values - var newStart = this.start + diff * moveFactor; - var newEnd = this.end + diff * moveFactor; - - // TODO: reckon with min and max range - - this.start = newStart; - this.end = newEnd; -}; - -/** - * Move the range to a new center point - * @param {Number} moveTo New center point of the range - */ -Range.prototype.moveTo = function(moveTo) { - var center = (this.start + this.end) / 2; - - var diff = center - moveTo; - - // calculate new start and end - var newStart = this.start - diff; - var newEnd = this.end - diff; - - this.setRange(newStart, newEnd); -} - -/** - * @constructor Controller - * - * A Controller controls the reflows and repaints of all visual components - */ -function Controller () { - this.id = util.randomUUID(); - this.components = {}; - - this.repaintTimer = undefined; - this.reflowTimer = undefined; -} - -/** - * Add a component to the controller - * @param {Component} component - */ -Controller.prototype.add = function add(component) { - // validate the component - if (component.id == undefined) { - throw new Error('Component has no field id'); - } - if (!(component instanceof Component) && !(component instanceof Controller)) { - throw new TypeError('Component must be an instance of ' + - 'prototype Component or Controller'); - } - - // add the component - component.controller = this; - this.components[component.id] = component; -}; - -/** - * Remove a component from the controller - * @param {Component | String} component - */ -Controller.prototype.remove = function remove(component) { - var id; - for (id in this.components) { - if (this.components.hasOwnProperty(id)) { - if (id == component || this.components[id] == component) { - break; - } - } - } - - if (id) { - delete this.components[id]; - } -}; - -/** - * Request a reflow. The controller will schedule a reflow - * @param {Boolean} [force] If true, an immediate reflow is forced. Default - * is false. - */ -Controller.prototype.requestReflow = function requestReflow(force) { - if (force) { - this.reflow(); - } - else { - if (!this.reflowTimer) { - var me = this; - this.reflowTimer = setTimeout(function () { - me.reflowTimer = undefined; - me.reflow(); - }, 0); - } - } -}; - -/** - * Request a repaint. The controller will schedule a repaint - * @param {Boolean} [force] If true, an immediate repaint is forced. Default - * is false. - */ -Controller.prototype.requestRepaint = function requestRepaint(force) { - if (force) { - this.repaint(); - } - else { - if (!this.repaintTimer) { - var me = this; - this.repaintTimer = setTimeout(function () { - me.repaintTimer = undefined; - me.repaint(); - }, 0); - } - } -}; - -/** - * Repaint all components - */ -Controller.prototype.repaint = function repaint() { - var changed = false; - - // cancel any running repaint request - if (this.repaintTimer) { - clearTimeout(this.repaintTimer); - this.repaintTimer = undefined; - } - - var done = {}; - - function repaint(component, id) { - if (!(id in done)) { - // first repaint the components on which this component is dependent - if (component.depends) { - component.depends.forEach(function (dep) { - repaint(dep, dep.id); - }); - } - if (component.parent) { - repaint(component.parent, component.parent.id); - } - - // repaint the component itself and mark as done - changed = component.repaint() || changed; - done[id] = true; - } - } - - util.forEach(this.components, repaint); - - // immediately reflow when needed - if (changed) { - this.reflow(); - } - // TODO: limit the number of nested reflows/repaints, prevent loop -}; - -/** - * Reflow all components - */ -Controller.prototype.reflow = function reflow() { - var resized = false; - - // cancel any running repaint request - if (this.reflowTimer) { - clearTimeout(this.reflowTimer); - this.reflowTimer = undefined; - } - - var done = {}; - - function reflow(component, id) { - if (!(id in done)) { - // first reflow the components on which this component is dependent - if (component.depends) { - component.depends.forEach(function (dep) { - reflow(dep, dep.id); - }); - } - if (component.parent) { - reflow(component.parent, component.parent.id); - } - - // reflow the component itself and mark as done - resized = component.reflow() || resized; - done[id] = true; - } - } - - util.forEach(this.components, reflow); - - // immediately repaint when needed - if (resized) { - this.repaint(); - } - // TODO: limit the number of nested reflows/repaints, prevent loop -}; - -/** - * Prototype for visual components - */ -function Component () { - this.id = null; - this.parent = null; - this.depends = null; - this.controller = null; - this.options = null; - - this.frame = null; // main DOM element - this.top = 0; - this.left = 0; - this.width = 0; - this.height = 0; -} - -/** - * Set parameters for the frame. Parameters will be merged in current parameter - * set. - * @param {Object} options Available parameters: - * {String | function} [className] - * {EventBus} [eventBus] - * {String | Number | function} [left] - * {String | Number | function} [top] - * {String | Number | function} [width] - * {String | Number | function} [height] - */ -Component.prototype.setOptions = function setOptions(options) { - if (options) { - util.extend(this.options, options); - - if (this.controller) { - this.requestRepaint(); - this.requestReflow(); - } - } -}; - -/** - * Get an option value by name - * The function will first check this.options object, and else will check - * this.defaultOptions. - * @param {String} name - * @return {*} value - */ -Component.prototype.getOption = function getOption(name) { - var value; - if (this.options) { - value = this.options[name]; - } - if (value === undefined && this.defaultOptions) { - value = this.defaultOptions[name]; - } - return value; -}; - -/** - * Get the container element of the component, which can be used by a child to - * add its own widgets. Not all components do have a container for childs, in - * that case null is returned. - * @returns {HTMLElement | null} container - */ -// TODO: get rid of the getContainer and getFrame methods, provide these via the options -Component.prototype.getContainer = function getContainer() { - // should be implemented by the component - return null; -}; - -/** - * Get the frame element of the component, the outer HTML DOM element. - * @returns {HTMLElement | null} frame - */ -Component.prototype.getFrame = function getFrame() { - return this.frame; -}; - -/** - * Repaint the component - * @return {Boolean} changed - */ -Component.prototype.repaint = function repaint() { - // should be implemented by the component - return false; -}; - -/** - * Reflow the component - * @return {Boolean} resized - */ -Component.prototype.reflow = function reflow() { - // should be implemented by the component - return false; -}; - -/** - * Hide the component from the DOM - * @return {Boolean} changed - */ -Component.prototype.hide = function hide() { - if (this.frame && this.frame.parentNode) { - this.frame.parentNode.removeChild(this.frame); - return true; - } - else { - return false; - } -}; - -/** - * Show the component in the DOM (when not already visible). - * A repaint will be executed when the component is not visible - * @return {Boolean} changed - */ -Component.prototype.show = function show() { - if (!this.frame || !this.frame.parentNode) { - return this.repaint(); - } - else { - return false; - } -}; - -/** - * Request a repaint. The controller will schedule a repaint - */ -Component.prototype.requestRepaint = function requestRepaint() { - if (this.controller) { - this.controller.requestRepaint(); - } - else { - throw new Error('Cannot request a repaint: no controller configured'); - // TODO: just do a repaint when no parent is configured? - } -}; - -/** - * Request a reflow. The controller will schedule a reflow - */ -Component.prototype.requestReflow = function requestReflow() { - if (this.controller) { - this.controller.requestReflow(); - } - else { - throw new Error('Cannot request a reflow: no controller configured'); - // TODO: just do a reflow when no parent is configured? - } -}; - -/** - * A panel can contain components - * @param {Component} [parent] - * @param {Component[]} [depends] Components on which this components depends - * (except for the parent) - * @param {Object} [options] Available parameters: - * {String | Number | function} [left] - * {String | Number | function} [top] - * {String | Number | function} [width] - * {String | Number | function} [height] - * {String | function} [className] - * @constructor Panel - * @extends Component - */ -function Panel(parent, depends, options) { - this.id = util.randomUUID(); - this.parent = parent; - this.depends = depends; - - this.options = options || {}; -} - -Panel.prototype = new Component(); - -/** - * Set options. Will extend the current options. - * @param {Object} [options] Available parameters: - * {String | function} [className] - * {String | Number | function} [left] - * {String | Number | function} [top] - * {String | Number | function} [width] - * {String | Number | function} [height] - */ -Panel.prototype.setOptions = Component.prototype.setOptions; - -/** - * Get the container element of the panel, which can be used by a child to - * add its own widgets. - * @returns {HTMLElement} container - */ -Panel.prototype.getContainer = function () { - return this.frame; -}; - -/** - * Repaint the component - * @return {Boolean} changed - */ -Panel.prototype.repaint = function () { - var changed = 0, - update = util.updateProperty, - asSize = util.option.asSize, - options = this.options, - frame = this.frame; - if (!frame) { - frame = document.createElement('div'); - frame.className = 'panel'; - - var className = options.className; - if (className) { - if (typeof className == 'function') { - util.addClassName(frame, String(className())); - } - else { - util.addClassName(frame, String(className)); - } - } - - this.frame = frame; - changed += 1; - } - if (!frame.parentNode) { - if (!this.parent) { - throw new Error('Cannot repaint panel: no parent attached'); - } - var parentContainer = this.parent.getContainer(); - if (!parentContainer) { - throw new Error('Cannot repaint panel: parent has no container element'); - } - parentContainer.appendChild(frame); - changed += 1; - } - - changed += update(frame.style, 'top', asSize(options.top, '0px')); - changed += update(frame.style, 'left', asSize(options.left, '0px')); - changed += update(frame.style, 'width', asSize(options.width, '100%')); - changed += update(frame.style, 'height', asSize(options.height, '100%')); - - return (changed > 0); -}; - -/** - * Reflow the component - * @return {Boolean} resized - */ -Panel.prototype.reflow = function () { - var changed = 0, - update = util.updateProperty, - frame = this.frame; - - if (frame) { - changed += update(this, 'top', frame.offsetTop); - changed += update(this, 'left', frame.offsetLeft); - changed += update(this, 'width', frame.offsetWidth); - changed += update(this, 'height', frame.offsetHeight); - } - else { - changed += 1; - } - - return (changed > 0); -}; - -/** - * A root panel can hold components. The root panel must be initialized with - * a DOM element as container. - * @param {HTMLElement} container - * @param {Object} [options] Available parameters: see RootPanel.setOptions. - * @constructor RootPanel - * @extends Panel - */ -function RootPanel(container, options) { - this.id = util.randomUUID(); - this.container = container; - - this.options = options || {}; - this.defaultOptions = { - autoResize: true - }; - - this.listeners = {}; // event listeners -} - -RootPanel.prototype = new Panel(); - -/** - * Set options. Will extend the current options. - * @param {Object} [options] Available parameters: - * {String | function} [className] - * {String | Number | function} [left] - * {String | Number | function} [top] - * {String | Number | function} [width] - * {String | Number | function} [height] - * {Boolean | function} [autoResize] - */ -RootPanel.prototype.setOptions = Component.prototype.setOptions; - -/** - * Repaint the component - * @return {Boolean} changed - */ -RootPanel.prototype.repaint = function () { - var changed = 0, - update = util.updateProperty, - asSize = util.option.asSize, - options = this.options, - frame = this.frame; - - if (!frame) { - frame = document.createElement('div'); - frame.className = 'vis timeline rootpanel'; - - var className = options.className; - if (className) { - util.addClassName(frame, util.option.asString(className)); - } - - this.frame = frame; - - changed += 1; - } - if (!frame.parentNode) { - if (!this.container) { - throw new Error('Cannot repaint root panel: no container attached'); - } - this.container.appendChild(frame); - changed += 1; - } - - changed += update(frame.style, 'top', asSize(options.top, '0px')); - changed += update(frame.style, 'left', asSize(options.left, '0px')); - changed += update(frame.style, 'width', asSize(options.width, '100%')); - changed += update(frame.style, 'height', asSize(options.height, '100%')); - - this._updateEventEmitters(); - this._updateWatch(); - - return (changed > 0); -}; - -/** - * Reflow the component - * @return {Boolean} resized - */ -RootPanel.prototype.reflow = function () { - var changed = 0, - update = util.updateProperty, - frame = this.frame; - - if (frame) { - changed += update(this, 'top', frame.offsetTop); - changed += update(this, 'left', frame.offsetLeft); - changed += update(this, 'width', frame.offsetWidth); - changed += update(this, 'height', frame.offsetHeight); - } - else { - changed += 1; - } - - return (changed > 0); -}; - -/** - * Update watching for resize, depending on the current option - * @private - */ -RootPanel.prototype._updateWatch = function () { - var autoResize = this.getOption('autoResize'); - if (autoResize) { - this._watch(); - } - else { - this._unwatch(); - } -}; - -/** - * Watch for changes in the size of the frame. On resize, the Panel will - * automatically redraw itself. - * @private - */ -RootPanel.prototype._watch = function () { - var me = this; - - this._unwatch(); - - var checkSize = function () { - var autoResize = me.getOption('autoResize'); - if (!autoResize) { - // stop watching when the option autoResize is changed to false - me._unwatch(); - return; - } - - if (me.frame) { - // check whether the frame is resized - if ((me.frame.clientWidth != me.width) || - (me.frame.clientHeight != me.height)) { - me.requestReflow(); - } - } - }; - - // TODO: automatically cleanup the event listener when the frame is deleted - util.addEventListener(window, 'resize', checkSize); - - this.watchTimer = setInterval(checkSize, 1000); -}; - -/** - * Stop watching for a resize of the frame. - * @private - */ -RootPanel.prototype._unwatch = function () { - if (this.watchTimer) { - clearInterval(this.watchTimer); - this.watchTimer = undefined; - } - - // TODO: remove event listener on window.resize -}; - -/** - * Event handler - * @param {String} event name of the event, for example 'click', 'mousemove' - * @param {function} callback callback handler, invoked with the raw HTML Event - * as parameter. - */ -RootPanel.prototype.on = function (event, callback) { - // register the listener at this component - var arr = this.listeners[event]; - if (!arr) { - arr = []; - this.listeners[event] = arr; - } - arr.push(callback); - - this._updateEventEmitters(); -}; - -/** - * Update the event listeners for all event emitters - * @private - */ -RootPanel.prototype._updateEventEmitters = function () { - if (this.listeners) { - var me = this; - util.forEach(this.listeners, function (listeners, event) { - if (!me.emitters) { - me.emitters = {}; - } - if (!(event in me.emitters)) { - // create event - var frame = me.frame; - if (frame) { - //console.log('Created a listener for event ' + event + ' on component ' + me.id); // TODO: cleanup logging - var callback = function(event) { - listeners.forEach(function (listener) { - // TODO: filter on event target! - listener(event); - }); - }; - me.emitters[event] = callback; - util.addEventListener(frame, event, callback); - } - } - }); - - // TODO: be able to delete event listeners - // TODO: be able to move event listeners to a parent when available - } -}; - -/** - * A horizontal time axis - * @param {Component} parent - * @param {Component[]} [depends] Components on which this components depends - * (except for the parent) - * @param {Object} [options] See TimeAxis.setOptions for the available - * options. - * @constructor TimeAxis - * @extends Component - */ -function TimeAxis (parent, depends, options) { - this.id = util.randomUUID(); - this.parent = parent; - this.depends = depends; - - this.dom = { - majorLines: [], - majorTexts: [], - minorLines: [], - minorTexts: [], - redundant: { - majorLines: [], - majorTexts: [], - minorLines: [], - minorTexts: [] - } - }; - this.props = { - range: { - start: 0, - end: 0, - minimumStep: 0 - }, - lineTop: 0 - }; - - this.options = options || {}; - this.defaultOptions = { - orientation: 'bottom', // supported: 'top', 'bottom' - // TODO: implement timeaxis orientations 'left' and 'right' - showMinorLabels: true, - showMajorLabels: true - }; - - this.conversion = null; - this.range = null; -} - -TimeAxis.prototype = new Component(); - -// TODO: comment options -TimeAxis.prototype.setOptions = Component.prototype.setOptions; - -/** - * Set a range (start and end) - * @param {Range | Object} range A Range or an object containing start and end. - */ -TimeAxis.prototype.setRange = function (range) { - if (!(range instanceof Range) && (!range || !range.start || !range.end)) { - throw new TypeError('Range must be an instance of Range, ' + - 'or an object containing start and end.'); - } - this.range = range; -}; - -/** - * Convert a position on screen (pixels) to a datetime - * @param {int} x Position on the screen in pixels - * @return {Date} time The datetime the corresponds with given position x - */ -TimeAxis.prototype.toTime = function(x) { - var conversion = this.conversion; - return new Date(x / conversion.factor + conversion.offset); -}; - -/** - * Convert a datetime (Date object) into a position on the screen - * @param {Date} time A date - * @return {int} x The position on the screen in pixels which corresponds - * with the given date. - * @private - */ -TimeAxis.prototype.toScreen = function(time) { - var conversion = this.conversion; - return (time.valueOf() - conversion.offset) * conversion.factor; -}; - -/** - * Repaint the component - * @return {Boolean} changed - */ -TimeAxis.prototype.repaint = function () { - var changed = 0, - update = util.updateProperty, - asSize = util.option.asSize, - options = this.options, - orientation = this.getOption('orientation'), - props = this.props, - step = this.step; - - var frame = this.frame; - if (!frame) { - frame = document.createElement('div'); - this.frame = frame; - changed += 1; - } - frame.className = 'axis ' + orientation; - // TODO: custom className? - - if (!frame.parentNode) { - if (!this.parent) { - throw new Error('Cannot repaint time axis: no parent attached'); - } - var parentContainer = this.parent.getContainer(); - if (!parentContainer) { - throw new Error('Cannot repaint time axis: parent has no container element'); - } - parentContainer.appendChild(frame); - - changed += 1; - } - - var parent = frame.parentNode; - if (parent) { - var beforeChild = frame.nextSibling; - parent.removeChild(frame); // take frame offline while updating (is almost twice as fast) - - var defaultTop = (orientation == 'bottom' && this.props.parentHeight && this.height) ? - (this.props.parentHeight - this.height) + 'px' : - '0px'; - changed += update(frame.style, 'top', asSize(options.top, defaultTop)); - changed += update(frame.style, 'left', asSize(options.left, '0px')); - changed += update(frame.style, 'width', asSize(options.width, '100%')); - changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); - - // get characters width and height - this._repaintMeasureChars(); - - if (this.step) { - this._repaintStart(); - - step.first(); - var xFirstMajorLabel = undefined; - var max = 0; - while (step.hasNext() && max < 1000) { - max++; - var cur = step.getCurrent(), - x = this.toScreen(cur), - isMajor = step.isMajor(); - - // TODO: lines must have a width, such that we can create css backgrounds - - if (this.getOption('showMinorLabels')) { - this._repaintMinorText(x, step.getLabelMinor()); - } - - if (isMajor && this.getOption('showMajorLabels')) { - if (x > 0) { - if (xFirstMajorLabel == undefined) { - xFirstMajorLabel = x; - } - this._repaintMajorText(x, step.getLabelMajor()); - } - this._repaintMajorLine(x); - } - else { - this._repaintMinorLine(x); - } - - step.next(); - } - - // create a major label on the left when needed - if (this.getOption('showMajorLabels')) { - var leftTime = this.toTime(0), - leftText = step.getLabelMajor(leftTime), - widthText = leftText.length * (props.majorCharWidth || 10) + 10; // upper bound estimation - - if (xFirstMajorLabel == undefined || widthText < xFirstMajorLabel) { - this._repaintMajorText(0, leftText); - } - } - - this._repaintEnd(); - } - - this._repaintLine(); - - // put frame online again - if (beforeChild) { - parent.insertBefore(frame, beforeChild); - } - else { - parent.appendChild(frame) - } - } - - return (changed > 0); -}; - -/** - * Start a repaint. Move all DOM elements to a redundant list, where they - * can be picked for re-use, or can be cleaned up in the end - * @private - */ -TimeAxis.prototype._repaintStart = function () { - var dom = this.dom, - redundant = dom.redundant; - - redundant.majorLines = dom.majorLines; - redundant.majorTexts = dom.majorTexts; - redundant.minorLines = dom.minorLines; - redundant.minorTexts = dom.minorTexts; - - dom.majorLines = []; - dom.majorTexts = []; - dom.minorLines = []; - dom.minorTexts = []; -}; - -/** - * End a repaint. Cleanup leftover DOM elements in the redundant list - * @private - */ -TimeAxis.prototype._repaintEnd = function () { - util.forEach(this.dom.redundant, function (arr) { - while (arr.length) { - var elem = arr.pop(); - if (elem && elem.parentNode) { - elem.parentNode.removeChild(elem); - } - } - }); -}; - - -/** - * Create a minor label for the axis at position x - * @param {Number} x - * @param {String} text - * @private - */ -TimeAxis.prototype._repaintMinorText = function (x, text) { - // reuse redundant label - var label = this.dom.redundant.minorTexts.shift(); - - if (!label) { - // create new label - var content = document.createTextNode(''); - label = document.createElement('div'); - label.appendChild(content); - label.className = 'text minor'; - this.frame.appendChild(label); - } - this.dom.minorTexts.push(label); - - label.childNodes[0].nodeValue = text; - label.style.left = x + 'px'; - label.style.top = this.props.minorLabelTop + 'px'; - //label.title = title; // TODO: this is a heavy operation -}; - -/** - * Create a Major label for the axis at position x - * @param {Number} x - * @param {String} text - * @private - */ -TimeAxis.prototype._repaintMajorText = function (x, text) { - // reuse redundant label - var label = this.dom.redundant.majorTexts.shift(); - - if (!label) { - // create label - var content = document.createTextNode(text); - label = document.createElement('div'); - label.className = 'text major'; - label.appendChild(content); - this.frame.appendChild(label); - } - this.dom.majorTexts.push(label); - - label.childNodes[0].nodeValue = text; - label.style.top = this.props.majorLabelTop + 'px'; - label.style.left = x + 'px'; - //label.title = title; // TODO: this is a heavy operation -}; - -/** - * Create a minor line for the axis at position x - * @param {Number} x - * @private - */ -TimeAxis.prototype._repaintMinorLine = function (x) { - // reuse redundant line - var line = this.dom.redundant.minorLines.shift(); - - if (!line) { - // create vertical line - line = document.createElement('div'); - line.className = 'grid vertical minor'; - this.frame.appendChild(line); - } - this.dom.minorLines.push(line); - - var props = this.props; - line.style.top = props.minorLineTop + 'px'; - line.style.height = props.minorLineHeight + 'px'; - line.style.left = (x - props.minorLineWidth / 2) + 'px'; -}; - -/** - * Create a Major line for the axis at position x - * @param {Number} x - * @private - */ -TimeAxis.prototype._repaintMajorLine = function (x) { - // reuse redundant line - var line = this.dom.redundant.majorLines.shift(); - - if (!line) { - // create vertical line - line = document.createElement('DIV'); - line.className = 'grid vertical major'; - this.frame.appendChild(line); - } - this.dom.majorLines.push(line); - - var props = this.props; - line.style.top = props.majorLineTop + 'px'; - line.style.left = (x - props.majorLineWidth / 2) + 'px'; - line.style.height = props.majorLineHeight + 'px'; -}; - - -/** - * Repaint the horizontal line for the axis - * @private - */ -TimeAxis.prototype._repaintLine = function() { - var line = this.dom.line, - frame = this.frame, - options = this.options; - - // line before all axis elements - if (this.getOption('showMinorLabels') || this.getOption('showMajorLabels')) { - if (line) { - // put this line at the end of all childs - frame.removeChild(line); - frame.appendChild(line); - } - else { - // create the axis line - line = document.createElement('div'); - line.className = 'grid horizontal major'; - frame.appendChild(line); - this.dom.line = line; - } - - line.style.top = this.props.lineTop + 'px'; - } - else { - if (line && axis.parentElement) { - frame.removeChild(axis.line); - delete this.dom.line; - } - } -}; - -/** - * Create characters used to determine the size of text on the axis - * @private - */ -TimeAxis.prototype._repaintMeasureChars = function () { - // calculate the width and height of a single character - // this is used to calculate the step size, and also the positioning of the - // axis - var dom = this.dom, - text; - - if (!dom.measureCharMinor) { - text = document.createTextNode('0'); - var measureCharMinor = document.createElement('DIV'); - measureCharMinor.className = 'text minor measure'; - measureCharMinor.appendChild(text); - this.frame.appendChild(measureCharMinor); - - dom.measureCharMinor = measureCharMinor; - } - - if (!dom.measureCharMajor) { - text = document.createTextNode('0'); - var measureCharMajor = document.createElement('DIV'); - measureCharMajor.className = 'text major measure'; - measureCharMajor.appendChild(text); - this.frame.appendChild(measureCharMajor); - - dom.measureCharMajor = measureCharMajor; - } -}; - -/** - * Reflow the component - * @return {Boolean} resized - */ -TimeAxis.prototype.reflow = function () { - var changed = 0, - update = util.updateProperty, - frame = this.frame, - range = this.range; - - if (!range) { - throw new Error('Cannot repaint time axis: no range configured'); - } - - if (frame) { - changed += update(this, 'top', frame.offsetTop); - changed += update(this, 'left', frame.offsetLeft); - - // calculate size of a character - var props = this.props, - showMinorLabels = this.getOption('showMinorLabels'), - showMajorLabels = this.getOption('showMajorLabels'), - measureCharMinor = this.dom.measureCharMinor, - measureCharMajor = this.dom.measureCharMajor; - if (measureCharMinor) { - props.minorCharHeight = measureCharMinor.clientHeight; - props.minorCharWidth = measureCharMinor.clientWidth; - } - if (measureCharMajor) { - props.majorCharHeight = measureCharMajor.clientHeight; - props.majorCharWidth = measureCharMajor.clientWidth; - } - - var parentHeight = frame.parentNode ? frame.parentNode.offsetHeight : 0; - if (parentHeight != props.parentHeight) { - props.parentHeight = parentHeight; - changed += 1; - } - switch (this.getOption('orientation')) { - case 'bottom': - props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; - props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; - - props.minorLabelTop = 0; - props.majorLabelTop = props.minorLabelTop + props.minorLabelHeight; - - props.minorLineTop = -this.top; - props.minorLineHeight = Math.max(this.top + props.majorLabelHeight, 0); - props.minorLineWidth = 1; // TODO: really calculate width - - props.majorLineTop = -this.top; - props.majorLineHeight = Math.max(this.top + props.minorLabelHeight + props.majorLabelHeight, 0); - props.majorLineWidth = 1; // TODO: really calculate width - - props.lineTop = 0; - - break; - - case 'top': - props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; - props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; - - props.majorLabelTop = 0; - props.minorLabelTop = props.majorLabelTop + props.majorLabelHeight; - - props.minorLineTop = props.minorLabelTop; - props.minorLineHeight = Math.max(parentHeight - props.majorLabelHeight - this.top); - props.minorLineWidth = 1; // TODO: really calculate width - - props.majorLineTop = 0; - props.majorLineHeight = Math.max(parentHeight - this.top); - props.majorLineWidth = 1; // TODO: really calculate width - - props.lineTop = props.majorLabelHeight + props.minorLabelHeight; - - break; - - default: - throw new Error('Unkown orientation "' + this.getOption('orientation') + '"'); - } - - var height = props.minorLabelHeight + props.majorLabelHeight; - changed += update(this, 'width', frame.offsetWidth); - changed += update(this, 'height', height); - - // calculate range and step - this._updateConversion(); - - var start = util.convert(range.start, 'Date'), - end = util.convert(range.end, 'Date'), - minimumStep = this.toTime((props.minorCharWidth || 10) * 5) - this.toTime(0); - this.step = new TimeStep(start, end, minimumStep); - changed += update(props.range, 'start', start.valueOf()); - changed += update(props.range, 'end', end.valueOf()); - changed += update(props.range, 'minimumStep', minimumStep.valueOf()); - } - - return (changed > 0); -}; - -/** - * Calculate the factor and offset to convert a position on screen to the - * corresponding date and vice versa. - * After the method _updateConversion is executed once, the methods toTime - * and toScreen can be used. - * @private - */ -TimeAxis.prototype._updateConversion = function() { - var range = this.range; - if (!range) { - throw new Error('No range configured'); - } - - if (range.conversion) { - this.conversion = range.conversion(this.width); - } - else { - this.conversion = Range.conversion(range.start, range.end, this.width); - } -}; - -/** - * An ItemSet holds a set of items and ranges which can be displayed in a - * range. The width is determined by the parent of the ItemSet, and the height - * is determined by the size of the items. - * @param {Component} parent - * @param {Component[]} [depends] Components on which this components depends - * (except for the parent) - * @param {Object} [options] See ItemSet.setOptions for the available - * options. - * @constructor ItemSet - * @extends Panel - */ -// TODO: improve performance by replacing all Array.forEach with a for loop -function ItemSet(parent, depends, options) { - this.id = util.randomUUID(); - this.parent = parent; - this.depends = depends; - - // one options object is shared by this itemset and all its items - this.options = options || {}; - this.defaultOptions = { - type: 'box', - align: 'center', - orientation: 'bottom', - margin: { - axis: 20, - item: 10 - }, - padding: 5 - }; - - this.dom = {}; - - var me = this; - this.itemsData = null; // DataSet - this.range = null; // Range or Object {start: number, end: number} - - this.listeners = { - 'add': function (event, params, senderId) { - if (senderId != me.id) { - me._onAdd(params.items); - } - }, - 'update': function (event, params, senderId) { - if (senderId != me.id) { - me._onUpdate(params.items); - } - }, - 'remove': function (event, params, senderId) { - if (senderId != me.id) { - me._onRemove(params.items); - } - } - }; - - this.items = {}; // object with an Item for every data item - this.queue = {}; // queue with id/actions: 'add', 'update', 'delete' - this.stack = new Stack(this, Object.create(this.options)); - this.conversion = null; - - // TODO: ItemSet should also attach event listeners for rangechange and rangechanged, like timeaxis -} - -ItemSet.prototype = new Panel(); - -// available item types will be registered here -ItemSet.types = { - box: ItemBox, - range: ItemRange, - point: ItemPoint -}; - -/** - * Set options for the ItemSet. Existing options will be extended/overwritten. - * @param {Object} [options] The following options are available: - * {String | function} [className] - * class name for the itemset - * {String} [type] - * Default type for the items. Choose from 'box' - * (default), 'point', or 'range'. The default - * Style can be overwritten by individual items. - * {String} align - * Alignment for the items, only applicable for - * ItemBox. Choose 'center' (default), 'left', or - * 'right'. - * {String} orientation - * Orientation of the item set. Choose 'top' or - * 'bottom' (default). - * {Number} margin.axis - * Margin between the axis and the items in pixels. - * Default is 20. - * {Number} margin.item - * Margin between items in pixels. Default is 10. - * {Number} padding - * Padding of the contents of an item in pixels. - * Must correspond with the items css. Default is 5. - */ -ItemSet.prototype.setOptions = Component.prototype.setOptions; - -/** - * Set range (start and end). - * @param {Range | Object} range A Range or an object containing start and end. - */ -ItemSet.prototype.setRange = function setRange(range) { - if (!(range instanceof Range) && (!range || !range.start || !range.end)) { - throw new TypeError('Range must be an instance of Range, ' + - 'or an object containing start and end.'); - } - this.range = range; -}; - -/** - * Repaint the component - * @return {Boolean} changed - */ -ItemSet.prototype.repaint = function repaint() { - var changed = 0, - update = util.updateProperty, - asSize = util.option.asSize, - options = this.options, - orientation = this.getOption('orientation'), - defaultOptions = this.defaultOptions, - frame = this.frame; - - if (!frame) { - frame = document.createElement('div'); - frame.className = 'itemset'; - - var className = options.className; - if (className) { - util.addClassName(frame, util.option.asString(className)); - } - - // create background panel - var background = document.createElement('div'); - background.className = 'background'; - frame.appendChild(background); - this.dom.background = background; - - // create foreground panel - var foreground = document.createElement('div'); - foreground.className = 'foreground'; - frame.appendChild(foreground); - this.dom.foreground = foreground; - - // create axis panel - var axis = document.createElement('div'); - axis.className = 'itemset-axis'; - //frame.appendChild(axis); - this.dom.axis = axis; - - this.frame = frame; - changed += 1; - } - - if (!this.parent) { - throw new Error('Cannot repaint itemset: no parent attached'); - } - var parentContainer = this.parent.getContainer(); - if (!parentContainer) { - throw new Error('Cannot repaint itemset: parent has no container element'); - } - if (!frame.parentNode) { - parentContainer.appendChild(frame); - changed += 1; - } - if (!this.dom.axis.parentNode) { - parentContainer.appendChild(this.dom.axis); - changed += 1; - } - - // reposition frame - changed += update(frame.style, 'left', asSize(options.left, '0px')); - changed += update(frame.style, 'top', asSize(options.top, '0px')); - changed += update(frame.style, 'width', asSize(options.width, '100%')); - changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); - - // reposition axis - changed += update(this.dom.axis.style, 'left', asSize(options.left, '0px')); - changed += update(this.dom.axis.style, 'width', asSize(options.width, '100%')); - if (orientation == 'bottom') { - changed += update(this.dom.axis.style, 'top', (this.height + this.top) + 'px'); - } - else { // orientation == 'top' - changed += update(this.dom.axis.style, 'top', this.top + 'px'); - } - - this._updateConversion(); - - var me = this, - queue = this.queue, - itemsData = this.itemsData, - items = this.items, - dataOptions = { - // TODO: cleanup - // fields: [(itemsData && itemsData.fieldId || 'id'), 'start', 'end', 'content', 'type', 'className'] - }; - - // show/hide added/changed/removed items - Object.keys(queue).forEach(function (id) { - //var entry = queue[id]; - var action = queue[id]; - var item = items[id]; - //var item = entry.item; - //noinspection FallthroughInSwitchStatementJS - switch (action) { - case 'add': - case 'update': - var itemData = itemsData && itemsData.get(id, dataOptions); - - if (itemData) { - var type = itemData.type || - (itemData.start && itemData.end && 'range') || - options.type || - 'box'; - var constructor = ItemSet.types[type]; - - // TODO: how to handle items with invalid data? hide them and give a warning? or throw an error? - if (item) { - // update item - if (!constructor || !(item instanceof constructor)) { - // item type has changed, hide and delete the item - changed += item.hide(); - item = null; - } - else { - item.data = itemData; // TODO: create a method item.setData ? - changed++; - } - } - - if (!item) { - // create item - if (constructor) { - item = new constructor(me, itemData, options, defaultOptions); - changed++; - } - else { - throw new TypeError('Unknown item type "' + type + '"'); - } - } - - // force a repaint (not only a reposition) - item.repaint(); - - items[id] = item; - } - - // update queue - delete queue[id]; - break; - - case 'remove': - if (item) { - // remove DOM of the item - changed += item.hide(); - } - - // update lists - delete items[id]; - delete queue[id]; - break; - - default: - console.log('Error: unknown action "' + action + '"'); - } - }); - - // reposition all items. Show items only when in the visible area - util.forEach(this.items, function (item) { - if (item.visible) { - changed += item.show(); - item.reposition(); - } - else { - changed += item.hide(); - } - }); - - return (changed > 0); -}; - -/** - * Get the foreground container element - * @return {HTMLElement} foreground - */ -ItemSet.prototype.getForeground = function getForeground() { - return this.dom.foreground; -}; - -/** - * Get the background container element - * @return {HTMLElement} background - */ -ItemSet.prototype.getBackground = function getBackground() { - return this.dom.background; -}; - -/** - * Get the axis container element - * @return {HTMLElement} axis - */ -ItemSet.prototype.getAxis = function getAxis() { - return this.dom.axis; -}; - -/** - * Reflow the component - * @return {Boolean} resized - */ -ItemSet.prototype.reflow = function reflow () { - var changed = 0, - options = this.options, - marginAxis = options.margin && options.margin.axis || this.defaultOptions.margin.axis, - marginItem = options.margin && options.margin.item || this.defaultOptions.margin.item, - update = util.updateProperty, - asNumber = util.option.asNumber, - asSize = util.option.asSize, - frame = this.frame; - - if (frame) { - this._updateConversion(); - - util.forEach(this.items, function (item) { - changed += item.reflow(); - }); - - // TODO: stack.update should be triggered via an event, in stack itself - // TODO: only update the stack when there are changed items - this.stack.update(); - - var maxHeight = asNumber(options.maxHeight); - var fixedHeight = (asSize(options.height) != null); - var height; - if (fixedHeight) { - height = frame.offsetHeight; - } - else { - // height is not specified, determine the height from the height and positioned items - var visibleItems = this.stack.ordered; // TODO: not so nice way to get the filtered items - if (visibleItems.length) { - var min = visibleItems[0].top; - var max = visibleItems[0].top + visibleItems[0].height; - util.forEach(visibleItems, function (item) { - min = Math.min(min, item.top); - max = Math.max(max, (item.top + item.height)); - }); - height = (max - min) + marginAxis + marginItem; - } - else { - height = marginAxis + marginItem; - } - } - if (maxHeight != null) { - height = Math.min(height, maxHeight); - } - changed += update(this, 'height', height); - - // calculate height from items - changed += update(this, 'top', frame.offsetTop); - changed += update(this, 'left', frame.offsetLeft); - changed += update(this, 'width', frame.offsetWidth); - } - else { - changed += 1; - } - - return (changed > 0); -}; - -/** - * Hide this component from the DOM - * @return {Boolean} changed - */ -ItemSet.prototype.hide = function hide() { - var changed = false; - - // remove the DOM - if (this.frame && this.frame.parentNode) { - this.frame.parentNode.removeChild(this.frame); - changed = true; - } - if (this.dom.axis && this.dom.axis.parentNode) { - this.dom.axis.parentNode.removeChild(this.dom.axis); - changed = true; - } - - return changed; -}; - -/** - * Set items - * @param {vis.DataSet | null} items - */ -ItemSet.prototype.setItems = function setItems(items) { - var me = this, - ids, - oldItemsData = this.itemsData; - - // replace the dataset - if (!items) { - this.itemsData = null; - } - else if (items instanceof DataSet || items instanceof DataView) { - this.itemsData = items; - } - else { - throw new TypeError('Data must be an instance of DataSet'); - } - - if (oldItemsData) { - // unsubscribe from old dataset - util.forEach(this.listeners, function (callback, event) { - oldItemsData.unsubscribe(event, callback); - }); - - // remove all drawn items - ids = oldItemsData.getIds(); - this._onRemove(ids); - } - - if (this.itemsData) { - // subscribe to new dataset - var id = this.id; - util.forEach(this.listeners, function (callback, event) { - me.itemsData.subscribe(event, callback, id); - }); - - // draw all new items - ids = this.itemsData.getIds(); - this._onAdd(ids); - } -}; - -/** - * Get the current items items - * @returns {vis.DataSet | null} - */ -ItemSet.prototype.getItems = function getItems() { - return this.itemsData; -}; - -/** - * Handle updated items - * @param {Number[]} ids - * @private - */ -ItemSet.prototype._onUpdate = function _onUpdate(ids) { - this._toQueue('update', ids); -}; - -/** - * Handle changed items - * @param {Number[]} ids - * @private - */ -ItemSet.prototype._onAdd = function _onAdd(ids) { - this._toQueue('add', ids); -}; - -/** - * Handle removed items - * @param {Number[]} ids - * @private - */ -ItemSet.prototype._onRemove = function _onRemove(ids) { - this._toQueue('remove', ids); -}; - -/** - * Put items in the queue to be added/updated/remove - * @param {String} action can be 'add', 'update', 'remove' - * @param {Number[]} ids - */ -ItemSet.prototype._toQueue = function _toQueue(action, ids) { - var queue = this.queue; - ids.forEach(function (id) { - queue[id] = action; - }); - - if (this.controller) { - //this.requestReflow(); - this.requestRepaint(); - } -}; - -/** - * Calculate the factor and offset to convert a position on screen to the - * corresponding date and vice versa. - * After the method _updateConversion is executed once, the methods toTime - * and toScreen can be used. - * @private - */ -ItemSet.prototype._updateConversion = function _updateConversion() { - var range = this.range; - if (!range) { - throw new Error('No range configured'); - } - - if (range.conversion) { - this.conversion = range.conversion(this.width); - } - else { - this.conversion = Range.conversion(range.start, range.end, this.width); - } -}; - -/** - * Convert a position on screen (pixels) to a datetime - * Before this method can be used, the method _updateConversion must be - * executed once. - * @param {int} x Position on the screen in pixels - * @return {Date} time The datetime the corresponds with given position x - */ -ItemSet.prototype.toTime = function toTime(x) { - var conversion = this.conversion; - return new Date(x / conversion.factor + conversion.offset); -}; - -/** - * Convert a datetime (Date object) into a position on the screen - * Before this method can be used, the method _updateConversion must be - * executed once. - * @param {Date} time A date - * @return {int} x The position on the screen in pixels which corresponds - * with the given date. - */ -ItemSet.prototype.toScreen = function toScreen(time) { - var conversion = this.conversion; - return (time.valueOf() - conversion.offset) * conversion.factor; -}; - -/** - * @constructor Item - * @param {ItemSet} parent - * @param {Object} data Object containing (optional) parameters type, - * start, end, content, group, className. - * @param {Object} [options] Options to set initial property values - * @param {Object} [defaultOptions] default options - * // TODO: describe available options - */ -function Item (parent, data, options, defaultOptions) { - this.parent = parent; - this.data = data; - this.dom = null; - this.options = options || {}; - this.defaultOptions = defaultOptions || {}; - - this.selected = false; - this.visible = false; - this.top = 0; - this.left = 0; - this.width = 0; - this.height = 0; -} - -/** - * Select current item - */ -Item.prototype.select = function select() { - this.selected = true; -}; - -/** - * Unselect current item - */ -Item.prototype.unselect = function unselect() { - this.selected = false; -}; - -/** - * Show the Item in the DOM (when not already visible) - * @return {Boolean} changed - */ -Item.prototype.show = function show() { - return false; -}; - -/** - * Hide the Item from the DOM (when visible) - * @return {Boolean} changed - */ -Item.prototype.hide = function hide() { - return false; -}; - -/** - * Repaint the item - * @return {Boolean} changed - */ -Item.prototype.repaint = function repaint() { - // should be implemented by the item - return false; -}; - -/** - * Reflow the item - * @return {Boolean} resized - */ -Item.prototype.reflow = function reflow() { - // should be implemented by the item - return false; -}; - -/** - * @constructor ItemBox - * @extends Item - * @param {ItemSet} parent - * @param {Object} data Object containing parameters start - * content, className. - * @param {Object} [options] Options to set initial property values - * @param {Object} [defaultOptions] default options - * // TODO: describe available options - */ -function ItemBox (parent, data, options, defaultOptions) { - this.props = { - dot: { - left: 0, - top: 0, - width: 0, - height: 0 - }, - line: { - top: 0, - left: 0, - width: 0, - height: 0 - } - }; - - Item.call(this, parent, data, options, defaultOptions); -} - -ItemBox.prototype = new Item (null, null); - -/** - * Select the item - * @override - */ -ItemBox.prototype.select = function select() { - this.selected = true; - // TODO: select and unselect -}; - -/** - * Unselect the item - * @override - */ -ItemBox.prototype.unselect = function unselect() { - this.selected = false; - // TODO: select and unselect -}; - -/** - * Repaint the item - * @return {Boolean} changed - */ -ItemBox.prototype.repaint = function repaint() { - // TODO: make an efficient repaint - var changed = false; - var dom = this.dom; - - if (!dom) { - this._create(); - dom = this.dom; - changed = true; - } - - if (dom) { - if (!this.parent) { - throw new Error('Cannot repaint item: no parent attached'); - } - var foreground = this.parent.getForeground(); - if (!foreground) { - throw new Error('Cannot repaint time axis: ' + - 'parent has no foreground container element'); - } - var background = this.parent.getBackground(); - if (!background) { - throw new Error('Cannot repaint time axis: ' + - 'parent has no background container element'); - } - var axis = this.parent.getAxis(); - if (!background) { - throw new Error('Cannot repaint time axis: ' + - 'parent has no axis container element'); - } - - if (!dom.box.parentNode) { - foreground.appendChild(dom.box); - changed = true; - } - if (!dom.line.parentNode) { - background.appendChild(dom.line); - changed = true; - } - if (!dom.dot.parentNode) { - axis.appendChild(dom.dot); - changed = true; - } - - // update contents - if (this.data.content != this.content) { - this.content = this.data.content; - if (this.content instanceof Element) { - dom.content.innerHTML = ''; - dom.content.appendChild(this.content); - } - else if (this.data.content != undefined) { - dom.content.innerHTML = this.content; - } - else { - throw new Error('Property "content" missing in item ' + this.data.id); - } - changed = true; - } - - // update class - var className = (this.data.className? ' ' + this.data.className : '') + - (this.selected ? ' selected' : ''); - if (this.className != className) { - this.className = className; - dom.box.className = 'item box' + className; - dom.line.className = 'item line' + className; - dom.dot.className = 'item dot' + className; - changed = true; - } - } - - return changed; -}; - -/** - * Show the item in the DOM (when not already visible). The items DOM will - * be created when needed. - * @return {Boolean} changed - */ -ItemBox.prototype.show = function show() { - if (!this.dom || !this.dom.box.parentNode) { - return this.repaint(); - } - else { - return false; - } -}; - -/** - * Hide the item from the DOM (when visible) - * @return {Boolean} changed - */ -ItemBox.prototype.hide = function hide() { - var changed = false, - dom = this.dom; - if (dom) { - if (dom.box.parentNode) { - dom.box.parentNode.removeChild(dom.box); - changed = true; - } - if (dom.line.parentNode) { - dom.line.parentNode.removeChild(dom.line); - } - if (dom.dot.parentNode) { - dom.dot.parentNode.removeChild(dom.dot); - } - } - return changed; -}; - -/** - * Reflow the item: calculate its actual size and position from the DOM - * @return {boolean} resized returns true if the axis is resized - * @override - */ -ItemBox.prototype.reflow = function reflow() { - var changed = 0, - update, - dom, - props, - options, - margin, - start, - align, - orientation, - top, - left, - data, - range; - - if (this.data.start == undefined) { - throw new Error('Property "start" missing in item ' + this.data.id); - } - - data = this.data; - range = this.parent && this.parent.range; - if (data && range) { - // TODO: account for the width of the item - var interval = (range.end - range.start); - this.visible = (data.start > range.start - interval) && (data.start < range.end + interval); - } - else { - this.visible = false; - } - - if (this.visible) { - dom = this.dom; - if (dom) { - update = util.updateProperty; - props = this.props; - options = this.options; - start = this.parent.toScreen(this.data.start); - align = options.align || this.defaultOptions.align; - margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; - orientation = options.orientation || this.defaultOptions.orientation; - - changed += update(props.dot, 'height', dom.dot.offsetHeight); - changed += update(props.dot, 'width', dom.dot.offsetWidth); - changed += update(props.line, 'width', dom.line.offsetWidth); - changed += update(props.line, 'height', dom.line.offsetHeight); - changed += update(props.line, 'top', dom.line.offsetTop); - changed += update(this, 'width', dom.box.offsetWidth); - changed += update(this, 'height', dom.box.offsetHeight); - if (align == 'right') { - left = start - this.width; - } - else if (align == 'left') { - left = start; - } - else { - // default or 'center' - left = start - this.width / 2; - } - changed += update(this, 'left', left); - - changed += update(props.line, 'left', start - props.line.width / 2); - changed += update(props.dot, 'left', start - props.dot.width / 2); - changed += update(props.dot, 'top', -props.dot.height / 2); - if (orientation == 'top') { - top = margin; - - changed += update(this, 'top', top); - } - else { - // default or 'bottom' - var parentHeight = this.parent.height; - top = parentHeight - this.height - margin; - - changed += update(this, 'top', top); - } - } - else { - changed += 1; - } - } - - return (changed > 0); -}; - -/** - * Create an items DOM - * @private - */ -ItemBox.prototype._create = function _create() { - var dom = this.dom; - if (!dom) { - this.dom = dom = {}; - - // create the box - dom.box = document.createElement('DIV'); - // className is updated in repaint() - - // contents box (inside the background box). used for making margins - dom.content = document.createElement('DIV'); - dom.content.className = 'content'; - dom.box.appendChild(dom.content); - - // line to axis - dom.line = document.createElement('DIV'); - dom.line.className = 'line'; - - // dot on axis - dom.dot = document.createElement('DIV'); - dom.dot.className = 'dot'; - } -}; - -/** - * Reposition the item, recalculate its left, top, and width, using the current - * range and size of the items itemset - * @override - */ -ItemBox.prototype.reposition = function reposition() { - var dom = this.dom, - props = this.props, - orientation = this.options.orientation || this.defaultOptions.orientation; - - if (dom) { - var box = dom.box, - line = dom.line, - dot = dom.dot; - - box.style.left = this.left + 'px'; - box.style.top = this.top + 'px'; - - line.style.left = props.line.left + 'px'; - if (orientation == 'top') { - line.style.top = 0 + 'px'; - line.style.height = this.top + 'px'; - } - else { - // orientation 'bottom' - line.style.top = (this.top + this.height) + 'px'; - line.style.height = Math.max(this.parent.height - this.top - this.height + - this.props.dot.height / 2, 0) + 'px'; - } - - dot.style.left = props.dot.left + 'px'; - dot.style.top = props.dot.top + 'px'; - } -}; - -/** - * @constructor ItemPoint - * @extends Item - * @param {ItemSet} parent - * @param {Object} data Object containing parameters start - * content, className. - * @param {Object} [options] Options to set initial property values - * @param {Object} [defaultOptions] default options - * // TODO: describe available options - */ -function ItemPoint (parent, data, options, defaultOptions) { - this.props = { - dot: { - top: 0, - width: 0, - height: 0 - }, - content: { - height: 0, - marginLeft: 0 - } - }; - - Item.call(this, parent, data, options, defaultOptions); -} - -ItemPoint.prototype = new Item (null, null); - -/** - * Select the item - * @override - */ -ItemPoint.prototype.select = function select() { - this.selected = true; - // TODO: select and unselect -}; - -/** - * Unselect the item - * @override - */ -ItemPoint.prototype.unselect = function unselect() { - this.selected = false; - // TODO: select and unselect -}; - -/** - * Repaint the item - * @return {Boolean} changed - */ -ItemPoint.prototype.repaint = function repaint() { - // TODO: make an efficient repaint - var changed = false; - var dom = this.dom; - - if (!dom) { - this._create(); - dom = this.dom; - changed = true; - } - - if (dom) { - if (!this.parent) { - throw new Error('Cannot repaint item: no parent attached'); - } - var foreground = this.parent.getForeground(); - if (!foreground) { - throw new Error('Cannot repaint time axis: ' + - 'parent has no foreground container element'); - } - - if (!dom.point.parentNode) { - foreground.appendChild(dom.point); - foreground.appendChild(dom.point); - changed = true; - } - - // update contents - if (this.data.content != this.content) { - this.content = this.data.content; - if (this.content instanceof Element) { - dom.content.innerHTML = ''; - dom.content.appendChild(this.content); - } - else if (this.data.content != undefined) { - dom.content.innerHTML = this.content; - } - else { - throw new Error('Property "content" missing in item ' + this.data.id); - } - changed = true; - } - - // update class - var className = (this.data.className? ' ' + this.data.className : '') + - (this.selected ? ' selected' : ''); - if (this.className != className) { - this.className = className; - dom.point.className = 'item point' + className; - changed = true; - } - } - - return changed; -}; - -/** - * Show the item in the DOM (when not already visible). The items DOM will - * be created when needed. - * @return {Boolean} changed - */ -ItemPoint.prototype.show = function show() { - if (!this.dom || !this.dom.point.parentNode) { - return this.repaint(); - } - else { - return false; - } -}; - -/** - * Hide the item from the DOM (when visible) - * @return {Boolean} changed - */ -ItemPoint.prototype.hide = function hide() { - var changed = false, - dom = this.dom; - if (dom) { - if (dom.point.parentNode) { - dom.point.parentNode.removeChild(dom.point); - changed = true; - } - } - return changed; -}; - -/** - * Reflow the item: calculate its actual size from the DOM - * @return {boolean} resized returns true if the axis is resized - * @override - */ -ItemPoint.prototype.reflow = function reflow() { - var changed = 0, - update, - dom, - props, - options, - margin, - orientation, - start, - top, - data, - range; - - if (this.data.start == undefined) { - throw new Error('Property "start" missing in item ' + this.data.id); - } - - data = this.data; - range = this.parent && this.parent.range; - if (data && range) { - // TODO: account for the width of the item - var interval = (range.end - range.start); - this.visible = (data.start > range.start - interval) && (data.start < range.end); - } - else { - this.visible = false; - } - - if (this.visible) { - dom = this.dom; - if (dom) { - update = util.updateProperty; - props = this.props; - options = this.options; - orientation = options.orientation || this.defaultOptions.orientation; - margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; - start = this.parent.toScreen(this.data.start); - - changed += update(this, 'width', dom.point.offsetWidth); - changed += update(this, 'height', dom.point.offsetHeight); - changed += update(props.dot, 'width', dom.dot.offsetWidth); - changed += update(props.dot, 'height', dom.dot.offsetHeight); - changed += update(props.content, 'height', dom.content.offsetHeight); - - if (orientation == 'top') { - top = margin; - } - else { - // default or 'bottom' - var parentHeight = this.parent.height; - top = Math.max(parentHeight - this.height - margin, 0); - } - changed += update(this, 'top', top); - changed += update(this, 'left', start - props.dot.width / 2); - changed += update(props.content, 'marginLeft', 1.5 * props.dot.width); - //changed += update(props.content, 'marginRight', 0.5 * props.dot.width); // TODO - - changed += update(props.dot, 'top', (this.height - props.dot.height) / 2); - } - else { - changed += 1; - } - } - - return (changed > 0); -}; - -/** - * Create an items DOM - * @private - */ -ItemPoint.prototype._create = function _create() { - var dom = this.dom; - if (!dom) { - this.dom = dom = {}; - - // background box - dom.point = document.createElement('div'); - // className is updated in repaint() - - // contents box, right from the dot - dom.content = document.createElement('div'); - dom.content.className = 'content'; - dom.point.appendChild(dom.content); - - // dot at start - dom.dot = document.createElement('div'); - dom.dot.className = 'dot'; - dom.point.appendChild(dom.dot); - } -}; - -/** - * Reposition the item, recalculate its left, top, and width, using the current - * range and size of the items itemset - * @override - */ -ItemPoint.prototype.reposition = function reposition() { - var dom = this.dom, - props = this.props; - - if (dom) { - dom.point.style.top = this.top + 'px'; - dom.point.style.left = this.left + 'px'; - - dom.content.style.marginLeft = props.content.marginLeft + 'px'; - //dom.content.style.marginRight = props.content.marginRight + 'px'; // TODO - - dom.dot.style.top = props.dot.top + 'px'; - } -}; - -/** - * @constructor ItemRange - * @extends Item - * @param {ItemSet} parent - * @param {Object} data Object containing parameters start, end - * content, className. - * @param {Object} [options] Options to set initial property values - * @param {Object} [defaultOptions] default options - * // TODO: describe available options - */ -function ItemRange (parent, data, options, defaultOptions) { - this.props = { - content: { - left: 0, - width: 0 - } - }; - - Item.call(this, parent, data, options, defaultOptions); -} - -ItemRange.prototype = new Item (null, null); - -/** - * Select the item - * @override - */ -ItemRange.prototype.select = function select() { - this.selected = true; - // TODO: select and unselect -}; - -/** - * Unselect the item - * @override - */ -ItemRange.prototype.unselect = function unselect() { - this.selected = false; - // TODO: select and unselect -}; - -/** - * Repaint the item - * @return {Boolean} changed - */ -ItemRange.prototype.repaint = function repaint() { - // TODO: make an efficient repaint - var changed = false; - var dom = this.dom; - - if (!dom) { - this._create(); - dom = this.dom; - changed = true; - } - - if (dom) { - if (!this.parent) { - throw new Error('Cannot repaint item: no parent attached'); - } - var foreground = this.parent.getForeground(); - if (!foreground) { - throw new Error('Cannot repaint time axis: ' + - 'parent has no foreground container element'); - } - - if (!dom.box.parentNode) { - foreground.appendChild(dom.box); - changed = true; - } - - // update content - if (this.data.content != this.content) { - this.content = this.data.content; - if (this.content instanceof Element) { - dom.content.innerHTML = ''; - dom.content.appendChild(this.content); - } - else if (this.data.content != undefined) { - dom.content.innerHTML = this.content; - } - else { - throw new Error('Property "content" missing in item ' + this.data.id); - } - changed = true; - } - - // update class - var className = this.data.className ? (' ' + this.data.className) : ''; - if (this.className != className) { - this.className = className; - dom.box.className = 'item range' + className; - changed = true; - } - } - - return changed; -}; - -/** - * Show the item in the DOM (when not already visible). The items DOM will - * be created when needed. - * @return {Boolean} changed - */ -ItemRange.prototype.show = function show() { - if (!this.dom || !this.dom.box.parentNode) { - return this.repaint(); - } - else { - return false; - } -}; - -/** - * Hide the item from the DOM (when visible) - * @return {Boolean} changed - */ -ItemRange.prototype.hide = function hide() { - var changed = false, - dom = this.dom; - if (dom) { - if (dom.box.parentNode) { - dom.box.parentNode.removeChild(dom.box); - changed = true; - } - } - return changed; -}; - -/** - * Reflow the item: calculate its actual size from the DOM - * @return {boolean} resized returns true if the axis is resized - * @override - */ -ItemRange.prototype.reflow = function reflow() { - var changed = 0, - dom, - props, - options, - margin, - padding, - parent, - start, - end, - data, - range, - update, - box, - parentWidth, - contentLeft, - orientation, - top; - - if (this.data.start == undefined) { - throw new Error('Property "start" missing in item ' + this.data.id); - } - if (this.data.end == undefined) { - throw new Error('Property "end" missing in item ' + this.data.id); - } - - data = this.data; - range = this.parent && this.parent.range; - if (data && range) { - // TODO: account for the width of the item. Take some margin - this.visible = (data.start < range.end) && (data.end > range.start); - } - else { - this.visible = false; - } - - if (this.visible) { - dom = this.dom; - if (dom) { - props = this.props; - options = this.options; - parent = this.parent; - start = parent.toScreen(this.data.start); - end = parent.toScreen(this.data.end); - update = util.updateProperty; - box = dom.box; - parentWidth = parent.width; - orientation = options.orientation || this.defaultOptions.orientation; - margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; - padding = options.padding || this.defaultOptions.padding; - - changed += update(props.content, 'width', dom.content.offsetWidth); - - changed += update(this, 'height', box.offsetHeight); - - // limit the width of the this, as browsers cannot draw very wide divs - if (start < -parentWidth) { - start = -parentWidth; - } - if (end > 2 * parentWidth) { - end = 2 * parentWidth; - } - - // when range exceeds left of the window, position the contents at the left of the visible area - if (start < 0) { - contentLeft = Math.min(-start, - (end - start - props.content.width - 2 * padding)); - // TODO: remove the need for options.padding. it's terrible. - } - else { - contentLeft = 0; - } - changed += update(props.content, 'left', contentLeft); - - if (orientation == 'top') { - top = margin; - changed += update(this, 'top', top); - } - else { - // default or 'bottom' - top = parent.height - this.height - margin; - changed += update(this, 'top', top); - } - - changed += update(this, 'left', start); - changed += update(this, 'width', Math.max(end - start, 1)); // TODO: reckon with border width; - } - else { - changed += 1; - } - } - - return (changed > 0); -}; - -/** - * Create an items DOM - * @private - */ -ItemRange.prototype._create = function _create() { - var dom = this.dom; - if (!dom) { - this.dom = dom = {}; - // background box - dom.box = document.createElement('div'); - // className is updated in repaint() - - // contents box - dom.content = document.createElement('div'); - dom.content.className = 'content'; - dom.box.appendChild(dom.content); - } -}; - -/** - * Reposition the item, recalculate its left, top, and width, using the current - * range and size of the items itemset - * @override - */ -ItemRange.prototype.reposition = function reposition() { - var dom = this.dom, - props = this.props; - - if (dom) { - dom.box.style.top = this.top + 'px'; - dom.box.style.left = this.left + 'px'; - dom.box.style.width = this.width + 'px'; - - dom.content.style.left = props.content.left + 'px'; - } -}; - -/** - * @constructor Group - * @param {GroupSet} parent - * @param {Number | String} groupId - * @param {Object} [options] Options to set initial property values - * // TODO: describe available options - * @extends Component - */ -function Group (parent, groupId, options) { - this.id = util.randomUUID(); - this.parent = parent; - - this.groupId = groupId; - this.itemset = null; // ItemSet - this.options = options || {}; - this.options.top = 0; - - this.props = { - label: { - width: 0, - height: 0 - } - }; - - this.top = 0; - this.left = 0; - this.width = 0; - this.height = 0; -} - -Group.prototype = new Component(); - -// TODO: comment -Group.prototype.setOptions = Component.prototype.setOptions; - -/** - * Get the container element of the panel, which can be used by a child to - * add its own widgets. - * @returns {HTMLElement} container - */ -Group.prototype.getContainer = function () { - return this.parent.getContainer(); -}; - -/** - * Set item set for the group. The group will create a view on the itemset, - * filtered by the groups id. - * @param {DataSet | DataView} items - */ -Group.prototype.setItems = function setItems(items) { - if (this.itemset) { - // remove current item set - this.itemset.hide(); - this.itemset.setItems(); - - this.parent.controller.remove(this.itemset); - this.itemset = null; - } - - if (items) { - var groupId = this.groupId; - - var itemsetOptions = Object.create(this.options); - this.itemset = new ItemSet(this, null, itemsetOptions); - this.itemset.setRange(this.parent.range); - - this.view = new DataView(items, { - filter: function (item) { - return item.group == groupId; - } - }); - this.itemset.setItems(this.view); - - this.parent.controller.add(this.itemset); - } -}; - -/** - * Repaint the item - * @return {Boolean} changed - */ -Group.prototype.repaint = function repaint() { - return false; -}; - -/** - * Reflow the item - * @return {Boolean} resized - */ -Group.prototype.reflow = function reflow() { - var changed = 0, - update = util.updateProperty; - - changed += update(this, 'top', this.itemset ? this.itemset.top : 0); - changed += update(this, 'height', this.itemset ? this.itemset.height : 0); - - // TODO: reckon with the height of the group label - - if (this.label) { - var inner = this.label.firstChild; - changed += update(this.props.label, 'width', inner.clientWidth); - changed += update(this.props.label, 'height', inner.clientHeight); - } - else { - changed += update(this.props.label, 'width', 0); - changed += update(this.props.label, 'height', 0); - } - - return (changed > 0); -}; - -/** - * An GroupSet holds a set of groups - * @param {Component} parent - * @param {Component[]} [depends] Components on which this components depends - * (except for the parent) - * @param {Object} [options] See GroupSet.setOptions for the available - * options. - * @constructor GroupSet - * @extends Panel - */ -function GroupSet(parent, depends, options) { - this.id = util.randomUUID(); - this.parent = parent; - this.depends = depends; - - this.options = options || {}; - - this.range = null; // Range or Object {start: number, end: number} - this.itemsData = null; // DataSet with items - this.groupsData = null; // DataSet with groups - - this.groups = {}; // map with groups - - this.dom = {}; - this.props = { - labels: { - width: 0 - } - }; - - // TODO: implement right orientation of the labels - - // changes in groups are queued key/value map containing id/action - this.queue = {}; - - var me = this; - this.listeners = { - 'add': function (event, params) { - me._onAdd(params.items); - }, - 'update': function (event, params) { - me._onUpdate(params.items); - }, - 'remove': function (event, params) { - me._onRemove(params.items); - } - }; -} - -GroupSet.prototype = new Panel(); - -/** - * Set options for the GroupSet. Existing options will be extended/overwritten. - * @param {Object} [options] The following options are available: - * {String | function} groupsOrder - * TODO: describe options - */ -GroupSet.prototype.setOptions = Component.prototype.setOptions; - -GroupSet.prototype.setRange = function (range) { - // TODO: implement setRange -}; - -/** - * Set items - * @param {vis.DataSet | null} items - */ -GroupSet.prototype.setItems = function setItems(items) { - this.itemsData = items; - - for (var id in this.groups) { - if (this.groups.hasOwnProperty(id)) { - var group = this.groups[id]; - group.setItems(items); - } - } -}; - -/** - * Get items - * @return {vis.DataSet | null} items - */ -GroupSet.prototype.getItems = function getItems() { - return this.itemsData; -}; - -/** - * Set range (start and end). - * @param {Range | Object} range A Range or an object containing start and end. - */ -GroupSet.prototype.setRange = function setRange(range) { - this.range = range; -}; - -/** - * Set groups - * @param {vis.DataSet} groups - */ -GroupSet.prototype.setGroups = function setGroups(groups) { - var me = this, - ids; - - // unsubscribe from current dataset - if (this.groupsData) { - util.forEach(this.listeners, function (callback, event) { - me.groupsData.unsubscribe(event, callback); - }); - - // remove all drawn groups - ids = this.groupsData.getIds(); - this._onRemove(ids); - } - - // replace the dataset - if (!groups) { - this.groupsData = null; - } - else if (groups instanceof DataSet) { - this.groupsData = groups; - } - else { - this.groupsData = new DataSet({ - convert: { - start: 'Date', - end: 'Date' - } - }); - this.groupsData.add(groups); - } - - if (this.groupsData) { - // subscribe to new dataset - var id = this.id; - util.forEach(this.listeners, function (callback, event) { - me.groupsData.subscribe(event, callback, id); - }); - - // draw all new groups - ids = this.groupsData.getIds(); - this._onAdd(ids); - } -}; - -/** - * Get groups - * @return {vis.DataSet | null} groups - */ -GroupSet.prototype.getGroups = function getGroups() { - return this.groupsData; -}; - -/** - * Repaint the component - * @return {Boolean} changed - */ -GroupSet.prototype.repaint = function repaint() { - var changed = 0, - i, id, group, label, - update = util.updateProperty, - asSize = util.option.asSize, - asElement = util.option.asElement, - options = this.options, - frame = this.dom.frame, - labels = this.dom.labels; - - // create frame - if (!this.parent) { - throw new Error('Cannot repaint groupset: no parent attached'); - } - var parentContainer = this.parent.getContainer(); - if (!parentContainer) { - throw new Error('Cannot repaint groupset: parent has no container element'); - } - if (!frame) { - frame = document.createElement('div'); - frame.className = 'groupset'; - this.dom.frame = frame; - - var className = options.className; - if (className) { - util.addClassName(frame, util.option.asString(className)); - } - - changed += 1; - } - if (!frame.parentNode) { - parentContainer.appendChild(frame); - changed += 1; - } - - // create labels - var labelContainer = asElement(options.labelContainer); - if (!labelContainer) { - throw new Error('Cannot repaint groupset: option "labelContainer" not defined'); - } - if (!labels) { - labels = document.createElement('div'); - labels.className = 'labels'; - //frame.appendChild(labels); - this.dom.labels = labels; - } - if (!labels.parentNode || labels.parentNode != labelContainer) { - if (labels.parentNode) { - labels.parentNode.removeChild(labels.parentNode); - } - labelContainer.appendChild(labels); - } - - // reposition frame - changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); - changed += update(frame.style, 'top', asSize(options.top, '0px')); - changed += update(frame.style, 'left', asSize(options.left, '0px')); - changed += update(frame.style, 'width', asSize(options.width, '100%')); - - // reposition labels - changed += update(labels.style, 'top', asSize(options.top, '0px')); - - var me = this, - queue = this.queue, - groups = this.groups, - groupsData = this.groupsData; - - // show/hide added/changed/removed groups - var ids = Object.keys(queue); - if (ids.length) { - ids.forEach(function (id) { - var action = queue[id]; - var group = groups[id]; - - //noinspection FallthroughInSwitchStatementJS - switch (action) { - case 'add': - case 'update': - if (!group) { - var groupOptions = Object.create(me.options); - group = new Group(me, id, groupOptions); - group.setItems(me.itemsData); // attach items data - groups[id] = group; - - me.controller.add(group); - } - - // TODO: update group data - group.data = groupsData.get(id); - - delete queue[id]; - break; - - case 'remove': - if (group) { - group.setItems(); // detach items data - delete groups[id]; - - me.controller.remove(group); - } - - // update lists - delete queue[id]; - break; - - default: - console.log('Error: unknown action "' + action + '"'); - } - }); - - // the groupset depends on each of the groups - //this.depends = this.groups; // TODO: gives a circular reference through the parent - - // TODO: apply dependencies of the groupset - - // update the top positions of the groups in the correct order - var orderedGroups = this.groupsData.getIds({ - order: this.options.groupsOrder - }); - for (i = 0; i < orderedGroups.length; i++) { - (function (group, prevGroup) { - var top = 0; - if (prevGroup) { - top = function () { - // TODO: top must reckon with options.maxHeight - return prevGroup.top + prevGroup.height; - } - } - group.setOptions({ - top: top - }); - })(groups[orderedGroups[i]], groups[orderedGroups[i - 1]]); - } - - // (re)create the labels - while (labels.firstChild) { - labels.removeChild(labels.firstChild); - } - for (i = 0; i < orderedGroups.length; i++) { - id = orderedGroups[i]; - label = this._createLabel(id); - labels.appendChild(label); - } - - changed++; - } - - // reposition the labels - // TODO: labels are not displayed correctly when orientation=='top' - // TODO: width of labelPanel is not immediately updated on a change in groups - for (id in groups) { - if (groups.hasOwnProperty(id)) { - group = groups[id]; - label = group.label; - if (label) { - label.style.top = group.top + 'px'; - label.style.height = group.height + 'px'; - } - } - } - - return (changed > 0); -}; - -/** - * Create a label for group with given id - * @param {Number} id - * @return {Element} label - * @private - */ -GroupSet.prototype._createLabel = function(id) { - var group = this.groups[id]; - var label = document.createElement('div'); - label.className = 'label'; - var inner = document.createElement('div'); - inner.className = 'inner'; - label.appendChild(inner); - - var content = group.data && group.data.content; - if (content instanceof Element) { - inner.appendChild(content); - } - else if (content != undefined) { - inner.innerHTML = content; - } - - var className = group.data && group.data.className; - if (className) { - util.addClassName(label, className); - } - - group.label = label; // TODO: not so nice, parking labels in the group this way!!! - - return label; -}; - -/** - * Get container element - * @return {HTMLElement} container - */ -GroupSet.prototype.getContainer = function getContainer() { - return this.dom.frame; -}; - -/** - * Get the width of the group labels - * @return {Number} width - */ -GroupSet.prototype.getLabelsWidth = function getContainer() { - return this.props.labels.width; -}; - -/** - * Reflow the component - * @return {Boolean} resized - */ -GroupSet.prototype.reflow = function reflow() { - var changed = 0, - id, group, - options = this.options, - update = util.updateProperty, - asNumber = util.option.asNumber, - asSize = util.option.asSize, - frame = this.dom.frame; - - if (frame) { - var maxHeight = asNumber(options.maxHeight); - var fixedHeight = (asSize(options.height) != null); - var height; - if (fixedHeight) { - height = frame.offsetHeight; - } - else { - // height is not specified, calculate the sum of the height of all groups - height = 0; - - for (id in this.groups) { - if (this.groups.hasOwnProperty(id)) { - group = this.groups[id]; - height += group.height; - } - } - } - if (maxHeight != null) { - height = Math.min(height, maxHeight); - } - changed += update(this, 'height', height); - - changed += update(this, 'top', frame.offsetTop); - changed += update(this, 'left', frame.offsetLeft); - changed += update(this, 'width', frame.offsetWidth); - } - - // calculate the maximum width of the labels - var width = 0; - for (id in this.groups) { - if (this.groups.hasOwnProperty(id)) { - group = this.groups[id]; - var labelWidth = group.props && group.props.label && group.props.label.width || 0; - width = Math.max(width, labelWidth); - } - } - changed += update(this.props.labels, 'width', width); - - return (changed > 0); -}; - -/** - * Hide the component from the DOM - * @return {Boolean} changed - */ -GroupSet.prototype.hide = function hide() { - if (this.dom.frame && this.dom.frame.parentNode) { - this.dom.frame.parentNode.removeChild(this.dom.frame); - return true; - } - else { - return false; - } -}; - -/** - * Show the component in the DOM (when not already visible). - * A repaint will be executed when the component is not visible - * @return {Boolean} changed - */ -GroupSet.prototype.show = function show() { - if (!this.dom.frame || !this.dom.frame.parentNode) { - return this.repaint(); - } - else { - return false; - } -}; - -/** - * Handle updated groups - * @param {Number[]} ids - * @private - */ -GroupSet.prototype._onUpdate = function _onUpdate(ids) { - this._toQueue(ids, 'update'); -}; - -/** - * Handle changed groups - * @param {Number[]} ids - * @private - */ -GroupSet.prototype._onAdd = function _onAdd(ids) { - this._toQueue(ids, 'add'); -}; - -/** - * Handle removed groups - * @param {Number[]} ids - * @private - */ -GroupSet.prototype._onRemove = function _onRemove(ids) { - this._toQueue(ids, 'remove'); -}; - -/** - * Put groups in the queue to be added/updated/remove - * @param {Number[]} ids - * @param {String} action can be 'add', 'update', 'remove' - */ -GroupSet.prototype._toQueue = function _toQueue(ids, action) { - var queue = this.queue; - ids.forEach(function (id) { - queue[id] = action; - }); - - if (this.controller) { - //this.requestReflow(); - this.requestRepaint(); - } -}; - -/** - * Create a timeline visualization - * @param {HTMLElement} container - * @param {vis.DataSet | Array | DataTable} [items] - * @param {Object} [options] See Timeline.setOptions for the available options. - * @constructor - */ -function Timeline (container, items, options) { - var me = this; - this.options = util.extend({ - orientation: 'bottom', - min: null, - max: null, - zoomMin: 10, // milliseconds - zoomMax: 1000 * 60 * 60 * 24 * 365 * 10000, // milliseconds - // moveable: true, // TODO: option moveable - // zoomable: true, // TODO: option zoomable - showMinorLabels: true, - showMajorLabels: true, - autoResize: false - }, options); - - // controller - this.controller = new Controller(); - - // root panel - if (!container) { - throw new Error('No container element provided'); - } - var rootOptions = Object.create(this.options); - rootOptions.height = function () { - if (me.options.height) { - // fixed height - return me.options.height; - } - else { - // auto height - return me.timeaxis.height + me.content.height; - } - }; - this.rootPanel = new RootPanel(container, rootOptions); - this.controller.add(this.rootPanel); - - // item panel - var itemOptions = Object.create(this.options); - itemOptions.left = function () { - return me.labelPanel.width; - }; - itemOptions.width = function () { - return me.rootPanel.width - me.labelPanel.width; - }; - itemOptions.top = null; - itemOptions.height = null; - this.itemPanel = new Panel(this.rootPanel, [], itemOptions); - this.controller.add(this.itemPanel); - - // label panel - var labelOptions = Object.create(this.options); - labelOptions.top = null; - labelOptions.left = null; - labelOptions.height = null; - labelOptions.width = function () { - if (me.content && typeof me.content.getLabelsWidth === 'function') { - return me.content.getLabelsWidth(); - } - else { - return 0; - } - }; - this.labelPanel = new Panel(this.rootPanel, [], labelOptions); - this.controller.add(this.labelPanel); - - // range - var now = moment().hours(0).minutes(0).seconds(0).milliseconds(0); - this.range = new Range({ - start: now.clone().add('days', -3).valueOf(), - end: now.clone().add('days', 4).valueOf() - }); - /* TODO: fix range options - var rangeOptions = Object.create(this.options); - this.range = new Range(rangeOptions); - this.range.setRange( - now.clone().add('days', -3).valueOf(), - now.clone().add('days', 4).valueOf() - ); - */ - // TODO: reckon with options moveable and zoomable - this.range.subscribe(this.rootPanel, 'move', 'horizontal'); - this.range.subscribe(this.rootPanel, 'zoom', 'horizontal'); - this.range.on('rangechange', function () { - var force = true; - me.controller.requestReflow(force); - }); - this.range.on('rangechanged', function () { - var force = true; - me.controller.requestReflow(force); - }); - - // TODO: put the listeners in setOptions, be able to dynamically change with options moveable and zoomable - - // time axis - var timeaxisOptions = Object.create(rootOptions); - timeaxisOptions.range = this.range; - timeaxisOptions.left = null; - timeaxisOptions.top = null; - timeaxisOptions.width = '100%'; - timeaxisOptions.height = null; - this.timeaxis = new TimeAxis(this.itemPanel, [], timeaxisOptions); - this.timeaxis.setRange(this.range); - this.controller.add(this.timeaxis); - - // create itemset or groupset - this.setGroups(null); - - this.itemsData = null; // DataSet - this.groupsData = null; // DataSet - - // set data - if (items) { - this.setItems(items); - } -} - -/** - * Set options - * @param {Object} options TODO: describe the available options - */ -Timeline.prototype.setOptions = function (options) { - if (options) { - util.extend(this.options, options); - } - - // TODO: apply range min,max - - this.controller.reflow(); - this.controller.repaint(); -}; - -/** - * Set items - * @param {vis.DataSet | Array | DataTable | null} items - */ -Timeline.prototype.setItems = function(items) { - var initialLoad = (this.itemsData == null); - - // convert to type DataSet when needed - var newItemSet; - if (!items) { - newItemSet = null; - } - else if (items instanceof DataSet) { - newItemSet = items; - } - if (!(items instanceof DataSet)) { - newItemSet = new DataSet({ - convert: { - start: 'Date', - end: 'Date' - } - }); - newItemSet.add(items); - } - - // set items - this.itemsData = newItemSet; - this.content.setItems(newItemSet); - - if (initialLoad && (this.options.start == undefined || this.options.end == undefined)) { - // apply the data range as range - var dataRange = this.getItemRange(); - - // add 5% on both sides - var min = dataRange.min; - var max = dataRange.max; - if (min != null && max != null) { - var interval = (max.valueOf() - min.valueOf()); - if (interval <= 0) { - // prevent an empty interval - interval = 24 * 60 * 60 * 1000; // 1 day - } - min = new Date(min.valueOf() - interval * 0.05); - max = new Date(max.valueOf() + interval * 0.05); - } - - // override specified start and/or end date - if (this.options.start != undefined) { - min = new Date(this.options.start.valueOf()); - } - if (this.options.end != undefined) { - max = new Date(this.options.end.valueOf()); - } - - // apply range if there is a min or max available - if (min != null || max != null) { - this.range.setRange(min, max); - } - } -}; - -/** - * Set groups - * @param {vis.DataSet | Array | DataTable} groups - */ -Timeline.prototype.setGroups = function(groups) { - var me = this; - this.groupsData = groups; - - // switch content type between ItemSet or GroupSet when needed - var type = this.groupsData ? GroupSet : ItemSet; - if (!(this.content instanceof type)) { - // remove old content set - if (this.content) { - this.content.hide(); - if (this.content.setItems) { - this.content.setItems(); // disconnect from items - } - if (this.content.setGroups) { - this.content.setGroups(); // disconnect from groups - } - this.controller.remove(this.content); - } - - // create new content set - var options = Object.create(this.options); - util.extend(options, { - top: function () { - if (me.options.orientation == 'top') { - return me.timeaxis.height; - } - else { - return me.itemPanel.height - me.timeaxis.height - me.content.height; - } - }, - left: null, - width: '100%', - height: function () { - if (me.options.height) { - return me.itemPanel.height - me.timeaxis.height; - } - else { - return null; - } - }, - maxHeight: function () { - if (me.options.maxHeight) { - if (!util.isNumber(me.options.maxHeight)) { - throw new TypeError('Number expected for property maxHeight'); - } - return me.options.maxHeight - me.timeaxis.height; - } - else { - return null; - } - }, - labelContainer: function () { - return me.labelPanel.getContainer(); - } - }); - this.content = new type(this.itemPanel, [this.timeaxis], options); - if (this.content.setRange) { - this.content.setRange(this.range); - } - if (this.content.setItems) { - this.content.setItems(this.itemsData); - } - if (this.content.setGroups) { - this.content.setGroups(this.groupsData); - } - this.controller.add(this.content); - } -}; - -/** - * Get the data range of the item set. - * @returns {{min: Date, max: Date}} range A range with a start and end Date. - * When no minimum is found, min==null - * When no maximum is found, max==null - */ -Timeline.prototype.getItemRange = function getItemRange() { - // calculate min from start filed - var itemsData = this.itemsData, - min = null, - max = null; - - if (itemsData) { - // calculate the minimum value of the field 'start' - var minItem = itemsData.min('start'); - min = minItem ? minItem.start.valueOf() : null; - - // calculate maximum value of fields 'start' and 'end' - var maxStartItem = itemsData.max('start'); - if (maxStartItem) { - max = maxStartItem.start.valueOf(); - } - var maxEndItem = itemsData.max('end'); - if (maxEndItem) { - if (max == null) { - max = maxEndItem.end.valueOf(); - } - else { - max = Math.max(max, maxEndItem.end.valueOf()); - } - } - } - - return { - min: (min != null) ? new Date(min) : null, - max: (max != null) ? new Date(max) : null - }; -}; - -(function(exports) { - /** - * Parse a text source containing data in DOT language into a JSON object. - * The object contains two lists: one with nodes and one with edges. - * - * DOT language reference: http://www.graphviz.org/doc/info/lang.html - * - * @param {String} data Text containing a graph in DOT-notation - * @return {Object} graph An object containing two parameters: - * {Object[]} nodes - * {Object[]} edges - */ - function parseDOT (data) { - dot = data; - return parseGraph(); - } - - // token types enumeration - var TOKENTYPE = { - NULL : 0, - DELIMITER : 1, - IDENTIFIER: 2, - UNKNOWN : 3 - }; - - // map with all delimiters - var DELIMITERS = { - '{': true, - '}': true, - '[': true, - ']': true, - ';': true, - '=': true, - ',': true, - - '->': true, - '--': true - }; - - var dot = ''; // current dot file - var index = 0; // current index in dot file - var c = ''; // current token character in expr - var token = ''; // current token - var tokenType = TOKENTYPE.NULL; // type of the token - - /** - * Get the first character from the dot file. - * The character is stored into the char c. If the end of the dot file is - * reached, the function puts an empty string in c. - */ - function first() { - index = 0; - c = dot.charAt(0); - } - - /** - * Get the next character from the dot file. - * The character is stored into the char c. If the end of the dot file is - * reached, the function puts an empty string in c. - */ - function next() { - index++; - c = dot.charAt(index); - } - - /** - * Preview the next character from the dot file. - * @return {String} cNext - */ - function nextPreview() { - return dot.charAt(index + 1); - } - - /** - * Test whether given character is alphabetic or numeric - * @param {String} c - * @return {Boolean} isAlphaNumeric - */ - var regexAlphaNumeric = /[a-zA-Z_0-9.:#]/; - function isAlphaNumeric(c) { - return regexAlphaNumeric.test(c); - } - - /** - * Merge all properties of object b into object b - * @param {Object} a - * @param {Object} b - * @return {Object} a - */ - function merge (a, b) { - if (!a) { - a = {}; - } - - if (b) { - for (var name in b) { - if (b.hasOwnProperty(name)) { - a[name] = b[name]; - } - } - } - return a; - } - - /** - * Set a value in an object, where the provided parameter name can be a - * path with nested parameters. For example: - * - * var obj = {a: 2}; - * setValue(obj, 'b.c', 3); // obj = {a: 2, b: {c: 3}} - * - * @param {Object} obj - * @param {String} path A parameter name or dot-separated parameter path, - * like "color.highlight.border". - * @param {*} value - */ - function setValue(obj, path, value) { - var keys = path.split('.'); - var o = obj; - while (keys.length) { - var key = keys.shift(); - if (keys.length) { - // this isn't the end point - if (!o[key]) { - o[key] = {}; - } - o = o[key]; - } - else { - // this is the end point - o[key] = value; - } - } - } - - /** - * Add a node to a graph object. If there is already a node with - * the same id, their attributes will be merged. - * @param {Object} graph - * @param {Object} node - */ - function addNode(graph, node) { - var i, len; - var current = null; - - // find root graph (in case of subgraph) - var graphs = [graph]; // list with all graphs from current graph to root graph - var root = graph; - while (root.parent) { - graphs.push(root.parent); - root = root.parent; - } - - // find existing node (at root level) by its id - if (root.nodes) { - for (i = 0, len = root.nodes.length; i < len; i++) { - if (node.id === root.nodes[i].id) { - current = root.nodes[i]; - break; - } - } - } - - if (!current) { - // this is a new node - current = { - id: node.id - }; - if (graph.node) { - // clone default attributes - current.attr = merge(current.attr, graph.node); - } - } - - // add node to this (sub)graph and all its parent graphs - for (i = graphs.length - 1; i >= 0; i--) { - var g = graphs[i]; - - if (!g.nodes) { - g.nodes = []; - } - if (g.nodes.indexOf(current) == -1) { - g.nodes.push(current); - } - } - - // merge attributes - if (node.attr) { - current.attr = merge(current.attr, node.attr); - } - } - - /** - * Add an edge to a graph object - * @param {Object} graph - * @param {Object} edge - */ - function addEdge(graph, edge) { - if (!graph.edges) { - graph.edges = []; - } - graph.edges.push(edge); - if (graph.edge) { - var attr = merge({}, graph.edge); // clone default attributes - edge.attr = merge(attr, edge.attr); // merge attributes - } - } - - /** - * Create an edge to a graph object - * @param {Object} graph - * @param {String | Number | Object} from - * @param {String | Number | Object} to - * @param {String} type - * @param {Object | null} attr - * @return {Object} edge - */ - function createEdge(graph, from, to, type, attr) { - var edge = { - from: from, - to: to, - type: type - }; - - if (graph.edge) { - edge.attr = merge({}, graph.edge); // clone default attributes - } - edge.attr = merge(edge.attr || {}, attr); // merge attributes - - return edge; - } - - /** - * Get next token in the current dot file. - * The token and token type are available as token and tokenType - */ - function getToken() { - tokenType = TOKENTYPE.NULL; - token = ''; - - // skip over whitespaces - while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter - next(); - } - - do { - var isComment = false; - - // skip comment - if (c == '#') { - // find the previous non-space character - var i = index - 1; - while (dot.charAt(i) == ' ' || dot.charAt(i) == '\t') { - i--; - } - if (dot.charAt(i) == '\n' || dot.charAt(i) == '') { - // the # is at the start of a line, this is indeed a line comment - while (c != '' && c != '\n') { - next(); - } - isComment = true; - } - } - if (c == '/' && nextPreview() == '/') { - // skip line comment - while (c != '' && c != '\n') { - next(); - } - isComment = true; - } - if (c == '/' && nextPreview() == '*') { - // skip block comment - while (c != '') { - if (c == '*' && nextPreview() == '/') { - // end of block comment found. skip these last two characters - next(); - next(); - break; - } - else { - next(); - } - } - isComment = true; - } - - // skip over whitespaces - while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter - next(); - } - } - while (isComment); - - // check for end of dot file - if (c == '') { - // token is still empty - tokenType = TOKENTYPE.DELIMITER; - return; - } - - // check for delimiters consisting of 2 characters - var c2 = c + nextPreview(); - if (DELIMITERS[c2]) { - tokenType = TOKENTYPE.DELIMITER; - token = c2; - next(); - next(); - return; - } - - // check for delimiters consisting of 1 character - if (DELIMITERS[c]) { - tokenType = TOKENTYPE.DELIMITER; - token = c; - next(); - return; - } - - // check for an identifier (number or string) - // TODO: more precise parsing of numbers/strings (and the port separator ':') - if (isAlphaNumeric(c) || c == '-') { - token += c; - next(); - - while (isAlphaNumeric(c)) { - token += c; - next(); - } - if (token == 'false') { - token = false; // convert to boolean - } - else if (token == 'true') { - token = true; // convert to boolean - } - else if (!isNaN(Number(token))) { - token = Number(token); // convert to number - } - tokenType = TOKENTYPE.IDENTIFIER; - return; - } - - // check for a string enclosed by double quotes - if (c == '"') { - next(); - while (c != '' && (c != '"' || (c == '"' && nextPreview() == '"'))) { - token += c; - if (c == '"') { // skip the escape character - next(); - } - next(); - } - if (c != '"') { - throw newSyntaxError('End of string " expected'); - } - next(); - tokenType = TOKENTYPE.IDENTIFIER; - return; - } - - // something unknown is found, wrong characters, a syntax error - tokenType = TOKENTYPE.UNKNOWN; - while (c != '') { - token += c; - next(); - } - throw new SyntaxError('Syntax error in part "' + chop(token, 30) + '"'); - } - - /** - * Parse a graph. - * @returns {Object} graph - */ - function parseGraph() { - var graph = {}; - - first(); - getToken(); - - // optional strict keyword - if (token == 'strict') { - graph.strict = true; - getToken(); - } - - // graph or digraph keyword - if (token == 'graph' || token == 'digraph') { - graph.type = token; - getToken(); - } - - // optional graph id - if (tokenType == TOKENTYPE.IDENTIFIER) { - graph.id = token; - getToken(); - } - - // open angle bracket - if (token != '{') { - throw newSyntaxError('Angle bracket { expected'); - } - getToken(); - - // statements - parseStatements(graph); - - // close angle bracket - if (token != '}') { - throw newSyntaxError('Angle bracket } expected'); - } - getToken(); - - // end of file - if (token !== '') { - throw newSyntaxError('End of file expected'); - } - getToken(); - - // remove temporary default properties - delete graph.node; - delete graph.edge; - delete graph.graph; - - return graph; - } - - /** - * Parse a list with statements. - * @param {Object} graph - */ - function parseStatements (graph) { - while (token !== '' && token != '}') { - parseStatement(graph); - if (token == ';') { - getToken(); - } - } - } - - /** - * Parse a single statement. Can be a an attribute statement, node - * statement, a series of node statements and edge statements, or a - * parameter. - * @param {Object} graph - */ - function parseStatement(graph) { - // parse subgraph - var subgraph = parseSubgraph(graph); - if (subgraph) { - // edge statements - parseEdge(graph, subgraph); - - return; - } - - // parse an attribute statement - var attr = parseAttributeStatement(graph); - if (attr) { - return; - } - - // parse node - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Identifier expected'); - } - var id = token; // id can be a string or a number - getToken(); - - if (token == '=') { - // id statement - getToken(); - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Identifier expected'); - } - graph[id] = token; - getToken(); - // TODO: implement comma separated list with "a_list: ID=ID [','] [a_list] " - } - else { - parseNodeStatement(graph, id); - } - } - - /** - * Parse a subgraph - * @param {Object} graph parent graph object - * @return {Object | null} subgraph - */ - function parseSubgraph (graph) { - var subgraph = null; - - // optional subgraph keyword - if (token == 'subgraph') { - subgraph = {}; - subgraph.type = 'subgraph'; - getToken(); - - // optional graph id - if (tokenType == TOKENTYPE.IDENTIFIER) { - subgraph.id = token; - getToken(); - } - } - - // open angle bracket - if (token == '{') { - getToken(); - - if (!subgraph) { - subgraph = {}; - } - subgraph.parent = graph; - subgraph.node = graph.node; - subgraph.edge = graph.edge; - subgraph.graph = graph.graph; - - // statements - parseStatements(subgraph); - - // close angle bracket - if (token != '}') { - throw newSyntaxError('Angle bracket } expected'); - } - getToken(); - - // remove temporary default properties - delete subgraph.node; - delete subgraph.edge; - delete subgraph.graph; - delete subgraph.parent; - - // register at the parent graph - if (!graph.subgraphs) { - graph.subgraphs = []; - } - graph.subgraphs.push(subgraph); - } - - return subgraph; - } - - /** - * parse an attribute statement like "node [shape=circle fontSize=16]". - * Available keywords are 'node', 'edge', 'graph'. - * The previous list with default attributes will be replaced - * @param {Object} graph - * @returns {String | null} keyword Returns the name of the parsed attribute - * (node, edge, graph), or null if nothing - * is parsed. - */ - function parseAttributeStatement (graph) { - // attribute statements - if (token == 'node') { - getToken(); - - // node attributes - graph.node = parseAttributeList(); - return 'node'; - } - else if (token == 'edge') { - getToken(); - - // edge attributes - graph.edge = parseAttributeList(); - return 'edge'; - } - else if (token == 'graph') { - getToken(); - - // graph attributes - graph.graph = parseAttributeList(); - return 'graph'; - } - - return null; - } - - /** - * parse a node statement - * @param {Object} graph - * @param {String | Number} id - */ - function parseNodeStatement(graph, id) { - // node statement - var node = { - id: id - }; - var attr = parseAttributeList(); - if (attr) { - node.attr = attr; - } - addNode(graph, node); - - // edge statements - parseEdge(graph, id); - } - - /** - * Parse an edge or a series of edges - * @param {Object} graph - * @param {String | Number} from Id of the from node - */ - function parseEdge(graph, from) { - while (token == '->' || token == '--') { - var to; - var type = token; - getToken(); - - var subgraph = parseSubgraph(graph); - if (subgraph) { - to = subgraph; - } - else { - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Identifier or subgraph expected'); - } - to = token; - addNode(graph, { - id: to - }); - getToken(); - } - - // parse edge attributes - var attr = parseAttributeList(); - - // create edge - var edge = createEdge(graph, from, to, type, attr); - addEdge(graph, edge); - - from = to; - } - } - - /** - * Parse a set with attributes, - * for example [label="1.000", shape=solid] - * @return {Object | null} attr - */ - function parseAttributeList() { - var attr = null; - - while (token == '[') { - getToken(); - attr = {}; - while (token !== '' && token != ']') { - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Attribute name expected'); - } - var name = token; - - getToken(); - if (token != '=') { - throw newSyntaxError('Equal sign = expected'); - } - getToken(); - - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Attribute value expected'); - } - var value = token; - setValue(attr, name, value); // name can be a path - - getToken(); - if (token ==',') { - getToken(); - } - } - - if (token != ']') { - throw newSyntaxError('Bracket ] expected'); - } - getToken(); - } - - return attr; - } - - /** - * Create a syntax error with extra information on current token and index. - * @param {String} message - * @returns {SyntaxError} err - */ - function newSyntaxError(message) { - return new SyntaxError(message + ', got "' + chop(token, 30) + '" (char ' + index + ')'); - } - - /** - * Chop off text after a maximum length - * @param {String} text - * @param {Number} maxLength - * @returns {String} - */ - function chop (text, maxLength) { - return (text.length <= maxLength) ? text : (text.substr(0, 27) + '...'); - } - - /** - * Execute a function fn for each pair of elements in two arrays - * @param {Array | *} array1 - * @param {Array | *} array2 - * @param {function} fn - */ - function forEach2(array1, array2, fn) { - if (array1 instanceof Array) { - array1.forEach(function (elem1) { - if (array2 instanceof Array) { - array2.forEach(function (elem2) { - fn(elem1, elem2); - }); - } - else { - fn(elem1, array2); - } - }); - } - else { - if (array2 instanceof Array) { - array2.forEach(function (elem2) { - fn(array1, elem2); - }); - } - else { - fn(array1, array2); - } - } - } - - /** - * Convert a string containing a graph in DOT language into a map containing - * with nodes and edges in the format of graph. - * @param {String} data Text containing a graph in DOT-notation - * @return {Object} graphData - */ - function DOTToGraph (data) { - // parse the DOT file - var dotData = parseDOT(data); - var graphData = { - nodes: [], - edges: [], - options: {} - }; - - // copy the nodes - if (dotData.nodes) { - dotData.nodes.forEach(function (dotNode) { - var graphNode = { - id: dotNode.id, - label: String(dotNode.label || dotNode.id) - }; - merge(graphNode, dotNode.attr); - if (graphNode.image) { - graphNode.shape = 'image'; - } - graphData.nodes.push(graphNode); - }); - } - - // copy the edges - if (dotData.edges) { - /** - * Convert an edge in DOT format to an edge with VisGraph format - * @param {Object} dotEdge - * @returns {Object} graphEdge - */ - function convertEdge(dotEdge) { - var graphEdge = { - from: dotEdge.from, - to: dotEdge.to - }; - merge(graphEdge, dotEdge.attr); - graphEdge.style = (dotEdge.type == '->') ? 'arrow' : 'line'; - return graphEdge; - } - - dotData.edges.forEach(function (dotEdge) { - var from, to; - if (dotEdge.from instanceof Object) { - from = dotEdge.from.nodes; - } - else { - from = { - id: dotEdge.from - } - } - - if (dotEdge.to instanceof Object) { - to = dotEdge.to.nodes; - } - else { - to = { - id: dotEdge.to - } - } - - if (dotEdge.from instanceof Object && dotEdge.from.edges) { - dotEdge.from.edges.forEach(function (subEdge) { - var graphEdge = convertEdge(subEdge); - graphData.edges.push(graphEdge); - }); - } - - forEach2(from, to, function (from, to) { - var subEdge = createEdge(graphData, from.id, to.id, dotEdge.type, dotEdge.attr); - var graphEdge = convertEdge(subEdge); - graphData.edges.push(graphEdge); - }); - - if (dotEdge.to instanceof Object && dotEdge.to.edges) { - dotEdge.to.edges.forEach(function (subEdge) { - var graphEdge = convertEdge(subEdge); - graphData.edges.push(graphEdge); - }); - } - }); - } - - // copy the options - if (dotData.attr) { - graphData.options = dotData.attr; - } - - return graphData; - } - - // exports - exports.parseDOT = parseDOT; - exports.DOTToGraph = DOTToGraph; - -})(typeof util !== 'undefined' ? util : exports); - -/** - * Canvas shapes used by the Graph - */ -if (typeof CanvasRenderingContext2D !== 'undefined') { - - /** - * Draw a circle shape - */ - CanvasRenderingContext2D.prototype.circle = function(x, y, r) { - this.beginPath(); - this.arc(x, y, r, 0, 2*Math.PI, false); - }; - - /** - * Draw a square shape - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r size, width and height of the square - */ - CanvasRenderingContext2D.prototype.square = function(x, y, r) { - this.beginPath(); - this.rect(x - r, y - r, r * 2, r * 2); - }; - - /** - * Draw a triangle shape - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r radius, half the length of the sides of the triangle - */ - CanvasRenderingContext2D.prototype.triangle = function(x, y, r) { - // http://en.wikipedia.org/wiki/Equilateral_triangle - this.beginPath(); - - var s = r * 2; - var s2 = s / 2; - var ir = Math.sqrt(3) / 6 * s; // radius of inner circle - var h = Math.sqrt(s * s - s2 * s2); // height - - this.moveTo(x, y - (h - ir)); - this.lineTo(x + s2, y + ir); - this.lineTo(x - s2, y + ir); - this.lineTo(x, y - (h - ir)); - this.closePath(); - }; - - /** - * Draw a triangle shape in downward orientation - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r radius - */ - CanvasRenderingContext2D.prototype.triangleDown = function(x, y, r) { - // http://en.wikipedia.org/wiki/Equilateral_triangle - this.beginPath(); - - var s = r * 2; - var s2 = s / 2; - var ir = Math.sqrt(3) / 6 * s; // radius of inner circle - var h = Math.sqrt(s * s - s2 * s2); // height - - this.moveTo(x, y + (h - ir)); - this.lineTo(x + s2, y - ir); - this.lineTo(x - s2, y - ir); - this.lineTo(x, y + (h - ir)); - this.closePath(); - }; - - /** - * Draw a star shape, a star with 5 points - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r radius, half the length of the sides of the triangle - */ - CanvasRenderingContext2D.prototype.star = function(x, y, r) { - // http://www.html5canvastutorials.com/labs/html5-canvas-star-spinner/ - this.beginPath(); - - for (var n = 0; n < 10; n++) { - var radius = (n % 2 === 0) ? r * 1.3 : r * 0.5; - this.lineTo( - x + radius * Math.sin(n * 2 * Math.PI / 10), - y - radius * Math.cos(n * 2 * Math.PI / 10) - ); - } - - this.closePath(); - }; - - /** - * http://stackoverflow.com/questions/1255512/how-to-draw-a-rounded-rectangle-on-html-canvas - */ - CanvasRenderingContext2D.prototype.roundRect = function(x, y, w, h, r) { - var r2d = Math.PI/180; - if( w - ( 2 * r ) < 0 ) { r = ( w / 2 ); } //ensure that the radius isn't too large for x - if( h - ( 2 * r ) < 0 ) { r = ( h / 2 ); } //ensure that the radius isn't too large for y - this.beginPath(); - this.moveTo(x+r,y); - this.lineTo(x+w-r,y); - this.arc(x+w-r,y+r,r,r2d*270,r2d*360,false); - this.lineTo(x+w,y+h-r); - this.arc(x+w-r,y+h-r,r,0,r2d*90,false); - this.lineTo(x+r,y+h); - this.arc(x+r,y+h-r,r,r2d*90,r2d*180,false); - this.lineTo(x,y+r); - this.arc(x+r,y+r,r,r2d*180,r2d*270,false); - }; - - /** - * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - */ - CanvasRenderingContext2D.prototype.ellipse = function(x, y, w, h) { - var kappa = .5522848, - ox = (w / 2) * kappa, // control point offset horizontal - oy = (h / 2) * kappa, // control point offset vertical - xe = x + w, // x-end - ye = y + h, // y-end - xm = x + w / 2, // x-middle - ym = y + h / 2; // y-middle - - this.beginPath(); - this.moveTo(x, ym); - this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); - this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); - this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); - this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - }; - - - - /** - * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - */ - CanvasRenderingContext2D.prototype.database = function(x, y, w, h) { - var f = 1/3; - var wEllipse = w; - var hEllipse = h * f; - - var kappa = .5522848, - ox = (wEllipse / 2) * kappa, // control point offset horizontal - oy = (hEllipse / 2) * kappa, // control point offset vertical - xe = x + wEllipse, // x-end - ye = y + hEllipse, // y-end - xm = x + wEllipse / 2, // x-middle - ym = y + hEllipse / 2, // y-middle - ymb = y + (h - hEllipse/2), // y-midlle, bottom ellipse - yeb = y + h; // y-end, bottom ellipse - - this.beginPath(); - this.moveTo(xe, ym); - - this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); - this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - - this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); - this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); - - this.lineTo(xe, ymb); - - this.bezierCurveTo(xe, ymb + oy, xm + ox, yeb, xm, yeb); - this.bezierCurveTo(xm - ox, yeb, x, ymb + oy, x, ymb); - - this.lineTo(x, ym); - }; - - - /** - * Draw an arrow point (no line) - */ - CanvasRenderingContext2D.prototype.arrow = function(x, y, angle, length) { - // tail - var xt = x - length * Math.cos(angle); - var yt = y - length * Math.sin(angle); - - // inner tail - // TODO: allow to customize different shapes - var xi = x - length * 0.9 * Math.cos(angle); - var yi = y - length * 0.9 * Math.sin(angle); - - // left - var xl = xt + length / 3 * Math.cos(angle + 0.5 * Math.PI); - var yl = yt + length / 3 * Math.sin(angle + 0.5 * Math.PI); - - // right - var xr = xt + length / 3 * Math.cos(angle - 0.5 * Math.PI); - var yr = yt + length / 3 * Math.sin(angle - 0.5 * Math.PI); - - this.beginPath(); - this.moveTo(x, y); - this.lineTo(xl, yl); - this.lineTo(xi, yi); - this.lineTo(xr, yr); - this.closePath(); - }; - - /** - * Sets up the dashedLine functionality for drawing - * Original code came from http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas - * @author David Jordan - * @date 2012-08-08 - */ - CanvasRenderingContext2D.prototype.dashedLine = function(x,y,x2,y2,dashArray){ - if (!dashArray) dashArray=[10,5]; - if (dashLength==0) dashLength = 0.001; // Hack for Safari - var dashCount = dashArray.length; - this.moveTo(x, y); - var dx = (x2-x), dy = (y2-y); - var slope = dy/dx; - var distRemaining = Math.sqrt( dx*dx + dy*dy ); - var dashIndex=0, draw=true; - while (distRemaining>=0.1){ - var dashLength = dashArray[dashIndex++%dashCount]; - if (dashLength > distRemaining) dashLength = distRemaining; - var xStep = Math.sqrt( dashLength*dashLength / (1 + slope*slope) ); - if (dx<0) xStep = -xStep; - x += xStep; - y += slope*xStep; - this[draw ? 'lineTo' : 'moveTo'](x,y); - distRemaining -= dashLength; - draw = !draw; - } - }; - - // TODO: add diamond shape -} - -/** - * @class Node - * A node. A node can be connected to other nodes via one or multiple edges. - * @param {object} properties An object containing properties for the node. All - * properties are optional, except for the id. - * {number} id Id of the node. Required - * {string} label Text label for the node - * {number} x Horizontal position of the node - * {number} y Vertical position of the node - * {string} shape Node shape, available: - * "database", "circle", "ellipse", - * "box", "image", "text", "dot", - * "star", "triangle", "triangleDown", - * "square" - * {string} image An image url - * {string} title An title text, can be HTML - * {anytype} group A group name or number - * @param {Graph.Images} imagelist A list with images. Only needed - * when the node has an image - * @param {Graph.Groups} grouplist A list with groups. Needed for - * retrieving group properties - * @param {Object} constants An object with default values for - * example for the color - */ -function Node(properties, imagelist, grouplist, constants) { - this.selected = false; - - this.edges = []; // all edges connected to this node - this.group = constants.nodes.group; - - this.fontSize = constants.nodes.fontSize; - this.fontFace = constants.nodes.fontFace; - this.fontColor = constants.nodes.fontColor; - - this.color = constants.nodes.color; - - // set defaults for the properties - this.id = undefined; - this.shape = constants.nodes.shape; - this.image = constants.nodes.image; - this.x = 0; - this.y = 0; - this.xFixed = false; - this.yFixed = false; - this.radius = constants.nodes.radius; - this.radiusFixed = false; - this.radiusMin = constants.nodes.radiusMin; - this.radiusMax = constants.nodes.radiusMax; - - this.imagelist = imagelist; - this.grouplist = grouplist; - - this.setProperties(properties, constants); - - // mass, force, velocity - this.mass = 50; // kg (mass is adjusted for the number of connected edges) - this.fx = 0.0; // external force x - this.fy = 0.0; // external force y - this.vx = 0.0; // velocity x - this.vy = 0.0; // velocity y - this.minForce = constants.minForce; - this.damping = 0.9; // damping factor -}; - -/** - * Attach a edge to the node - * @param {Edge} edge - */ -Node.prototype.attachEdge = function(edge) { - if (this.edges.indexOf(edge) == -1) { - this.edges.push(edge); - } - this._updateMass(); -}; - -/** - * Detach a edge from the node - * @param {Edge} edge - */ -Node.prototype.detachEdge = function(edge) { - var index = this.edges.indexOf(edge); - if (index != -1) { - this.edges.splice(index, 1); - } - this._updateMass(); -}; - -/** - * Update the nodes mass, which is determined by the number of edges connecting - * to it (more edges -> heavier node). - * @private - */ -Node.prototype._updateMass = function() { - this.mass = 50 + 20 * this.edges.length; // kg -}; - -/** - * Set or overwrite properties for the node - * @param {Object} properties an object with properties - * @param {Object} constants and object with default, global properties - */ -Node.prototype.setProperties = function(properties, constants) { - if (!properties) { - return; - } - - // basic properties - if (properties.id != undefined) {this.id = properties.id;} - if (properties.label != undefined) {this.label = properties.label;} - if (properties.title != undefined) {this.title = properties.title;} - if (properties.group != undefined) {this.group = properties.group;} - if (properties.x != undefined) {this.x = properties.x;} - if (properties.y != undefined) {this.y = properties.y;} - if (properties.value != undefined) {this.value = properties.value;} - - if (this.id === undefined) { - throw "Node must have an id"; - } - - // copy group properties - if (this.group) { - var groupObj = this.grouplist.get(this.group); - for (var prop in groupObj) { - if (groupObj.hasOwnProperty(prop)) { - this[prop] = groupObj[prop]; - } - } - } - - // individual shape properties - if (properties.shape != undefined) {this.shape = properties.shape;} - if (properties.image != undefined) {this.image = properties.image;} - if (properties.radius != undefined) {this.radius = properties.radius;} - if (properties.color != undefined) {this.color = Node.parseColor(properties.color);} - - if (properties.fontColor != undefined) {this.fontColor = properties.fontColor;} - if (properties.fontSize != undefined) {this.fontSize = properties.fontSize;} - if (properties.fontFace != undefined) {this.fontFace = properties.fontFace;} - - - if (this.image != undefined) { - if (this.imagelist) { - this.imageObj = this.imagelist.load(this.image); - } - else { - throw "No imagelist provided"; - } - } - - this.xFixed = this.xFixed || (properties.x != undefined); - this.yFixed = this.yFixed || (properties.y != undefined); - this.radiusFixed = this.radiusFixed || (properties.radius != undefined); - - if (this.shape == 'image') { - this.radiusMin = constants.nodes.widthMin; - this.radiusMax = constants.nodes.widthMax; - } - - // choose draw method depending on the shape - switch (this.shape) { - case 'database': this.draw = this._drawDatabase; this.resize = this._resizeDatabase; break; - case 'box': this.draw = this._drawBox; this.resize = this._resizeBox; break; - case 'circle': this.draw = this._drawCircle; this.resize = this._resizeCircle; break; - case 'ellipse': this.draw = this._drawEllipse; this.resize = this._resizeEllipse; break; - // TODO: add diamond shape - case 'image': this.draw = this._drawImage; this.resize = this._resizeImage; break; - case 'text': this.draw = this._drawText; this.resize = this._resizeText; break; - case 'dot': this.draw = this._drawDot; this.resize = this._resizeShape; break; - case 'square': this.draw = this._drawSquare; this.resize = this._resizeShape; break; - case 'triangle': this.draw = this._drawTriangle; this.resize = this._resizeShape; break; - case 'triangleDown': this.draw = this._drawTriangleDown; this.resize = this._resizeShape; break; - case 'star': this.draw = this._drawStar; this.resize = this._resizeShape; break; - default: this.draw = this._drawEllipse; this.resize = this._resizeEllipse; break; - } - - // reset the size of the node, this can be changed - this._reset(); -}; - -/** - * Parse a color property into an object with border, background, and - * hightlight colors - * @param {Object | String} color - * @return {Object} colorObject - */ -Node.parseColor = function(color) { - var c; - if (util.isString(color)) { - c = { - border: color, - background: color, - highlight: { - border: color, - background: color - } - }; - // TODO: automatically generate a nice highlight color - } - else { - c = {}; - c.background = color.background || 'white'; - c.border = color.border || c.background; - if (util.isString(color.highlight)) { - c.highlight = { - border: color.highlight, - background: color.highlight - } - } - else { - c.highlight = {}; - c.highlight.background = color.highlight && color.highlight.background || c.background; - c.highlight.border = color.highlight && color.highlight.border || c.border; - } - } - return c; -}; - -/** - * select this node - */ -Node.prototype.select = function() { - this.selected = true; - this._reset(); -}; - -/** - * unselect this node - */ -Node.prototype.unselect = function() { - this.selected = false; - this._reset(); -}; - -/** - * Reset the calculated size of the node, forces it to recalculate its size - * @private - */ -Node.prototype._reset = function() { - this.width = undefined; - this.height = undefined; -}; - -/** - * get the title of this node. - * @return {string} title The title of the node, or undefined when no title - * has been set. - */ -Node.prototype.getTitle = function() { - return this.title; -}; - -/** - * Calculate the distance to the border of the Node - * @param {CanvasRenderingContext2D} ctx - * @param {Number} angle Angle in radians - * @returns {number} distance Distance to the border in pixels - */ -Node.prototype.distanceToBorder = function (ctx, angle) { - var borderWidth = 1; - - if (!this.width) { - this.resize(ctx); - } - - //noinspection FallthroughInSwitchStatementJS - switch (this.shape) { - case 'circle': - case 'dot': - return this.radius + borderWidth; - - case 'ellipse': - var a = this.width / 2; - var b = this.height / 2; - var w = (Math.sin(angle) * a); - var h = (Math.cos(angle) * b); - return a * b / Math.sqrt(w * w + h * h); - - // TODO: implement distanceToBorder for database - // TODO: implement distanceToBorder for triangle - // TODO: implement distanceToBorder for triangleDown - - case 'box': - case 'image': - case 'text': - default: - if (this.width) { - return Math.min( - Math.abs(this.width / 2 / Math.cos(angle)), - Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth; - // TODO: reckon with border radius too in case of box - } - else { - return 0; - } - - } - - // TODO: implement calculation of distance to border for all shapes -}; - -/** - * Set forces acting on the node - * @param {number} fx Force in horizontal direction - * @param {number} fy Force in vertical direction - */ -Node.prototype._setForce = function(fx, fy) { - this.fx = fx; - this.fy = fy; -}; - -/** - * Add forces acting on the node - * @param {number} fx Force in horizontal direction - * @param {number} fy Force in vertical direction - * @private - */ -Node.prototype._addForce = function(fx, fy) { - this.fx += fx; - this.fy += fy; -}; - -/** - * Perform one discrete step for the node - * @param {number} interval Time interval in seconds - */ -Node.prototype.discreteStep = function(interval) { - if (!this.xFixed) { - var dx = -this.damping * this.vx; // damping force - var ax = (this.fx + dx) / this.mass; // acceleration - this.vx += ax / interval; // velocity - this.x += this.vx / interval; // position - } - - if (!this.yFixed) { - var dy = -this.damping * this.vy; // damping force - var ay = (this.fy + dy) / this.mass; // acceleration - this.vy += ay / interval; // velocity - this.y += this.vy / interval; // position - } -}; - - -/** - * Check if this node has a fixed x and y position - * @return {boolean} true if fixed, false if not - */ -Node.prototype.isFixed = function() { - return (this.xFixed && this.yFixed); -}; - -/** - * Check if this node is moving - * @param {number} vmin the minimum velocity considered as "moving" - * @return {boolean} true if moving, false if it has no velocity - */ -// TODO: replace this method with calculating the kinetic energy -Node.prototype.isMoving = function(vmin) { - return (Math.abs(this.vx) > vmin || Math.abs(this.vy) > vmin || - (!this.xFixed && Math.abs(this.fx) > this.minForce) || - (!this.yFixed && Math.abs(this.fy) > this.minForce)); -}; - -/** - * check if this node is selecte - * @return {boolean} selected True if node is selected, else false - */ -Node.prototype.isSelected = function() { - return this.selected; -}; - -/** - * Retrieve the value of the node. Can be undefined - * @return {Number} value - */ -Node.prototype.getValue = function() { - return this.value; -}; - -/** - * Calculate the distance from the nodes location to the given location (x,y) - * @param {Number} x - * @param {Number} y - * @return {Number} value - */ -Node.prototype.getDistance = function(x, y) { - var dx = this.x - x, - dy = this.y - y; - return Math.sqrt(dx * dx + dy * dy); -}; - - -/** - * Adjust the value range of the node. The node will adjust it's radius - * based on its value. - * @param {Number} min - * @param {Number} max - */ -Node.prototype.setValueRange = function(min, max) { - if (!this.radiusFixed && this.value !== undefined) { - var scale = (this.radiusMax - this.radiusMin) / (max - min); - this.radius = (this.value - min) * scale + this.radiusMin; - } -}; - -/** - * Draw this node in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - */ -Node.prototype.draw = function(ctx) { - throw "Draw method not initialized for node"; -}; - -/** - * Recalculate the size of this node in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - */ -Node.prototype.resize = function(ctx) { - throw "Resize method not initialized for node"; -}; - -/** - * Check if this object is overlapping with the provided object - * @param {Object} obj an object with parameters left, top, right, bottom - * @return {boolean} True if location is located on node - */ -Node.prototype.isOverlappingWith = function(obj) { - return (this.left < obj.right && - this.left + this.width > obj.left && - this.top < obj.bottom && - this.top + this.height > obj.top); -}; - -Node.prototype._resizeImage = function (ctx) { - // TODO: pre calculate the image size - if (!this.width) { // undefined or 0 - var width, height; - if (this.value) { - var scale = this.imageObj.height / this.imageObj.width; - width = this.radius || this.imageObj.width; - height = this.radius * scale || this.imageObj.height; - } - else { - width = this.imageObj.width; - height = this.imageObj.height; - } - this.width = width; - this.height = height; - } -}; - -Node.prototype._drawImage = function (ctx) { - this._resizeImage(ctx); - - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - var yLabel; - if (this.imageObj) { - ctx.drawImage(this.imageObj, this.left, this.top, this.width, this.height); - yLabel = this.y + this.height / 2; - } - else { - // image still loading... just draw the label for now - yLabel = this.y; - } - - this._label(ctx, this.label, this.x, yLabel, undefined, "top"); -}; - - -Node.prototype._resizeBox = function (ctx) { - if (!this.width) { - var margin = 5; - var textSize = this.getTextSize(ctx); - this.width = textSize.width + 2 * margin; - this.height = textSize.height + 2 * margin; - } -}; - -Node.prototype._drawBox = function (ctx) { - this._resizeBox(ctx); - - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; - ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; - ctx.lineWidth = this.selected ? 2.0 : 1.0; - ctx.roundRect(this.left, this.top, this.width, this.height, this.radius); - ctx.fill(); - ctx.stroke(); - - this._label(ctx, this.label, this.x, this.y); -}; - - -Node.prototype._resizeDatabase = function (ctx) { - if (!this.width) { - var margin = 5; - var textSize = this.getTextSize(ctx); - var size = textSize.width + 2 * margin; - this.width = size; - this.height = size; - } -}; - -Node.prototype._drawDatabase = function (ctx) { - this._resizeDatabase(ctx); - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; - ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; - ctx.lineWidth = this.selected ? 2.0 : 1.0; - ctx.database(this.x - this.width/2, this.y - this.height*0.5, this.width, this.height); - ctx.fill(); - ctx.stroke(); - - this._label(ctx, this.label, this.x, this.y); -}; - - -Node.prototype._resizeCircle = function (ctx) { - if (!this.width) { - var margin = 5; - var textSize = this.getTextSize(ctx); - var diameter = Math.max(textSize.width, textSize.height) + 2 * margin; - this.radius = diameter / 2; - - this.width = diameter; - this.height = diameter; - } -}; - -Node.prototype._drawCircle = function (ctx) { - this._resizeCircle(ctx); - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; - ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; - ctx.lineWidth = this.selected ? 2.0 : 1.0; - ctx.circle(this.x, this.y, this.radius); - ctx.fill(); - ctx.stroke(); - - this._label(ctx, this.label, this.x, this.y); -}; - -Node.prototype._resizeEllipse = function (ctx) { - if (!this.width) { - var textSize = this.getTextSize(ctx); - - this.width = textSize.width * 1.5; - this.height = textSize.height * 2; - if (this.width < this.height) { - this.width = this.height; - } - } -}; - -Node.prototype._drawEllipse = function (ctx) { - this._resizeEllipse(ctx); - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; - ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; - ctx.lineWidth = this.selected ? 2.0 : 1.0; - ctx.ellipse(this.left, this.top, this.width, this.height); - ctx.fill(); - ctx.stroke(); - - this._label(ctx, this.label, this.x, this.y); -}; - -Node.prototype._drawDot = function (ctx) { - this._drawShape(ctx, 'circle'); -}; - -Node.prototype._drawTriangle = function (ctx) { - this._drawShape(ctx, 'triangle'); -}; - -Node.prototype._drawTriangleDown = function (ctx) { - this._drawShape(ctx, 'triangleDown'); -}; - -Node.prototype._drawSquare = function (ctx) { - this._drawShape(ctx, 'square'); -}; - -Node.prototype._drawStar = function (ctx) { - this._drawShape(ctx, 'star'); -}; - -Node.prototype._resizeShape = function (ctx) { - if (!this.width) { - var size = 2 * this.radius; - this.width = size; - this.height = size; - } -}; - -Node.prototype._drawShape = function (ctx, shape) { - this._resizeShape(ctx); - - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; - ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; - ctx.lineWidth = this.selected ? 2.0 : 1.0; - - ctx[shape](this.x, this.y, this.radius); - ctx.fill(); - ctx.stroke(); - - if (this.label) { - this._label(ctx, this.label, this.x, this.y + this.height / 2, undefined, 'top'); - } -}; - -Node.prototype._resizeText = function (ctx) { - if (!this.width) { - var margin = 5; - var textSize = this.getTextSize(ctx); - this.width = textSize.width + 2 * margin; - this.height = textSize.height + 2 * margin; - } -}; - -Node.prototype._drawText = function (ctx) { - this._resizeText(ctx); - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - this._label(ctx, this.label, this.x, this.y); -}; - - -Node.prototype._label = function (ctx, text, x, y, align, baseline) { - if (text) { - ctx.font = (this.selected ? "bold " : "") + this.fontSize + "px " + this.fontFace; - ctx.fillStyle = this.fontColor || "black"; - ctx.textAlign = align || "center"; - ctx.textBaseline = baseline || "middle"; - - var lines = text.split('\n'), - lineCount = lines.length, - fontSize = (this.fontSize + 4), - yLine = y + (1 - lineCount) / 2 * fontSize; - - for (var i = 0; i < lineCount; i++) { - ctx.fillText(lines[i], x, yLine); - yLine += fontSize; - } - } -}; - - -Node.prototype.getTextSize = function(ctx) { - if (this.label != undefined) { - ctx.font = (this.selected ? "bold " : "") + this.fontSize + "px " + this.fontFace; - - var lines = this.label.split('\n'), - height = (this.fontSize + 4) * lines.length, - width = 0; - - for (var i = 0, iMax = lines.length; i < iMax; i++) { - width = Math.max(width, ctx.measureText(lines[i]).width); - } - - return {"width": width, "height": height}; - } - else { - return {"width": 0, "height": 0}; - } -}; - -/** - * @class Edge - * - * A edge connects two nodes - * @param {Object} properties Object with properties. Must contain - * At least properties from and to. - * Available properties: from (number), - * to (number), label (string, color (string), - * width (number), style (string), - * length (number), title (string) - * @param {Graph} graph A graph object, used to find and edge to - * nodes. - * @param {Object} constants An object with default values for - * example for the color - */ -function Edge (properties, graph, constants) { - if (!graph) { - throw "No graph provided"; - } - this.graph = graph; - - // initialize constants - this.widthMin = constants.edges.widthMin; - this.widthMax = constants.edges.widthMax; - - // initialize variables - this.id = undefined; - this.fromId = undefined; - this.toId = undefined; - this.style = constants.edges.style; - this.title = undefined; - this.width = constants.edges.width; - this.value = undefined; - this.length = constants.edges.length; - - this.from = null; // a node - this.to = null; // a node - this.connected = false; - - // Added to support dashed lines - // David Jordan - // 2012-08-08 - this.dash = util.extend({}, constants.edges.dash); // contains properties length, gap, altLength - - this.stiffness = undefined; // depends on the length of the edge - this.color = constants.edges.color; - this.widthFixed = false; - this.lengthFixed = false; - - this.setProperties(properties, constants); -} - -/** - * Set or overwrite properties for the edge - * @param {Object} properties an object with properties - * @param {Object} constants and object with default, global properties - */ -Edge.prototype.setProperties = function(properties, constants) { - if (!properties) { - return; - } - - if (properties.from != undefined) {this.fromId = properties.from;} - if (properties.to != undefined) {this.toId = properties.to;} - - if (properties.id != undefined) {this.id = properties.id;} - if (properties.style != undefined) {this.style = properties.style;} - if (properties.label != undefined) {this.label = properties.label;} - if (this.label) { - this.fontSize = constants.edges.fontSize; - this.fontFace = constants.edges.fontFace; - this.fontColor = constants.edges.fontColor; - if (properties.fontColor != undefined) {this.fontColor = properties.fontColor;} - if (properties.fontSize != undefined) {this.fontSize = properties.fontSize;} - if (properties.fontFace != undefined) {this.fontFace = properties.fontFace;} - } - if (properties.title != undefined) {this.title = properties.title;} - if (properties.width != undefined) {this.width = properties.width;} - if (properties.value != undefined) {this.value = properties.value;} - if (properties.length != undefined) {this.length = properties.length;} - - // Added to support dashed lines - // David Jordan - // 2012-08-08 - if (properties.dash) { - if (properties.dash.length != undefined) {this.dash.length = properties.dash.length;} - if (properties.dash.gap != undefined) {this.dash.gap = properties.dash.gap;} - if (properties.dash.altLength != undefined) {this.dash.altLength = properties.dash.altLength;} - } - - if (properties.color != undefined) {this.color = properties.color;} - - // A node is connected when it has a from and to node. - this.connect(); - - this.widthFixed = this.widthFixed || (properties.width != undefined); - this.lengthFixed = this.lengthFixed || (properties.length != undefined); - this.stiffness = 1 / this.length; - - // set draw method based on style - switch (this.style) { - case 'line': this.draw = this._drawLine; break; - case 'arrow': this.draw = this._drawArrow; break; - case 'arrow-center': this.draw = this._drawArrowCenter; break; - case 'dash-line': this.draw = this._drawDashLine; break; - default: this.draw = this._drawLine; break; - } -}; - -/** - * Connect an edge to its nodes - */ -Edge.prototype.connect = function () { - this.disconnect(); - - this.from = this.graph.nodes[this.fromId] || null; - this.to = this.graph.nodes[this.toId] || null; - this.connected = (this.from && this.to); - - if (this.connected) { - this.from.attachEdge(this); - this.to.attachEdge(this); - } - else { - if (this.from) { - this.from.detachEdge(this); - } - if (this.to) { - this.to.detachEdge(this); - } - } -}; - -/** - * Disconnect an edge from its nodes - */ -Edge.prototype.disconnect = function () { - if (this.from) { - this.from.detachEdge(this); - this.from = null; - } - if (this.to) { - this.to.detachEdge(this); - this.to = null; - } - - this.connected = false; -}; - -/** - * get the title of this edge. - * @return {string} title The title of the edge, or undefined when no title - * has been set. - */ -Edge.prototype.getTitle = function() { - return this.title; -}; - - -/** - * Retrieve the value of the edge. Can be undefined - * @return {Number} value - */ -Edge.prototype.getValue = function() { - return this.value; -}; - -/** - * Adjust the value range of the edge. The edge will adjust it's width - * based on its value. - * @param {Number} min - * @param {Number} max - */ -Edge.prototype.setValueRange = function(min, max) { - if (!this.widthFixed && this.value !== undefined) { - var factor = (this.widthMax - this.widthMin) / (max - min); - this.width = (this.value - min) * factor + this.widthMin; - } -}; - -/** - * Redraw a edge - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - */ -Edge.prototype.draw = function(ctx) { - throw "Method draw not initialized in edge"; -}; - -/** - * Check if this object is overlapping with the provided object - * @param {Object} obj an object with parameters left, top - * @return {boolean} True if location is located on the edge - */ -Edge.prototype.isOverlappingWith = function(obj) { - var distMax = 10; - - var xFrom = this.from.x; - var yFrom = this.from.y; - var xTo = this.to.x; - var yTo = this.to.y; - var xObj = obj.left; - var yObj = obj.top; - - - var dist = Edge._dist(xFrom, yFrom, xTo, yTo, xObj, yObj); - - return (dist < distMax); -}; - - -/** - * Redraw a edge as a line - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Edge.prototype._drawLine = function(ctx) { - // set style - ctx.strokeStyle = this.color; - ctx.lineWidth = this._getLineWidth(); - - var point; - if (this.from != this.to) { - // draw line - this._line(ctx); - - // draw label - if (this.label) { - point = this._pointOnLine(0.5); - this._label(ctx, this.label, point.x, point.y); - } - } - else { - var x, y; - var radius = this.length / 4; - var node = this.from; - if (!node.width) { - node.resize(ctx); - } - if (node.width > node.height) { - x = node.x + node.width / 2; - y = node.y - radius; - } - else { - x = node.x + radius; - y = node.y - node.height / 2; - } - this._circle(ctx, x, y, radius); - point = this._pointOnCircle(x, y, radius, 0.5); - this._label(ctx, this.label, point.x, point.y); - } -}; - -/** - * Get the line width of the edge. Depends on width and whether one of the - * connected nodes is selected. - * @return {Number} width - * @private - */ -Edge.prototype._getLineWidth = function() { - if (this.from.selected || this.to.selected) { - return Math.min(this.width * 2, this.widthMax); - } - else { - return this.width; - } -}; - -/** - * Draw a line between two nodes - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Edge.prototype._line = function (ctx) { - // draw a straight line - ctx.beginPath(); - ctx.moveTo(this.from.x, this.from.y); - ctx.lineTo(this.to.x, this.to.y); - ctx.stroke(); -}; - -/** - * Draw a line from a node to itself, a circle - * @param {CanvasRenderingContext2D} ctx - * @param {Number} x - * @param {Number} y - * @param {Number} radius - * @private - */ -Edge.prototype._circle = function (ctx, x, y, radius) { - // draw a circle - ctx.beginPath(); - ctx.arc(x, y, radius, 0, 2 * Math.PI, false); - ctx.stroke(); -}; - -/** - * Draw label with white background and with the middle at (x, y) - * @param {CanvasRenderingContext2D} ctx - * @param {String} text - * @param {Number} x - * @param {Number} y - * @private - */ -Edge.prototype._label = function (ctx, text, x, y) { - if (text) { - // TODO: cache the calculated size - ctx.font = ((this.from.selected || this.to.selected) ? "bold " : "") + - this.fontSize + "px " + this.fontFace; - ctx.fillStyle = 'white'; - var width = ctx.measureText(text).width; - var height = this.fontSize; - var left = x - width / 2; - var top = y - height / 2; - - ctx.fillRect(left, top, width, height); - - // draw text - ctx.fillStyle = this.fontColor || "black"; - ctx.textAlign = "left"; - ctx.textBaseline = "top"; - ctx.fillText(text, left, top); - } -}; - -/** - * Redraw a edge as a dashed line - * Draw this edge in the given canvas - * @author David Jordan - * @date 2012-08-08 - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Edge.prototype._drawDashLine = function(ctx) { - // set style - ctx.strokeStyle = this.color; - ctx.lineWidth = this._getLineWidth(); - - // draw dashed line - ctx.beginPath(); - ctx.lineCap = 'round'; - if (this.dash.altLength != undefined) //If an alt dash value has been set add to the array this value - { - ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, - [this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]); - } - else if (this.dash.length != undefined && this.dash.gap != undefined) //If a dash and gap value has been set add to the array this value - { - ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, - [this.dash.length,this.dash.gap]); - } - else //If all else fails draw a line - { - ctx.moveTo(this.from.x, this.from.y); - ctx.lineTo(this.to.x, this.to.y); - } - ctx.stroke(); - - // draw label - if (this.label) { - var point = this._pointOnLine(0.5); - this._label(ctx, this.label, point.x, point.y); - } -}; - -/** - * Get a point on a line - * @param {Number} percentage. Value between 0 (line start) and 1 (line end) - * @return {Object} point - * @private - */ -Edge.prototype._pointOnLine = function (percentage) { - return { - x: (1 - percentage) * this.from.x + percentage * this.to.x, - y: (1 - percentage) * this.from.y + percentage * this.to.y - } -}; - -/** - * Get a point on a circle - * @param {Number} x - * @param {Number} y - * @param {Number} radius - * @param {Number} percentage. Value between 0 (line start) and 1 (line end) - * @return {Object} point - * @private - */ -Edge.prototype._pointOnCircle = function (x, y, radius, percentage) { - var angle = (percentage - 3/8) * 2 * Math.PI; - return { - x: x + radius * Math.cos(angle), - y: y - radius * Math.sin(angle) - } -}; - -/** - * Redraw a edge as a line with an arrow halfway the line - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Edge.prototype._drawArrowCenter = function(ctx) { - var point; - // set style - ctx.strokeStyle = this.color; - ctx.fillStyle = this.color; - ctx.lineWidth = this._getLineWidth(); - - if (this.from != this.to) { - // draw line - this._line(ctx); - - // draw an arrow halfway the line - var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); - var length = 10 + 5 * this.width; // TODO: make customizable? - point = this._pointOnLine(0.5); - ctx.arrow(point.x, point.y, angle, length); - ctx.fill(); - ctx.stroke(); - - // draw label - if (this.label) { - point = this._pointOnLine(0.5); - this._label(ctx, this.label, point.x, point.y); - } - } - else { - // draw circle - var x, y; - var radius = this.length / 4; - var node = this.from; - if (!node.width) { - node.resize(ctx); - } - if (node.width > node.height) { - x = node.x + node.width / 2; - y = node.y - radius; - } - else { - x = node.x + radius; - y = node.y - node.height / 2; - } - this._circle(ctx, x, y, radius); - - // draw all arrows - var angle = 0.2 * Math.PI; - var length = 10 + 5 * this.width; // TODO: make customizable? - point = this._pointOnCircle(x, y, radius, 0.5); - ctx.arrow(point.x, point.y, angle, length); - ctx.fill(); - ctx.stroke(); - - // draw label - if (this.label) { - point = this._pointOnCircle(x, y, radius, 0.5); - this._label(ctx, this.label, point.x, point.y); - } - } -}; - - - -/** - * Redraw a edge as a line with an arrow - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Edge.prototype._drawArrow = function(ctx) { - // set style - ctx.strokeStyle = this.color; - ctx.fillStyle = this.color; - ctx.lineWidth = this._getLineWidth(); - - // draw line - var angle, length; - if (this.from != this.to) { - // calculate length and angle of the line - angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); - var dx = (this.to.x - this.from.x); - var dy = (this.to.y - this.from.y); - var lEdge = Math.sqrt(dx * dx + dy * dy); - - var lFrom = this.from.distanceToBorder(ctx, angle + Math.PI); - var pFrom = (lEdge - lFrom) / lEdge; - var xFrom = (pFrom) * this.from.x + (1 - pFrom) * this.to.x; - var yFrom = (pFrom) * this.from.y + (1 - pFrom) * this.to.y; - - var lTo = this.to.distanceToBorder(ctx, angle); - var pTo = (lEdge - lTo) / lEdge; - var xTo = (1 - pTo) * this.from.x + pTo * this.to.x; - var yTo = (1 - pTo) * this.from.y + pTo * this.to.y; - - ctx.beginPath(); - ctx.moveTo(xFrom, yFrom); - ctx.lineTo(xTo, yTo); - ctx.stroke(); - - // draw arrow at the end of the line - length = 10 + 5 * this.width; // TODO: make customizable? - ctx.arrow(xTo, yTo, angle, length); - ctx.fill(); - ctx.stroke(); - - // draw label - if (this.label) { - var point = this._pointOnLine(0.5); - this._label(ctx, this.label, point.x, point.y); - } - } - else { - // draw circle - var node = this.from; - var x, y, arrow; - var radius = this.length / 4; - if (!node.width) { - node.resize(ctx); - } - if (node.width > node.height) { - x = node.x + node.width / 2; - y = node.y - radius; - arrow = { - x: x, - y: node.y, - angle: 0.9 * Math.PI - }; - } - else { - x = node.x + radius; - y = node.y - node.height / 2; - arrow = { - x: node.x, - y: y, - angle: 0.6 * Math.PI - }; - } - ctx.beginPath(); - // TODO: do not draw a circle, but an arc - // TODO: similarly, for a line without arrows, draw to the border of the nodes instead of the center - ctx.arc(x, y, radius, 0, 2 * Math.PI, false); - ctx.stroke(); - - // draw all arrows - length = 10 + 5 * this.width; // TODO: make customizable? - ctx.arrow(arrow.x, arrow.y, arrow.angle, length); - ctx.fill(); - ctx.stroke(); - - // draw label - if (this.label) { - point = this._pointOnCircle(x, y, radius, 0.5); - this._label(ctx, this.label, point.x, point.y); - } - } -}; - - - -/** - * Calculate the distance between a point (x3,y3) and a line segment from - * (x1,y1) to (x2,y2). - * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment - * @param {number} x1 - * @param {number} y1 - * @param {number} x2 - * @param {number} y2 - * @param {number} x3 - * @param {number} y3 - * @private - */ -Edge._dist = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point - var px = x2-x1, - py = y2-y1, - something = px*px + py*py, - u = ((x3 - x1) * px + (y3 - y1) * py) / something; - - if (u > 1) { - u = 1; - } - else if (u < 0) { - u = 0; - } - - var x = x1 + u * px, - y = y1 + u * py, - dx = x - x3, - dy = y - y3; - - //# Note: If the actual distance does not matter, - //# if you only want to compare what this function - //# returns to other results of this function, you - //# can just return the squared distance instead - //# (i.e. remove the sqrt) to gain a little performance - - return Math.sqrt(dx*dx + dy*dy); -}; - -/** - * Popup is a class to create a popup window with some text - * @param {Element} container The container object. - * @param {Number} [x] - * @param {Number} [y] - * @param {String} [text] - */ -function Popup(container, x, y, text) { - if (container) { - this.container = container; - } - else { - this.container = document.body; - } - this.x = 0; - this.y = 0; - this.padding = 5; - - if (x !== undefined && y !== undefined ) { - this.setPosition(x, y); - } - if (text !== undefined) { - this.setText(text); - } - - // create the frame - this.frame = document.createElement("div"); - var style = this.frame.style; - style.position = "absolute"; - style.visibility = "hidden"; - style.border = "1px solid #666"; - style.color = "black"; - style.padding = this.padding + "px"; - style.backgroundColor = "#FFFFC6"; - style.borderRadius = "3px"; - style.MozBorderRadius = "3px"; - style.WebkitBorderRadius = "3px"; - style.boxShadow = "3px 3px 10px rgba(128, 128, 128, 0.5)"; - style.whiteSpace = "nowrap"; - this.container.appendChild(this.frame); -}; - -/** - * @param {number} x Horizontal position of the popup window - * @param {number} y Vertical position of the popup window - */ -Popup.prototype.setPosition = function(x, y) { - this.x = parseInt(x); - this.y = parseInt(y); -}; - -/** - * Set the text for the popup window. This can be HTML code - * @param {string} text - */ -Popup.prototype.setText = function(text) { - this.frame.innerHTML = text; -}; - -/** - * Show the popup window - * @param {boolean} show Optional. Show or hide the window - */ -Popup.prototype.show = function (show) { - if (show === undefined) { - show = true; - } - - if (show) { - var height = this.frame.clientHeight; - var width = this.frame.clientWidth; - var maxHeight = this.frame.parentNode.clientHeight; - var maxWidth = this.frame.parentNode.clientWidth; - - var top = (this.y - height); - if (top + height + this.padding > maxHeight) { - top = maxHeight - height - this.padding; - } - if (top < this.padding) { - top = this.padding; - } - - var left = this.x; - if (left + width + this.padding > maxWidth) { - left = maxWidth - width - this.padding; - } - if (left < this.padding) { - left = this.padding; - } - - this.frame.style.left = left + "px"; - this.frame.style.top = top + "px"; - this.frame.style.visibility = "visible"; - } - else { - this.hide(); - } -}; - -/** - * Hide the popup window - */ -Popup.prototype.hide = function () { - this.frame.style.visibility = "hidden"; -}; - -/** - * @class Groups - * This class can store groups and properties specific for groups. - */ -Groups = function () { - this.clear(); - this.defaultIndex = 0; -}; - - -/** - * default constants for group colors - */ -Groups.DEFAULT = [ - {border: "#2B7CE9", background: "#97C2FC", highlight: {border: "#2B7CE9", background: "#D2E5FF"}}, // blue - {border: "#FFA500", background: "#FFFF00", highlight: {border: "#FFA500", background: "#FFFFA3"}}, // yellow - {border: "#FA0A10", background: "#FB7E81", highlight: {border: "#FA0A10", background: "#FFAFB1"}}, // red - {border: "#41A906", background: "#7BE141", highlight: {border: "#41A906", background: "#A1EC76"}}, // green - {border: "#E129F0", background: "#EB7DF4", highlight: {border: "#E129F0", background: "#F0B3F5"}}, // magenta - {border: "#7C29F0", background: "#AD85E4", highlight: {border: "#7C29F0", background: "#D3BDF0"}}, // purple - {border: "#C37F00", background: "#FFA807", highlight: {border: "#C37F00", background: "#FFCA66"}}, // orange - {border: "#4220FB", background: "#6E6EFD", highlight: {border: "#4220FB", background: "#9B9BFD"}}, // darkblue - {border: "#FD5A77", background: "#FFC0CB", highlight: {border: "#FD5A77", background: "#FFD1D9"}}, // pink - {border: "#4AD63A", background: "#C2FABC", highlight: {border: "#4AD63A", background: "#E6FFE3"}} // mint -]; - - -/** - * Clear all groups - */ -Groups.prototype.clear = function () { - this.groups = {}; - this.groups.length = function() - { - var i = 0; - for ( var p in this ) { - if (this.hasOwnProperty(p)) { - i++; - } - } - return i; - } -}; - - -/** - * get group properties of a groupname. If groupname is not found, a new group - * is added. - * @param {*} groupname Can be a number, string, Date, etc. - * @return {Object} group The created group, containing all group properties - */ -Groups.prototype.get = function (groupname) { - var group = this.groups[groupname]; - - if (group == undefined) { - // create new group - var index = this.defaultIndex % Groups.DEFAULT.length; - this.defaultIndex++; - group = {}; - group.color = Groups.DEFAULT[index]; - this.groups[groupname] = group; - } - - return group; -}; - -/** - * Add a custom group style - * @param {String} groupname - * @param {Object} style An object containing borderColor, - * backgroundColor, etc. - * @return {Object} group The created group object - */ -Groups.prototype.add = function (groupname, style) { - this.groups[groupname] = style; - if (style.color) { - style.color = Node.parseColor(style.color); - } - return style; -}; - -/** - * @class Images - * This class loads images and keeps them stored. - */ -Images = function () { - this.images = {}; - - this.callback = undefined; -}; - -/** - * Set an onload callback function. This will be called each time an image - * is loaded - * @param {function} callback - */ -Images.prototype.setOnloadCallback = function(callback) { - this.callback = callback; -}; - -/** - * - * @param {string} url Url of the image - * @return {Image} img The image object - */ -Images.prototype.load = function(url) { - var img = this.images[url]; - if (img == undefined) { - // create the image - var images = this; - img = new Image(); - this.images[url] = img; - img.onload = function() { - if (images.callback) { - images.callback(this); - } - }; - img.src = url; - } - - return img; -}; - -/** - * @constructor Graph - * Create a graph visualization, displaying nodes and edges. - * - * @param {Element} container The DOM element in which the Graph will - * be created. Normally a div element. - * @param {Object} data An object containing parameters - * {Array} nodes - * {Array} edges - * @param {Object} options Options - */ -function Graph (container, data, options) { - // create variables and set default values - this.containerElement = container; - this.width = '100%'; - this.height = '100%'; - this.refreshRate = 50; // milliseconds - this.stabilize = true; // stabilize before displaying the graph - this.selectable = true; - - // set constant values - this.constants = { - nodes: { - radiusMin: 5, - radiusMax: 20, - radius: 5, - distance: 100, // px - shape: 'ellipse', - image: undefined, - widthMin: 16, // px - widthMax: 64, // px - fontColor: 'black', - fontSize: 14, // px - //fontFace: verdana, - fontFace: 'arial', - color: { - border: '#2B7CE9', - background: '#97C2FC', - highlight: { - border: '#2B7CE9', - background: '#D2E5FF' - } - }, - borderColor: '#2B7CE9', - backgroundColor: '#97C2FC', - highlightColor: '#D2E5FF', - group: undefined - }, - edges: { - widthMin: 1, - widthMax: 15, - width: 1, - style: 'line', - color: '#343434', - fontColor: '#343434', - fontSize: 14, // px - fontFace: 'arial', - //distance: 100, //px - length: 100, // px - dash: { - length: 10, - gap: 5, - altLength: undefined - } - }, - minForce: 0.05, - minVelocity: 0.02, // px/s - maxIterations: 1000 // maximum number of iteration to stabilize - }; - - var graph = this; - this.nodes = {}; // object with Node objects - this.edges = {}; // object with Edge objects - // TODO: create a counter to keep track on the number of nodes having values - // TODO: create a counter to keep track on the number of nodes currently moving - // TODO: create a counter to keep track on the number of edges having values - - this.nodesData = null; // A DataSet or DataView - this.edgesData = null; // A DataSet or DataView - - // create event listeners used to subscribe on the DataSets of the nodes and edges - var me = this; - this.nodesListeners = { - 'add': function (event, params) { - me._addNodes(params.items); - me.start(); - }, - 'update': function (event, params) { - me._updateNodes(params.items); - me.start(); - }, - 'remove': function (event, params) { - me._removeNodes(params.items); - me.start(); - } - }; - this.edgesListeners = { - 'add': function (event, params) { - me._addEdges(params.items); - me.start(); - }, - 'update': function (event, params) { - me._updateEdges(params.items); - me.start(); - }, - 'remove': function (event, params) { - me._removeEdges(params.items); - me.start(); - } - }; - - this.groups = new Groups(); // object with groups - this.images = new Images(); // object with images - this.images.setOnloadCallback(function () { - graph._redraw(); - }); - - // properties of the data - this.moving = false; // True if any of the nodes have an undefined position - - this.selection = []; - this.timer = undefined; - - // create a frame and canvas - this._create(); - - // apply options - this.setOptions(options); - - // draw data - this.setData(data); -} - -/** - * Set nodes and edges, and optionally options as well. - * - * @param {Object} data Object containing parameters: - * {Array | DataSet | DataView} [nodes] Array with nodes - * {Array | DataSet | DataView} [edges] Array with edges - * {String} [dot] String containing data in DOT format - * {Options} [options] Object with options - */ -Graph.prototype.setData = function(data) { - if (data && data.dot && (data.nodes || data.edges)) { - throw new SyntaxError('Data must contain either parameter "dot" or ' + - ' parameter pair "nodes" and "edges", but not both.'); - } - - // set options - this.setOptions(data && data.options); - - // set all data - if (data && data.dot) { - // parse DOT file - if(data && data.dot) { - var dotData = vis.util.DOTToGraph(data.dot); - this.setData(dotData); - return; - } - } - else { - this._setNodes(data && data.nodes); - this._setEdges(data && data.edges); - } - - // find a stable position or start animating to a stable position - if (this.stabilize) { - this._doStabilize(); - } - this.start(); -}; - -/** - * Set options - * @param {Object} options - */ -Graph.prototype.setOptions = function (options) { - if (options) { - // retrieve parameter values - if (options.width != undefined) {this.width = options.width;} - if (options.height != undefined) {this.height = options.height;} - if (options.stabilize != undefined) {this.stabilize = options.stabilize;} - if (options.selectable != undefined) {this.selectable = options.selectable;} - - // TODO: work out these options and document them - if (options.edges) { - for (var prop in options.edges) { - if (options.edges.hasOwnProperty(prop)) { - this.constants.edges[prop] = options.edges[prop]; - } - } - - if (options.edges.length != undefined && - options.nodes && options.nodes.distance == undefined) { - this.constants.edges.length = options.edges.length; - this.constants.nodes.distance = options.edges.length * 1.25; - } - - if (!options.edges.fontColor) { - this.constants.edges.fontColor = options.edges.color; - } - - // Added to support dashed lines - // David Jordan - // 2012-08-08 - if (options.edges.dash) { - if (options.edges.dash.length != undefined) { - this.constants.edges.dash.length = options.edges.dash.length; - } - if (options.edges.dash.gap != undefined) { - this.constants.edges.dash.gap = options.edges.dash.gap; - } - if (options.edges.dash.altLength != undefined) { - this.constants.edges.dash.altLength = options.edges.dash.altLength; - } - } - } - - if (options.nodes) { - for (prop in options.nodes) { - if (options.nodes.hasOwnProperty(prop)) { - this.constants.nodes[prop] = options.nodes[prop]; - } - } - - if (options.nodes.color) { - this.constants.nodes.color = Node.parseColor(options.nodes.color); - } - - /* - if (options.nodes.widthMin) this.constants.nodes.radiusMin = options.nodes.widthMin; - if (options.nodes.widthMax) this.constants.nodes.radiusMax = options.nodes.widthMax; - */ - } - - if (options.groups) { - for (var groupname in options.groups) { - if (options.groups.hasOwnProperty(groupname)) { - var group = options.groups[groupname]; - this.groups.add(groupname, group); - } - } - } - } - - this.setSize(this.width, this.height); - this._setTranslation(this.frame.clientWidth / 2, this.frame.clientHeight / 2); - this._setScale(1); -}; - -/** - * fire an event - * @param {String} event The name of an event, for example 'select' - * @param {Object} params Optional object with event parameters - * @private - */ -Graph.prototype._trigger = function (event, params) { - events.trigger(this, event, params); -}; - - -/** - * Create the main frame for the Graph. - * This function is executed once when a Graph object is created. The frame - * contains a canvas, and this canvas contains all objects like the axis and - * nodes. - * @private - */ -Graph.prototype._create = function () { - // remove all elements from the container element. - while (this.containerElement.hasChildNodes()) { - this.containerElement.removeChild(this.containerElement.firstChild); - } - - this.frame = document.createElement('div'); - this.frame.className = 'graph-frame'; - this.frame.style.position = 'relative'; - this.frame.style.overflow = 'hidden'; - - // create the graph canvas (HTML canvas element) - this.frame.canvas = document.createElement( 'canvas' ); - this.frame.canvas.style.position = 'relative'; - this.frame.appendChild(this.frame.canvas); - if (!this.frame.canvas.getContext) { - var noCanvas = document.createElement( 'DIV' ); - noCanvas.style.color = 'red'; - noCanvas.style.fontWeight = 'bold' ; - noCanvas.style.padding = '10px'; - noCanvas.innerHTML = 'Error: your browser does not support HTML canvas'; - this.frame.canvas.appendChild(noCanvas); - } - - var me = this; - this.drag = {}; - this.pinch = {}; - this.hammer = Hammer(this.frame.canvas, { - prevent_default: true - }); - this.hammer.on('tap', me._onTap.bind(me) ); - this.hammer.on('hold', me._onHold.bind(me) ); - this.hammer.on('pinch', me._onPinch.bind(me) ); - this.hammer.on('touch', me._onTouch.bind(me) ); - this.hammer.on('dragstart', me._onDragStart.bind(me) ); - this.hammer.on('drag', me._onDrag.bind(me) ); - this.hammer.on('dragend', me._onDragEnd.bind(me) ); - this.hammer.on('mousewheel',me._onMouseWheel.bind(me) ); - this.hammer.on('mousemove', me._onMouseMoveTitle.bind(me) ); - - // add the frame to the container element - this.containerElement.appendChild(this.frame); -}; - -/** - * - * @param {{x: Number, y: Number}} pointer - * @return {Number | null} node - * @private - */ -Graph.prototype._getNodeAt = function (pointer) { - var x = this._canvasToX(pointer.x); - var y = this._canvasToY(pointer.y); - - var obj = { - left: x, - top: y, - right: x, - bottom: y - }; - - // if there are overlapping nodes, select the last one, this is the - // one which is drawn on top of the others - var overlappingNodes = this._getNodesOverlappingWith(obj); - return (overlappingNodes.length > 0) ? - overlappingNodes[overlappingNodes.length - 1] : null; -}; - -/** - * Get the pointer location from a touch location - * @param {{pageX: Number, pageY: Number}} touch - * @return {{x: Number, y: Number}} pointer - * @private - */ -Graph.prototype._getPointer = function (touch) { - return { - x: touch.pageX - vis.util.getAbsoluteLeft(this.frame.canvas), - y: touch.pageY - vis.util.getAbsoluteTop(this.frame.canvas) - }; -}; - -/** - * On start of a touch gesture, store the pointer - * @param event - * @private - */ -Graph.prototype._onTouch = function (event) { - this.drag.pointer = this._getPointer(event.gesture.touches[0]); - this.drag.pinched = false; - this.pinch.scale = this._getScale(); -}; - -/** - * handle drag start event - * @private - */ -Graph.prototype._onDragStart = function () { - var drag = this.drag; - - drag.selection = []; - drag.translation = this._getTranslation(); - drag.nodeId = this._getNodeAt(drag.pointer); - // note: drag.pointer is set in _onTouch to get the initial touch location - - var node = this.nodes[drag.nodeId]; - if (node) { - // select the clicked node if not yet selected - if (!node.isSelected()) { - this._selectNodes([drag.nodeId]); - } - - // create an array with the selected nodes and their original location and status - var me = this; - this.selection.forEach(function (id) { - var node = me.nodes[id]; - if (node) { - var s = { - id: id, - node: node, - - // store original x, y, xFixed and yFixed, make the node temporarily Fixed - x: node.x, - y: node.y, - xFixed: node.xFixed, - yFixed: node.yFixed - }; - - node.xFixed = true; - node.yFixed = true; - - drag.selection.push(s); - } - }); - - } -}; - -/** - * handle drag event - * @private - */ -Graph.prototype._onDrag = function (event) { - if (this.drag.pinched) { - return; - } - - var pointer = this._getPointer(event.gesture.touches[0]); - - var me = this, - drag = this.drag, - selection = drag.selection; - if (selection && selection.length) { - // calculate delta's and new location - var deltaX = pointer.x - drag.pointer.x, - deltaY = pointer.y - drag.pointer.y; - - // update position of all selected nodes - selection.forEach(function (s) { - var node = s.node; - - if (!s.xFixed) { - node.x = me._canvasToX(me._xToCanvas(s.x) + deltaX); - } - - if (!s.yFixed) { - node.y = me._canvasToY(me._yToCanvas(s.y) + deltaY); - } - }); - - // start animation if not yet running - if (!this.moving) { - this.moving = true; - this.start(); - } - } - else { - // move the graph - var diffX = pointer.x - this.drag.pointer.x; - var diffY = pointer.y - this.drag.pointer.y; - - this._setTranslation( - this.drag.translation.x + diffX, - this.drag.translation.y + diffY); - this._redraw(); - - this.moved = true; - } -}; - -/** - * handle drag start event - * @private - */ -Graph.prototype._onDragEnd = function () { - var selection = this.drag.selection; - if (selection) { - selection.forEach(function (s) { - // restore original xFixed and yFixed - s.node.xFixed = s.xFixed; - s.node.yFixed = s.yFixed; - }); - } -}; - -/** - * handle tap/click event: select/unselect a node - * @private - */ -Graph.prototype._onTap = function (event) { - var pointer = this._getPointer(event.gesture.touches[0]); - - var nodeId = this._getNodeAt(pointer); - var node = this.nodes[nodeId]; - if (node) { - // select this node - this._selectNodes([nodeId]); - - if (!this.moving) { - this._redraw(); - } - } - else { - // remove selection - this._unselectNodes(); - this._redraw(); - } -}; - -/** - * handle long tap event: multi select nodes - * @private - */ -Graph.prototype._onHold = function (event) { - var pointer = this._getPointer(event.gesture.touches[0]); - var nodeId = this._getNodeAt(pointer); - var node = this.nodes[nodeId]; - if (node) { - if (!node.isSelected()) { - // select this node, keep previous selection - var append = true; - this._selectNodes([nodeId], append); - } - else { - this._unselectNodes([nodeId]); - } - - if (!this.moving) { - this._redraw(); - } - } - else { - // Do nothing - } -}; - -/** - * Handle pinch event - * @param event - * @private - */ -Graph.prototype._onPinch = function (event) { - var pointer = this._getPointer(event.gesture.center); - - this.drag.pinched = true; - if (!('scale' in this.pinch)) { - this.pinch.scale = 1; - } - - // TODO: enable moving while pinching? - var scale = this.pinch.scale * event.gesture.scale; - this._zoom(scale, pointer) -}; - -/** - * Zoom the graph in or out - * @param {Number} scale a number around 1, and between 0.01 and 10 - * @param {{x: Number, y: Number}} pointer - * @return {Number} appliedScale scale is limited within the boundaries - * @private - */ -Graph.prototype._zoom = function(scale, pointer) { - var scaleOld = this._getScale(); - if (scale < 0.01) { - scale = 0.01; - } - if (scale > 10) { - scale = 10; - } - - var translation = this._getTranslation(); - var scaleFrac = scale / scaleOld; - var tx = (1 - scaleFrac) * pointer.x + translation.x * scaleFrac; - var ty = (1 - scaleFrac) * pointer.y + translation.y * scaleFrac; - - this._setScale(scale); - this._setTranslation(tx, ty); - this._redraw(); - - return scale; -}; - -/** - * Event handler for mouse wheel event, used to zoom the timeline - * See http://adomas.org/javascript-mouse-wheel/ - * https://github.com/EightMedia/hammer.js/issues/256 - * @param {MouseEvent} event - * @private - */ -Graph.prototype._onMouseWheel = function(event) { - // retrieve delta - var delta = 0; - if (event.wheelDelta) { /* IE/Opera. */ - delta = event.wheelDelta/120; - } else if (event.detail) { /* Mozilla case. */ - // In Mozilla, sign of delta is different than in IE. - // Also, delta is multiple of 3. - delta = -event.detail/3; - } - - // If delta is nonzero, handle it. - // Basically, delta is now positive if wheel was scrolled up, - // and negative, if wheel was scrolled down. - if (delta) { - if (!('mouswheelScale' in this.pinch)) { - this.pinch.mouswheelScale = 1; - } - - // calculate the new scale - var scale = this.pinch.mouswheelScale; - var zoom = delta / 10; - if (delta < 0) { - zoom = zoom / (1 - zoom); - } - scale *= (1 + zoom); - - // calculate the pointer location - var gesture = Hammer.event.collectEventData(this, 'scroll', event); - var pointer = this._getPointer(gesture.center); - - // apply the new scale - scale = this._zoom(scale, pointer); - - // store the new, applied scale - this.pinch.mouswheelScale = scale; - } - - // Prevent default actions caused by mouse wheel. - event.preventDefault(); -}; - - -/** - * Mouse move handler for checking whether the title moves over a node with a title. - * @param {Event} event - * @private - */ -Graph.prototype._onMouseMoveTitle = function (event) { - var gesture = Hammer.event.collectEventData(this, 'mousemove', event); - var pointer = this._getPointer(gesture.center); - - // check if the previously selected node is still selected - if (this.popupNode) { - this._checkHidePopup(pointer); - } - - // start a timeout that will check if the mouse is positioned above - // an element - var me = this; - var checkShow = function() { - me._checkShowPopup(pointer); - }; - if (this.popupTimer) { - clearInterval(this.popupTimer); // stop any running timer - } - if (!this.leftButtonDown) { - this.popupTimer = setTimeout(checkShow, 300); - } -}; - -/** - * Check if there is an element on the given position in the graph - * (a node or edge). If so, and if this element has a title, - * show a popup window with its title. - * - * @param {{x:Number, y:Number}} pointer - * @private - */ -Graph.prototype._checkShowPopup = function (pointer) { - var obj = { - left: this._canvasToX(pointer.x), - top: this._canvasToY(pointer.y), - right: this._canvasToX(pointer.x), - bottom: this._canvasToY(pointer.y) - }; - - var id; - var lastPopupNode = this.popupNode; - - if (this.popupNode == undefined) { - // search the nodes for overlap, select the top one in case of multiple nodes - var nodes = this.nodes; - for (id in nodes) { - if (nodes.hasOwnProperty(id)) { - var node = nodes[id]; - if (node.getTitle() != undefined && node.isOverlappingWith(obj)) { - this.popupNode = node; - break; - } - } - } - } - - if (this.popupNode == undefined) { - // search the edges for overlap - var edges = this.edges; - for (id in edges) { - if (edges.hasOwnProperty(id)) { - var edge = edges[id]; - if (edge.connected && (edge.getTitle() != undefined) && - edge.isOverlappingWith(obj)) { - this.popupNode = edge; - break; - } - } - } - } - - if (this.popupNode) { - // show popup message window - if (this.popupNode != lastPopupNode) { - var me = this; - if (!me.popup) { - me.popup = new Popup(me.frame); - } - - // adjust a small offset such that the mouse cursor is located in the - // bottom left location of the popup, and you can easily move over the - // popup area - me.popup.setPosition(pointer.x - 3, pointer.y - 3); - me.popup.setText(me.popupNode.getTitle()); - me.popup.show(); - } - } - else { - if (this.popup) { - this.popup.hide(); - } - } -}; - -/** - * Check if the popup must be hided, which is the case when the mouse is no - * longer hovering on the object - * @param {{x:Number, y:Number}} pointer - * @private - */ -Graph.prototype._checkHidePopup = function (pointer) { - if (!this.popupNode || !this._getNodeAt(pointer) ) { - this.popupNode = undefined; - if (this.popup) { - this.popup.hide(); - } - } -}; - -/** - * Unselect selected nodes. If no selection array is provided, all nodes - * are unselected - * @param {Object[]} selection Array with selection objects, each selection - * object has a parameter row. Optional - * @param {Boolean} triggerSelect If true (default), the select event - * is triggered when nodes are unselected - * @return {Boolean} changed True if the selection is changed - * @private - */ -Graph.prototype._unselectNodes = function(selection, triggerSelect) { - var changed = false; - var i, iMax, id; - - if (selection) { - // remove provided selections - for (i = 0, iMax = selection.length; i < iMax; i++) { - id = selection[i]; - this.nodes[id].unselect(); - - var j = 0; - while (j < this.selection.length) { - if (this.selection[j] == id) { - this.selection.splice(j, 1); - changed = true; - } - else { - j++; - } - } - } - } - else if (this.selection && this.selection.length) { - // remove all selections - for (i = 0, iMax = this.selection.length; i < iMax; i++) { - id = this.selection[i]; - this.nodes[id].unselect(); - changed = true; - } - this.selection = []; - } - - if (changed && (triggerSelect == true || triggerSelect == undefined)) { - // fire the select event - this._trigger('select'); - } - - return changed; -}; - -/** - * select all nodes on given location x, y - * @param {Array} selection an array with node ids - * @param {boolean} append If true, the new selection will be appended to the - * current selection (except for duplicate entries) - * @return {Boolean} changed True if the selection is changed - * @private - */ -Graph.prototype._selectNodes = function(selection, append) { - var changed = false; - var i, iMax; - - // TODO: the selectNodes method is a little messy, rework this - - // check if the current selection equals the desired selection - var selectionAlreadyThere = true; - if (selection.length != this.selection.length) { - selectionAlreadyThere = false; - } - else { - for (i = 0, iMax = Math.min(selection.length, this.selection.length); i < iMax; i++) { - if (selection[i] != this.selection[i]) { - selectionAlreadyThere = false; - break; - } - } - } - if (selectionAlreadyThere) { - return changed; - } - - if (append == undefined || append == false) { - // first deselect any selected node - var triggerSelect = false; - changed = this._unselectNodes(undefined, triggerSelect); - } - - for (i = 0, iMax = selection.length; i < iMax; i++) { - // add each of the new selections, but only when they are not duplicate - var id = selection[i]; - var isDuplicate = (this.selection.indexOf(id) != -1); - if (!isDuplicate) { - this.nodes[id].select(); - this.selection.push(id); - changed = true; - } - } - - if (changed) { - // fire the select event - this._trigger('select'); - } - - return changed; -}; - -/** - * retrieve all nodes overlapping with given object - * @param {Object} obj An object with parameters left, top, right, bottom - * @return {Number[]} An array with id's of the overlapping nodes - * @private - */ -Graph.prototype._getNodesOverlappingWith = function (obj) { - var nodes = this.nodes, - overlappingNodes = []; - - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - if (nodes[id].isOverlappingWith(obj)) { - overlappingNodes.push(id); - } - } - } - - return overlappingNodes; -}; - -/** - * retrieve the currently selected nodes - * @return {Number[] | String[]} selection An array with the ids of the - * selected nodes. - */ -Graph.prototype.getSelection = function() { - return this.selection.concat([]); -}; - -/** - * select zero or more nodes - * @param {Number[] | String[]} selection An array with the ids of the - * selected nodes. - */ -Graph.prototype.setSelection = function(selection) { - var i, iMax, id; - - if (!selection || (selection.length == undefined)) - throw 'Selection must be an array with ids'; - - // first unselect any selected node - for (i = 0, iMax = this.selection.length; i < iMax; i++) { - id = this.selection[i]; - this.nodes[id].unselect(); - } - - this.selection = []; - - for (i = 0, iMax = selection.length; i < iMax; i++) { - id = selection[i]; - - var node = this.nodes[id]; - if (!node) { - throw new RangeError('Node with id "' + id + '" not found'); - } - node.select(); - this.selection.push(id); - } - - this.redraw(); -}; - -/** - * Validate the selection: remove ids of nodes which no longer exist - * @private - */ -Graph.prototype._updateSelection = function () { - var i = 0; - while (i < this.selection.length) { - var id = this.selection[i]; - if (!this.nodes[id]) { - this.selection.splice(i, 1); - } - else { - i++; - } - } -}; - -/** - * Temporary method to test calculating a hub value for the nodes - * @param {number} level Maximum number edges between two nodes in order - * to call them connected. Optional, 1 by default - * @return {Number[]} connectioncount array with the connection count - * for each node - * @private - */ -Graph.prototype._getConnectionCount = function(level) { - if (level == undefined) { - level = 1; - } - - // get the nodes connected to given nodes - function getConnectedNodes(nodes) { - var connectedNodes = []; - - for (var j = 0, jMax = nodes.length; j < jMax; j++) { - var node = nodes[j]; - - // find all nodes connected to this node - var edges = node.edges; - for (var i = 0, iMax = edges.length; i < iMax; i++) { - var edge = edges[i]; - var other = null; - - // check if connected - if (edge.from == node) - other = edge.to; - else if (edge.to == node) - other = edge.from; - - // check if the other node is not already in the list with nodes - var k, kMax; - if (other) { - for (k = 0, kMax = nodes.length; k < kMax; k++) { - if (nodes[k] == other) { - other = null; - break; - } - } - } - if (other) { - for (k = 0, kMax = connectedNodes.length; k < kMax; k++) { - if (connectedNodes[k] == other) { - other = null; - break; - } - } - } - - if (other) - connectedNodes.push(other); - } - } - - return connectedNodes; - } - - var connections = []; - var nodes = this.nodes; - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - var c = [nodes[id]]; - for (var l = 0; l < level; l++) { - c = c.concat(getConnectedNodes(c)); - } - connections.push(c); - } - } - - var hubs = []; - for (var i = 0, len = connections.length; i < len; i++) { - hubs.push(connections[i].length); - } - - return hubs; -}; - - -/** - * Set a new size for the graph - * @param {string} width Width in pixels or percentage (for example '800px' - * or '50%') - * @param {string} height Height in pixels or percentage (for example '400px' - * or '30%') - */ -Graph.prototype.setSize = function(width, height) { - this.frame.style.width = width; - this.frame.style.height = height; - - this.frame.canvas.style.width = '100%'; - this.frame.canvas.style.height = '100%'; - - this.frame.canvas.width = this.frame.canvas.clientWidth; - this.frame.canvas.height = this.frame.canvas.clientHeight; -}; - -/** - * Set a data set with nodes for the graph - * @param {Array | DataSet | DataView} nodes The data containing the nodes. - * @private - */ -Graph.prototype._setNodes = function(nodes) { - var oldNodesData = this.nodesData; - - if (nodes instanceof DataSet || nodes instanceof DataView) { - this.nodesData = nodes; - } - else if (nodes instanceof Array) { - this.nodesData = new DataSet(); - this.nodesData.add(nodes); - } - else if (!nodes) { - this.nodesData = new DataSet(); - } - else { - throw new TypeError('Array or DataSet expected'); - } - - if (oldNodesData) { - // unsubscribe from old dataset - util.forEach(this.nodesListeners, function (callback, event) { - oldNodesData.unsubscribe(event, callback); - }); - } - - // remove drawn nodes - this.nodes = {}; - - if (this.nodesData) { - // subscribe to new dataset - var me = this; - util.forEach(this.nodesListeners, function (callback, event) { - me.nodesData.subscribe(event, callback); - }); - - // draw all new nodes - var ids = this.nodesData.getIds(); - this._addNodes(ids); - } - - this._updateSelection(); -}; - -/** - * Add nodes - * @param {Number[] | String[]} ids - * @private - */ -Graph.prototype._addNodes = function(ids) { - var id; - for (var i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - var data = this.nodesData.get(id); - var node = new Node(data, this.images, this.groups, this.constants); - this.nodes[id] = node; // note: this may replace an existing node - - if (!node.isFixed()) { - // TODO: position new nodes in a smarter way! - var radius = this.constants.edges.length * 2; - var count = ids.length; - var angle = 2 * Math.PI * (i / count); - node.x = radius * Math.cos(angle); - node.y = radius * Math.sin(angle); - - // note: no not use node.isMoving() here, as that gives the current - // velocity of the node, which is zero after creation of the node. - this.moving = true; - } - } - - this._reconnectEdges(); - this._updateValueRange(this.nodes); -}; - -/** - * Update existing nodes, or create them when not yet existing - * @param {Number[] | String[]} ids - * @private - */ -Graph.prototype._updateNodes = function(ids) { - var nodes = this.nodes, - nodesData = this.nodesData; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - var node = nodes[id]; - var data = nodesData.get(id); - if (node) { - // update node - node.setProperties(data, this.constants); - } - else { - // create node - node = new Node(properties, this.images, this.groups, this.constants); - nodes[id] = node; - - if (!node.isFixed()) { - this.moving = true; - } - } - } - - this._reconnectEdges(); - this._updateValueRange(nodes); -}; - -/** - * Remove existing nodes. If nodes do not exist, the method will just ignore it. - * @param {Number[] | String[]} ids - * @private - */ -Graph.prototype._removeNodes = function(ids) { - var nodes = this.nodes; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - delete nodes[id]; - } - - this._reconnectEdges(); - this._updateSelection(); - this._updateValueRange(nodes); -}; - -/** - * Load edges by reading the data table - * @param {Array | DataSet | DataView} edges The data containing the edges. - * @private - * @private - */ -Graph.prototype._setEdges = function(edges) { - var oldEdgesData = this.edgesData; - - if (edges instanceof DataSet || edges instanceof DataView) { - this.edgesData = edges; - } - else if (edges instanceof Array) { - this.edgesData = new DataSet(); - this.edgesData.add(edges); - } - else if (!edges) { - this.edgesData = new DataSet(); - } - else { - throw new TypeError('Array or DataSet expected'); - } - - if (oldEdgesData) { - // unsubscribe from old dataset - util.forEach(this.edgesListeners, function (callback, event) { - oldEdgesData.unsubscribe(event, callback); - }); - } - - // remove drawn edges - this.edges = {}; - - if (this.edgesData) { - // subscribe to new dataset - var me = this; - util.forEach(this.edgesListeners, function (callback, event) { - me.edgesData.subscribe(event, callback); - }); - - // draw all new nodes - var ids = this.edgesData.getIds(); - this._addEdges(ids); - } - - this._reconnectEdges(); -}; - -/** - * Add edges - * @param {Number[] | String[]} ids - * @private - */ -Graph.prototype._addEdges = function (ids) { - var edges = this.edges, - edgesData = this.edgesData; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - - var oldEdge = edges[id]; - if (oldEdge) { - oldEdge.disconnect(); - } - - var data = edgesData.get(id); - edges[id] = new Edge(data, this, this.constants); - } - - this.moving = true; - this._updateValueRange(edges); -}; - -/** - * Update existing edges, or create them when not yet existing - * @param {Number[] | String[]} ids - * @private - */ -Graph.prototype._updateEdges = function (ids) { - var edges = this.edges, - edgesData = this.edgesData; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - - var data = edgesData.get(id); - var edge = edges[id]; - if (edge) { - // update edge - edge.disconnect(); - edge.setProperties(data, this.constants); - edge.connect(); - } - else { - // create edge - edge = new Edge(data, this, this.constants); - this.edges[id] = edge; - } - } - - this.moving = true; - this._updateValueRange(edges); -}; - -/** - * Remove existing edges. Non existing ids will be ignored - * @param {Number[] | String[]} ids - * @private - */ -Graph.prototype._removeEdges = function (ids) { - var edges = this.edges; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - var edge = edges[id]; - if (edge) { - edge.disconnect(); - delete edges[id]; - } - } - - this.moving = true; - this._updateValueRange(edges); -}; - -/** - * Reconnect all edges - * @private - */ -Graph.prototype._reconnectEdges = function() { - var id, - nodes = this.nodes, - edges = this.edges; - for (id in nodes) { - if (nodes.hasOwnProperty(id)) { - nodes[id].edges = []; - } - } - - for (id in edges) { - if (edges.hasOwnProperty(id)) { - var edge = edges[id]; - edge.from = null; - edge.to = null; - edge.connect(); - } - } -}; - -/** - * Update the values of all object in the given array according to the current - * value range of the objects in the array. - * @param {Object} obj An object containing a set of Edges or Nodes - * The objects must have a method getValue() and - * setValueRange(min, max). - * @private - */ -Graph.prototype._updateValueRange = function(obj) { - var id; - - // determine the range of the objects - var valueMin = undefined; - var valueMax = undefined; - for (id in obj) { - if (obj.hasOwnProperty(id)) { - var value = obj[id].getValue(); - if (value !== undefined) { - valueMin = (valueMin === undefined) ? value : Math.min(value, valueMin); - valueMax = (valueMax === undefined) ? value : Math.max(value, valueMax); - } - } - } - - // adjust the range of all objects - if (valueMin !== undefined && valueMax !== undefined) { - for (id in obj) { - if (obj.hasOwnProperty(id)) { - obj[id].setValueRange(valueMin, valueMax); - } - } - } -}; - -/** - * Redraw the graph with the current data - * chart will be resized too. - */ -Graph.prototype.redraw = function() { - this.setSize(this.width, this.height); - - this._redraw(); -}; - -/** - * Redraw the graph with the current data - * @private - */ -Graph.prototype._redraw = function() { - var ctx = this.frame.canvas.getContext('2d'); - - // clear the canvas - var w = this.frame.canvas.width; - var h = this.frame.canvas.height; - ctx.clearRect(0, 0, w, h); - - // set scaling and translation - ctx.save(); - ctx.translate(this.translation.x, this.translation.y); - ctx.scale(this.scale, this.scale); - - this._drawEdges(ctx); - this._drawNodes(ctx); - - // restore original scaling and translation - ctx.restore(); -}; - -/** - * Set the translation of the graph - * @param {Number} offsetX Horizontal offset - * @param {Number} offsetY Vertical offset - * @private - */ -Graph.prototype._setTranslation = function(offsetX, offsetY) { - if (this.translation === undefined) { - this.translation = { - x: 0, - y: 0 - }; - } - - if (offsetX !== undefined) { - this.translation.x = offsetX; - } - if (offsetY !== undefined) { - this.translation.y = offsetY; - } -}; - -/** - * Get the translation of the graph - * @return {Object} translation An object with parameters x and y, both a number - * @private - */ -Graph.prototype._getTranslation = function() { - return { - x: this.translation.x, - y: this.translation.y - }; -}; - -/** - * Scale the graph - * @param {Number} scale Scaling factor 1.0 is unscaled - * @private - */ -Graph.prototype._setScale = function(scale) { - this.scale = scale; -}; -/** - * Get the current scale of the graph - * @return {Number} scale Scaling factor 1.0 is unscaled - * @private - */ -Graph.prototype._getScale = function() { - return this.scale; -}; - -/** - * Convert a horizontal point on the HTML canvas to the x-value of the model - * @param {number} x - * @returns {number} - * @private - */ -Graph.prototype._canvasToX = function(x) { - return (x - this.translation.x) / this.scale; -}; - -/** - * Convert an x-value in the model to a horizontal point on the HTML canvas - * @param {number} x - * @returns {number} - * @private - */ -Graph.prototype._xToCanvas = function(x) { - return x * this.scale + this.translation.x; -}; - -/** - * Convert a vertical point on the HTML canvas to the y-value of the model - * @param {number} y - * @returns {number} - * @private - */ -Graph.prototype._canvasToY = function(y) { - return (y - this.translation.y) / this.scale; -}; - -/** - * Convert an y-value in the model to a vertical point on the HTML canvas - * @param {number} y - * @returns {number} - * @private - */ -Graph.prototype._yToCanvas = function(y) { - return y * this.scale + this.translation.y ; -}; - -/** - * Redraw all nodes - * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Graph.prototype._drawNodes = function(ctx) { - // first draw the unselected nodes - var nodes = this.nodes; - var selected = []; - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - if (nodes[id].isSelected()) { - selected.push(id); - } - else { - nodes[id].draw(ctx); - } - } - } - - // draw the selected nodes on top - for (var s = 0, sMax = selected.length; s < sMax; s++) { - nodes[selected[s]].draw(ctx); - } -}; - -/** - * Redraw all edges - * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Graph.prototype._drawEdges = function(ctx) { - var edges = this.edges; - for (var id in edges) { - if (edges.hasOwnProperty(id)) { - var edge = edges[id]; - if (edge.connected) { - edges[id].draw(ctx); - } - } - } -}; - -/** - * Find a stable position for all nodes - * @private - */ -Graph.prototype._doStabilize = function() { - var start = new Date(); - - // find stable position - var count = 0; - var vmin = this.constants.minVelocity; - var stable = false; - while (!stable && count < this.constants.maxIterations) { - this._calculateForces(); - this._discreteStepNodes(); - stable = !this._isMoving(vmin); - count++; - } - - var end = new Date(); - - // console.log('Stabilized in ' + (end-start) + ' ms, ' + count + ' iterations' ); // TODO: cleanup -}; - -/** - * Calculate the external forces acting on the nodes - * Forces are caused by: edges, repulsing forces between nodes, gravity - * @private - */ -Graph.prototype._calculateForces = function() { - // create a local edge to the nodes and edges, that is faster - var id, dx, dy, angle, distance, fx, fy, - repulsingForce, springForce, length, edgeLength, - nodes = this.nodes, - edges = this.edges; - - // gravity, add a small constant force to pull the nodes towards the center of - // the graph - // Also, the forces are reset to zero in this loop by using _setForce instead - // of _addForce - var gravity = 0.01, - gx = this.frame.canvas.clientWidth / 2, - gy = this.frame.canvas.clientHeight / 2; - for (id in nodes) { - if (nodes.hasOwnProperty(id)) { - var node = nodes[id]; - dx = gx - node.x; - dy = gy - node.y; - angle = Math.atan2(dy, dx); - fx = Math.cos(angle) * gravity; - fy = Math.sin(angle) * gravity; - - node._setForce(fx, fy); - } - } - - // repulsing forces between nodes - var minimumDistance = this.constants.nodes.distance, - steepness = 10; // higher value gives steeper slope of the force around the given minimumDistance - - for (var id1 in nodes) { - if (nodes.hasOwnProperty(id1)) { - var node1 = nodes[id1]; - for (var id2 in nodes) { - if (nodes.hasOwnProperty(id2)) { - var node2 = nodes[id2]; - // calculate normally distributed force - dx = node2.x - node1.x; - dy = node2.y - node1.y; - distance = Math.sqrt(dx * dx + dy * dy); - angle = Math.atan2(dy, dx); - - // TODO: correct factor for repulsing force - //repulsingForce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force - //repulsingForce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force - repulsingForce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)); // TODO: customize the repulsing force - fx = Math.cos(angle) * repulsingForce; - fy = Math.sin(angle) * repulsingForce; - - node1._addForce(-fx, -fy); - node2._addForce(fx, fy); - } - } - } - } - - /* TODO: re-implement repulsion of edges - for (var n = 0; n < nodes.length; n++) { - for (var l = 0; l < edges.length; l++) { - var lx = edges[l].from.x+(edges[l].to.x - edges[l].from.x)/2, - ly = edges[l].from.y+(edges[l].to.y - edges[l].from.y)/2, - - // calculate normally distributed force - dx = nodes[n].x - lx, - dy = nodes[n].y - ly, - distance = Math.sqrt(dx * dx + dy * dy), - angle = Math.atan2(dy, dx), - - - // TODO: correct factor for repulsing force - //var repulsingforce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force - //repulsingforce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ), // TODO: customize the repulsing force - repulsingforce = 1 / (1 + Math.exp((distance / (minimumDistance / 2) - 1) * steepness)), // TODO: customize the repulsing force - fx = Math.cos(angle) * repulsingforce, - fy = Math.sin(angle) * repulsingforce; - nodes[n]._addForce(fx, fy); - edges[l].from._addForce(-fx/2,-fy/2); - edges[l].to._addForce(-fx/2,-fy/2); - } - } - */ - - // forces caused by the edges, modelled as springs - for (id in edges) { - if (edges.hasOwnProperty(id)) { - var edge = edges[id]; - if (edge.connected) { - dx = (edge.to.x - edge.from.x); - dy = (edge.to.y - edge.from.y); - //edgeLength = (edge.from.width + edge.from.height + edge.to.width + edge.to.height)/2 || edge.length; // TODO: dmin - //edgeLength = (edge.from.width + edge.to.width)/2 || edge.length; // TODO: dmin - //edgeLength = 20 + ((edge.from.width + edge.to.width) || 0) / 2; - edgeLength = edge.length; - length = Math.sqrt(dx * dx + dy * dy); - angle = Math.atan2(dy, dx); - - springForce = edge.stiffness * (edgeLength - length); - - fx = Math.cos(angle) * springForce; - fy = Math.sin(angle) * springForce; - - edge.from._addForce(-fx, -fy); - edge.to._addForce(fx, fy); - } - } - } - - /* TODO: re-implement repulsion of edges - // repulsing forces between edges - var minimumDistance = this.constants.edges.distance, - steepness = 10; // higher value gives steeper slope of the force around the given minimumDistance - for (var l = 0; l < edges.length; l++) { - //Keep distance from other edge centers - for (var l2 = l + 1; l2 < this.edges.length; l2++) { - //var dmin = (nodes[n].width + nodes[n].height + nodes[n2].width + nodes[n2].height) / 1 || minimumDistance, // TODO: dmin - //var dmin = (nodes[n].width + nodes[n2].width)/2 || minimumDistance, // TODO: dmin - //dmin = 40 + ((nodes[n].width/2 + nodes[n2].width/2) || 0), - var lx = edges[l].from.x+(edges[l].to.x - edges[l].from.x)/2, - ly = edges[l].from.y+(edges[l].to.y - edges[l].from.y)/2, - l2x = edges[l2].from.x+(edges[l2].to.x - edges[l2].from.x)/2, - l2y = edges[l2].from.y+(edges[l2].to.y - edges[l2].from.y)/2, - - // calculate normally distributed force - dx = l2x - lx, - dy = l2y - ly, - distance = Math.sqrt(dx * dx + dy * dy), - angle = Math.atan2(dy, dx), - - - // TODO: correct factor for repulsing force - //var repulsingforce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force - //repulsingforce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ), // TODO: customize the repulsing force - repulsingforce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)), // TODO: customize the repulsing force - fx = Math.cos(angle) * repulsingforce, - fy = Math.sin(angle) * repulsingforce; - - edges[l].from._addForce(-fx, -fy); - edges[l].to._addForce(-fx, -fy); - edges[l2].from._addForce(fx, fy); - edges[l2].to._addForce(fx, fy); - } - } - */ -}; - - -/** - * Check if any of the nodes is still moving - * @param {number} vmin the minimum velocity considered as 'moving' - * @return {boolean} true if moving, false if non of the nodes is moving - * @private - */ -Graph.prototype._isMoving = function(vmin) { - // TODO: ismoving does not work well: should check the kinetic energy, not its velocity - var nodes = this.nodes; - for (var id in nodes) { - if (nodes.hasOwnProperty(id) && nodes[id].isMoving(vmin)) { - return true; - } - } - return false; -}; - - -/** - * Perform one discrete step for all nodes - * @private - */ -Graph.prototype._discreteStepNodes = function() { - var interval = this.refreshRate / 1000.0; // in seconds - var nodes = this.nodes; - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - nodes[id].discreteStep(interval); - } - } -}; - -/** - * Start animating nodes and edges - */ -Graph.prototype.start = function() { - if (this.moving) { - this._calculateForces(); - this._discreteStepNodes(); - - var vmin = this.constants.minVelocity; - this.moving = this._isMoving(vmin); - } - - if (this.moving) { - // start animation. only start timer if it is not already running - if (!this.timer) { - var graph = this; - this.timer = window.setTimeout(function () { - graph.timer = undefined; - graph.start(); - graph._redraw(); - }, this.refreshRate); - } - } - else { - this._redraw(); - } -}; - -/** - * Stop animating nodes and edges. - */ -Graph.prototype.stop = function () { - if (this.timer) { - window.clearInterval(this.timer); - this.timer = undefined; - } -}; - -/** - * vis.js module exports - */ -var vis = { - util: util, - events: events, - - Controller: Controller, - DataSet: DataSet, - DataView: DataView, - Range: Range, - Stack: Stack, - TimeStep: TimeStep, - EventBus: EventBus, - - components: { - items: { - Item: Item, - ItemBox: ItemBox, - ItemPoint: ItemPoint, - ItemRange: ItemRange - }, - - Component: Component, - Panel: Panel, - RootPanel: RootPanel, - ItemSet: ItemSet, - TimeAxis: TimeAxis - }, - - graph: { - Node: Node, - Edge: Edge, - Popup: Popup, - Groups: Groups, - Images: Images - }, - - Timeline: Timeline, - Graph: Graph -}; - -/** - * CommonJS module exports - */ -if (typeof exports !== 'undefined') { - exports = vis; -} -if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { - module.exports = vis; -} - -/** - * AMD module exports - */ -if (typeof(define) === 'function') { - define(function () { - return vis; - }); -} - -/** - * Window exports - */ -if (typeof window !== 'undefined') { - // attach the module to the window, load as a regular javascript file - window['vis'] = vis; -} - -// inject css -util.loadCss("/* vis.js stylesheet */\n.vis.timeline {\n}\n\n\n.vis.timeline.rootpanel {\n position: relative;\n overflow: hidden;\n\n border: 1px solid #bfbfbf;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n\n.vis.timeline .panel {\n position: absolute;\n overflow: hidden;\n}\n\n\n.vis.timeline .groupset {\n position: absolute;\n padding: 0;\n margin: 0;\n}\n\n.vis.timeline .labels {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n\n padding: 0;\n margin: 0;\n\n border-right: 1px solid #bfbfbf;\n box-sizing: border-box;\n -moz-box-sizing: border-box;\n}\n\n.vis.timeline .labels .label {\n position: absolute;\n left: 0;\n top: 0;\n width: 100%;\n border-bottom: 1px solid #bfbfbf;\n color: #4d4d4d;\n}\n\n.vis.timeline .labels .label .inner {\n display: inline-block;\n padding: 5px;\n}\n\n\n.vis.timeline .itemset {\n position: absolute;\n padding: 0;\n margin: 0;\n overflow: hidden;\n}\n\n.vis.timeline .background {\n}\n\n.vis.timeline .foreground {\n}\n\n.vis.timeline .itemset-axis {\n position: absolute;\n}\n\n.vis.timeline .groupset .itemset-axis {\n border-top: 1px solid #bfbfbf;\n}\n\n/* TODO: with orientation=='bottom', this will more or less overlap with timeline axis\n.vis.timeline .groupset .itemset-axis:last-child {\n border-top: none;\n}\n*/\n\n\n.vis.timeline .item {\n position: absolute;\n color: #1A1A1A;\n border-color: #97B0F8;\n background-color: #D5DDF6;\n display: inline-block;\n}\n\n.vis.timeline .item.selected {\n border-color: #FFC200;\n background-color: #FFF785;\n z-index: 999;\n}\n\n.vis.timeline .item.cluster {\n /* TODO: use another color or pattern? */\n background: #97B0F8 url('img/cluster_bg.png');\n color: white;\n}\n.vis.timeline .item.cluster.point {\n border-color: #D5DDF6;\n}\n\n.vis.timeline .item.box {\n text-align: center;\n border-style: solid;\n border-width: 1px;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.point {\n background: none;\n}\n\n.vis.timeline .dot {\n border: 5px solid #97B0F8;\n position: absolute;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.range {\n overflow: hidden;\n border-style: solid;\n border-width: 1px;\n border-radius: 2px;\n -moz-border-radius: 2px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.range .drag-left {\n cursor: w-resize;\n z-index: 1000;\n}\n\n.vis.timeline .item.range .drag-right {\n cursor: e-resize;\n z-index: 1000;\n}\n\n.vis.timeline .item.range .content {\n position: relative;\n display: inline-block;\n}\n\n.vis.timeline .item.line {\n position: absolute;\n width: 0;\n border-left-width: 1px;\n border-left-style: solid;\n}\n\n.vis.timeline .item .content {\n margin: 5px;\n white-space: nowrap;\n overflow: hidden;\n}\n\n.vis.timeline .axis {\n position: relative;\n}\n\n.vis.timeline .axis .text {\n position: absolute;\n color: #4d4d4d;\n padding: 3px;\n white-space: nowrap;\n}\n\n.vis.timeline .axis .text.measure {\n position: absolute;\n padding-left: 0;\n padding-right: 0;\n margin-left: 0;\n margin-right: 0;\n visibility: hidden;\n}\n\n.vis.timeline .axis .grid.vertical {\n position: absolute;\n width: 0;\n border-right: 1px solid;\n}\n\n.vis.timeline .axis .grid.horizontal {\n position: absolute;\n left: 0;\n width: 100%;\n height: 0;\n border-bottom: 1px solid;\n}\n\n.vis.timeline .axis .grid.minor {\n border-color: #e5e5e5;\n}\n\n.vis.timeline .axis .grid.major {\n border-color: #bfbfbf;\n}\n\n"); - -},{"hammerjs":1,"moment":2}]},{},[3]) -(3) -}); -; \ No newline at end of file diff --git a/vis.min.js b/vis.min.js deleted file mode 100644 index 3f3d76a8..00000000 --- a/vis.min.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * vis.js - * https://github.com/almende/vis - * - * A dynamic, browser-based visualization library. - * - * @version 0.2.0 - * @date 2013-09-20 - * - * @license - * Copyright (C) 2011-2013 Almende B.V, http://almende.com - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -(function(t){if("function"==typeof bootstrap)bootstrap("vis",t);else if("object"==typeof exports)module.exports=t();else if("function"==typeof define&&define.amd)define(t);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeVis=t}else"undefined"!=typeof window?window.vis=t():global.vis=t()})(function(){var t;return function e(t,i,n){function s(r,a){if(!i[r]){if(!t[r]){var h="function"==typeof require&&require;if(!a&&h)return h(r,!0);if(o)return o(r,!0);throw Error("Cannot find module '"+r+"'")}var d=i[r]={exports:{}};t[r][0].call(d.exports,function(e){var i=t[r][1][e];return s(i?i:e)},d,d.exports,e,t,i,n)}return i[r].exports}for(var o="function"==typeof require&&require,r=0;n.length>r;r++)s(n[r]);return s}({1:[function(t,e){(function(t,i){"use strict";function n(){if(!s.READY){s.event.determineEventTypes();for(var t in s.gestures)s.gestures.hasOwnProperty(t)&&s.detection.register(s.gestures[t]);s.event.onTouch(s.DOCUMENT,s.EVENT_MOVE,s.detection.detect),s.event.onTouch(s.DOCUMENT,s.EVENT_END,s.detection.detect),s.READY=!0}}var s=function(t,e){return new s.Instance(t,e||{})};s.defaults={stop_browser_behavior:{userSelect:"none",touchAction:"none",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}},s.HAS_POINTEREVENTS=navigator.pointerEnabled||navigator.msPointerEnabled,s.HAS_TOUCHEVENTS="ontouchstart"in t,s.MOBILE_REGEX=/mobile|tablet|ip(ad|hone|od)|android/i,s.NO_MOUSEEVENTS=s.HAS_TOUCHEVENTS&&navigator.userAgent.match(s.MOBILE_REGEX),s.EVENT_TYPES={},s.DIRECTION_DOWN="down",s.DIRECTION_LEFT="left",s.DIRECTION_UP="up",s.DIRECTION_RIGHT="right",s.POINTER_MOUSE="mouse",s.POINTER_TOUCH="touch",s.POINTER_PEN="pen",s.EVENT_START="start",s.EVENT_MOVE="move",s.EVENT_END="end",s.DOCUMENT=document,s.plugins={},s.READY=!1,s.Instance=function(t,e){var i=this;return n(),this.element=t,this.enabled=!0,this.options=s.utils.extend(s.utils.extend({},s.defaults),e||{}),this.options.stop_browser_behavior&&s.utils.stopDefaultBrowserBehavior(this.element,this.options.stop_browser_behavior),s.event.onTouch(t,s.EVENT_START,function(t){i.enabled&&s.detection.startDetect(i,t)}),this},s.Instance.prototype={on:function(t,e){for(var i=t.split(" "),n=0;i.length>n;n++)this.element.addEventListener(i[n],e,!1);return this},off:function(t,e){for(var i=t.split(" "),n=0;i.length>n;n++)this.element.removeEventListener(i[n],e,!1);return this},trigger:function(t,e){var i=s.DOCUMENT.createEvent("Event");i.initEvent(t,!0,!0),i.gesture=e;var n=this.element;return s.utils.hasParent(e.target,n)&&(n=e.target),n.dispatchEvent(i),this},enable:function(t){return this.enabled=t,this}};var o=null,r=!1,a=!1;s.event={bindDom:function(t,e,i){for(var n=e.split(" "),s=0;n.length>s;s++)t.addEventListener(n[s],i,!1)},onTouch:function(t,e,i){var n=this;this.bindDom(t,s.EVENT_TYPES[e],function(h){var d=h.type.toLowerCase();if(!d.match(/mouse/)||!a){(d.match(/touch/)||d.match(/pointerdown/)||d.match(/mouse/)&&1===h.which)&&(r=!0),d.match(/touch|pointer/)&&(a=!0);var l=0;r&&(s.HAS_POINTEREVENTS&&e!=s.EVENT_END?l=s.PointerEvent.updatePointer(e,h):d.match(/touch/)?l=h.touches.length:a||(l=d.match(/up/)?0:1),l>0&&e==s.EVENT_END?e=s.EVENT_MOVE:l||(e=s.EVENT_END),l||null===o?o=h:h=o,i.call(s.detection,n.collectEventData(t,e,h)),s.HAS_POINTEREVENTS&&e==s.EVENT_END&&(l=s.PointerEvent.updatePointer(e,h))),l||(o=null,r=!1,a=!1,s.PointerEvent.reset())}})},determineEventTypes:function(){var t;t=s.HAS_POINTEREVENTS?s.PointerEvent.getEvents():s.NO_MOUSEEVENTS?["touchstart","touchmove","touchend touchcancel"]:["touchstart mousedown","touchmove mousemove","touchend touchcancel mouseup"],s.EVENT_TYPES[s.EVENT_START]=t[0],s.EVENT_TYPES[s.EVENT_MOVE]=t[1],s.EVENT_TYPES[s.EVENT_END]=t[2]},getTouchList:function(t){return s.HAS_POINTEREVENTS?s.PointerEvent.getTouchList():t.touches?t.touches:[{identifier:1,pageX:t.pageX,pageY:t.pageY,target:t.target}]},collectEventData:function(t,e,i){var n=this.getTouchList(i,e),o=s.POINTER_TOUCH;return(i.type.match(/mouse/)||s.PointerEvent.matchType(s.POINTER_MOUSE,i))&&(o=s.POINTER_MOUSE),{center:s.utils.getCenter(n),timeStamp:(new Date).getTime(),target:i.target,touches:n,eventType:e,pointerType:o,srcEvent:i,preventDefault:function(){this.srcEvent.preventManipulation&&this.srcEvent.preventManipulation(),this.srcEvent.preventDefault&&this.srcEvent.preventDefault()},stopPropagation:function(){this.srcEvent.stopPropagation()},stopDetect:function(){return s.detection.stopDetect()}}}},s.PointerEvent={pointers:{},getTouchList:function(){var t=this,e=[];return Object.keys(t.pointers).sort().forEach(function(i){e.push(t.pointers[i])}),e},updatePointer:function(t,e){return t==s.EVENT_END?this.pointers={}:(e.identifier=e.pointerId,this.pointers[e.pointerId]=e),Object.keys(this.pointers).length},matchType:function(t,e){if(!e.pointerType)return!1;var i={};return i[s.POINTER_MOUSE]=e.pointerType==e.MSPOINTER_TYPE_MOUSE||e.pointerType==s.POINTER_MOUSE,i[s.POINTER_TOUCH]=e.pointerType==e.MSPOINTER_TYPE_TOUCH||e.pointerType==s.POINTER_TOUCH,i[s.POINTER_PEN]=e.pointerType==e.MSPOINTER_TYPE_PEN||e.pointerType==s.POINTER_PEN,i[t]},getEvents:function(){return["pointerdown MSPointerDown","pointermove MSPointerMove","pointerup pointercancel MSPointerUp MSPointerCancel"]},reset:function(){this.pointers={}}},s.utils={extend:function(t,e,n){for(var s in e)t[s]!==i&&n||(t[s]=e[s]);return t},hasParent:function(t,e){for(;t;){if(t==e)return!0;t=t.parentNode}return!1},getCenter:function(t){for(var e=[],i=[],n=0,s=t.length;s>n;n++)e.push(t[n].pageX),i.push(t[n].pageY);return{pageX:(Math.min.apply(Math,e)+Math.max.apply(Math,e))/2,pageY:(Math.min.apply(Math,i)+Math.max.apply(Math,i))/2}},getVelocity:function(t,e,i){return{x:Math.abs(e/t)||0,y:Math.abs(i/t)||0}},getAngle:function(t,e){var i=e.pageY-t.pageY,n=e.pageX-t.pageX;return 180*Math.atan2(i,n)/Math.PI},getDirection:function(t,e){var i=Math.abs(t.pageX-e.pageX),n=Math.abs(t.pageY-e.pageY);return i>=n?t.pageX-e.pageX>0?s.DIRECTION_LEFT:s.DIRECTION_RIGHT:t.pageY-e.pageY>0?s.DIRECTION_UP:s.DIRECTION_DOWN},getDistance:function(t,e){var i=e.pageX-t.pageX,n=e.pageY-t.pageY;return Math.sqrt(i*i+n*n)},getScale:function(t,e){return t.length>=2&&e.length>=2?this.getDistance(e[0],e[1])/this.getDistance(t[0],t[1]):1},getRotation:function(t,e){return t.length>=2&&e.length>=2?this.getAngle(e[1],e[0])-this.getAngle(t[1],t[0]):0},isVertical:function(t){return t==s.DIRECTION_UP||t==s.DIRECTION_DOWN},stopDefaultBrowserBehavior:function(t,e){var i,n=["webkit","khtml","moz","ms","o",""];if(e&&t.style){for(var s=0;n.length>s;s++)for(var o in e)e.hasOwnProperty(o)&&(i=o,n[s]&&(i=n[s]+i.substring(0,1).toUpperCase()+i.substring(1)),t.style[i]=e[o]);"none"==e.userSelect&&(t.onselectstart=function(){return!1})}}},s.detection={gestures:[],current:null,previous:null,stopped:!1,startDetect:function(t,e){this.current||(this.stopped=!1,this.current={inst:t,startEvent:s.utils.extend({},e),lastEvent:!1,name:""},this.detect(e))},detect:function(t){if(this.current&&!this.stopped){t=this.extendEventData(t);for(var e=this.current.inst.options,i=0,n=this.gestures.length;n>i;i++){var o=this.gestures[i];if(!this.stopped&&e[o.name]!==!1&&o.handler.call(o,t,this.current.inst)===!1){this.stopDetect();break}}return this.current&&(this.current.lastEvent=t),t.eventType==s.EVENT_END&&!t.touches.length-1&&this.stopDetect(),t}},stopDetect:function(){this.previous=s.utils.extend({},this.current),this.current=null,this.stopped=!0},extendEventData:function(t){var e=this.current.startEvent;if(e&&(t.touches.length!=e.touches.length||t.touches===e.touches)){e.touches=[];for(var i=0,n=t.touches.length;n>i;i++)e.touches.push(s.utils.extend({},t.touches[i]))}var o=t.timeStamp-e.timeStamp,r=t.center.pageX-e.center.pageX,a=t.center.pageY-e.center.pageY,h=s.utils.getVelocity(o,r,a);return s.utils.extend(t,{deltaTime:o,deltaX:r,deltaY:a,velocityX:h.x,velocityY:h.y,distance:s.utils.getDistance(e.center,t.center),angle:s.utils.getAngle(e.center,t.center),direction:s.utils.getDirection(e.center,t.center),scale:s.utils.getScale(e.touches,t.touches),rotation:s.utils.getRotation(e.touches,t.touches),startEvent:e}),t},register:function(t){var e=t.defaults||{};return e[t.name]===i&&(e[t.name]=!0),s.utils.extend(s.defaults,e,!0),t.index=t.index||1e3,this.gestures.push(t),this.gestures.sort(function(t,e){return t.indexe.index?1:0}),this.gestures}},s.gestures=s.gestures||{},s.gestures.Hold={name:"hold",index:10,defaults:{hold_timeout:500,hold_threshold:1},timer:null,handler:function(t,e){switch(t.eventType){case s.EVENT_START:clearTimeout(this.timer),s.detection.current.name=this.name,this.timer=setTimeout(function(){"hold"==s.detection.current.name&&e.trigger("hold",t)},e.options.hold_timeout);break;case s.EVENT_MOVE:t.distance>e.options.hold_threshold&&clearTimeout(this.timer);break;case s.EVENT_END:clearTimeout(this.timer)}}},s.gestures.Tap={name:"tap",index:100,defaults:{tap_max_touchtime:250,tap_max_distance:10,tap_always:!0,doubletap_distance:20,doubletap_interval:300},handler:function(t,e){if(t.eventType==s.EVENT_END){var i=s.detection.previous,n=!1;if(t.deltaTime>e.options.tap_max_touchtime||t.distance>e.options.tap_max_distance)return;i&&"tap"==i.name&&t.timeStamp-i.lastEvent.timeStamp0&&t.touches.length>e.options.swipe_max_touches)return;(t.velocityX>e.options.swipe_velocity||t.velocityY>e.options.swipe_velocity)&&(e.trigger(this.name,t),e.trigger(this.name+t.direction,t))}}},s.gestures.Drag={name:"drag",index:50,defaults:{drag_min_distance:10,drag_max_touches:1,drag_block_horizontal:!1,drag_block_vertical:!1,drag_lock_to_axis:!1,drag_lock_min_distance:25},triggered:!1,handler:function(t,e){if(s.detection.current.name!=this.name&&this.triggered)return e.trigger(this.name+"end",t),this.triggered=!1,i;if(!(e.options.drag_max_touches>0&&t.touches.length>e.options.drag_max_touches))switch(t.eventType){case s.EVENT_START:this.triggered=!1;break;case s.EVENT_MOVE:if(t.distancet.deltaY?s.DIRECTION_UP:s.DIRECTION_DOWN:0>t.deltaX?s.DIRECTION_LEFT:s.DIRECTION_RIGHT),this.triggered||(e.trigger(this.name+"start",t),this.triggered=!0),e.trigger(this.name,t),e.trigger(this.name+t.direction,t),(e.options.drag_block_vertical&&s.utils.isVertical(t.direction)||e.options.drag_block_horizontal&&!s.utils.isVertical(t.direction))&&t.preventDefault();break;case s.EVENT_END:this.triggered&&e.trigger(this.name+"end",t),this.triggered=!1}}},s.gestures.Transform={name:"transform",index:45,defaults:{transform_min_scale:.01,transform_min_rotation:1,transform_always_block:!1},triggered:!1,handler:function(t,e){if(s.detection.current.name!=this.name&&this.triggered)return e.trigger(this.name+"end",t),this.triggered=!1,i;if(!(2>t.touches.length))switch(e.options.transform_always_block&&t.preventDefault(),t.eventType){case s.EVENT_START:this.triggered=!1;break;case s.EVENT_MOVE:var n=Math.abs(1-t.scale),o=Math.abs(t.rotation);if(e.options.transform_min_scale>n&&e.options.transform_min_rotation>o)return;s.detection.current.name=this.name,this.triggered||(e.trigger(this.name+"start",t),this.triggered=!0),e.trigger(this.name,t),o>e.options.transform_min_rotation&&e.trigger("rotate",t),n>e.options.transform_min_scale&&(e.trigger("pinch",t),e.trigger("pinch"+(1>t.scale?"in":"out"),t));break;case s.EVENT_END:this.triggered&&e.trigger(this.name+"end",t),this.triggered=!1}}},s.gestures.Touch={name:"touch",index:-1/0,defaults:{prevent_default:!1,prevent_mouseevents:!1},handler:function(t,e){return e.options.prevent_mouseevents&&t.pointerType==s.POINTER_MOUSE?(t.stopDetect(),i):(e.options.prevent_default&&t.preventDefault(),t.eventType==s.EVENT_START&&e.trigger(this.name,t),i)}},s.gestures.Release={name:"release",index:1/0,handler:function(t,e){t.eventType==s.EVENT_END&&e.trigger(this.name,t)}},"object"==typeof e&&"object"==typeof e.exports?e.exports=s:(t.Hammer=s,"function"==typeof t.define&&t.define.amd&&t.define("hammer",[],function(){return s}))})(this)},{}],2:[function(e,i){(function(n){function s(t,e){return function(i){return p(t.call(this,i),e)}}function o(t,e){return function(i){return this.lang().ordinal(t.call(this,i),e)}}function r(){}function a(t){d(this,t)}function h(t){var e=t.years||t.year||t.y||0,i=t.months||t.month||t.M||0,n=t.weeks||t.week||t.w||0,s=t.days||t.day||t.d||0,o=t.hours||t.hour||t.h||0,r=t.minutes||t.minute||t.m||0,a=t.seconds||t.second||t.s||0,h=t.milliseconds||t.millisecond||t.ms||0;this._input=t,this._milliseconds=+h+1e3*a+6e4*r+36e5*o,this._days=+s+7*n,this._months=+i+12*e,this._data={},this._bubble()}function d(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function l(t){return 0>t?Math.ceil(t):Math.floor(t)}function p(t,e){for(var i=t+"";e>i.length;)i="0"+i;return i}function c(t,e,i,n){var s,o,r=e._milliseconds,a=e._days,h=e._months;r&&t._d.setTime(+t._d+r*i),(a||h)&&(s=t.minute(),o=t.hour()),a&&t.date(t.date()+a*i),h&&t.month(t.month()+h*i),r&&!n&&H.updateOffset(t),(a||h)&&(t.minute(s),t.hour(o))}function u(t){return"[object Array]"===Object.prototype.toString.call(t)}function f(t,e){var i,n=Math.min(t.length,e.length),s=Math.abs(t.length-e.length),o=0;for(i=0;n>i;i++)~~t[i]!==~~e[i]&&o++;return o+s}function m(t){return t?pe[t]||t.toLowerCase().replace(/(.)s$/,"$1"):t}function g(t,e){return e.abbr=t,V[t]||(V[t]=new r),V[t].set(e),V[t]}function v(t){delete V[t]}function y(t){if(!t)return H.fn._lang;if(!V[t]&&B)try{e("./lang/"+t)}catch(i){return H.fn._lang}return V[t]||H.fn._lang}function b(t){return t.match(/\[.*\]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function w(t){var e,i,n=t.match(X);for(e=0,i=n.length;i>e;e++)n[e]=me[n[e]]?me[n[e]]:b(n[e]);return function(s){var o="";for(e=0;i>e;e++)o+=n[e]instanceof Function?n[e].call(s,t):n[e];return o}}function _(t,e){return e=E(e,t.lang()),ce[e]||(ce[e]=w(e)),ce[e](t)}function E(t,e){function i(t){return e.longDateFormat(t)||t}for(var n=5;n--&&(Z.lastIndex=0,Z.test(t));)t=t.replace(Z,i);return t}function T(t,e){switch(t){case"DDDD":return Q;case"YYYY":return $;case"YYYYY":return te;case"S":case"SS":case"SSS":case"DDD":return J;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return ee;case"a":case"A":return y(e._l)._meridiemParse;case"X":return se;case"Z":case"ZZ":return ie;case"T":return ne;case"MM":case"DD":case"YY":case"HH":case"hh":case"mm":case"ss":case"M":case"D":case"d":case"H":case"h":case"m":case"s":return K;default:return RegExp(t.replace("\\",""))}}function x(t){var e=(ie.exec(t)||[])[0],i=(e+"").match(he)||["-",0,0],n=+(60*i[1])+~~i[2];return"+"===i[0]?-n:n}function S(t,e,i){var n,s=i._a;switch(t){case"M":case"MM":null!=e&&(s[1]=~~e-1);break;case"MMM":case"MMMM":n=y(i._l).monthsParse(e),null!=n?s[1]=n:i._isValid=!1;break;case"D":case"DD":null!=e&&(s[2]=~~e);break;case"DDD":case"DDDD":null!=e&&(s[1]=0,s[2]=~~e);break;case"YY":s[0]=~~e+(~~e>68?1900:2e3);break;case"YYYY":case"YYYYY":s[0]=~~e;break;case"a":case"A":i._isPm=y(i._l).isPM(e);break;case"H":case"HH":case"h":case"hh":s[3]=~~e;break;case"m":case"mm":s[4]=~~e;break;case"s":case"ss":s[5]=~~e;break;case"S":case"SS":case"SSS":s[6]=~~(1e3*("0."+e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,i._tzm=x(e)}null==e&&(i._isValid=!1)}function M(t){var e,i,n,s=[];if(!t._d){for(n=C(t),e=0;3>e&&null==t._a[e];++e)t._a[e]=s[e]=n[e];for(;7>e;e++)t._a[e]=s[e]=null==t._a[e]?2===e?1:0:t._a[e];s[3]+=~~((t._tzm||0)/60),s[4]+=~~((t._tzm||0)%60),i=new Date(0),t._useUTC?(i.setUTCFullYear(s[0],s[1],s[2]),i.setUTCHours(s[3],s[4],s[5],s[6])):(i.setFullYear(s[0],s[1],s[2]),i.setHours(s[3],s[4],s[5],s[6])),t._d=i}}function D(t){var e=t._i;t._d||(t._a=[e.years||e.year||e.y,e.months||e.month||e.M,e.days||e.day||e.d,e.hours||e.hour||e.h,e.minutes||e.minute||e.m,e.seconds||e.second||e.s,e.milliseconds||e.millisecond||e.ms],M(t))}function C(t){var e=new Date;return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function O(t){var e,i,n,s=y(t._l),o=""+t._i;for(n=E(t._f,s).match(X),t._a=[],e=0;n.length>e;e++)i=(T(n[e],t).exec(o)||[])[0],i&&(o=o.slice(o.indexOf(i)+i.length)),me[n[e]]&&S(n[e],i,t);o&&(t._il=o),t._isPm&&12>t._a[3]&&(t._a[3]+=12),t._isPm===!1&&12===t._a[3]&&(t._a[3]=0),M(t)}function N(t){var e,i,n,s,o,r=99;for(s=0;t._f.length>s;s++)e=d({},t),e._f=t._f[s],O(e),i=new a(e),o=f(e._a,i.toArray()),i._il&&(o+=i._il.length),r>o&&(r=o,n=i);d(t,n)}function L(t){var e,i=t._i,n=oe.exec(i);if(n){for(t._f="YYYY-MM-DD"+(n[2]||" "),e=0;4>e;e++)if(ae[e][1].exec(i)){t._f+=ae[e][0];break}ie.exec(i)&&(t._f+=" Z"),O(t)}else t._d=new Date(i)}function k(t){var e=t._i,i=q.exec(e);e===n?t._d=new Date:i?t._d=new Date(+i[1]):"string"==typeof e?L(t):u(e)?(t._a=e.slice(0),M(t)):e instanceof Date?t._d=new Date(+e):"object"==typeof e?D(t):t._d=new Date(e)}function I(t,e,i,n,s){return s.relativeTime(e||1,!!i,t,n)}function A(t,e,i){var n=W(Math.abs(t)/1e3),s=W(n/60),o=W(s/60),r=W(o/24),a=W(r/365),h=45>n&&["s",n]||1===s&&["m"]||45>s&&["mm",s]||1===o&&["h"]||22>o&&["hh",o]||1===r&&["d"]||25>=r&&["dd",r]||45>=r&&["M"]||345>r&&["MM",W(r/30)]||1===a&&["y"]||["yy",a];return h[2]=e,h[3]=t>0,h[4]=i,I.apply({},h)}function P(t,e,i){var n,s=i-e,o=i-t.day();return o>s&&(o-=7),s-7>o&&(o+=7),n=H(t).add("d",o),{week:Math.ceil(n.dayOfYear()/7),year:n.year()}}function F(t){var e=t._i,i=t._f;return null===e||""===e?null:("string"==typeof e&&(t._i=e=y().preparse(e)),H.isMoment(e)?(t=d({},e),t._d=new Date(+e._d)):i?u(i)?N(t):O(t):k(t),new a(t))}function Y(t,e){H.fn[t]=H.fn[t+"s"]=function(t){var i=this._isUTC?"UTC":"";return null!=t?(this._d["set"+i+e](t),H.updateOffset(this),this):this._d["get"+i+e]()}}function R(t){H.duration.fn[t]=function(){return this._data[t]}}function z(t,e){H.duration.fn["as"+t]=function(){return+this/e}}for(var H,U,j="2.2.1",W=Math.round,V={},B=i!==n&&i.exports,q=/^\/?Date\((\-?\d+)/i,G=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)\:(\d+)\.?(\d{3})?/,X=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|SS?S?|X|zz?|ZZ?|.)/g,Z=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,K=/\d\d?/,J=/\d{1,3}/,Q=/\d{3}/,$=/\d{1,4}/,te=/[+\-]?\d{1,6}/,ee=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,ie=/Z|[\+\-]\d\d:?\d\d/i,ne=/T/i,se=/[\+\-]?\d+(\.\d{1,3})?/,oe=/^\s*\d{4}-\d\d-\d\d((T| )(\d\d(:\d\d(:\d\d(\.\d\d?\d?)?)?)?)?([\+\-]\d\d:?\d\d)?)?/,re="YYYY-MM-DDTHH:mm:ssZ",ae=[["HH:mm:ss.S",/(T| )\d\d:\d\d:\d\d\.\d{1,3}/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],he=/([\+\-]|\d\d)/gi,de="Date|Hours|Minutes|Seconds|Milliseconds".split("|"),le={Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6},pe={ms:"millisecond",s:"second",m:"minute",h:"hour",d:"day",w:"week",W:"isoweek",M:"month",y:"year"},ce={},ue="DDD w W M D d".split(" "),fe="M D H h m s w W".split(" "),me={M:function(){return this.month()+1},MMM:function(t){return this.lang().monthsShort(this,t)},MMMM:function(t){return this.lang().months(this,t)},D:function(){return this.date()},DDD:function(){return this.dayOfYear()},d:function(){return this.day()},dd:function(t){return this.lang().weekdaysMin(this,t)},ddd:function(t){return this.lang().weekdaysShort(this,t)},dddd:function(t){return this.lang().weekdays(this,t)},w:function(){return this.week()},W:function(){return this.isoWeek()},YY:function(){return p(this.year()%100,2)},YYYY:function(){return p(this.year(),4)},YYYYY:function(){return p(this.year(),5)},gg:function(){return p(this.weekYear()%100,2)},gggg:function(){return this.weekYear()},ggggg:function(){return p(this.weekYear(),5)},GG:function(){return p(this.isoWeekYear()%100,2)},GGGG:function(){return this.isoWeekYear()},GGGGG:function(){return p(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.lang().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.lang().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return~~(this.milliseconds()/100)},SS:function(){return p(~~(this.milliseconds()/10),2)},SSS:function(){return p(this.milliseconds(),3)},Z:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(~~(t/60),2)+":"+p(~~t%60,2)},ZZ:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(~~(10*t/6),4)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},X:function(){return this.unix()}};ue.length;)U=ue.pop(),me[U+"o"]=o(me[U],U);for(;fe.length;)U=fe.pop(),me[U+U]=s(me[U],2);for(me.DDDD=s(me.DDD,3),d(r.prototype,{set:function(t){var e,i;for(i in t)e=t[i],"function"==typeof e?this[i]=e:this["_"+i]=e},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(t){return this._months[t.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(t){return this._monthsShort[t.month()]},monthsParse:function(t){var e,i,n;for(this._monthsParse||(this._monthsParse=[]),e=0;12>e;e++)if(this._monthsParse[e]||(i=H.utc([2e3,e]),n="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[e]=RegExp(n.replace(".",""),"i")),this._monthsParse[e].test(t))return e},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(t){return this._weekdays[t.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(t){return this._weekdaysShort[t.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(t){return this._weekdaysMin[t.day()]},weekdaysParse:function(t){var e,i,n;for(this._weekdaysParse||(this._weekdaysParse=[]),e=0;7>e;e++)if(this._weekdaysParse[e]||(i=H([2e3,1]).day(e),n="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[e]=RegExp(n.replace(".",""),"i")),this._weekdaysParse[e].test(t))return e},_longDateFormat:{LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D YYYY",LLL:"MMMM D YYYY LT",LLLL:"dddd, MMMM D YYYY LT"},longDateFormat:function(t){var e=this._longDateFormat[t];return!e&&this._longDateFormat[t.toUpperCase()]&&(e=this._longDateFormat[t.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t]=e),e},isPM:function(t){return"p"===(t+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(t,e,i){return t>11?i?"pm":"PM":i?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(t,e){var i=this._calendar[t];return"function"==typeof i?i.apply(e):i},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(t,e,i,n){var s=this._relativeTime[i];return"function"==typeof s?s(t,e,i,n):s.replace(/%d/i,t)},pastFuture:function(t,e){var i=this._relativeTime[t>0?"future":"past"];return"function"==typeof i?i(e):i.replace(/%s/i,e)},ordinal:function(t){return this._ordinal.replace("%d",t)},_ordinal:"%d",preparse:function(t){return t},postformat:function(t){return t},week:function(t){return P(t,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6}}),H=function(t,e,i){return F({_i:t,_f:e,_l:i,_isUTC:!1})},H.utc=function(t,e,i){return F({_useUTC:!0,_isUTC:!0,_l:i,_i:t,_f:e}).utc()},H.unix=function(t){return H(1e3*t)},H.duration=function(t,e){var i,n,s=H.isDuration(t),o="number"==typeof t,r=s?t._input:o?{}:t,a=G.exec(t);return o?e?r[e]=t:r.milliseconds=t:a&&(i="-"===a[1]?-1:1,r={y:0,d:~~a[2]*i,h:~~a[3]*i,m:~~a[4]*i,s:~~a[5]*i,ms:~~a[6]*i}),n=new h(r),s&&t.hasOwnProperty("_lang")&&(n._lang=t._lang),n},H.version=j,H.defaultFormat=re,H.updateOffset=function(){},H.lang=function(t,e){return t?(t=t.toLowerCase(),t=t.replace("_","-"),e?g(t,e):null===e?(v(t),t="en"):V[t]||y(t),H.duration.fn._lang=H.fn._lang=y(t),n):H.fn._lang._abbr},H.langData=function(t){return t&&t._lang&&t._lang._abbr&&(t=t._lang._abbr),y(t)},H.isMoment=function(t){return t instanceof a},H.isDuration=function(t){return t instanceof h},d(H.fn=a.prototype,{clone:function(){return H(this)},valueOf:function(){return+this._d+6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){return _(H(this).utc(),"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]")},toArray:function(){var t=this;return[t.year(),t.month(),t.date(),t.hours(),t.minutes(),t.seconds(),t.milliseconds()]},isValid:function(){return null==this._isValid&&(this._isValid=this._a?!f(this._a,(this._isUTC?H.utc(this._a):H(this._a)).toArray()):!isNaN(this._d.getTime())),!!this._isValid},invalidAt:function(){var t,e=this._a,i=(this._isUTC?H.utc(this._a):H(this._a)).toArray();for(t=6;t>=0&&e[t]===i[t];--t);return t},utc:function(){return this.zone(0)},local:function(){return this.zone(0),this._isUTC=!1,this},format:function(t){var e=_(this,t||H.defaultFormat);return this.lang().postformat(e)},add:function(t,e){var i;return i="string"==typeof t?H.duration(+e,t):H.duration(t,e),c(this,i,1),this},subtract:function(t,e){var i;return i="string"==typeof t?H.duration(+e,t):H.duration(t,e),c(this,i,-1),this},diff:function(t,e,i){var n,s,o=this._isUTC?H(t).zone(this._offset||0):H(t).local(),r=6e4*(this.zone()-o.zone());return e=m(e),"year"===e||"month"===e?(n=432e5*(this.daysInMonth()+o.daysInMonth()),s=12*(this.year()-o.year())+(this.month()-o.month()),s+=(this-H(this).startOf("month")-(o-H(o).startOf("month")))/n,s-=6e4*(this.zone()-H(this).startOf("month").zone()-(o.zone()-H(o).startOf("month").zone()))/n,"year"===e&&(s/=12)):(n=this-o,s="second"===e?n/1e3:"minute"===e?n/6e4:"hour"===e?n/36e5:"day"===e?(n-r)/864e5:"week"===e?(n-r)/6048e5:n),i?s:l(s)},from:function(t,e){return H.duration(this.diff(t)).lang(this.lang()._abbr).humanize(!e)},fromNow:function(t){return this.from(H(),t)},calendar:function(){var t=this.diff(H().zone(this.zone()).startOf("day"),"days",!0),e=-6>t?"sameElse":-1>t?"lastWeek":0>t?"lastDay":1>t?"sameDay":2>t?"nextDay":7>t?"nextWeek":"sameElse";return this.format(this.lang().calendar(e,this))},isLeapYear:function(){var t=this.year();return 0===t%4&&0!==t%100||0===t%400},isDST:function(){return this.zone()+H(t).startOf(e)},isBefore:function(t,e){return e=e!==n?e:"millisecond",+this.clone().startOf(e)<+H(t).startOf(e)},isSame:function(t,e){return e=e!==n?e:"millisecond",+this.clone().startOf(e)===+H(t).startOf(e)},min:function(t){return t=H.apply(null,arguments),this>t?this:t},max:function(t){return t=H.apply(null,arguments),t>this?this:t},zone:function(t){var e=this._offset||0;return null==t?this._isUTC?e:this._d.getTimezoneOffset():("string"==typeof t&&(t=x(t)),16>Math.abs(t)&&(t=60*t),this._offset=t,this._isUTC=!0,e!==t&&c(this,H.duration(e-t,"m"),1,!0),this)},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},hasAlignedHourOffset:function(t){return t=t?H(t).zone():0,0===(this.zone()-t)%60},daysInMonth:function(){return H.utc([this.year(),this.month()+1,0]).date()},dayOfYear:function(t){var e=W((H(this).startOf("day")-H(this).startOf("year"))/864e5)+1;return null==t?e:this.add("d",t-e)},weekYear:function(t){var e=P(this,this.lang()._week.dow,this.lang()._week.doy).year;return null==t?e:this.add("y",t-e)},isoWeekYear:function(t){var e=P(this,1,4).year;return null==t?e:this.add("y",t-e)},week:function(t){var e=this.lang().week(this);return null==t?e:this.add("d",7*(t-e))},isoWeek:function(t){var e=P(this,1,4).week;return null==t?e:this.add("d",7*(t-e))},weekday:function(t){var e=(this._d.getDay()+7-this.lang()._week.dow)%7;return null==t?e:this.add("d",t-e)},isoWeekday:function(t){return null==t?this.day()||7:this.day(this.day()%7?t:t-7)},get:function(t){return t=m(t),this[t.toLowerCase()]()},set:function(t,e){t=m(t),this[t.toLowerCase()](e)},lang:function(t){return t===n?this._lang:(this._lang=y(t),this)}}),U=0;de.length>U;U++)Y(de[U].toLowerCase().replace(/s$/,""),de[U]);Y("year","FullYear"),H.fn.days=H.fn.day,H.fn.months=H.fn.month,H.fn.weeks=H.fn.week,H.fn.isoWeeks=H.fn.isoWeek,H.fn.toJSON=H.fn.toISOString,d(H.duration.fn=h.prototype,{_bubble:function(){var t,e,i,n,s=this._milliseconds,o=this._days,r=this._months,a=this._data;a.milliseconds=s%1e3,t=l(s/1e3),a.seconds=t%60,e=l(t/60),a.minutes=e%60,i=l(e/60),a.hours=i%24,o+=l(i/24),a.days=o%30,r+=l(o/30),a.months=r%12,n=l(r/12),a.years=n},weeks:function(){return l(this.days()/7)},valueOf:function(){return this._milliseconds+864e5*this._days+2592e6*(this._months%12)+31536e6*~~(this._months/12)},humanize:function(t){var e=+this,i=A(e,!t,this.lang());return t&&(i=this.lang().pastFuture(e,i)),this.lang().postformat(i)},add:function(t,e){var i=H.duration(t,e);return this._milliseconds+=i._milliseconds,this._days+=i._days,this._months+=i._months,this._bubble(),this},subtract:function(t,e){var i=H.duration(t,e);return this._milliseconds-=i._milliseconds,this._days-=i._days,this._months-=i._months,this._bubble(),this},get:function(t){return t=m(t),this[t.toLowerCase()+"s"]()},as:function(t){return t=m(t),this["as"+t.charAt(0).toUpperCase()+t.slice(1)+"s"]()},lang:H.fn.lang});for(U in le)le.hasOwnProperty(U)&&(z(U,le[U]),R(U.toLowerCase()));z("Weeks",6048e5),H.duration.fn.asMonths=function(){return(+this-31536e6*this.years())/2592e6+12*this.years()},H.lang("en",{ordinal:function(t){var e=t%10,i=1===~~(t%100/10)?"th":1===e?"st":2===e?"nd":3===e?"rd":"th";return t+i}}),B&&(i.exports=H),"undefined"==typeof ender&&(this.moment=H),"function"==typeof t&&t.amd&&t("moment",[],function(){return H})}).call(this)},{}],3:[function(e,i,n){function s(){this.subscriptions=[]}function o(t){if(this.id=O.randomUUID(),this.options=t||{},this.data={},this.fieldId=this.options.fieldId||"id",this.convert={},this.options.convert)for(var e in this.options.convert)if(this.options.convert.hasOwnProperty(e)){var i=this.options.convert[e];this.convert[e]="Date"==i||"ISODate"==i||"ASPDate"==i?"Date":i -}this.subscribers={},this.internalIds={}}function r(t,e){this.id=O.randomUUID(),this.data=null,this.ids={},this.options=e||{},this.fieldId="id",this.subscribers={};var i=this;this.listener=function(){i._onEvent.apply(i,arguments)},this.setData(t)}function a(t,e){this.parent=t,this.options=e||{},this.defaultOptions={order:function(t,e){if(t instanceof y){if(e instanceof y){var i=t.data.end-t.data.start,n=e.data.end-e.data.start;return i-n||t.data.start-e.data.start}return-1}return e instanceof y?1:t.data.start-e.data.start},margin:{item:10}},this.ordered=[]}function h(t){this.id=O.randomUUID(),this.start=0,this.end=0,this.options={min:null,max:null,zoomMin:null,zoomMax:null},this.listeners=[],this.setOptions(t)}function d(){this.id=O.randomUUID(),this.components={},this.repaintTimer=void 0,this.reflowTimer=void 0}function l(){this.id=null,this.parent=null,this.depends=null,this.controller=null,this.options=null,this.frame=null,this.top=0,this.left=0,this.width=0,this.height=0}function p(t,e,i){this.id=O.randomUUID(),this.parent=t,this.depends=e,this.options=i||{}}function c(t,e){this.id=O.randomUUID(),this.container=t,this.options=e||{},this.defaultOptions={autoResize:!0},this.listeners={}}function u(t,e,i){this.id=O.randomUUID(),this.parent=t,this.depends=e,this.dom={majorLines:[],majorTexts:[],minorLines:[],minorTexts:[],redundant:{majorLines:[],majorTexts:[],minorLines:[],minorTexts:[]}},this.props={range:{start:0,end:0,minimumStep:0},lineTop:0},this.options=i||{},this.defaultOptions={orientation:"bottom",showMinorLabels:!0,showMajorLabels:!0},this.conversion=null,this.range=null}function f(t,e,i){this.id=O.randomUUID(),this.parent=t,this.depends=e,this.options=i||{},this.defaultOptions={type:"box",align:"center",orientation:"bottom",margin:{axis:20,item:10},padding:5},this.dom={};var n=this;this.itemsData=null,this.range=null,this.listeners={add:function(t,e,i){i!=n.id&&n._onAdd(e.items)},update:function(t,e,i){i!=n.id&&n._onUpdate(e.items)},remove:function(t,e,i){i!=n.id&&n._onRemove(e.items)}},this.items={},this.queue={},this.stack=new a(this,Object.create(this.options)),this.conversion=null}function m(t,e,i,n){this.parent=t,this.data=e,this.dom=null,this.options=i||{},this.defaultOptions=n||{},this.selected=!1,this.visible=!1,this.top=0,this.left=0,this.width=0,this.height=0}function g(t,e,i,n){this.props={dot:{left:0,top:0,width:0,height:0},line:{top:0,left:0,width:0,height:0}},m.call(this,t,e,i,n)}function v(t,e,i,n){this.props={dot:{top:0,width:0,height:0},content:{height:0,marginLeft:0}},m.call(this,t,e,i,n)}function y(t,e,i,n){this.props={content:{left:0,width:0}},m.call(this,t,e,i,n)}function b(t,e,i){this.id=O.randomUUID(),this.parent=t,this.groupId=e,this.itemset=null,this.options=i||{},this.options.top=0,this.props={label:{width:0,height:0}},this.top=0,this.left=0,this.width=0,this.height=0}function w(t,e,i){this.id=O.randomUUID(),this.parent=t,this.depends=e,this.options=i||{},this.range=null,this.itemsData=null,this.groupsData=null,this.groups={},this.dom={},this.props={labels:{width:0}},this.queue={};var n=this;this.listeners={add:function(t,e){n._onAdd(e.items)},update:function(t,e){n._onUpdate(e.items)},remove:function(t,e){n._onRemove(e.items)}}}function _(t,e,i){var n=this;if(this.options=O.extend({orientation:"bottom",min:null,max:null,zoomMin:10,zoomMax:31536e10,showMinorLabels:!0,showMajorLabels:!0,autoResize:!1},i),this.controller=new d,!t)throw Error("No container element provided");var s=Object.create(this.options);s.height=function(){return n.options.height?n.options.height:n.timeaxis.height+n.content.height},this.rootPanel=new c(t,s),this.controller.add(this.rootPanel);var o=Object.create(this.options);o.left=function(){return n.labelPanel.width},o.width=function(){return n.rootPanel.width-n.labelPanel.width},o.top=null,o.height=null,this.itemPanel=new p(this.rootPanel,[],o),this.controller.add(this.itemPanel);var r=Object.create(this.options);r.top=null,r.left=null,r.height=null,r.width=function(){return n.content&&"function"==typeof n.content.getLabelsWidth?n.content.getLabelsWidth():0},this.labelPanel=new p(this.rootPanel,[],r),this.controller.add(this.labelPanel);var a=M().hours(0).minutes(0).seconds(0).milliseconds(0);this.range=new h({start:a.clone().add("days",-3).valueOf(),end:a.clone().add("days",4).valueOf()}),this.range.subscribe(this.rootPanel,"move","horizontal"),this.range.subscribe(this.rootPanel,"zoom","horizontal"),this.range.on("rangechange",function(){var t=!0;n.controller.requestReflow(t)}),this.range.on("rangechanged",function(){var t=!0;n.controller.requestReflow(t)});var l=Object.create(s);l.range=this.range,l.left=null,l.top=null,l.width="100%",l.height=null,this.timeaxis=new u(this.itemPanel,[],l),this.timeaxis.setRange(this.range),this.controller.add(this.timeaxis),this.setGroups(null),this.itemsData=null,this.groupsData=null,e&&this.setItems(e)}function E(t,e,i,n){this.selected=!1,this.edges=[],this.group=n.nodes.group,this.fontSize=n.nodes.fontSize,this.fontFace=n.nodes.fontFace,this.fontColor=n.nodes.fontColor,this.color=n.nodes.color,this.id=void 0,this.shape=n.nodes.shape,this.image=n.nodes.image,this.x=0,this.y=0,this.xFixed=!1,this.yFixed=!1,this.radius=n.nodes.radius,this.radiusFixed=!1,this.radiusMin=n.nodes.radiusMin,this.radiusMax=n.nodes.radiusMax,this.imagelist=e,this.grouplist=i,this.setProperties(t,n),this.mass=50,this.fx=0,this.fy=0,this.vx=0,this.vy=0,this.minForce=n.minForce,this.damping=.9}function T(t,e,i){if(!e)throw"No graph provided";this.graph=e,this.widthMin=i.edges.widthMin,this.widthMax=i.edges.widthMax,this.id=void 0,this.fromId=void 0,this.toId=void 0,this.style=i.edges.style,this.title=void 0,this.width=i.edges.width,this.value=void 0,this.length=i.edges.length,this.from=null,this.to=null,this.connected=!1,this.dash=O.extend({},i.edges.dash),this.stiffness=void 0,this.color=i.edges.color,this.widthFixed=!1,this.lengthFixed=!1,this.setProperties(t,i)}function x(t,e,i,n){this.container=t?t:document.body,this.x=0,this.y=0,this.padding=5,void 0!==e&&void 0!==i&&this.setPosition(e,i),void 0!==n&&this.setText(n),this.frame=document.createElement("div");var s=this.frame.style;s.position="absolute",s.visibility="hidden",s.border="1px solid #666",s.color="black",s.padding=this.padding+"px",s.backgroundColor="#FFFFC6",s.borderRadius="3px",s.MozBorderRadius="3px",s.WebkitBorderRadius="3px",s.boxShadow="3px 3px 10px rgba(128, 128, 128, 0.5)",s.whiteSpace="nowrap",this.container.appendChild(this.frame)}function S(t,e,i){this.containerElement=t,this.width="100%",this.height="100%",this.refreshRate=50,this.stabilize=!0,this.selectable=!0,this.constants={nodes:{radiusMin:5,radiusMax:20,radius:5,distance:100,shape:"ellipse",image:void 0,widthMin:16,widthMax:64,fontColor:"black",fontSize:14,fontFace:"arial",color:{border:"#2B7CE9",background:"#97C2FC",highlight:{border:"#2B7CE9",background:"#D2E5FF"}},borderColor:"#2B7CE9",backgroundColor:"#97C2FC",highlightColor:"#D2E5FF",group:void 0},edges:{widthMin:1,widthMax:15,width:1,style:"line",color:"#343434",fontColor:"#343434",fontSize:14,fontFace:"arial",length:100,dash:{length:10,gap:5,altLength:void 0}},minForce:.05,minVelocity:.02,maxIterations:1e3};var n=this;this.nodes={},this.edges={},this.nodesData=null,this.edgesData=null;var s=this;this.nodesListeners={add:function(t,e){s._addNodes(e.items),s.start()},update:function(t,e){s._updateNodes(e.items),s.start()},remove:function(t,e){s._removeNodes(e.items),s.start()}},this.edgesListeners={add:function(t,e){s._addEdges(e.items),s.start()},update:function(t,e){s._updateEdges(e.items),s.start()},remove:function(t,e){s._removeEdges(e.items),s.start()}},this.groups=new Groups,this.images=new Images,this.images.setOnloadCallback(function(){n._redraw()}),this.moving=!1,this.selection=[],this.timer=void 0,this._create(),this.setOptions(i),this.setData(e)}var M="undefined"!=typeof window&&window.moment||e("moment"),D="undefined"!=typeof window&&window.Hammer||e("hammerjs");if(!Array.prototype.indexOf){Array.prototype.indexOf=function(t){for(var e=0;this.length>e;e++)if(this[e]==t)return e;return-1};try{console.log("Warning: Ancient browser detected. Please update your browser")}catch(C){}}Array.prototype.forEach||(Array.prototype.forEach=function(t,e){for(var i=0,n=this.length;n>i;++i)t.call(e||this,this[i],i,this)}),Array.prototype.map||(Array.prototype.map=function(t,e){var i,n,s;if(null==this)throw new TypeError(" this is null or not defined");var o=Object(this),r=o.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(e&&(i=e),n=Array(r),s=0;r>s;){var a,h;s in o&&(a=o[s],h=t.call(i,a,s,o),n[s]=h),s++}return n}),Array.prototype.filter||(Array.prototype.filter=function(t){"use strict";if(null==this)throw new TypeError;var e=Object(this),i=e.length>>>0;if("function"!=typeof t)throw new TypeError;for(var n=[],s=arguments[1],o=0;i>o;o++)if(o in e){var r=e[o];t.call(s,r,o,e)&&n.push(r)}return n}),Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,e=!{toString:null}.propertyIsEnumerable("toString"),i=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],n=i.length;return function(s){if("object"!=typeof s&&"function"!=typeof s||null===s)throw new TypeError("Object.keys called on non-object");var o=[];for(var r in s)t.call(s,r)&&o.push(r);if(e)for(var a=0;n>a;a++)t.call(s,i[a])&&o.push(i[a]);return o}}()),Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s}),Object.create||(Object.create=function(t){function e(){}if(arguments.length>1)throw Error("Object.create implementation only accepts the first parameter.");return e.prototype=t,new e}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s});var O={};O.isNumber=function(t){return t instanceof Number||"number"==typeof t},O.isString=function(t){return t instanceof String||"string"==typeof t},O.isDate=function(t){if(t instanceof Date)return!0;if(O.isString(t)){var e=N.exec(t);if(e)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},O.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},O.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},O.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var n=arguments[e];for(var s in n)n.hasOwnProperty(s)&&void 0!==n[s]&&(t[s]=n[s])}return t},O.convert=function(t,e){var i;if(void 0===t)return void 0;if(null===t)return null;if(!e)return t;if("string"!=typeof e&&!(e instanceof String))throw Error("Type must be a string");switch(e){case"boolean":case"Boolean":return Boolean(t);case"number":case"Number":return Number(t.valueOf());case"string":case"String":return t+"";case"Date":if(O.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(M.isMoment(t))return new Date(t.valueOf());if(O.isString(t))return i=N.exec(t),i?new Date(Number(i[1])):M(t).toDate();throw Error("Cannot convert object of type "+O.getType(t)+" to type Date");case"Moment":if(O.isNumber(t))return M(t);if(t instanceof Date)return M(t.valueOf());if(M.isMoment(t))return M.clone();if(O.isString(t))return i=N.exec(t),i?M(Number(i[1])):M(t);throw Error("Cannot convert object of type "+O.getType(t)+" to type Date");case"ISODate":if(O.isNumber(t))return new Date(t);if(t instanceof Date)return t.toISOString();if(M.isMoment(t))return t.toDate().toISOString();if(O.isString(t))return i=N.exec(t),i?new Date(Number(i[1])).toISOString():new Date(t).toISOString();throw Error("Cannot convert object of type "+O.getType(t)+" to type ISODate");case"ASPDate":if(O.isNumber(t))return"/Date("+t+")/";if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(O.isString(t)){i=N.exec(t);var n;return n=i?new Date(Number(i[1])).valueOf():new Date(t).valueOf(),"/Date("+n+")/"}throw Error("Cannot convert object of type "+O.getType(t)+" to type ASPDate");default:throw Error("Cannot convert object of type "+O.getType(t)+' to type "'+e+'"')}};var N=/^\/?Date\((\-?\d+)/i;O.getType=function(t){var e=typeof t;return"object"==e?null==t?"null":t instanceof Boolean?"Boolean":t instanceof Number?"Number":t instanceof String?"String":t instanceof Array?"Array":t instanceof Date?"Date":"Object":"number"==e?"Number":"boolean"==e?"Boolean":"string"==e?"String":e},O.getAbsoluteLeft=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetLeft,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetLeft,n-=s.scrollLeft,s=s.offsetParent;return n},O.getAbsoluteTop=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetTop,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetTop,n-=s.scrollTop,s=s.offsetParent;return n},O.getPageY=function(t){if("pageY"in t)return t.pageY;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientY:t.clientY;var i=document.documentElement,n=document.body;return e+(i&&i.scrollTop||n&&n.scrollTop||0)-(i&&i.clientTop||n&&n.clientTop||0)},O.getPageX=function(t){if("pageY"in t)return t.pageX;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientX:t.clientX;var i=document.documentElement,n=document.body;return e+(i&&i.scrollLeft||n&&n.scrollLeft||0)-(i&&i.clientLeft||n&&n.clientLeft||0)},O.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},O.removeClassName=function(t,e){var i=t.className.split(" "),n=i.indexOf(e);-1!=n&&(i.splice(n,1),t.className=i.join(" "))},O.forEach=function(t,e){var i,n;if(t instanceof Array)for(i=0,n=t.length;n>i;i++)e(t[i],i,t);else for(i in t)t.hasOwnProperty(i)&&e(t[i],i,t)},O.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},O.addEventListener=function(t,e,i,n){t.addEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.addEventListener(e,i,n)):t.attachEvent("on"+e,i)},O.removeEventListener=function(t,e,i,n){t.removeEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.removeEventListener(e,i,n)):t.detachEvent("on"+e,i)},O.getTarget=function(t){t||(t=window.event);var e;return t.target?e=t.target:t.srcElement&&(e=t.srcElement),void 0!=e.nodeType&&3==e.nodeType&&(e=e.parentNode),e},O.stopPropagation=function(t){t||(t=window.event),t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},O.preventDefault=function(t){t||(t=window.event),t.preventDefault?t.preventDefault():t.returnValue=!1},O.option={},O.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},O.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},O.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?t+"":e||null},O.option.asSize=function(t,e){return"function"==typeof t&&(t=t()),O.isString(t)?t:O.isNumber(t)?t+"px":e||null},O.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null},O.loadCss=function(t){if("undefined"!=typeof document){var e=document.createElement("style");e.type="text/css",e.styleSheet?e.styleSheet.cssText=t:e.appendChild(document.createTextNode(t)),document.getElementsByTagName("head")[0].appendChild(e)}};var L={listeners:[],indexOf:function(t){for(var e=this.listeners,i=0,n=this.listeners.length;n>i;i++){var s=e[i];if(s&&s.object==t)return i}return-1},addListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];s||(s={object:t,events:{}},this.listeners.push(s));var o=s.events[e];o||(o=[],s.events[e]=o),-1==o.indexOf(i)&&o.push(i)},removeListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];o&&(n=o.indexOf(i),-1!=n&&o.splice(n,1),0==o.length&&delete s.events[e]);var r=0,a=s.events;for(var h in a)a.hasOwnProperty(h)&&r++;0==r&&delete this.listeners[n]}},removeAllListeners:function(){this.listeners=[]},trigger:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];if(o)for(var r=0,a=o.length;a>r;r++)o[r](i)}}};s.prototype.on=function(t,e,i){var n=t instanceof RegExp?t:RegExp(t.replace("*","\\w+")),s={id:O.randomUUID(),event:t,regexp:n,callback:"function"==typeof e?e:null,target:i};return this.subscriptions.push(s),s.id},s.prototype.off=function(t){for(var e=0;this.subscriptions.length>e;){var i=this.subscriptions[e],n=!0;if(t instanceof Object)for(var s in t)t.hasOwnProperty(s)&&t[s]!==i[s]&&(n=!1);else n=i.id==t;n?this.subscriptions.splice(e,1):e++}},s.prototype.emit=function(t,e,i){for(var n=0;this.subscriptions.length>n;n++){var s=this.subscriptions[n];s.regexp.test(t)&&s.callback&&s.callback(t,e,i)}},o.prototype.subscribe=function(t,e){var i=this.subscribers[t];i||(i=[],this.subscribers[t]=i),i.push({callback:e})},o.prototype.unsubscribe=function(t,e){var i=this.subscribers[t];i&&(this.subscribers[t]=i.filter(function(t){return t.callback!=e}))},o.prototype._trigger=function(t,e,i){if("*"==t)throw Error("Cannot trigger event *");var n=[];t in this.subscribers&&(n=n.concat(this.subscribers[t])),"*"in this.subscribers&&(n=n.concat(this.subscribers["*"]));for(var s=0;n.length>s;s++){var o=n[s];o.callback&&o.callback(t,e,i||null)}},o.prototype.add=function(t,e){var i,n=[],s=this;if(t instanceof Array)for(var o=0,r=t.length;r>o;o++)i=s._addItem(t[o]),n.push(i);else if(O.isDataTable(t))for(var a=this._getColumnNames(t),h=0,d=t.getNumberOfRows();d>h;h++){for(var l={},p=0,c=a.length;c>p;p++){var u=a[p];l[u]=t.getValue(h,p)}i=s._addItem(l),n.push(i)}else{if(!(t instanceof Object))throw Error("Unknown dataType");i=s._addItem(t),n.push(i)}return n.length&&this._trigger("add",{items:n},e),n},o.prototype.update=function(t,e){var i=[],n=[],s=this,o=s.fieldId,r=function(t){var e=t[o];s.data[e]?(e=s._updateItem(t),n.push(e)):(e=s._addItem(t),i.push(e))};if(t instanceof Array)for(var a=0,h=t.length;h>a;a++)r(t[a]);else if(O.isDataTable(t))for(var d=this._getColumnNames(t),l=0,p=t.getNumberOfRows();p>l;l++){for(var c={},u=0,f=d.length;f>u;u++){var m=d[u];c[m]=t.getValue(l,u)}r(c)}else{if(!(t instanceof Object))throw Error("Unknown dataType");r(t)}return i.length&&this._trigger("add",{items:i},e),n.length&&this._trigger("update",{items:n},e),i.concat(n)},o.prototype.get=function(){var t,e,i,n,s=this,o=O.getType(arguments[0]);"String"==o||"Number"==o?(t=arguments[0],i=arguments[1],n=arguments[2]):"Array"==o?(e=arguments[0],i=arguments[1],n=arguments[2]):(i=arguments[0],n=arguments[1]);var r;if(i&&i.type){if(r="DataTable"==i.type?"DataTable":"Array",n&&r!=O.getType(n))throw Error('Type of parameter "data" ('+O.getType(n)+") "+"does not correspond with specified options.type ("+i.type+")");if("DataTable"==r&&!O.isDataTable(n))throw Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else r=n?"DataTable"==O.getType(n)?"DataTable":"Array":"Array";var a,h,d,l,p=i&&i.convert||this.options.convert,c=i&&i.filter,u=[];if(void 0!=t)a=s._getItem(t,p),c&&!c(a)&&(a=null);else if(void 0!=e)for(d=0,l=e.length;l>d;d++)a=s._getItem(e[d],p),(!c||c(a))&&u.push(a);else for(h in this.data)this.data.hasOwnProperty(h)&&(a=s._getItem(h,p),(!c||c(a))&&u.push(a));if(i&&i.order&&void 0==t&&this._sort(u,i.order),i&&i.fields){var f=i.fields;if(void 0!=t)a=this._filterFields(a,f);else for(d=0,l=u.length;l>d;d++)u[d]=this._filterFields(u[d],f)}if("DataTable"==r){var m=this._getColumnNames(n);if(void 0!=t)s._appendRow(n,m,a);else for(d=0,l=u.length;l>d;d++)s._appendRow(n,m,u[d]);return n}if(void 0!=t)return a;if(n){for(d=0,l=u.length;l>d;d++)n.push(u[d]);return n}return u},o.prototype.getIds=function(t){var e,i,n,s,o,r=this.data,a=t&&t.filter,h=t&&t.order,d=t&&t.convert||this.options.convert,l=[];if(a)if(h){o=[];for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,d),a(s)&&o.push(s));for(this._sort(o,h),e=0,i=o.length;i>e;e++)l[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,d),a(s)&&l.push(s[this.fieldId]));else if(h){o=[];for(n in r)r.hasOwnProperty(n)&&o.push(r[n]);for(this._sort(o,h),e=0,i=o.length;i>e;e++)l[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=r[n],l.push(s[this.fieldId]));return l},o.prototype.forEach=function(t,e){var i,n,s=e&&e.filter,o=e&&e.convert||this.options.convert,r=this.data;if(e&&e.order)for(var a=this.get(e),h=0,d=a.length;d>h;h++)i=a[h],n=i[this.fieldId],t(i,n);else for(n in r)r.hasOwnProperty(n)&&(i=this._getItem(n,o),(!s||s(i))&&t(i,n))},o.prototype.map=function(t,e){var i,n=e&&e.filter,s=e&&e.convert||this.options.convert,o=[],r=this.data;for(var a in r)r.hasOwnProperty(a)&&(i=this._getItem(a,s),(!n||n(i))&&o.push(t(i,a)));return e&&e.order&&this._sort(o,e.order),o},o.prototype._filterFields=function(t,e){var i={};for(var n in t)t.hasOwnProperty(n)&&-1!=e.indexOf(n)&&(i[n]=t[n]);return i},o.prototype._sort=function(t,e){if(O.isString(e)){var i=e;t.sort(function(t,e){var n=t[i],s=e[i];return n>s?1:s>n?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},o.prototype.remove=function(t,e){var i,n,s,o=[];if(t instanceof Array)for(i=0,n=t.length;n>i;i++)s=this._remove(t[i]),null!=s&&o.push(s);else s=this._remove(t),null!=s&&o.push(s);return o.length&&this._trigger("remove",{items:o},e),o},o.prototype._remove=function(t){if(O.isNumber(t)||O.isString(t)){if(this.data[t])return delete this.data[t],delete this.internalIds[t],t}else if(t instanceof Object){var e=t[this.fieldId];if(e&&this.data[e])return delete this.data[e],delete this.internalIds[e],e}return null},o.prototype.clear=function(t){var e=Object.keys(this.data);return this.data={},this.internalIds={},this._trigger("remove",{items:e},t),e},o.prototype.max=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||r>n)&&(i=o,n=r)}return i},o.prototype.min=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||n>r)&&(i=o,n=r)}return i},o.prototype.distinct=function(t){var e=this.data,i=[],n=this.options.convert[t],s=0;for(var o in e)if(e.hasOwnProperty(o)){for(var r=e[o],a=O.convert(r[t],n),h=!1,d=0;s>d;d++)if(i[d]==a){h=!0;break}h||(i[s]=a,s++)}return i},o.prototype._addItem=function(t){var e=t[this.fieldId];if(void 0!=e){if(this.data[e])throw Error("Cannot add item: item with id "+e+" already exists")}else e=O.randomUUID(),t[this.fieldId]=e,this.internalIds[e]=t;var i={};for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=O.convert(t[n],s)}return this.data[e]=i,e},o.prototype._getItem=function(t,e){var i,n,s=this.data[t];if(!s)return null;var o={},r=this.fieldId,a=this.internalIds;if(e)for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a||(o[i]=O.convert(n,e[i])));else for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a||(o[i]=n));return o},o.prototype._updateItem=function(t){var e=t[this.fieldId];if(void 0==e)throw Error("Cannot update item: item has no id (item: "+JSON.stringify(t)+")");var i=this.data[e];if(!i)throw Error("Cannot update item: no item with id "+e+" found");for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=O.convert(t[n],s)}return e},o.prototype._getColumnNames=function(t){for(var e=[],i=0,n=t.getNumberOfColumns();n>i;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},o.prototype._appendRow=function(t,e,i){for(var n=t.addRow(),s=0,o=e.length;o>s;s++){var r=e[s];t.setValue(n,s,i[r])}},r.prototype.setData=function(t){var e,i,n;if(this.data){this.data.unsubscribe&&this.data.unsubscribe("*",this.listener),e=[];for(var s in this.ids)this.ids.hasOwnProperty(s)&&e.push(s);this.ids={},this._trigger("remove",{items:e})}if(this.data=t,this.data){for(this.fieldId=this.options.fieldId||this.data&&this.data.options&&this.data.options.fieldId||"id",e=this.data.getIds({filter:this.options&&this.options.filter}),i=0,n=e.length;n>i;i++)s=e[i],this.ids[s]=!0;this._trigger("add",{items:e}),this.data.subscribe&&this.data.subscribe("*",this.listener)}},r.prototype.get=function(){var t,e,i,n=this,s=O.getType(arguments[0]);"String"==s||"Number"==s||"Array"==s?(t=arguments[0],e=arguments[1],i=arguments[2]):(e=arguments[0],i=arguments[1]);var o=O.extend({},this.options,e);this.options.filter&&e&&e.filter&&(o.filter=function(t){return n.options.filter(t)&&e.filter(t)});var r=[];return void 0!=t&&r.push(t),r.push(o),r.push(i),this.data&&this.data.get.apply(this.data,r)},r.prototype.getIds=function(t){var e;if(this.data){var i,n=this.options.filter;i=t&&t.filter?n?function(e){return n(e)&&t.filter(e)}:t.filter:n,e=this.data.getIds({filter:i,order:t&&t.order})}else e=[];return e},r.prototype._onEvent=function(t,e,i){var n,s,o,r,a=e&&e.items,h=this.data,d=[],l=[],p=[];if(a&&h){switch(t){case"add":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r&&(this.ids[o]=!0,d.push(o));break;case"update":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r?this.ids[o]?l.push(o):(this.ids[o]=!0,d.push(o)):this.ids[o]&&(delete this.ids[o],p.push(o));break;case"remove":for(n=0,s=a.length;s>n;n++)o=a[n],this.ids[o]&&(delete this.ids[o],p.push(o))}d.length&&this._trigger("add",{items:d},i),l.length&&this._trigger("update",{items:l},i),p.length&&this._trigger("remove",{items:p},i)}},r.prototype.subscribe=o.prototype.subscribe,r.prototype.unsubscribe=o.prototype.unsubscribe,r.prototype._trigger=o.prototype._trigger,TimeStep=function(t,e,i){this.current=new Date,this._start=new Date,this._end=new Date,this.autoScale=!0,this.scale=TimeStep.SCALE.DAY,this.step=1,this.setRange(t,e,i)},TimeStep.SCALE={MILLISECOND:1,SECOND:2,MINUTE:3,HOUR:4,DAY:5,WEEKDAY:6,MONTH:7,YEAR:8},TimeStep.prototype.setRange=function(t,e,i){t instanceof Date&&e instanceof Date&&(this._start=void 0!=t?new Date(t.valueOf()):new Date,this._end=void 0!=e?new Date(e.valueOf()):new Date,this.autoScale&&this.setMinimumStep(i))},TimeStep.prototype.first=function(){this.current=new Date(this._start.valueOf()),this.roundToMinor()},TimeStep.prototype.roundToMinor=function(){switch(this.scale){case TimeStep.SCALE.YEAR:this.current.setFullYear(this.step*Math.floor(this.current.getFullYear()/this.step)),this.current.setMonth(0);case TimeStep.SCALE.MONTH:this.current.setDate(1);case TimeStep.SCALE.DAY:case TimeStep.SCALE.WEEKDAY:this.current.setHours(0);case TimeStep.SCALE.HOUR:this.current.setMinutes(0);case TimeStep.SCALE.MINUTE:this.current.setSeconds(0);case TimeStep.SCALE.SECOND:this.current.setMilliseconds(0)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.setMilliseconds(this.current.getMilliseconds()-this.current.getMilliseconds()%this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()-this.current.getSeconds()%this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()-this.current.getMinutes()%this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()-this.current.getHours()%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()-1-(this.current.getDate()-1)%this.step+1);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()-this.current.getMonth()%this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()-this.current.getFullYear()%this.step);break;default:}},TimeStep.prototype.hasNext=function(){return this.current.valueOf()<=this._end.valueOf()},TimeStep.prototype.next=function(){var t=this.current.valueOf();if(6>this.current.getMonth())switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current=new Date(this.current.valueOf()+1e3*this.step);break;case TimeStep.SCALE.MINUTE:this.current=new Date(this.current.valueOf()+60*1e3*this.step);break;case TimeStep.SCALE.HOUR:this.current=new Date(this.current.valueOf()+60*60*1e3*this.step);var e=this.current.getHours();this.current.setHours(e-e%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step);break;default:}else switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()+this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()+this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()+this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step);break;default:}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.getMilliseconds()0&&(this.step=e),this.autoScale=!1},TimeStep.prototype.setAutoScale=function(t){this.autoScale=t},TimeStep.prototype.setMinimumStep=function(t){if(void 0!=t){var e=31104e6,i=2592e6,n=864e5,s=36e5,o=6e4,r=1e3,a=1;1e3*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1e3),500*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=500),100*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=100),50*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=50),10*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=10),5*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=5),e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1),3*i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=3),i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=1),5*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=5),2*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=2),n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=1),n/2>t&&(this.scale=TimeStep.SCALE.WEEKDAY,this.step=1),4*s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=4),s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=1),15*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=15),10*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=10),5*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=5),o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=1),15*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=15),10*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=10),5*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=5),r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=1),200*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=200),100*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=100),50*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=50),10*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=10),5*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=5),a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=1) -}},TimeStep.prototype.snap=function(t){if(this.scale==TimeStep.SCALE.YEAR){var e=t.getFullYear()+Math.round(t.getMonth()/12);t.setFullYear(Math.round(e/this.step)*this.step),t.setMonth(0),t.setDate(0),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MONTH)t.getDate()>15?(t.setDate(1),t.setMonth(t.getMonth()+1)):t.setDate(1),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0);else if(this.scale==TimeStep.SCALE.DAY||this.scale==TimeStep.SCALE.WEEKDAY){switch(this.step){case 5:case 2:t.setHours(24*Math.round(t.getHours()/24));break;default:t.setHours(12*Math.round(t.getHours()/12))}t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.HOUR){switch(this.step){case 4:t.setMinutes(60*Math.round(t.getMinutes()/60));break;default:t.setMinutes(30*Math.round(t.getMinutes()/30))}t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MINUTE){switch(this.step){case 15:case 10:t.setMinutes(5*Math.round(t.getMinutes()/5)),t.setSeconds(0);break;case 5:t.setSeconds(60*Math.round(t.getSeconds()/60));break;default:t.setSeconds(30*Math.round(t.getSeconds()/30))}t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.SECOND)switch(this.step){case 15:case 10:t.setSeconds(5*Math.round(t.getSeconds()/5)),t.setMilliseconds(0);break;case 5:t.setMilliseconds(1e3*Math.round(t.getMilliseconds()/1e3));break;default:t.setMilliseconds(500*Math.round(t.getMilliseconds()/500))}else if(this.scale==TimeStep.SCALE.MILLISECOND){var i=this.step>5?this.step/2:1;t.setMilliseconds(Math.round(t.getMilliseconds()/i)*i)}},TimeStep.prototype.isMajor=function(){switch(this.scale){case TimeStep.SCALE.MILLISECOND:return 0==this.current.getMilliseconds();case TimeStep.SCALE.SECOND:return 0==this.current.getSeconds();case TimeStep.SCALE.MINUTE:return 0==this.current.getHours()&&0==this.current.getMinutes();case TimeStep.SCALE.HOUR:return 0==this.current.getHours();case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return 1==this.current.getDate();case TimeStep.SCALE.MONTH:return 0==this.current.getMonth();case TimeStep.SCALE.YEAR:return!1;default:return!1}},TimeStep.prototype.getLabelMinor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return M(t).format("SSS");case TimeStep.SCALE.SECOND:return M(t).format("s");case TimeStep.SCALE.MINUTE:return M(t).format("HH:mm");case TimeStep.SCALE.HOUR:return M(t).format("HH:mm");case TimeStep.SCALE.WEEKDAY:return M(t).format("ddd D");case TimeStep.SCALE.DAY:return M(t).format("D");case TimeStep.SCALE.MONTH:return M(t).format("MMM");case TimeStep.SCALE.YEAR:return M(t).format("YYYY");default:return""}},TimeStep.prototype.getLabelMajor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return M(t).format("HH:mm:ss");case TimeStep.SCALE.SECOND:return M(t).format("D MMMM HH:mm");case TimeStep.SCALE.MINUTE:case TimeStep.SCALE.HOUR:return M(t).format("ddd D MMMM");case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return M(t).format("MMMM YYYY");case TimeStep.SCALE.MONTH:return M(t).format("YYYY");case TimeStep.SCALE.YEAR:return"";default:return""}},a.prototype.setOptions=function(t){O.extend(this.options,t)},a.prototype.update=function(){this._order(),this._stack()},a.prototype._order=function(){var t=this.parent.items;if(!t)throw Error("Cannot stack items: parent does not contain items");var e=[],i=0;O.forEach(t,function(t){t.visible&&(e[i]=t,i++)});var n=this.options.order||this.defaultOptions.order;if("function"!=typeof n)throw Error("Option order must be a function");e.sort(n),this.ordered=e},a.prototype._stack=function(){var t,e,i,n=this.ordered,s=this.options,o=s.orientation||this.defaultOptions.orientation,r="top"==o;for(i=s.margin&&void 0!==s.margin.item?s.margin.item:this.defaultOptions.margin.item,t=0,e=n.length;e>t;t++){var a=n[t],h=null;do h=this.checkOverlap(n,t,0,t-1,i),null!=h&&(a.top=r?h.top+h.height+i:h.top-a.height-i);while(h)}},a.prototype.checkOverlap=function(t,e,i,n,s){for(var o=this.collision,r=t[e],a=n;a>=i;a--){var h=t[a];if(o(r,h,s)&&a!=e)return h}return null},a.prototype.collision=function(t,e,i){return t.left-ie.left&&t.top-ie.top},h.prototype.setOptions=function(t){O.extend(this.options,t),(null!=t.start||null!=t.end)&&this.setRange(t.start,t.end)},h.prototype.subscribe=function(t,e,i){var n,s=this;if("horizontal"!=i&&"vertical"!=i)throw new TypeError('Unknown direction "'+i+'". '+'Choose "horizontal" or "vertical".');if("move"==e)n={component:t,event:e,direction:i,callback:function(t){s._onMouseDown(t,n)},params:{}},t.on("mousedown",n.callback),s.listeners.push(n);else{if("zoom"!=e)throw new TypeError('Unknown event "'+e+'". '+'Choose "move" or "zoom".');n={component:t,event:e,direction:i,callback:function(t){s._onMouseWheel(t,n)},params:{}},t.on("mousewheel",n.callback),s.listeners.push(n)}},h.prototype.on=function(t,e){L.addListener(this,t,e)},h.prototype._trigger=function(t){L.trigger(this,t,{start:this.start,end:this.end})},h.prototype.setRange=function(t,e){var i=this._applyRange(t,e);i&&(this._trigger("rangechange"),this._trigger("rangechanged"))},h.prototype._applyRange=function(t,e){var i,n=null!=t?O.convert(t,"Number"):this.start,s=null!=e?O.convert(e,"Number"):this.end;if(isNaN(n))throw Error('Invalid start "'+t+'"');if(isNaN(s))throw Error('Invalid end "'+e+'"');if(n>s&&(s=n),null!=this.options.min){var o=this.options.min.valueOf();o>n&&(i=o-n,n+=i,s+=i)}if(null!=this.options.max){var r=this.options.max.valueOf();s>r&&(i=s-r,n-=i,s-=i)}if(null!=this.options.zoomMin){var a=this.options.zoomMin.valueOf();0>a&&(a=0),a>s-n&&(this.end-this.start>a?(i=a-(s-n),n-=i/2,s+=i/2):(n=this.start,s=this.end))}if(null!=this.options.zoomMax){var h=this.options.zoomMax.valueOf();0>h&&(h=0),s-n>h&&(h>this.end-this.start?(i=s-n-h,n+=i/2,s-=i/2):(n=this.start,s=this.end))}var d=this.start!=n||this.end!=s;return this.start=n,this.end=s,d},h.prototype.getRange=function(){return{start:this.start,end:this.end}},h.prototype.conversion=function(t){return this.start,this.end,h.conversion(this.start,this.end,t)},h.conversion=function(t,e,i){return 0!=i&&0!=e-t?{offset:t,factor:i/(e-t)}:{offset:0,factor:1}},h.prototype._onMouseDown=function(t,e){t=t||window.event;var i=e.params,n=t.which?1==t.which:1==t.button;if(n){i.mouseX=O.getPageX(t),i.mouseY=O.getPageY(t),i.previousLeft=0,i.previousOffset=0,i.moved=!1,i.start=this.start,i.end=this.end;var s=e.component.frame;s&&(s.style.cursor="move");var o=this;i.onMouseMove||(i.onMouseMove=function(t){o._onMouseMove(t,e)},O.addEventListener(document,"mousemove",i.onMouseMove)),i.onMouseUp||(i.onMouseUp=function(t){o._onMouseUp(t,e)},O.addEventListener(document,"mouseup",i.onMouseUp)),O.preventDefault(t)}},h.prototype._onMouseMove=function(t,e){t=t||window.event;var i=e.params,n=O.getPageX(t),s=O.getPageY(t);void 0==i.mouseX&&(i.mouseX=n),void 0==i.mouseY&&(i.mouseY=s);var o=n-i.mouseX,r=s-i.mouseY,a="horizontal"==e.direction?o:r;Math.abs(a)>=1&&(i.moved=!0);var h=i.end-i.start,d="horizontal"==e.direction?e.component.width:e.component.height,l=-a/d*h;this._applyRange(i.start+l,i.end+l),this._trigger("rangechange"),O.preventDefault(t)},h.prototype._onMouseUp=function(t,e){t=t||window.event;var i=e.params;e.component.frame&&(e.component.frame.style.cursor="auto"),i.onMouseMove&&(O.removeEventListener(document,"mousemove",i.onMouseMove),i.onMouseMove=null),i.onMouseUp&&(O.removeEventListener(document,"mouseup",i.onMouseUp),i.onMouseUp=null),i.moved&&this._trigger("rangechanged")},h.prototype._onMouseWheel=function(t,e){t=t||window.event;var i=0;if(t.wheelDelta?i=t.wheelDelta/120:t.detail&&(i=-t.detail/3),i){var n=this,s=function(){var s=i/5,o=null,r=e.component.frame;if(r){var a,h;if("horizontal"==e.direction){a=e.component.width,h=n.conversion(a);var d=O.getAbsoluteLeft(r),l=O.getPageX(t);o=(l-d)/h.factor+h.offset}else{a=e.component.height,h=n.conversion(a);var p=O.getAbsoluteTop(r),c=O.getPageY(t);o=(p+a-c-p)/h.factor+h.offset}}n.zoom(s,o)};s()}O.preventDefault(t)},h.prototype.zoom=function(t,e){null==e&&(e=(this.start+this.end)/2),t>=1&&(t=.9),-1>=t&&(t=-.9),0>t&&(t/=1+t);var i=this.start-e,n=this.end-e,s=this.start-i*t,o=this.end-n*t;this.setRange(s,o)},h.prototype.move=function(t){var e=this.end-this.start,i=this.start+e*t,n=this.end+e*t;this.start=i,this.end=n},h.prototype.moveTo=function(t){var e=(this.start+this.end)/2,i=e-t,n=this.start-i,s=this.end-i;this.setRange(n,s)},d.prototype.add=function(t){if(void 0==t.id)throw Error("Component has no field id");if(!(t instanceof l||t instanceof d))throw new TypeError("Component must be an instance of prototype Component or Controller");t.controller=this,this.components[t.id]=t},d.prototype.remove=function(t){var e;for(e in this.components)if(this.components.hasOwnProperty(e)&&(e==t||this.components[e]==t))break;e&&delete this.components[e]},d.prototype.requestReflow=function(t){if(t)this.reflow();else if(!this.reflowTimer){var e=this;this.reflowTimer=setTimeout(function(){e.reflowTimer=void 0,e.reflow()},0)}},d.prototype.requestRepaint=function(t){if(t)this.repaint();else if(!this.repaintTimer){var e=this;this.repaintTimer=setTimeout(function(){e.repaintTimer=void 0,e.repaint()},0)}},d.prototype.repaint=function(){function t(n,s){s in i||(n.depends&&n.depends.forEach(function(e){t(e,e.id)}),n.parent&&t(n.parent,n.parent.id),e=n.repaint()||e,i[s]=!0)}var e=!1;this.repaintTimer&&(clearTimeout(this.repaintTimer),this.repaintTimer=void 0);var i={};O.forEach(this.components,t),e&&this.reflow()},d.prototype.reflow=function(){function t(n,s){s in i||(n.depends&&n.depends.forEach(function(e){t(e,e.id)}),n.parent&&t(n.parent,n.parent.id),e=n.reflow()||e,i[s]=!0)}var e=!1;this.reflowTimer&&(clearTimeout(this.reflowTimer),this.reflowTimer=void 0);var i={};O.forEach(this.components,t),e&&this.repaint()},l.prototype.setOptions=function(t){t&&(O.extend(this.options,t),this.controller&&(this.requestRepaint(),this.requestReflow()))},l.prototype.getOption=function(t){var e;return this.options&&(e=this.options[t]),void 0===e&&this.defaultOptions&&(e=this.defaultOptions[t]),e},l.prototype.getContainer=function(){return null},l.prototype.getFrame=function(){return this.frame},l.prototype.repaint=function(){return!1},l.prototype.reflow=function(){return!1},l.prototype.hide=function(){return this.frame&&this.frame.parentNode?(this.frame.parentNode.removeChild(this.frame),!0):!1},l.prototype.show=function(){return this.frame&&this.frame.parentNode?!1:this.repaint()},l.prototype.requestRepaint=function(){if(!this.controller)throw Error("Cannot request a repaint: no controller configured");this.controller.requestRepaint()},l.prototype.requestReflow=function(){if(!this.controller)throw Error("Cannot request a reflow: no controller configured");this.controller.requestReflow()},p.prototype=new l,p.prototype.setOptions=l.prototype.setOptions,p.prototype.getContainer=function(){return this.frame},p.prototype.repaint=function(){var t=0,e=O.updateProperty,i=O.option.asSize,n=this.options,s=this.frame;if(!s){s=document.createElement("div"),s.className="panel";var o=n.className;o&&("function"==typeof o?O.addClassName(s,o()+""):O.addClassName(s,o+"")),this.frame=s,t+=1}if(!s.parentNode){if(!this.parent)throw Error("Cannot repaint panel: no parent attached");var r=this.parent.getContainer();if(!r)throw Error("Cannot repaint panel: parent has no container element");r.appendChild(s),t+=1}return t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),t>0},p.prototype.reflow=function(){var t=0,e=O.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},c.prototype=new p,c.prototype.setOptions=l.prototype.setOptions,c.prototype.repaint=function(){var t=0,e=O.updateProperty,i=O.option.asSize,n=this.options,s=this.frame;if(!s){s=document.createElement("div"),s.className="vis timeline rootpanel";var o=n.className;o&&O.addClassName(s,O.option.asString(o)),this.frame=s,t+=1}if(!s.parentNode){if(!this.container)throw Error("Cannot repaint root panel: no container attached");this.container.appendChild(s),t+=1}return t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),this._updateEventEmitters(),this._updateWatch(),t>0},c.prototype.reflow=function(){var t=0,e=O.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},c.prototype._updateWatch=function(){var t=this.getOption("autoResize");t?this._watch():this._unwatch()},c.prototype._watch=function(){var t=this;this._unwatch();var e=function(){var e=t.getOption("autoResize");return e?(t.frame&&(t.frame.clientWidth!=t.width||t.frame.clientHeight!=t.height)&&t.requestReflow(),void 0):(t._unwatch(),void 0)};O.addEventListener(window,"resize",e),this.watchTimer=setInterval(e,1e3)},c.prototype._unwatch=function(){this.watchTimer&&(clearInterval(this.watchTimer),this.watchTimer=void 0)},c.prototype.on=function(t,e){var i=this.listeners[t];i||(i=[],this.listeners[t]=i),i.push(e),this._updateEventEmitters()},c.prototype._updateEventEmitters=function(){if(this.listeners){var t=this;O.forEach(this.listeners,function(e,i){if(t.emitters||(t.emitters={}),!(i in t.emitters)){var n=t.frame;if(n){var s=function(t){e.forEach(function(e){e(t)})};t.emitters[i]=s,O.addEventListener(n,i,s)}}})}},u.prototype=new l,u.prototype.setOptions=l.prototype.setOptions,u.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},u.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.factor+e.offset)},u.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.factor},u.prototype.repaint=function(){var t=0,e=O.updateProperty,i=O.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.props,r=this.step,a=this.frame;if(a||(a=document.createElement("div"),this.frame=a,t+=1),a.className="axis "+s,!a.parentNode){if(!this.parent)throw Error("Cannot repaint time axis: no parent attached");var h=this.parent.getContainer();if(!h)throw Error("Cannot repaint time axis: parent has no container element");h.appendChild(a),t+=1}var d=a.parentNode;if(d){var l=a.nextSibling;d.removeChild(a);var p="bottom"==s&&this.props.parentHeight&&this.height?this.props.parentHeight-this.height+"px":"0px";if(t+=e(a.style,"top",i(n.top,p)),t+=e(a.style,"left",i(n.left,"0px")),t+=e(a.style,"width",i(n.width,"100%")),t+=e(a.style,"height",i(n.height,this.height+"px")),this._repaintMeasureChars(),this.step){this._repaintStart(),r.first();for(var c=void 0,u=0;r.hasNext()&&1e3>u;){u++;var f=r.getCurrent(),m=this.toScreen(f),g=r.isMajor();this.getOption("showMinorLabels")&&this._repaintMinorText(m,r.getLabelMinor()),g&&this.getOption("showMajorLabels")?(m>0&&(void 0==c&&(c=m),this._repaintMajorText(m,r.getLabelMajor())),this._repaintMajorLine(m)):this._repaintMinorLine(m),r.next()}if(this.getOption("showMajorLabels")){var v=this.toTime(0),y=r.getLabelMajor(v),b=y.length*(o.majorCharWidth||10)+10;(void 0==c||c>b)&&this._repaintMajorText(0,y)}this._repaintEnd()}this._repaintLine(),l?d.insertBefore(a,l):d.appendChild(a)}return t>0},u.prototype._repaintStart=function(){var t=this.dom,e=t.redundant;e.majorLines=t.majorLines,e.majorTexts=t.majorTexts,e.minorLines=t.minorLines,e.minorTexts=t.minorTexts,t.majorLines=[],t.majorTexts=[],t.minorLines=[],t.minorTexts=[]},u.prototype._repaintEnd=function(){O.forEach(this.dom.redundant,function(t){for(;t.length;){var e=t.pop();e&&e.parentNode&&e.parentNode.removeChild(e)}})},u.prototype._repaintMinorText=function(t,e){var i=this.dom.redundant.minorTexts.shift();if(!i){var n=document.createTextNode("");i=document.createElement("div"),i.appendChild(n),i.className="text minor",this.frame.appendChild(i)}this.dom.minorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.left=t+"px",i.style.top=this.props.minorLabelTop+"px"},u.prototype._repaintMajorText=function(t,e){var i=this.dom.redundant.majorTexts.shift();if(!i){var n=document.createTextNode(e);i=document.createElement("div"),i.className="text major",i.appendChild(n),this.frame.appendChild(i)}this.dom.majorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.top=this.props.majorLabelTop+"px",i.style.left=t+"px"},u.prototype._repaintMinorLine=function(t){var e=this.dom.redundant.minorLines.shift();e||(e=document.createElement("div"),e.className="grid vertical minor",this.frame.appendChild(e)),this.dom.minorLines.push(e);var i=this.props;e.style.top=i.minorLineTop+"px",e.style.height=i.minorLineHeight+"px",e.style.left=t-i.minorLineWidth/2+"px"},u.prototype._repaintMajorLine=function(t){var e=this.dom.redundant.majorLines.shift();e||(e=document.createElement("DIV"),e.className="grid vertical major",this.frame.appendChild(e)),this.dom.majorLines.push(e);var i=this.props;e.style.top=i.majorLineTop+"px",e.style.left=t-i.majorLineWidth/2+"px",e.style.height=i.majorLineHeight+"px"},u.prototype._repaintLine=function(){var t=this.dom.line,e=this.frame;this.options,this.getOption("showMinorLabels")||this.getOption("showMajorLabels")?(t?(e.removeChild(t),e.appendChild(t)):(t=document.createElement("div"),t.className="grid horizontal major",e.appendChild(t),this.dom.line=t),t.style.top=this.props.lineTop+"px"):t&&axis.parentElement&&(e.removeChild(axis.line),delete this.dom.line)},u.prototype._repaintMeasureChars=function(){var t,e=this.dom;if(!e.measureCharMinor){t=document.createTextNode("0");var i=document.createElement("DIV");i.className="text minor measure",i.appendChild(t),this.frame.appendChild(i),e.measureCharMinor=i}if(!e.measureCharMajor){t=document.createTextNode("0");var n=document.createElement("DIV");n.className="text major measure",n.appendChild(t),this.frame.appendChild(n),e.measureCharMajor=n}},u.prototype.reflow=function(){var t=0,e=O.updateProperty,i=this.frame,n=this.range;if(!n)throw Error("Cannot repaint time axis: no range configured");if(i){t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft);var s=this.props,o=this.getOption("showMinorLabels"),r=this.getOption("showMajorLabels"),a=this.dom.measureCharMinor,h=this.dom.measureCharMajor;a&&(s.minorCharHeight=a.clientHeight,s.minorCharWidth=a.clientWidth),h&&(s.majorCharHeight=h.clientHeight,s.majorCharWidth=h.clientWidth);var d=i.parentNode?i.parentNode.offsetHeight:0;switch(d!=s.parentHeight&&(s.parentHeight=d,t+=1),this.getOption("orientation")){case"bottom":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.minorLabelTop=0,s.majorLabelTop=s.minorLabelTop+s.minorLabelHeight,s.minorLineTop=-this.top,s.minorLineHeight=Math.max(this.top+s.majorLabelHeight,0),s.minorLineWidth=1,s.majorLineTop=-this.top,s.majorLineHeight=Math.max(this.top+s.minorLabelHeight+s.majorLabelHeight,0),s.majorLineWidth=1,s.lineTop=0;break;case"top":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.majorLabelTop=0,s.minorLabelTop=s.majorLabelTop+s.majorLabelHeight,s.minorLineTop=s.minorLabelTop,s.minorLineHeight=Math.max(d-s.majorLabelHeight-this.top),s.minorLineWidth=1,s.majorLineTop=0,s.majorLineHeight=Math.max(d-this.top),s.majorLineWidth=1,s.lineTop=s.majorLabelHeight+s.minorLabelHeight;break;default:throw Error('Unkown orientation "'+this.getOption("orientation")+'"')}var l=s.minorLabelHeight+s.majorLabelHeight;t+=e(this,"width",i.offsetWidth),t+=e(this,"height",l),this._updateConversion();var p=O.convert(n.start,"Date"),c=O.convert(n.end,"Date"),u=this.toTime(5*(s.minorCharWidth||10))-this.toTime(0);this.step=new TimeStep(p,c,u),t+=e(s.range,"start",p.valueOf()),t+=e(s.range,"end",c.valueOf()),t+=e(s.range,"minimumStep",u.valueOf())}return t>0},u.prototype._updateConversion=function(){var t=this.range;if(!t)throw Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},f.prototype=new p,f.types={box:g,range:y,point:v},f.prototype.setOptions=l.prototype.setOptions,f.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},f.prototype.repaint=function(){var t=0,e=O.updateProperty,i=O.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.defaultOptions,r=this.frame;if(!r){r=document.createElement("div"),r.className="itemset";var a=n.className;a&&O.addClassName(r,O.option.asString(a));var h=document.createElement("div");h.className="background",r.appendChild(h),this.dom.background=h;var d=document.createElement("div");d.className="foreground",r.appendChild(d),this.dom.foreground=d;var l=document.createElement("div");l.className="itemset-axis",this.dom.axis=l,this.frame=r,t+=1}if(!this.parent)throw Error("Cannot repaint itemset: no parent attached");var p=this.parent.getContainer();if(!p)throw Error("Cannot repaint itemset: parent has no container element");r.parentNode||(p.appendChild(r),t+=1),this.dom.axis.parentNode||(p.appendChild(this.dom.axis),t+=1),t+=e(r.style,"left",i(n.left,"0px")),t+=e(r.style,"top",i(n.top,"0px")),t+=e(r.style,"width",i(n.width,"100%")),t+=e(r.style,"height",i(n.height,this.height+"px")),t+=e(this.dom.axis.style,"left",i(n.left,"0px")),t+=e(this.dom.axis.style,"width",i(n.width,"100%")),t+="bottom"==s?e(this.dom.axis.style,"top",this.height+this.top+"px"):e(this.dom.axis.style,"top",this.top+"px"),this._updateConversion();var c=this,u=this.queue,m=this.itemsData,g=this.items,v={};return Object.keys(u).forEach(function(e){var i=u[e],s=g[e];switch(i){case"add":case"update":var r=m&&m.get(e,v);if(r){var a=r.type||r.start&&r.end&&"range"||n.type||"box",h=f.types[a];if(s&&(h&&s instanceof h?(s.data=r,t++):(t+=s.hide(),s=null)),!s){if(!h)throw new TypeError('Unknown item type "'+a+'"');s=new h(c,r,n,o),t++}s.repaint(),g[e]=s}delete u[e];break;case"remove":s&&(t+=s.hide()),delete g[e],delete u[e];break;default:console.log('Error: unknown action "'+i+'"')}}),O.forEach(this.items,function(e){e.visible?(t+=e.show(),e.reposition()):t+=e.hide()}),t>0},f.prototype.getForeground=function(){return this.dom.foreground},f.prototype.getBackground=function(){return this.dom.background},f.prototype.getAxis=function(){return this.dom.axis},f.prototype.reflow=function(){var t=0,e=this.options,i=e.margin&&e.margin.axis||this.defaultOptions.margin.axis,n=e.margin&&e.margin.item||this.defaultOptions.margin.item,s=O.updateProperty,o=O.option.asNumber,r=O.option.asSize,a=this.frame;if(a){this._updateConversion(),O.forEach(this.items,function(e){t+=e.reflow()}),this.stack.update();var h,d=o(e.maxHeight),l=null!=r(e.height);if(l)h=a.offsetHeight;else{var p=this.stack.ordered;if(p.length){var c=p[0].top,u=p[0].top+p[0].height;O.forEach(p,function(t){c=Math.min(c,t.top),u=Math.max(u,t.top+t.height)}),h=u-c+i+n}else h=i+n}null!=d&&(h=Math.min(h,d)),t+=s(this,"height",h),t+=s(this,"top",a.offsetTop),t+=s(this,"left",a.offsetLeft),t+=s(this,"width",a.offsetWidth)}else t+=1;return t>0},f.prototype.hide=function(){var t=!1;return this.frame&&this.frame.parentNode&&(this.frame.parentNode.removeChild(this.frame),t=!0),this.dom.axis&&this.dom.axis.parentNode&&(this.dom.axis.parentNode.removeChild(this.dom.axis),t=!0),t},f.prototype.setItems=function(t){var e,i=this,n=this.itemsData;if(t){if(!(t instanceof o||t instanceof r))throw new TypeError("Data must be an instance of DataSet");this.itemsData=t}else this.itemsData=null;if(n&&(O.forEach(this.listeners,function(t,e){n.unsubscribe(e,t)}),e=n.getIds(),this._onRemove(e)),this.itemsData){var s=this.id;O.forEach(this.listeners,function(t,e){i.itemsData.subscribe(e,t,s)}),e=this.itemsData.getIds(),this._onAdd(e)}},f.prototype.getItems=function(){return this.itemsData},f.prototype._onUpdate=function(t){this._toQueue("update",t)},f.prototype._onAdd=function(t){this._toQueue("add",t)},f.prototype._onRemove=function(t){this._toQueue("remove",t)},f.prototype._toQueue=function(t,e){var i=this.queue;e.forEach(function(e){i[e]=t}),this.controller&&this.requestRepaint()},f.prototype._updateConversion=function(){var t=this.range;if(!t)throw Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},f.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.factor+e.offset)},f.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.factor},m.prototype.select=function(){this.selected=!0},m.prototype.unselect=function(){this.selected=!1},m.prototype.show=function(){return!1},m.prototype.hide=function(){return!1},m.prototype.repaint=function(){return!1},m.prototype.reflow=function(){return!1},g.prototype=new m(null,null),g.prototype.select=function(){this.selected=!0},g.prototype.unselect=function(){this.selected=!1},g.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw Error("Cannot repaint time axis: parent has no foreground container element");var n=this.parent.getBackground();if(!n)throw Error("Cannot repaint time axis: parent has no background container element");var s=this.parent.getAxis();if(!n)throw Error("Cannot repaint time axis: parent has no axis container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),e.line.parentNode||(n.appendChild(e.line),t=!0),e.dot.parentNode||(s.appendChild(e.dot),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var o=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=o&&(this.className=o,e.box.className="item box"+o,e.line.className="item line"+o,e.dot.className="item dot"+o,t=!0)}return t},g.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},g.prototype.hide=function(){var t=!1,e=this.dom;return e&&(e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),e.line.parentNode&&e.line.parentNode.removeChild(e.line),e.dot.parentNode&&e.dot.parentNode.removeChild(e.dot)),t},g.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,d,l,p,c=0;if(void 0==this.data.start)throw Error('Property "start" missing in item '+this.data.id);if(l=this.data,p=this.parent&&this.parent.range,l&&p){var u=p.end-p.start;this.visible=l.start>p.start-u&&l.start0},g.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("DIV"),t.content=document.createElement("DIV"),t.content.className="content",t.box.appendChild(t.content),t.line=document.createElement("DIV"),t.line.className="line",t.dot=document.createElement("DIV"),t.dot.className="dot")},g.prototype.reposition=function(){var t=this.dom,e=this.props,i=this.options.orientation||this.defaultOptions.orientation;if(t){var n=t.box,s=t.line,o=t.dot;n.style.left=this.left+"px",n.style.top=this.top+"px",s.style.left=e.line.left+"px","top"==i?(s.style.top="0px",s.style.height=this.top+"px"):(s.style.top=this.top+this.height+"px",s.style.height=Math.max(this.parent.height-this.top-this.height+this.props.dot.height/2,0)+"px"),o.style.left=e.dot.left+"px",o.style.top=e.dot.top+"px"}},v.prototype=new m(null,null),v.prototype.select=function(){this.selected=!0},v.prototype.unselect=function(){this.selected=!1},v.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw Error("Cannot repaint time axis: parent has no foreground container element");if(e.point.parentNode||(i.appendChild(e.point),i.appendChild(e.point),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.point.className="item point"+n,t=!0)}return t},v.prototype.show=function(){return this.dom&&this.dom.point.parentNode?!1:this.repaint()},v.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.point.parentNode&&(e.point.parentNode.removeChild(e.point),t=!0),t},v.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,d,l=0;if(void 0==this.data.start)throw Error('Property "start" missing in item '+this.data.id);if(h=this.data,d=this.parent&&this.parent.range,h&&d){var p=d.end-d.start;this.visible=h.start>d.start-p&&h.start0},v.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.point=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.point.appendChild(t.content),t.dot=document.createElement("div"),t.dot.className="dot",t.point.appendChild(t.dot))},v.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.point.style.top=this.top+"px",t.point.style.left=this.left+"px",t.content.style.marginLeft=e.content.marginLeft+"px",t.dot.style.top=e.dot.top+"px")},y.prototype=new m(null,null),y.prototype.select=function(){this.selected=!0},y.prototype.unselect=function(){this.selected=!1},y.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw Error('Property "content" missing in item '+this.data.id); -e.content.innerHTML=this.content}t=!0}var n=this.data.className?" "+this.data.className:"";this.className!=n&&(this.className=n,e.box.className="item range"+n,t=!0)}return t},y.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},y.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),t},y.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,d,l,p,c,u,f,m,g=0;if(void 0==this.data.start)throw Error('Property "start" missing in item '+this.data.id);if(void 0==this.data.end)throw Error('Property "end" missing in item '+this.data.id);return h=this.data,d=this.parent&&this.parent.range,this.visible=h&&d?h.startd.start:!1,this.visible&&(t=this.dom,t?(e=this.props,i=this.options,o=this.parent,r=o.toScreen(this.data.start),a=o.toScreen(this.data.end),l=O.updateProperty,p=t.box,c=o.width,f=i.orientation||this.defaultOptions.orientation,n=i.margin&&i.margin.axis||this.defaultOptions.margin.axis,s=i.padding||this.defaultOptions.padding,g+=l(e.content,"width",t.content.offsetWidth),g+=l(this,"height",p.offsetHeight),-c>r&&(r=-c),a>2*c&&(a=2*c),u=0>r?Math.min(-r,a-r-e.content.width-2*s):0,g+=l(e.content,"left",u),"top"==f?(m=n,g+=l(this,"top",m)):(m=o.height-this.height-n,g+=l(this,"top",m)),g+=l(this,"left",r),g+=l(this,"width",Math.max(a-r,1))):g+=1),g>0},y.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content))},y.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.box.style.top=this.top+"px",t.box.style.left=this.left+"px",t.box.style.width=this.width+"px",t.content.style.left=e.content.left+"px")},b.prototype=new l,b.prototype.setOptions=l.prototype.setOptions,b.prototype.getContainer=function(){return this.parent.getContainer()},b.prototype.setItems=function(t){if(this.itemset&&(this.itemset.hide(),this.itemset.setItems(),this.parent.controller.remove(this.itemset),this.itemset=null),t){var e=this.groupId,i=Object.create(this.options);this.itemset=new f(this,null,i),this.itemset.setRange(this.parent.range),this.view=new r(t,{filter:function(t){return t.group==e}}),this.itemset.setItems(this.view),this.parent.controller.add(this.itemset)}},b.prototype.repaint=function(){return!1},b.prototype.reflow=function(){var t=0,e=O.updateProperty;if(t+=e(this,"top",this.itemset?this.itemset.top:0),t+=e(this,"height",this.itemset?this.itemset.height:0),this.label){var i=this.label.firstChild;t+=e(this.props.label,"width",i.clientWidth),t+=e(this.props.label,"height",i.clientHeight)}else t+=e(this.props.label,"width",0),t+=e(this.props.label,"height",0);return t>0},w.prototype=new p,w.prototype.setOptions=l.prototype.setOptions,w.prototype.setRange=function(){},w.prototype.setItems=function(t){this.itemsData=t;for(var e in this.groups)if(this.groups.hasOwnProperty(e)){var i=this.groups[e];i.setItems(t)}},w.prototype.getItems=function(){return this.itemsData},w.prototype.setRange=function(t){this.range=t},w.prototype.setGroups=function(t){var e,i=this;if(this.groupsData&&(O.forEach(this.listeners,function(t,e){i.groupsData.unsubscribe(e,t)}),e=this.groupsData.getIds(),this._onRemove(e)),t?t instanceof o?this.groupsData=t:(this.groupsData=new o({convert:{start:"Date",end:"Date"}}),this.groupsData.add(t)):this.groupsData=null,this.groupsData){var n=this.id;O.forEach(this.listeners,function(t,e){i.groupsData.subscribe(e,t,n)}),e=this.groupsData.getIds(),this._onAdd(e)}},w.prototype.getGroups=function(){return this.groupsData},w.prototype.repaint=function(){var t,e,i,n,s=0,o=O.updateProperty,r=O.option.asSize,a=O.option.asElement,h=this.options,d=this.dom.frame,l=this.dom.labels;if(!this.parent)throw Error("Cannot repaint groupset: no parent attached");var p=this.parent.getContainer();if(!p)throw Error("Cannot repaint groupset: parent has no container element");if(!d){d=document.createElement("div"),d.className="groupset",this.dom.frame=d;var c=h.className;c&&O.addClassName(d,O.option.asString(c)),s+=1}d.parentNode||(p.appendChild(d),s+=1);var u=a(h.labelContainer);if(!u)throw Error('Cannot repaint groupset: option "labelContainer" not defined');l||(l=document.createElement("div"),l.className="labels",this.dom.labels=l),l.parentNode&&l.parentNode==u||(l.parentNode&&l.parentNode.removeChild(l.parentNode),u.appendChild(l)),s+=o(d.style,"height",r(h.height,this.height+"px")),s+=o(d.style,"top",r(h.top,"0px")),s+=o(d.style,"left",r(h.left,"0px")),s+=o(d.style,"width",r(h.width,"100%")),s+=o(l.style,"top",r(h.top,"0px"));var f=this,m=this.queue,g=this.groups,v=this.groupsData,y=Object.keys(m);if(y.length){y.forEach(function(t){var e=m[t],i=g[t];switch(e){case"add":case"update":if(!i){var n=Object.create(f.options);i=new b(f,t,n),i.setItems(f.itemsData),g[t]=i,f.controller.add(i)}i.data=v.get(t),delete m[t];break;case"remove":i&&(i.setItems(),delete g[t],f.controller.remove(i)),delete m[t];break;default:console.log('Error: unknown action "'+e+'"')}});var w=this.groupsData.getIds({order:this.options.groupsOrder});for(t=0;w.length>t;t++)(function(t,e){var i=0;e&&(i=function(){return e.top+e.height}),t.setOptions({top:i})})(g[w[t]],g[w[t-1]]);for(;l.firstChild;)l.removeChild(l.firstChild);for(t=0;w.length>t;t++)e=w[t],n=this._createLabel(e),l.appendChild(n);s++}for(e in g)g.hasOwnProperty(e)&&(i=g[e],n=i.label,n&&(n.style.top=i.top+"px",n.style.height=i.height+"px"));return s>0},w.prototype._createLabel=function(t){var e=this.groups[t],i=document.createElement("div");i.className="label";var n=document.createElement("div");n.className="inner",i.appendChild(n);var s=e.data&&e.data.content;s instanceof Element?n.appendChild(s):void 0!=s&&(n.innerHTML=s);var o=e.data&&e.data.className;return o&&O.addClassName(i,o),e.label=i,i},w.prototype.getContainer=function(){return this.dom.frame},w.prototype.getLabelsWidth=function(){return this.props.labels.width},w.prototype.reflow=function(){var t,e,i=0,n=this.options,s=O.updateProperty,o=O.option.asNumber,r=O.option.asSize,a=this.dom.frame;if(a){var h,d=o(n.maxHeight),l=null!=r(n.height);if(l)h=a.offsetHeight;else{h=0;for(t in this.groups)this.groups.hasOwnProperty(t)&&(e=this.groups[t],h+=e.height)}null!=d&&(h=Math.min(h,d)),i+=s(this,"height",h),i+=s(this,"top",a.offsetTop),i+=s(this,"left",a.offsetLeft),i+=s(this,"width",a.offsetWidth)}var p=0;for(t in this.groups)if(this.groups.hasOwnProperty(t)){e=this.groups[t];var c=e.props&&e.props.label&&e.props.label.width||0;p=Math.max(p,c)}return i+=s(this.props.labels,"width",p),i>0},w.prototype.hide=function(){return this.dom.frame&&this.dom.frame.parentNode?(this.dom.frame.parentNode.removeChild(this.dom.frame),!0):!1},w.prototype.show=function(){return this.dom.frame&&this.dom.frame.parentNode?!1:this.repaint()},w.prototype._onUpdate=function(t){this._toQueue(t,"update")},w.prototype._onAdd=function(t){this._toQueue(t,"add")},w.prototype._onRemove=function(t){this._toQueue(t,"remove")},w.prototype._toQueue=function(t,e){var i=this.queue;t.forEach(function(t){i[t]=e}),this.controller&&this.requestRepaint()},_.prototype.setOptions=function(t){t&&O.extend(this.options,t),this.controller.reflow(),this.controller.repaint()},_.prototype.setItems=function(t){var e,i=null==this.itemsData;if(t?t instanceof o&&(e=t):e=null,t instanceof o||(e=new o({convert:{start:"Date",end:"Date"}}),e.add(t)),this.itemsData=e,this.content.setItems(e),i&&(void 0==this.options.start||void 0==this.options.end)){var n=this.getItemRange(),s=n.min,r=n.max;if(null!=s&&null!=r){var a=r.valueOf()-s.valueOf();0>=a&&(a=864e5),s=new Date(s.valueOf()-.05*a),r=new Date(r.valueOf()+.05*a)}void 0!=this.options.start&&(s=new Date(this.options.start.valueOf())),void 0!=this.options.end&&(r=new Date(this.options.end.valueOf())),(null!=s||null!=r)&&this.range.setRange(s,r)}},_.prototype.setGroups=function(t){var e=this;this.groupsData=t;var i=this.groupsData?w:f;if(!(this.content instanceof i)){this.content&&(this.content.hide(),this.content.setItems&&this.content.setItems(),this.content.setGroups&&this.content.setGroups(),this.controller.remove(this.content));var n=Object.create(this.options);O.extend(n,{top:function(){return"top"==e.options.orientation?e.timeaxis.height:e.itemPanel.height-e.timeaxis.height-e.content.height},left:null,width:"100%",height:function(){return e.options.height?e.itemPanel.height-e.timeaxis.height:null},maxHeight:function(){if(e.options.maxHeight){if(!O.isNumber(e.options.maxHeight))throw new TypeError("Number expected for property maxHeight");return e.options.maxHeight-e.timeaxis.height}return null},labelContainer:function(){return e.labelPanel.getContainer()}}),this.content=new i(this.itemPanel,[this.timeaxis],n),this.content.setRange&&this.content.setRange(this.range),this.content.setItems&&this.content.setItems(this.itemsData),this.content.setGroups&&this.content.setGroups(this.groupsData),this.controller.add(this.content)}},_.prototype.getItemRange=function(){var t=this.itemsData,e=null,i=null;if(t){var n=t.min("start");e=n?n.start.valueOf():null;var s=t.max("start");s&&(i=s.start.valueOf());var o=t.max("end");o&&(i=null==i?o.end.valueOf():Math.max(i,o.end.valueOf()))}return{min:null!=e?new Date(e):null,max:null!=i?new Date(i):null}},function(t){function e(t){return M=t,c()}function i(){D=0,C=M.charAt(0)}function n(){D++,C=M.charAt(D)}function s(){return M.charAt(D+1)}function o(t){return L.test(t)}function r(t,e){if(t||(t={}),e)for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function a(t,e,i){for(var n=e.split("."),s=t;n.length;){var o=n.shift();n.length?(s[o]||(s[o]={}),s=s[o]):s[o]=i}}function h(t,e){for(var i,n,s=null,o=[t],a=t;a.parent;)o.push(a.parent),a=a.parent;if(a.nodes)for(i=0,n=a.nodes.length;n>i;i++)if(e.id===a.nodes[i].id){s=a.nodes[i];break}for(s||(s={id:e.id},t.node&&(s.attr=r(s.attr,t.node))),i=o.length-1;i>=0;i--){var h=o[i];h.nodes||(h.nodes=[]),-1==h.nodes.indexOf(s)&&h.nodes.push(s)}e.attr&&(s.attr=r(s.attr,e.attr))}function d(t,e){if(t.edges||(t.edges=[]),t.edges.push(e),t.edge){var i=r({},t.edge);e.attr=r(i,e.attr)}}function l(t,e,i,n,s){var o={from:e,to:i,type:n};return t.edge&&(o.attr=r({},t.edge)),o.attr=r(o.attr||{},s),o}function p(){for(N=x.NULL,O="";" "==C||" "==C||"\n"==C||"\r"==C;)n();do{var t=!1;if("#"==C){for(var e=D-1;" "==M.charAt(e)||" "==M.charAt(e);)e--;if("\n"==M.charAt(e)||""==M.charAt(e)){for(;""!=C&&"\n"!=C;)n();t=!0}}if("/"==C&&"/"==s()){for(;""!=C&&"\n"!=C;)n();t=!0}if("/"==C&&"*"==s()){for(;""!=C;){if("*"==C&&"/"==s()){n(),n();break}n()}t=!0}for(;" "==C||" "==C||"\n"==C||"\r"==C;)n()}while(t);if(""==C)return N=x.DELIMITER,void 0;var i=C+s();if(S[i])return N=x.DELIMITER,O=i,n(),n(),void 0;if(S[C])return N=x.DELIMITER,O=C,n(),void 0;if(o(C)||"-"==C){for(O+=C,n();o(C);)O+=C,n();return"false"==O?O=!1:"true"==O?O=!0:isNaN(Number(O))||(O=Number(O)),N=x.IDENTIFIER,void 0}if('"'==C){for(n();""!=C&&('"'!=C||'"'==C&&'"'==s());)O+=C,'"'==C&&n(),n();if('"'!=C)throw w('End of string " expected');return n(),N=x.IDENTIFIER,void 0}for(N=x.UNKNOWN;""!=C;)O+=C,n();throw new SyntaxError('Syntax error in part "'+_(O,30)+'"')}function c(){var t={};if(i(),p(),"strict"==O&&(t.strict=!0,p()),("graph"==O||"digraph"==O)&&(t.type=O,p()),N==x.IDENTIFIER&&(t.id=O,p()),"{"!=O)throw w("Angle bracket { expected");if(p(),u(t),"}"!=O)throw w("Angle bracket } expected");if(p(),""!==O)throw w("End of file expected");return p(),delete t.node,delete t.edge,delete t.graph,t}function u(t){for(;""!==O&&"}"!=O;)f(t),";"==O&&p()}function f(t){var e=m(t);if(e)return y(t,e),void 0;var i=g(t);if(!i){if(N!=x.IDENTIFIER)throw w("Identifier expected");var n=O;if(p(),"="==O){if(p(),N!=x.IDENTIFIER)throw w("Identifier expected");t[n]=O,p()}else v(t,n)}}function m(t){var e=null;if("subgraph"==O&&(e={},e.type="subgraph",p(),N==x.IDENTIFIER&&(e.id=O,p())),"{"==O){if(p(),e||(e={}),e.parent=t,e.node=t.node,e.edge=t.edge,e.graph=t.graph,u(e),"}"!=O)throw w("Angle bracket } expected");p(),delete e.node,delete e.edge,delete e.graph,delete e.parent,t.subgraphs||(t.subgraphs=[]),t.subgraphs.push(e)}return e}function g(t){return"node"==O?(p(),t.node=b(),"node"):"edge"==O?(p(),t.edge=b(),"edge"):"graph"==O?(p(),t.graph=b(),"graph"):null}function v(t,e){var i={id:e},n=b();n&&(i.attr=n),h(t,i),y(t,e)}function y(t,e){for(;"->"==O||"--"==O;){var i,n=O;p();var s=m(t);if(s)i=s;else{if(N!=x.IDENTIFIER)throw w("Identifier or subgraph expected");i=O,h(t,{id:i}),p()}var o=b(),r=l(t,e,i,n,o);d(t,r),e=i}}function b(){for(var t=null;"["==O;){for(p(),t={};""!==O&&"]"!=O;){if(N!=x.IDENTIFIER)throw w("Attribute name expected");var e=O;if(p(),"="!=O)throw w("Equal sign = expected");if(p(),N!=x.IDENTIFIER)throw w("Attribute value expected");var i=O;a(t,e,i),p(),","==O&&p()}if("]"!=O)throw w("Bracket ] expected");p()}return t}function w(t){return new SyntaxError(t+', got "'+_(O,30)+'" (char '+D+")")}function _(t,e){return e>=t.length?t:t.substr(0,27)+"..."}function E(t,e,i){t instanceof Array?t.forEach(function(t){e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}):e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}function T(t){function i(t){var e={from:t.from,to:t.to};return r(e,t.attr),e.style="->"==t.type?"arrow":"line",e}var n=e(t),s={nodes:[],edges:[],options:{}};return n.nodes&&n.nodes.forEach(function(t){var e={id:t.id,label:(t.label||t.id)+""};r(e,t.attr),e.image&&(e.shape="image"),s.nodes.push(e)}),n.edges&&n.edges.forEach(function(t){var e,n;e=t.from instanceof Object?t.from.nodes:{id:t.from},n=t.to instanceof Object?t.to.nodes:{id:t.to},t.from instanceof Object&&t.from.edges&&t.from.edges.forEach(function(t){var e=i(t);s.edges.push(e)}),E(e,n,function(e,n){var o=l(s,e.id,n.id,t.type,t.attr),r=i(o);s.edges.push(r)}),t.to instanceof Object&&t.to.edges&&t.to.edges.forEach(function(t){var e=i(t);s.edges.push(e)})}),n.attr&&(s.options=n.attr),s}var x={NULL:0,DELIMITER:1,IDENTIFIER:2,UNKNOWN:3},S={"{":!0,"}":!0,"[":!0,"]":!0,";":!0,"=":!0,",":!0,"->":!0,"--":!0},M="",D=0,C="",O="",N=x.NULL,L=/[a-zA-Z_0-9.:#]/;t.parseDOT=e,t.DOTToGraph=T}(O!==void 0?O:n),"undefined"!=typeof CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.circle=function(t,e,i){this.beginPath(),this.arc(t,e,i,0,2*Math.PI,!1)},CanvasRenderingContext2D.prototype.square=function(t,e,i){this.beginPath(),this.rect(t-i,e-i,2*i,2*i)},CanvasRenderingContext2D.prototype.triangle=function(t,e,i){this.beginPath();var n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e-(r-o)),this.lineTo(t+s,e+o),this.lineTo(t-s,e+o),this.lineTo(t,e-(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.triangleDown=function(t,e,i){this.beginPath();var n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e+(r-o)),this.lineTo(t+s,e-o),this.lineTo(t-s,e-o),this.lineTo(t,e+(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.star=function(t,e,i){this.beginPath();for(var n=0;10>n;n++){var s=0===n%2?1.3*i:.5*i;this.lineTo(t+s*Math.sin(2*n*Math.PI/10),e-s*Math.cos(2*n*Math.PI/10))}this.closePath()},CanvasRenderingContext2D.prototype.roundRect=function(t,e,i,n,s){var o=Math.PI/180;0>i-2*s&&(s=i/2),0>n-2*s&&(s=n/2),this.beginPath(),this.moveTo(t+s,e),this.lineTo(t+i-s,e),this.arc(t+i-s,e+s,s,270*o,360*o,!1),this.lineTo(t+i,e+n-s),this.arc(t+i-s,e+n-s,s,0,90*o,!1),this.lineTo(t+s,e+n),this.arc(t+s,e+n-s,s,90*o,180*o,!1),this.lineTo(t,e+s),this.arc(t+s,e+s,s,180*o,270*o,!1)},CanvasRenderingContext2D.prototype.ellipse=function(t,e,i,n){var s=.5522848,o=i/2*s,r=n/2*s,a=t+i,h=e+n,d=t+i/2,l=e+n/2;this.beginPath(),this.moveTo(t,l),this.bezierCurveTo(t,l-r,d-o,e,d,e),this.bezierCurveTo(d+o,e,a,l-r,a,l),this.bezierCurveTo(a,l+r,d+o,h,d,h),this.bezierCurveTo(d-o,h,t,l+r,t,l)},CanvasRenderingContext2D.prototype.database=function(t,e,i,n){var s=1/3,o=i,r=n*s,a=.5522848,h=o/2*a,d=r/2*a,l=t+o,p=e+r,c=t+o/2,u=e+r/2,f=e+(n-r/2),m=e+n;this.beginPath(),this.moveTo(l,u),this.bezierCurveTo(l,u+d,c+h,p,c,p),this.bezierCurveTo(c-h,p,t,u+d,t,u),this.bezierCurveTo(t,u-d,c-h,e,c,e),this.bezierCurveTo(c+h,e,l,u-d,l,u),this.lineTo(l,f),this.bezierCurveTo(l,f+d,c+h,m,c,m),this.bezierCurveTo(c-h,m,t,f+d,t,f),this.lineTo(t,u)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,n){var s=t-n*Math.cos(i),o=e-n*Math.sin(i),r=t-.9*n*Math.cos(i),a=e-.9*n*Math.sin(i),h=s+n/3*Math.cos(i+.5*Math.PI),d=o+n/3*Math.sin(i+.5*Math.PI),l=s+n/3*Math.cos(i-.5*Math.PI),p=o+n/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,d),this.lineTo(r,a),this.lineTo(l,p),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,n,s){s||(s=[10,5]),0==c&&(c=.001);var o=s.length;this.moveTo(t,e);for(var r=i-t,a=n-e,h=a/r,d=Math.sqrt(r*r+a*a),l=0,p=!0;d>=.1;){var c=s[l++%o];c>d&&(c=d);var u=Math.sqrt(c*c/(1+h*h));0>r&&(u=-u),t+=u,e+=h*u,this[p?"lineTo":"moveTo"](t,e),d-=c,p=!p}}),E.prototype.attachEdge=function(t){-1==this.edges.indexOf(t)&&this.edges.push(t),this._updateMass()},E.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&this.edges.splice(e,1),this._updateMass()},E.prototype._updateMass=function(){this.mass=50+20*this.edges.length},E.prototype.setProperties=function(t,e){if(t){if(void 0!=t.id&&(this.id=t.id),void 0!=t.label&&(this.label=t.label),void 0!=t.title&&(this.title=t.title),void 0!=t.group&&(this.group=t.group),void 0!=t.x&&(this.x=t.x),void 0!=t.y&&(this.y=t.y),void 0!=t.value&&(this.value=t.value),void 0===this.id)throw"Node must have an id";if(this.group){var i=this.grouplist.get(this.group);for(var n in i)i.hasOwnProperty(n)&&(this[n]=i[n])}if(void 0!=t.shape&&(this.shape=t.shape),void 0!=t.image&&(this.image=t.image),void 0!=t.radius&&(this.radius=t.radius),void 0!=t.color&&(this.color=E.parseColor(t.color)),void 0!=t.fontColor&&(this.fontColor=t.fontColor),void 0!=t.fontSize&&(this.fontSize=t.fontSize),void 0!=t.fontFace&&(this.fontFace=t.fontFace),void 0!=this.image){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.image)}switch(this.xFixed=this.xFixed||void 0!=t.x,this.yFixed=this.yFixed||void 0!=t.y,this.radiusFixed=this.radiusFixed||void 0!=t.radius,"image"==this.shape&&(this.radiusMin=e.nodes.widthMin,this.radiusMax=e.nodes.widthMax),this.shape){case"database":this.draw=this._drawDatabase,this.resize=this._resizeDatabase;break;case"box":this.draw=this._drawBox,this.resize=this._resizeBox;break;case"circle":this.draw=this._drawCircle,this.resize=this._resizeCircle;break;case"ellipse":this.draw=this._drawEllipse,this.resize=this._resizeEllipse;break;case"image":this.draw=this._drawImage,this.resize=this._resizeImage;break;case"text":this.draw=this._drawText,this.resize=this._resizeText;break;case"dot":this.draw=this._drawDot,this.resize=this._resizeShape;break;case"square":this.draw=this._drawSquare,this.resize=this._resizeShape;break;case"triangle":this.draw=this._drawTriangle,this.resize=this._resizeShape;break;case"triangleDown":this.draw=this._drawTriangleDown,this.resize=this._resizeShape;break;case"star":this.draw=this._drawStar,this.resize=this._resizeShape;break;default:this.draw=this._drawEllipse,this.resize=this._resizeEllipse}this._reset()}},E.parseColor=function(t){var e;return O.isString(t)?e={border:t,background:t,highlight:{border:t,background:t}}:(e={},e.background=t.background||"white",e.border=t.border||e.background,O.isString(t.highlight)?e.highlight={border:t.highlight,background:t.highlight}:(e.highlight={},e.highlight.background=t.highlight&&t.highlight.background||e.background,e.highlight.border=t.highlight&&t.highlight.border||e.border)),e},E.prototype.select=function(){this.selected=!0,this._reset()},E.prototype.unselect=function(){this.selected=!1,this._reset()},E.prototype._reset=function(){this.width=void 0,this.height=void 0},E.prototype.getTitle=function(){return this.title},E.prototype.distanceToBorder=function(t,e){var i=1;switch(this.width||this.resize(t),this.shape){case"circle":case"dot":return this.radius+i;case"ellipse":var n=this.width/2,s=this.height/2,o=Math.sin(e)*n,r=Math.cos(e)*s;return n*s/Math.sqrt(o*o+r*r);case"box":case"image":case"text":default:return this.width?Math.min(Math.abs(this.width/2/Math.cos(e)),Math.abs(this.height/2/Math.sin(e)))+i:0}},E.prototype._setForce=function(t,e){this.fx=t,this.fy=e},E.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},E.prototype.discreteStep=function(t){if(!this.xFixed){var e=-this.damping*this.vx,i=(this.fx+e)/this.mass;this.vx+=i/t,this.x+=this.vx/t}if(!this.yFixed){var n=-this.damping*this.vy,s=(this.fy+n)/this.mass;this.vy+=s/t,this.y+=this.vy/t}},E.prototype.isFixed=function(){return this.xFixed&&this.yFixed},E.prototype.isMoving=function(t){return Math.abs(this.vx)>t||Math.abs(this.vy)>t||!this.xFixed&&Math.abs(this.fx)>this.minForce||!this.yFixed&&Math.abs(this.fy)>this.minForce},E.prototype.isSelected=function(){return this.selected},E.prototype.getValue=function(){return this.value},E.prototype.getDistance=function(t,e){var i=this.x-t,n=this.y-e;return Math.sqrt(i*i+n*n)},E.prototype.setValueRange=function(t,e){if(!this.radiusFixed&&void 0!==this.value){var i=(this.radiusMax-this.radiusMin)/(e-t);this.radius=(this.value-t)*i+this.radiusMin}},E.prototype.draw=function(){throw"Draw method not initialized for node"},E.prototype.resize=function(){throw"Resize method not initialized for node"},E.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},E.prototype._resizeImage=function(){if(!this.width){var t,e;if(this.value){var i=this.imageObj.height/this.imageObj.width;t=this.radius||this.imageObj.width,e=this.radius*i||this.imageObj.height}else t=this.imageObj.width,e=this.imageObj.height;this.width=t,this.height=e}},E.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e;this.imageObj?(t.drawImage(this.imageObj,this.left,this.top,this.width,this.height),e=this.y+this.height/2):e=this.y,this._label(t,this.label,this.x,e,void 0,"top")},E.prototype._resizeBox=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e}},E.prototype._drawBox=function(t){this._resizeBox(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,t.roundRect(this.left,this.top,this.width,this.height,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},E.prototype._resizeDatabase=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=i.width+2*e;this.width=n,this.height=n}},E.prototype._drawDatabase=function(t){this._resizeDatabase(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,t.database(this.x-this.width/2,this.y-.5*this.height,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},E.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=Math.max(i.width,i.height)+2*e;this.radius=n/2,this.width=n,this.height=n}},E.prototype._drawCircle=function(t){this._resizeCircle(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,t.circle(this.x,this.y,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},E.prototype._resizeEllipse=function(t){if(!this.width){var e=this.getTextSize(t);this.width=1.5*e.width,this.height=2*e.height,this.widthl;l++)t.fillText(r[l],i,d),d+=h}},E.prototype.getTextSize=function(t){if(void 0!=this.label){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace;for(var e=this.label.split("\n"),i=(this.fontSize+4)*e.length,n=0,s=0,o=e.length;o>s;s++)n=Math.max(n,t.measureText(e[s]).width);return{width:n,height:i}}return{width:0,height:0}},T.prototype.setProperties=function(t,e){if(t)switch(void 0!=t.from&&(this.fromId=t.from),void 0!=t.to&&(this.toId=t.to),void 0!=t.id&&(this.id=t.id),void 0!=t.style&&(this.style=t.style),void 0!=t.label&&(this.label=t.label),this.label&&(this.fontSize=e.edges.fontSize,this.fontFace=e.edges.fontFace,this.fontColor=e.edges.fontColor,void 0!=t.fontColor&&(this.fontColor=t.fontColor),void 0!=t.fontSize&&(this.fontSize=t.fontSize),void 0!=t.fontFace&&(this.fontFace=t.fontFace)),void 0!=t.title&&(this.title=t.title),void 0!=t.width&&(this.width=t.width),void 0!=t.value&&(this.value=t.value),void 0!=t.length&&(this.length=t.length),t.dash&&(void 0!=t.dash.length&&(this.dash.length=t.dash.length),void 0!=t.dash.gap&&(this.dash.gap=t.dash.gap),void 0!=t.dash.altLength&&(this.dash.altLength=t.dash.altLength)),void 0!=t.color&&(this.color=t.color),this.connect(),this.widthFixed=this.widthFixed||void 0!=t.width,this.lengthFixed=this.lengthFixed||void 0!=t.length,this.stiffness=1/this.length,this.style){case"line":this.draw=this._drawLine;break;case"arrow":this.draw=this._drawArrow;break;case"arrow-center":this.draw=this._drawArrowCenter;break;case"dash-line":this.draw=this._drawDashLine;break;default:this.draw=this._drawLine}},T.prototype.connect=function(){this.disconnect(),this.from=this.graph.nodes[this.fromId]||null,this.to=this.graph.nodes[this.toId]||null,this.connected=this.from&&this.to,this.connected?(this.from.attachEdge(this),this.to.attachEdge(this)):(this.from&&this.from.detachEdge(this),this.to&&this.to.detachEdge(this))},T.prototype.disconnect=function(){this.from&&(this.from.detachEdge(this),this.from=null),this.to&&(this.to.detachEdge(this),this.to=null),this.connected=!1},T.prototype.getTitle=function(){return this.title},T.prototype.getValue=function(){return this.value},T.prototype.setValueRange=function(t,e){if(!this.widthFixed&&void 0!==this.value){var i=(this.widthMax-this.widthMin)/(e-t);this.width=(this.value-t)*i+this.widthMin}},T.prototype.draw=function(){throw"Method draw not initialized in edge"},T.prototype.isOverlappingWith=function(t){var e=10,i=this.from.x,n=this.from.y,s=this.to.x,o=this.to.y,r=t.left,a=t.top,h=T._dist(i,n,s,o,r,a);return e>h},T.prototype._drawLine=function(t){t.strokeStyle=this.color,t.lineWidth=this._getLineWidth();var e;if(this.from!=this.to)this._line(t),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y));else{var i,n,s=this.length/4,o=this.from;o.width||o.resize(t),o.width>o.height?(i=o.x+o.width/2,n=o.y-s):(i=o.x+s,n=o.y-o.height/2),this._circle(t,i,n,s),e=this._pointOnCircle(i,n,s,.5),this._label(t,this.label,e.x,e.y)}},T.prototype._getLineWidth=function(){return this.from.selected||this.to.selected?Math.min(2*this.width,this.widthMax):this.width},T.prototype._line=function(t){t.beginPath(),t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y),t.stroke()},T.prototype._circle=function(t,e,i,n){t.beginPath(),t.arc(e,i,n,0,2*Math.PI,!1),t.stroke()},T.prototype._label=function(t,e,i,n){if(e){t.font=(this.from.selected||this.to.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle="white";var s=t.measureText(e).width,o=this.fontSize,r=i-s/2,a=n-o/2;t.fillRect(r,a,s,o),t.fillStyle=this.fontColor||"black",t.textAlign="left",t.textBaseline="top",t.fillText(e,r,a)}},T.prototype._drawDashLine=function(t){if(t.strokeStyle=this.color,t.lineWidth=this._getLineWidth(),t.beginPath(),t.lineCap="round",void 0!=this.dash.altLength?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]):void 0!=this.dash.length&&void 0!=this.dash.gap?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap]):(t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y)),t.stroke(),this.label){var e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}},T.prototype._pointOnLine=function(t){return{x:(1-t)*this.from.x+t*this.to.x,y:(1-t)*this.from.y+t*this.to.y}},T.prototype._pointOnCircle=function(t,e,i,n){var s=2*(n-3/8)*Math.PI;return{x:t+i*Math.cos(s),y:e-i*Math.sin(s)}},T.prototype._drawArrowCenter=function(t){var e;if(t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth(),this.from!=this.to){this._line(t);var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),n=10+5*this.width;e=this._pointOnLine(.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y))}else{var s,o,r=this.length/4,a=this.from;a.width||a.resize(t),a.width>a.height?(s=a.x+a.width/2,o=a.y-r):(s=a.x+r,o=a.y-a.height/2),this._circle(t,s,o,r);var i=.2*Math.PI,n=10+5*this.width;e=this._pointOnCircle(s,o,r,.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(s,o,r,.5),this._label(t,this.label,e.x,e.y))}},T.prototype._drawArrow=function(t){t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth();var e,i;if(this.from!=this.to){e=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x);var n=this.to.x-this.from.x,s=this.to.y-this.from.y,o=Math.sqrt(n*n+s*s),r=this.from.distanceToBorder(t,e+Math.PI),a=(o-r)/o,h=a*this.from.x+(1-a)*this.to.x,d=a*this.from.y+(1-a)*this.to.y,l=this.to.distanceToBorder(t,e),p=(o-l)/o,c=(1-p)*this.from.x+p*this.to.x,u=(1-p)*this.from.y+p*this.to.y;if(t.beginPath(),t.moveTo(h,d),t.lineTo(c,u),t.stroke(),i=10+5*this.width,t.arrow(c,u,e,i),t.fill(),t.stroke(),this.label){var f=this._pointOnLine(.5);this._label(t,this.label,f.x,f.y)}}else{var m,g,v,y=this.from,b=this.length/4;y.width||y.resize(t),y.width>y.height?(m=y.x+y.width/2,g=y.y-b,v={x:m,y:y.y,angle:.9*Math.PI}):(m=y.x+b,g=y.y-y.height/2,v={x:y.x,y:g,angle:.6*Math.PI}),t.beginPath(),t.arc(m,g,b,0,2*Math.PI,!1),t.stroke(),i=10+5*this.width,t.arrow(v.x,v.y,v.angle,i),t.fill(),t.stroke(),this.label&&(f=this._pointOnCircle(m,g,b,.5),this._label(t,this.label,f.x,f.y)) -}},T._dist=function(t,e,i,n,s,o){var r=i-t,a=n-e,h=r*r+a*a,d=((s-t)*r+(o-e)*a)/h;d>1?d=1:0>d&&(d=0);var l=t+d*r,p=e+d*a,c=l-s,u=p-o;return Math.sqrt(c*c+u*u)},x.prototype.setPosition=function(t,e){this.x=parseInt(t),this.y=parseInt(e)},x.prototype.setText=function(t){this.frame.innerHTML=t},x.prototype.show=function(t){if(void 0===t&&(t=!0),t){var e=this.frame.clientHeight,i=this.frame.clientWidth,n=this.frame.parentNode.clientHeight,s=this.frame.parentNode.clientWidth,o=this.y-e;o+e+this.padding>n&&(o=n-e-this.padding),this.padding>o&&(o=this.padding);var r=this.x;r+i+this.padding>s&&(r=s-i-this.padding),this.padding>r&&(r=this.padding),this.frame.style.left=r+"px",this.frame.style.top=o+"px",this.frame.style.visibility="visible"}else this.hide()},x.prototype.hide=function(){this.frame.style.visibility="hidden"},Groups=function(){this.clear(),this.defaultIndex=0},Groups.DEFAULT=[{border:"#2B7CE9",background:"#97C2FC",highlight:{border:"#2B7CE9",background:"#D2E5FF"}},{border:"#FFA500",background:"#FFFF00",highlight:{border:"#FFA500",background:"#FFFFA3"}},{border:"#FA0A10",background:"#FB7E81",highlight:{border:"#FA0A10",background:"#FFAFB1"}},{border:"#41A906",background:"#7BE141",highlight:{border:"#41A906",background:"#A1EC76"}},{border:"#E129F0",background:"#EB7DF4",highlight:{border:"#E129F0",background:"#F0B3F5"}},{border:"#7C29F0",background:"#AD85E4",highlight:{border:"#7C29F0",background:"#D3BDF0"}},{border:"#C37F00",background:"#FFA807",highlight:{border:"#C37F00",background:"#FFCA66"}},{border:"#4220FB",background:"#6E6EFD",highlight:{border:"#4220FB",background:"#9B9BFD"}},{border:"#FD5A77",background:"#FFC0CB",highlight:{border:"#FD5A77",background:"#FFD1D9"}},{border:"#4AD63A",background:"#C2FABC",highlight:{border:"#4AD63A",background:"#E6FFE3"}}],Groups.prototype.clear=function(){this.groups={},this.groups.length=function(){var t=0;for(var e in this)this.hasOwnProperty(e)&&t++;return t}},Groups.prototype.get=function(t){var e=this.groups[t];if(void 0==e){var i=this.defaultIndex%Groups.DEFAULT.length;this.defaultIndex++,e={},e.color=Groups.DEFAULT[i],this.groups[t]=e}return e},Groups.prototype.add=function(t,e){return this.groups[t]=e,e.color&&(e.color=E.parseColor(e.color)),e},Images=function(){this.images={},this.callback=void 0},Images.prototype.setOnloadCallback=function(t){this.callback=t},Images.prototype.load=function(t){var e=this.images[t];if(void 0==e){var i=this;e=new Image,this.images[t]=e,e.onload=function(){i.callback&&i.callback(this)},e.src=t}return e},S.prototype.setData=function(t){if(t&&t.dot&&(t.nodes||t.edges))throw new SyntaxError('Data must contain either parameter "dot" or parameter pair "nodes" and "edges", but not both.');if(this.setOptions(t&&t.options),t&&t.dot){if(t&&t.dot){var e=k.util.DOTToGraph(t.dot);return this.setData(e),void 0}}else this._setNodes(t&&t.nodes),this._setEdges(t&&t.edges);this.stabilize&&this._doStabilize(),this.start()},S.prototype.setOptions=function(t){if(t){if(void 0!=t.width&&(this.width=t.width),void 0!=t.height&&(this.height=t.height),void 0!=t.stabilize&&(this.stabilize=t.stabilize),void 0!=t.selectable&&(this.selectable=t.selectable),t.edges){for(var e in t.edges)t.edges.hasOwnProperty(e)&&(this.constants.edges[e]=t.edges[e]);void 0!=t.edges.length&&t.nodes&&void 0==t.nodes.distance&&(this.constants.edges.length=t.edges.length,this.constants.nodes.distance=1.25*t.edges.length),t.edges.fontColor||(this.constants.edges.fontColor=t.edges.color),t.edges.dash&&(void 0!=t.edges.dash.length&&(this.constants.edges.dash.length=t.edges.dash.length),void 0!=t.edges.dash.gap&&(this.constants.edges.dash.gap=t.edges.dash.gap),void 0!=t.edges.dash.altLength&&(this.constants.edges.dash.altLength=t.edges.dash.altLength))}if(t.nodes){for(e in t.nodes)t.nodes.hasOwnProperty(e)&&(this.constants.nodes[e]=t.nodes[e]);t.nodes.color&&(this.constants.nodes.color=E.parseColor(t.nodes.color))}if(t.groups)for(var i in t.groups)if(t.groups.hasOwnProperty(i)){var n=t.groups[i];this.groups.add(i,n)}}this.setSize(this.width,this.height),this._setTranslation(this.frame.clientWidth/2,this.frame.clientHeight/2),this._setScale(1)},S.prototype._trigger=function(t,e){L.trigger(this,t,e)},S.prototype._create=function(){for(;this.containerElement.hasChildNodes();)this.containerElement.removeChild(this.containerElement.firstChild);if(this.frame=document.createElement("div"),this.frame.className="graph-frame",this.frame.style.position="relative",this.frame.style.overflow="hidden",this.frame.canvas=document.createElement("canvas"),this.frame.canvas.style.position="relative",this.frame.appendChild(this.frame.canvas),!this.frame.canvas.getContext){var t=document.createElement("DIV");t.style.color="red",t.style.fontWeight="bold",t.style.padding="10px",t.innerHTML="Error: your browser does not support HTML canvas",this.frame.canvas.appendChild(t)}var e=this;this.drag={},this.pinch={},this.hammer=D(this.frame.canvas,{prevent_default:!0}),this.hammer.on("tap",e._onTap.bind(e)),this.hammer.on("hold",e._onHold.bind(e)),this.hammer.on("pinch",e._onPinch.bind(e)),this.hammer.on("touch",e._onTouch.bind(e)),this.hammer.on("dragstart",e._onDragStart.bind(e)),this.hammer.on("drag",e._onDrag.bind(e)),this.hammer.on("dragend",e._onDragEnd.bind(e)),this.hammer.on("mousewheel",e._onMouseWheel.bind(e)),this.hammer.on("mousemove",e._onMouseMoveTitle.bind(e)),this.containerElement.appendChild(this.frame)},S.prototype._getNodeAt=function(t){var e=this._canvasToX(t.x),i=this._canvasToY(t.y),n={left:e,top:i,right:e,bottom:i},s=this._getNodesOverlappingWith(n);return s.length>0?s[s.length-1]:null},S.prototype._getPointer=function(t){return{x:t.pageX-k.util.getAbsoluteLeft(this.frame.canvas),y:t.pageY-k.util.getAbsoluteTop(this.frame.canvas)}},S.prototype._onTouch=function(t){this.drag.pointer=this._getPointer(t.gesture.touches[0]),this.drag.pinched=!1,this.pinch.scale=this._getScale()},S.prototype._onDragStart=function(){var t=this.drag;t.selection=[],t.translation=this._getTranslation(),t.nodeId=this._getNodeAt(t.pointer);var e=this.nodes[t.nodeId];if(e){e.isSelected()||this._selectNodes([t.nodeId]);var i=this;this.selection.forEach(function(e){var n=i.nodes[e];if(n){var s={id:e,node:n,x:n.x,y:n.y,xFixed:n.xFixed,yFixed:n.yFixed};n.xFixed=!0,n.yFixed=!0,t.selection.push(s)}})}},S.prototype._onDrag=function(t){if(!this.drag.pinched){var e=this._getPointer(t.gesture.touches[0]),i=this,n=this.drag,s=n.selection;if(s&&s.length){var o=e.x-n.pointer.x,r=e.y-n.pointer.y;s.forEach(function(t){var e=t.node;t.xFixed||(e.x=i._canvasToX(i._xToCanvas(t.x)+o)),t.yFixed||(e.y=i._canvasToY(i._yToCanvas(t.y)+r))}),this.moving||(this.moving=!0,this.start())}else{var a=e.x-this.drag.pointer.x,h=e.y-this.drag.pointer.y;this._setTranslation(this.drag.translation.x+a,this.drag.translation.y+h),this._redraw(),this.moved=!0}}},S.prototype._onDragEnd=function(){var t=this.drag.selection;t&&t.forEach(function(t){t.node.xFixed=t.xFixed,t.node.yFixed=t.yFixed})},S.prototype._onTap=function(t){var e=this._getPointer(t.gesture.touches[0]),i=this._getNodeAt(e),n=this.nodes[i];n?(this._selectNodes([i]),this.moving||this._redraw()):(this._unselectNodes(),this._redraw())},S.prototype._onHold=function(t){var e=this._getPointer(t.gesture.touches[0]),i=this._getNodeAt(e),n=this.nodes[i];if(n){if(n.isSelected())this._unselectNodes([i]);else{var s=!0;this._selectNodes([i],s)}this.moving||this._redraw()}},S.prototype._onPinch=function(t){var e=this._getPointer(t.gesture.center);this.drag.pinched=!0,"scale"in this.pinch||(this.pinch.scale=1);var i=this.pinch.scale*t.gesture.scale;this._zoom(i,e)},S.prototype._zoom=function(t,e){var i=this._getScale();.01>t&&(t=.01),t>10&&(t=10);var n=this._getTranslation(),s=t/i,o=(1-s)*e.x+n.x*s,r=(1-s)*e.y+n.y*s;return this._setScale(t),this._setTranslation(o,r),this._redraw(),t},S.prototype._onMouseWheel=function(t){var e=0;if(t.wheelDelta?e=t.wheelDelta/120:t.detail&&(e=-t.detail/3),e){"mouswheelScale"in this.pinch||(this.pinch.mouswheelScale=1);var i=this.pinch.mouswheelScale,n=e/10;0>e&&(n/=1-n),i*=1+n;var s=D.event.collectEventData(this,"scroll",t),o=this._getPointer(s.center);i=this._zoom(i,o),this.pinch.mouswheelScale=i}t.preventDefault()},S.prototype._onMouseMoveTitle=function(t){var e=D.event.collectEventData(this,"mousemove",t),i=this._getPointer(e.center);this.popupNode&&this._checkHidePopup(i);var n=this,s=function(){n._checkShowPopup(i)};this.popupTimer&&clearInterval(this.popupTimer),this.leftButtonDown||(this.popupTimer=setTimeout(s,300))},S.prototype._checkShowPopup=function(t){var e,i={left:this._canvasToX(t.x),top:this._canvasToY(t.y),right:this._canvasToX(t.x),bottom:this._canvasToY(t.y)},n=this.popupNode;if(void 0==this.popupNode){var s=this.nodes;for(e in s)if(s.hasOwnProperty(e)){var o=s[e];if(void 0!=o.getTitle()&&o.isOverlappingWith(i)){this.popupNode=o;break}}}if(void 0==this.popupNode){var r=this.edges;for(e in r)if(r.hasOwnProperty(e)){var a=r[e];if(a.connected&&void 0!=a.getTitle()&&a.isOverlappingWith(i)){this.popupNode=a;break}}}if(this.popupNode){if(this.popupNode!=n){var h=this;h.popup||(h.popup=new x(h.frame)),h.popup.setPosition(t.x-3,t.y-3),h.popup.setText(h.popupNode.getTitle()),h.popup.show()}}else this.popup&&this.popup.hide()},S.prototype._checkHidePopup=function(t){this.popupNode&&this._getNodeAt(t)||(this.popupNode=void 0,this.popup&&this.popup.hide())},S.prototype._unselectNodes=function(t,e){var i,n,s,o=!1;if(t)for(i=0,n=t.length;n>i;i++){s=t[i],this.nodes[s].unselect();for(var r=0;this.selection.length>r;)this.selection[r]==s?(this.selection.splice(r,1),o=!0):r++}else if(this.selection&&this.selection.length){for(i=0,n=this.selection.length;n>i;i++)s=this.selection[i],this.nodes[s].unselect(),o=!0;this.selection=[]}return!o||1!=e&&void 0!=e||this._trigger("select"),o},S.prototype._selectNodes=function(t,e){var i,n,s=!1,o=!0;if(t.length!=this.selection.length)o=!1;else for(i=0,n=Math.min(t.length,this.selection.length);n>i;i++)if(t[i]!=this.selection[i]){o=!1;break}if(o)return s;if(void 0==e||0==e){var r=!1;s=this._unselectNodes(void 0,r)}for(i=0,n=t.length;n>i;i++){var a=t[i],h=-1!=this.selection.indexOf(a);h||(this.nodes[a].select(),this.selection.push(a),s=!0)}return s&&this._trigger("select"),s},S.prototype._getNodesOverlappingWith=function(t){var e=this.nodes,i=[];for(var n in e)e.hasOwnProperty(n)&&e[n].isOverlappingWith(t)&&i.push(n);return i},S.prototype.getSelection=function(){return this.selection.concat([])},S.prototype.setSelection=function(t){var e,i,n;if(!t||void 0==t.length)throw"Selection must be an array with ids";for(e=0,i=this.selection.length;i>e;e++)n=this.selection[e],this.nodes[n].unselect();for(this.selection=[],e=0,i=t.length;i>e;e++){n=t[e];var s=this.nodes[n];if(!s)throw new RangeError('Node with id "'+n+'" not found');s.select(),this.selection.push(n)}this.redraw()},S.prototype._updateSelection=function(){for(var t=0;this.selection.length>t;){var e=this.selection[t];this.nodes[e]?t++:this.selection.splice(t,1)}},S.prototype._getConnectionCount=function(t){function e(t){for(var e=[],i=0,n=t.length;n>i;i++)for(var s=t[i],o=s.edges,r=0,a=o.length;a>r;r++){var h=o[r],d=null;h.from==s?d=h.to:h.to==s&&(d=h.from);var l,p;if(d)for(l=0,p=t.length;p>l;l++)if(t[l]==d){d=null;break}if(d)for(l=0,p=e.length;p>l;l++)if(e[l]==d){d=null;break}d&&e.push(d)}return e}void 0==t&&(t=1);var i=[],n=this.nodes;for(var s in n)if(n.hasOwnProperty(s)){for(var o=[n[s]],r=0;t>r;r++)o=o.concat(e(o));i.push(o)}for(var a=[],h=0,d=i.length;d>h;h++)a.push(i[h].length);return a},S.prototype.setSize=function(t,e){this.frame.style.width=t,this.frame.style.height=e,this.frame.canvas.style.width="100%",this.frame.canvas.style.height="100%",this.frame.canvas.width=this.frame.canvas.clientWidth,this.frame.canvas.height=this.frame.canvas.clientHeight},S.prototype._setNodes=function(t){var e=this.nodesData;if(t instanceof o||t instanceof r)this.nodesData=t;else if(t instanceof Array)this.nodesData=new o,this.nodesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.nodesData=new o}if(e&&O.forEach(this.nodesListeners,function(t,i){e.unsubscribe(i,t)}),this.nodes={},this.nodesData){var i=this;O.forEach(this.nodesListeners,function(t,e){i.nodesData.subscribe(e,t)});var n=this.nodesData.getIds();this._addNodes(n)}this._updateSelection()},S.prototype._addNodes=function(t){for(var e,i=0,n=t.length;n>i;i++){e=t[i];var s=this.nodesData.get(e),o=new E(s,this.images,this.groups,this.constants);if(this.nodes[e]=o,!o.isFixed()){var r=2*this.constants.edges.length,a=t.length,h=2*Math.PI*(i/a);o.x=r*Math.cos(h),o.y=r*Math.sin(h),this.moving=!0}}this._reconnectEdges(),this._updateValueRange(this.nodes)},S.prototype._updateNodes=function(t){for(var e=this.nodes,i=this.nodesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o],a=i.get(o);r?r.setProperties(a,this.constants):(r=new E(properties,this.images,this.groups,this.constants),e[o]=r,r.isFixed()||(this.moving=!0))}this._reconnectEdges(),this._updateValueRange(e)},S.prototype._removeNodes=function(t){for(var e=this.nodes,i=0,n=t.length;n>i;i++){var s=t[i];delete e[s]}this._reconnectEdges(),this._updateSelection(),this._updateValueRange(e)},S.prototype._setEdges=function(t){var e=this.edgesData;if(t instanceof o||t instanceof r)this.edgesData=t;else if(t instanceof Array)this.edgesData=new o,this.edgesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.edgesData=new o}if(e&&O.forEach(this.edgesListeners,function(t,i){e.unsubscribe(i,t)}),this.edges={},this.edgesData){var i=this;O.forEach(this.edgesListeners,function(t,e){i.edgesData.subscribe(e,t)});var n=this.edgesData.getIds();this._addEdges(n)}this._reconnectEdges()},S.prototype._addEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o];r&&r.disconnect();var a=i.get(o);e[o]=new T(a,this,this.constants)}this.moving=!0,this._updateValueRange(e)},S.prototype._updateEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=i.get(o),a=e[o];a?(a.disconnect(),a.setProperties(r,this.constants),a.connect()):(a=new T(r,this,this.constants),this.edges[o]=a)}this.moving=!0,this._updateValueRange(e)},S.prototype._removeEdges=function(t){for(var e=this.edges,i=0,n=t.length;n>i;i++){var s=t[i],o=e[s];o&&(o.disconnect(),delete e[s])}this.moving=!0,this._updateValueRange(e)},S.prototype._reconnectEdges=function(){var t,e=this.nodes,i=this.edges;for(t in e)e.hasOwnProperty(t)&&(e[t].edges=[]);for(t in i)if(i.hasOwnProperty(t)){var n=i[t];n.from=null,n.to=null,n.connect()}},S.prototype._updateValueRange=function(t){var e,i=void 0,n=void 0;for(e in t)if(t.hasOwnProperty(e)){var s=t[e].getValue();void 0!==s&&(i=void 0===i?s:Math.min(s,i),n=void 0===n?s:Math.max(s,n))}if(void 0!==i&&void 0!==n)for(e in t)t.hasOwnProperty(e)&&t[e].setValueRange(i,n)},S.prototype.redraw=function(){this.setSize(this.width,this.height),this._redraw()},S.prototype._redraw=function(){var t=this.frame.canvas.getContext("2d"),e=this.frame.canvas.width,i=this.frame.canvas.height;t.clearRect(0,0,e,i),t.save(),t.translate(this.translation.x,this.translation.y),t.scale(this.scale,this.scale),this._drawEdges(t),this._drawNodes(t),t.restore()},S.prototype._setTranslation=function(t,e){void 0===this.translation&&(this.translation={x:0,y:0}),void 0!==t&&(this.translation.x=t),void 0!==e&&(this.translation.y=e)},S.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},S.prototype._setScale=function(t){this.scale=t},S.prototype._getScale=function(){return this.scale},S.prototype._canvasToX=function(t){return(t-this.translation.x)/this.scale},S.prototype._xToCanvas=function(t){return t*this.scale+this.translation.x},S.prototype._canvasToY=function(t){return(t-this.translation.y)/this.scale},S.prototype._yToCanvas=function(t){return t*this.scale+this.translation.y},S.prototype._drawNodes=function(t){var e=this.nodes,i=[];for(var n in e)e.hasOwnProperty(n)&&(e[n].isSelected()?i.push(n):e[n].draw(t));for(var s=0,o=i.length;o>s;s++)e[i[s]].draw(t)},S.prototype._drawEdges=function(t){var e=this.edges;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];n.connected&&e[i].draw(t)}},S.prototype._doStabilize=function(){new Date;for(var t=0,e=this.constants.minVelocity,i=!1;!i&&this.constants.maxIterations>t;)this._calculateForces(),this._discreteStepNodes(),i=!this._isMoving(e),t++;new Date},S.prototype._calculateForces=function(){var t,e,i,n,s,o,r,a,h,d,l,p=this.nodes,c=this.edges,u=.01,f=this.frame.canvas.clientWidth/2,m=this.frame.canvas.clientHeight/2;for(t in p)if(p.hasOwnProperty(t)){var g=p[t];e=f-g.x,i=m-g.y,n=Math.atan2(i,e),o=Math.cos(n)*u,r=Math.sin(n)*u,g._setForce(o,r)}var v=this.constants.nodes.distance,y=10;for(var b in p)if(p.hasOwnProperty(b)){var w=p[b];for(var _ in p)if(p.hasOwnProperty(_)){var E=p[_];e=E.x-w.x,i=E.y-w.y,s=Math.sqrt(e*e+i*i),n=Math.atan2(i,e),a=1/(1+Math.exp((s/v-1)*y)),o=Math.cos(n)*a,r=Math.sin(n)*a,w._addForce(-o,-r),E._addForce(o,r)}}for(t in c)if(c.hasOwnProperty(t)){var T=c[t];T.connected&&(e=T.to.x-T.from.x,i=T.to.y-T.from.y,l=T.length,d=Math.sqrt(e*e+i*i),n=Math.atan2(i,e),h=T.stiffness*(l-d),o=Math.cos(n)*h,r=Math.sin(n)*h,T.from._addForce(-o,-r),T.to._addForce(o,r))}},S.prototype._isMoving=function(t){var e=this.nodes;for(var i in e)if(e.hasOwnProperty(i)&&e[i].isMoving(t))return!0;return!1},S.prototype._discreteStepNodes=function(){var t=this.refreshRate/1e3,e=this.nodes;for(var i in e)e.hasOwnProperty(i)&&e[i].discreteStep(t)},S.prototype.start=function(){if(this.moving){this._calculateForces(),this._discreteStepNodes();var t=this.constants.minVelocity;this.moving=this._isMoving(t)}if(this.moving){if(!this.timer){var e=this;this.timer=window.setTimeout(function(){e.timer=void 0,e.start(),e._redraw()},this.refreshRate)}}else this._redraw()},S.prototype.stop=function(){this.timer&&(window.clearInterval(this.timer),this.timer=void 0)};var k={util:O,events:L,Controller:d,DataSet:o,DataView:r,Range:h,Stack:a,TimeStep:TimeStep,EventBus:s,components:{items:{Item:m,ItemBox:g,ItemPoint:v,ItemRange:y},Component:l,Panel:p,RootPanel:c,ItemSet:f,TimeAxis:u},graph:{Node:E,Edge:T,Popup:x,Groups:Groups,Images:Images},Timeline:_,Graph:S};n!==void 0&&(n=k),i!==void 0&&i.exports!==void 0&&(i.exports=k),"function"==typeof t&&t(function(){return k}),"undefined"!=typeof window&&(window.vis=k),O.loadCss("/* vis.js stylesheet */\n.vis.timeline {\n}\n\n\n.vis.timeline.rootpanel {\n position: relative;\n overflow: hidden;\n\n border: 1px solid #bfbfbf;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n\n.vis.timeline .panel {\n position: absolute;\n overflow: hidden;\n}\n\n\n.vis.timeline .groupset {\n position: absolute;\n padding: 0;\n margin: 0;\n}\n\n.vis.timeline .labels {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n\n padding: 0;\n margin: 0;\n\n border-right: 1px solid #bfbfbf;\n box-sizing: border-box;\n -moz-box-sizing: border-box;\n}\n\n.vis.timeline .labels .label {\n position: absolute;\n left: 0;\n top: 0;\n width: 100%;\n border-bottom: 1px solid #bfbfbf;\n color: #4d4d4d;\n}\n\n.vis.timeline .labels .label .inner {\n display: inline-block;\n padding: 5px;\n}\n\n\n.vis.timeline .itemset {\n position: absolute;\n padding: 0;\n margin: 0;\n overflow: hidden;\n}\n\n.vis.timeline .background {\n}\n\n.vis.timeline .foreground {\n}\n\n.vis.timeline .itemset-axis {\n position: absolute;\n}\n\n.vis.timeline .groupset .itemset-axis {\n border-top: 1px solid #bfbfbf;\n}\n\n/* TODO: with orientation=='bottom', this will more or less overlap with timeline axis\n.vis.timeline .groupset .itemset-axis:last-child {\n border-top: none;\n}\n*/\n\n\n.vis.timeline .item {\n position: absolute;\n color: #1A1A1A;\n border-color: #97B0F8;\n background-color: #D5DDF6;\n display: inline-block;\n}\n\n.vis.timeline .item.selected {\n border-color: #FFC200;\n background-color: #FFF785;\n z-index: 999;\n}\n\n.vis.timeline .item.cluster {\n /* TODO: use another color or pattern? */\n background: #97B0F8 url('img/cluster_bg.png');\n color: white;\n}\n.vis.timeline .item.cluster.point {\n border-color: #D5DDF6;\n}\n\n.vis.timeline .item.box {\n text-align: center;\n border-style: solid;\n border-width: 1px;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.point {\n background: none;\n}\n\n.vis.timeline .dot {\n border: 5px solid #97B0F8;\n position: absolute;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.range {\n overflow: hidden;\n border-style: solid;\n border-width: 1px;\n border-radius: 2px;\n -moz-border-radius: 2px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.range .drag-left {\n cursor: w-resize;\n z-index: 1000;\n}\n\n.vis.timeline .item.range .drag-right {\n cursor: e-resize;\n z-index: 1000;\n}\n\n.vis.timeline .item.range .content {\n position: relative;\n display: inline-block;\n}\n\n.vis.timeline .item.line {\n position: absolute;\n width: 0;\n border-left-width: 1px;\n border-left-style: solid;\n}\n\n.vis.timeline .item .content {\n margin: 5px;\n white-space: nowrap;\n overflow: hidden;\n}\n\n.vis.timeline .axis {\n position: relative;\n}\n\n.vis.timeline .axis .text {\n position: absolute;\n color: #4d4d4d;\n padding: 3px;\n white-space: nowrap;\n}\n\n.vis.timeline .axis .text.measure {\n position: absolute;\n padding-left: 0;\n padding-right: 0;\n margin-left: 0;\n margin-right: 0;\n visibility: hidden;\n}\n\n.vis.timeline .axis .grid.vertical {\n position: absolute;\n width: 0;\n border-right: 1px solid;\n}\n\n.vis.timeline .axis .grid.horizontal {\n position: absolute;\n left: 0;\n width: 100%;\n height: 0;\n border-bottom: 1px solid;\n}\n\n.vis.timeline .axis .grid.minor {\n border-color: #e5e5e5;\n}\n\n.vis.timeline .axis .grid.major {\n border-color: #bfbfbf;\n}\n\n")},{hammerjs:1,moment:2}]},{},[3])(3)}); \ No newline at end of file From c81ab9157a94755f69334842912faccf01595b6a Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Thu, 30 Jan 2014 12:38:17 +0100 Subject: [PATCH 25/52] removed this.selection in favor or this.selectionObj. This allows keeping track of selection of nodes and edges. --- dist/vis.js | 386 ++++++++++++++++++++---------------- src/graph/ClusterMixin.js | 7 + src/graph/Edge.js | 14 +- src/graph/Graph.js | 42 ++-- src/graph/SelectionMixin.js | 327 ++++++++++++++++-------------- 5 files changed, 430 insertions(+), 346 deletions(-) diff --git a/dist/vis.js b/dist/vis.js index 6e3682d1..1cb8c8c3 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -5,7 +5,7 @@ * A dynamic, browser-based visualization library. * * @version 0.4.0-SNAPSHOT - * @date 2014-01-29 + * @date 2014-01-30 * * @license * Copyright (C) 2011-2014 Almende B.V, http://almende.com @@ -9780,6 +9780,7 @@ function Edge (properties, graph, constants) { this.width = constants.edges.width; this.value = undefined; this.length = constants.edges.length; + this.selected = false; this.from = null; // a node this.to = null; // a node @@ -10016,7 +10017,7 @@ Edge.prototype._drawLine = function(ctx) { * @private */ Edge.prototype._getLineWidth = function() { - if (this.from.selected || this.to.selected) { + if (this.selected == true) { return Math.min(this.width * 2, this.widthMax)*this.graphScaleInv; } else { @@ -10366,6 +10367,15 @@ Edge._dist = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point Edge.prototype.setScale = function(scale) { this.graphScaleInv = 1.0/scale; }; + + +Edge.prototype.select = function() { + this.selected = true; +} + +Edge.prototype.unselect = function() { + this.selected = false; +} /** * Popup is a class to create a popup window with some text * @param {Element} container The container object. @@ -11479,6 +11489,10 @@ var ClusterMixin = { // if child node has been added on smaller scale than current, kick out if (childNode.formationScale < this.scale || force == true) { + // remove the selection, first remove the selection from the connected edges + this._unselectConnectedEdges(parentNode); + parentNode.unselect(); + // put the child node back in the global nodes object this.nodes[containedNodeId] = childNode; @@ -11527,6 +11541,9 @@ var ClusterMixin = { // recalculate the size of the node on the next time the node is rendered parentNode.clearSizeCache(); + + // this unselects the rest of the edges + this._unselectConnectedEdges(parentNode); } // check if a further expansion step is possible if recursivity is enabled @@ -12272,7 +12289,7 @@ var SelectionMixin = { _getNodeAt : function (pointer) { // we first check if this is an navigationUI element var positionObject = this._pointerToPositionObject(pointer); - overlappingNodes = this._getAllNodesOverlappingWith(positionObject); + var overlappingNodes = this._getAllNodesOverlappingWith(positionObject); // if there are overlapping nodes, select the last one, this is the // one which is drawn on top of the others @@ -12285,6 +12302,36 @@ var SelectionMixin = { }, + /** + * retrieve all edges overlapping with given object, selector is around center + * @param {Object} object An object with parameters left, top, right, bottom + * @return {Number[]} An array with id's of the overlapping nodes + * @private + */ + _getEdgesOverlappingWith : function (object, overlappingEdges) { + var edges = this.edges; + for (var edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + if (edges[edgeId].isOverlappingWith(object)) { + overlappingEdges.push(edgeId); + } + } + } + }, + + + /** + * retrieve all nodes overlapping with given object + * @param {Object} object An object with parameters left, top, right, bottom + * @return {Number[]} An array with id's of the overlapping nodes + * @private + */ + _getAllEdgesOverlappingWith : function (object) { + var overlappingEdges = []; + this._doInAllActiveSectors("_getEdgesOverlappingWith",object,overlappingEdges); + return overlappingEdges; + }, + /** * Place holder. To implement change the _getNodeAt to a _getObjectAt. Have the _getObjectAt call * _getNodeAt and _getEdgesAt, then priortize the selection to user preferences. @@ -12294,18 +12341,25 @@ var SelectionMixin = { * @private */ _getEdgeAt : function(pointer) { - return null; + var positionObject = this._pointerToPositionObject(pointer); + var overlappingEdges = this._getAllEdgesOverlappingWith(positionObject); + + if (overlappingEdges.length > 0) { + return this.edges[overlappingEdges[overlappingEdges.length - 1]]; + } + else { + return null; + } }, /** - * Add object to the selection array. The this.selection id array may not be needed. + * Add object to the selection array. * * @param obj * @private */ _addToSelection : function(obj) { - this.selection.push(obj.id); this.selectionObj[obj.id] = obj; }, @@ -12317,12 +12371,6 @@ var SelectionMixin = { * @private */ _removeFromSelection : function(obj) { - for (var i = 0; i < this.selection.length; i++) { - if (obj.id == this.selection[i]) { - this.selection.splice(i,1); - break; - } - } delete this.selectionObj[obj.id]; }, @@ -12338,10 +12386,9 @@ var SelectionMixin = { doNotTrigger = false; } - this.selection = []; - for (var objId in this.selectionObj) { - if (this.selectionObj.hasOwnProperty(objId)) { - this.selectionObj[objId].unselect(); + for (var objectId in this.selectionObj) { + if (this.selectionObj.hasOwnProperty(objectId)) { + this.selectionObj[objectId].unselect(); } } this.selectionObj = {}; @@ -12359,25 +12406,55 @@ var SelectionMixin = { * @private */ _selectionIsEmpty : function() { - if (this.selection.length == 0) { - return true; + for(var objectId in this.selectionObj) { + if(this.selectionObj.hasOwnProperty(objectId)) { + return false; + } } - else { - return false; + return true; + }, + + /** + * select the edges connected to the node that is being selected + * + * @param {Node} node + * @private + */ + _selectConnectedEdges : function(node) { + for (var i = 0; i < node.dynamicEdges.length; i++) { + var edge = node.dynamicEdges[i]; + edge.select(); + this._addToSelection(edge); } }, + /** + * unselect the edges connected to the node that is being selected + * + * @param {Node} node + * @private + */ + _unselectConnectedEdges : function(node) { + for (var i = 0; i < node.dynamicEdges.length; i++) { + var edge = node.dynamicEdges[i]; + edge.unselect(); + this._removeFromSelection(edge); + } + }, + + + /** * This is called when someone clicks on a node. either select or deselect it. * If there is an existing selection and we don't want to append to it, clear the existing selection * - * @param {Node} node + * @param {Node || Edge} object * @param {Boolean} append * @param {Boolean} [doNotTrigger] | ignore trigger * @private */ - _selectNode : function(node, append, doNotTrigger) { + _selectObject : function(object, append, doNotTrigger) { if (doNotTrigger === undefined) { doNotTrigger = false; } @@ -12386,14 +12463,16 @@ var SelectionMixin = { this._unselectAll(true); } - - if (node.selected == false) { - node.select(); - this._addToSelection(node); + if (object.selected == false) { + object.select(); + this._addToSelection(object); + if (object instanceof Node) { + this._selectConnectedEdges(object); + } } else { - node.unselect(); - this._removeFromSelection(node); + object.unselect(); + this._removeFromSelection(object); } if (doNotTrigger == false) { this._trigger('select'); @@ -12428,10 +12507,16 @@ var SelectionMixin = { _handleTap : function(pointer) { var node = this._getNodeAt(pointer); if (node != null) { - this._selectNode(node,false); + this._selectObject(node,false); } else { - this._unselectAll(); + var edge = this._getEdgeAt(pointer); + if (edge != null) { + this._selectObject(edge,false); + } + else { + this._unselectAll(); + } } this._redraw(); }, @@ -12463,7 +12548,13 @@ var SelectionMixin = { _handleOnHold : function(pointer) { var node = this._getNodeAt(pointer); if (node != null) { - this._selectNode(node,true); + this._selectObject(node,true); + } + else { + var edge = this._getEdgeAt(pointer); + if (edge != null) { + this._selectObject(edge,true); + } } this._redraw(); }, @@ -12485,12 +12576,72 @@ var SelectionMixin = { /** * - * retrieve the currently selected nodes + * retrieve the currently selected objects * @return {Number[] | String[]} selection An array with the ids of the * selected nodes. */ getSelection : function() { - return this.selection.concat([]); + var nodeIdString = this.getSelectedNodes(); + /* + var edgeIdString = this.getSelectedEdges(); + + var idString = ""; + if (nodeIdString != "") { + idString = idString.concat("Nodes: ",nodeIdString); + + if (edgeIdString != "") { + idString = idString.concat("; "); + } + } + if (edgeIdString != "") { + idString = idString.concat("Edges: ",edgeIdString); + } + */ + return nodeIdString + }, + + /** + * + * retrieve the currently selected nodes + * @return {String} selection An array with the ids of the + * selected nodes. + */ + getSelectedNodes : function() { + var idString = "", i = 0; + for(var objectId in this.selectionObj) { + if(this.selectionObj.hasOwnProperty(objectId)) { + if (this.selectionObj[objectId] instanceof Node) { + if (i != 0) { + idString = idString.concat(", "); + } + idString = idString.concat(String(objectId)); + i++; + } + } + } + return idString + }, + + /** + * + * retrieve the currently selected edges + * @return {String} selection An array with the ids of the + * selected nodes. + */ + getSelectedEdges : function() { + var idString = "", i = 0; + for(var objectId in this.selectionObj) { + if(this.selectionObj.hasOwnProperty(objectId)) { + if (this.selectionObj[objectId] instanceof Edge) { + if (i != 0) { + idString = idString.concat(", "); + } + idString = idString.concat(String(objectId)); + i++; + } + } + } + return idString }, /** @@ -12504,8 +12655,6 @@ var SelectionMixin = { }, /** - * // TODO: rework this function, it is from the old system - * * select zero or more nodes * @param {Number[] | String[]} selection An array with the ids of the * selected nodes. @@ -12526,7 +12675,7 @@ var SelectionMixin = { if (!node) { throw new RangeError('Node with id "' + id + '" not found'); } - this._selectNode(node,true,true); + this._selectObject(node,true,true); } this.redraw(); @@ -12534,135 +12683,28 @@ var SelectionMixin = { /** - * TODO: rework this function, it is from the old system - * * Validate the selection: remove ids of nodes which no longer exist * @private */ _updateSelection : function () { - var i = 0; - while (i < this.selection.length) { - var nodeId = this.selection[i]; - if (!this.nodes.hasOwnProperty(nodeId)) { - this.selection.splice(i, 1); - delete this.selectionObj[nodeId]; - } - else { - i++; - } - } - } - - - /** - * Unselect selected nodes. If no selection array is provided, all nodes - * are unselected - * @param {Object[]} selection Array with selection objects, each selection - * object has a parameter row. Optional - * @param {Boolean} triggerSelect If true (default), the select event - * is triggered when nodes are unselected - * @return {Boolean} changed True if the selection is changed - * @private - */ - /* _unselectNodes : function(selection, triggerSelect) { - var changed = false; - var i, iMax, id; - - if (selection) { - // remove provided selections - for (i = 0, iMax = selection.length; i < iMax; i++) { - id = selection[i]; - if (this.nodes.hasOwnProperty(id)) { - this.nodes[id].unselect(); - } - var j = 0; - while (j < this.selection.length) { - if (this.selection[j] == id) { - this.selection.splice(j, 1); - changed = true; + for(var objectId in this.selectionObj) { + if(this.selectionObj.hasOwnProperty(objectId)) { + if (this.selectionObj[objectId] instanceof Node) { + if (!this.nodes.hasOwnProperty(objectId)) { + delete this.selectionObj[objectId]; } - else { - j++; - } - } - } - } - else if (this.selection && this.selection.length) { - // remove all selections - for (i = 0, iMax = this.selection.length; i < iMax; i++) { - id = this.selection[i]; - if (this.nodes.hasOwnProperty(id)) { - this.nodes[id].unselect(); } - changed = true; - } - this.selection = []; - } - - if (changed && (triggerSelect == true || triggerSelect == undefined)) { - // fire the select event - this._trigger('select'); - } - - return changed; - }, -*/ -/** - * select all nodes on given location x, y - * @param {Array} selection an array with node ids - * @param {boolean} append If true, the new selection will be appended to the - * current selection (except for duplicate entries) - * @return {Boolean} changed True if the selection is changed - * @private - */ -/* _selectNodes : function(selection, append) { - var changed = false; - var i, iMax; - - // TODO: the selectNodes method is a little messy, rework this - - // check if the current selection equals the desired selection - var selectionAlreadyThere = true; - if (selection.length != this.selection.length) { - selectionAlreadyThere = false; - } - else { - for (i = 0, iMax = Math.min(selection.length, this.selection.length); i < iMax; i++) { - if (selection[i] != this.selection[i]) { - selectionAlreadyThere = false; - break; + else { // assuming only edges and nodes are selected + if (!this.edges.hasOwnProperty(objectId)) { + delete this.selectionObj[objectId]; + } } } } - if (selectionAlreadyThere) { - return changed; - } + } - if (append == undefined || append == false) { - // first deselect any selected node - var triggerSelect = false; - changed = this._unselectNodes(undefined, triggerSelect); - } - for (i = 0, iMax = selection.length; i < iMax; i++) { - // add each of the new selections, but only when they are not duplicate - var id = selection[i]; - var isDuplicate = (this.selection.indexOf(id) != -1); - if (!isDuplicate) { - this.nodes[id].select(); - this.selection.push(id); - changed = true; - } - } - if (changed) { - // fire the select event - this._trigger('select'); - } - - return changed; - }, - */ }; @@ -13569,27 +13611,28 @@ Graph.prototype._onDragStart = function () { } // create an array with the selected nodes and their original location and status - var me = this; - this.selection.forEach(function (id) { - var node = me.nodes[id]; - if (node) { - var s = { - id: id, - node: node, - - // store original x, y, xFixed and yFixed, make the node temporarily Fixed - x: node.x, - y: node.y, - xFixed: node.xFixed, - yFixed: node.yFixed - }; + for (var objectId in this.selectionObj) { + if (this.selectionObj.hasOwnProperty(objectId)) { + var object = this.selectionObj[objectId]; + if (object instanceof Node) { + var s = { + id: object.id, + node: object, + + // store original x, y, xFixed and yFixed, make the node temporarily Fixed + x: object.x, + y: object.y, + xFixed: object.xFixed, + yFixed: object.yFixed + }; - node.xFixed = true; - node.yFixed = true; + object.xFixed = true; + object.yFixed = true; - drag.selection.push(s); + drag.selection.push(s); + } } - }); + } } }; @@ -14932,7 +14975,6 @@ Graph.prototype._loadSectorSystem = function() { * @private */ Graph.prototype._loadSelectionSystem = function() { - this.selection = []; this.selectionObj = {}; for (var mixinFunction in SelectionMixin) { diff --git a/src/graph/ClusterMixin.js b/src/graph/ClusterMixin.js index b89ceac7..cfb50d3b 100644 --- a/src/graph/ClusterMixin.js +++ b/src/graph/ClusterMixin.js @@ -335,6 +335,10 @@ var ClusterMixin = { // if child node has been added on smaller scale than current, kick out if (childNode.formationScale < this.scale || force == true) { + // remove the selection, first remove the selection from the connected edges + this._unselectConnectedEdges(parentNode); + parentNode.unselect(); + // put the child node back in the global nodes object this.nodes[containedNodeId] = childNode; @@ -383,6 +387,9 @@ var ClusterMixin = { // recalculate the size of the node on the next time the node is rendered parentNode.clearSizeCache(); + + // this unselects the rest of the edges + this._unselectConnectedEdges(parentNode); } // check if a further expansion step is possible if recursivity is enabled diff --git a/src/graph/Edge.js b/src/graph/Edge.js index 574685e8..145dac2b 100644 --- a/src/graph/Edge.js +++ b/src/graph/Edge.js @@ -32,6 +32,7 @@ function Edge (properties, graph, constants) { this.width = constants.edges.width; this.value = undefined; this.length = constants.edges.length; + this.selected = false; this.from = null; // a node this.to = null; // a node @@ -268,7 +269,7 @@ Edge.prototype._drawLine = function(ctx) { * @private */ Edge.prototype._getLineWidth = function() { - if (this.from.selected || this.to.selected) { + if (this.selected == true) { return Math.min(this.width * 2, this.widthMax)*this.graphScaleInv; } else { @@ -617,4 +618,13 @@ Edge._dist = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point */ Edge.prototype.setScale = function(scale) { this.graphScaleInv = 1.0/scale; -}; \ No newline at end of file +}; + + +Edge.prototype.select = function() { + this.selected = true; +} + +Edge.prototype.unselect = function() { + this.selected = false; +} \ No newline at end of file diff --git a/src/graph/Graph.js b/src/graph/Graph.js index 2da33c92..3922a17d 100644 --- a/src/graph/Graph.js +++ b/src/graph/Graph.js @@ -640,27 +640,28 @@ Graph.prototype._onDragStart = function () { } // create an array with the selected nodes and their original location and status - var me = this; - this.selection.forEach(function (id) { - var node = me.nodes[id]; - if (node) { - var s = { - id: id, - node: node, - - // store original x, y, xFixed and yFixed, make the node temporarily Fixed - x: node.x, - y: node.y, - xFixed: node.xFixed, - yFixed: node.yFixed - }; - - node.xFixed = true; - node.yFixed = true; - - drag.selection.push(s); + for (var objectId in this.selectionObj) { + if (this.selectionObj.hasOwnProperty(objectId)) { + var object = this.selectionObj[objectId]; + if (object instanceof Node) { + var s = { + id: object.id, + node: object, + + // store original x, y, xFixed and yFixed, make the node temporarily Fixed + x: object.x, + y: object.y, + xFixed: object.xFixed, + yFixed: object.yFixed + }; + + object.xFixed = true; + object.yFixed = true; + + drag.selection.push(s); + } } - }); + } } }; @@ -2003,7 +2004,6 @@ Graph.prototype._loadSectorSystem = function() { * @private */ Graph.prototype._loadSelectionSystem = function() { - this.selection = []; this.selectionObj = {}; for (var mixinFunction in SelectionMixin) { diff --git a/src/graph/SelectionMixin.js b/src/graph/SelectionMixin.js index 491298d3..072b4295 100644 --- a/src/graph/SelectionMixin.js +++ b/src/graph/SelectionMixin.js @@ -108,7 +108,7 @@ var SelectionMixin = { _getNodeAt : function (pointer) { // we first check if this is an navigationUI element var positionObject = this._pointerToPositionObject(pointer); - overlappingNodes = this._getAllNodesOverlappingWith(positionObject); + var overlappingNodes = this._getAllNodesOverlappingWith(positionObject); // if there are overlapping nodes, select the last one, this is the // one which is drawn on top of the others @@ -121,6 +121,36 @@ var SelectionMixin = { }, + /** + * retrieve all edges overlapping with given object, selector is around center + * @param {Object} object An object with parameters left, top, right, bottom + * @return {Number[]} An array with id's of the overlapping nodes + * @private + */ + _getEdgesOverlappingWith : function (object, overlappingEdges) { + var edges = this.edges; + for (var edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + if (edges[edgeId].isOverlappingWith(object)) { + overlappingEdges.push(edgeId); + } + } + } + }, + + + /** + * retrieve all nodes overlapping with given object + * @param {Object} object An object with parameters left, top, right, bottom + * @return {Number[]} An array with id's of the overlapping nodes + * @private + */ + _getAllEdgesOverlappingWith : function (object) { + var overlappingEdges = []; + this._doInAllActiveSectors("_getEdgesOverlappingWith",object,overlappingEdges); + return overlappingEdges; + }, + /** * Place holder. To implement change the _getNodeAt to a _getObjectAt. Have the _getObjectAt call * _getNodeAt and _getEdgesAt, then priortize the selection to user preferences. @@ -130,18 +160,25 @@ var SelectionMixin = { * @private */ _getEdgeAt : function(pointer) { - return null; + var positionObject = this._pointerToPositionObject(pointer); + var overlappingEdges = this._getAllEdgesOverlappingWith(positionObject); + + if (overlappingEdges.length > 0) { + return this.edges[overlappingEdges[overlappingEdges.length - 1]]; + } + else { + return null; + } }, /** - * Add object to the selection array. The this.selection id array may not be needed. + * Add object to the selection array. * * @param obj * @private */ _addToSelection : function(obj) { - this.selection.push(obj.id); this.selectionObj[obj.id] = obj; }, @@ -153,12 +190,6 @@ var SelectionMixin = { * @private */ _removeFromSelection : function(obj) { - for (var i = 0; i < this.selection.length; i++) { - if (obj.id == this.selection[i]) { - this.selection.splice(i,1); - break; - } - } delete this.selectionObj[obj.id]; }, @@ -174,10 +205,9 @@ var SelectionMixin = { doNotTrigger = false; } - this.selection = []; - for (var objId in this.selectionObj) { - if (this.selectionObj.hasOwnProperty(objId)) { - this.selectionObj[objId].unselect(); + for (var objectId in this.selectionObj) { + if (this.selectionObj.hasOwnProperty(objectId)) { + this.selectionObj[objectId].unselect(); } } this.selectionObj = {}; @@ -195,25 +225,55 @@ var SelectionMixin = { * @private */ _selectionIsEmpty : function() { - if (this.selection.length == 0) { - return true; + for(var objectId in this.selectionObj) { + if(this.selectionObj.hasOwnProperty(objectId)) { + return false; + } } - else { - return false; + return true; + }, + + /** + * select the edges connected to the node that is being selected + * + * @param {Node} node + * @private + */ + _selectConnectedEdges : function(node) { + for (var i = 0; i < node.dynamicEdges.length; i++) { + var edge = node.dynamicEdges[i]; + edge.select(); + this._addToSelection(edge); } }, + /** + * unselect the edges connected to the node that is being selected + * + * @param {Node} node + * @private + */ + _unselectConnectedEdges : function(node) { + for (var i = 0; i < node.dynamicEdges.length; i++) { + var edge = node.dynamicEdges[i]; + edge.unselect(); + this._removeFromSelection(edge); + } + }, + + + /** * This is called when someone clicks on a node. either select or deselect it. * If there is an existing selection and we don't want to append to it, clear the existing selection * - * @param {Node} node + * @param {Node || Edge} object * @param {Boolean} append * @param {Boolean} [doNotTrigger] | ignore trigger * @private */ - _selectNode : function(node, append, doNotTrigger) { + _selectObject : function(object, append, doNotTrigger) { if (doNotTrigger === undefined) { doNotTrigger = false; } @@ -222,14 +282,16 @@ var SelectionMixin = { this._unselectAll(true); } - - if (node.selected == false) { - node.select(); - this._addToSelection(node); + if (object.selected == false) { + object.select(); + this._addToSelection(object); + if (object instanceof Node) { + this._selectConnectedEdges(object); + } } else { - node.unselect(); - this._removeFromSelection(node); + object.unselect(); + this._removeFromSelection(object); } if (doNotTrigger == false) { this._trigger('select'); @@ -264,10 +326,16 @@ var SelectionMixin = { _handleTap : function(pointer) { var node = this._getNodeAt(pointer); if (node != null) { - this._selectNode(node,false); + this._selectObject(node,false); } else { - this._unselectAll(); + var edge = this._getEdgeAt(pointer); + if (edge != null) { + this._selectObject(edge,false); + } + else { + this._unselectAll(); + } } this._redraw(); }, @@ -299,7 +367,13 @@ var SelectionMixin = { _handleOnHold : function(pointer) { var node = this._getNodeAt(pointer); if (node != null) { - this._selectNode(node,true); + this._selectObject(node,true); + } + else { + var edge = this._getEdgeAt(pointer); + if (edge != null) { + this._selectObject(edge,true); + } } this._redraw(); }, @@ -321,12 +395,72 @@ var SelectionMixin = { /** * - * retrieve the currently selected nodes + * retrieve the currently selected objects * @return {Number[] | String[]} selection An array with the ids of the * selected nodes. */ getSelection : function() { - return this.selection.concat([]); + var nodeIdString = this.getSelectedNodes(); + /* + var edgeIdString = this.getSelectedEdges(); + + var idString = ""; + if (nodeIdString != "") { + idString = idString.concat("Nodes: ",nodeIdString); + + if (edgeIdString != "") { + idString = idString.concat("; "); + } + } + if (edgeIdString != "") { + idString = idString.concat("Edges: ",edgeIdString); + } + */ + return nodeIdString + }, + + /** + * + * retrieve the currently selected nodes + * @return {String} selection An array with the ids of the + * selected nodes. + */ + getSelectedNodes : function() { + var idString = "", i = 0; + for(var objectId in this.selectionObj) { + if(this.selectionObj.hasOwnProperty(objectId)) { + if (this.selectionObj[objectId] instanceof Node) { + if (i != 0) { + idString = idString.concat(", "); + } + idString = idString.concat(String(objectId)); + i++; + } + } + } + return idString + }, + + /** + * + * retrieve the currently selected edges + * @return {String} selection An array with the ids of the + * selected nodes. + */ + getSelectedEdges : function() { + var idString = "", i = 0; + for(var objectId in this.selectionObj) { + if(this.selectionObj.hasOwnProperty(objectId)) { + if (this.selectionObj[objectId] instanceof Edge) { + if (i != 0) { + idString = idString.concat(", "); + } + idString = idString.concat(String(objectId)); + i++; + } + } + } + return idString }, /** @@ -340,8 +474,6 @@ var SelectionMixin = { }, /** - * // TODO: rework this function, it is from the old system - * * select zero or more nodes * @param {Number[] | String[]} selection An array with the ids of the * selected nodes. @@ -362,7 +494,7 @@ var SelectionMixin = { if (!node) { throw new RangeError('Node with id "' + id + '" not found'); } - this._selectNode(node,true,true); + this._selectObject(node,true,true); } this.redraw(); @@ -370,135 +502,28 @@ var SelectionMixin = { /** - * TODO: rework this function, it is from the old system - * * Validate the selection: remove ids of nodes which no longer exist * @private */ _updateSelection : function () { - var i = 0; - while (i < this.selection.length) { - var nodeId = this.selection[i]; - if (!this.nodes.hasOwnProperty(nodeId)) { - this.selection.splice(i, 1); - delete this.selectionObj[nodeId]; - } - else { - i++; - } - } - } - - - /** - * Unselect selected nodes. If no selection array is provided, all nodes - * are unselected - * @param {Object[]} selection Array with selection objects, each selection - * object has a parameter row. Optional - * @param {Boolean} triggerSelect If true (default), the select event - * is triggered when nodes are unselected - * @return {Boolean} changed True if the selection is changed - * @private - */ - /* _unselectNodes : function(selection, triggerSelect) { - var changed = false; - var i, iMax, id; - - if (selection) { - // remove provided selections - for (i = 0, iMax = selection.length; i < iMax; i++) { - id = selection[i]; - if (this.nodes.hasOwnProperty(id)) { - this.nodes[id].unselect(); - } - var j = 0; - while (j < this.selection.length) { - if (this.selection[j] == id) { - this.selection.splice(j, 1); - changed = true; - } - else { - j++; + for(var objectId in this.selectionObj) { + if(this.selectionObj.hasOwnProperty(objectId)) { + if (this.selectionObj[objectId] instanceof Node) { + if (!this.nodes.hasOwnProperty(objectId)) { + delete this.selectionObj[objectId]; } } - } - } - else if (this.selection && this.selection.length) { - // remove all selections - for (i = 0, iMax = this.selection.length; i < iMax; i++) { - id = this.selection[i]; - if (this.nodes.hasOwnProperty(id)) { - this.nodes[id].unselect(); - } - changed = true; - } - this.selection = []; - } - - if (changed && (triggerSelect == true || triggerSelect == undefined)) { - // fire the select event - this._trigger('select'); - } - - return changed; - }, -*/ -/** - * select all nodes on given location x, y - * @param {Array} selection an array with node ids - * @param {boolean} append If true, the new selection will be appended to the - * current selection (except for duplicate entries) - * @return {Boolean} changed True if the selection is changed - * @private - */ -/* _selectNodes : function(selection, append) { - var changed = false; - var i, iMax; - - // TODO: the selectNodes method is a little messy, rework this - - // check if the current selection equals the desired selection - var selectionAlreadyThere = true; - if (selection.length != this.selection.length) { - selectionAlreadyThere = false; - } - else { - for (i = 0, iMax = Math.min(selection.length, this.selection.length); i < iMax; i++) { - if (selection[i] != this.selection[i]) { - selectionAlreadyThere = false; - break; + else { // assuming only edges and nodes are selected + if (!this.edges.hasOwnProperty(objectId)) { + delete this.selectionObj[objectId]; + } } } } - if (selectionAlreadyThere) { - return changed; - } - - if (append == undefined || append == false) { - // first deselect any selected node - var triggerSelect = false; - changed = this._unselectNodes(undefined, triggerSelect); - } + } - for (i = 0, iMax = selection.length; i < iMax; i++) { - // add each of the new selections, but only when they are not duplicate - var id = selection[i]; - var isDuplicate = (this.selection.indexOf(id) != -1); - if (!isDuplicate) { - this.nodes[id].select(); - this.selection.push(id); - changed = true; - } - } - if (changed) { - // fire the select event - this._trigger('select'); - } - return changed; - }, - */ }; From 181516e2dd1defa89dc36cec6bf4aad02eacfc13 Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Thu, 30 Jan 2014 15:18:31 +0100 Subject: [PATCH 26/52] added edge selection and removed this.selection from the graph --- dist/vis.js | 44 +++++-------------- examples/graph/02_random_nodes.html | 2 +- .../18_fully_random_nodes_clustering.html | 2 +- .../graph/19_scale_free_graph_clustering.html | 2 +- examples/graph/20_UI_example.html | 2 +- src/graph/SelectionMixin.js | 40 +++++------------ 6 files changed, 26 insertions(+), 66 deletions(-) diff --git a/dist/vis.js b/dist/vis.js index 1cb8c8c3..f1ec8ecb 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -4,8 +4,8 @@ * * A dynamic, browser-based visualization library. * - * @version 0.4.0-SNAPSHOT - * @date 2014-01-30 + * @version @@version + * @date @@date * * @license * Copyright (C) 2011-2014 Almende B.V, http://almende.com @@ -12581,23 +12581,11 @@ var SelectionMixin = { * selected nodes. */ getSelection : function() { - var nodeIdString = this.getSelectedNodes(); - /* - var edgeIdString = this.getSelectedEdges(); + var nodeIds = this.getSelectedNodes(); - var idString = ""; - if (nodeIdString != "") { - idString = idString.concat("Nodes: ",nodeIdString); + var edgeIds = this.getSelectedEdges(); - if (edgeIdString != "") { - idString = idString.concat("; "); - } - } - if (edgeIdString != "") { - idString = idString.concat("Edges: ",edgeIdString); - } - */ - return nodeIdString + return {nodes:nodeIds, edges:edgeIds}; }, /** @@ -12607,41 +12595,33 @@ var SelectionMixin = { * selected nodes. */ getSelectedNodes : function() { - var idString = "", i = 0; + var idArray = []; for(var objectId in this.selectionObj) { if(this.selectionObj.hasOwnProperty(objectId)) { if (this.selectionObj[objectId] instanceof Node) { - if (i != 0) { - idString = idString.concat(", "); - } - idString = idString.concat(String(objectId)); - i++; + idArray.push(objectId); } } } - return idString + return idArray }, /** * * retrieve the currently selected edges - * @return {String} selection An array with the ids of the + * @return {Array} selection An array with the ids of the * selected nodes. */ getSelectedEdges : function() { - var idString = "", i = 0; + var idArray = []; for(var objectId in this.selectionObj) { if(this.selectionObj.hasOwnProperty(objectId)) { if (this.selectionObj[objectId] instanceof Edge) { - if (i != 0) { - idString = idString.concat(", "); - } - idString = idString.concat(String(objectId)); - i++; + idArray.push(objectId); } } } - return idString + return idArray }, /** diff --git a/examples/graph/02_random_nodes.html b/examples/graph/02_random_nodes.html index fdf27193..6a8a3a0f 100755 --- a/examples/graph/02_random_nodes.html +++ b/examples/graph/02_random_nodes.html @@ -96,7 +96,7 @@ // add event listeners vis.events.addListener(graph, 'select', function(params) { document.getElementById('selection').innerHTML = - 'Selection: ' + graph.getSelection(); + 'Selection: ' + JSON.stringify(graph.getSelection()); }); } diff --git a/examples/graph/18_fully_random_nodes_clustering.html b/examples/graph/18_fully_random_nodes_clustering.html index 8bfd679d..0ee22562 100644 --- a/examples/graph/18_fully_random_nodes_clustering.html +++ b/examples/graph/18_fully_random_nodes_clustering.html @@ -65,7 +65,7 @@ // add event listeners vis.events.addListener(graph, 'select', function(params) { document.getElementById('selection').innerHTML = - 'Selection: ' + graph.getSelection(); + 'Selection: ' + JSON.stringify(graph.getSelection()); }); } diff --git a/examples/graph/19_scale_free_graph_clustering.html b/examples/graph/19_scale_free_graph_clustering.html index 2bce437e..efe43b8f 100644 --- a/examples/graph/19_scale_free_graph_clustering.html +++ b/examples/graph/19_scale_free_graph_clustering.html @@ -102,7 +102,7 @@ // add event listeners vis.events.addListener(graph, 'select', function(params) { document.getElementById('selection').innerHTML = - 'Selection: ' + graph.getSelection(); + 'Selection: ' + JSON.stringify(graph.getSelection()); }); } diff --git a/examples/graph/20_UI_example.html b/examples/graph/20_UI_example.html index bd94dc4d..dd24eb2f 100644 --- a/examples/graph/20_UI_example.html +++ b/examples/graph/20_UI_example.html @@ -122,7 +122,7 @@ // add event listeners vis.events.addListener(graph, 'select', function(params) { document.getElementById('selection').innerHTML = - 'Selection: ' + graph.getSelection(); + 'Selection: ' + JSON.stringify(graph.getSelection()); }); } diff --git a/src/graph/SelectionMixin.js b/src/graph/SelectionMixin.js index 072b4295..5a0154c5 100644 --- a/src/graph/SelectionMixin.js +++ b/src/graph/SelectionMixin.js @@ -400,23 +400,11 @@ var SelectionMixin = { * selected nodes. */ getSelection : function() { - var nodeIdString = this.getSelectedNodes(); - /* - var edgeIdString = this.getSelectedEdges(); + var nodeIds = this.getSelectedNodes(); - var idString = ""; - if (nodeIdString != "") { - idString = idString.concat("Nodes: ",nodeIdString); + var edgeIds = this.getSelectedEdges(); - if (edgeIdString != "") { - idString = idString.concat("; "); - } - } - if (edgeIdString != "") { - idString = idString.concat("Edges: ",edgeIdString); - } - */ - return nodeIdString + return {nodes:nodeIds, edges:edgeIds}; }, /** @@ -426,41 +414,33 @@ var SelectionMixin = { * selected nodes. */ getSelectedNodes : function() { - var idString = "", i = 0; + var idArray = []; for(var objectId in this.selectionObj) { if(this.selectionObj.hasOwnProperty(objectId)) { if (this.selectionObj[objectId] instanceof Node) { - if (i != 0) { - idString = idString.concat(", "); - } - idString = idString.concat(String(objectId)); - i++; + idArray.push(objectId); } } } - return idString + return idArray }, /** * * retrieve the currently selected edges - * @return {String} selection An array with the ids of the + * @return {Array} selection An array with the ids of the * selected nodes. */ getSelectedEdges : function() { - var idString = "", i = 0; + var idArray = []; for(var objectId in this.selectionObj) { if(this.selectionObj.hasOwnProperty(objectId)) { if (this.selectionObj[objectId] instanceof Edge) { - if (i != 0) { - idString = idString.concat(", "); - } - idString = idString.concat(String(objectId)); - i++; + idArray.push(objectId); } } } - return idString + return idArray }, /** From aee5908912ad126d4e57a0aea5fa0d2b5e4ed6e8 Mon Sep 17 00:00:00 2001 From: josdejong Date: Fri, 31 Jan 2014 16:00:20 +0100 Subject: [PATCH 27/52] Released version 0.4.0 --- dist/img/downarrow.png | Bin 0 -> 4460 bytes dist/img/leftarrow.png | Bin 0 -> 4531 bytes dist/img/minus.png | Bin 0 -> 4147 bytes dist/img/plus.png | Bin 0 -> 4341 bytes dist/img/rightarrow.png | Bin 0 -> 4514 bytes dist/img/uparrow.png | Bin 0 -> 4461 bytes dist/img/zoomExtends.png | Bin 0 -> 4464 bytes dist/vis.css | 8 + dist/vis.js | 10619 +++++++++++----- dist/vis.min.js | 18 +- docs/graph.html | 964 +- docs/img/vis_overview.odg | Bin 32645 -> 17762 bytes docs/img/vis_overview.png | Bin 49562 -> 64008 bytes docs/index.html | 2 +- docs/timeline.html | 151 +- download/vis.zip | Bin 941597 -> 1021812 bytes examples/graph/02_random_nodes.html | 13 +- examples/graph/07_selections.html | 8 +- examples/graph/17_network_info.html | 2 +- .../18_fully_random_nodes_clustering.html | 102 + .../graph/19_scale_free_graph_clustering.html | 141 + examples/graph/20_navigation.html | 181 + examples/graph/index.html | 3 + examples/timeline/02_dataset.html | 16 +- examples/timeline/06_event_listeners.html | 53 + examples/timeline/index.html | 1 + index.html | 2 +- 27 files changed, 8716 insertions(+), 3568 deletions(-) create mode 100644 dist/img/downarrow.png create mode 100644 dist/img/leftarrow.png create mode 100644 dist/img/minus.png create mode 100644 dist/img/plus.png create mode 100644 dist/img/rightarrow.png create mode 100644 dist/img/uparrow.png create mode 100644 dist/img/zoomExtends.png create mode 100644 examples/graph/18_fully_random_nodes_clustering.html create mode 100644 examples/graph/19_scale_free_graph_clustering.html create mode 100644 examples/graph/20_navigation.html create mode 100644 examples/timeline/06_event_listeners.html diff --git a/dist/img/downarrow.png b/dist/img/downarrow.png new file mode 100644 index 0000000000000000000000000000000000000000..e77d5e6d4157b12a5b2fa08a9fc138f0ab9eb4e7 GIT binary patch literal 4460 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�EM>-Bgb&Rym2{we-b7Oawc(c4k4MzLw~<#m(JZ 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 Re)#|Z002ovPDHLkV1iMdkGuc? literal 0 HcmV?d00001 diff --git a/dist/img/minus.png b/dist/img/minus.png new file mode 100644 index 0000000000000000000000000000000000000000..30698076b9ac59f0880752ddc13af3f6bf062403 GIT binary patch literal 4147 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 literal 0 HcmV?d00001 diff --git a/dist/img/plus.png b/dist/img/plus.png new file mode 100644 index 0000000000000000000000000000000000000000..f7ab2a334e566b6deb9657d7d8370f591bfb81bc GIT binary patch literal 4341 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 literal 0 HcmV?d00001 diff --git a/dist/img/rightarrow.png b/dist/img/rightarrow.png new file mode 100644 index 0000000000000000000000000000000000000000..c3a209d8b0a58355305aae03b5520a1e070d8eab GIT binary patch literal 4514 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 literal 0 HcmV?d00001 diff --git a/dist/img/zoomExtends.png b/dist/img/zoomExtends.png new file mode 100644 index 0000000000000000000000000000000000000000..74595c6358448fbdcfbd62629084841ca7e8b8a9 GIT binary patch literal 4464 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 select it + selection.push(item.id); + } + else { + // item is already selected -> deselect it + selection.splice(index, 1); + } + this.setSelection(selection); + + this._trigger('select', { + items: this.getSelection() + }); + + event.stopPropagation(); +}; + +/** + * Find an item from an event target: + * searches for the attribute 'timeline-item' in the event target's element tree + * @param {Event} event + * @return {Item | null| item + * @private + */ +Timeline.prototype._itemFromTarget = function _itemFromTarget (event) { + var target = event.target; + while (target) { + if (target.hasOwnProperty('timeline-item')) { + return target['timeline-item']; + } + target = target.parentNode; + } + + return null; +}; (function(exports) { /** * Parse a text source containing data in DOT language into a JSON object. @@ -8673,6 +8955,8 @@ function Node(properties, imagelist, grouplist, constants) { this.selected = false; this.edges = []; // all edges connected to this node + this.dynamicEdges = []; + this.reroutedEdges = {}; this.group = constants.nodes.group; this.fontSize = constants.nodes.fontSize; @@ -8689,24 +8973,53 @@ function Node(properties, imagelist, grouplist, constants) { this.y = 0; this.xFixed = false; this.yFixed = false; + this.horizontalAlignLeft = true; // these are for the navigation controls + this.verticalAlignTop = true; // these are for the navigation controls this.radius = constants.nodes.radius; + this.baseRadiusValue = constants.nodes.radius; this.radiusFixed = false; this.radiusMin = constants.nodes.radiusMin; this.radiusMax = constants.nodes.radiusMax; this.imagelist = imagelist; + this.grouplist = grouplist; this.setProperties(properties, constants); + // creating the variables for clustering + this.resetCluster(); + this.dynamicEdgesLength = 0; + this.clusterSession = 0; + this.clusterSizeWidthFactor = constants.clustering.nodeScaling.width; + this.clusterSizeHeightFactor = constants.clustering.nodeScaling.height; + this.clusterSizeRadiusFactor = constants.clustering.nodeScaling.radius; + // mass, force, velocity - this.mass = 50; // kg (mass is adjusted for the number of connected edges) + this.mass = 1; // kg (mass is adjusted for the number of connected edges) this.fx = 0.0; // external force x this.fy = 0.0; // external force y this.vx = 0.0; // velocity x this.vy = 0.0; // velocity y this.minForce = constants.minForce; - this.damping = 0.9; // damping factor + this.damping = 0.9; + this.dampingFactor = 75; + + this.graphScaleInv = 1; + this.canvasTopLeft = {"x": -300, "y": -300}; + this.canvasBottomRight = {"x": 300, "y": 300}; +} + +/** + * (re)setting the clustering variables and objects + */ +Node.prototype.resetCluster = function() { + // clustering variables + this.formationScale = undefined; // this is used to determine when to open the cluster + this.clusterSize = 1; // this signifies the total amount of nodes in this cluster + this.containedNodes = {}; + this.containedEdges = {}; + this.clusterSessions = []; }; /** @@ -8717,6 +9030,10 @@ Node.prototype.attachEdge = function(edge) { if (this.edges.indexOf(edge) == -1) { this.edges.push(edge); } + if (this.dynamicEdges.indexOf(edge) == -1) { + this.dynamicEdges.push(edge); + } + this.dynamicEdgesLength = this.dynamicEdges.length; this._updateMass(); }; @@ -8728,7 +9045,9 @@ Node.prototype.detachEdge = function(edge) { var index = this.edges.indexOf(edge); if (index != -1) { this.edges.splice(index, 1); + this.dynamicEdges.splice(index, 1); } + this.dynamicEdgesLength = this.dynamicEdges.length; this._updateMass(); }; @@ -8738,7 +9057,7 @@ Node.prototype.detachEdge = function(edge) { * @private */ Node.prototype._updateMass = function() { - this.mass = 50 + 20 * this.edges.length; // kg + this.mass = 1 + 0.6 * this.edges.length; // kg }; /** @@ -8750,15 +9069,20 @@ Node.prototype.setProperties = function(properties, constants) { if (!properties) { return; } - + this.originalLabel = undefined; // basic properties - if (properties.id != undefined) {this.id = properties.id;} - if (properties.label != undefined) {this.label = properties.label;} - if (properties.title != undefined) {this.title = properties.title;} - if (properties.group != undefined) {this.group = properties.group;} - if (properties.x != undefined) {this.x = properties.x;} - if (properties.y != undefined) {this.y = properties.y;} - if (properties.value != undefined) {this.value = properties.value;} + if (properties.id !== undefined) {this.id = properties.id;} + if (properties.label !== undefined) {this.label = properties.label; this.originalLabel = properties.label;} + if (properties.title !== undefined) {this.title = properties.title;} + if (properties.group !== undefined) {this.group = properties.group;} + if (properties.x !== undefined) {this.x = properties.x;} + if (properties.y !== undefined) {this.y = properties.y;} + if (properties.value !== undefined) {this.value = properties.value;} + + // navigation controls properties + if (properties.horizontalAlignLeft !== undefined) {this.horizontalAlignLeft = properties.horizontalAlignLeft;} + if (properties.verticalAlignTop !== undefined) {this.verticalAlignTop = properties.verticalAlignTop;} + if (properties.triggerFunction !== undefined) {this.triggerFunction = properties.triggerFunction;} if (this.id === undefined) { throw "Node must have an id"; @@ -8775,17 +9099,16 @@ Node.prototype.setProperties = function(properties, constants) { } // individual shape properties - if (properties.shape != undefined) {this.shape = properties.shape;} - if (properties.image != undefined) {this.image = properties.image;} - if (properties.radius != undefined) {this.radius = properties.radius;} - if (properties.color != undefined) {this.color = Node.parseColor(properties.color);} - - if (properties.fontColor != undefined) {this.fontColor = properties.fontColor;} - if (properties.fontSize != undefined) {this.fontSize = properties.fontSize;} - if (properties.fontFace != undefined) {this.fontFace = properties.fontFace;} + if (properties.shape !== undefined) {this.shape = properties.shape;} + if (properties.image !== undefined) {this.image = properties.image;} + if (properties.radius !== undefined) {this.radius = properties.radius;} + if (properties.color !== undefined) {this.color = Node.parseColor(properties.color);} + if (properties.fontColor !== undefined) {this.fontColor = properties.fontColor;} + if (properties.fontSize !== undefined) {this.fontSize = properties.fontSize;} + if (properties.fontFace !== undefined) {this.fontFace = properties.fontFace;} - if (this.image != undefined) { + if (this.image !== undefined) { if (this.imagelist) { this.imageObj = this.imagelist.load(this.image); } @@ -8794,9 +9117,9 @@ Node.prototype.setProperties = function(properties, constants) { } } - this.xFixed = this.xFixed || (properties.x != undefined); - this.yFixed = this.yFixed || (properties.y != undefined); - this.radiusFixed = this.radiusFixed || (properties.radius != undefined); + this.xFixed = this.xFixed || (properties.x !== undefined); + this.yFixed = this.yFixed || (properties.y !== undefined); + this.radiusFixed = this.radiusFixed || (properties.radius !== undefined); if (this.shape == 'image') { this.radiusMin = constants.nodes.widthMin; @@ -8819,7 +9142,6 @@ Node.prototype.setProperties = function(properties, constants) { case 'star': this.draw = this._drawStar; this.resize = this._resizeShape; break; default: this.draw = this._drawEllipse; this.resize = this._resizeEllipse; break; } - // reset the size of the node, this can be changed this._reset(); }; @@ -8847,6 +9169,7 @@ Node.parseColor = function(color) { c = {}; c.background = color.background || 'white'; c.border = color.border || c.background; + if (util.isString(color.highlight)) { c.highlight = { border: color.highlight, @@ -8859,6 +9182,7 @@ Node.parseColor = function(color) { c.highlight.border = color.highlight && color.highlight.border || c.border; } } + return c; }; @@ -8878,13 +9202,21 @@ Node.prototype.unselect = function() { this._reset(); }; + /** * Reset the calculated size of the node, forces it to recalculate its size - * @private */ -Node.prototype._reset = function() { - this.width = undefined; - this.height = undefined; +Node.prototype.clearSizeCache = function() { + this._reset(); +}; + +/** + * Reset the calculated size of the node, forces it to recalculate its size + * @private + */ +Node.prototype._reset = function() { + this.width = undefined; + this.height = undefined; }; /** @@ -8974,15 +9306,15 @@ Node.prototype.discreteStep = function(interval) { if (!this.xFixed) { var dx = -this.damping * this.vx; // damping force var ax = (this.fx + dx) / this.mass; // acceleration - this.vx += ax / interval; // velocity - this.x += this.vx / interval; // position + this.vx += ax * interval; // velocity + this.x += this.vx * interval; // position } if (!this.yFixed) { var dy = -this.damping * this.vy; // damping force var ay = (this.fy + dy) / this.mass; // acceleration - this.vy += ay / interval; // velocity - this.y += this.vy / interval; // position + this.vy += ay * interval; // velocity + this.y += this.vy * interval; // position } }; @@ -9002,9 +9334,16 @@ Node.prototype.isFixed = function() { */ // TODO: replace this method with calculating the kinetic energy Node.prototype.isMoving = function(vmin) { - return (Math.abs(this.vx) > vmin || Math.abs(this.vy) > vmin || - (!this.xFixed && Math.abs(this.fx) > this.minForce) || - (!this.yFixed && Math.abs(this.fy) > this.minForce)); + + if (Math.abs(this.vx) > vmin || Math.abs(this.vy) > vmin) { +// console.log(vmin,this.vx,this.vy); + return true; + } + else { + this.vx = 0; this.vy = 0; + return false; + } + //return (Math.abs(this.vx) > vmin || Math.abs(this.vy) > vmin); }; /** @@ -9052,6 +9391,7 @@ Node.prototype.setValueRange = function(min, max) { this.radius = (this.value - min) * scale + this.radiusMin; } } + this.baseRadiusValue = this.radius; }; /** @@ -9078,20 +9418,28 @@ Node.prototype.resize = function(ctx) { * @return {boolean} True if location is located on node */ Node.prototype.isOverlappingWith = function(obj) { - return (this.left < obj.right && - this.left + this.width > obj.left && - this.top < obj.bottom && - this.top + this.height > obj.top); + return (this.left < obj.right && + this.left + this.width > obj.left && + this.top < obj.bottom && + this.top + this.height > obj.top); }; Node.prototype._resizeImage = function (ctx) { // TODO: pre calculate the image size - if (!this.width) { // undefined or 0 + + if (!this.width || !this.height) { // undefined or 0 var width, height; if (this.value) { + this.radius = this.baseRadiusValue; var scale = this.imageObj.height / this.imageObj.width; - width = this.radius || this.imageObj.width; - height = this.radius * scale || this.imageObj.height; + if (scale !== undefined) { + width = this.radius || this.imageObj.width; + height = this.radius * scale || this.imageObj.height; + } + else { + width = 0; + height = 0; + } } else { width = this.imageObj.width; @@ -9099,7 +9447,14 @@ Node.prototype._resizeImage = function (ctx) { } this.width = width; this.height = height; + + if (this.width > 0 && this.height > 0) { + this.width += (this.clusterSize - 1) * this.clusterSizeWidthFactor; + this.height += (this.clusterSize - 1) * this.clusterSizeHeightFactor; + this.radius += (this.clusterSize - 1) * this.clusterSizeRadiusFactor; + } } + }; Node.prototype._drawImage = function (ctx) { @@ -9109,7 +9464,19 @@ Node.prototype._drawImage = function (ctx) { this.top = this.y - this.height / 2; var yLabel; - if (this.imageObj) { + if (this.imageObj.width != 0 ) { + // draw the shade + if (this.clusterSize > 1) { + var lineWidth = ((this.clusterSize > 1) ? 10 : 0.0); + lineWidth *= this.graphScaleInv; + lineWidth = Math.min(0.2 * this.width,lineWidth); + + ctx.globalAlpha = 0.5; + ctx.drawImage(this.imageObj, this.left - lineWidth, this.top - lineWidth, this.width + 2*lineWidth, this.height + 2*lineWidth); + } + + // draw the image + ctx.globalAlpha = 1.0; ctx.drawImage(this.imageObj, this.left, this.top, this.width, this.height); yLabel = this.y + this.height / 2; } @@ -9128,6 +9495,10 @@ Node.prototype._resizeBox = function (ctx) { var textSize = this.getTextSize(ctx); this.width = textSize.width + 2 * margin; this.height = textSize.height + 2 * margin; + + this.width += (this.clusterSize - 1) * 0.5 * this.clusterSizeWidthFactor; + this.height += (this.clusterSize - 1) * 0.5 * this.clusterSizeHeightFactor; +// this.radius += (this.clusterSize - 1) * 0.5 * this.clusterSizeRadiusFactor; } }; @@ -9137,9 +9508,26 @@ Node.prototype._drawBox = function (ctx) { this.left = this.x - this.width / 2; this.top = this.y - this.height / 2; + var clusterLineWidth = 2.5; + var selectionLineWidth = 2; + ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; + + // draw the outer border + if (this.clusterSize > 1) { + ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.graphScaleInv; + ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth); + + ctx.roundRect(this.left-2*ctx.lineWidth, this.top-2*ctx.lineWidth, this.width+4*ctx.lineWidth, this.height+4*ctx.lineWidth, this.radius); + ctx.stroke(); + } + ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.graphScaleInv; + ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth); + ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; - ctx.lineWidth = this.selected ? 2.0 : 1.0; + ctx.roundRect(this.left, this.top, this.width, this.height, this.radius); ctx.fill(); ctx.stroke(); @@ -9155,6 +9543,11 @@ Node.prototype._resizeDatabase = function (ctx) { var size = textSize.width + 2 * margin; this.width = size; this.height = size; + + // scaling used for clustering + this.width += (this.clusterSize - 1) * this.clusterSizeWidthFactor; + this.height += (this.clusterSize - 1) * this.clusterSizeHeightFactor; + this.radius += (this.clusterSize - 1) * this.clusterSizeRadiusFactor; } }; @@ -9163,9 +9556,25 @@ Node.prototype._drawDatabase = function (ctx) { this.left = this.x - this.width / 2; this.top = this.y - this.height / 2; + var clusterLineWidth = 2.5; + var selectionLineWidth = 2; + ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; + + // draw the outer border + if (this.clusterSize > 1) { + ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.graphScaleInv; + ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth); + + ctx.database(this.x - this.width/2 - 2*ctx.lineWidth, this.y - this.height*0.5 - 2*ctx.lineWidth, this.width + 4*ctx.lineWidth, this.height + 4*ctx.lineWidth); + ctx.stroke(); + } + ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.graphScaleInv; + ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth); + ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; - ctx.lineWidth = this.selected ? 2.0 : 1.0; ctx.database(this.x - this.width/2, this.y - this.height*0.5, this.width, this.height); ctx.fill(); ctx.stroke(); @@ -9183,6 +9592,11 @@ Node.prototype._resizeCircle = function (ctx) { this.width = diameter; this.height = diameter; + + // scaling used for clustering +// this.width += (this.clusterSize - 1) * 0.5 * this.clusterSizeWidthFactor; +// this.height += (this.clusterSize - 1) * 0.5 * this.clusterSizeHeightFactor; + this.radius += (this.clusterSize - 1) * 0.5 * this.clusterSizeRadiusFactor; } }; @@ -9191,9 +9605,25 @@ Node.prototype._drawCircle = function (ctx) { this.left = this.x - this.width / 2; this.top = this.y - this.height / 2; + var clusterLineWidth = 2.5; + var selectionLineWidth = 2; + ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; + + // draw the outer border + if (this.clusterSize > 1) { + ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.graphScaleInv; + ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth); + + ctx.circle(this.x, this.y, this.radius+2*ctx.lineWidth); + ctx.stroke(); + } + ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.graphScaleInv; + ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth); + ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; - ctx.lineWidth = this.selected ? 2.0 : 1.0; ctx.circle(this.x, this.y, this.radius); ctx.fill(); ctx.stroke(); @@ -9210,6 +9640,11 @@ Node.prototype._resizeEllipse = function (ctx) { if (this.width < this.height) { this.width = this.height; } + + // scaling used for clustering + this.width += (this.clusterSize - 1) * this.clusterSizeWidthFactor; + this.height += (this.clusterSize - 1) * this.clusterSizeHeightFactor; + this.radius += (this.clusterSize - 1) * this.clusterSizeRadiusFactor; } }; @@ -9218,13 +9653,29 @@ Node.prototype._drawEllipse = function (ctx) { this.left = this.x - this.width / 2; this.top = this.y - this.height / 2; + var clusterLineWidth = 2.5; + var selectionLineWidth = 2; + ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; + + // draw the outer border + if (this.clusterSize > 1) { + ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.graphScaleInv; + ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth); + + ctx.ellipse(this.left-2*ctx.lineWidth, this.top-2*ctx.lineWidth, this.width+4*ctx.lineWidth, this.height+4*ctx.lineWidth); + ctx.stroke(); + } + ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.graphScaleInv; + ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth); + ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; - ctx.lineWidth = this.selected ? 2.0 : 1.0; + ctx.ellipse(this.left, this.top, this.width, this.height); ctx.fill(); ctx.stroke(); - this._label(ctx, this.label, this.x, this.y); }; @@ -9250,9 +9701,15 @@ Node.prototype._drawStar = function (ctx) { Node.prototype._resizeShape = function (ctx) { if (!this.width) { + this.radius = this.baseRadiusValue; var size = 2 * this.radius; this.width = size; this.height = size; + + // scaling used for clustering + this.width += (this.clusterSize - 1) * this.clusterSizeWidthFactor; + this.height += (this.clusterSize - 1) * this.clusterSizeHeightFactor; + this.radius += (this.clusterSize - 1) * 0.5 * this.clusterSizeRadiusFactor; } }; @@ -9262,9 +9719,35 @@ Node.prototype._drawShape = function (ctx, shape) { this.left = this.x - this.width / 2; this.top = this.y - this.height / 2; + var clusterLineWidth = 2.5; + var selectionLineWidth = 2; + var radiusMultiplier = 2; + + // choose draw method depending on the shape + switch (shape) { + case 'dot': radiusMultiplier = 2; break; + case 'square': radiusMultiplier = 2; break; + case 'triangle': radiusMultiplier = 3; break; + case 'triangleDown': radiusMultiplier = 3; break; + case 'star': radiusMultiplier = 4; break; + } + ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; + + // draw the outer border + if (this.clusterSize > 1) { + ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.graphScaleInv; + ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth); + + ctx[shape](this.x, this.y, this.radius + radiusMultiplier * ctx.lineWidth); + ctx.stroke(); + } + ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.graphScaleInv; + ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth); + ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; - ctx.lineWidth = this.selected ? 2.0 : 1.0; ctx[shape](this.x, this.y, this.radius); ctx.fill(); @@ -9281,6 +9764,11 @@ Node.prototype._resizeText = function (ctx) { var textSize = this.getTextSize(ctx); this.width = textSize.width + 2 * margin; this.height = textSize.height + 2 * margin; + + // scaling used for clustering + this.width += (this.clusterSize - 1) * this.clusterSizeWidthFactor; + this.height += (this.clusterSize - 1) * this.clusterSizeHeightFactor; + this.radius += (this.clusterSize - 1) * this.clusterSizeRadiusFactor; } }; @@ -9314,7 +9802,7 @@ Node.prototype._label = function (ctx, text, x, y, align, baseline) { Node.prototype.getTextSize = function(ctx) { - if (this.label != undefined) { + if (this.label !== undefined) { ctx.font = (this.selected ? "bold " : "") + this.fontSize + "px " + this.fontFace; var lines = this.label.split('\n'), @@ -9332,6 +9820,92 @@ Node.prototype.getTextSize = function(ctx) { } }; +/** + * this is used to determine if a node is visible at all. this is used to determine when it needs to be drawn. + * there is a safety margin of 0.3 * width; + * + * @returns {boolean} + */ +Node.prototype.inArea = function() { + if (this.width !== undefined) { + return (this.x + this.width*this.graphScaleInv >= this.canvasTopLeft.x && + this.x - this.width*this.graphScaleInv < this.canvasBottomRight.x && + this.y + this.height*this.graphScaleInv >= this.canvasTopLeft.y && + this.y - this.height*this.graphScaleInv < this.canvasBottomRight.y); + } + else { + return true; + } +} + +/** + * checks if the core of the node is in the display area, this is used for opening clusters around zoom + * @returns {boolean} + */ +Node.prototype.inView = function() { + return (this.x >= this.canvasTopLeft.x && + this.x < this.canvasBottomRight.x && + this.y >= this.canvasTopLeft.y && + this.y < this.canvasBottomRight.y); +} + +/** + * This allows the zoom level of the graph to influence the rendering + * We store the inverted scale and the coordinates of the top left, and bottom right points of the canvas + * + * @param scale + * @param canvasTopLeft + * @param canvasBottomRight + */ +Node.prototype.setScaleAndPos = function(scale,canvasTopLeft,canvasBottomRight) { + this.graphScaleInv = 1.0/scale; + this.canvasTopLeft = canvasTopLeft; + this.canvasBottomRight = canvasBottomRight; +}; + + +/** + * This allows the zoom level of the graph to influence the rendering + * + * @param scale + */ +Node.prototype.setScale = function(scale) { + this.graphScaleInv = 1.0/scale; +}; + +/** + * This function updates the damping parameter for clusters, based ont he + * + * @param {Number} numberOfNodes + */ +Node.prototype.updateDamping = function(numberOfNodes) { + this.damping = (0.8 + 0.1*this.clusterSize * (1 + Math.pow(numberOfNodes,-2))); + this.damping *= this.dampingFactor; +}; + + +/** + * set the velocity at 0. Is called when this node is contained in another during clustering + */ +Node.prototype.clearVelocity = function() { + this.vx = 0; + this.vy = 0; +}; + + +/** + * Basic preservation of (kinectic) energy + * + * @param massBeforeClustering + */ +Node.prototype.updateVelocity = function(massBeforeClustering) { + var energyBefore = this.vx * this.vx * massBeforeClustering; + this.vx = Math.sqrt(energyBefore/this.mass); + energyBefore = this.vy * this.vy * massBeforeClustering; + this.vy = Math.sqrt(energyBefore/this.mass); +}; + + /** * @class Edge * @@ -9360,7 +9934,7 @@ function Edge (properties, graph, constants) { // initialize variables this.id = undefined; this.fromId = undefined; - this.toId = undefined; + this.toId = undefined; this.style = constants.edges.style; this.title = undefined; this.width = constants.edges.width; @@ -9369,6 +9943,12 @@ function Edge (properties, graph, constants) { this.from = null; // a node this.to = null; // a node + + // we use this to be able to reconnect the edge to a cluster if its node is put into a cluster + // by storing the original information we can revert to the original connection when the cluser is opened. + this.originalFromId = []; + this.originalToId = []; + this.connected = false; // Added to support dashed lines @@ -9382,6 +9962,7 @@ function Edge (properties, graph, constants) { this.lengthFixed = false; this.setProperties(properties, constants); + } /** @@ -9394,41 +9975,41 @@ Edge.prototype.setProperties = function(properties, constants) { return; } - if (properties.from != undefined) {this.fromId = properties.from;} - if (properties.to != undefined) {this.toId = properties.to;} + if (properties.from !== undefined) {this.fromId = properties.from;} + if (properties.to !== undefined) {this.toId = properties.to;} - if (properties.id != undefined) {this.id = properties.id;} - if (properties.style != undefined) {this.style = properties.style;} - if (properties.label != undefined) {this.label = properties.label;} + if (properties.id !== undefined) {this.id = properties.id;} + if (properties.style !== undefined) {this.style = properties.style;} + if (properties.label !== undefined) {this.label = properties.label;} if (this.label) { this.fontSize = constants.edges.fontSize; this.fontFace = constants.edges.fontFace; this.fontColor = constants.edges.fontColor; - if (properties.fontColor != undefined) {this.fontColor = properties.fontColor;} - if (properties.fontSize != undefined) {this.fontSize = properties.fontSize;} - if (properties.fontFace != undefined) {this.fontFace = properties.fontFace;} + if (properties.fontColor !== undefined) {this.fontColor = properties.fontColor;} + if (properties.fontSize !== undefined) {this.fontSize = properties.fontSize;} + if (properties.fontFace !== undefined) {this.fontFace = properties.fontFace;} } - if (properties.title != undefined) {this.title = properties.title;} - if (properties.width != undefined) {this.width = properties.width;} - if (properties.value != undefined) {this.value = properties.value;} - if (properties.length != undefined) {this.length = properties.length;} + if (properties.title !== undefined) {this.title = properties.title;} + if (properties.width !== undefined) {this.width = properties.width;} + if (properties.value !== undefined) {this.value = properties.value;} + if (properties.length !== undefined) {this.length = properties.length;} // Added to support dashed lines // David Jordan // 2012-08-08 if (properties.dash) { - if (properties.dash.length != undefined) {this.dash.length = properties.dash.length;} - if (properties.dash.gap != undefined) {this.dash.gap = properties.dash.gap;} - if (properties.dash.altLength != undefined) {this.dash.altLength = properties.dash.altLength;} + if (properties.dash.length !== undefined) {this.dash.length = properties.dash.length;} + if (properties.dash.gap !== undefined) {this.dash.gap = properties.dash.gap;} + if (properties.dash.altLength !== undefined) {this.dash.altLength = properties.dash.altLength;} } - if (properties.color != undefined) {this.color = properties.color;} + if (properties.color !== undefined) {this.color = properties.color;} // A node is connected when it has a from and to node. this.connect(); - this.widthFixed = this.widthFixed || (properties.width != undefined); - this.lengthFixed = this.lengthFixed || (properties.length != undefined); + this.widthFixed = this.widthFixed || (properties.width !== undefined); + this.lengthFixed = this.lengthFixed || (properties.length !== undefined); this.stiffness = 1 / this.length; // set draw method based on style @@ -9596,10 +10177,10 @@ Edge.prototype._drawLine = function(ctx) { */ Edge.prototype._getLineWidth = function() { if (this.from.selected || this.to.selected) { - return Math.min(this.width * 2, this.widthMax); + return Math.min(this.width * 2, this.widthMax)*this.graphScaleInv; } else { - return this.width; + return this.width*this.graphScaleInv; } }; @@ -9677,12 +10258,12 @@ Edge.prototype._drawDashLine = function(ctx) { // draw dashed line ctx.beginPath(); ctx.lineCap = 'round'; - if (this.dash.altLength != undefined) //If an alt dash value has been set add to the array this value + if (this.dash.altLength !== undefined) //If an alt dash value has been set add to the array this value { ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, [this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]); } - else if (this.dash.length != undefined && this.dash.gap != undefined) //If a dash and gap value has been set add to the array this value + else if (this.dash.length !== undefined && this.dash.gap !== undefined) //If a dash and gap value has been set add to the array this value { ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, [this.dash.length,this.dash.gap]); @@ -9935,6 +10516,16 @@ Edge._dist = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point return Math.sqrt(dx*dx + dy*dy); }; + + +/** + * This allows the zoom level of the graph to influence the rendering + * + * @param scale + */ +Edge.prototype.setScale = function(scale) { + this.graphScaleInv = 1.0/scale; +}; /** * Popup is a class to create a popup window with some text * @param {Element} container The container object. @@ -9975,7 +10566,7 @@ function Popup(container, x, y, text) { style.boxShadow = "3px 3px 10px rgba(128, 128, 128, 0.5)"; style.whiteSpace = "nowrap"; this.container.appendChild(this.frame); -}; +} /** * @param {number} x Horizontal position of the popup window @@ -10165,2371 +10756,5073 @@ Images.prototype.load = function(url) { }; /** - * @constructor Graph - * Create a graph visualization, displaying nodes and edges. + * Creation of the SectorMixin var. * - * @param {Element} container The DOM element in which the Graph will - * be created. Normally a div element. - * @param {Object} data An object containing parameters - * {Array} nodes - * {Array} edges - * @param {Object} options Options + * This contains all the functions the Graph object can use to employ the sector system. + * The sector system is always used by Graph, though the benefits only apply to the use of clustering. + * If clustering is not used, there is no overhead except for a duplicate object with references to nodes and edges. + * + * Alex de Mulder + * 21-01-2013 */ -function Graph (container, data, options) { - // create variables and set default values - this.containerElement = container; - this.width = '100%'; - this.height = '100%'; - this.refreshRate = 50; // milliseconds - this.stabilize = true; // stabilize before displaying the graph - this.selectable = true; - - // set constant values - this.constants = { - nodes: { - radiusMin: 5, - radiusMax: 20, - radius: 5, - distance: 100, // px - shape: 'ellipse', - image: undefined, - widthMin: 16, // px - widthMax: 64, // px - fontColor: 'black', - fontSize: 14, // px - //fontFace: verdana, - fontFace: 'arial', - color: { - border: '#2B7CE9', - background: '#97C2FC', - highlight: { - border: '#2B7CE9', - background: '#D2E5FF' - } - }, - borderColor: '#2B7CE9', - backgroundColor: '#97C2FC', - highlightColor: '#D2E5FF', - group: undefined - }, - edges: { - widthMin: 1, - widthMax: 15, - width: 1, - style: 'line', - color: '#343434', - fontColor: '#343434', - fontSize: 14, // px - fontFace: 'arial', - //distance: 100, //px - length: 100, // px - dash: { - length: 10, - gap: 5, - altLength: undefined - } - }, - minForce: 0.05, - minVelocity: 0.02, // px/s - maxIterations: 1000 // maximum number of iteration to stabilize - }; +var SectorMixin = { - var graph = this; - this.nodes = {}; // object with Node objects - this.edges = {}; // object with Edge objects - // TODO: create a counter to keep track on the number of nodes having values - // TODO: create a counter to keep track on the number of nodes currently moving - // TODO: create a counter to keep track on the number of edges having values + /** + * This function is only called by the setData function of the Graph object. + * This loads the global references into the active sector. This initializes the sector. + * + * @private + */ + _putDataInSector : function() { + this.sectors["active"][this._sector()].nodes = this.nodes; + this.sectors["active"][this._sector()].edges = this.edges; + this.sectors["active"][this._sector()].nodeIndices = this.nodeIndices; + }, - this.nodesData = null; // A DataSet or DataView - this.edgesData = null; // A DataSet or DataView - // create event listeners used to subscribe on the DataSets of the nodes and edges - var me = this; - this.nodesListeners = { - 'add': function (event, params) { - me._addNodes(params.items); - me.start(); - }, - 'update': function (event, params) { - me._updateNodes(params.items); - me.start(); - }, - 'remove': function (event, params) { - me._removeNodes(params.items); - me.start(); + /** + * /** + * This function sets the global references to nodes, edges and nodeIndices back to + * those of the supplied (active) sector. If a type is defined, do the specific type + * + * @param {String} sectorId + * @param {String} [sectorType] | "active" or "frozen" + * @private + */ + _switchToSector : function(sectorId, sectorType) { + if (sectorType === undefined || sectorType == "active") { + this._switchToActiveSector(sectorId); } - }; - this.edgesListeners = { - 'add': function (event, params) { - me._addEdges(params.items); - me.start(); - }, - 'update': function (event, params) { - me._updateEdges(params.items); - me.start(); - }, - 'remove': function (event, params) { - me._removeEdges(params.items); - me.start(); + else { + this._switchToFrozenSector(sectorId); } - }; + }, - this.groups = new Groups(); // object with groups - this.images = new Images(); // object with images - this.images.setOnloadCallback(function () { - graph._redraw(); - }); - // properties of the data - this.moving = false; // True if any of the nodes have an undefined position + /** + * This function sets the global references to nodes, edges and nodeIndices back to + * those of the supplied active sector. + * + * @param sectorId + * @private + */ + _switchToActiveSector : function(sectorId) { + this.nodeIndices = this.sectors["active"][sectorId]["nodeIndices"]; + this.nodes = this.sectors["active"][sectorId]["nodes"]; + this.edges = this.sectors["active"][sectorId]["edges"]; + }, - this.selection = []; - this.timer = undefined; - // create a frame and canvas - this._create(); + /** + * This function sets the global references to nodes, edges and nodeIndices back to + * those of the supplied frozen sector. + * + * @param sectorId + * @private + */ + _switchToFrozenSector : function(sectorId) { + this.nodeIndices = this.sectors["frozen"][sectorId]["nodeIndices"]; + this.nodes = this.sectors["frozen"][sectorId]["nodes"]; + this.edges = this.sectors["frozen"][sectorId]["edges"]; + }, - // apply options - this.setOptions(options); - // draw data - this.setData(data); -} + /** + * This function sets the global references to nodes, edges and nodeIndices to + * those of the navigation controls sector. + * + * @private + */ + _switchToNavigationSector : function() { + this.nodeIndices = this.sectors["navigation"]["nodeIndices"]; + this.nodes = this.sectors["navigation"]["nodes"]; + this.edges = this.sectors["navigation"]["edges"]; + }, -/** - * Set nodes and edges, and optionally options as well. - * - * @param {Object} data Object containing parameters: - * {Array | DataSet | DataView} [nodes] Array with nodes - * {Array | DataSet | DataView} [edges] Array with edges - * {String} [dot] String containing data in DOT format - * {Options} [options] Object with options - */ -Graph.prototype.setData = function(data) { - if (data && data.dot && (data.nodes || data.edges)) { - throw new SyntaxError('Data must contain either parameter "dot" or ' + - ' parameter pair "nodes" and "edges", but not both.'); - } - // set options - this.setOptions(data && data.options); + /** + * This function sets the global references to nodes, edges and nodeIndices back to + * those of the currently active sector. + * + * @private + */ + _loadLatestSector : function() { + this._switchToSector(this._sector()); + }, - // set all data - if (data && data.dot) { - // parse DOT file - if(data && data.dot) { - var dotData = vis.util.DOTToGraph(data.dot); - this.setData(dotData); - return; + + /** + * This function returns the currently active sector Id + * + * @returns {String} + * @private + */ + _sector : function() { + return this.activeSector[this.activeSector.length-1]; + }, + + + /** + * This function returns the previously active sector Id + * + * @returns {String} + * @private + */ + _previousSector : function() { + if (this.activeSector.length > 1) { + return this.activeSector[this.activeSector.length-2]; } - } - else { - this._setNodes(data && data.nodes); - this._setEdges(data && data.edges); - } + else { + throw new TypeError('there are not enough sectors in the this.activeSector array.'); + } + }, - // find a stable position or start animating to a stable position - if (this.stabilize) { - this._doStabilize(); - } - this.start(); -}; -/** - * Set options - * @param {Object} options - */ -Graph.prototype.setOptions = function (options) { - if (options) { - // retrieve parameter values - if (options.width != undefined) {this.width = options.width;} - if (options.height != undefined) {this.height = options.height;} - if (options.stabilize != undefined) {this.stabilize = options.stabilize;} - if (options.selectable != undefined) {this.selectable = options.selectable;} + /** + * We add the active sector at the end of the this.activeSector array + * This ensures it is the currently active sector returned by _sector() and it reaches the top + * of the activeSector stack. When we reverse our steps we move from the end to the beginning of this stack. + * + * @param newId + * @private + */ + _setActiveSector : function(newId) { + this.activeSector.push(newId); + }, - // TODO: work out these options and document them - if (options.edges) { - for (var prop in options.edges) { - if (options.edges.hasOwnProperty(prop)) { - this.constants.edges[prop] = options.edges[prop]; - } + + /** + * We remove the currently active sector id from the active sector stack. This happens when + * we reactivate the previously active sector + * + * @private + */ + _forgetLastSector : function() { + this.activeSector.pop(); + }, + + + /** + * This function creates a new active sector with the supplied newId. This newId + * is the expanding node id. + * + * @param {String} newId | Id of the new active sector + * @private + */ + _createNewSector : function(newId) { + // create the new sector + this.sectors["active"][newId] = {"nodes":{}, + "edges":{}, + "nodeIndices":[], + "formationScale": this.scale, + "drawingNode": undefined}; + + // create the new sector render node. This gives visual feedback that you are in a new sector. + this.sectors["active"][newId]['drawingNode'] = new Node( + {id:newId, + color: { + background: "#eaefef", + border: "495c5e" + } + },{},{},this.constants); + this.sectors["active"][newId]['drawingNode'].clusterSize = 2; + }, + + + /** + * This function removes the currently active sector. This is called when we create a new + * active sector. + * + * @param {String} sectorId | Id of the active sector that will be removed + * @private + */ + _deleteActiveSector : function(sectorId) { + delete this.sectors["active"][sectorId]; + }, + + + /** + * This function removes the currently active sector. This is called when we reactivate + * the previously active sector. + * + * @param {String} sectorId | Id of the active sector that will be removed + * @private + */ + _deleteFrozenSector : function(sectorId) { + delete this.sectors["frozen"][sectorId]; + }, + + + /** + * Freezing an active sector means moving it from the "active" object to the "frozen" object. + * We copy the references, then delete the active entree. + * + * @param sectorId + * @private + */ + _freezeSector : function(sectorId) { + // we move the set references from the active to the frozen stack. + this.sectors["frozen"][sectorId] = this.sectors["active"][sectorId]; + + // we have moved the sector data into the frozen set, we now remove it from the active set + this._deleteActiveSector(sectorId); + }, + + + /** + * This is the reverse operation of _freezeSector. Activating means moving the sector from the "frozen" + * object to the "active" object. + * + * @param sectorId + * @private + */ + _activateSector : function(sectorId) { + // we move the set references from the frozen to the active stack. + this.sectors["active"][sectorId] = this.sectors["frozen"][sectorId]; + + // we have moved the sector data into the active set, we now remove it from the frozen stack + this._deleteFrozenSector(sectorId); + }, + + + /** + * This function merges the data from the currently active sector with a frozen sector. This is used + * in the process of reverting back to the previously active sector. + * The data that is placed in the frozen (the previously active) sector is the node that has been removed from it + * upon the creation of a new active sector. + * + * @param sectorId + * @private + */ + _mergeThisWithFrozen : function(sectorId) { + // copy all nodes + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + this.sectors["frozen"][sectorId]["nodes"][nodeId] = this.nodes[nodeId]; } + } - if (options.edges.length != undefined && - options.nodes && options.nodes.distance == undefined) { - this.constants.edges.length = options.edges.length; - this.constants.nodes.distance = options.edges.length * 1.25; + // copy all edges (if not fully clustered, else there are no edges) + for (var edgeId in this.edges) { + if (this.edges.hasOwnProperty(edgeId)) { + this.sectors["frozen"][sectorId]["edges"][edgeId] = this.edges[edgeId]; } + } - if (!options.edges.fontColor) { - this.constants.edges.fontColor = options.edges.color; + // merge the nodeIndices + for (var i = 0; i < this.nodeIndices.length; i++) { + this.sectors["frozen"][sectorId]["nodeIndices"].push(this.nodeIndices[i]); + } + }, + + + /** + * This clusters the sector to one cluster. It was a single cluster before this process started so + * we revert to that state. The clusterToFit function with a maximum size of 1 node does this. + * + * @private + */ + _collapseThisToSingleCluster : function() { + this.clusterToFit(1,false); + }, + + + /** + * We create a new active sector from the node that we want to open. + * + * @param node + * @private + */ + _addSector : function(node) { + // this is the currently active sector + var sector = this._sector(); + +// // this should allow me to select nodes from a frozen set. +// if (this.sectors['active'][sector]["nodes"].hasOwnProperty(node.id)) { +// console.log("the node is part of the active sector"); +// } +// else { +// console.log("I dont know what the fuck happened!!"); +// } + + // when we switch to a new sector, we remove the node that will be expanded from the current nodes list. + delete this.nodes[node.id]; + + var unqiueIdentifier = util.randomUUID(); + + // we fully freeze the currently active sector + this._freezeSector(sector); + + // we create a new active sector. This sector has the Id of the node to ensure uniqueness + this._createNewSector(unqiueIdentifier); + + // we add the active sector to the sectors array to be able to revert these steps later on + this._setActiveSector(unqiueIdentifier); + + // we redirect the global references to the new sector's references. this._sector() now returns unqiueIdentifier + this._switchToSector(this._sector()); + + // finally we add the node we removed from our previous active sector to the new active sector + this.nodes[node.id] = node; + }, + + + /** + * We close the sector that is currently open and revert back to the one before. + * If the active sector is the "default" sector, nothing happens. + * + * @private + */ + _collapseSector : function() { + // the currently active sector + var sector = this._sector(); + + // we cannot collapse the default sector + if (sector != "default") { + if ((this.nodeIndices.length == 1) || + (this.sectors["active"][sector]["drawingNode"].width*this.scale < this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientWidth) || + (this.sectors["active"][sector]["drawingNode"].height*this.scale < this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientHeight)) { + var previousSector = this._previousSector(); + + // we collapse the sector back to a single cluster + this._collapseThisToSingleCluster(); + + // we move the remaining nodes, edges and nodeIndices to the previous sector. + // This previous sector is the one we will reactivate + this._mergeThisWithFrozen(previousSector); + + // the previously active (frozen) sector now has all the data from the currently active sector. + // we can now delete the active sector. + this._deleteActiveSector(sector); + + // we activate the previously active (and currently frozen) sector. + this._activateSector(previousSector); + + // we load the references from the newly active sector into the global references + this._switchToSector(previousSector); + + // we forget the previously active sector because we reverted to the one before + this._forgetLastSector(); + + // finally, we update the node index list. + this._updateNodeIndexList(); } + } + }, - // Added to support dashed lines - // David Jordan - // 2012-08-08 - if (options.edges.dash) { - if (options.edges.dash.length != undefined) { - this.constants.edges.dash.length = options.edges.dash.length; - } - if (options.edges.dash.gap != undefined) { - this.constants.edges.dash.gap = options.edges.dash.gap; + + /** + * This runs a function in all active sectors. This is used in _redraw() and the _initializeForceCalculation(). + * + * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors + * | we dont pass the function itself because then the "this" is the window object + * | instead of the Graph object + * @param {*} [argument] | Optional: arguments to pass to the runFunction + * @private + */ + _doInAllActiveSectors : function(runFunction,argument) { + if (argument === undefined) { + for (var sector in this.sectors["active"]) { + if (this.sectors["active"].hasOwnProperty(sector)) { + // switch the global references to those of this sector + this._switchToActiveSector(sector); + this[runFunction](); } - if (options.edges.dash.altLength != undefined) { - this.constants.edges.dash.altLength = options.edges.dash.altLength; + } + } + else { + for (var sector in this.sectors["active"]) { + if (this.sectors["active"].hasOwnProperty(sector)) { + // switch the global references to those of this sector + this._switchToActiveSector(sector); + var args = Array.prototype.splice.call(arguments, 1); + if (args.length > 1) { + this[runFunction](args[0],args[1]); + } + else { + this[runFunction](argument); + } } } } + // we revert the global references back to our active sector + this._loadLatestSector(); + }, - if (options.nodes) { - for (prop in options.nodes) { - if (options.nodes.hasOwnProperty(prop)) { - this.constants.nodes[prop] = options.nodes[prop]; + + /** + * This runs a function in all frozen sectors. This is used in the _redraw(). + * + * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors + * | we don't pass the function itself because then the "this" is the window object + * | instead of the Graph object + * @param {*} [argument] | Optional: arguments to pass to the runFunction + * @private + */ + _doInAllFrozenSectors : function(runFunction,argument) { + if (argument === undefined) { + for (var sector in this.sectors["frozen"]) { + if (this.sectors["frozen"].hasOwnProperty(sector)) { + // switch the global references to those of this sector + this._switchToFrozenSector(sector); + this[runFunction](); + } + } + } + else { + for (var sector in this.sectors["frozen"]) { + if (this.sectors["frozen"].hasOwnProperty(sector)) { + // switch the global references to those of this sector + this._switchToFrozenSector(sector); + var args = Array.prototype.splice.call(arguments, 1); + if (args.length > 1) { + this[runFunction](args[0],args[1]); + } + else { + this[runFunction](argument); + } } } + } + this._loadLatestSector(); + }, - if (options.nodes.color) { - this.constants.nodes.color = Node.parseColor(options.nodes.color); + + /** + * This runs a function in the navigation controls sector. + * + * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors + * | we don't pass the function itself because then the "this" is the window object + * | instead of the Graph object + * @param {*} [argument] | Optional: arguments to pass to the runFunction + * @private + */ + _doInNavigationSector : function(runFunction,argument) { + this._switchToNavigationSector(); + if (argument === undefined) { + this[runFunction](); + } + else { + var args = Array.prototype.splice.call(arguments, 1); + if (args.length > 1) { + this[runFunction](args[0],args[1]); } + else { + this[runFunction](argument); + } + } + this._loadLatestSector(); + }, - /* - if (options.nodes.widthMin) this.constants.nodes.radiusMin = options.nodes.widthMin; - if (options.nodes.widthMax) this.constants.nodes.radiusMax = options.nodes.widthMax; - */ + + /** + * This runs a function in all sectors. This is used in the _redraw(). + * + * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors + * | we don't pass the function itself because then the "this" is the window object + * | instead of the Graph object + * @param {*} [argument] | Optional: arguments to pass to the runFunction + * @private + */ + _doInAllSectors : function(runFunction,argument) { + var args = Array.prototype.splice.call(arguments, 1); + if (argument === undefined) { + this._doInAllActiveSectors(runFunction); + this._doInAllFrozenSectors(runFunction); + } + else { + if (args.length > 1) { + this._doInAllActiveSectors(runFunction,args[0],args[1]); + this._doInAllFrozenSectors(runFunction,args[0],args[1]); + } + else { + this._doInAllActiveSectors(runFunction,argument); + this._doInAllFrozenSectors(runFunction,argument); + } } - if (options.groups) { - for (var groupname in options.groups) { - if (options.groups.hasOwnProperty(groupname)) { - var group = options.groups[groupname]; - this.groups.add(groupname, group); + }, + + + /** + * This clears the nodeIndices list. We cannot use this.nodeIndices = [] because we would break the link with the + * active sector. Thus we clear the nodeIndices in the active sector, then reconnect the this.nodeIndices to it. + * + * @private + */ + _clearNodeIndexList : function() { + var sector = this._sector(); + this.sectors["active"][sector]["nodeIndices"] = []; + this.nodeIndices = this.sectors["active"][sector]["nodeIndices"]; + }, + + + /** + * Draw the encompassing sector node + * + * @param ctx + * @param sectorType + * @private + */ + _drawSectorNodes : function(ctx,sectorType) { + var minY = 1e9, maxY = -1e9, minX = 1e9, maxX = -1e9, node; + for (var sector in this.sectors[sectorType]) { + if (this.sectors[sectorType].hasOwnProperty(sector)) { + if (this.sectors[sectorType][sector]["drawingNode"] !== undefined) { + + this._switchToSector(sector,sectorType); + + minY = 1e9; maxY = -1e9; minX = 1e9; maxX = -1e9; + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + node = this.nodes[nodeId]; + node.resize(ctx); + if (minX > node.x - 0.5 * node.width) {minX = node.x - 0.5 * node.width;} + if (maxX < node.x + 0.5 * node.width) {maxX = node.x + 0.5 * node.width;} + if (minY > node.y - 0.5 * node.height) {minY = node.y - 0.5 * node.height;} + if (maxY < node.y + 0.5 * node.height) {maxY = node.y + 0.5 * node.height;} + } + } + node = this.sectors[sectorType][sector]["drawingNode"]; + node.x = 0.5 * (maxX + minX); + node.y = 0.5 * (maxY + minY); + node.width = 2 * (node.x - minX); + node.height = 2 * (node.y - minY); + node.radius = Math.sqrt(Math.pow(0.5*node.width,2) + Math.pow(0.5*node.height,2)); + node.setScale(this.scale); + node._drawCircle(ctx); } } } - } + }, - this.setSize(this.width, this.height); - this._setTranslation(this.frame.clientWidth / 2, this.frame.clientHeight / 2); - this._setScale(1); + _drawAllSectorNodes : function(ctx) { + this._drawSectorNodes(ctx,"frozen"); + this._drawSectorNodes(ctx,"active"); + this._loadLatestSector(); + } }; - /** - * fire an event - * @param {String} event The name of an event, for example 'select' - * @param {Object} params Optional object with event parameters - * @private + * Creation of the ClusterMixin var. + * + * This contains all the functions the Graph object can use to employ clustering + * + * Alex de Mulder + * 21-01-2013 */ -Graph.prototype._trigger = function (event, params) { - events.trigger(this, event, params); -}; - +var ClusterMixin = { /** - * Create the main frame for the Graph. - * This function is executed once when a Graph object is created. The frame - * contains a canvas, and this canvas contains all objects like the axis and - * nodes. - * @private - */ -Graph.prototype._create = function () { - // remove all elements from the container element. - while (this.containerElement.hasChildNodes()) { - this.containerElement.removeChild(this.containerElement.firstChild); - } + * This is only called in the constructor of the graph object + * */ + startWithClustering : function() { + // cluster if the data set is big + this.clusterToFit(this.constants.clustering.initialMaxNodes, true); - this.frame = document.createElement('div'); - this.frame.className = 'graph-frame'; - this.frame.style.position = 'relative'; - this.frame.style.overflow = 'hidden'; + // updates the lables after clustering + this.updateLabels(); - // create the graph canvas (HTML canvas element) - this.frame.canvas = document.createElement( 'canvas' ); - this.frame.canvas.style.position = 'relative'; - this.frame.appendChild(this.frame.canvas); - if (!this.frame.canvas.getContext) { - var noCanvas = document.createElement( 'DIV' ); - noCanvas.style.color = 'red'; - noCanvas.style.fontWeight = 'bold' ; - noCanvas.style.padding = '10px'; - noCanvas.innerHTML = 'Error: your browser does not support HTML canvas'; - this.frame.canvas.appendChild(noCanvas); - } + // this is called here because if clusterin is disabled, the start and stabilize are called in + // the setData function. + if (this.stabilize) { + this._doStabilize(); + } + this.start(); + }, - var me = this; - this.drag = {}; - this.pinch = {}; - this.hammer = Hammer(this.frame.canvas, { - prevent_default: true - }); - this.hammer.on('tap', me._onTap.bind(me) ); - this.hammer.on('hold', me._onHold.bind(me) ); - this.hammer.on('pinch', me._onPinch.bind(me) ); - this.hammer.on('touch', me._onTouch.bind(me) ); - this.hammer.on('dragstart', me._onDragStart.bind(me) ); - this.hammer.on('drag', me._onDrag.bind(me) ); - this.hammer.on('dragend', me._onDragEnd.bind(me) ); - this.hammer.on('mousewheel',me._onMouseWheel.bind(me) ); - this.hammer.on('DOMMouseScroll',me._onMouseWheel.bind(me) ); // for FF - this.hammer.on('mousemove', me._onMouseMoveTitle.bind(me) ); + /** + * This function clusters until the initialMaxNodes has been reached + * + * @param {Number} maxNumberOfNodes + * @param {Boolean} reposition + */ + clusterToFit : function(maxNumberOfNodes, reposition) { + var numberOfNodes = this.nodeIndices.length; - // add the frame to the container element - this.containerElement.appendChild(this.frame); -}; + var maxLevels = 50; + var level = 0; -/** - * - * @param {{x: Number, y: Number}} pointer - * @return {Number | null} node - * @private - */ -Graph.prototype._getNodeAt = function (pointer) { - var x = this._canvasToX(pointer.x); - var y = this._canvasToY(pointer.y); + // we first cluster the hubs, then we pull in the outliers, repeat + while (numberOfNodes > maxNumberOfNodes && level < maxLevels) { + if (level % 3 == 0) { + this.forceAggregateHubs(); + } + else { + this.increaseClusterLevel(); + } + numberOfNodes = this.nodeIndices.length; + level += 1; + } - var obj = { - left: x, - top: y, - right: x, - bottom: y - }; + // after the clustering we reposition the nodes to reduce the initial chaos + if (level > 1 && reposition == true) { + this.repositionNodes(); + } + }, - // if there are overlapping nodes, select the last one, this is the - // one which is drawn on top of the others - var overlappingNodes = this._getNodesOverlappingWith(obj); - return (overlappingNodes.length > 0) ? - overlappingNodes[overlappingNodes.length - 1] : null; -}; + /** + * This function can be called to open up a specific cluster. It is only called by + * It will unpack the cluster back one level. + * + * @param node | Node object: cluster to open. + */ + openCluster : function(node) { + var isMovingBeforeClustering = this.moving; + if (node.clusterSize > this.constants.clustering.sectorThreshold && this._nodeInActiveArea(node) && + !(this._sector() == "default" && this.nodeIndices.length == 1)) { + this._addSector(node); + var level = 0; + while ((this.nodeIndices.length < this.constants.clustering.initialMaxNodes) && (level < 10)) { + this.decreaseClusterLevel(); + level += 1; + } + } + else { + this._expandClusterNode(node,false,true); -/** - * Get the pointer location from a touch location - * @param {{pageX: Number, pageY: Number}} touch - * @return {{x: Number, y: Number}} pointer - * @private - */ -Graph.prototype._getPointer = function (touch) { - return { - x: touch.pageX - vis.util.getAbsoluteLeft(this.frame.canvas), - y: touch.pageY - vis.util.getAbsoluteTop(this.frame.canvas) - }; -}; + // update the index list, dynamic edges and labels + this._updateNodeIndexList(); + this._updateDynamicEdges(); + this.updateLabels(); + } -/** - * On start of a touch gesture, store the pointer - * @param event - * @private - */ -Graph.prototype._onTouch = function (event) { - this.drag.pointer = this._getPointer(event.gesture.touches[0]); - this.drag.pinched = false; - this.pinch.scale = this._getScale(); -}; + // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded + if (this.moving != isMovingBeforeClustering) { + this.start(); + } + }, -/** - * handle drag start event - * @private - */ -Graph.prototype._onDragStart = function () { - var drag = this.drag; + /** + * This calls the updateClustes with default arguments + */ + updateClustersDefault : function() { + if (this.constants.clustering.enabled == true) { + this.updateClusters(0,false,false); + } + }, - drag.selection = []; - drag.translation = this._getTranslation(); - drag.nodeId = this._getNodeAt(drag.pointer); - // note: drag.pointer is set in _onTouch to get the initial touch location + /** + * This function can be called to increase the cluster level. This means that the nodes with only one edge connection will + * be clustered with their connected node. This can be repeated as many times as needed. + * This can be called externally (by a keybind for instance) to reduce the complexity of big datasets. + */ + increaseClusterLevel : function() { + this.updateClusters(-1,false,true); + }, - var node = this.nodes[drag.nodeId]; - if (node) { - // select the clicked node if not yet selected - if (!node.isSelected()) { - this._selectNodes([drag.nodeId]); - } - // create an array with the selected nodes and their original location and status - var me = this; - this.selection.forEach(function (id) { - var node = me.nodes[id]; - if (node) { - var s = { - id: id, - node: node, - // store original x, y, xFixed and yFixed, make the node temporarily Fixed - x: node.x, - y: node.y, - xFixed: node.xFixed, - yFixed: node.yFixed - }; + /** + * This function can be called to decrease the cluster level. This means that the nodes with only one edge connection will + * be unpacked if they are a cluster. This can be repeated as many times as needed. + * This can be called externally (by a key-bind for instance) to look into clusters without zooming. + */ + decreaseClusterLevel : function() { + this.updateClusters(1,false,true); + }, - node.xFixed = true; - node.yFixed = true; - drag.selection.push(s); + /** + * This is the main clustering function. It clusters and declusters on zoom or forced + * This function clusters on zoom, it can be called with a predefined zoom direction + * If out, check if we can form clusters, if in, check if we can open clusters. + * This function is only called from _zoom() + * + * @param {Number} zoomDirection | -1 / 0 / +1 for zoomOut / determineByZoom / zoomIn + * @param {Boolean} recursive | enabled or disable recursive calling of the opening of clusters + * @param {Boolean} force | enabled or disable forcing + * + */ + updateClusters : function(zoomDirection,recursive,force) { + var isMovingBeforeClustering = this.moving; + var amountOfNodes = this.nodeIndices.length; + + // on zoom out collapse the sector if the scale is at the level the sector was made + if (this.previousScale > this.scale && zoomDirection == 0) { + this._collapseSector(); + } + + // check if we zoom in or out + if (this.previousScale > this.scale || zoomDirection == -1) { // zoom out + // forming clusters when forced pulls outliers in. When not forced, the edge length of the + // outer nodes determines if it is being clustered + this._formClusters(force); + } + else if (this.previousScale < this.scale || zoomDirection == 1) { // zoom in + if (force == true) { + // _openClusters checks for each node if the formationScale of the cluster is smaller than + // the current scale and if so, declusters. When forced, all clusters are reduced by one step + this._openClusters(recursive,force); } - }); + else { + // if a cluster takes up a set percentage of the active window + this._openClustersBySize(); + } + } + this._updateNodeIndexList(); - } -}; + // if a cluster was NOT formed and the user zoomed out, we try clustering by hubs + if (this.nodeIndices.length == amountOfNodes && (this.previousScale > this.scale || zoomDirection == -1)) { + this._aggregateHubs(force); + this._updateNodeIndexList(); + } -/** - * handle drag event - * @private - */ -Graph.prototype._onDrag = function (event) { - if (this.drag.pinched) { - return; - } + // we now reduce chains. + if (this.previousScale > this.scale || zoomDirection == -1) { // zoom out + this.handleChains(); + this._updateNodeIndexList(); + } - var pointer = this._getPointer(event.gesture.touches[0]); + this.previousScale = this.scale; - var me = this, - drag = this.drag, - selection = drag.selection; - if (selection && selection.length) { - // calculate delta's and new location - var deltaX = pointer.x - drag.pointer.x, - deltaY = pointer.y - drag.pointer.y; + // rest of the update the index list, dynamic edges and labels + this._updateDynamicEdges(); + this.updateLabels(); - // update position of all selected nodes - selection.forEach(function (s) { - var node = s.node; + // if a cluster was formed, we increase the clusterSession + if (this.nodeIndices.length < amountOfNodes) { // this means a clustering operation has taken place + this.clusterSession += 1; + } - if (!s.xFixed) { - node.x = me._canvasToX(me._xToCanvas(s.x) + deltaX); - } + // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded + if (this.moving != isMovingBeforeClustering) { + this.start(); + } + }, - if (!s.yFixed) { - node.y = me._canvasToY(me._yToCanvas(s.y) + deltaY); - } - }); + /** + * This function handles the chains. It is called on every updateClusters(). + */ + handleChains : function() { + // after clustering we check how many chains there are + var chainPercentage = this._getChainFraction(); + if (chainPercentage > this.constants.clustering.chainThreshold) { + this._reduceAmountOfChains(1 - this.constants.clustering.chainThreshold / chainPercentage) - // start animation if not yet running - if (!this.moving) { - this.moving = true; - this.start(); } - } - else { - // move the graph - var diffX = pointer.x - this.drag.pointer.x; - var diffY = pointer.y - this.drag.pointer.y; + }, - this._setTranslation( - this.drag.translation.x + diffX, - this.drag.translation.y + diffY); - this._redraw(); + /** + * this functions starts clustering by hubs + * The minimum hub threshold is set globally + * + * @private + */ + _aggregateHubs : function(force) { + this._getHubSize(); + this._formClustersByHub(force,false); + }, - this.moved = true; - } -}; -/** - * handle drag start event - * @private - */ -Graph.prototype._onDragEnd = function () { - var selection = this.drag.selection; - if (selection) { - selection.forEach(function (s) { - // restore original xFixed and yFixed - s.node.xFixed = s.xFixed; - s.node.yFixed = s.yFixed; - }); - } -}; + /** + * This function is fired by keypress. It forces hubs to form. + * + */ + forceAggregateHubs : function() { + var isMovingBeforeClustering = this.moving; + var amountOfNodes = this.nodeIndices.length; -/** - * handle tap/click event: select/unselect a node - * @private - */ -Graph.prototype._onTap = function (event) { - var pointer = this._getPointer(event.gesture.touches[0]); + this._aggregateHubs(true); - var nodeId = this._getNodeAt(pointer); - var node = this.nodes[nodeId]; - if (node) { - // select this node - this._selectNodes([nodeId]); + // update the index list, dynamic edges and labels + this._updateNodeIndexList(); + this._updateDynamicEdges(); + this.updateLabels(); - if (!this.moving) { - this._redraw(); + // if a cluster was formed, we increase the clusterSession + if (this.nodeIndices.length != amountOfNodes) { + this.clusterSession += 1; } - } - else { - // remove selection - this._unselectNodes(); - this._redraw(); - } -}; -/** - * handle long tap event: multi select nodes - * @private - */ -Graph.prototype._onHold = function (event) { - var pointer = this._getPointer(event.gesture.touches[0]); - var nodeId = this._getNodeAt(pointer); - var node = this.nodes[nodeId]; - if (node) { - if (!node.isSelected()) { - // select this node, keep previous selection - var append = true; - this._selectNodes([nodeId], append); - } - else { - this._unselectNodes([nodeId]); + // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded + if (this.moving != isMovingBeforeClustering) { + this.start(); } + }, - if (!this.moving) { - this._redraw(); + /** + * If a cluster takes up more than a set percentage of the screen, open the cluster + * + * @private + */ + _openClustersBySize : function() { + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + var node = this.nodes[nodeId]; + if (node.inView() == true) { + if ((node.width*this.scale > this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientWidth) || + (node.height*this.scale > this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientHeight)) { + this.openCluster(node); + } + } + } } - } - else { - // Do nothing - } -}; - -/** - * Handle pinch event - * @param event - * @private - */ -Graph.prototype._onPinch = function (event) { - var pointer = this._getPointer(event.gesture.center); + }, - this.drag.pinched = true; - if (!('scale' in this.pinch)) { - this.pinch.scale = 1; - } - // TODO: enable moving while pinching? - var scale = this.pinch.scale * event.gesture.scale; - this._zoom(scale, pointer) -}; + /** + * This function loops over all nodes in the nodeIndices list. For each node it checks if it is a cluster and if it + * has to be opened based on the current zoom level. + * + * @private + */ + _openClusters : function(recursive,force) { + for (var i = 0; i < this.nodeIndices.length; i++) { + var node = this.nodes[this.nodeIndices[i]]; + this._expandClusterNode(node,recursive,force); + } + }, -/** - * Zoom the graph in or out - * @param {Number} scale a number around 1, and between 0.01 and 10 - * @param {{x: Number, y: Number}} pointer - * @return {Number} appliedScale scale is limited within the boundaries - * @private - */ -Graph.prototype._zoom = function(scale, pointer) { - var scaleOld = this._getScale(); - if (scale < 0.01) { - scale = 0.01; - } - if (scale > 10) { - scale = 10; - } - - var translation = this._getTranslation(); - var scaleFrac = scale / scaleOld; - var tx = (1 - scaleFrac) * pointer.x + translation.x * scaleFrac; - var ty = (1 - scaleFrac) * pointer.y + translation.y * scaleFrac; + /** + * This function checks if a node has to be opened. This is done by checking the zoom level. + * If the node contains child nodes, this function is recursively called on the child nodes as well. + * This recursive behaviour is optional and can be set by the recursive argument. + * + * @param {Node} parentNode | to check for cluster and expand + * @param {Boolean} recursive | enabled or disable recursive calling + * @param {Boolean} force | enabled or disable forcing + * @param {Boolean} [openAll] | This will recursively force all nodes in the parent to be released + * @private + */ + _expandClusterNode : function(parentNode, recursive, force, openAll) { + // first check if node is a cluster + if (parentNode.clusterSize > 1) { + // this means that on a double tap event or a zoom event, the cluster fully unpacks if it is smaller than 20 + if (parentNode.clusterSize < this.constants.clustering.sectorThreshold) { + openAll = true; + } + recursive = openAll ? true : recursive; + + // if the last child has been added on a smaller scale than current scale decluster + if (parentNode.formationScale < this.scale || force == true) { + // we will check if any of the contained child nodes should be removed from the cluster + for (var containedNodeId in parentNode.containedNodes) { + if (parentNode.containedNodes.hasOwnProperty(containedNodeId)) { + var childNode = parentNode.containedNodes[containedNodeId]; + + // force expand will expand the largest cluster size clusters. Since we cluster from outside in, we assume that + // the largest cluster is the one that comes from outside + if (force == true) { + if (childNode.clusterSession == parentNode.clusterSessions[parentNode.clusterSessions.length-1] + || openAll) { + this._expelChildFromParent(parentNode,containedNodeId,recursive,force,openAll); + } + } + else { + if (this._nodeInActiveArea(parentNode)) { + this._expelChildFromParent(parentNode,containedNodeId,recursive,force,openAll); + } + } + } + } + } + } + }, - this._setScale(scale); - this._setTranslation(tx, ty); - this._redraw(); + /** + * ONLY CALLED FROM _expandClusterNode + * + * This function will expel a child_node from a parent_node. This is to de-cluster the node. This function will remove + * the child node from the parent contained_node object and put it back into the global nodes object. + * The same holds for the edge that was connected to the child node. It is moved back into the global edges object. + * + * @param {Node} parentNode | the parent node + * @param {String} containedNodeId | child_node id as it is contained in the containedNodes object of the parent node + * @param {Boolean} recursive | This will also check if the child needs to be expanded. + * With force and recursive both true, the entire cluster is unpacked + * @param {Boolean} force | This will disregard the zoom level and will expel this child from the parent + * @param {Boolean} openAll | This will recursively force all nodes in the parent to be released + * @private + */ + _expelChildFromParent : function(parentNode, containedNodeId, recursive, force, openAll) { + var childNode = parentNode.containedNodes[containedNodeId]; + + // if child node has been added on smaller scale than current, kick out + if (childNode.formationScale < this.scale || force == true) { + // put the child node back in the global nodes object + this.nodes[containedNodeId] = childNode; + + // release the contained edges from this childNode back into the global edges + this._releaseContainedEdges(parentNode,childNode); + + // reconnect rerouted edges to the childNode + this._connectEdgeBackToChild(parentNode,childNode); + + // validate all edges in dynamicEdges + this._validateEdges(parentNode); + + // undo the changes from the clustering operation on the parent node + parentNode.mass -= this.constants.clustering.massTransferCoefficient * childNode.mass; + parentNode.fontSize -= this.constants.clustering.fontSizeMultiplier * childNode.clusterSize; + parentNode.clusterSize -= childNode.clusterSize; + parentNode.dynamicEdgesLength = parentNode.dynamicEdges.length; + + // place the child node near the parent, not at the exact same location to avoid chaos in the system + childNode.x = parentNode.x + this.constants.edges.length * 0.3 * (0.5 - Math.random()) * parentNode.clusterSize; + childNode.y = parentNode.y + this.constants.edges.length * 0.3 * (0.5 - Math.random()) * parentNode.clusterSize; + + // remove node from the list + delete parentNode.containedNodes[containedNodeId]; + + // check if there are other childs with this clusterSession in the parent. + var othersPresent = false; + for (var childNodeId in parentNode.containedNodes) { + if (parentNode.containedNodes.hasOwnProperty(childNodeId)) { + if (parentNode.containedNodes[childNodeId].clusterSession == childNode.clusterSession) { + othersPresent = true; + break; + } + } + } + // if there are no others, remove the cluster session from the list + if (othersPresent == false) { + parentNode.clusterSessions.pop(); + } - return scale; -}; + // remove the clusterSession from the child node + childNode.clusterSession = 0; -/** - * Event handler for mouse wheel event, used to zoom the timeline - * See http://adomas.org/javascript-mouse-wheel/ - * https://github.com/EightMedia/hammer.js/issues/256 - * @param {MouseEvent} event - * @private - */ -Graph.prototype._onMouseWheel = function(event) { - // retrieve delta - var delta = 0; - if (event.wheelDelta) { /* IE/Opera. */ - delta = event.wheelDelta/120; - } else if (event.detail) { /* Mozilla case. */ - // In Mozilla, sign of delta is different than in IE. - // Also, delta is multiple of 3. - delta = -event.detail/3; - } + // restart the simulation to reorganise all nodes + this.moving = true; - // If delta is nonzero, handle it. - // Basically, delta is now positive if wheel was scrolled up, - // and negative, if wheel was scrolled down. - if (delta) { - if (!('mouswheelScale' in this.pinch)) { - this.pinch.mouswheelScale = 1; + // recalculate the size of the node on the next time the node is rendered + parentNode.clearSizeCache(); } - // calculate the new scale - var scale = this.pinch.mouswheelScale; - var zoom = delta / 10; - if (delta < 0) { - zoom = zoom / (1 - zoom); + // check if a further expansion step is possible if recursivity is enabled + if (recursive == true) { + this._expandClusterNode(childNode,recursive,force,openAll); } - scale *= (1 + zoom); + }, - // calculate the pointer location - var gesture = util.fakeGesture(this, event); - var pointer = this._getPointer(gesture.center); - - // apply the new scale - scale = this._zoom(scale, pointer); - - // store the new, applied scale - this.pinch.mouswheelScale = scale; - } - // Prevent default actions caused by mouse wheel. - event.preventDefault(); -}; + /** + * This function checks if any nodes at the end of their trees have edges below a threshold length + * This function is called only from updateClusters() + * forceLevelCollapse ignores the length of the edge and collapses one level + * This means that a node with only one edge will be clustered with its connected node + * + * @private + * @param {Boolean} force + */ + _formClusters : function(force) { + if (force == false) { + this._formClustersByZoom(); + } + else { + this._forceClustersByZoom(); + } + }, + /** + * This function handles the clustering by zooming out, this is based on a minimum edge distance + * + * @private + */ + _formClustersByZoom : function() { + var dx,dy,length, + minLength = this.constants.clustering.clusterEdgeThreshold/this.scale; + + // check if any edges are shorter than minLength and start the clustering + // the clustering favours the node with the larger mass + for (var edgeId in this.edges) { + if (this.edges.hasOwnProperty(edgeId)) { + var edge = this.edges[edgeId]; + if (edge.connected) { + if (edge.toId != edge.fromId) { + dx = (edge.to.x - edge.from.x); + dy = (edge.to.y - edge.from.y); + length = Math.sqrt(dx * dx + dy * dy); + + + if (length < minLength) { + // first check which node is larger + var parentNode = edge.from; + var childNode = edge.to; + if (edge.to.mass > edge.from.mass) { + parentNode = edge.to; + childNode = edge.from; + } + + if (childNode.dynamicEdgesLength == 1) { + this._addToCluster(parentNode,childNode,false); + } + else if (parentNode.dynamicEdgesLength == 1) { + this._addToCluster(childNode,parentNode,false); + } + } + } + } + } + } + }, -/** - * Mouse move handler for checking whether the title moves over a node with a title. - * @param {Event} event - * @private - */ -Graph.prototype._onMouseMoveTitle = function (event) { - var gesture = util.fakeGesture(this, event); - var pointer = this._getPointer(gesture.center); + /** + * This function forces the graph to cluster all nodes with only one connecting edge to their + * connected node. + * + * @private + */ + _forceClustersByZoom : function() { + for (var nodeId in this.nodes) { + // another node could have absorbed this child. + if (this.nodes.hasOwnProperty(nodeId)) { + var childNode = this.nodes[nodeId]; + + // the edges can be swallowed by another decrease + if (childNode.dynamicEdgesLength == 1 && childNode.dynamicEdges.length != 0) { + var edge = childNode.dynamicEdges[0]; + var parentNode = (edge.toId == childNode.id) ? this.nodes[edge.fromId] : this.nodes[edge.toId]; + + // group to the largest node + if (childNode.id != parentNode.id) { + if (parentNode.mass > childNode.mass) { + this._addToCluster(parentNode,childNode,true); + } + else { + this._addToCluster(childNode,parentNode,true); + } + } + } + } + } + }, - // check if the previously selected node is still selected - if (this.popupNode) { - this._checkHidePopup(pointer); - } - // start a timeout that will check if the mouse is positioned above - // an element - var me = this; - var checkShow = function() { - me._checkShowPopup(pointer); - }; - if (this.popupTimer) { - clearInterval(this.popupTimer); // stop any running timer - } - if (!this.leftButtonDown) { - this.popupTimer = setTimeout(checkShow, 300); - } -}; -/** - * Check if there is an element on the given position in the graph - * (a node or edge). If so, and if this element has a title, - * show a popup window with its title. - * - * @param {{x:Number, y:Number}} pointer - * @private - */ -Graph.prototype._checkShowPopup = function (pointer) { - var obj = { - left: this._canvasToX(pointer.x), - top: this._canvasToY(pointer.y), - right: this._canvasToX(pointer.x), - bottom: this._canvasToY(pointer.y) - }; + /** + * This function forms clusters from hubs, it loops over all nodes + * + * @param {Boolean} force | Disregard zoom level + * @param {Boolean} onlyEqual | This only clusters a hub with a specific number of edges + * @private + */ + _formClustersByHub : function(force, onlyEqual) { + // we loop over all nodes in the list + for (var nodeId in this.nodes) { + // we check if it is still available since it can be used by the clustering in this loop + if (this.nodes.hasOwnProperty(nodeId)) { + this._formClusterFromHub(this.nodes[nodeId],force,onlyEqual); + } + } + }, - var id; - var lastPopupNode = this.popupNode; + /** + * This function forms a cluster from a specific preselected hub node + * + * @param {Node} hubNode | the node we will cluster as a hub + * @param {Boolean} force | Disregard zoom level + * @param {Boolean} onlyEqual | This only clusters a hub with a specific number of edges + * @param {Number} [absorptionSizeOffset] | + * @private + */ + _formClusterFromHub : function(hubNode, force, onlyEqual, absorptionSizeOffset) { + if (absorptionSizeOffset === undefined) { + absorptionSizeOffset = 0; + } + // we decide if the node is a hub + if ((hubNode.dynamicEdgesLength >= this.hubThreshold && onlyEqual == false) || + (hubNode.dynamicEdgesLength == this.hubThreshold && onlyEqual == true)) { + // initialize variables + var dx,dy,length; + var minLength = this.constants.clustering.clusterEdgeThreshold/this.scale; + var allowCluster = false; + + // we create a list of edges because the dynamicEdges change over the course of this loop + var edgesIdarray = []; + var amountOfInitialEdges = hubNode.dynamicEdges.length; + for (var j = 0; j < amountOfInitialEdges; j++) { + edgesIdarray.push(hubNode.dynamicEdges[j].id); + } - if (this.popupNode == undefined) { - // search the nodes for overlap, select the top one in case of multiple nodes - var nodes = this.nodes; - for (id in nodes) { - if (nodes.hasOwnProperty(id)) { - var node = nodes[id]; - if (node.getTitle() != undefined && node.isOverlappingWith(obj)) { - this.popupNode = node; - break; + // if the hub clustering is not forces, we check if one of the edges connected + // to a cluster is small enough based on the constants.clustering.clusterEdgeThreshold + if (force == false) { + allowCluster = false; + for (j = 0; j < amountOfInitialEdges; j++) { + var edge = this.edges[edgesIdarray[j]]; + if (edge !== undefined) { + if (edge.connected) { + if (edge.toId != edge.fromId) { + dx = (edge.to.x - edge.from.x); + dy = (edge.to.y - edge.from.y); + length = Math.sqrt(dx * dx + dy * dy); + + if (length < minLength) { + allowCluster = true; + break; + } + } + } + } } } - } - } - if (this.popupNode == undefined) { - // search the edges for overlap - var edges = this.edges; - for (id in edges) { - if (edges.hasOwnProperty(id)) { - var edge = edges[id]; - if (edge.connected && (edge.getTitle() != undefined) && - edge.isOverlappingWith(obj)) { - this.popupNode = edge; - break; + // start the clustering if allowed + if ((!force && allowCluster) || force) { + // we loop over all edges INITIALLY connected to this hub + for (j = 0; j < amountOfInitialEdges; j++) { + edge = this.edges[edgesIdarray[j]]; + // the edge can be clustered by this function in a previous loop + if (edge !== undefined) { + var childNode = this.nodes[(edge.fromId == hubNode.id) ? edge.toId : edge.fromId]; + // we do not want hubs to merge with other hubs nor do we want to cluster itself. + if ((childNode.dynamicEdges.length <= (this.hubThreshold + absorptionSizeOffset)) && + (childNode.id != hubNode.id)) { + this._addToCluster(hubNode,childNode,force); + } + } } } } - } + }, - if (this.popupNode) { - // show popup message window - if (this.popupNode != lastPopupNode) { - var me = this; - if (!me.popup) { - me.popup = new Popup(me.frame); - } - // adjust a small offset such that the mouse cursor is located in the - // bottom left location of the popup, and you can easily move over the - // popup area - me.popup.setPosition(pointer.x - 3, pointer.y - 3); - me.popup.setText(me.popupNode.getTitle()); - me.popup.show(); - } - } - else { - if (this.popup) { - this.popup.hide(); - } - } -}; -/** - * Check if the popup must be hided, which is the case when the mouse is no - * longer hovering on the object - * @param {{x:Number, y:Number}} pointer - * @private - */ -Graph.prototype._checkHidePopup = function (pointer) { - if (!this.popupNode || !this._getNodeAt(pointer) ) { - this.popupNode = undefined; - if (this.popup) { - this.popup.hide(); + /** + * This function adds the child node to the parent node, creating a cluster if it is not already. + * + * @param {Node} parentNode | this is the node that will house the child node + * @param {Node} childNode | this node will be deleted from the global this.nodes and stored in the parent node + * @param {Boolean} force | true will only update the remainingEdges at the very end of the clustering, ensuring single level collapse + * @private + */ + _addToCluster : function(parentNode, childNode, force) { + // join child node in the parent node + parentNode.containedNodes[childNode.id] = childNode; + + // manage all the edges connected to the child and parent nodes + for (var i = 0; i < childNode.dynamicEdges.length; i++) { + var edge = childNode.dynamicEdges[i]; + if (edge.toId == parentNode.id || edge.fromId == parentNode.id) { // edge connected to parentNode + this._addToContainedEdges(parentNode,childNode,edge); + } + else { + this._connectEdgeToCluster(parentNode,childNode,edge); + } } - } -}; + // a contained node has no dynamic edges. + childNode.dynamicEdges = []; -/** - * Unselect selected nodes. If no selection array is provided, all nodes - * are unselected - * @param {Object[]} selection Array with selection objects, each selection - * object has a parameter row. Optional - * @param {Boolean} triggerSelect If true (default), the select event - * is triggered when nodes are unselected - * @return {Boolean} changed True if the selection is changed - * @private - */ -Graph.prototype._unselectNodes = function(selection, triggerSelect) { - var changed = false; - var i, iMax, id; + // remove circular edges from clusters + this._containCircularEdgesFromNode(parentNode,childNode); - if (selection) { - // remove provided selections - for (i = 0, iMax = selection.length; i < iMax; i++) { - id = selection[i]; - this.nodes[id].unselect(); - var j = 0; - while (j < this.selection.length) { - if (this.selection[j] == id) { - this.selection.splice(j, 1); - changed = true; - } - else { - j++; - } - } + // remove the childNode from the global nodes object + delete this.nodes[childNode.id]; + + // update the properties of the child and parent + var massBefore = parentNode.mass; + childNode.clusterSession = this.clusterSession; + parentNode.mass += this.constants.clustering.massTransferCoefficient * childNode.mass; + parentNode.clusterSize += childNode.clusterSize; + parentNode.fontSize += this.constants.clustering.fontSizeMultiplier * childNode.clusterSize; + + // keep track of the clustersessions so we can open the cluster up as it has been formed. + if (parentNode.clusterSessions[parentNode.clusterSessions.length - 1] != this.clusterSession) { + parentNode.clusterSessions.push(this.clusterSession); } - } - else if (this.selection && this.selection.length) { - // remove all selections - for (i = 0, iMax = this.selection.length; i < iMax; i++) { - id = this.selection[i]; - this.nodes[id].unselect(); - changed = true; + + // forced clusters only open from screen size and double tap + if (force == true) { + // parentNode.formationScale = Math.pow(1 - (1.0/11.0),this.clusterSession+3); + parentNode.formationScale = 0; + } + else { + parentNode.formationScale = this.scale; // The latest child has been added on this scale } - this.selection = []; - } - if (changed && (triggerSelect == true || triggerSelect == undefined)) { - // fire the select event - this._trigger('select'); - } + // recalculate the size of the node on the next time the node is rendered + parentNode.clearSizeCache(); - return changed; -}; + // set the pop-out scale for the childnode + parentNode.containedNodes[childNode.id].formationScale = parentNode.formationScale; -/** - * select all nodes on given location x, y - * @param {Array} selection an array with node ids - * @param {boolean} append If true, the new selection will be appended to the - * current selection (except for duplicate entries) - * @return {Boolean} changed True if the selection is changed - * @private - */ -Graph.prototype._selectNodes = function(selection, append) { - var changed = false; - var i, iMax; + // nullify the movement velocity of the child, this is to avoid hectic behaviour + childNode.clearVelocity(); - // TODO: the selectNodes method is a little messy, rework this + // the mass has altered, preservation of energy dictates the velocity to be updated + parentNode.updateVelocity(massBefore); - // check if the current selection equals the desired selection - var selectionAlreadyThere = true; - if (selection.length != this.selection.length) { - selectionAlreadyThere = false; - } - else { - for (i = 0, iMax = Math.min(selection.length, this.selection.length); i < iMax; i++) { - if (selection[i] != this.selection[i]) { - selectionAlreadyThere = false; - break; - } - } - } - if (selectionAlreadyThere) { - return changed; - } + // restart the simulation to reorganise all nodes + this.moving = true; + }, - if (append == undefined || append == false) { - // first deselect any selected node - var triggerSelect = false; - changed = this._unselectNodes(undefined, triggerSelect); - } - for (i = 0, iMax = selection.length; i < iMax; i++) { - // add each of the new selections, but only when they are not duplicate - var id = selection[i]; - var isDuplicate = (this.selection.indexOf(id) != -1); - if (!isDuplicate) { - this.nodes[id].select(); - this.selection.push(id); - changed = true; + /** + * This function will apply the changes made to the remainingEdges during the formation of the clusters. + * This is a seperate function to allow for level-wise collapsing of the node tree. + * It has to be called if a level is collapsed. It is called by _formClusters(). + * @private + */ + _updateDynamicEdges : function() { + for (var i = 0; i < this.nodeIndices.length; i++) { + var node = this.nodes[this.nodeIndices[i]]; + node.dynamicEdgesLength = node.dynamicEdges.length; + + // this corrects for multiple edges pointing at the same other node + var correction = 0; + if (node.dynamicEdgesLength > 1) { + for (var j = 0; j < node.dynamicEdgesLength - 1; j++) { + var edgeToId = node.dynamicEdges[j].toId; + var edgeFromId = node.dynamicEdges[j].fromId; + for (var k = j+1; k < node.dynamicEdgesLength; k++) { + if ((node.dynamicEdges[k].toId == edgeToId && node.dynamicEdges[k].fromId == edgeFromId) || + (node.dynamicEdges[k].fromId == edgeToId && node.dynamicEdges[k].toId == edgeFromId)) { + correction += 1; + } + } + } + } + node.dynamicEdgesLength -= correction; } - } + }, - if (changed) { - // fire the select event - this._trigger('select'); - } - return changed; -}; + /** + * This adds an edge from the childNode to the contained edges of the parent node + * + * @param parentNode | Node object + * @param childNode | Node object + * @param edge | Edge object + * @private + */ + _addToContainedEdges : function(parentNode, childNode, edge) { + // create an array object if it does not yet exist for this childNode + if (!(parentNode.containedEdges.hasOwnProperty(childNode.id))) { + parentNode.containedEdges[childNode.id] = [] + } + // add this edge to the list + parentNode.containedEdges[childNode.id].push(edge); -/** - * retrieve all nodes overlapping with given object - * @param {Object} obj An object with parameters left, top, right, bottom - * @return {Number[]} An array with id's of the overlapping nodes - * @private - */ -Graph.prototype._getNodesOverlappingWith = function (obj) { - var nodes = this.nodes, - overlappingNodes = []; + // remove the edge from the global edges object + delete this.edges[edge.id]; - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - if (nodes[id].isOverlappingWith(obj)) { - overlappingNodes.push(id); + // remove the edge from the parent object + for (var i = 0; i < parentNode.dynamicEdges.length; i++) { + if (parentNode.dynamicEdges[i].id == edge.id) { + parentNode.dynamicEdges.splice(i,1); + break; } } - } + }, - return overlappingNodes; -}; + /** + * This function connects an edge that was connected to a child node to the parent node. + * It keeps track of which nodes it has been connected to with the originalId array. + * + * @param {Node} parentNode | Node object + * @param {Node} childNode | Node object + * @param {Edge} edge | Edge object + * @private + */ + _connectEdgeToCluster : function(parentNode, childNode, edge) { + // handle circular edges + if (edge.toId == edge.fromId) { + this._addToContainedEdges(parentNode, childNode, edge); + } + else { + if (edge.toId == childNode.id) { // edge connected to other node on the "to" side + edge.originalToId.push(childNode.id); + edge.to = parentNode; + edge.toId = parentNode.id; + } + else { // edge connected to other node with the "from" side -/** - * retrieve the currently selected nodes - * @return {Number[] | String[]} selection An array with the ids of the - * selected nodes. - */ -Graph.prototype.getSelection = function() { - return this.selection.concat([]); -}; + edge.originalFromId.push(childNode.id); + edge.from = parentNode; + edge.fromId = parentNode.id; + } -/** - * select zero or more nodes - * @param {Number[] | String[]} selection An array with the ids of the - * selected nodes. - */ -Graph.prototype.setSelection = function(selection) { - var i, iMax, id; + this._addToReroutedEdges(parentNode,childNode,edge); + } + }, - if (!selection || (selection.length == undefined)) - throw 'Selection must be an array with ids'; - // first unselect any selected node - for (i = 0, iMax = this.selection.length; i < iMax; i++) { - id = this.selection[i]; - this.nodes[id].unselect(); - } + _containCircularEdgesFromNode : function(parentNode, childNode) { + // manage all the edges connected to the child and parent nodes + for (var i = 0; i < parentNode.dynamicEdges.length; i++) { + var edge = parentNode.dynamicEdges[i]; + // handle circular edges + if (edge.toId == edge.fromId) { + this._addToContainedEdges(parentNode, childNode, edge); + } + } + }, - this.selection = []; - for (i = 0, iMax = selection.length; i < iMax; i++) { - id = selection[i]; + /** + * This adds an edge from the childNode to the rerouted edges of the parent node + * + * @param parentNode | Node object + * @param childNode | Node object + * @param edge | Edge object + * @private + */ + _addToReroutedEdges : function(parentNode, childNode, edge) { + // create an array object if it does not yet exist for this childNode + // we store the edge in the rerouted edges so we can restore it when the cluster pops open + if (!(parentNode.reroutedEdges.hasOwnProperty(childNode.id))) { + parentNode.reroutedEdges[childNode.id] = []; + } + parentNode.reroutedEdges[childNode.id].push(edge); + + // this edge becomes part of the dynamicEdges of the cluster node + parentNode.dynamicEdges.push(edge); + }, - var node = this.nodes[id]; - if (!node) { - throw new RangeError('Node with id "' + id + '" not found'); + + + /** + * This function connects an edge that was connected to a cluster node back to the child node. + * + * @param parentNode | Node object + * @param childNode | Node object + * @private + */ + _connectEdgeBackToChild : function(parentNode, childNode) { + if (parentNode.reroutedEdges.hasOwnProperty(childNode.id)) { + for (var i = 0; i < parentNode.reroutedEdges[childNode.id].length; i++) { + var edge = parentNode.reroutedEdges[childNode.id][i]; + if (edge.originalFromId[edge.originalFromId.length-1] == childNode.id) { + edge.originalFromId.pop(); + edge.fromId = childNode.id; + edge.from = childNode; + } + else { + edge.originalToId.pop(); + edge.toId = childNode.id; + edge.to = childNode; + } + + // append this edge to the list of edges connecting to the childnode + childNode.dynamicEdges.push(edge); + + // remove the edge from the parent object + for (var j = 0; j < parentNode.dynamicEdges.length; j++) { + if (parentNode.dynamicEdges[j].id == edge.id) { + parentNode.dynamicEdges.splice(j,1); + break; + } + } + } + // remove the entry from the rerouted edges + delete parentNode.reroutedEdges[childNode.id]; } - node.select(); - this.selection.push(id); - } + }, - this.redraw(); -}; -/** - * Validate the selection: remove ids of nodes which no longer exist - * @private - */ -Graph.prototype._updateSelection = function () { - var i = 0; - while (i < this.selection.length) { - var id = this.selection[i]; - if (!this.nodes[id]) { - this.selection.splice(i, 1); + /** + * When loops are clustered, an edge can be both in the rerouted array and the contained array. + * This function is called last to verify that all edges in dynamicEdges are in fact connected to the + * parentNode + * + * @param parentNode | Node object + * @private + */ + _validateEdges : function(parentNode) { + for (var i = 0; i < parentNode.dynamicEdges.length; i++) { + var edge = parentNode.dynamicEdges[i]; + if (parentNode.id != edge.toId && parentNode.id != edge.fromId) { + parentNode.dynamicEdges.splice(i,1); + } } - else { - i++; + }, + + + /** + * This function released the contained edges back into the global domain and puts them back into the + * dynamic edges of both parent and child. + * + * @param {Node} parentNode | + * @param {Node} childNode | + * @private + */ + _releaseContainedEdges : function(parentNode, childNode) { + for (var i = 0; i < parentNode.containedEdges[childNode.id].length; i++) { + var edge = parentNode.containedEdges[childNode.id][i]; + + // put the edge back in the global edges object + this.edges[edge.id] = edge; + + // put the edge back in the dynamic edges of the child and parent + childNode.dynamicEdges.push(edge); + parentNode.dynamicEdges.push(edge); } - } -}; + // remove the entry from the contained edges + delete parentNode.containedEdges[childNode.id]; -/** - * Temporary method to test calculating a hub value for the nodes - * @param {number} level Maximum number edges between two nodes in order - * to call them connected. Optional, 1 by default - * @return {Number[]} connectioncount array with the connection count - * for each node - * @private - */ -Graph.prototype._getConnectionCount = function(level) { - if (level == undefined) { - level = 1; - } + }, - // get the nodes connected to given nodes - function getConnectedNodes(nodes) { - var connectedNodes = []; - for (var j = 0, jMax = nodes.length; j < jMax; j++) { - var node = nodes[j]; - // find all nodes connected to this node - var edges = node.edges; - for (var i = 0, iMax = edges.length; i < iMax; i++) { - var edge = edges[i]; - var other = null; - // check if connected - if (edge.from == node) - other = edge.to; - else if (edge.to == node) - other = edge.from; + // ------------------- UTILITY FUNCTIONS ---------------------------- // - // check if the other node is not already in the list with nodes - var k, kMax; - if (other) { - for (k = 0, kMax = nodes.length; k < kMax; k++) { - if (nodes[k] == other) { - other = null; - break; - } - } + + /** + * This updates the node labels for all nodes (for debugging purposes) + */ + updateLabels : function() { + var nodeId; + // update node labels + for (nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + var node = this.nodes[nodeId]; + if (node.clusterSize > 1) { + node.label = "[".concat(String(node.clusterSize),"]"); } - if (other) { - for (k = 0, kMax = connectedNodes.length; k < kMax; k++) { - if (connectedNodes[k] == other) { - other = null; - break; - } + } + } + + // update node labels + for (nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + node = this.nodes[nodeId]; + if (node.clusterSize == 1) { + if (node.originalLabel !== undefined) { + node.label = node.originalLabel; + } + else { + node.label = String(node.id); } } - - if (other) - connectedNodes.push(other); } } - return connectedNodes; - } + /* Debug Override */ + // for (nodeId in this.nodes) { + // if (this.nodes.hasOwnProperty(nodeId)) { + // node = this.nodes[nodeId]; + // node.label = String(Math.round(node.width)).concat(":",Math.round(node.width*this.scale)); + // } + // } - var connections = []; - var nodes = this.nodes; - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - var c = [nodes[id]]; - for (var l = 0; l < level; l++) { - c = c.concat(getConnectedNodes(c)); - } - connections.push(c); - } - } + }, - var hubs = []; - for (var i = 0, len = connections.length; i < len; i++) { - hubs.push(connections[i].length); - } - return hubs; -}; + /** + * This function determines if the cluster we want to decluster is in the active area + * this means around the zoom center + * + * @param {Node} node + * @returns {boolean} + * @private + */ + _nodeInActiveArea : function(node) { + return ( + Math.abs(node.x - this.areaCenter.x) <= this.constants.clustering.activeAreaBoxSize/this.scale + && + Math.abs(node.y - this.areaCenter.y) <= this.constants.clustering.activeAreaBoxSize/this.scale + ) + }, -/** - * Set a new size for the graph - * @param {string} width Width in pixels or percentage (for example '800px' - * or '50%') - * @param {string} height Height in pixels or percentage (for example '400px' - * or '30%') - */ -Graph.prototype.setSize = function(width, height) { - this.frame.style.width = width; - this.frame.style.height = height; + /** + * This is an adaptation of the original repositioning function. This is called if the system is clustered initially + * It puts large clusters away from the center and randomizes the order. + * + */ + repositionNodes : function() { + for (var i = 0; i < this.nodeIndices.length; i++) { + var node = this.nodes[this.nodeIndices[i]]; + if (!node.isFixed()) { + var radius = this.constants.edges.length * (1 + 0.6*node.clusterSize); + var angle = 2 * Math.PI * Math.random(); + node.x = radius * Math.cos(angle); + node.y = radius * Math.sin(angle); + } + } + }, - this.frame.canvas.style.width = '100%'; - this.frame.canvas.style.height = '100%'; - this.frame.canvas.width = this.frame.canvas.clientWidth; - this.frame.canvas.height = this.frame.canvas.clientHeight; -}; -/** - * Set a data set with nodes for the graph - * @param {Array | DataSet | DataView} nodes The data containing the nodes. - * @private - */ -Graph.prototype._setNodes = function(nodes) { - var oldNodesData = this.nodesData; - if (nodes instanceof DataSet || nodes instanceof DataView) { - this.nodesData = nodes; - } - else if (nodes instanceof Array) { - this.nodesData = new DataSet(); - this.nodesData.add(nodes); - } - else if (!nodes) { - this.nodesData = new DataSet(); - } - else { - throw new TypeError('Array or DataSet expected'); - } - if (oldNodesData) { - // unsubscribe from old dataset - util.forEach(this.nodesListeners, function (callback, event) { - oldNodesData.unsubscribe(event, callback); - }); - } + /** + * We determine how many connections denote an important hub. + * We take the mean + 2*std as the important hub size. (Assuming a normal distribution of data, ~2.2%) + * + * @private + */ + _getHubSize : function() { + var average = 0; + var averageSquared = 0; + var hubCounter = 0; + var largestHub = 0; + + for (var i = 0; i < this.nodeIndices.length; i++) { + var node = this.nodes[this.nodeIndices[i]]; + if (node.dynamicEdgesLength > largestHub) { + largestHub = node.dynamicEdgesLength; + } + average += node.dynamicEdgesLength; + averageSquared += Math.pow(node.dynamicEdgesLength,2); + hubCounter += 1; + } + average = average / hubCounter; + averageSquared = averageSquared / hubCounter; - // remove drawn nodes - this.nodes = {}; + var variance = averageSquared - Math.pow(average,2); - if (this.nodesData) { - // subscribe to new dataset - var me = this; - util.forEach(this.nodesListeners, function (callback, event) { - me.nodesData.subscribe(event, callback); - }); + var standardDeviation = Math.sqrt(variance); - // draw all new nodes - var ids = this.nodesData.getIds(); - this._addNodes(ids); - } + this.hubThreshold = Math.floor(average + 2*standardDeviation); - this._updateSelection(); -}; + // always have at least one to cluster + if (this.hubThreshold > largestHub) { + this.hubThreshold = largestHub; + } -/** - * Add nodes - * @param {Number[] | String[]} ids - * @private - */ -Graph.prototype._addNodes = function(ids) { - var id; - for (var i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - var data = this.nodesData.get(id); - var node = new Node(data, this.images, this.groups, this.constants); - this.nodes[id] = node; // note: this may replace an existing node + // console.log("average",average,"averageSQ",averageSquared,"var",variance,"std",standardDeviation); + // console.log("hubThreshold:",this.hubThreshold); + }, - if (!node.isFixed()) { - // TODO: position new nodes in a smarter way! - var radius = this.constants.edges.length * 2; - var count = ids.length; - var angle = 2 * Math.PI * (i / count); - node.x = radius * Math.cos(angle); - node.y = radius * Math.sin(angle); - // note: no not use node.isMoving() here, as that gives the current - // velocity of the node, which is zero after creation of the node. - this.moving = true; + /** + * We reduce the amount of "extension nodes" or chains. These are not quickly clustered with the outliers and hubs methods + * with this amount we can cluster specifically on these chains. + * + * @param {Number} fraction | between 0 and 1, the percentage of chains to reduce + * @private + */ + _reduceAmountOfChains : function(fraction) { + this.hubThreshold = 2; + var reduceAmount = Math.floor(this.nodeIndices.length * fraction); + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + if (this.nodes[nodeId].dynamicEdgesLength == 2 && this.nodes[nodeId].dynamicEdges.length >= 2) { + if (reduceAmount > 0) { + this._formClusterFromHub(this.nodes[nodeId],true,true,1); + reduceAmount -= 1; + } + } + } } - } + }, - this._reconnectEdges(); - this._updateValueRange(this.nodes); -}; - -/** - * Update existing nodes, or create them when not yet existing - * @param {Number[] | String[]} ids - * @private - */ -Graph.prototype._updateNodes = function(ids) { - var nodes = this.nodes, - nodesData = this.nodesData; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - var node = nodes[id]; - var data = nodesData.get(id); - if (node) { - // update node - node.setProperties(data, this.constants); - } - else { - // create node - node = new Node(properties, this.images, this.groups, this.constants); - nodes[id] = node; - - if (!node.isFixed()) { - this.moving = true; + /** + * We get the amount of "extension nodes" or chains. These are not quickly clustered with the outliers and hubs methods + * with this amount we can cluster specifically on these chains. + * + * @private + */ + _getChainFraction : function() { + var chains = 0; + var total = 0; + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + if (this.nodes[nodeId].dynamicEdgesLength == 2 && this.nodes[nodeId].dynamicEdges.length >= 2) { + chains += 1; + } + total += 1; } } - } - - this._reconnectEdges(); - this._updateValueRange(nodes); + return chains/total; + } }; -/** - * Remove existing nodes. If nodes do not exist, the method will just ignore it. - * @param {Number[] | String[]} ids - * @private - */ -Graph.prototype._removeNodes = function(ids) { - var nodes = this.nodes; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - delete nodes[id]; - } - - this._reconnectEdges(); - this._updateSelection(); - this._updateValueRange(nodes); -}; -/** - * Load edges by reading the data table - * @param {Array | DataSet | DataView} edges The data containing the edges. - * @private - * @private - */ -Graph.prototype._setEdges = function(edges) { - var oldEdgesData = this.edgesData; +var SelectionMixin = { - if (edges instanceof DataSet || edges instanceof DataView) { - this.edgesData = edges; - } - else if (edges instanceof Array) { - this.edgesData = new DataSet(); - this.edgesData.add(edges); - } - else if (!edges) { - this.edgesData = new DataSet(); - } - else { - throw new TypeError('Array or DataSet expected'); - } + /** + * This function can be called from the _doInAllSectors function + * + * @param object + * @param overlappingNodes + * @private + */ + _getNodesOverlappingWith : function(object, overlappingNodes) { + var nodes = this.nodes; + for (var nodeId in nodes) { + if (nodes.hasOwnProperty(nodeId)) { + if (nodes[nodeId].isOverlappingWith(object)) { + overlappingNodes.push(nodeId); + } + } + } + }, - if (oldEdgesData) { - // unsubscribe from old dataset - util.forEach(this.edgesListeners, function (callback, event) { - oldEdgesData.unsubscribe(event, callback); - }); - } + /** + * retrieve all nodes overlapping with given object + * @param {Object} object An object with parameters left, top, right, bottom + * @return {Number[]} An array with id's of the overlapping nodes + * @private + */ + _getAllNodesOverlappingWith : function (object) { + var overlappingNodes = []; + this._doInAllActiveSectors("_getNodesOverlappingWith",object,overlappingNodes); + return overlappingNodes; + }, - // remove drawn edges - this.edges = {}; - if (this.edgesData) { - // subscribe to new dataset - var me = this; - util.forEach(this.edgesListeners, function (callback, event) { - me.edgesData.subscribe(event, callback); - }); + /** + * retrieve all nodes in the navigation controls overlapping with given object + * @param {Object} object An object with parameters left, top, right, bottom + * @return {Number[]} An array with id's of the overlapping nodes + * @private + */ + _getAllNavigationNodesOverlappingWith : function (object) { + var overlappingNodes = []; + this._doInNavigationSector("_getNodesOverlappingWith",object,overlappingNodes); + return overlappingNodes; + }, - // draw all new nodes - var ids = this.edgesData.getIds(); - this._addEdges(ids); - } + /** + * Return a position object in canvasspace from a single point in screenspace + * + * @param pointer + * @returns {{left: number, top: number, right: number, bottom: number}} + * @private + */ + _pointerToPositionObject : function(pointer) { + var x = this._canvasToX(pointer.x); + var y = this._canvasToY(pointer.y); + + return {left: x, + top: y, + right: x, + bottom: y}; + }, - this._reconnectEdges(); -}; + /** + * Return a position object in canvasspace from a single point in screenspace + * + * @param pointer + * @returns {{left: number, top: number, right: number, bottom: number}} + * @private + */ + _pointerToScreenPositionObject : function(pointer) { + var x = pointer.x; + var y = pointer.y; + + return {left: x, + top: y, + right: x, + bottom: y}; + }, -/** - * Add edges - * @param {Number[] | String[]} ids - * @private - */ -Graph.prototype._addEdges = function (ids) { - var edges = this.edges, - edgesData = this.edgesData; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - var oldEdge = edges[id]; - if (oldEdge) { - oldEdge.disconnect(); + /** + * Get the top navigation controls node at the a specific point (like a click) + * + * @param {{x: Number, y: Number}} pointer + * @return {Node | null} node + * @private + */ + _getNavigationNodeAt : function (pointer) { + var screenPositionObject = this._pointerToScreenPositionObject(pointer); + var overlappingNodes = this._getAllNavigationNodesOverlappingWith(screenPositionObject); + if (overlappingNodes.length > 0) { + return this.sectors["navigation"]["nodes"][overlappingNodes[overlappingNodes.length - 1]]; } + else { + return null; + } + }, - var data = edgesData.get(id); - edges[id] = new Edge(data, this, this.constants); - } - - this.moving = true; - this._updateValueRange(edges); -}; -/** - * Update existing edges, or create them when not yet existing - * @param {Number[] | String[]} ids - * @private - */ -Graph.prototype._updateEdges = function (ids) { - var edges = this.edges, - edgesData = this.edgesData; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; + /** + * Get the top node at the a specific point (like a click) + * + * @param {{x: Number, y: Number}} pointer + * @return {Node | null} node + * @private + */ + _getNodeAt : function (pointer) { + // we first check if this is an navigation controls element + var positionObject = this._pointerToPositionObject(pointer); + overlappingNodes = this._getAllNodesOverlappingWith(positionObject); - var data = edgesData.get(id); - var edge = edges[id]; - if (edge) { - // update edge - edge.disconnect(); - edge.setProperties(data, this.constants); - edge.connect(); + // if there are overlapping nodes, select the last one, this is the + // one which is drawn on top of the others + if (overlappingNodes.length > 0) { + return this.nodes[overlappingNodes[overlappingNodes.length - 1]]; } else { - // create edge - edge = new Edge(data, this, this.constants); - this.edges[id] = edge; + return null; } - } + }, - this.moving = true; - this._updateValueRange(edges); -}; -/** - * Remove existing edges. Non existing ids will be ignored - * @param {Number[] | String[]} ids - * @private - */ -Graph.prototype._removeEdges = function (ids) { - var edges = this.edges; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - var edge = edges[id]; - if (edge) { - edge.disconnect(); - delete edges[id]; - } - } + /** + * Place holder. To implement change the _getNodeAt to a _getObjectAt. Have the _getObjectAt call + * _getNodeAt and _getEdgesAt, then priortize the selection to user preferences. + * + * @param pointer + * @returns {null} + * @private + */ + _getEdgeAt : function(pointer) { + return null; + }, - this.moving = true; - this._updateValueRange(edges); -}; -/** - * Reconnect all edges - * @private - */ -Graph.prototype._reconnectEdges = function() { - var id, - nodes = this.nodes, - edges = this.edges; - for (id in nodes) { - if (nodes.hasOwnProperty(id)) { - nodes[id].edges = []; - } - } + /** + * Add object to the selection array. The this.selection id array may not be needed. + * + * @param obj + * @private + */ + _addToSelection : function(obj) { + this.selection.push(obj.id); + this.selectionObj[obj.id] = obj; + }, - for (id in edges) { - if (edges.hasOwnProperty(id)) { - var edge = edges[id]; - edge.from = null; - edge.to = null; - edge.connect(); + + /** + * Remove a single option from selection. + * + * @param obj + * @private + */ + _removeFromSelection : function(obj) { + for (var i = 0; i < this.selection.length; i++) { + if (obj.id == this.selection[i]) { + this.selection.splice(i,1); + break; + } } - } -}; + delete this.selectionObj[obj.id]; + }, -/** - * Update the values of all object in the given array according to the current - * value range of the objects in the array. - * @param {Object} obj An object containing a set of Edges or Nodes - * The objects must have a method getValue() and - * setValueRange(min, max). - * @private - */ -Graph.prototype._updateValueRange = function(obj) { - var id; - // determine the range of the objects - var valueMin = undefined; - var valueMax = undefined; - for (id in obj) { - if (obj.hasOwnProperty(id)) { - var value = obj[id].getValue(); - if (value !== undefined) { - valueMin = (valueMin === undefined) ? value : Math.min(value, valueMin); - valueMax = (valueMax === undefined) ? value : Math.max(value, valueMax); - } + /** + * Unselect all. The selectionObj is useful for this. + * + * @param {Boolean} [doNotTrigger] | ignore trigger + * @private + */ + _unselectAll : function(doNotTrigger) { + if (doNotTrigger === undefined) { + doNotTrigger = false; } - } - // adjust the range of all objects - if (valueMin !== undefined && valueMax !== undefined) { - for (id in obj) { - if (obj.hasOwnProperty(id)) { - obj[id].setValueRange(valueMin, valueMax); + this.selection = []; + for (var objId in this.selectionObj) { + if (this.selectionObj.hasOwnProperty(objId)) { + this.selectionObj[objId].unselect(); } } - } -}; + this.selectionObj = {}; -/** - * Redraw the graph with the current data - * chart will be resized too. - */ -Graph.prototype.redraw = function() { - this.setSize(this.width, this.height); - - this._redraw(); -}; - -/** - * Redraw the graph with the current data - * @private - */ -Graph.prototype._redraw = function() { - var ctx = this.frame.canvas.getContext('2d'); + if (doNotTrigger == false) { + this._trigger('select', { + nodes: this.getSelection() + }); + } + }, - // clear the canvas - var w = this.frame.canvas.width; - var h = this.frame.canvas.height; - ctx.clearRect(0, 0, w, h); - // set scaling and translation - ctx.save(); - ctx.translate(this.translation.x, this.translation.y); - ctx.scale(this.scale, this.scale); + /** + * Check if anything is selected + * + * @returns {boolean} + * @private + */ + _selectionIsEmpty : function() { + if (this.selection.length == 0) { + return true; + } + else { + return false; + } + }, - this._drawEdges(ctx); - this._drawNodes(ctx); - // restore original scaling and translation - ctx.restore(); -}; + /** + * This is called when someone clicks on a node. either select or deselect it. + * If there is an existing selection and we don't want to append to it, clear the existing selection + * + * @param {Node} node + * @param {Boolean} append + * @param {Boolean} [doNotTrigger] | ignore trigger + * @private + */ + _selectNode : function(node, append, doNotTrigger) { + if (doNotTrigger === undefined) { + doNotTrigger = false; + } -/** - * Set the translation of the graph - * @param {Number} offsetX Horizontal offset - * @param {Number} offsetY Vertical offset - * @private - */ -Graph.prototype._setTranslation = function(offsetX, offsetY) { - if (this.translation === undefined) { - this.translation = { - x: 0, - y: 0 - }; - } + if (this._selectionIsEmpty() == false && append == false) { + this._unselectAll(true); + } - if (offsetX !== undefined) { - this.translation.x = offsetX; - } - if (offsetY !== undefined) { - this.translation.y = offsetY; - } -}; -/** - * Get the translation of the graph - * @return {Object} translation An object with parameters x and y, both a number - * @private - */ -Graph.prototype._getTranslation = function() { - return { - x: this.translation.x, - y: this.translation.y - }; -}; + if (node.selected == false) { + node.select(); + this._addToSelection(node); + } + else { + node.unselect(); + this._removeFromSelection(node); + } + if (doNotTrigger == false) { + this._trigger('select', { + nodes: this.getSelection() + }); + } + }, -/** - * Scale the graph - * @param {Number} scale Scaling factor 1.0 is unscaled - * @private - */ -Graph.prototype._setScale = function(scale) { - this.scale = scale; -}; -/** - * Get the current scale of the graph - * @return {Number} scale Scaling factor 1.0 is unscaled - * @private - */ -Graph.prototype._getScale = function() { - return this.scale; -}; -/** - * Convert a horizontal point on the HTML canvas to the x-value of the model - * @param {number} x - * @returns {number} - * @private - */ -Graph.prototype._canvasToX = function(x) { - return (x - this.translation.x) / this.scale; -}; + /** + * handles the selection part of the touch, only for navigation controls elements; + * Touch is triggered before tap, also before hold. Hold triggers after a while. + * This is the most responsive solution + * + * @param {Object} pointer + * @private + */ + _handleTouch : function(pointer) { + if (this.constants.navigation.enabled == true) { + var node = this._getNavigationNodeAt(pointer); + if (node != null) { + if (this[node.triggerFunction] !== undefined) { + this[node.triggerFunction](); + } + } + } + }, -/** - * Convert an x-value in the model to a horizontal point on the HTML canvas - * @param {number} x - * @returns {number} - * @private - */ -Graph.prototype._xToCanvas = function(x) { - return x * this.scale + this.translation.x; -}; -/** - * Convert a vertical point on the HTML canvas to the y-value of the model - * @param {number} y - * @returns {number} - * @private - */ -Graph.prototype._canvasToY = function(y) { - return (y - this.translation.y) / this.scale; -}; + /** + * handles the selection part of the tap; + * + * @param {Object} pointer + * @private + */ + _handleTap : function(pointer) { + var node = this._getNodeAt(pointer); + if (node != null) { + this._selectNode(node,false); + } + else { + this._unselectAll(); + } + this._redraw(); + }, -/** - * Convert an y-value in the model to a vertical point on the HTML canvas - * @param {number} y - * @returns {number} - * @private - */ -Graph.prototype._yToCanvas = function(y) { - return y * this.scale + this.translation.y ; -}; -/** - * Redraw all nodes - * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Graph.prototype._drawNodes = function(ctx) { - // first draw the unselected nodes - var nodes = this.nodes; - var selected = []; - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - if (nodes[id].isSelected()) { - selected.push(id); - } - else { - nodes[id].draw(ctx); - } + /** + * handles the selection part of the double tap and opens a cluster if needed + * + * @param {Object} pointer + * @private + */ + _handleDoubleTap : function(pointer) { + var node = this._getNodeAt(pointer); + if (node != null && node !== undefined) { + // we reset the areaCenter here so the opening of the node will occur + this.areaCenter = {"x" : this._canvasToX(pointer.x), + "y" : this._canvasToY(pointer.y)}; + this.openCluster(node); } - } + }, - // draw the selected nodes on top - for (var s = 0, sMax = selected.length; s < sMax; s++) { - nodes[selected[s]].draw(ctx); - } -}; -/** - * Redraw all edges - * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Graph.prototype._drawEdges = function(ctx) { - var edges = this.edges; - for (var id in edges) { - if (edges.hasOwnProperty(id)) { - var edge = edges[id]; - if (edge.connected) { - edges[id].draw(ctx); - } + /** + * Handle the onHold selection part + * + * @param pointer + * @private + */ + _handleOnHold : function(pointer) { + var node = this._getNodeAt(pointer); + if (node != null) { + this._selectNode(node,true); } - } -}; + this._redraw(); + }, -/** - * Find a stable position for all nodes - * @private - */ -Graph.prototype._doStabilize = function() { - var start = new Date(); - // find stable position - var count = 0; - var vmin = this.constants.minVelocity; - var stable = false; - while (!stable && count < this.constants.maxIterations) { - this._calculateForces(); - this._discreteStepNodes(); - stable = !this._isMoving(vmin); - count++; - } + /** + * handle the onRelease event. These functions are here for the navigation controls module. + * + * @private + */ + _handleOnRelease : function() { + this.xIncrement = 0; + this.yIncrement = 0; + this.zoomIncrement = 0; + this._unHighlightAll(); + }, - var end = new Date(); - // console.log('Stabilized in ' + (end-start) + ' ms, ' + count + ' iterations' ); // TODO: cleanup -}; -/** - * Calculate the external forces acting on the nodes - * Forces are caused by: edges, repulsing forces between nodes, gravity - * @private - */ -Graph.prototype._calculateForces = function() { - // create a local edge to the nodes and edges, that is faster - var id, dx, dy, angle, distance, fx, fy, - repulsingForce, springForce, length, edgeLength, - nodes = this.nodes, - edges = this.edges; + /** + * + * retrieve the currently selected nodes + * @return {Number[] | String[]} selection An array with the ids of the + * selected nodes. + */ + getSelection : function() { + return this.selection.concat([]); + }, - // gravity, add a small constant force to pull the nodes towards the center of - // the graph - // Also, the forces are reset to zero in this loop by using _setForce instead - // of _addForce - var gravity = 0.01, - gx = this.frame.canvas.clientWidth / 2, - gy = this.frame.canvas.clientHeight / 2; - for (id in nodes) { - if (nodes.hasOwnProperty(id)) { - var node = nodes[id]; - dx = gx - node.x; - dy = gy - node.y; - angle = Math.atan2(dy, dx); - fx = Math.cos(angle) * gravity; - fy = Math.sin(angle) * gravity; + /** + * + * retrieve the currently selected nodes as objects + * @return {Objects} selection An array with the ids of the + * selected nodes. + */ + getSelectionObjects : function() { + return this.selectionObj; + }, - node._setForce(fx, fy); - } - } + /** + * // TODO: rework this function, it is from the old system + * + * select zero or more nodes + * @param {Number[] | String[]} selection An array with the ids of the + * selected nodes. + */ + setSelection : function(selection) { + var i, iMax, id; - // repulsing forces between nodes - var minimumDistance = this.constants.nodes.distance, - steepness = 10; // higher value gives steeper slope of the force around the given minimumDistance + if (!selection || (selection.length == undefined)) + throw 'Selection must be an array with ids'; - for (var id1 in nodes) { - if (nodes.hasOwnProperty(id1)) { - var node1 = nodes[id1]; - for (var id2 in nodes) { - if (nodes.hasOwnProperty(id2)) { - var node2 = nodes[id2]; - // calculate normally distributed force - dx = node2.x - node1.x; - dy = node2.y - node1.y; - distance = Math.sqrt(dx * dx + dy * dy); - angle = Math.atan2(dy, dx); + // first unselect any selected node + this._unselectAll(true); - // TODO: correct factor for repulsing force - //repulsingForce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force - //repulsingForce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force - repulsingForce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)); // TODO: customize the repulsing force - fx = Math.cos(angle) * repulsingForce; - fy = Math.sin(angle) * repulsingForce; + for (i = 0, iMax = selection.length; i < iMax; i++) { + id = selection[i]; - node1._addForce(-fx, -fy); - node2._addForce(fx, fy); - } + var node = this.nodes[id]; + if (!node) { + throw new RangeError('Node with id "' + id + '" not found'); } + this._selectNode(node,true,true); } - } - /* TODO: re-implement repulsion of edges - for (var n = 0; n < nodes.length; n++) { - for (var l = 0; l < edges.length; l++) { - var lx = edges[l].from.x+(edges[l].to.x - edges[l].from.x)/2, - ly = edges[l].from.y+(edges[l].to.y - edges[l].from.y)/2, + this.redraw(); + }, - // calculate normally distributed force - dx = nodes[n].x - lx, - dy = nodes[n].y - ly, - distance = Math.sqrt(dx * dx + dy * dy), - angle = Math.atan2(dy, dx), + /** + * TODO: rework this function, it is from the old system + * + * Validate the selection: remove ids of nodes which no longer exist + * @private + */ + _updateSelection : function () { + var i = 0; + while (i < this.selection.length) { + var nodeId = this.selection[i]; + if (!this.nodes.hasOwnProperty(nodeId)) { + this.selection.splice(i, 1); + delete this.selectionObj[nodeId]; + } + else { + i++; + } + } + } - // TODO: correct factor for repulsing force - //var repulsingforce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force - //repulsingforce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ), // TODO: customize the repulsing force - repulsingforce = 1 / (1 + Math.exp((distance / (minimumDistance / 2) - 1) * steepness)), // TODO: customize the repulsing force - fx = Math.cos(angle) * repulsingforce, - fy = Math.sin(angle) * repulsingforce; - nodes[n]._addForce(fx, fy); - edges[l].from._addForce(-fx/2,-fy/2); - edges[l].to._addForce(-fx/2,-fy/2); - } - } + + /** + * Unselect selected nodes. If no selection array is provided, all nodes + * are unselected + * @param {Object[]} selection Array with selection objects, each selection + * object has a parameter row. Optional + * @param {Boolean} triggerSelect If true (default), the select event + * is triggered when nodes are unselected + * @return {Boolean} changed True if the selection is changed + * @private */ + /* _unselectNodes : function(selection, triggerSelect) { + var changed = false; + var i, iMax, id; + + if (selection) { + // remove provided selections + for (i = 0, iMax = selection.length; i < iMax; i++) { + id = selection[i]; + if (this.nodes.hasOwnProperty(id)) { + this.nodes[id].unselect(); + } + var j = 0; + while (j < this.selection.length) { + if (this.selection[j] == id) { + this.selection.splice(j, 1); + changed = true; + } + else { + j++; + } + } + } + } + else if (this.selection && this.selection.length) { + // remove all selections + for (i = 0, iMax = this.selection.length; i < iMax; i++) { + id = this.selection[i]; + if (this.nodes.hasOwnProperty(id)) { + this.nodes[id].unselect(); + } + changed = true; + } + this.selection = []; + } - // forces caused by the edges, modelled as springs - for (id in edges) { - if (edges.hasOwnProperty(id)) { - var edge = edges[id]; - if (edge.connected) { - dx = (edge.to.x - edge.from.x); - dy = (edge.to.y - edge.from.y); - //edgeLength = (edge.from.width + edge.from.height + edge.to.width + edge.to.height)/2 || edge.length; // TODO: dmin - //edgeLength = (edge.from.width + edge.to.width)/2 || edge.length; // TODO: dmin - //edgeLength = 20 + ((edge.from.width + edge.to.width) || 0) / 2; - edgeLength = edge.length; - length = Math.sqrt(dx * dx + dy * dy); - angle = Math.atan2(dy, dx); + if (changed && (triggerSelect == true || triggerSelect == undefined)) { + // fire the select event + this._trigger('select', { + nodes: this.getSelection() + }); + } - springForce = edge.stiffness * (edgeLength - length); + return changed; + }, +*/ +/** + * select all nodes on given location x, y + * @param {Array} selection an array with node ids + * @param {boolean} append If true, the new selection will be appended to the + * current selection (except for duplicate entries) + * @return {Boolean} changed True if the selection is changed + * @private + */ +/* _selectNodes : function(selection, append) { + var changed = false; + var i, iMax; - fx = Math.cos(angle) * springForce; - fy = Math.sin(angle) * springForce; + // TODO: the selectNodes method is a little messy, rework this - edge.from._addForce(-fx, -fy); - edge.to._addForce(fx, fy); + // check if the current selection equals the desired selection + var selectionAlreadyThere = true; + if (selection.length != this.selection.length) { + selectionAlreadyThere = false; + } + else { + for (i = 0, iMax = Math.min(selection.length, this.selection.length); i < iMax; i++) { + if (selection[i] != this.selection[i]) { + selectionAlreadyThere = false; + break; + } } } - } - - /* TODO: re-implement repulsion of edges - // repulsing forces between edges - var minimumDistance = this.constants.edges.distance, - steepness = 10; // higher value gives steeper slope of the force around the given minimumDistance - for (var l = 0; l < edges.length; l++) { - //Keep distance from other edge centers - for (var l2 = l + 1; l2 < this.edges.length; l2++) { - //var dmin = (nodes[n].width + nodes[n].height + nodes[n2].width + nodes[n2].height) / 1 || minimumDistance, // TODO: dmin - //var dmin = (nodes[n].width + nodes[n2].width)/2 || minimumDistance, // TODO: dmin - //dmin = 40 + ((nodes[n].width/2 + nodes[n2].width/2) || 0), - var lx = edges[l].from.x+(edges[l].to.x - edges[l].from.x)/2, - ly = edges[l].from.y+(edges[l].to.y - edges[l].from.y)/2, - l2x = edges[l2].from.x+(edges[l2].to.x - edges[l2].from.x)/2, - l2y = edges[l2].from.y+(edges[l2].to.y - edges[l2].from.y)/2, + if (selectionAlreadyThere) { + return changed; + } - // calculate normally distributed force - dx = l2x - lx, - dy = l2y - ly, - distance = Math.sqrt(dx * dx + dy * dy), - angle = Math.atan2(dy, dx), + if (append == undefined || append == false) { + // first deselect any selected node + var triggerSelect = false; + changed = this._unselectNodes(undefined, triggerSelect); + } + for (i = 0, iMax = selection.length; i < iMax; i++) { + // add each of the new selections, but only when they are not duplicate + var id = selection[i]; + var isDuplicate = (this.selection.indexOf(id) != -1); + if (!isDuplicate) { + this.nodes[id].select(); + this.selection.push(id); + changed = true; + } + } - // TODO: correct factor for repulsing force - //var repulsingforce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force - //repulsingforce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ), // TODO: customize the repulsing force - repulsingforce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)), // TODO: customize the repulsing force - fx = Math.cos(angle) * repulsingforce, - fy = Math.sin(angle) * repulsingforce; + if (changed) { + // fire the select event + this._trigger('select', { + nodes: this.getSelection() + }); + } - edges[l].from._addForce(-fx, -fy); - edges[l].to._addForce(-fx, -fy); - edges[l2].from._addForce(fx, fy); - edges[l2].to._addForce(fx, fy); - } - } - */ + return changed; + }, + */ }; + + /** - * Check if any of the nodes is still moving - * @param {number} vmin the minimum velocity considered as 'moving' - * @return {boolean} true if moving, false if non of the nodes is moving - * @private + * Created by Alex on 1/22/14. */ -Graph.prototype._isMoving = function(vmin) { - // TODO: ismoving does not work well: should check the kinetic energy, not its velocity - var nodes = this.nodes; - for (var id in nodes) { - if (nodes.hasOwnProperty(id) && nodes[id].isMoving(vmin)) { - return true; + +var NavigationMixin = { + + /** + * This function moves the navigation controls if the canvas size has been changed. If the arugments + * verticaAlignTop and horizontalAlignLeft are false, the correction will be made + * + * @private + */ + _relocateNavigation : function() { + if (this.sectors !== undefined) { + var xOffset = this.navigationClientWidth - this.frame.canvas.clientWidth; + var yOffset = this.navigationClientHeight - this.frame.canvas.clientHeight; + this.navigationClientWidth = this.frame.canvas.clientWidth; + this.navigationClientHeight = this.frame.canvas.clientHeight; + var node = null; + + for (var nodeId in this.sectors["navigation"]["nodes"]) { + if (this.sectors["navigation"]["nodes"].hasOwnProperty(nodeId)) { + node = this.sectors["navigation"]["nodes"][nodeId]; + if (!node.horizontalAlignLeft) { + node.x -= xOffset; + } + if (!node.verticalAlignTop) { + node.y -= yOffset; + } + } + } } - } - return false; -}; + }, -/** - * Perform one discrete step for all nodes - * @private - */ -Graph.prototype._discreteStepNodes = function() { - var interval = this.refreshRate / 1000.0; // in seconds - var nodes = this.nodes; - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - nodes[id].discreteStep(interval); + /** + * Creation of the navigation controls nodes. They are drawn over the rest of the nodes and are not affected by scale and translation + * they have a triggerFunction which is called on click. If the position of the navigation controls is dependent + * on this.frame.canvas.clientWidth or this.frame.canvas.clientHeight, we flag horizontalAlignLeft and verticalAlignTop false. + * This means that the location will be corrected by the _relocateNavigation function on a size change of the canvas. + * + * @private + */ + _loadNavigationElements : function() { + var DIR = this.constants.navigation.iconPath; + this.navigationClientWidth = this.frame.canvas.clientWidth; + this.navigationClientHeight = this.frame.canvas.clientHeight; + if (this.navigationClientWidth === undefined) { + this.navigationClientWidth = 0; + this.navigationClientHeight = 0; + } + var offset = 15; + var intermediateOffset = 7; + var navigationNodes = [ + {id: 'navigation_up', shape: 'image', image: DIR + '/uparrow.png', triggerFunction: "_moveUp", + verticalAlignTop: false, x: 45 + offset + intermediateOffset, y: this.navigationClientHeight - 45 - offset - intermediateOffset}, + {id: 'navigation_down', shape: 'image', image: DIR + '/downarrow.png', triggerFunction: "_moveDown", + verticalAlignTop: false, x: 45 + offset + intermediateOffset, y: this.navigationClientHeight - 15 - offset}, + {id: 'navigation_left', shape: 'image', image: DIR + '/leftarrow.png', triggerFunction: "_moveLeft", + verticalAlignTop: false, x: 15 + offset, y: this.navigationClientHeight - 15 - offset}, + {id: 'navigation_right', shape: 'image', image: DIR + '/rightarrow.png',triggerFunction: "_moveRight", + verticalAlignTop: false, x: 75 + offset + 2 * intermediateOffset, y: this.navigationClientHeight - 15 - offset}, + + {id: 'navigation_plus', shape: 'image', image: DIR + '/plus.png', triggerFunction: "_zoomIn", + verticalAlignTop: false, horizontalAlignLeft: false, + x: this.navigationClientWidth - 45 - offset - intermediateOffset, y: this.navigationClientHeight - 15 - offset}, + {id: 'navigation_min', shape: 'image', image: DIR + '/minus.png', triggerFunction: "_zoomOut", + verticalAlignTop: false, horizontalAlignLeft: false, + x: this.navigationClientWidth - 15 - offset, y: this.navigationClientHeight - 15 - offset}, + {id: 'navigation_zoomExtends', shape: 'image', image: DIR + '/zoomExtends.png', triggerFunction: "zoomToFit", + verticalAlignTop: false, horizontalAlignLeft: false, + x: this.navigationClientWidth - 15 - offset, y: this.navigationClientHeight - 45 - offset - intermediateOffset} + ]; + + var nodeObj = null; + for (var i = 0; i < navigationNodes.length; i++) { + nodeObj = this.sectors["navigation"]['nodes']; + nodeObj[navigationNodes[i]['id']] = new Node(navigationNodes[i], this.images, this.groups, this.constants); } - } -}; + }, -/** - * Start animating nodes and edges - */ -Graph.prototype.start = function() { - if (this.moving) { - this._calculateForces(); - this._discreteStepNodes(); - var vmin = this.constants.minVelocity; - this.moving = this._isMoving(vmin); - } + /** + * By setting the clustersize to be larger than 1, we use the clustering drawing method + * to illustrate the buttons are presed. We call this highlighting. + * + * @param {String} elementId + * @private + */ + _highlightNavigationElement : function(elementId) { + if (this.sectors["navigation"]["nodes"].hasOwnProperty(elementId)) { + this.sectors["navigation"]["nodes"][elementId].clusterSize = 2; + } + }, - if (this.moving) { - // start animation. only start timer if it is not already running - if (!this.timer) { - var graph = this; - this.timer = window.setTimeout(function () { - graph.timer = undefined; - graph.start(); - graph._redraw(); - }, this.refreshRate); + + /** + * Reverting back to a normal button + * + * @param {String} elementId + * @private + */ + _unHighlightNavigationElement : function(elementId) { + if (this.sectors["navigation"]["nodes"].hasOwnProperty(elementId)) { + this.sectors["navigation"]["nodes"][elementId].clusterSize = 1; } - } - else { - this._redraw(); - } -}; + }, -/** - * Stop animating nodes and edges. - */ -Graph.prototype.stop = function () { - if (this.timer) { - window.clearInterval(this.timer); - this.timer = undefined; - } -}; + /** + * un-highlight (for lack of a better term) all navigation controls elements + * @private + */ + _unHighlightAll : function() { + for (var nodeId in this.sectors['navigation']['nodes']) { + if (this.sectors['navigation']['nodes'].hasOwnProperty(nodeId)) { + this._unHighlightNavigationElement(nodeId); + } + } + }, -/** - * vis.js module exports - */ -var vis = { - util: util, - events: events, - Controller: Controller, - DataSet: DataSet, - DataView: DataView, - Range: Range, - Stack: Stack, - TimeStep: TimeStep, - EventBus: EventBus, + _preventDefault : function(event) { + if (event !== undefined) { + if (event.preventDefault) { + event.preventDefault(); + } else { + event.returnValue = false; + } + } + }, - components: { - items: { - Item: Item, - ItemBox: ItemBox, - ItemPoint: ItemPoint, - ItemRange: ItemRange - }, - Component: Component, - Panel: Panel, - RootPanel: RootPanel, - ItemSet: ItemSet, - TimeAxis: TimeAxis + /** + * move the screen up + * By using the increments, instead of adding a fixed number to the translation, we keep fluent and + * instant movement. The onKeypress event triggers immediately, then pauses, then triggers frequently + * To avoid this behaviour, we do the translation in the start loop. + * + * @private + */ + _moveUp : function(event) { + this._highlightNavigationElement("navigation_up"); + this.yIncrement = this.constants.keyboard.speed.y; + this.start(); // if there is no node movement, the calculation wont be done + this._preventDefault(event); }, - graph: { - Node: Node, - Edge: Edge, - Popup: Popup, - Groups: Groups, - Images: Images + + /** + * move the screen down + * @private + */ + _moveDown : function(event) { + this._highlightNavigationElement("navigation_down"); + this.yIncrement = -this.constants.keyboard.speed.y; + this.start(); // if there is no node movement, the calculation wont be done + this._preventDefault(event); }, - Timeline: Timeline, - Graph: Graph -}; -/** - * CommonJS module exports - */ -if (typeof exports !== 'undefined') { - exports = vis; -} -if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { - module.exports = vis; -} + /** + * move the screen left + * @private + */ + _moveLeft : function(event) { + this._highlightNavigationElement("navigation_left"); + this.xIncrement = this.constants.keyboard.speed.x; + this.start(); // if there is no node movement, the calculation wont be done + this._preventDefault(event); + }, -/** - * AMD module exports - */ -if (typeof(define) === 'function') { - define(function () { - return vis; - }); -} -/** - * Window exports - */ -if (typeof window !== 'undefined') { - // attach the module to the window, load as a regular javascript file - window['vis'] = vis; -} + /** + * move the screen right + * @private + */ + _moveRight : function(event) { + this._highlightNavigationElement("navigation_right"); + this.xIncrement = -this.constants.keyboard.speed.y; + this.start(); // if there is no node movement, the calculation wont be done + this._preventDefault(event); + }, -},{"hammerjs":2,"moment":3}],2:[function(require,module,exports){ -/*! Hammer.JS - v1.0.5 - 2013-04-07 - * http://eightmedia.github.com/hammer.js - * - * Copyright (c) 2013 Jorik Tangelder ; - * Licensed under the MIT license */ + /** + * Zoom in, using the same method as the movement. + * @private + */ + _zoomIn : function(event) { + this._highlightNavigationElement("navigation_plus"); + this.zoomIncrement = this.constants.keyboard.speed.zoom; + this.start(); // if there is no node movement, the calculation wont be done + this._preventDefault(event); + }, -(function(window, undefined) { - 'use strict'; -/** - * Hammer - * use this to create instances - * @param {HTMLElement} element - * @param {Object} options - * @returns {Hammer.Instance} - * @constructor - */ -var Hammer = function(element, options) { - return new Hammer.Instance(element, options || {}); -}; + /** + * Zoom out + * @private + */ + _zoomOut : function() { + this._highlightNavigationElement("navigation_min"); + this.zoomIncrement = -this.constants.keyboard.speed.zoom; + this.start(); // if there is no node movement, the calculation wont be done + this._preventDefault(event); + }, -// default settings -Hammer.defaults = { - // add styles and attributes to the element to prevent the browser from doing - // its native behavior. this doesnt prevent the scrolling, but cancels - // the contextmenu, tap highlighting etc - // set to false to disable this - stop_browser_behavior: { - // this also triggers onselectstart=false for IE - userSelect: 'none', - // this makes the element blocking in IE10 >, you could experiment with the value - // see for more options this issue; https://github.com/EightMedia/hammer.js/issues/241 - touchAction: 'none', - touchCallout: 'none', - contentZooming: 'none', - userDrag: 'none', - tapHighlightColor: 'rgba(0,0,0,0)' - } - // more settings are defined per gesture at gestures.js -}; + /** + * Stop zooming and unhighlight the zoom controls + * @private + */ + _stopZoom : function() { + this._unHighlightNavigationElement("navigation_plus"); + this._unHighlightNavigationElement("navigation_min"); -// detect touchevents -Hammer.HAS_POINTEREVENTS = navigator.pointerEnabled || navigator.msPointerEnabled; -Hammer.HAS_TOUCHEVENTS = ('ontouchstart' in window); + this.zoomIncrement = 0; + }, -// dont use mouseevents on mobile devices -Hammer.MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i; -Hammer.NO_MOUSEEVENTS = Hammer.HAS_TOUCHEVENTS && navigator.userAgent.match(Hammer.MOBILE_REGEX); -// eventtypes per touchevent (start, move, end) -// are filled by Hammer.event.determineEventTypes on setup -Hammer.EVENT_TYPES = {}; + /** + * Stop moving in the Y direction and unHighlight the up and down + * @private + */ + _yStopMoving : function() { + this._unHighlightNavigationElement("navigation_up"); + this._unHighlightNavigationElement("navigation_down"); -// direction defines -Hammer.DIRECTION_DOWN = 'down'; -Hammer.DIRECTION_LEFT = 'left'; -Hammer.DIRECTION_UP = 'up'; -Hammer.DIRECTION_RIGHT = 'right'; + this.yIncrement = 0; + }, -// pointer type -Hammer.POINTER_MOUSE = 'mouse'; -Hammer.POINTER_TOUCH = 'touch'; -Hammer.POINTER_PEN = 'pen'; -// touch event defines -Hammer.EVENT_START = 'start'; -Hammer.EVENT_MOVE = 'move'; -Hammer.EVENT_END = 'end'; + /** + * Stop moving in the X direction and unHighlight left and right. + * @private + */ + _xStopMoving : function() { + this._unHighlightNavigationElement("navigation_left"); + this._unHighlightNavigationElement("navigation_right"); -// hammer document where the base events are added at -Hammer.DOCUMENT = document; + this.xIncrement = 0; + } -// plugins namespace -Hammer.plugins = {}; -// if the window events are set... -Hammer.READY = false; +}; /** - * setup events to detect gestures on the document + * @constructor Graph + * Create a graph visualization, displaying nodes and edges. + * + * @param {Element} container The DOM element in which the Graph will + * be created. Normally a div element. + * @param {Object} data An object containing parameters + * {Array} nodes + * {Array} edges + * @param {Object} options Options */ -function setup() { - if(Hammer.READY) { - return; - } +function Graph (container, data, options) { + // create variables and set default values + this.containerElement = container; + this.width = '100%'; + this.height = '100%'; + // to give everything a nice fluidity, we seperate the rendering and calculating of the forces + this.renderRefreshRate = 60; // hz (fps) + this.renderTimestep = 1000 / this.renderRefreshRate; // ms -- saves calculation later on + this.stabilize = true; // stabilize before displaying the graph + this.selectable = true; - // find what eventtypes we add listeners to - Hammer.event.determineEventTypes(); + this.forceFactor = 50000; - // Register all gestures inside Hammer.gestures - for(var name in Hammer.gestures) { - if(Hammer.gestures.hasOwnProperty(name)) { - Hammer.detection.register(Hammer.gestures[name]); + // set constant values + this.constants = { + nodes: { + radiusMin: 5, + radiusMax: 20, + radius: 5, + distance: 100, // px + shape: 'ellipse', + image: undefined, + widthMin: 16, // px + widthMax: 64, // px + fontColor: 'black', + fontSize: 14, // px + //fontFace: verdana, + fontFace: 'arial', + color: { + border: '#2B7CE9', + background: '#97C2FC', + highlight: { + border: '#2B7CE9', + background: '#D2E5FF' } - } - - // Add touch events on the document - Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_MOVE, Hammer.detection.detect); - Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_END, Hammer.detection.detect); + }, + borderColor: '#2B7CE9', + backgroundColor: '#97C2FC', + highlightColor: '#D2E5FF', + group: undefined + }, + edges: { + widthMin: 1, + widthMax: 15, + width: 1, + style: 'line', + color: '#343434', + fontColor: '#343434', + fontSize: 14, // px + fontFace: 'arial', + //distance: 100, //px + length: 100, // px + dash: { + length: 10, + gap: 5, + altLength: undefined + } + }, + clustering: { // Per Node in Cluster = PNiC + enabled: false, // (Boolean) | global on/off switch for clustering. + initialMaxNodes: 100, // (# nodes) | if the initial amount of nodes is larger than this, we cluster until the total number is less than this threshold. + clusterThreshold:500, // (# nodes) | during calculate forces, we check if the total number of nodes is larger than this. If it is, cluster until reduced to reduceToNodes + reduceToNodes:300, // (# nodes) | during calculate forces, we check if the total number of nodes is larger than clusterThreshold. If it is, cluster until reduced to this + chainThreshold: 0.4, // (% of all drawn nodes)| maximum percentage of allowed chainnodes (long strings of connected nodes) within all nodes. (lower means less chains). + clusterEdgeThreshold: 20, // (px) | edge length threshold. if smaller, this node is clustered. + sectorThreshold: 50, // (# nodes in cluster) | cluster size threshold. If larger, expanding in own sector. + screenSizeThreshold: 0.2, // (% of canvas) | relative size threshold. If the width or height of a clusternode takes up this much of the screen, decluster node. + fontSizeMultiplier: 4.0, // (px PNiC) | how much the cluster font size grows per node in cluster (in px). + forceAmplification: 0.6, // (multiplier PNiC) | factor of increase fo the repulsion force of a cluster (per node in cluster). + distanceAmplification: 0.2, // (multiplier PNiC) | factor how much the repulsion distance of a cluster increases (per node in cluster). + edgeGrowth: 11, // (px PNiC) | amount of clusterSize connected to the edge is multiplied with this and added to edgeLength. + nodeScaling: {width: 10, // (px PNiC) | growth of the width per node in cluster. + height: 10, // (px PNiC) | growth of the height per node in cluster. + radius: 10}, // (px PNiC) | growth of the radius per node in cluster. + activeAreaBoxSize: 100, // (px) | box area around the curser where clusters are popped open. + massTransferCoefficient: 1 // (multiplier) | parent.mass += massTransferCoefficient * child.mass + }, + navigation: { + enabled: false, + iconPath: this._getScriptPath() + '/img' + }, + keyboard: { + enabled: false, + speed: {x: 10, y: 10, zoom: 0.02} + }, + minVelocity: 2, // px/s + maxIterations: 1000 // maximum number of iteration to stabilize + }; - // Hammer is ready...! - Hammer.READY = true; -} + // Node variables + this.groups = new Groups(); // object with groups + this.images = new Images(); // object with images + this.images.setOnloadCallback(function () { + graph._redraw(); + }); -/** - * create new hammer instance - * all methods should return the instance itself, so it is chainable. - * @param {HTMLElement} element - * @param {Object} [options={}] - * @returns {Hammer.Instance} - * @constructor - */ -Hammer.Instance = function(element, options) { - var self = this; + // navigation variables + this.xIncrement = 0; + this.yIncrement = 0; + this.zoomIncrement = 0; - // setup HammerJS window events and register all gestures - // this also sets up the default options - setup(); + // create a frame and canvas + this._create(); - this.element = element; + // load the sector system. (mandatory, fully integrated with Graph) + this._loadSectorSystem(); - // start/stop detection option - this.enabled = true; + // apply options + this.setOptions(options); - // merge options - this.options = Hammer.utils.extend( - Hammer.utils.extend({}, Hammer.defaults), - options || {}); + // load the cluster system. (mandatory, even when not using the cluster system, there are function calls to it) + this._loadClusterSystem(); - // add some css to the element to prevent the browser from doing its native behavoir - if(this.options.stop_browser_behavior) { - Hammer.utils.stopDefaultBrowserBehavior(this.element, this.options.stop_browser_behavior); - } + // load the selection system. (mandatory, required by Graph) + this._loadSelectionSystem(); - // start detection on touchstart - Hammer.event.onTouch(element, Hammer.EVENT_START, function(ev) { - if(self.enabled) { - Hammer.detection.startDetect(self, ev); - } - }); + // other vars + var graph = this; + this.freezeSimulation = false;// freeze the simulation - // return instance - return this; -}; + this.nodeIndices = []; // array with all the indices of the nodes. Used to speed up forces calculation + this.nodes = {}; // object with Node objects + this.edges = {}; // object with Edge objects + this.canvasTopLeft = {"x": 0,"y": 0}; // coordinates of the top left of the canvas. they will be set during _redraw. + this.canvasBottomRight = {"x": 0,"y": 0}; // coordinates of the bottom right of the canvas. they will be set during _redraw -Hammer.Instance.prototype = { - /** - * bind events to the instance - * @param {String} gesture - * @param {Function} handler - * @returns {Hammer.Instance} - */ - on: function onEvent(gesture, handler){ - var gestures = gesture.split(' '); - for(var t=0; t (node.x - node.width)) {minX = node.x - node.width;} + if (maxX < (node.x + node.width)) {maxX = node.x + node.width;} + if (minY > (node.y - node.height)) {minY = node.y - node.height;} + if (maxY < (node.y + node.height)) {maxY = node.y + node.height;} + } + return {minX: minX, maxX: maxX, minY: minY, maxY: maxY}; +}; /** - * when the mouse is hold down, this is true - * @type {Boolean} + * @param {object} range = {minX: minX, maxX: maxX, minY: minY, maxY: maxY}; + * @returns {{x: number, y: number}} + * @private */ -var enable_detect = false; +Graph.prototype._findCenter = function(range) { + var center = {x: (0.5 * (range.maxX + range.minX)), + y: (0.5 * (range.maxY + range.minY))}; + return center; +}; /** - * when touch events have been fired, this is true - * @type {Boolean} + * center the graph + * + * @param {object} range = {minX: minX, maxX: maxX, minY: minY, maxY: maxY}; */ -var touch_triggered = false; +Graph.prototype._centerGraph = function(range) { + var center = this._findCenter(range); + center.x *= this.scale; + center.y *= this.scale; + center.x -= 0.5 * this.frame.canvas.clientWidth; + center.y -= 0.5 * this.frame.canvas.clientHeight; -Hammer.event = { - /** - * simple addEventListener - * @param {HTMLElement} element - * @param {String} type - * @param {Function} handler - */ - bindDom: function(element, type, handler) { - var types = type.split(' '); - for(var t=0; t= this.constants.clustering.initialMaxNodes) { + var zoomLevel = 38.8467 / (numberOfNodes - 14.50184) + 0.0116; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. + } + else { + var zoomLevel = 42.54117319 / (numberOfNodes + 39.31966387) + 0.1944405; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. + } + } + else { + var xDistance = (Math.abs(range.minX) + Math.abs(range.maxX)) * 1.1; + var yDistance = (Math.abs(range.minY) + Math.abs(range.maxY)) * 1.1; - // mousebutton must be down or a touch event - else if( sourceEventType.match(/touch/) || // touch events are always on screen - sourceEventType.match(/pointerdown/) || // pointerevents touch - (sourceEventType.match(/mouse/) && ev.which === 1) // mouse is pressed - ){ - enable_detect = true; - } + var xZoomLevel = this.frame.canvas.clientWidth / xDistance; + var yZoomLevel = this.frame.canvas.clientHeight / yDistance; - // we are in a touch event, set the touch triggered bool to true, - // this for the conflicts that may occur on ios and android - if(sourceEventType.match(/touch|pointer/)) { - touch_triggered = true; - } + zoomLevel = (xZoomLevel <= yZoomLevel) ? xZoomLevel : yZoomLevel; + } - // count the total touches on the screen - var count_touches = 0; + if (zoomLevel > 1.0) { + zoomLevel = 1.0; + } - // when touch has been triggered in this detection session - // and we are now handling a mouse event, we stop that to prevent conflicts - if(enable_detect) { - // update pointerevent - if(Hammer.HAS_POINTEREVENTS && eventType != Hammer.EVENT_END) { - count_touches = Hammer.PointerEvent.updatePointer(eventType, ev); - } - // touch - else if(sourceEventType.match(/touch/)) { - count_touches = ev.touches.length; - } - // mouse - else if(!touch_triggered) { - count_touches = sourceEventType.match(/up/) ? 0 : 1; - } + this.pinch.mousewheelScale = zoomLevel; + this._setScale(zoomLevel); + this._centerGraph(range); + this.start(); +}; - // if we are in a end event, but when we remove one touch and - // we still have enough, set eventType to move - if(count_touches > 0 && eventType == Hammer.EVENT_END) { - eventType = Hammer.EVENT_MOVE; - } - // no touches, force the end event - else if(!count_touches) { - eventType = Hammer.EVENT_END; - } - // because touchend has no touches, and we often want to use these in our gestures, - // we send the last move event as our eventData in touchend - if(!count_touches && last_move_event !== null) { - ev = last_move_event; - } - // store the last move event - else { - last_move_event = ev; - } +/** + * Update the this.nodeIndices with the most recent node index list + * @private + */ +Graph.prototype._updateNodeIndexList = function() { + this._clearNodeIndexList(); + for (var idx in this.nodes) { + if (this.nodes.hasOwnProperty(idx)) { + this.nodeIndices.push(idx); + } + } +}; - // trigger the handler - handler.call(Hammer.detection, self.collectEventData(element, eventType, ev)); - // remove pointerevent from list - if(Hammer.HAS_POINTEREVENTS && eventType == Hammer.EVENT_END) { - count_touches = Hammer.PointerEvent.updatePointer(eventType, ev); - } - } +/** + * Set nodes and edges, and optionally options as well. + * + * @param {Object} data Object containing parameters: + * {Array | DataSet | DataView} [nodes] Array with nodes + * {Array | DataSet | DataView} [edges] Array with edges + * {String} [dot] String containing data in DOT format + * {Options} [options] Object with options + * @param {Boolean} [disableStart] | optional: disable the calling of the start function. + */ +Graph.prototype.setData = function(data, disableStart) { + if (disableStart === undefined) { + disableStart = false; + } - //debug(sourceEventType +" "+ eventType); + if (data && data.dot && (data.nodes || data.edges)) { + throw new SyntaxError('Data must contain either parameter "dot" or ' + + ' parameter pair "nodes" and "edges", but not both.'); + } - // on the end we reset everything - if(!count_touches) { - last_move_event = null; - enable_detect = false; - touch_triggered = false; - Hammer.PointerEvent.reset(); - } - }); - }, + // set options + this.setOptions(data && data.options); + + // set all data + if (data && data.dot) { + // parse DOT file + if(data && data.dot) { + var dotData = vis.util.DOTToGraph(data.dot); + this.setData(dotData); + return; + } + } + else { + this._setNodes(data && data.nodes); + this._setEdges(data && data.edges); + } + this._putDataInSector(); - /** - * we have different events for each device/browser - * determine what we need and set them in the Hammer.EVENT_TYPES constant - */ - determineEventTypes: function determineEventTypes() { - // determine the eventtype we want to set - var types; + if (!disableStart) { + // find a stable position or start animating to a stable position + if (this.stabilize) { + this._doStabilize(); + } + this.moving = true; + this.start(); + } +}; - // pointerEvents magic - if(Hammer.HAS_POINTEREVENTS) { - types = Hammer.PointerEvent.getEvents(); +/** + * Set options + * @param {Object} options + */ +Graph.prototype.setOptions = function (options) { + if (options) { + // retrieve parameter values + if (options.width !== undefined) {this.width = options.width;} + if (options.height !== undefined) {this.height = options.height;} + if (options.stabilize !== undefined) {this.stabilize = options.stabilize;} + if (options.selectable !== undefined) {this.selectable = options.selectable;} + + if (options.clustering) { + this.constants.clustering.enabled = true; + for (var prop in options.clustering) { + if (options.clustering.hasOwnProperty(prop)) { + this.constants.clustering[prop] = options.clustering[prop]; } - // on Android, iOS, blackberry, windows mobile we dont want any mouseevents - else if(Hammer.NO_MOUSEEVENTS) { - types = [ - 'touchstart', - 'touchmove', - 'touchend touchcancel']; + } + } + else if (options.clustering !== undefined) { + this.constants.clustering.enabled = false; + } + + if (options.navigation) { + this.constants.navigation.enabled = true; + for (var prop in options.navigation) { + if (options.navigation.hasOwnProperty(prop)) { + this.constants.navigation[prop] = options.navigation[prop]; } - // for non pointer events browsers and mixed browsers, - // like chrome on windows8 touch laptop - else { - types = [ - 'touchstart mousedown', - 'touchmove mousemove', - 'touchend touchcancel mouseup']; + } + } + else if (options.navigation !== undefined) { + this.constants.navigation.enabled = false; + } + + if (options.keyboard) { + this.constants.keyboard.enabled = true; + for (var prop in options.keyboard) { + if (options.keyboard.hasOwnProperty(prop)) { + this.constants.keyboard[prop] = options.keyboard[prop]; } + } + } + else if (options.keyboard !== undefined) { + this.constants.keyboard.enabled = false; + } - Hammer.EVENT_TYPES[Hammer.EVENT_START] = types[0]; - Hammer.EVENT_TYPES[Hammer.EVENT_MOVE] = types[1]; - Hammer.EVENT_TYPES[Hammer.EVENT_END] = types[2]; - }, + // TODO: work out these options and document them + if (options.edges) { + for (prop in options.edges) { + if (options.edges.hasOwnProperty(prop)) { + this.constants.edges[prop] = options.edges[prop]; + } + } - /** - * create touchlist depending on the event - * @param {Object} ev - * @param {String} eventType used by the fakemultitouch plugin - */ - getTouchList: function getTouchList(ev/*, eventType*/) { - // get the fake pointerEvent touchlist - if(Hammer.HAS_POINTEREVENTS) { - return Hammer.PointerEvent.getTouchList(); + if (options.edges.length !== undefined && + options.nodes && options.nodes.distance === undefined) { + this.constants.edges.length = options.edges.length; + this.constants.nodes.distance = options.edges.length * 1.25; + } + + if (!options.edges.fontColor) { + this.constants.edges.fontColor = options.edges.color; + } + + // Added to support dashed lines + // David Jordan + // 2012-08-08 + if (options.edges.dash) { + if (options.edges.dash.length !== undefined) { + this.constants.edges.dash.length = options.edges.dash.length; } - // get the touchlist - else if(ev.touches) { - return ev.touches; + if (options.edges.dash.gap !== undefined) { + this.constants.edges.dash.gap = options.edges.dash.gap; } - // make fake touchlist from mouse position - else { - return [{ - identifier: 1, - pageX: ev.pageX, - pageY: ev.pageY, - target: ev.target - }]; + if (options.edges.dash.altLength !== undefined) { + this.constants.edges.dash.altLength = options.edges.dash.altLength; } - }, + } + } + if (options.nodes) { + for (prop in options.nodes) { + if (options.nodes.hasOwnProperty(prop)) { + this.constants.nodes[prop] = options.nodes[prop]; + } + } - /** - * collect event data for Hammer js - * @param {HTMLElement} element - * @param {String} eventType like Hammer.EVENT_MOVE - * @param {Object} eventData - */ - collectEventData: function collectEventData(element, eventType, ev) { - var touches = this.getTouchList(ev, eventType); + if (options.nodes.color) { + this.constants.nodes.color = Node.parseColor(options.nodes.color); + } - // find out pointerType - var pointerType = Hammer.POINTER_TOUCH; - if(ev.type.match(/mouse/) || Hammer.PointerEvent.matchType(Hammer.POINTER_MOUSE, ev)) { - pointerType = Hammer.POINTER_MOUSE; + /* + if (options.nodes.widthMin) this.constants.nodes.radiusMin = options.nodes.widthMin; + if (options.nodes.widthMax) this.constants.nodes.radiusMax = options.nodes.widthMax; + */ + } + if (options.groups) { + for (var groupname in options.groups) { + if (options.groups.hasOwnProperty(groupname)) { + var group = options.groups[groupname]; + this.groups.add(groupname, group); } + } + } + } - return { - center : Hammer.utils.getCenter(touches), - timeStamp : new Date().getTime(), - target : ev.target, - touches : touches, - eventType : eventType, - pointerType : pointerType, - srcEvent : ev, - - /** - * prevent the browser default actions - * mostly used to disable scrolling of the browser - */ - preventDefault: function() { - if(this.srcEvent.preventManipulation) { - this.srcEvent.preventManipulation(); - } + this.setSize(this.width, this.height); + this._setTranslation(this.frame.clientWidth / 2, this.frame.clientHeight / 2); + this._setScale(1); - if(this.srcEvent.preventDefault) { - this.srcEvent.preventDefault(); - } - }, + // load the navigation system. + this._loadNavigationControls(); - /** - * stop bubbling the event up to its parents - */ - stopPropagation: function() { - this.srcEvent.stopPropagation(); - }, + // bind keys. If disabled, this will not do anything; + this._createKeyBinds(); - /** - * immediately stop gesture detection - * might be useful after a swipe was detected - * @return {*} - */ - stopDetect: function() { - return Hammer.detection.stopDetect(); - } - }; - } + this._redraw(); }; -Hammer.PointerEvent = { - /** - * holds all pointers - * @type {Object} - */ - pointers: {}, - - /** - * get a list of pointers - * @returns {Array} touchlist - */ - getTouchList: function() { - var self = this; - var touchlist = []; +/** + * Add event listener + * @param {String} event Event name. Available events: + * 'select' + * @param {function} callback Callback function, invoked as callback(properties) + * where properties is an optional object containing + * event specific properties. + */ +Graph.prototype.on = function on (event, callback) { + var available = ['select']; - // we can use forEach since pointerEvents only is in IE10 - Object.keys(self.pointers).sort().forEach(function(id) { - touchlist.push(self.pointers[id]); - }); - return touchlist; - }, + if (available.indexOf(event) == -1) { + throw new Error('Unknown event "' + event + '". Choose from ' + available.join()); + } - /** - * update the position of a pointer - * @param {String} type Hammer.EVENT_END - * @param {Object} pointerEvent - */ - updatePointer: function(type, pointerEvent) { - if(type == Hammer.EVENT_END) { - this.pointers = {}; - } - else { - pointerEvent.identifier = pointerEvent.pointerId; - this.pointers[pointerEvent.pointerId] = pointerEvent; - } + events.addListener(this, event, callback); +}; - return Object.keys(this.pointers).length; - }, +/** + * Remove an event listener + * @param {String} event Event name + * @param {function} callback Callback function + */ +Graph.prototype.off = function off (event, callback) { + events.removeListener(this, event, callback); +}; - /** - * check if ev matches pointertype - * @param {String} pointerType Hammer.POINTER_MOUSE - * @param {PointerEvent} ev - */ - matchType: function(pointerType, ev) { - if(!ev.pointerType) { - return false; - } +/** + * fire an event + * @param {String} event The name of an event, for example 'select' + * @param {Object} params Optional object with event parameters + * @private + */ +Graph.prototype._trigger = function (event, params) { + events.trigger(this, event, params); +}; - var types = {}; - types[Hammer.POINTER_MOUSE] = (ev.pointerType == ev.MSPOINTER_TYPE_MOUSE || ev.pointerType == Hammer.POINTER_MOUSE); - types[Hammer.POINTER_TOUCH] = (ev.pointerType == ev.MSPOINTER_TYPE_TOUCH || ev.pointerType == Hammer.POINTER_TOUCH); - types[Hammer.POINTER_PEN] = (ev.pointerType == ev.MSPOINTER_TYPE_PEN || ev.pointerType == Hammer.POINTER_PEN); - return types[pointerType]; - }, +/** + * Create the main frame for the Graph. + * This function is executed once when a Graph object is created. The frame + * contains a canvas, and this canvas contains all objects like the axis and + * nodes. + * @private + */ +Graph.prototype._create = function () { + // remove all elements from the container element. + while (this.containerElement.hasChildNodes()) { + this.containerElement.removeChild(this.containerElement.firstChild); + } - /** - * get events - */ - getEvents: function() { - return [ - 'pointerdown MSPointerDown', - 'pointermove MSPointerMove', - 'pointerup pointercancel MSPointerUp MSPointerCancel' - ]; - }, + this.frame = document.createElement('div'); + this.frame.className = 'graph-frame'; + this.frame.style.position = 'relative'; + this.frame.style.overflow = 'hidden'; - /** - * reset the list - */ - reset: function() { - this.pointers = {}; - } -}; + // create the graph canvas (HTML canvas element) + this.frame.canvas = document.createElement( 'canvas' ); + this.frame.canvas.style.position = 'relative'; + this.frame.appendChild(this.frame.canvas); + if (!this.frame.canvas.getContext) { + var noCanvas = document.createElement( 'DIV' ); + noCanvas.style.color = 'red'; + noCanvas.style.fontWeight = 'bold' ; + noCanvas.style.padding = '10px'; + noCanvas.innerHTML = 'Error: your browser does not support HTML canvas'; + this.frame.canvas.appendChild(noCanvas); + } + var me = this; + this.drag = {}; + this.pinch = {}; + this.hammer = Hammer(this.frame.canvas, { + prevent_default: true + }); + this.hammer.on('tap', me._onTap.bind(me) ); + this.hammer.on('doubletap', me._onDoubleTap.bind(me) ); + this.hammer.on('hold', me._onHold.bind(me) ); + this.hammer.on('pinch', me._onPinch.bind(me) ); + this.hammer.on('touch', me._onTouch.bind(me) ); + this.hammer.on('dragstart', me._onDragStart.bind(me) ); + this.hammer.on('drag', me._onDrag.bind(me) ); + this.hammer.on('dragend', me._onDragEnd.bind(me) ); + this.hammer.on('release', me._onRelease.bind(me) ); + this.hammer.on('mousewheel',me._onMouseWheel.bind(me) ); + this.hammer.on('DOMMouseScroll',me._onMouseWheel.bind(me) ); // for FF + this.hammer.on('mousemove', me._onMouseMoveTitle.bind(me) ); -Hammer.utils = { - /** - * extend method, - * also used for cloning when dest is an empty object - * @param {Object} dest - * @param {Object} src - * @parm {Boolean} merge do a merge - * @returns {Object} dest - */ - extend: function extend(dest, src, merge) { - for (var key in src) { - if(dest[key] !== undefined && merge) { - continue; - } - dest[key] = src[key]; - } - return dest; - }, + // add the frame to the container element + this.containerElement.appendChild(this.frame); +}; + + +/** + * Binding the keys for keyboard navigation. These functions are defined in the NavigationMixin + * @private + */ +Graph.prototype._createKeyBinds = function() { + var me = this; + this.mousetrap = mousetrap; + + this.mousetrap.reset(); + + if (this.constants.keyboard.enabled == true) { + this.mousetrap.bind("up", this._moveUp.bind(me) , "keydown"); + this.mousetrap.bind("up", this._yStopMoving.bind(me), "keyup"); + this.mousetrap.bind("down", this._moveDown.bind(me) , "keydown"); + this.mousetrap.bind("down", this._yStopMoving.bind(me), "keyup"); + this.mousetrap.bind("left", this._moveLeft.bind(me) , "keydown"); + this.mousetrap.bind("left", this._xStopMoving.bind(me), "keyup"); + this.mousetrap.bind("right",this._moveRight.bind(me), "keydown"); + this.mousetrap.bind("right",this._xStopMoving.bind(me), "keyup"); + this.mousetrap.bind("=", this._zoomIn.bind(me), "keydown"); + this.mousetrap.bind("=", this._stopZoom.bind(me), "keyup"); + this.mousetrap.bind("-", this._zoomOut.bind(me), "keydown"); + this.mousetrap.bind("-", this._stopZoom.bind(me), "keyup"); + this.mousetrap.bind("[", this._zoomIn.bind(me), "keydown"); + this.mousetrap.bind("[", this._stopZoom.bind(me), "keyup"); + this.mousetrap.bind("]", this._zoomOut.bind(me), "keydown"); + this.mousetrap.bind("]", this._stopZoom.bind(me), "keyup"); + this.mousetrap.bind("pageup",this._zoomIn.bind(me), "keydown"); + this.mousetrap.bind("pageup",this._stopZoom.bind(me), "keyup"); + this.mousetrap.bind("pagedown",this._zoomOut.bind(me),"keydown"); + this.mousetrap.bind("pagedown",this._stopZoom.bind(me), "keyup"); + } + /* + this.mousetrap.bind("=",this.decreaseClusterLevel.bind(me)); + this.mousetrap.bind("-",this.increaseClusterLevel.bind(me)); + this.mousetrap.bind("s",this.singleStep.bind(me)); + this.mousetrap.bind("h",this.updateClustersDefault.bind(me)); + this.mousetrap.bind("c",this._collapseSector.bind(me)); + this.mousetrap.bind("f",this.toggleFreeze.bind(me)); + */ +} + +/** + * Get the pointer location from a touch location + * @param {{pageX: Number, pageY: Number}} touch + * @return {{x: Number, y: Number}} pointer + * @private + */ +Graph.prototype._getPointer = function (touch) { + return { + x: touch.pageX - vis.util.getAbsoluteLeft(this.frame.canvas), + y: touch.pageY - vis.util.getAbsoluteTop(this.frame.canvas) + }; +}; + +/** + * On start of a touch gesture, store the pointer + * @param event + * @private + */ +Graph.prototype._onTouch = function (event) { + this.drag.pointer = this._getPointer(event.gesture.touches[0]); + this.drag.pinched = false; + this.pinch.scale = this._getScale(); + + this._handleTouch(this.drag.pointer); +}; + +/** + * handle drag start event + * @private + */ +Graph.prototype._onDragStart = function () { + var drag = this.drag; + var node = this._getNodeAt(drag.pointer); + // note: drag.pointer is set in _onTouch to get the initial touch location + + drag.dragging = true; + drag.selection = []; + drag.translation = this._getTranslation(); + drag.nodeId = null; + + if (node != null) { + drag.nodeId = node.id; + // select the clicked node if not yet selected + if (!node.isSelected()) { + this._selectNode(node,false); + } + + // create an array with the selected nodes and their original location and status + var me = this; + this.selection.forEach(function (id) { + var node = me.nodes[id]; + if (node) { + var s = { + id: id, + node: node, + + // store original x, y, xFixed and yFixed, make the node temporarily Fixed + x: node.x, + y: node.y, + xFixed: node.xFixed, + yFixed: node.yFixed + }; + + node.xFixed = true; + node.yFixed = true; + + drag.selection.push(s); + } + }); + } +}; + +/** + * handle drag event + * @private + */ +Graph.prototype._onDrag = function (event) { + if (this.drag.pinched) { + return; + } + + var pointer = this._getPointer(event.gesture.touches[0]); + + var me = this, + drag = this.drag, + selection = drag.selection; + if (selection && selection.length) { + // calculate delta's and new location + var deltaX = pointer.x - drag.pointer.x, + deltaY = pointer.y - drag.pointer.y; + + // update position of all selected nodes + selection.forEach(function (s) { + var node = s.node; + + if (!s.xFixed) { + node.x = me._canvasToX(me._xToCanvas(s.x) + deltaX); + } + + if (!s.yFixed) { + node.y = me._canvasToY(me._yToCanvas(s.y) + deltaY); + } + }); + + // start animation if not yet running + if (!this.moving) { + this.moving = true; + this.start(); + } + } + else { + // move the graph + var diffX = pointer.x - this.drag.pointer.x; + var diffY = pointer.y - this.drag.pointer.y; + + this._setTranslation( + this.drag.translation.x + diffX, + this.drag.translation.y + diffY); + this._redraw(); + this.moved = true; + } +}; + +/** + * handle drag start event + * @private + */ +Graph.prototype._onDragEnd = function () { + this.drag.dragging = false; + var selection = this.drag.selection; + if (selection) { + selection.forEach(function (s) { + // restore original xFixed and yFixed + s.node.xFixed = s.xFixed; + s.node.yFixed = s.yFixed; + }); + } +}; + +/** + * handle tap/click event: select/unselect a node + * @private + */ +Graph.prototype._onTap = function (event) { + var pointer = this._getPointer(event.gesture.touches[0]); + this._handleTap(pointer); +}; + + +/** + * handle doubletap event + * @private + */ +Graph.prototype._onDoubleTap = function (event) { + var pointer = this._getPointer(event.gesture.touches[0]); + this._handleDoubleTap(pointer); + +}; + + +/** + * handle long tap event: multi select nodes + * @private + */ +Graph.prototype._onHold = function (event) { + var pointer = this._getPointer(event.gesture.touches[0]); + this._handleOnHold(pointer); +}; + +/** + * handle the release of the screen + * + * @param event + * @private + */ +Graph.prototype._onRelease = function (event) { + this._handleOnRelease(); +}; + +/** + * Handle pinch event + * @param event + * @private + */ +Graph.prototype._onPinch = function (event) { + var pointer = this._getPointer(event.gesture.center); + + this.drag.pinched = true; + if (!('scale' in this.pinch)) { + this.pinch.scale = 1; + } + + // TODO: enabled moving while pinching? + var scale = this.pinch.scale * event.gesture.scale; + this._zoom(scale, pointer) +}; + +/** + * Zoom the graph in or out + * @param {Number} scale a number around 1, and between 0.01 and 10 + * @param {{x: Number, y: Number}} pointer Position on screen + * @return {Number} appliedScale scale is limited within the boundaries + * @private + */ +Graph.prototype._zoom = function(scale, pointer) { + var scaleOld = this._getScale(); + if (scale < 0.00001) { + scale = 0.00001; + } + if (scale > 10) { + scale = 10; + } +// + this.frame.canvas.clientHeight / 2 + var translation = this._getTranslation(); + + var scaleFrac = scale / scaleOld; + var tx = (1 - scaleFrac) * pointer.x + translation.x * scaleFrac; + var ty = (1 - scaleFrac) * pointer.y + translation.y * scaleFrac; + + this.areaCenter = {"x" : this._canvasToX(pointer.x), + "y" : this._canvasToY(pointer.y)}; + + // this.areaCenter = {"x" : pointer.x,"y" : pointer.y }; +// console.log(translation.x,translation.y,pointer.x,pointer.y,scale); + this.pinch.mousewheelScale = scale; + this._setScale(scale); + this._setTranslation(tx, ty); + this.updateClustersDefault(); + this._redraw(); + + return scale; +}; + +/** + * Event handler for mouse wheel event, used to zoom the timeline + * See http://adomas.org/javascript-mouse-wheel/ + * https://github.com/EightMedia/hammer.js/issues/256 + * @param {MouseEvent} event + * @private + */ +Graph.prototype._onMouseWheel = function(event) { + // retrieve delta + var delta = 0; + if (event.wheelDelta) { /* IE/Opera. */ + delta = event.wheelDelta/120; + } else if (event.detail) { /* Mozilla case. */ + // In Mozilla, sign of delta is different than in IE. + // Also, delta is multiple of 3. + delta = -event.detail/3; + } + + // If delta is nonzero, handle it. + // Basically, delta is now positive if wheel was scrolled up, + // and negative, if wheel was scrolled down. + if (delta) { + if (!('mousewheelScale' in this.pinch)) { + this.pinch.mousewheelScale = 1; + } + + // calculate the new scale + var scale = this.pinch.mousewheelScale; + var zoom = delta / 10; + if (delta < 0) { + zoom = zoom / (1 - zoom); + } + scale *= (1 + zoom); + + // calculate the pointer location + var gesture = util.fakeGesture(this, event); + var pointer = this._getPointer(gesture.center); + + // apply the new scale + scale = this._zoom(scale, pointer); + + // store the new, applied scale -- this is now done in _zoom +// this.pinch.mousewheelScale = scale; + } + + // Prevent default actions caused by mouse wheel. + event.preventDefault(); +}; + + +/** + * Mouse move handler for checking whether the title moves over a node with a title. + * @param {Event} event + * @private + */ +Graph.prototype._onMouseMoveTitle = function (event) { + var gesture = util.fakeGesture(this, event); + var pointer = this._getPointer(gesture.center); + + // check if the previously selected node is still selected + if (this.popupNode) { + this._checkHidePopup(pointer); + } + + // start a timeout that will check if the mouse is positioned above + // an element + var me = this; + var checkShow = function() { + me._checkShowPopup(pointer); + }; + if (this.popupTimer) { + clearInterval(this.popupTimer); // stop any running calculationTimer + } + if (!this.drag.dragging) { + this.popupTimer = setTimeout(checkShow, 300); + } +}; + +/** + * Check if there is an element on the given position in the graph + * (a node or edge). If so, and if this element has a title, + * show a popup window with its title. + * + * @param {{x:Number, y:Number}} pointer + * @private + */ +Graph.prototype._checkShowPopup = function (pointer) { + var obj = { + left: this._canvasToX(pointer.x), + top: this._canvasToY(pointer.y), + right: this._canvasToX(pointer.x), + bottom: this._canvasToY(pointer.y) + }; + + var id; + var lastPopupNode = this.popupNode; + + if (this.popupNode == undefined) { + // search the nodes for overlap, select the top one in case of multiple nodes + var nodes = this.nodes; + for (id in nodes) { + if (nodes.hasOwnProperty(id)) { + var node = nodes[id]; + if (node.getTitle() !== undefined && node.isOverlappingWith(obj)) { + this.popupNode = node; + break; + } + } + } + } + + if (this.popupNode === undefined) { + // search the edges for overlap + var edges = this.edges; + for (id in edges) { + if (edges.hasOwnProperty(id)) { + var edge = edges[id]; + if (edge.connected && (edge.getTitle() !== undefined) && + edge.isOverlappingWith(obj)) { + this.popupNode = edge; + break; + } + } + } + } + + if (this.popupNode) { + // show popup message window + if (this.popupNode != lastPopupNode) { + var me = this; + if (!me.popup) { + me.popup = new Popup(me.frame); + } + + // adjust a small offset such that the mouse cursor is located in the + // bottom left location of the popup, and you can easily move over the + // popup area + me.popup.setPosition(pointer.x - 3, pointer.y - 3); + me.popup.setText(me.popupNode.getTitle()); + me.popup.show(); + } + } + else { + if (this.popup) { + this.popup.hide(); + } + } +}; + +/** + * Check if the popup must be hided, which is the case when the mouse is no + * longer hovering on the object + * @param {{x:Number, y:Number}} pointer + * @private + */ +Graph.prototype._checkHidePopup = function (pointer) { + if (!this.popupNode || !this._getNodeAt(pointer) ) { + this.popupNode = undefined; + if (this.popup) { + this.popup.hide(); + } + } +}; + + +/** + * Temporary method to test calculating a hub value for the nodes + * @param {number} level Maximum number edges between two nodes in order + * to call them connected. Optional, 1 by default + * @return {Number[]} connectioncount array with the connection count + * for each node + * @private + */ +Graph.prototype._getConnectionCount = function(level) { + if (level == undefined) { + level = 1; + } + + // get the nodes connected to given nodes + function getConnectedNodes(nodes) { + var connectedNodes = []; + + for (var j = 0, jMax = nodes.length; j < jMax; j++) { + var node = nodes[j]; + + // find all nodes connected to this node + var edges = node.edges; + for (var i = 0, iMax = edges.length; i < iMax; i++) { + var edge = edges[i]; + var other = null; + + // check if connected + if (edge.from == node) + other = edge.to; + else if (edge.to == node) + other = edge.from; + + // check if the other node is not already in the list with nodes + var k, kMax; + if (other) { + for (k = 0, kMax = nodes.length; k < kMax; k++) { + if (nodes[k] == other) { + other = null; + break; + } + } + } + if (other) { + for (k = 0, kMax = connectedNodes.length; k < kMax; k++) { + if (connectedNodes[k] == other) { + other = null; + break; + } + } + } + + if (other) + connectedNodes.push(other); + } + } + + return connectedNodes; + } + + var connections = []; + var nodes = this.nodes; + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + var c = [nodes[id]]; + for (var l = 0; l < level; l++) { + c = c.concat(getConnectedNodes(c)); + } + connections.push(c); + } + } + + var hubs = []; + for (var i = 0, len = connections.length; i < len; i++) { + hubs.push(connections[i].length); + } + + return hubs; +}; + +/** + * Set a new size for the graph + * @param {string} width Width in pixels or percentage (for example '800px' + * or '50%') + * @param {string} height Height in pixels or percentage (for example '400px' + * or '30%') + */ +Graph.prototype.setSize = function(width, height) { + this.frame.style.width = width; + this.frame.style.height = height; + + this.frame.canvas.style.width = '100%'; + this.frame.canvas.style.height = '100%'; + + this.frame.canvas.width = this.frame.canvas.clientWidth; + this.frame.canvas.height = this.frame.canvas.clientHeight; + + if (this.constants.navigation.enabled == true) { + this._relocateNavigation(); + } +}; + +/** + * Set a data set with nodes for the graph + * @param {Array | DataSet | DataView} nodes The data containing the nodes. + * @private + */ +Graph.prototype._setNodes = function(nodes) { + var oldNodesData = this.nodesData; + + if (nodes instanceof DataSet || nodes instanceof DataView) { + this.nodesData = nodes; + } + else if (nodes instanceof Array) { + this.nodesData = new DataSet(); + this.nodesData.add(nodes); + } + else if (!nodes) { + this.nodesData = new DataSet(); + } + else { + throw new TypeError('Array or DataSet expected'); + } + + if (oldNodesData) { + // unsubscribe from old dataset + util.forEach(this.nodesListeners, function (callback, event) { + oldNodesData.unsubscribe(event, callback); + }); + } + + // remove drawn nodes + this.nodes = {}; + + if (this.nodesData) { + // subscribe to new dataset + var me = this; + util.forEach(this.nodesListeners, function (callback, event) { + me.nodesData.subscribe(event, callback); + }); + + // draw all new nodes + var ids = this.nodesData.getIds(); + this._addNodes(ids); + } + this._updateSelection(); +}; + +/** + * Add nodes + * @param {Number[] | String[]} ids + * @private + */ +Graph.prototype._addNodes = function(ids) { + var id; + for (var i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + var data = this.nodesData.get(id); + var node = new Node(data, this.images, this.groups, this.constants); + this.nodes[id] = node; // note: this may replace an existing node + + if (!node.isFixed()) { + // TODO: position new nodes in a smarter way! + var radius = this.constants.edges.length * 2; + var count = ids.length; + var angle = 2 * Math.PI * (i / count); + node.x = radius * Math.cos(angle); + node.y = radius * Math.sin(angle); + + // note: no not use node.isMoving() here, as that gives the current + // velocity of the node, which is zero after creation of the node. + this.moving = true; + } + } + this._updateNodeIndexList(); + this._reconnectEdges(); + this._updateValueRange(this.nodes); +}; + +/** + * Update existing nodes, or create them when not yet existing + * @param {Number[] | String[]} ids + * @private + */ +Graph.prototype._updateNodes = function(ids) { + var nodes = this.nodes, + nodesData = this.nodesData; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + var node = nodes[id]; + var data = nodesData.get(id); + if (node) { + // update node + node.setProperties(data, this.constants); + } + else { + // create node + node = new Node(properties, this.images, this.groups, this.constants); + nodes[id] = node; + + if (!node.isFixed()) { + this.moving = true; + } + } + } + this._updateNodeIndexList(); + this._reconnectEdges(); + this._updateValueRange(nodes); +}; + +/** + * Remove existing nodes. If nodes do not exist, the method will just ignore it. + * @param {Number[] | String[]} ids + * @private + */ +Graph.prototype._removeNodes = function(ids) { + var nodes = this.nodes; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + delete nodes[id]; + } + this._updateNodeIndexList(); + this._reconnectEdges(); + this._updateSelection(); + this._updateValueRange(nodes); +}; + +/** + * Load edges by reading the data table + * @param {Array | DataSet | DataView} edges The data containing the edges. + * @private + * @private + */ +Graph.prototype._setEdges = function(edges) { + var oldEdgesData = this.edgesData; + + if (edges instanceof DataSet || edges instanceof DataView) { + this.edgesData = edges; + } + else if (edges instanceof Array) { + this.edgesData = new DataSet(); + this.edgesData.add(edges); + } + else if (!edges) { + this.edgesData = new DataSet(); + } + else { + throw new TypeError('Array or DataSet expected'); + } + + if (oldEdgesData) { + // unsubscribe from old dataset + util.forEach(this.edgesListeners, function (callback, event) { + oldEdgesData.unsubscribe(event, callback); + }); + } + + // remove drawn edges + this.edges = {}; + + if (this.edgesData) { + // subscribe to new dataset + var me = this; + util.forEach(this.edgesListeners, function (callback, event) { + me.edgesData.subscribe(event, callback); + }); + + // draw all new nodes + var ids = this.edgesData.getIds(); + this._addEdges(ids); + } + + this._reconnectEdges(); +}; + +/** + * Add edges + * @param {Number[] | String[]} ids + * @private + */ +Graph.prototype._addEdges = function (ids) { + var edges = this.edges, + edgesData = this.edgesData; + + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + + var oldEdge = edges[id]; + if (oldEdge) { + oldEdge.disconnect(); + } + + var data = edgesData.get(id, {"showInternalIds" : true}); + edges[id] = new Edge(data, this, this.constants); + } + + this.moving = true; + this._updateValueRange(edges); +}; + +/** + * Update existing edges, or create them when not yet existing + * @param {Number[] | String[]} ids + * @private + */ +Graph.prototype._updateEdges = function (ids) { + var edges = this.edges, + edgesData = this.edgesData; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + + var data = edgesData.get(id); + var edge = edges[id]; + if (edge) { + // update edge + edge.disconnect(); + edge.setProperties(data, this.constants); + edge.connect(); + } + else { + // create edge + edge = new Edge(data, this, this.constants); + this.edges[id] = edge; + } + } + + this.moving = true; + this._updateValueRange(edges); +}; + +/** + * Remove existing edges. Non existing ids will be ignored + * @param {Number[] | String[]} ids + * @private + */ +Graph.prototype._removeEdges = function (ids) { + var edges = this.edges; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + var edge = edges[id]; + if (edge) { + edge.disconnect(); + delete edges[id]; + } + } + + this.moving = true; + this._updateValueRange(edges); +}; + +/** + * Reconnect all edges + * @private + */ +Graph.prototype._reconnectEdges = function() { + var id, + nodes = this.nodes, + edges = this.edges; + for (id in nodes) { + if (nodes.hasOwnProperty(id)) { + nodes[id].edges = []; + } + } + + for (id in edges) { + if (edges.hasOwnProperty(id)) { + var edge = edges[id]; + edge.from = null; + edge.to = null; + edge.connect(); + } + } +}; + +/** + * Update the values of all object in the given array according to the current + * value range of the objects in the array. + * @param {Object} obj An object containing a set of Edges or Nodes + * The objects must have a method getValue() and + * setValueRange(min, max). + * @private + */ +Graph.prototype._updateValueRange = function(obj) { + var id; + + // determine the range of the objects + var valueMin = undefined; + var valueMax = undefined; + for (id in obj) { + if (obj.hasOwnProperty(id)) { + var value = obj[id].getValue(); + if (value !== undefined) { + valueMin = (valueMin === undefined) ? value : Math.min(value, valueMin); + valueMax = (valueMax === undefined) ? value : Math.max(value, valueMax); + } + } + } + + // adjust the range of all objects + if (valueMin !== undefined && valueMax !== undefined) { + for (id in obj) { + if (obj.hasOwnProperty(id)) { + obj[id].setValueRange(valueMin, valueMax); + } + } + } +}; + +/** + * Redraw the graph with the current data + * chart will be resized too. + */ +Graph.prototype.redraw = function() { + this.setSize(this.width, this.height); + + this._redraw(); +}; + +/** + * Redraw the graph with the current data + * @private + */ +Graph.prototype._redraw = function() { + var ctx = this.frame.canvas.getContext('2d'); + // clear the canvas + var w = this.frame.canvas.width; + var h = this.frame.canvas.height; + ctx.clearRect(0, 0, w, h); + + // set scaling and translation + ctx.save(); + ctx.translate(this.translation.x, this.translation.y); + ctx.scale(this.scale, this.scale); + + this.canvasTopLeft = { + "x": this._canvasToX(0), + "y": this._canvasToY(0) + }; + this.canvasBottomRight = { + "x": this._canvasToX(this.frame.canvas.clientWidth), + "y": this._canvasToY(this.frame.canvas.clientHeight) + }; + + this._doInAllSectors("_drawAllSectorNodes",ctx); + this._doInAllSectors("_drawEdges",ctx); + this._doInAllSectors("_drawNodes",ctx); + + // restore original scaling and translation + ctx.restore(); + + if (this.constants.navigation.enabled == true) { + this._doInNavigationSector("_drawNodes",ctx,true); + } +}; + +/** + * Set the translation of the graph + * @param {Number} offsetX Horizontal offset + * @param {Number} offsetY Vertical offset + * @private + */ +Graph.prototype._setTranslation = function(offsetX, offsetY) { + if (this.translation === undefined) { + this.translation = { + x: 0, + y: 0 + }; + } + + if (offsetX !== undefined) { + this.translation.x = offsetX; + } + if (offsetY !== undefined) { + this.translation.y = offsetY; + } +}; + +/** + * Get the translation of the graph + * @return {Object} translation An object with parameters x and y, both a number + * @private + */ +Graph.prototype._getTranslation = function() { + return { + x: this.translation.x, + y: this.translation.y + }; +}; + +/** + * Scale the graph + * @param {Number} scale Scaling factor 1.0 is unscaled + * @private + */ +Graph.prototype._setScale = function(scale) { + this.scale = scale; +}; + +/** + * Get the current scale of the graph + * @return {Number} scale Scaling factor 1.0 is unscaled + * @private + */ +Graph.prototype._getScale = function() { + return this.scale; +}; + +/** + * Convert a horizontal point on the HTML canvas to the x-value of the model + * @param {number} x + * @returns {number} + * @private + */ +Graph.prototype._canvasToX = function(x) { + return (x - this.translation.x) / this.scale; +}; + +/** + * Convert an x-value in the model to a horizontal point on the HTML canvas + * @param {number} x + * @returns {number} + * @private + */ +Graph.prototype._xToCanvas = function(x) { + return x * this.scale + this.translation.x; +}; + +/** + * Convert a vertical point on the HTML canvas to the y-value of the model + * @param {number} y + * @returns {number} + * @private + */ +Graph.prototype._canvasToY = function(y) { + return (y - this.translation.y) / this.scale; +}; + +/** + * Convert an y-value in the model to a vertical point on the HTML canvas + * @param {number} y + * @returns {number} + * @private + */ +Graph.prototype._yToCanvas = function(y) { + return y * this.scale + this.translation.y ; +}; + +/** + * Redraw all nodes + * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); + * @param {CanvasRenderingContext2D} ctx + * @param {Boolean} [alwaysShow] + * @private + */ +Graph.prototype._drawNodes = function(ctx,alwaysShow) { + if (alwaysShow === undefined) { + alwaysShow = false; + } + + // first draw the unselected nodes + var nodes = this.nodes; + var selected = []; + + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + nodes[id].setScaleAndPos(this.scale,this.canvasTopLeft,this.canvasBottomRight); + if (nodes[id].isSelected()) { + selected.push(id); + } + else { + if (nodes[id].inArea() || alwaysShow) { + nodes[id].draw(ctx); + } + } + } + } + + // draw the selected nodes on top + for (var s = 0, sMax = selected.length; s < sMax; s++) { + if (nodes[selected[s]].inArea() || alwaysShow) { + nodes[selected[s]].draw(ctx); + } + } +}; + +/** + * Redraw all edges + * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); + * @param {CanvasRenderingContext2D} ctx + * @private + */ +Graph.prototype._drawEdges = function(ctx) { + var edges = this.edges; + for (var id in edges) { + if (edges.hasOwnProperty(id)) { + var edge = edges[id]; + edge.setScale(this.scale); + if (edge.connected) { + edges[id].draw(ctx); + } + } + } +}; + +/** + * Find a stable position for all nodes + * @private + */ +Graph.prototype._doStabilize = function() { + //var start = new Date(); + + // find stable position + var count = 0; + var vmin = this.constants.minVelocity; + var stable = false; + while (!stable && count < this.constants.maxIterations) { + this._initializeForceCalculation(); + this._discreteStepNodes(); + stable = !this._isMoving(vmin); + count++; + } + this.zoomToFit(); + + // var end = new Date(); + + // console.log('Stabilized in ' + (end-start) + ' ms, ' + count + ' iterations' ); // TODO: cleanup +}; + + +/** + * Before calculating the forces, we check if we need to cluster to keep up performance and we check + * if there is more than one node. If it is just one node, we dont calculate anything. + * + * @private + */ +Graph.prototype._initializeForceCalculation = function() { + // stop calculation if there is only one node + if (this.nodeIndices.length == 1) { + this.nodes[this.nodeIndices[0]]._setForce(0,0); + } + else { + // if there are too many nodes on screen, we cluster without repositioning + if (this.nodeIndices.length > this.constants.clustering.clusterThreshold && this.constants.clustering.enabled == true) { + this.clusterToFit(this.constants.clustering.reduceToNodes, false); + } + + // we now start the force calculation + this._calculateForces(); + } +}; + + +/** + * Calculate the external forces acting on the nodes + * Forces are caused by: edges, repulsing forces between nodes, gravity + * @private + */ +Graph.prototype._calculateForces = function() { +// var screenCenterPos = {"x":(0.5*(this.canvasTopLeft.x + this.canvasBottomRight.x)), +// "y":(0.5*(this.canvasTopLeft.y + this.canvasBottomRight.y))} + // create a local edge to the nodes and edges, that is faster + var dx, dy, angle, distance, fx, fy, + repulsingForce, springForce, length, edgeLength, + node, node1, node2, edge, edgeId, i, j, nodeId, xCenter, yCenter; + var clusterSize; + var nodes = this.nodes; + var edges = this.edges; + + // Gravity is required to keep separated groups from floating off + // the forces are reset to zero in this loop by using _setForce instead + // of _addForce + var gravity = 0.08 * this.forceFactor; + for (i = 0; i < this.nodeIndices.length; i++) { + node = nodes[this.nodeIndices[i]]; + // gravity does not apply when we are in a pocket sector + if (this._sector() == "default") { + dx = -node.x;// + screenCenterPos.x; + dy = -node.y;// + screenCenterPos.y; + + angle = Math.atan2(dy, dx); + fx = Math.cos(angle) * gravity; + fy = Math.sin(angle) * gravity; + } + else { + fx = 0; + fy = 0; + } + node._setForce(fx, fy); + + node.updateDamping(this.nodeIndices.length); + } + + // repulsing forces between nodes + var minimumDistance = this.constants.nodes.distance, + steepness = 10; // higher value gives steeper slope of the force around the given minimumDistance + + + // we loop from i over all but the last entree in the array + // j loops from i+1 to the last. This way we do not double count any of the indices, nor i == j + for (i = 0; i < this.nodeIndices.length-1; i++) { + node1 = nodes[this.nodeIndices[i]]; + for (j = i+1; j < this.nodeIndices.length; j++) { + node2 = nodes[this.nodeIndices[j]]; + clusterSize = (node1.clusterSize + node2.clusterSize - 2); + dx = node2.x - node1.x; + dy = node2.y - node1.y; + distance = Math.sqrt(dx * dx + dy * dy); + + + // clusters have a larger region of influence + minimumDistance = (clusterSize == 0) ? this.constants.nodes.distance : (this.constants.nodes.distance * (1 + clusterSize * this.constants.clustering.distanceAmplification)); + if (distance < 2*minimumDistance) { // at 2.0 * the minimum distance, the force is 0.000045 + angle = Math.atan2(dy, dx); + + if (distance < 0.5*minimumDistance) { // at 0.5 * the minimum distance, the force is 0.993307 + repulsingForce = 1.0; + } + else { + // TODO: correct factor for repulsing force + //repulsingForce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force + //repulsingForce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force + repulsingForce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)); // TODO: customize the repulsing force + } + // amplify the repulsion for clusters. + repulsingForce *= (clusterSize == 0) ? 1 : 1 + clusterSize * this.constants.clustering.forceAmplification; + repulsingForce *= this.forceFactor; + + + fx = Math.cos(angle) * repulsingForce; + fy = Math.sin(angle) * repulsingForce ; + + node1._addForce(-fx, -fy); + node2._addForce(fx, fy); + } + } + } + +/* + // repulsion of the edges on the nodes and + for (var nodeId in nodes) { + if (nodes.hasOwnProperty(nodeId)) { + node = nodes[nodeId]; + for(var edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + + // get the center of the edge + xCenter = edge.from.x+(edge.to.x - edge.from.x)/2; + yCenter = edge.from.y+(edge.to.y - edge.from.y)/2; + + // calculate normally distributed force + dx = node.x - xCenter; + dy = node.y - yCenter; + distance = Math.sqrt(dx * dx + dy * dy); + if (distance < 2*minimumDistance) { // at 2.0 * the minimum distance, the force is 0.000045 + angle = Math.atan2(dy, dx); + + if (distance < 0.5*minimumDistance) { // at 0.5 * the minimum distance, the force is 0.993307 + repulsingForce = 1.0; + } + else { + // TODO: correct factor for repulsing force + //var repulsingforce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force + //repulsingforce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ), // TODO: customize the repulsing force + repulsingForce = 1 / (1 + Math.exp((distance / (minimumDistance / 2) - 1) * steepness)); // TODO: customize the repulsing force + } + fx = Math.cos(angle) * repulsingForce; + fy = Math.sin(angle) * repulsingForce; + node._addForce(fx, fy); + edge.from._addForce(-fx/2,-fy/2); + edge.to._addForce(-fx/2,-fy/2); + } + } + } + } + } +*/ + + // forces caused by the edges, modelled as springs + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.connected) { + // only calculate forces if nodes are in the same sector + if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { + clusterSize = (edge.to.clusterSize + edge.from.clusterSize - 2); + dx = (edge.to.x - edge.from.x); + dy = (edge.to.y - edge.from.y); + //edgeLength = (edge.from.width + edge.from.height + edge.to.width + edge.to.height)/2 || edge.length; // TODO: dmin + //edgeLength = (edge.from.width + edge.to.width)/2 || edge.length; // TODO: dmin + //edgeLength = 20 + ((edge.from.width + edge.to.width) || 0) / 2; + edgeLength = edge.length; + // this implies that the edges between big clusters are longer + edgeLength += clusterSize * this.constants.clustering.edgeGrowth; + length = Math.sqrt(dx * dx + dy * dy); + angle = Math.atan2(dy, dx); + + springForce = edge.stiffness * (edgeLength - length) * this.forceFactor; + + fx = Math.cos(angle) * springForce; + fy = Math.sin(angle) * springForce; + + edge.from._addForce(-fx, -fy); + edge.to._addForce(fx, fy); + } + } + } + } +/* + // TODO: re-implement repulsion of edges + + // repulsing forces between edges + var minimumDistance = this.constants.edges.distance, + steepness = 10; // higher value gives steeper slope of the force around the given minimumDistance + for (var l = 0; l < edges.length; l++) { + //Keep distance from other edge centers + for (var l2 = l + 1; l2 < this.edges.length; l2++) { + //var dmin = (nodes[n].width + nodes[n].height + nodes[n2].width + nodes[n2].height) / 1 || minimumDistance, // TODO: dmin + //var dmin = (nodes[n].width + nodes[n2].width)/2 || minimumDistance, // TODO: dmin + //dmin = 40 + ((nodes[n].width/2 + nodes[n2].width/2) || 0), + var lx = edges[l].from.x+(edges[l].to.x - edges[l].from.x)/2, + ly = edges[l].from.y+(edges[l].to.y - edges[l].from.y)/2, + l2x = edges[l2].from.x+(edges[l2].to.x - edges[l2].from.x)/2, + l2y = edges[l2].from.y+(edges[l2].to.y - edges[l2].from.y)/2, + + // calculate normally distributed force + dx = l2x - lx, + dy = l2y - ly, + distance = Math.sqrt(dx * dx + dy * dy), + angle = Math.atan2(dy, dx), + + + // TODO: correct factor for repulsing force + //var repulsingforce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force + //repulsingforce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ), // TODO: customize the repulsing force + repulsingforce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)), // TODO: customize the repulsing force + fx = Math.cos(angle) * repulsingforce, + fy = Math.sin(angle) * repulsingforce; + + edges[l].from._addForce(-fx, -fy); + edges[l].to._addForce(-fx, -fy); + edges[l2].from._addForce(fx, fy); + edges[l2].to._addForce(fx, fy); + } + } +*/ +}; + + +/** + * Check if any of the nodes is still moving + * @param {number} vmin the minimum velocity considered as 'moving' + * @return {boolean} true if moving, false if non of the nodes is moving + * @private + */ +Graph.prototype._isMoving = function(vmin) { + var vminCorrected = vmin / this.scale; + var nodes = this.nodes; + for (var id in nodes) { + if (nodes.hasOwnProperty(id) && nodes[id].isMoving(vminCorrected)) { + return true; + } + } + return false; +}; + + +/** + * /** + * Perform one discrete step for all nodes + * + * @param interval + * @private + */ +Graph.prototype._discreteStepNodes = function() { + var interval = 0.01; + var nodes = this.nodes; + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + nodes[id].discreteStep(interval); + } + } + + var vmin = this.constants.minVelocity; + this.moving = this._isMoving(vmin); +}; + + + +/** + * Start animating nodes and edges + * + * @poram {Boolean} runCalculationStep + */ +Graph.prototype.start = function() { + if (!this.freezeSimulation) { + + if (this.moving) { + this._doInAllActiveSectors("_initializeForceCalculation"); + this._doInAllActiveSectors("_discreteStepNodes"); + this._findCenter(this._getRange()) + } + + if (this.moving || this.xIncrement != 0 || this.yIncrement != 0 || this.zoomIncrement != 0) { + // start animation. only start calculationTimer if it is not already running + if (!this.timer) { + var graph = this; + this.timer = window.setTimeout(function () { + graph.timer = undefined; + + // keyboad movement + if (graph.xIncrement != 0 || graph.yIncrement != 0) { + var translation = graph._getTranslation(); + graph._setTranslation(translation.x+graph.xIncrement, translation.y+graph.yIncrement); + } + if (graph.zoomIncrement != 0) { + var center = { + x: graph.frame.canvas.clientWidth / 2, + y: graph.frame.canvas.clientHeight / 2 + }; + graph._zoom(graph.scale*(1 + graph.zoomIncrement), center); + } + + graph.start(); + graph._redraw(); + + //this.end = window.performance.now(); + //this.time = this.end - this.startTime; + //console.log('refresh time: ' + this.time); + //this.startTime = window.performance.now(); + + }, this.renderTimestep); + } + } + else { + this._redraw(); + } + } +}; + + + + +Graph.prototype.singleStep = function() { + if (this.moving) { + this._initializeForceCalculation(); + this._discreteStepNodes(); + + var vmin = this.constants.minVelocity; + this.moving = this._isMoving(vmin); + this._redraw(); + } +}; + + + +/** + * Freeze the animation + */ +Graph.prototype.toggleFreeze = function() { + if (this.freezeSimulation == false) { + this.freezeSimulation = true; + } + else { + this.freezeSimulation = false; + this.start(); + } +}; + +/** + * Mixin the cluster system and initialize the parameters required. + * + * @private + */ +Graph.prototype._loadClusterSystem = function() { + this.clusterSession = 0; + this.hubThreshold = 5; + + for (var mixinFunction in ClusterMixin) { + if (ClusterMixin.hasOwnProperty(mixinFunction)) { + Graph.prototype[mixinFunction] = ClusterMixin[mixinFunction]; + } + } +} + +/** + * Mixin the sector system and initialize the parameters required + * + * @private + */ +Graph.prototype._loadSectorSystem = function() { + this.sectors = {}; + this.activeSector = ["default"]; + this.sectors["active"] = {}; + this.sectors["active"]["default"] = {"nodes":{}, + "edges":{}, + "nodeIndices":[], + "formationScale": 1.0, + "drawingNode": undefined}; + this.sectors["frozen"] = {}; + this.sectors["navigation"] = {"nodes":{}, + "edges":{}, + "nodeIndices":[], + "formationScale": 1.0, + "drawingNode": undefined}; + + this.nodeIndices = this.sectors["active"]["default"]["nodeIndices"]; // the node indices list is used to speed up the computation of the repulsion fields + for (var mixinFunction in SectorMixin) { + if (SectorMixin.hasOwnProperty(mixinFunction)) { + Graph.prototype[mixinFunction] = SectorMixin[mixinFunction]; + } + } +}; + + +/** + * Mixin the selection system and initialize the parameters required + * + * @private + */ +Graph.prototype._loadSelectionSystem = function() { + this.selection = []; + this.selectionObj = {}; + + for (var mixinFunction in SelectionMixin) { + if (SelectionMixin.hasOwnProperty(mixinFunction)) { + Graph.prototype[mixinFunction] = SelectionMixin[mixinFunction]; + } + } +} + + +/** + * Mixin the navigation (User Interface) system and initialize the parameters required + * + * @private + */ +Graph.prototype._loadNavigationControls = function() { + for (var mixinFunction in NavigationMixin) { + if (NavigationMixin.hasOwnProperty(mixinFunction)) { + Graph.prototype[mixinFunction] = NavigationMixin[mixinFunction]; + } + } + + if (this.constants.navigation.enabled == true) { + this._loadNavigationElements(); + } +} + +/** + * this function exists to avoid errors when not loading the navigation system + */ +Graph.prototype._relocateNavigation = function() { + // empty, is overloaded by navigation system +} + +/** + * * this function exists to avoid errors when not loading the navigation system + */ +Graph.prototype._unHighlightAll = function() { + // empty, is overloaded by the navigation system +} + + + + + + + + + + + + + + + + + + + + + + + + + +/** + * vis.js module exports + */ +var vis = { + util: util, + events: events, + + Controller: Controller, + DataSet: DataSet, + DataView: DataView, + Range: Range, + Stack: Stack, + TimeStep: TimeStep, + EventBus: EventBus, + + components: { + items: { + Item: Item, + ItemBox: ItemBox, + ItemPoint: ItemPoint, + ItemRange: ItemRange + }, + + Component: Component, + Panel: Panel, + RootPanel: RootPanel, + ItemSet: ItemSet, + TimeAxis: TimeAxis + }, + + graph: { + Node: Node, + Edge: Edge, + Popup: Popup, + Groups: Groups, + Images: Images + }, + + Timeline: Timeline, + Graph: Graph +}; + +/** + * CommonJS module exports + */ +if (typeof exports !== 'undefined') { + exports = vis; +} +if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { + module.exports = vis; +} + +/** + * AMD module exports + */ +if (typeof(define) === 'function') { + define(function () { + return vis; + }); +} + +/** + * Window exports + */ +if (typeof window !== 'undefined') { + // attach the module to the window, load as a regular javascript file + window['vis'] = vis; +} + + +},{"hammerjs":2,"moment":3,"mousetrap":4}],2:[function(require,module,exports){ +/*! Hammer.JS - v1.0.5 - 2013-04-07 + * http://eightmedia.github.com/hammer.js + * + * Copyright (c) 2013 Jorik Tangelder ; + * Licensed under the MIT license */ + +(function(window, undefined) { + 'use strict'; + +/** + * Hammer + * use this to create instances + * @param {HTMLElement} element + * @param {Object} options + * @returns {Hammer.Instance} + * @constructor + */ +var Hammer = function(element, options) { + return new Hammer.Instance(element, options || {}); +}; + +// default settings +Hammer.defaults = { + // add styles and attributes to the element to prevent the browser from doing + // its native behavior. this doesnt prevent the scrolling, but cancels + // the contextmenu, tap highlighting etc + // set to false to disable this + stop_browser_behavior: { + // this also triggers onselectstart=false for IE + userSelect: 'none', + // this makes the element blocking in IE10 >, you could experiment with the value + // see for more options this issue; https://github.com/EightMedia/hammer.js/issues/241 + touchAction: 'none', + touchCallout: 'none', + contentZooming: 'none', + userDrag: 'none', + tapHighlightColor: 'rgba(0,0,0,0)' + } + + // more settings are defined per gesture at gestures.js +}; + +// detect touchevents +Hammer.HAS_POINTEREVENTS = navigator.pointerEnabled || navigator.msPointerEnabled; +Hammer.HAS_TOUCHEVENTS = ('ontouchstart' in window); + +// dont use mouseevents on mobile devices +Hammer.MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i; +Hammer.NO_MOUSEEVENTS = Hammer.HAS_TOUCHEVENTS && navigator.userAgent.match(Hammer.MOBILE_REGEX); + +// eventtypes per touchevent (start, move, end) +// are filled by Hammer.event.determineEventTypes on setup +Hammer.EVENT_TYPES = {}; + +// direction defines +Hammer.DIRECTION_DOWN = 'down'; +Hammer.DIRECTION_LEFT = 'left'; +Hammer.DIRECTION_UP = 'up'; +Hammer.DIRECTION_RIGHT = 'right'; + +// pointer type +Hammer.POINTER_MOUSE = 'mouse'; +Hammer.POINTER_TOUCH = 'touch'; +Hammer.POINTER_PEN = 'pen'; + +// touch event defines +Hammer.EVENT_START = 'start'; +Hammer.EVENT_MOVE = 'move'; +Hammer.EVENT_END = 'end'; + +// hammer document where the base events are added at +Hammer.DOCUMENT = document; + +// plugins namespace +Hammer.plugins = {}; + +// if the window events are set... +Hammer.READY = false; + +/** + * setup events to detect gestures on the document + */ +function setup() { + if(Hammer.READY) { + return; + } + + // find what eventtypes we add listeners to + Hammer.event.determineEventTypes(); + + // Register all gestures inside Hammer.gestures + for(var name in Hammer.gestures) { + if(Hammer.gestures.hasOwnProperty(name)) { + Hammer.detection.register(Hammer.gestures[name]); + } + } + + // Add touch events on the document + Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_MOVE, Hammer.detection.detect); + Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_END, Hammer.detection.detect); + + // Hammer is ready...! + Hammer.READY = true; +} + +/** + * create new hammer instance + * all methods should return the instance itself, so it is chainable. + * @param {HTMLElement} element + * @param {Object} [options={}] + * @returns {Hammer.Instance} + * @constructor + */ +Hammer.Instance = function(element, options) { + var self = this; + + // setup HammerJS window events and register all gestures + // this also sets up the default options + setup(); + + this.element = element; + + // start/stop detection option + this.enabled = true; + + // merge options + this.options = Hammer.utils.extend( + Hammer.utils.extend({}, Hammer.defaults), + options || {}); + + // add some css to the element to prevent the browser from doing its native behavoir + if(this.options.stop_browser_behavior) { + Hammer.utils.stopDefaultBrowserBehavior(this.element, this.options.stop_browser_behavior); + } + + // start detection on touchstart + Hammer.event.onTouch(element, Hammer.EVENT_START, function(ev) { + if(self.enabled) { + Hammer.detection.startDetect(self, ev); + } + }); + + // return instance + return this; +}; + + +Hammer.Instance.prototype = { + /** + * bind events to the instance + * @param {String} gesture + * @param {Function} handler + * @returns {Hammer.Instance} + */ + on: function onEvent(gesture, handler){ + var gestures = gesture.split(' '); + for(var t=0; t 0 && eventType == Hammer.EVENT_END) { + eventType = Hammer.EVENT_MOVE; + } + // no touches, force the end event + else if(!count_touches) { + eventType = Hammer.EVENT_END; + } + + // because touchend has no touches, and we often want to use these in our gestures, + // we send the last move event as our eventData in touchend + if(!count_touches && last_move_event !== null) { + ev = last_move_event; + } + // store the last move event + else { + last_move_event = ev; + } + + // trigger the handler + handler.call(Hammer.detection, self.collectEventData(element, eventType, ev)); + + // remove pointerevent from list + if(Hammer.HAS_POINTEREVENTS && eventType == Hammer.EVENT_END) { + count_touches = Hammer.PointerEvent.updatePointer(eventType, ev); + } + } + + //debug(sourceEventType +" "+ eventType); + + // on the end we reset everything + if(!count_touches) { + last_move_event = null; + enable_detect = false; + touch_triggered = false; + Hammer.PointerEvent.reset(); + } + }); + }, + + + /** + * we have different events for each device/browser + * determine what we need and set them in the Hammer.EVENT_TYPES constant + */ + determineEventTypes: function determineEventTypes() { + // determine the eventtype we want to set + var types; + + // pointerEvents magic + if(Hammer.HAS_POINTEREVENTS) { + types = Hammer.PointerEvent.getEvents(); + } + // on Android, iOS, blackberry, windows mobile we dont want any mouseevents + else if(Hammer.NO_MOUSEEVENTS) { + types = [ + 'touchstart', + 'touchmove', + 'touchend touchcancel']; + } + // for non pointer events browsers and mixed browsers, + // like chrome on windows8 touch laptop + else { + types = [ + 'touchstart mousedown', + 'touchmove mousemove', + 'touchend touchcancel mouseup']; + } + + Hammer.EVENT_TYPES[Hammer.EVENT_START] = types[0]; + Hammer.EVENT_TYPES[Hammer.EVENT_MOVE] = types[1]; + Hammer.EVENT_TYPES[Hammer.EVENT_END] = types[2]; + }, + + + /** + * create touchlist depending on the event + * @param {Object} ev + * @param {String} eventType used by the fakemultitouch plugin + */ + getTouchList: function getTouchList(ev/*, eventType*/) { + // get the fake pointerEvent touchlist + if(Hammer.HAS_POINTEREVENTS) { + return Hammer.PointerEvent.getTouchList(); + } + // get the touchlist + else if(ev.touches) { + return ev.touches; + } + // make fake touchlist from mouse position + else { + return [{ + identifier: 1, + pageX: ev.pageX, + pageY: ev.pageY, + target: ev.target + }]; + } + }, + + + /** + * collect event data for Hammer js + * @param {HTMLElement} element + * @param {String} eventType like Hammer.EVENT_MOVE + * @param {Object} eventData + */ + collectEventData: function collectEventData(element, eventType, ev) { + var touches = this.getTouchList(ev, eventType); + + // find out pointerType + var pointerType = Hammer.POINTER_TOUCH; + if(ev.type.match(/mouse/) || Hammer.PointerEvent.matchType(Hammer.POINTER_MOUSE, ev)) { + pointerType = Hammer.POINTER_MOUSE; + } + + return { + center : Hammer.utils.getCenter(touches), + timeStamp : new Date().getTime(), + target : ev.target, + touches : touches, + eventType : eventType, + pointerType : pointerType, + srcEvent : ev, + + /** + * prevent the browser default actions + * mostly used to disable scrolling of the browser + */ + preventDefault: function() { + if(this.srcEvent.preventManipulation) { + this.srcEvent.preventManipulation(); + } + + if(this.srcEvent.preventDefault) { + this.srcEvent.preventDefault(); + } + }, + + /** + * stop bubbling the event up to its parents + */ + stopPropagation: function() { + this.srcEvent.stopPropagation(); + }, + + /** + * immediately stop gesture detection + * might be useful after a swipe was detected + * @return {*} + */ + stopDetect: function() { + return Hammer.detection.stopDetect(); + } + }; + } +}; + +Hammer.PointerEvent = { + /** + * holds all pointers + * @type {Object} + */ + pointers: {}, + + /** + * get a list of pointers + * @returns {Array} touchlist + */ + getTouchList: function() { + var self = this; + var touchlist = []; + + // we can use forEach since pointerEvents only is in IE10 + Object.keys(self.pointers).sort().forEach(function(id) { + touchlist.push(self.pointers[id]); + }); + return touchlist; + }, + + /** + * update the position of a pointer + * @param {String} type Hammer.EVENT_END + * @param {Object} pointerEvent + */ + updatePointer: function(type, pointerEvent) { + if(type == Hammer.EVENT_END) { + this.pointers = {}; + } + else { + pointerEvent.identifier = pointerEvent.pointerId; + this.pointers[pointerEvent.pointerId] = pointerEvent; + } + + return Object.keys(this.pointers).length; + }, + + /** + * check if ev matches pointertype + * @param {String} pointerType Hammer.POINTER_MOUSE + * @param {PointerEvent} ev + */ + matchType: function(pointerType, ev) { + if(!ev.pointerType) { + return false; + } + + var types = {}; + types[Hammer.POINTER_MOUSE] = (ev.pointerType == ev.MSPOINTER_TYPE_MOUSE || ev.pointerType == Hammer.POINTER_MOUSE); + types[Hammer.POINTER_TOUCH] = (ev.pointerType == ev.MSPOINTER_TYPE_TOUCH || ev.pointerType == Hammer.POINTER_TOUCH); + types[Hammer.POINTER_PEN] = (ev.pointerType == ev.MSPOINTER_TYPE_PEN || ev.pointerType == Hammer.POINTER_PEN); + return types[pointerType]; + }, + + + /** + * get events + */ + getEvents: function() { + return [ + 'pointerdown MSPointerDown', + 'pointermove MSPointerMove', + 'pointerup pointercancel MSPointerUp MSPointerCancel' + ]; + }, + + /** + * reset the list + */ + reset: function() { + this.pointers = {}; + } +}; + + +Hammer.utils = { + /** + * extend method, + * also used for cloning when dest is an empty object + * @param {Object} dest + * @param {Object} src + * @parm {Boolean} merge do a merge + * @returns {Object} dest + */ + extend: function extend(dest, src, merge) { + for (var key in src) { + if(dest[key] !== undefined && merge) { + continue; + } + dest[key] = src[key]; + } + return dest; + }, /** @@ -13397,7 +16690,7 @@ else { })(this); },{}],3:[function(require,module,exports){ //! moment.js -//! version : 2.5.0 +//! version : 2.5.1 //! authors : Tim Wood, Iskren Chernev, Moment.js contributors //! license : MIT //! momentjs.com @@ -13409,7 +16702,7 @@ else { ************************************/ var moment, - VERSION = "2.5.0", + VERSION = "2.5.1", global = this, round = Math.round, i, @@ -13425,6 +16718,19 @@ else { // internal storage for language config files languages = {}, + // moment internal properties + momentProperties = { + _isAMomentObject: null, + _i : null, + _f : null, + _l : null, + _strict : null, + _isUTC : null, + _offset : null, // optional. Combine with _isUTC + _pf : null, + _lang : null // optional + }, + // check for nodeJS hasModule = (typeof module !== 'undefined' && module.exports && typeof require !== 'undefined'), @@ -13456,19 +16762,21 @@ else { parseTokenTwoDigits = /\d\d/, // 00 - 99 parseTokenThreeDigits = /\d{3}/, // 000 - 999 parseTokenFourDigits = /\d{4}/, // 0000 - 9999 - parseTokenSixDigits = /[+\-]?\d{6}/, // -999,999 - 999,999 + parseTokenSixDigits = /[+-]?\d{6}/, // -999,999 - 999,999 + parseTokenSignedNumber = /[+-]?\d+/, // -inf - inf // iso 8601 regex // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00) - isoRegex = /^\s*\d{4}-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/, + isoRegex = /^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/, isoFormat = 'YYYY-MM-DDTHH:mm:ssZ', isoDates = [ - 'YYYY-MM-DD', - 'GGGG-[W]WW', - 'GGGG-[W]WW-E', - 'YYYY-DDD' + ['YYYYYY-MM-DD', /[+-]\d{6}-\d{2}-\d{2}/], + ['YYYY-MM-DD', /\d{4}-\d{2}-\d{2}/], + ['GGGG-[W]WW-E', /\d{4}-W\d{2}-\d/], + ['GGGG-[W]WW', /\d{4}-W\d{2}/], + ['YYYY-DDD', /\d{4}-\d{3}/] ], // iso time formats and regexes @@ -13578,7 +16886,7 @@ else { return leftZeroFill(this.weekYear() % 100, 2); }, gggg : function () { - return this.weekYear(); + return leftZeroFill(this.weekYear(), 4); }, ggggg : function () { return leftZeroFill(this.weekYear(), 5); @@ -13587,7 +16895,7 @@ else { return leftZeroFill(this.isoWeekYear() % 100, 2); }, GGGG : function () { - return this.isoWeekYear(); + return leftZeroFill(this.isoWeekYear(), 4); }, GGGGG : function () { return leftZeroFill(this.isoWeekYear(), 5); @@ -13662,6 +16970,23 @@ else { lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin']; + function defaultParsingFlags() { + // We need to deep clone this object, and es5 standard is not very + // helpful. + return { + empty : false, + unusedTokens : [], + unusedInput : [], + overflow : -2, + charsLeftOver : 0, + nullInput : false, + invalidMonth : null, + invalidFormat : false, + userInvalidated : false, + iso: false + }; + } + function padToken(func, count) { return function (a) { return leftZeroFill(func.call(this, a), count); @@ -13753,6 +17078,17 @@ else { return a; } + function cloneMoment(m) { + var result = {}, i; + for (i in m) { + if (m.hasOwnProperty(i) && momentProperties.hasOwnProperty(i)) { + result[i] = m[i]; + } + } + + return result; + } + function absRound(number) { if (number < 0) { return Math.ceil(number); @@ -13764,7 +17100,7 @@ else { // left zero fill a number // see http://jsperf.com/left-zero-filling for performance comparison function leftZeroFill(number, targetLength, forceSign) { - var output = Math.abs(number) + '', + var output = '' + Math.abs(number), sign = number >= 0; while (output.length < targetLength) { @@ -13944,21 +17280,6 @@ else { } } - function initializeParsingFlags(config) { - config._pf = { - empty : false, - unusedTokens : [], - unusedInput : [], - overflow : -2, - charsLeftOver : 0, - nullInput : false, - invalidMonth : null, - invalidFormat : false, - userInvalidated : false, - iso: false - }; - } - function isValid(m) { if (m._isValid == null) { m._isValid = !isNaN(m._d.getTime()) && @@ -14327,6 +17648,10 @@ else { case 'GGGG': case 'gggg': return strict ? parseTokenFourDigits : parseTokenOneToFourDigits; + case 'Y': + case 'G': + case 'g': + return parseTokenSignedNumber; case 'YYYYYY': case 'YYYYY': case 'GGGGG': @@ -14339,8 +17664,10 @@ else { if (strict) { return parseTokenTwoDigits; } /* falls through */ case 'SSS': + if (strict) { return parseTokenThreeDigits; } + /* falls through */ case 'DDD': - return strict ? parseTokenThreeDigits : parseTokenOneToThreeDigits; + return parseTokenOneToThreeDigits; case 'MMM': case 'MMMM': case 'dd': @@ -14382,7 +17709,7 @@ else { case 'W': case 'e': case 'E': - return strict ? parseTokenOneDigit : parseTokenOneOrTwoDigits; + return parseTokenOneOrTwoDigits; default : a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), "i")); return a; @@ -14510,1255 +17837,2059 @@ else { } } - // convert an array to a date. - // the array should mirror the parameters below - // note: all values past the year are optional and will default to the lowest possible value. - // [year, month, day , hour, minute, second, millisecond] - function dateFromConfig(config) { - var i, date, input = [], currentDate, - yearToUse, fixYear, w, temp, lang, weekday, week; + // convert an array to a date. + // the array should mirror the parameters below + // note: all values past the year are optional and will default to the lowest possible value. + // [year, month, day , hour, minute, second, millisecond] + function dateFromConfig(config) { + var i, date, input = [], currentDate, + yearToUse, fixYear, w, temp, lang, weekday, week; + + if (config._d) { + return; + } + + currentDate = currentDateArray(config); + + //compute day of the year from weeks and weekdays + if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { + fixYear = function (val) { + var int_val = parseInt(val, 10); + return val ? + (val.length < 3 ? (int_val > 68 ? 1900 + int_val : 2000 + int_val) : int_val) : + (config._a[YEAR] == null ? moment().weekYear() : config._a[YEAR]); + }; + + w = config._w; + if (w.GG != null || w.W != null || w.E != null) { + temp = dayOfYearFromWeeks(fixYear(w.GG), w.W || 1, w.E, 4, 1); + } + else { + lang = getLangDefinition(config._l); + weekday = w.d != null ? parseWeekday(w.d, lang) : + (w.e != null ? parseInt(w.e, 10) + lang._week.dow : 0); + + week = parseInt(w.w, 10) || 1; + + //if we're parsing 'd', then the low day numbers may be next week + if (w.d != null && weekday < lang._week.dow) { + week++; + } + + temp = dayOfYearFromWeeks(fixYear(w.gg), week, weekday, lang._week.doy, lang._week.dow); + } + + config._a[YEAR] = temp.year; + config._dayOfYear = temp.dayOfYear; + } + + //if the day of the year is set, figure out what it is + if (config._dayOfYear) { + yearToUse = config._a[YEAR] == null ? currentDate[YEAR] : config._a[YEAR]; + + if (config._dayOfYear > daysInYear(yearToUse)) { + config._pf._overflowDayOfYear = true; + } + + date = makeUTCDate(yearToUse, 0, config._dayOfYear); + config._a[MONTH] = date.getUTCMonth(); + config._a[DATE] = date.getUTCDate(); + } + + // Default to current date. + // * if no year, month, day of month are given, default to today + // * if day of month is given, default month and year + // * if month is given, default only year + // * if year is given, don't default anything + for (i = 0; i < 3 && config._a[i] == null; ++i) { + config._a[i] = input[i] = currentDate[i]; + } + + // Zero out whatever was not defaulted, including time + for (; i < 7; i++) { + config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; + } + + // add the offsets to the time to be parsed so that we can have a clean array for checking isValid + input[HOUR] += toInt((config._tzm || 0) / 60); + input[MINUTE] += toInt((config._tzm || 0) % 60); + + config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input); + } + + function dateFromObject(config) { + var normalizedInput; + + if (config._d) { + return; + } + + normalizedInput = normalizeObjectUnits(config._i); + config._a = [ + normalizedInput.year, + normalizedInput.month, + normalizedInput.day, + normalizedInput.hour, + normalizedInput.minute, + normalizedInput.second, + normalizedInput.millisecond + ]; + + dateFromConfig(config); + } + + function currentDateArray(config) { + var now = new Date(); + if (config._useUTC) { + return [ + now.getUTCFullYear(), + now.getUTCMonth(), + now.getUTCDate() + ]; + } else { + return [now.getFullYear(), now.getMonth(), now.getDate()]; + } + } + + // date from string and format string + function makeDateFromStringAndFormat(config) { + + config._a = []; + config._pf.empty = true; + + // This array is used to make a Date, either with `new Date` or `Date.UTC` + var lang = getLangDefinition(config._l), + string = '' + config._i, + i, parsedInput, tokens, token, skipped, + stringLength = string.length, + totalParsedInputLength = 0; + + tokens = expandFormat(config._f, lang).match(formattingTokens) || []; + + for (i = 0; i < tokens.length; i++) { + token = tokens[i]; + parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; + if (parsedInput) { + skipped = string.substr(0, string.indexOf(parsedInput)); + if (skipped.length > 0) { + config._pf.unusedInput.push(skipped); + } + string = string.slice(string.indexOf(parsedInput) + parsedInput.length); + totalParsedInputLength += parsedInput.length; + } + // don't parse if it's not a known token + if (formatTokenFunctions[token]) { + if (parsedInput) { + config._pf.empty = false; + } + else { + config._pf.unusedTokens.push(token); + } + addTimeToArrayFromToken(token, parsedInput, config); + } + else if (config._strict && !parsedInput) { + config._pf.unusedTokens.push(token); + } + } + + // add remaining unparsed input length to the string + config._pf.charsLeftOver = stringLength - totalParsedInputLength; + if (string.length > 0) { + config._pf.unusedInput.push(string); + } + + // handle am pm + if (config._isPm && config._a[HOUR] < 12) { + config._a[HOUR] += 12; + } + // if is 12 am, change hours to 0 + if (config._isPm === false && config._a[HOUR] === 12) { + config._a[HOUR] = 0; + } + + dateFromConfig(config); + checkOverflow(config); + } + + function unescapeFormat(s) { + return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) { + return p1 || p2 || p3 || p4; + }); + } - if (config._d) { + // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript + function regexpEscape(s) { + return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + } + + // date from string and array of format strings + function makeDateFromStringAndArray(config) { + var tempConfig, + bestMoment, + + scoreToBeat, + i, + currentScore; + + if (config._f.length === 0) { + config._pf.invalidFormat = true; + config._d = new Date(NaN); return; } - currentDate = currentDateArray(config); + for (i = 0; i < config._f.length; i++) { + currentScore = 0; + tempConfig = extend({}, config); + tempConfig._pf = defaultParsingFlags(); + tempConfig._f = config._f[i]; + makeDateFromStringAndFormat(tempConfig); - //compute day of the year from weeks and weekdays - if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { - fixYear = function (val) { - var int_val = parseInt(val, 10); - return val ? - (val.length < 3 ? (int_val > 68 ? 1900 + int_val : 2000 + int_val) : int_val) : - (config._a[YEAR] == null ? moment().weekYear() : config._a[YEAR]); - }; + if (!isValid(tempConfig)) { + continue; + } - w = config._w; - if (w.GG != null || w.W != null || w.E != null) { - temp = dayOfYearFromWeeks(fixYear(w.GG), w.W || 1, w.E, 4, 1); + // if there is any input that was not parsed add a penalty for that format + currentScore += tempConfig._pf.charsLeftOver; + + //or tokens + currentScore += tempConfig._pf.unusedTokens.length * 10; + + tempConfig._pf.score = currentScore; + + if (scoreToBeat == null || currentScore < scoreToBeat) { + scoreToBeat = currentScore; + bestMoment = tempConfig; } - else { - lang = getLangDefinition(config._l); - weekday = w.d != null ? parseWeekday(w.d, lang) : - (w.e != null ? parseInt(w.e, 10) + lang._week.dow : 0); + } - week = parseInt(w.w, 10) || 1; + extend(config, bestMoment || tempConfig); + } - //if we're parsing 'd', then the low day numbers may be next week - if (w.d != null && weekday < lang._week.dow) { - week++; - } + // date from iso format + function makeDateFromString(config) { + var i, l, + string = config._i, + match = isoRegex.exec(string); - temp = dayOfYearFromWeeks(fixYear(w.gg), week, weekday, lang._week.doy, lang._week.dow); + if (match) { + config._pf.iso = true; + for (i = 0, l = isoDates.length; i < l; i++) { + if (isoDates[i][1].exec(string)) { + // match[5] should be "T" or undefined + config._f = isoDates[i][0] + (match[6] || " "); + break; + } + } + for (i = 0, l = isoTimes.length; i < l; i++) { + if (isoTimes[i][1].exec(string)) { + config._f += isoTimes[i][0]; + break; + } + } + if (string.match(parseTokenTimezone)) { + config._f += "Z"; } + makeDateFromStringAndFormat(config); + } + else { + config._d = new Date(string); + } + } - config._a[YEAR] = temp.year; - config._dayOfYear = temp.dayOfYear; + function makeDateFromInput(config) { + var input = config._i, + matched = aspNetJsonRegex.exec(input); + + if (input === undefined) { + config._d = new Date(); + } else if (matched) { + config._d = new Date(+matched[1]); + } else if (typeof input === 'string') { + makeDateFromString(config); + } else if (isArray(input)) { + config._a = input.slice(0); + dateFromConfig(config); + } else if (isDate(input)) { + config._d = new Date(+input); + } else if (typeof(input) === 'object') { + dateFromObject(config); + } else { + config._d = new Date(input); } + } - //if the day of the year is set, figure out what it is - if (config._dayOfYear) { - yearToUse = config._a[YEAR] == null ? currentDate[YEAR] : config._a[YEAR]; + function makeDate(y, m, d, h, M, s, ms) { + //can't just apply() to create a date: + //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply + var date = new Date(y, m, d, h, M, s, ms); - if (config._dayOfYear > daysInYear(yearToUse)) { - config._pf._overflowDayOfYear = true; - } + //the date constructor doesn't accept years < 1970 + if (y < 1970) { + date.setFullYear(y); + } + return date; + } - date = makeUTCDate(yearToUse, 0, config._dayOfYear); - config._a[MONTH] = date.getUTCMonth(); - config._a[DATE] = date.getUTCDate(); + function makeUTCDate(y) { + var date = new Date(Date.UTC.apply(null, arguments)); + if (y < 1970) { + date.setUTCFullYear(y); } + return date; + } - // Default to current date. - // * if no year, month, day of month are given, default to today - // * if day of month is given, default month and year - // * if month is given, default only year - // * if year is given, don't default anything - for (i = 0; i < 3 && config._a[i] == null; ++i) { - config._a[i] = input[i] = currentDate[i]; + function parseWeekday(input, language) { + if (typeof input === 'string') { + if (!isNaN(input)) { + input = parseInt(input, 10); + } + else { + input = language.weekdaysParse(input); + if (typeof input !== 'number') { + return null; + } + } } + return input; + } - // Zero out whatever was not defaulted, including time - for (; i < 7; i++) { - config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; + /************************************ + Relative Time + ************************************/ + + + // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize + function substituteTimeAgo(string, number, withoutSuffix, isFuture, lang) { + return lang.relativeTime(number || 1, !!withoutSuffix, string, isFuture); + } + + function relativeTime(milliseconds, withoutSuffix, lang) { + var seconds = round(Math.abs(milliseconds) / 1000), + minutes = round(seconds / 60), + hours = round(minutes / 60), + days = round(hours / 24), + years = round(days / 365), + args = seconds < 45 && ['s', seconds] || + minutes === 1 && ['m'] || + minutes < 45 && ['mm', minutes] || + hours === 1 && ['h'] || + hours < 22 && ['hh', hours] || + days === 1 && ['d'] || + days <= 25 && ['dd', days] || + days <= 45 && ['M'] || + days < 345 && ['MM', round(days / 30)] || + years === 1 && ['y'] || ['yy', years]; + args[2] = withoutSuffix; + args[3] = milliseconds > 0; + args[4] = lang; + return substituteTimeAgo.apply({}, args); + } + + + /************************************ + Week of Year + ************************************/ + + + // firstDayOfWeek 0 = sun, 6 = sat + // the day of the week that starts the week + // (usually sunday or monday) + // firstDayOfWeekOfYear 0 = sun, 6 = sat + // the first week is the week that contains the first + // of this day of the week + // (eg. ISO weeks use thursday (4)) + function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { + var end = firstDayOfWeekOfYear - firstDayOfWeek, + daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(), + adjustedMoment; + + + if (daysToDayOfWeek > end) { + daysToDayOfWeek -= 7; } - // add the offsets to the time to be parsed so that we can have a clean array for checking isValid - input[HOUR] += toInt((config._tzm || 0) / 60); - input[MINUTE] += toInt((config._tzm || 0) % 60); + if (daysToDayOfWeek < end - 7) { + daysToDayOfWeek += 7; + } - config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input); + adjustedMoment = moment(mom).add('d', daysToDayOfWeek); + return { + week: Math.ceil(adjustedMoment.dayOfYear() / 7), + year: adjustedMoment.year() + }; } - function dateFromObject(config) { - var normalizedInput; + //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday + function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) { + var d = makeUTCDate(year, 0, 1).getUTCDay(), daysToAdd, dayOfYear; + + weekday = weekday != null ? weekday : firstDayOfWeek; + daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0) - (d < firstDayOfWeek ? 7 : 0); + dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1; + + return { + year: dayOfYear > 0 ? year : year - 1, + dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear + }; + } + + /************************************ + Top Level Functions + ************************************/ + + function makeMoment(config) { + var input = config._i, + format = config._f; - if (config._d) { - return; + if (input === null) { + return moment.invalid({nullInput: true}); } - normalizedInput = normalizeObjectUnits(config._i); - config._a = [ - normalizedInput.year, - normalizedInput.month, - normalizedInput.day, - normalizedInput.hour, - normalizedInput.minute, - normalizedInput.second, - normalizedInput.millisecond - ]; + if (typeof input === 'string') { + config._i = input = getLangDefinition().preparse(input); + } - dateFromConfig(config); - } + if (moment.isMoment(input)) { + config = cloneMoment(input); - function currentDateArray(config) { - var now = new Date(); - if (config._useUTC) { - return [ - now.getUTCFullYear(), - now.getUTCMonth(), - now.getUTCDate() - ]; + config._d = new Date(+input._d); + } else if (format) { + if (isArray(format)) { + makeDateFromStringAndArray(config); + } else { + makeDateFromStringAndFormat(config); + } } else { - return [now.getFullYear(), now.getMonth(), now.getDate()]; + makeDateFromInput(config); } + + return new Moment(config); } - // date from string and format string - function makeDateFromStringAndFormat(config) { + moment = function (input, format, lang, strict) { + var c; - config._a = []; - config._pf.empty = true; + if (typeof(lang) === "boolean") { + strict = lang; + lang = undefined; + } + // object construction must be done this way. + // https://github.com/moment/moment/issues/1423 + c = {}; + c._isAMomentObject = true; + c._i = input; + c._f = format; + c._l = lang; + c._strict = strict; + c._isUTC = false; + c._pf = defaultParsingFlags(); + + return makeMoment(c); + }; - // This array is used to make a Date, either with `new Date` or `Date.UTC` - var lang = getLangDefinition(config._l), - string = '' + config._i, - i, parsedInput, tokens, token, skipped, - stringLength = string.length, - totalParsedInputLength = 0; + // creating with utc + moment.utc = function (input, format, lang, strict) { + var c; - tokens = expandFormat(config._f, lang).match(formattingTokens) || []; + if (typeof(lang) === "boolean") { + strict = lang; + lang = undefined; + } + // object construction must be done this way. + // https://github.com/moment/moment/issues/1423 + c = {}; + c._isAMomentObject = true; + c._useUTC = true; + c._isUTC = true; + c._l = lang; + c._i = input; + c._f = format; + c._strict = strict; + c._pf = defaultParsingFlags(); + + return makeMoment(c).utc(); + }; - for (i = 0; i < tokens.length; i++) { - token = tokens[i]; - parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; - if (parsedInput) { - skipped = string.substr(0, string.indexOf(parsedInput)); - if (skipped.length > 0) { - config._pf.unusedInput.push(skipped); - } - string = string.slice(string.indexOf(parsedInput) + parsedInput.length); - totalParsedInputLength += parsedInput.length; - } - // don't parse if it's not a known token - if (formatTokenFunctions[token]) { - if (parsedInput) { - config._pf.empty = false; - } - else { - config._pf.unusedTokens.push(token); - } - addTimeToArrayFromToken(token, parsedInput, config); - } - else if (config._strict && !parsedInput) { - config._pf.unusedTokens.push(token); + // creating with unix timestamp (in seconds) + moment.unix = function (input) { + return moment(input * 1000); + }; + + // duration + moment.duration = function (input, key) { + var duration = input, + // matching against regexp is expensive, do it on demand + match = null, + sign, + ret, + parseIso; + + if (moment.isDuration(input)) { + duration = { + ms: input._milliseconds, + d: input._days, + M: input._months + }; + } else if (typeof input === 'number') { + duration = {}; + if (key) { + duration[key] = input; + } else { + duration.milliseconds = input; } + } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) { + sign = (match[1] === "-") ? -1 : 1; + duration = { + y: 0, + d: toInt(match[DATE]) * sign, + h: toInt(match[HOUR]) * sign, + m: toInt(match[MINUTE]) * sign, + s: toInt(match[SECOND]) * sign, + ms: toInt(match[MILLISECOND]) * sign + }; + } else if (!!(match = isoDurationRegex.exec(input))) { + sign = (match[1] === "-") ? -1 : 1; + parseIso = function (inp) { + // We'd normally use ~~inp for this, but unfortunately it also + // converts floats to ints. + // inp may be undefined, so careful calling replace on it. + var res = inp && parseFloat(inp.replace(',', '.')); + // apply sign while we're at it + return (isNaN(res) ? 0 : res) * sign; + }; + duration = { + y: parseIso(match[2]), + M: parseIso(match[3]), + d: parseIso(match[4]), + h: parseIso(match[5]), + m: parseIso(match[6]), + s: parseIso(match[7]), + w: parseIso(match[8]) + }; } - // add remaining unparsed input length to the string - config._pf.charsLeftOver = stringLength - totalParsedInputLength; - if (string.length > 0) { - config._pf.unusedInput.push(string); + ret = new Duration(duration); + + if (moment.isDuration(input) && input.hasOwnProperty('_lang')) { + ret._lang = input._lang; } - // handle am pm - if (config._isPm && config._a[HOUR] < 12) { - config._a[HOUR] += 12; + return ret; + }; + + // version number + moment.version = VERSION; + + // default format + moment.defaultFormat = isoFormat; + + // This function will be called whenever a moment is mutated. + // It is intended to keep the offset in sync with the timezone. + moment.updateOffset = function () {}; + + // This function will load languages and then set the global language. If + // no arguments are passed in, it will simply return the current global + // language key. + moment.lang = function (key, values) { + var r; + if (!key) { + return moment.fn._lang._abbr; } - // if is 12 am, change hours to 0 - if (config._isPm === false && config._a[HOUR] === 12) { - config._a[HOUR] = 0; + if (values) { + loadLang(normalizeLanguage(key), values); + } else if (values === null) { + unloadLang(key); + key = 'en'; + } else if (!languages[key]) { + getLangDefinition(key); } + r = moment.duration.fn._lang = moment.fn._lang = getLangDefinition(key); + return r._abbr; + }; - dateFromConfig(config); - checkOverflow(config); - } + // returns language data + moment.langData = function (key) { + if (key && key._lang && key._lang._abbr) { + key = key._lang._abbr; + } + return getLangDefinition(key); + }; - function unescapeFormat(s) { - return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) { - return p1 || p2 || p3 || p4; - }); - } + // compare moment object + moment.isMoment = function (obj) { + return obj instanceof Moment || + (obj != null && obj.hasOwnProperty('_isAMomentObject')); + }; - // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript - function regexpEscape(s) { - return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); - } + // for typechecking Duration objects + moment.isDuration = function (obj) { + return obj instanceof Duration; + }; - // date from string and array of format strings - function makeDateFromStringAndArray(config) { - var tempConfig, - bestMoment, + for (i = lists.length - 1; i >= 0; --i) { + makeList(lists[i]); + } - scoreToBeat, - i, - currentScore; + moment.normalizeUnits = function (units) { + return normalizeUnits(units); + }; - if (config._f.length === 0) { - config._pf.invalidFormat = true; - config._d = new Date(NaN); - return; + moment.invalid = function (flags) { + var m = moment.utc(NaN); + if (flags != null) { + extend(m._pf, flags); + } + else { + m._pf.userInvalidated = true; } - for (i = 0; i < config._f.length; i++) { - currentScore = 0; - tempConfig = extend({}, config); - initializeParsingFlags(tempConfig); - tempConfig._f = config._f[i]; - makeDateFromStringAndFormat(tempConfig); + return m; + }; + + moment.parseZone = function (input) { + return moment(input).parseZone(); + }; + + /************************************ + Moment Prototype + ************************************/ + + + extend(moment.fn = Moment.prototype, { + + clone : function () { + return moment(this); + }, - if (!isValid(tempConfig)) { - continue; - } + valueOf : function () { + return +this._d + ((this._offset || 0) * 60000); + }, - // if there is any input that was not parsed add a penalty for that format - currentScore += tempConfig._pf.charsLeftOver; + unix : function () { + return Math.floor(+this / 1000); + }, - //or tokens - currentScore += tempConfig._pf.unusedTokens.length * 10; + toString : function () { + return this.clone().lang('en').format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ"); + }, - tempConfig._pf.score = currentScore; + toDate : function () { + return this._offset ? new Date(+this) : this._d; + }, - if (scoreToBeat == null || currentScore < scoreToBeat) { - scoreToBeat = currentScore; - bestMoment = tempConfig; + toISOString : function () { + var m = moment(this).utc(); + if (0 < m.year() && m.year() <= 9999) { + return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); + } else { + return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); } - } + }, - extend(config, bestMoment || tempConfig); - } + toArray : function () { + var m = this; + return [ + m.year(), + m.month(), + m.date(), + m.hours(), + m.minutes(), + m.seconds(), + m.milliseconds() + ]; + }, - // date from iso format - function makeDateFromString(config) { - var i, - string = config._i, - match = isoRegex.exec(string); + isValid : function () { + return isValid(this); + }, - if (match) { - config._pf.iso = true; - for (i = 4; i > 0; i--) { - if (match[i]) { - // match[5] should be "T" or undefined - config._f = isoDates[i - 1] + (match[6] || " "); - break; - } - } - for (i = 0; i < 4; i++) { - if (isoTimes[i][1].exec(string)) { - config._f += isoTimes[i][0]; - break; - } - } - if (string.match(parseTokenTimezone)) { - config._f += "Z"; - } - makeDateFromStringAndFormat(config); - } - else { - config._d = new Date(string); - } - } + isDSTShifted : function () { - function makeDateFromInput(config) { - var input = config._i, - matched = aspNetJsonRegex.exec(input); + if (this._a) { + return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0; + } - if (input === undefined) { - config._d = new Date(); - } else if (matched) { - config._d = new Date(+matched[1]); - } else if (typeof input === 'string') { - makeDateFromString(config); - } else if (isArray(input)) { - config._a = input.slice(0); - dateFromConfig(config); - } else if (isDate(input)) { - config._d = new Date(+input); - } else if (typeof(input) === 'object') { - dateFromObject(config); - } else { - config._d = new Date(input); - } - } + return false; + }, - function makeDate(y, m, d, h, M, s, ms) { - //can't just apply() to create a date: - //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply - var date = new Date(y, m, d, h, M, s, ms); + parsingFlags : function () { + return extend({}, this._pf); + }, - //the date constructor doesn't accept years < 1970 - if (y < 1970) { - date.setFullYear(y); - } - return date; - } + invalidAt: function () { + return this._pf.overflow; + }, - function makeUTCDate(y) { - var date = new Date(Date.UTC.apply(null, arguments)); - if (y < 1970) { - date.setUTCFullYear(y); - } - return date; - } + utc : function () { + return this.zone(0); + }, - function parseWeekday(input, language) { - if (typeof input === 'string') { - if (!isNaN(input)) { - input = parseInt(input, 10); - } - else { - input = language.weekdaysParse(input); - if (typeof input !== 'number') { - return null; - } - } - } - return input; - } + local : function () { + this.zone(0); + this._isUTC = false; + return this; + }, - /************************************ - Relative Time - ************************************/ + format : function (inputString) { + var output = formatMoment(this, inputString || moment.defaultFormat); + return this.lang().postformat(output); + }, + add : function (input, val) { + var dur; + // switch args to support add('s', 1) and add(1, 's') + if (typeof input === 'string') { + dur = moment.duration(+val, input); + } else { + dur = moment.duration(input, val); + } + addOrSubtractDurationFromMoment(this, dur, 1); + return this; + }, - // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize - function substituteTimeAgo(string, number, withoutSuffix, isFuture, lang) { - return lang.relativeTime(number || 1, !!withoutSuffix, string, isFuture); - } + subtract : function (input, val) { + var dur; + // switch args to support subtract('s', 1) and subtract(1, 's') + if (typeof input === 'string') { + dur = moment.duration(+val, input); + } else { + dur = moment.duration(input, val); + } + addOrSubtractDurationFromMoment(this, dur, -1); + return this; + }, - function relativeTime(milliseconds, withoutSuffix, lang) { - var seconds = round(Math.abs(milliseconds) / 1000), - minutes = round(seconds / 60), - hours = round(minutes / 60), - days = round(hours / 24), - years = round(days / 365), - args = seconds < 45 && ['s', seconds] || - minutes === 1 && ['m'] || - minutes < 45 && ['mm', minutes] || - hours === 1 && ['h'] || - hours < 22 && ['hh', hours] || - days === 1 && ['d'] || - days <= 25 && ['dd', days] || - days <= 45 && ['M'] || - days < 345 && ['MM', round(days / 30)] || - years === 1 && ['y'] || ['yy', years]; - args[2] = withoutSuffix; - args[3] = milliseconds > 0; - args[4] = lang; - return substituteTimeAgo.apply({}, args); - } + diff : function (input, units, asFloat) { + var that = makeAs(input, this), + zoneDiff = (this.zone() - that.zone()) * 6e4, + diff, output; + units = normalizeUnits(units); - /************************************ - Week of Year - ************************************/ + if (units === 'year' || units === 'month') { + // average number of days in the months in the given dates + diff = (this.daysInMonth() + that.daysInMonth()) * 432e5; // 24 * 60 * 60 * 1000 / 2 + // difference in months + output = ((this.year() - that.year()) * 12) + (this.month() - that.month()); + // adjust by taking difference in days, average number of days + // and dst in the given months. + output += ((this - moment(this).startOf('month')) - + (that - moment(that).startOf('month'))) / diff; + // same as above but with zones, to negate all dst + output -= ((this.zone() - moment(this).startOf('month').zone()) - + (that.zone() - moment(that).startOf('month').zone())) * 6e4 / diff; + if (units === 'year') { + output = output / 12; + } + } else { + diff = (this - that); + output = units === 'second' ? diff / 1e3 : // 1000 + units === 'minute' ? diff / 6e4 : // 1000 * 60 + units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60 + units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst + units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst + diff; + } + return asFloat ? output : absRound(output); + }, + from : function (time, withoutSuffix) { + return moment.duration(this.diff(time)).lang(this.lang()._abbr).humanize(!withoutSuffix); + }, - // firstDayOfWeek 0 = sun, 6 = sat - // the day of the week that starts the week - // (usually sunday or monday) - // firstDayOfWeekOfYear 0 = sun, 6 = sat - // the first week is the week that contains the first - // of this day of the week - // (eg. ISO weeks use thursday (4)) - function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { - var end = firstDayOfWeekOfYear - firstDayOfWeek, - daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(), - adjustedMoment; + fromNow : function (withoutSuffix) { + return this.from(moment(), withoutSuffix); + }, + calendar : function () { + // We want to compare the start of today, vs this. + // Getting start-of-today depends on whether we're zone'd or not. + var sod = makeAs(moment(), this).startOf('day'), + diff = this.diff(sod, 'days', true), + format = diff < -6 ? 'sameElse' : + diff < -1 ? 'lastWeek' : + diff < 0 ? 'lastDay' : + diff < 1 ? 'sameDay' : + diff < 2 ? 'nextDay' : + diff < 7 ? 'nextWeek' : 'sameElse'; + return this.format(this.lang().calendar(format, this)); + }, - if (daysToDayOfWeek > end) { - daysToDayOfWeek -= 7; - } + isLeapYear : function () { + return isLeapYear(this.year()); + }, - if (daysToDayOfWeek < end - 7) { - daysToDayOfWeek += 7; - } + isDST : function () { + return (this.zone() < this.clone().month(0).zone() || + this.zone() < this.clone().month(5).zone()); + }, - adjustedMoment = moment(mom).add('d', daysToDayOfWeek); - return { - week: Math.ceil(adjustedMoment.dayOfYear() / 7), - year: adjustedMoment.year() - }; - } + day : function (input) { + var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); + if (input != null) { + input = parseWeekday(input, this.lang()); + return this.add({ d : input - day }); + } else { + return day; + } + }, - //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday - function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) { - // The only solid way to create an iso date from year is to use - // a string format (Date.UTC handles only years > 1900). Don't ask why - // it doesn't need Z at the end. - var d = new Date(leftZeroFill(year, 6, true) + '-01-01').getUTCDay(), - daysToAdd, dayOfYear; + month : function (input) { + var utc = this._isUTC ? 'UTC' : '', + dayOfMonth; - weekday = weekday != null ? weekday : firstDayOfWeek; - daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0); - dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1; + if (input != null) { + if (typeof input === 'string') { + input = this.lang().monthsParse(input); + if (typeof input !== 'number') { + return this; + } + } - return { - year: dayOfYear > 0 ? year : year - 1, - dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear - }; - } + dayOfMonth = this.date(); + this.date(1); + this._d['set' + utc + 'Month'](input); + this.date(Math.min(dayOfMonth, this.daysInMonth())); - /************************************ - Top Level Functions - ************************************/ + moment.updateOffset(this); + return this; + } else { + return this._d['get' + utc + 'Month'](); + } + }, - function makeMoment(config) { - var input = config._i, - format = config._f; + startOf: function (units) { + units = normalizeUnits(units); + // the following switch intentionally omits break keywords + // to utilize falling through the cases. + switch (units) { + case 'year': + this.month(0); + /* falls through */ + case 'month': + this.date(1); + /* falls through */ + case 'week': + case 'isoWeek': + case 'day': + this.hours(0); + /* falls through */ + case 'hour': + this.minutes(0); + /* falls through */ + case 'minute': + this.seconds(0); + /* falls through */ + case 'second': + this.milliseconds(0); + /* falls through */ + } - if (typeof config._pf === 'undefined') { - initializeParsingFlags(config); - } + // weeks are a special case + if (units === 'week') { + this.weekday(0); + } else if (units === 'isoWeek') { + this.isoWeekday(1); + } - if (input === null) { - return moment.invalid({nullInput: true}); - } + return this; + }, - if (typeof input === 'string') { - config._i = input = getLangDefinition().preparse(input); - } + endOf: function (units) { + units = normalizeUnits(units); + return this.startOf(units).add((units === 'isoWeek' ? 'week' : units), 1).subtract('ms', 1); + }, - if (moment.isMoment(input)) { - config = extend({}, input); + isAfter: function (input, units) { + units = typeof units !== 'undefined' ? units : 'millisecond'; + return +this.clone().startOf(units) > +moment(input).startOf(units); + }, - config._d = new Date(+input._d); - } else if (format) { - if (isArray(format)) { - makeDateFromStringAndArray(config); - } else { - makeDateFromStringAndFormat(config); - } - } else { - makeDateFromInput(config); - } + isBefore: function (input, units) { + units = typeof units !== 'undefined' ? units : 'millisecond'; + return +this.clone().startOf(units) < +moment(input).startOf(units); + }, - return new Moment(config); - } + isSame: function (input, units) { + units = units || 'ms'; + return +this.clone().startOf(units) === +makeAs(input, this).startOf(units); + }, - moment = function (input, format, lang, strict) { - if (typeof(lang) === "boolean") { - strict = lang; - lang = undefined; - } - return makeMoment({ - _i : input, - _f : format, - _l : lang, - _strict : strict, - _isUTC : false - }); - }; + min: function (other) { + other = moment.apply(null, arguments); + return other < this ? this : other; + }, - // creating with utc - moment.utc = function (input, format, lang, strict) { - var m; + max: function (other) { + other = moment.apply(null, arguments); + return other > this ? this : other; + }, - if (typeof(lang) === "boolean") { - strict = lang; - lang = undefined; - } - m = makeMoment({ - _useUTC : true, - _isUTC : true, - _l : lang, - _i : input, - _f : format, - _strict : strict - }).utc(); + zone : function (input) { + var offset = this._offset || 0; + if (input != null) { + if (typeof input === "string") { + input = timezoneMinutesFromString(input); + } + if (Math.abs(input) < 16) { + input = input * 60; + } + this._offset = input; + this._isUTC = true; + if (offset !== input) { + addOrSubtractDurationFromMoment(this, moment.duration(offset - input, 'm'), 1, true); + } + } else { + return this._isUTC ? offset : this._d.getTimezoneOffset(); + } + return this; + }, - return m; - }; + zoneAbbr : function () { + return this._isUTC ? "UTC" : ""; + }, - // creating with unix timestamp (in seconds) - moment.unix = function (input) { - return moment(input * 1000); - }; + zoneName : function () { + return this._isUTC ? "Coordinated Universal Time" : ""; + }, - // duration - moment.duration = function (input, key) { - var duration = input, - // matching against regexp is expensive, do it on demand - match = null, - sign, - ret, - parseIso; + parseZone : function () { + if (this._tzm) { + this.zone(this._tzm); + } else if (typeof this._i === 'string') { + this.zone(this._i); + } + return this; + }, - if (moment.isDuration(input)) { - duration = { - ms: input._milliseconds, - d: input._days, - M: input._months - }; - } else if (typeof input === 'number') { - duration = {}; - if (key) { - duration[key] = input; - } else { - duration.milliseconds = input; + hasAlignedHourOffset : function (input) { + if (!input) { + input = 0; } - } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) { - sign = (match[1] === "-") ? -1 : 1; - duration = { - y: 0, - d: toInt(match[DATE]) * sign, - h: toInt(match[HOUR]) * sign, - m: toInt(match[MINUTE]) * sign, - s: toInt(match[SECOND]) * sign, - ms: toInt(match[MILLISECOND]) * sign - }; - } else if (!!(match = isoDurationRegex.exec(input))) { - sign = (match[1] === "-") ? -1 : 1; - parseIso = function (inp) { - // We'd normally use ~~inp for this, but unfortunately it also - // converts floats to ints. - // inp may be undefined, so careful calling replace on it. - var res = inp && parseFloat(inp.replace(',', '.')); - // apply sign while we're at it - return (isNaN(res) ? 0 : res) * sign; - }; - duration = { - y: parseIso(match[2]), - M: parseIso(match[3]), - d: parseIso(match[4]), - h: parseIso(match[5]), - m: parseIso(match[6]), - s: parseIso(match[7]), - w: parseIso(match[8]) - }; - } + else { + input = moment(input).zone(); + } + + return (this.zone() - input) % 60 === 0; + }, - ret = new Duration(duration); + daysInMonth : function () { + return daysInMonth(this.year(), this.month()); + }, - if (moment.isDuration(input) && input.hasOwnProperty('_lang')) { - ret._lang = input._lang; - } + dayOfYear : function (input) { + var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1; + return input == null ? dayOfYear : this.add("d", (input - dayOfYear)); + }, - return ret; - }; + quarter : function () { + return Math.ceil((this.month() + 1.0) / 3.0); + }, - // version number - moment.version = VERSION; + weekYear : function (input) { + var year = weekOfYear(this, this.lang()._week.dow, this.lang()._week.doy).year; + return input == null ? year : this.add("y", (input - year)); + }, - // default format - moment.defaultFormat = isoFormat; + isoWeekYear : function (input) { + var year = weekOfYear(this, 1, 4).year; + return input == null ? year : this.add("y", (input - year)); + }, - // This function will be called whenever a moment is mutated. - // It is intended to keep the offset in sync with the timezone. - moment.updateOffset = function () {}; + week : function (input) { + var week = this.lang().week(this); + return input == null ? week : this.add("d", (input - week) * 7); + }, - // This function will load languages and then set the global language. If - // no arguments are passed in, it will simply return the current global - // language key. - moment.lang = function (key, values) { - var r; - if (!key) { - return moment.fn._lang._abbr; - } - if (values) { - loadLang(normalizeLanguage(key), values); - } else if (values === null) { - unloadLang(key); - key = 'en'; - } else if (!languages[key]) { - getLangDefinition(key); - } - r = moment.duration.fn._lang = moment.fn._lang = getLangDefinition(key); - return r._abbr; - }; + isoWeek : function (input) { + var week = weekOfYear(this, 1, 4).week; + return input == null ? week : this.add("d", (input - week) * 7); + }, - // returns language data - moment.langData = function (key) { - if (key && key._lang && key._lang._abbr) { - key = key._lang._abbr; - } - return getLangDefinition(key); - }; + weekday : function (input) { + var weekday = (this.day() + 7 - this.lang()._week.dow) % 7; + return input == null ? weekday : this.add("d", input - weekday); + }, - // compare moment object - moment.isMoment = function (obj) { - return obj instanceof Moment; - }; + isoWeekday : function (input) { + // behaves the same as moment#day except + // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) + // as a setter, sunday should belong to the previous week. + return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7); + }, - // for typechecking Duration objects - moment.isDuration = function (obj) { - return obj instanceof Duration; - }; + get : function (units) { + units = normalizeUnits(units); + return this[units](); + }, - for (i = lists.length - 1; i >= 0; --i) { - makeList(lists[i]); + set : function (units, value) { + units = normalizeUnits(units); + if (typeof this[units] === 'function') { + this[units](value); + } + return this; + }, + + // If passed a language key, it will set the language for this + // instance. Otherwise, it will return the language configuration + // variables for this instance. + lang : function (key) { + if (key === undefined) { + return this._lang; + } else { + this._lang = getLangDefinition(key); + return this; + } + } + }); + + // helper for adding shortcuts + function makeGetterAndSetter(name, key) { + moment.fn[name] = moment.fn[name + 's'] = function (input) { + var utc = this._isUTC ? 'UTC' : ''; + if (input != null) { + this._d['set' + utc + key](input); + moment.updateOffset(this); + return this; + } else { + return this._d['get' + utc + key](); + } + }; } - moment.normalizeUnits = function (units) { - return normalizeUnits(units); - }; + // loop through and add shortcuts (Month, Date, Hours, Minutes, Seconds, Milliseconds) + for (i = 0; i < proxyGettersAndSetters.length; i ++) { + makeGetterAndSetter(proxyGettersAndSetters[i].toLowerCase().replace(/s$/, ''), proxyGettersAndSetters[i]); + } - moment.invalid = function (flags) { - var m = moment.utc(NaN); - if (flags != null) { - extend(m._pf, flags); - } - else { - m._pf.userInvalidated = true; - } + // add shortcut for year (uses different syntax than the getter/setter 'year' == 'FullYear') + makeGetterAndSetter('year', 'FullYear'); - return m; - }; + // add plural methods + moment.fn.days = moment.fn.day; + moment.fn.months = moment.fn.month; + moment.fn.weeks = moment.fn.week; + moment.fn.isoWeeks = moment.fn.isoWeek; - moment.parseZone = function (input) { - return moment(input).parseZone(); - }; + // add aliased format methods + moment.fn.toJSON = moment.fn.toISOString; /************************************ - Moment Prototype + Duration Prototype ************************************/ - extend(moment.fn = Moment.prototype, { + extend(moment.duration.fn = Duration.prototype, { - clone : function () { - return moment(this); + _bubble : function () { + var milliseconds = this._milliseconds, + days = this._days, + months = this._months, + data = this._data, + seconds, minutes, hours, years; + + // The following code bubbles up values, see the tests for + // examples of what that means. + data.milliseconds = milliseconds % 1000; + + seconds = absRound(milliseconds / 1000); + data.seconds = seconds % 60; + + minutes = absRound(seconds / 60); + data.minutes = minutes % 60; + + hours = absRound(minutes / 60); + data.hours = hours % 24; + + days += absRound(hours / 24); + data.days = days % 30; + + months += absRound(days / 30); + data.months = months % 12; + + years = absRound(months / 12); + data.years = years; }, - valueOf : function () { - return +this._d + ((this._offset || 0) * 60000); + weeks : function () { + return absRound(this.days() / 7); }, - unix : function () { - return Math.floor(+this / 1000); + valueOf : function () { + return this._milliseconds + + this._days * 864e5 + + (this._months % 12) * 2592e6 + + toInt(this._months / 12) * 31536e6; }, - toString : function () { - return this.clone().lang('en').format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ"); + humanize : function (withSuffix) { + var difference = +this, + output = relativeTime(difference, !withSuffix, this.lang()); + + if (withSuffix) { + output = this.lang().pastFuture(difference, output); + } + + return this.lang().postformat(output); }, - toDate : function () { - return this._offset ? new Date(+this) : this._d; + add : function (input, val) { + // supports only 2.0-style add(1, 's') or add(moment) + var dur = moment.duration(input, val); + + this._milliseconds += dur._milliseconds; + this._days += dur._days; + this._months += dur._months; + + this._bubble(); + + return this; }, - toISOString : function () { - var m = moment(this).utc(); - if (0 < m.year() && m.year() <= 9999) { - return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); - } else { - return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); - } + subtract : function (input, val) { + var dur = moment.duration(input, val); + + this._milliseconds -= dur._milliseconds; + this._days -= dur._days; + this._months -= dur._months; + + this._bubble(); + + return this; }, - toArray : function () { - var m = this; - return [ - m.year(), - m.month(), - m.date(), - m.hours(), - m.minutes(), - m.seconds(), - m.milliseconds() - ]; + get : function (units) { + units = normalizeUnits(units); + return this[units.toLowerCase() + 's'](); }, - isValid : function () { - return isValid(this); + as : function (units) { + units = normalizeUnits(units); + return this['as' + units.charAt(0).toUpperCase() + units.slice(1) + 's'](); }, - isDSTShifted : function () { + lang : moment.fn.lang, - if (this._a) { - return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0; + toIsoString : function () { + // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js + var years = Math.abs(this.years()), + months = Math.abs(this.months()), + days = Math.abs(this.days()), + hours = Math.abs(this.hours()), + minutes = Math.abs(this.minutes()), + seconds = Math.abs(this.seconds() + this.milliseconds() / 1000); + + if (!this.asSeconds()) { + // this is the same as C#'s (Noda) and python (isodate)... + // but not other JS (goog.date) + return 'P0D'; } - return false; - }, + return (this.asSeconds() < 0 ? '-' : '') + + 'P' + + (years ? years + 'Y' : '') + + (months ? months + 'M' : '') + + (days ? days + 'D' : '') + + ((hours || minutes || seconds) ? 'T' : '') + + (hours ? hours + 'H' : '') + + (minutes ? minutes + 'M' : '') + + (seconds ? seconds + 'S' : ''); + } + }); - parsingFlags : function () { - return extend({}, this._pf); - }, + function makeDurationGetter(name) { + moment.duration.fn[name] = function () { + return this._data[name]; + }; + } - invalidAt: function () { - return this._pf.overflow; - }, + function makeDurationAsGetter(name, factor) { + moment.duration.fn['as' + name] = function () { + return +this / factor; + }; + } - utc : function () { - return this.zone(0); - }, + for (i in unitMillisecondFactors) { + if (unitMillisecondFactors.hasOwnProperty(i)) { + makeDurationAsGetter(i, unitMillisecondFactors[i]); + makeDurationGetter(i.toLowerCase()); + } + } - local : function () { - this.zone(0); - this._isUTC = false; - return this; - }, + makeDurationAsGetter('Weeks', 6048e5); + moment.duration.fn.asMonths = function () { + return (+this - this.years() * 31536e6) / 2592e6 + this.years() * 12; + }; - format : function (inputString) { - var output = formatMoment(this, inputString || moment.defaultFormat); - return this.lang().postformat(output); - }, - add : function (input, val) { - var dur; - // switch args to support add('s', 1) and add(1, 's') - if (typeof input === 'string') { - dur = moment.duration(+val, input); - } else { - dur = moment.duration(input, val); - } - addOrSubtractDurationFromMoment(this, dur, 1); - return this; - }, + /************************************ + Default Lang + ************************************/ - subtract : function (input, val) { - var dur; - // switch args to support subtract('s', 1) and subtract(1, 's') - if (typeof input === 'string') { - dur = moment.duration(+val, input); - } else { - dur = moment.duration(input, val); - } - addOrSubtractDurationFromMoment(this, dur, -1); - return this; - }, - diff : function (input, units, asFloat) { - var that = makeAs(input, this), - zoneDiff = (this.zone() - that.zone()) * 6e4, - diff, output; + // Set default language, other languages will inherit from English. + moment.lang('en', { + ordinal : function (number) { + var b = number % 10, + output = (toInt(number % 100 / 10) === 1) ? 'th' : + (b === 1) ? 'st' : + (b === 2) ? 'nd' : + (b === 3) ? 'rd' : 'th'; + return number + output; + } + }); - units = normalizeUnits(units); + /* EMBED_LANGUAGES */ - if (units === 'year' || units === 'month') { - // average number of days in the months in the given dates - diff = (this.daysInMonth() + that.daysInMonth()) * 432e5; // 24 * 60 * 60 * 1000 / 2 - // difference in months - output = ((this.year() - that.year()) * 12) + (this.month() - that.month()); - // adjust by taking difference in days, average number of days - // and dst in the given months. - output += ((this - moment(this).startOf('month')) - - (that - moment(that).startOf('month'))) / diff; - // same as above but with zones, to negate all dst - output -= ((this.zone() - moment(this).startOf('month').zone()) - - (that.zone() - moment(that).startOf('month').zone())) * 6e4 / diff; - if (units === 'year') { - output = output / 12; + /************************************ + Exposing Moment + ************************************/ + + function makeGlobal(deprecate) { + var warned = false, local_moment = moment; + /*global ender:false */ + if (typeof ender !== 'undefined') { + return; + } + // here, `this` means `window` in the browser, or `global` on the server + // add `moment` as a global object via a string identifier, + // for Closure Compiler "advanced" mode + if (deprecate) { + global.moment = function () { + if (!warned && console && console.warn) { + warned = true; + console.warn( + "Accessing Moment through the global scope is " + + "deprecated, and will be removed in an upcoming " + + "release."); } - } else { - diff = (this - that); - output = units === 'second' ? diff / 1e3 : // 1000 - units === 'minute' ? diff / 6e4 : // 1000 * 60 - units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60 - units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst - units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst - diff; + return local_moment.apply(null, arguments); + }; + extend(global.moment, local_moment); + } else { + global['moment'] = moment; + } + } + + // CommonJS module is defined + if (hasModule) { + module.exports = moment; + makeGlobal(true); + } else if (typeof define === "function" && define.amd) { + define("moment", function (require, exports, module) { + if (module.config && module.config() && module.config().noGlobal !== true) { + // If user provided noGlobal, he is aware of global + makeGlobal(module.config().noGlobal === undefined); } - return asFloat ? output : absRound(output); - }, - from : function (time, withoutSuffix) { - return moment.duration(this.diff(time)).lang(this.lang()._abbr).humanize(!withoutSuffix); - }, + return moment; + }); + } else { + makeGlobal(); + } +}).call(this); - fromNow : function (withoutSuffix) { - return this.from(moment(), withoutSuffix); - }, +},{}],4:[function(require,module,exports){ +/** + * Copyright 2012 Craig Campbell + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Mousetrap is a simple keyboard shortcut library for Javascript with + * no external dependencies + * + * @version 1.1.2 + * @url craig.is/killing/mice + */ - calendar : function () { - // We want to compare the start of today, vs this. - // Getting start-of-today depends on whether we're zone'd or not. - var sod = makeAs(moment(), this).startOf('day'), - diff = this.diff(sod, 'days', true), - format = diff < -6 ? 'sameElse' : - diff < -1 ? 'lastWeek' : - diff < 0 ? 'lastDay' : - diff < 1 ? 'sameDay' : - diff < 2 ? 'nextDay' : - diff < 7 ? 'nextWeek' : 'sameElse'; - return this.format(this.lang().calendar(format, this)); - }, + /** + * mapping of special keycodes to their corresponding keys + * + * everything in this dictionary cannot use keypress events + * so it has to be here to map to the correct keycodes for + * keyup/keydown events + * + * @type {Object} + */ + var _MAP = { + 8: 'backspace', + 9: 'tab', + 13: 'enter', + 16: 'shift', + 17: 'ctrl', + 18: 'alt', + 20: 'capslock', + 27: 'esc', + 32: 'space', + 33: 'pageup', + 34: 'pagedown', + 35: 'end', + 36: 'home', + 37: 'left', + 38: 'up', + 39: 'right', + 40: 'down', + 45: 'ins', + 46: 'del', + 91: 'meta', + 93: 'meta', + 224: 'meta' + }, - isLeapYear : function () { - return isLeapYear(this.year()); - }, + /** + * mapping for special characters so they can support + * + * this dictionary is only used incase you want to bind a + * keyup or keydown event to one of these keys + * + * @type {Object} + */ + _KEYCODE_MAP = { + 106: '*', + 107: '+', + 109: '-', + 110: '.', + 111 : '/', + 186: ';', + 187: '=', + 188: ',', + 189: '-', + 190: '.', + 191: '/', + 192: '`', + 219: '[', + 220: '\\', + 221: ']', + 222: '\'' + }, - isDST : function () { - return (this.zone() < this.clone().month(0).zone() || - this.zone() < this.clone().month(5).zone()); - }, + /** + * this is a mapping of keys that require shift on a US keypad + * back to the non shift equivelents + * + * this is so you can use keyup events with these keys + * + * note that this will only work reliably on US keyboards + * + * @type {Object} + */ + _SHIFT_MAP = { + '~': '`', + '!': '1', + '@': '2', + '#': '3', + '$': '4', + '%': '5', + '^': '6', + '&': '7', + '*': '8', + '(': '9', + ')': '0', + '_': '-', + '+': '=', + ':': ';', + '\"': '\'', + '<': ',', + '>': '.', + '?': '/', + '|': '\\' + }, - day : function (input) { - var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); - if (input != null) { - input = parseWeekday(input, this.lang()); - return this.add({ d : input - day }); - } else { - return day; - } - }, + /** + * this is a list of special strings you can use to map + * to modifier keys when you specify your keyboard shortcuts + * + * @type {Object} + */ + _SPECIAL_ALIASES = { + 'option': 'alt', + 'command': 'meta', + 'return': 'enter', + 'escape': 'esc' + }, - month : function (input) { - var utc = this._isUTC ? 'UTC' : '', - dayOfMonth; + /** + * variable to store the flipped version of _MAP from above + * needed to check if we should use keypress or not when no action + * is specified + * + * @type {Object|undefined} + */ + _REVERSE_MAP, + + /** + * a list of all the callbacks setup via Mousetrap.bind() + * + * @type {Object} + */ + _callbacks = {}, + + /** + * direct map of string combinations to callbacks used for trigger() + * + * @type {Object} + */ + _direct_map = {}, + + /** + * keeps track of what level each sequence is at since multiple + * sequences can start out with the same sequence + * + * @type {Object} + */ + _sequence_levels = {}, + + /** + * variable to store the setTimeout call + * + * @type {null|number} + */ + _reset_timer, + + /** + * temporary state where we will ignore the next keyup + * + * @type {boolean|string} + */ + _ignore_next_keyup = false, - if (input != null) { - if (typeof input === 'string') { - input = this.lang().monthsParse(input); - if (typeof input !== 'number') { - return this; - } - } + /** + * are we currently inside of a sequence? + * type of action ("keyup" or "keydown" or "keypress") or false + * + * @type {boolean|string} + */ + _inside_sequence = false; - dayOfMonth = this.date(); - this.date(1); - this._d['set' + utc + 'Month'](input); - this.date(Math.min(dayOfMonth, this.daysInMonth())); + /** + * loop through the f keys, f1 to f19 and add them to the map + * programatically + */ + for (var i = 1; i < 20; ++i) { + _MAP[111 + i] = 'f' + i; + } - moment.updateOffset(this); - return this; - } else { - return this._d['get' + utc + 'Month'](); - } - }, + /** + * loop through to map numbers on the numeric keypad + */ + for (i = 0; i <= 9; ++i) { + _MAP[i + 96] = i; + } - startOf: function (units) { - units = normalizeUnits(units); - // the following switch intentionally omits break keywords - // to utilize falling through the cases. - switch (units) { - case 'year': - this.month(0); - /* falls through */ - case 'month': - this.date(1); - /* falls through */ - case 'week': - case 'isoWeek': - case 'day': - this.hours(0); - /* falls through */ - case 'hour': - this.minutes(0); - /* falls through */ - case 'minute': - this.seconds(0); - /* falls through */ - case 'second': - this.milliseconds(0); - /* falls through */ - } + /** + * cross browser add event method + * + * @param {Element|HTMLDocument} object + * @param {string} type + * @param {Function} callback + * @returns void + */ + function _addEvent(object, type, callback) { + if (object.addEventListener) { + return object.addEventListener(type, callback, false); + } - // weeks are a special case - if (units === 'week') { - this.weekday(0); - } else if (units === 'isoWeek') { - this.isoWeekday(1); - } + object.attachEvent('on' + type, callback); + } - return this; - }, + /** + * takes the event and returns the key character + * + * @param {Event} e + * @return {string} + */ + function _characterFromEvent(e) { - endOf: function (units) { - units = normalizeUnits(units); - return this.startOf(units).add((units === 'isoWeek' ? 'week' : units), 1).subtract('ms', 1); - }, + // for keypress events we should return the character as is + if (e.type == 'keypress') { + return String.fromCharCode(e.which); + } - isAfter: function (input, units) { - units = typeof units !== 'undefined' ? units : 'millisecond'; - return +this.clone().startOf(units) > +moment(input).startOf(units); - }, + // for non keypress events the special maps are needed + if (_MAP[e.which]) { + return _MAP[e.which]; + } - isBefore: function (input, units) { - units = typeof units !== 'undefined' ? units : 'millisecond'; - return +this.clone().startOf(units) < +moment(input).startOf(units); - }, + if (_KEYCODE_MAP[e.which]) { + return _KEYCODE_MAP[e.which]; + } - isSame: function (input, units) { - units = units || 'ms'; - return +this.clone().startOf(units) === +makeAs(input, this).startOf(units); - }, + // if it is not in the special map + return String.fromCharCode(e.which).toLowerCase(); + } - min: function (other) { - other = moment.apply(null, arguments); - return other < this ? this : other; - }, + /** + * should we stop this event before firing off callbacks + * + * @param {Event} e + * @return {boolean} + */ + function _stop(e) { + var element = e.target || e.srcElement, + tag_name = element.tagName; - max: function (other) { - other = moment.apply(null, arguments); - return other > this ? this : other; - }, + // if the element has the class "mousetrap" then no need to stop + if ((' ' + element.className + ' ').indexOf(' mousetrap ') > -1) { + return false; + } - zone : function (input) { - var offset = this._offset || 0; - if (input != null) { - if (typeof input === "string") { - input = timezoneMinutesFromString(input); - } - if (Math.abs(input) < 16) { - input = input * 60; - } - this._offset = input; - this._isUTC = true; - if (offset !== input) { - addOrSubtractDurationFromMoment(this, moment.duration(offset - input, 'm'), 1, true); - } - } else { - return this._isUTC ? offset : this._d.getTimezoneOffset(); - } - return this; - }, + // stop for input, select, and textarea + return tag_name == 'INPUT' || tag_name == 'SELECT' || tag_name == 'TEXTAREA' || (element.contentEditable && element.contentEditable == 'true'); + } - zoneAbbr : function () { - return this._isUTC ? "UTC" : ""; - }, + /** + * checks if two arrays are equal + * + * @param {Array} modifiers1 + * @param {Array} modifiers2 + * @returns {boolean} + */ + function _modifiersMatch(modifiers1, modifiers2) { + return modifiers1.sort().join(',') === modifiers2.sort().join(','); + } - zoneName : function () { - return this._isUTC ? "Coordinated Universal Time" : ""; - }, + /** + * resets all sequence counters except for the ones passed in + * + * @param {Object} do_not_reset + * @returns void + */ + function _resetSequences(do_not_reset) { + do_not_reset = do_not_reset || {}; - parseZone : function () { - if (this._tzm) { - this.zone(this._tzm); - } else if (typeof this._i === 'string') { - this.zone(this._i); - } - return this; - }, + var active_sequences = false, + key; - hasAlignedHourOffset : function (input) { - if (!input) { - input = 0; - } - else { - input = moment(input).zone(); - } + for (key in _sequence_levels) { + if (do_not_reset[key]) { + active_sequences = true; + continue; + } + _sequence_levels[key] = 0; + } - return (this.zone() - input) % 60 === 0; - }, + if (!active_sequences) { + _inside_sequence = false; + } + } - daysInMonth : function () { - return daysInMonth(this.year(), this.month()); - }, + /** + * finds all callbacks that match based on the keycode, modifiers, + * and action + * + * @param {string} character + * @param {Array} modifiers + * @param {string} action + * @param {boolean=} remove - should we remove any matches + * @param {string=} combination + * @returns {Array} + */ + function _getMatches(character, modifiers, action, remove, combination) { + var i, + callback, + matches = []; + + // if there are no events related to this keycode + if (!_callbacks[character]) { + return []; + } - dayOfYear : function (input) { - var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1; - return input == null ? dayOfYear : this.add("d", (input - dayOfYear)); - }, + // if a modifier key is coming up on its own we should allow it + if (action == 'keyup' && _isModifier(character)) { + modifiers = [character]; + } - quarter : function () { - return Math.ceil((this.month() + 1.0) / 3.0); - }, + // loop through all callbacks for the key that was pressed + // and see if any of them match + for (i = 0; i < _callbacks[character].length; ++i) { + callback = _callbacks[character][i]; - weekYear : function (input) { - var year = weekOfYear(this, this.lang()._week.dow, this.lang()._week.doy).year; - return input == null ? year : this.add("y", (input - year)); - }, + // if this is a sequence but it is not at the right level + // then move onto the next match + if (callback.seq && _sequence_levels[callback.seq] != callback.level) { + continue; + } - isoWeekYear : function (input) { - var year = weekOfYear(this, 1, 4).year; - return input == null ? year : this.add("y", (input - year)); - }, + // if the action we are looking for doesn't match the action we got + // then we should keep going + if (action != callback.action) { + continue; + } - week : function (input) { - var week = this.lang().week(this); - return input == null ? week : this.add("d", (input - week) * 7); - }, + // if this is a keypress event that means that we need to only + // look at the character, otherwise check the modifiers as + // well + if (action == 'keypress' || _modifiersMatch(modifiers, callback.modifiers)) { - isoWeek : function (input) { - var week = weekOfYear(this, 1, 4).week; - return input == null ? week : this.add("d", (input - week) * 7); - }, + // remove is used so if you change your mind and call bind a + // second time with a new function the first one is overwritten + if (remove && callback.combo == combination) { + _callbacks[character].splice(i, 1); + } - weekday : function (input) { - var weekday = (this.day() + 7 - this.lang()._week.dow) % 7; - return input == null ? weekday : this.add("d", input - weekday); - }, + matches.push(callback); + } + } - isoWeekday : function (input) { - // behaves the same as moment#day except - // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) - // as a setter, sunday should belong to the previous week. - return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7); - }, + return matches; + } - get : function (units) { - units = normalizeUnits(units); - return this[units](); - }, + /** + * takes a key event and figures out what the modifiers are + * + * @param {Event} e + * @returns {Array} + */ + function _eventModifiers(e) { + var modifiers = []; - set : function (units, value) { - units = normalizeUnits(units); - if (typeof this[units] === 'function') { - this[units](value); - } - return this; - }, + if (e.shiftKey) { + modifiers.push('shift'); + } - // If passed a language key, it will set the language for this - // instance. Otherwise, it will return the language configuration - // variables for this instance. - lang : function (key) { - if (key === undefined) { - return this._lang; - } else { - this._lang = getLangDefinition(key); - return this; - } - } - }); + if (e.altKey) { + modifiers.push('alt'); + } - // helper for adding shortcuts - function makeGetterAndSetter(name, key) { - moment.fn[name] = moment.fn[name + 's'] = function (input) { - var utc = this._isUTC ? 'UTC' : ''; - if (input != null) { - this._d['set' + utc + key](input); - moment.updateOffset(this); - return this; - } else { - return this._d['get' + utc + key](); - } - }; - } + if (e.ctrlKey) { + modifiers.push('ctrl'); + } - // loop through and add shortcuts (Month, Date, Hours, Minutes, Seconds, Milliseconds) - for (i = 0; i < proxyGettersAndSetters.length; i ++) { - makeGetterAndSetter(proxyGettersAndSetters[i].toLowerCase().replace(/s$/, ''), proxyGettersAndSetters[i]); - } + if (e.metaKey) { + modifiers.push('meta'); + } - // add shortcut for year (uses different syntax than the getter/setter 'year' == 'FullYear') - makeGetterAndSetter('year', 'FullYear'); + return modifiers; + } + + /** + * actually calls the callback function + * + * if your callback function returns false this will use the jquery + * convention - prevent default and stop propogation on the event + * + * @param {Function} callback + * @param {Event} e + * @returns void + */ + function _fireCallback(callback, e) { + if (callback(e) === false) { + if (e.preventDefault) { + e.preventDefault(); + } - // add plural methods - moment.fn.days = moment.fn.day; - moment.fn.months = moment.fn.month; - moment.fn.weeks = moment.fn.week; - moment.fn.isoWeeks = moment.fn.isoWeek; + if (e.stopPropagation) { + e.stopPropagation(); + } - // add aliased format methods - moment.fn.toJSON = moment.fn.toISOString; + e.returnValue = false; + e.cancelBubble = true; + } + } - /************************************ - Duration Prototype - ************************************/ + /** + * handles a character key event + * + * @param {string} character + * @param {Event} e + * @returns void + */ + function _handleCharacter(character, e) { + // if this event should not happen stop here + if (_stop(e)) { + return; + } - extend(moment.duration.fn = Duration.prototype, { + var callbacks = _getMatches(character, _eventModifiers(e), e.type), + i, + do_not_reset = {}, + processed_sequence_callback = false; + + // loop through matching callbacks for this key event + for (i = 0; i < callbacks.length; ++i) { + + // fire for all sequence callbacks + // this is because if for example you have multiple sequences + // bound such as "g i" and "g t" they both need to fire the + // callback for matching g cause otherwise you can only ever + // match the first one + if (callbacks[i].seq) { + processed_sequence_callback = true; + + // keep a list of which sequences were matches for later + do_not_reset[callbacks[i].seq] = 1; + _fireCallback(callbacks[i].callback, e); + continue; + } - _bubble : function () { - var milliseconds = this._milliseconds, - days = this._days, - months = this._months, - data = this._data, - seconds, minutes, hours, years; + // if there were no sequence matches but we are still here + // that means this is a regular match so we should fire that + if (!processed_sequence_callback && !_inside_sequence) { + _fireCallback(callbacks[i].callback, e); + } + } - // The following code bubbles up values, see the tests for - // examples of what that means. - data.milliseconds = milliseconds % 1000; + // if you are inside of a sequence and the key you are pressing + // is not a modifier key then we should reset all sequences + // that were not matched by this key event + if (e.type == _inside_sequence && !_isModifier(character)) { + _resetSequences(do_not_reset); + } + } - seconds = absRound(milliseconds / 1000); - data.seconds = seconds % 60; + /** + * handles a keydown event + * + * @param {Event} e + * @returns void + */ + function _handleKey(e) { - minutes = absRound(seconds / 60); - data.minutes = minutes % 60; + // normalize e.which for key events + // @see http://stackoverflow.com/questions/4285627/javascript-keycode-vs-charcode-utter-confusion + e.which = typeof e.which == "number" ? e.which : e.keyCode; - hours = absRound(minutes / 60); - data.hours = hours % 24; + var character = _characterFromEvent(e); - days += absRound(hours / 24); - data.days = days % 30; + // no character found then stop + if (!character) { + return; + } - months += absRound(days / 30); - data.months = months % 12; + if (e.type == 'keyup' && _ignore_next_keyup == character) { + _ignore_next_keyup = false; + return; + } - years = absRound(months / 12); - data.years = years; - }, + _handleCharacter(character, e); + } - weeks : function () { - return absRound(this.days() / 7); - }, + /** + * determines if the keycode specified is a modifier key or not + * + * @param {string} key + * @returns {boolean} + */ + function _isModifier(key) { + return key == 'shift' || key == 'ctrl' || key == 'alt' || key == 'meta'; + } - valueOf : function () { - return this._milliseconds + - this._days * 864e5 + - (this._months % 12) * 2592e6 + - toInt(this._months / 12) * 31536e6; - }, + /** + * called to set a 1 second timeout on the specified sequence + * + * this is so after each key press in the sequence you have 1 second + * to press the next key before you have to start over + * + * @returns void + */ + function _resetSequenceTimer() { + clearTimeout(_reset_timer); + _reset_timer = setTimeout(_resetSequences, 1000); + } - humanize : function (withSuffix) { - var difference = +this, - output = relativeTime(difference, !withSuffix, this.lang()); + /** + * reverses the map lookup so that we can look for specific keys + * to see what can and can't use keypress + * + * @return {Object} + */ + function _getReverseMap() { + if (!_REVERSE_MAP) { + _REVERSE_MAP = {}; + for (var key in _MAP) { + + // pull out the numeric keypad from here cause keypress should + // be able to detect the keys from the character + if (key > 95 && key < 112) { + continue; + } + + if (_MAP.hasOwnProperty(key)) { + _REVERSE_MAP[_MAP[key]] = key; + } + } + } + return _REVERSE_MAP; + } - if (withSuffix) { - output = this.lang().pastFuture(difference, output); - } + /** + * picks the best action based on the key combination + * + * @param {string} key - character for key + * @param {Array} modifiers + * @param {string=} action passed in + */ + function _pickBestAction(key, modifiers, action) { - return this.lang().postformat(output); - }, + // if no action was picked in we should try to pick the one + // that we think would work best for this key + if (!action) { + action = _getReverseMap()[key] ? 'keydown' : 'keypress'; + } - add : function (input, val) { - // supports only 2.0-style add(1, 's') or add(moment) - var dur = moment.duration(input, val); + // modifier keys don't work as expected with keypress, + // switch to keydown + if (action == 'keypress' && modifiers.length) { + action = 'keydown'; + } - this._milliseconds += dur._milliseconds; - this._days += dur._days; - this._months += dur._months; + return action; + } - this._bubble(); + /** + * binds a key sequence to an event + * + * @param {string} combo - combo specified in bind call + * @param {Array} keys + * @param {Function} callback + * @param {string=} action + * @returns void + */ + function _bindSequence(combo, keys, callback, action) { - return this; - }, + // start off by adding a sequence level record for this combination + // and setting the level to 0 + _sequence_levels[combo] = 0; - subtract : function (input, val) { - var dur = moment.duration(input, val); + // if there is no action pick the best one for the first key + // in the sequence + if (!action) { + action = _pickBestAction(keys[0], []); + } - this._milliseconds -= dur._milliseconds; - this._days -= dur._days; - this._months -= dur._months; + /** + * callback to increase the sequence level for this sequence and reset + * all other sequences that were active + * + * @param {Event} e + * @returns void + */ + var _increaseSequence = function(e) { + _inside_sequence = action; + ++_sequence_levels[combo]; + _resetSequenceTimer(); + }, + + /** + * wraps the specified callback inside of another function in order + * to reset all sequence counters as soon as this sequence is done + * + * @param {Event} e + * @returns void + */ + _callbackAndReset = function(e) { + _fireCallback(callback, e); + + // we should ignore the next key up if the action is key down + // or keypress. this is so if you finish a sequence and + // release the key the final key will not trigger a keyup + if (action !== 'keyup') { + _ignore_next_keyup = _characterFromEvent(e); + } + + // weird race condition if a sequence ends with the key + // another sequence begins with + setTimeout(_resetSequences, 10); + }, + i; + + // loop through keys one at a time and bind the appropriate callback + // function. for any key leading up to the final one it should + // increase the sequence. after the final, it should reset all sequences + for (i = 0; i < keys.length; ++i) { + _bindSingle(keys[i], i < keys.length - 1 ? _increaseSequence : _callbackAndReset, action, combo, i); + } + } - this._bubble(); + /** + * binds a single keyboard combination + * + * @param {string} combination + * @param {Function} callback + * @param {string=} action + * @param {string=} sequence_name - name of sequence if part of sequence + * @param {number=} level - what part of the sequence the command is + * @returns void + */ + function _bindSingle(combination, callback, action, sequence_name, level) { - return this; - }, + // make sure multiple spaces in a row become a single space + combination = combination.replace(/\s+/g, ' '); - get : function (units) { - units = normalizeUnits(units); - return this[units.toLowerCase() + 's'](); - }, + var sequence = combination.split(' '), + i, + key, + keys, + modifiers = []; - as : function (units) { - units = normalizeUnits(units); - return this['as' + units.charAt(0).toUpperCase() + units.slice(1) + 's'](); - }, + // if this pattern is a sequence of keys then run through this method + // to reprocess each pattern one key at a time + if (sequence.length > 1) { + return _bindSequence(combination, sequence, callback, action); + } - lang : moment.fn.lang, + // take the keys from this pattern and figure out what the actual + // pattern is all about + keys = combination === '+' ? ['+'] : combination.split('+'); - toIsoString : function () { - // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js - var years = Math.abs(this.years()), - months = Math.abs(this.months()), - days = Math.abs(this.days()), - hours = Math.abs(this.hours()), - minutes = Math.abs(this.minutes()), - seconds = Math.abs(this.seconds() + this.milliseconds() / 1000); + for (i = 0; i < keys.length; ++i) { + key = keys[i]; - if (!this.asSeconds()) { - // this is the same as C#'s (Noda) and python (isodate)... - // but not other JS (goog.date) - return 'P0D'; - } + // normalize key names + if (_SPECIAL_ALIASES[key]) { + key = _SPECIAL_ALIASES[key]; + } - return (this.asSeconds() < 0 ? '-' : '') + - 'P' + - (years ? years + 'Y' : '') + - (months ? months + 'M' : '') + - (days ? days + 'D' : '') + - ((hours || minutes || seconds) ? 'T' : '') + - (hours ? hours + 'H' : '') + - (minutes ? minutes + 'M' : '') + - (seconds ? seconds + 'S' : ''); - } - }); + // if this is not a keypress event then we should + // be smart about using shift keys + // this will only work for US keyboards however + if (action && action != 'keypress' && _SHIFT_MAP[key]) { + key = _SHIFT_MAP[key]; + modifiers.push('shift'); + } - function makeDurationGetter(name) { - moment.duration.fn[name] = function () { - return this._data[name]; - }; - } + // if this key is a modifier then add it to the list of modifiers + if (_isModifier(key)) { + modifiers.push(key); + } + } - function makeDurationAsGetter(name, factor) { - moment.duration.fn['as' + name] = function () { - return +this / factor; - }; - } + // depending on what the key combination is + // we will try to pick the best event for it + action = _pickBestAction(key, modifiers, action); - for (i in unitMillisecondFactors) { - if (unitMillisecondFactors.hasOwnProperty(i)) { - makeDurationAsGetter(i, unitMillisecondFactors[i]); - makeDurationGetter(i.toLowerCase()); - } - } + // make sure to initialize array if this is the first time + // a callback is added for this key + if (!_callbacks[key]) { + _callbacks[key] = []; + } - makeDurationAsGetter('Weeks', 6048e5); - moment.duration.fn.asMonths = function () { - return (+this - this.years() * 31536e6) / 2592e6 + this.years() * 12; - }; + // remove an existing match if there is one + _getMatches(key, modifiers, action, !sequence_name, combination); + + // add this call back to the array + // if it is a sequence put it at the beginning + // if not put it at the end + // + // this is important because the way these are processed expects + // the sequence ones to come first + _callbacks[key][sequence_name ? 'unshift' : 'push']({ + callback: callback, + modifiers: modifiers, + action: action, + seq: sequence_name, + level: level, + combo: combination + }); + } + /** + * binds multiple combinations to the same callback + * + * @param {Array} combinations + * @param {Function} callback + * @param {string|undefined} action + * @returns void + */ + function _bindMultiple(combinations, callback, action) { + for (var i = 0; i < combinations.length; ++i) { + _bindSingle(combinations[i], callback, action); + } + } - /************************************ - Default Lang - ************************************/ + // start! + _addEvent(document, 'keypress', _handleKey); + _addEvent(document, 'keydown', _handleKey); + _addEvent(document, 'keyup', _handleKey); + var mousetrap = { - // Set default language, other languages will inherit from English. - moment.lang('en', { - ordinal : function (number) { - var b = number % 10, - output = (toInt(number % 100 / 10) === 1) ? 'th' : - (b === 1) ? 'st' : - (b === 2) ? 'nd' : - (b === 3) ? 'rd' : 'th'; - return number + output; - } - }); + /** + * binds an event to mousetrap + * + * can be a single key, a combination of keys separated with +, + * a comma separated list of keys, an array of keys, or + * a sequence of keys separated by spaces + * + * be sure to list the modifier keys first to make sure that the + * correct key ends up getting bound (the last key in the pattern) + * + * @param {string|Array} keys + * @param {Function} callback + * @param {string=} action - 'keypress', 'keydown', or 'keyup' + * @returns void + */ + bind: function(keys, callback, action) { + _bindMultiple(keys instanceof Array ? keys : [keys], callback, action); + _direct_map[keys + ':' + action] = callback; + return this; + }, - /* EMBED_LANGUAGES */ + /** + * unbinds an event to mousetrap + * + * the unbinding sets the callback function of the specified key combo + * to an empty function and deletes the corresponding key in the + * _direct_map dict. + * + * the keycombo+action has to be exactly the same as + * it was defined in the bind method + * + * TODO: actually remove this from the _callbacks dictionary instead + * of binding an empty function + * + * @param {string|Array} keys + * @param {string} action + * @returns void + */ + unbind: function(keys, action) { + if (_direct_map[keys + ':' + action]) { + delete _direct_map[keys + ':' + action]; + this.bind(keys, function() {}, action); + } + return this; + }, - /************************************ - Exposing Moment - ************************************/ + /** + * triggers an event that has already been bound + * + * @param {string} keys + * @param {string=} action + * @returns void + */ + trigger: function(keys, action) { + _direct_map[keys + ':' + action](); + return this; + }, - function makeGlobal(deprecate) { - var warned = false, local_moment = moment; - /*global ender:false */ - if (typeof ender !== 'undefined') { - return; - } - // here, `this` means `window` in the browser, or `global` on the server - // add `moment` as a global object via a string identifier, - // for Closure Compiler "advanced" mode - if (deprecate) { - global.moment = function () { - if (!warned && console && console.warn) { - warned = true; - console.warn( - "Accessing Moment through the global scope is " + - "deprecated, and will be removed in an upcoming " + - "release."); - } - return local_moment.apply(null, arguments); - }; - extend(global.moment, local_moment); - } else { - global['moment'] = moment; - } - } + /** + * resets the library back to its initial state. this is useful + * if you want to clear out the current keyboard shortcuts and bind + * new ones - for example if you switch to another page + * + * @returns void + */ + reset: function() { + _callbacks = {}; + _direct_map = {}; + return this; + } + }; - // CommonJS module is defined - if (hasModule) { - module.exports = moment; - makeGlobal(true); - } else if (typeof define === "function" && define.amd) { - define("moment", function (require, exports, module) { - if (module.config && module.config() && module.config().noGlobal !== true) { - // If user provided noGlobal, he is aware of global - makeGlobal(module.config().noGlobal === undefined); - } +module.exports = mousetrap; - return moment; - }); - } else { - makeGlobal(); - } -}).call(this); },{}]},{},[1]) (1) diff --git a/dist/vis.min.js b/dist/vis.min.js index 8ca53878..083f0f1f 100644 --- a/dist/vis.min.js +++ b/dist/vis.min.js @@ -4,11 +4,11 @@ * * A dynamic, browser-based visualization library. * - * @version 0.3.0 - * @date 2014-01-14 + * @version 0.4.0 + * @date 2014-01-31 * * @license - * Copyright (C) 2011-2013 Almende B.V, http://almende.com + * Copyright (C) 2011-2014 Almende B.V, http://almende.com * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -22,8 +22,10 @@ * License for the specific language governing permissions and limitations under * the License. */ -!function(t){if("object"==typeof exports)module.exports=t();else if("function"==typeof define&&define.amd)define(t);else{var e;"undefined"!=typeof window?e=window:"undefined"!=typeof global?e=global:"undefined"!=typeof self&&(e=self),e.vis=t()}}(function(){var t;return function e(t,i,n){function s(o,a){if(!i[o]){if(!t[o]){var h="function"==typeof require&&require;if(!a&&h)return h(o,!0);if(r)return r(o,!0);throw new Error("Cannot find module '"+o+"'")}var d=i[o]={exports:{}};t[o][0].call(d.exports,function(e){var i=t[o][1][e];return s(i?i:e)},d,d.exports,e,t,i,n)}return i[o].exports}for(var r="function"==typeof require&&require,o=0;oi;++i)t.call(e||this,this[i],i,this)}),Array.prototype.map||(Array.prototype.map=function(t,e){var i,n,s;if(null==this)throw new TypeError(" this is null or not defined");var r=Object(this),o=r.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(e&&(i=e),n=new Array(o),s=0;o>s;){var a,h;s in r&&(a=r[s],h=t.call(i,a,s,r),n[s]=h),s++}return n}),Array.prototype.filter||(Array.prototype.filter=function(t){"use strict";if(null==this)throw new TypeError;var e=Object(this),i=e.length>>>0;if("function"!=typeof t)throw new TypeError;for(var n=[],s=arguments[1],r=0;i>r;r++)if(r in e){var o=e[r];t.call(s,o,r,e)&&n.push(o)}return n}),Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,e=!{toString:null}.propertyIsEnumerable("toString"),i=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],n=i.length;return function(s){if("object"!=typeof s&&"function"!=typeof s||null===s)throw new TypeError("Object.keys called on non-object");var r=[];for(var o in s)t.call(s,o)&&r.push(o);if(e)for(var a=0;n>a;a++)t.call(s,i[a])&&r.push(i[a]);return r}}()),Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s}),Object.create||(Object.create=function(t){function e(){}if(arguments.length>1)throw new Error("Object.create implementation only accepts the first parameter.");return e.prototype=t,new e}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s});var A={};A.isNumber=function(t){return t instanceof Number||"number"==typeof t},A.isString=function(t){return t instanceof String||"string"==typeof t},A.isDate=function(t){if(t instanceof Date)return!0;if(A.isString(t)){var e=P.exec(t);if(e)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},A.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},A.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},A.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var n=arguments[e];for(var s in n)n.hasOwnProperty(s)&&void 0!==n[s]&&(t[s]=n[s])}return t},A.convert=function(t,e){var i;if(void 0===t)return void 0;if(null===t)return null;if(!e)return t;if("string"!=typeof e&&!(e instanceof String))throw new Error("Type must be a string");switch(e){case"boolean":case"Boolean":return Boolean(t);case"number":case"Number":return Number(t.valueOf());case"string":case"String":return String(t);case"Date":if(A.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(I.isMoment(t))return new Date(t.valueOf());if(A.isString(t))return i=P.exec(t),i?new Date(Number(i[1])):I(t).toDate();throw new Error("Cannot convert object of type "+A.getType(t)+" to type Date");case"Moment":if(A.isNumber(t))return I(t);if(t instanceof Date)return I(t.valueOf());if(I.isMoment(t))return I(t);if(A.isString(t))return i=P.exec(t),i?I(Number(i[1])):I(t);throw new Error("Cannot convert object of type "+A.getType(t)+" to type Date");case"ISODate":if(A.isNumber(t))return new Date(t);if(t instanceof Date)return t.toISOString();if(I.isMoment(t))return t.toDate().toISOString();if(A.isString(t))return i=P.exec(t),i?new Date(Number(i[1])).toISOString():new Date(t).toISOString();throw new Error("Cannot convert object of type "+A.getType(t)+" to type ISODate");case"ASPDate":if(A.isNumber(t))return"/Date("+t+")/";if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(A.isString(t)){i=P.exec(t);var n;return n=i?new Date(Number(i[1])).valueOf():new Date(t).valueOf(),"/Date("+n+")/"}throw new Error("Cannot convert object of type "+A.getType(t)+" to type ASPDate");default:throw new Error("Cannot convert object of type "+A.getType(t)+' to type "'+e+'"')}};var P=/^\/?Date\((\-?\d+)/i;A.getType=function(t){var e=typeof t;return"object"==e?null==t?"null":t instanceof Boolean?"Boolean":t instanceof Number?"Number":t instanceof String?"String":t instanceof Array?"Array":t instanceof Date?"Date":"Object":"number"==e?"Number":"boolean"==e?"Boolean":"string"==e?"String":e},A.getAbsoluteLeft=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetLeft,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetLeft,n-=s.scrollLeft,s=s.offsetParent;return n},A.getAbsoluteTop=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetTop,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetTop,n-=s.scrollTop,s=s.offsetParent;return n},A.getPageY=function(t){if("pageY"in t)return t.pageY;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientY:t.clientY;var i=document.documentElement,n=document.body;return e+(i&&i.scrollTop||n&&n.scrollTop||0)-(i&&i.clientTop||n&&n.clientTop||0)},A.getPageX=function(t){if("pageY"in t)return t.pageX;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientX:t.clientX;var i=document.documentElement,n=document.body;return e+(i&&i.scrollLeft||n&&n.scrollLeft||0)-(i&&i.clientLeft||n&&n.clientLeft||0)},A.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},A.removeClassName=function(t,e){var i=t.className.split(" "),n=i.indexOf(e);-1!=n&&(i.splice(n,1),t.className=i.join(" "))},A.forEach=function(t,e){var i,n;if(t instanceof Array)for(i=0,n=t.length;n>i;i++)e(t[i],i,t);else for(i in t)t.hasOwnProperty(i)&&e(t[i],i,t)},A.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},A.addEventListener=function(t,e,i,n){t.addEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.addEventListener(e,i,n)):t.attachEvent("on"+e,i)},A.removeEventListener=function(t,e,i,n){t.removeEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.removeEventListener(e,i,n)):t.detachEvent("on"+e,i)},A.getTarget=function(t){t||(t=window.event);var e;return t.target?e=t.target:t.srcElement&&(e=t.srcElement),void 0!=e.nodeType&&3==e.nodeType&&(e=e.parentNode),e},A.stopPropagation=function(t){t||(t=window.event),t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},A.fakeGesture=function(t,e){var i=null;return L.event.collectEventData(this,i,e)},A.preventDefault=function(t){t||(t=window.event),t.preventDefault?t.preventDefault():t.returnValue=!1},A.option={},A.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},A.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},A.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?String(t):e||null},A.option.asSize=function(t,e){return"function"==typeof t&&(t=t()),A.isString(t)?t:A.isNumber(t)?t+"px":e||null},A.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null};var Y={listeners:[],indexOf:function(t){for(var e=this.listeners,i=0,n=this.listeners.length;n>i;i++){var s=e[i];if(s&&s.object==t)return i}return-1},addListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];s||(s={object:t,events:{}},this.listeners.push(s));var r=s.events[e];r||(r=[],s.events[e]=r),-1==r.indexOf(i)&&r.push(i)},removeListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var r=s.events[e];r&&(n=r.indexOf(i),-1!=n&&r.splice(n,1),0==r.length&&delete s.events[e]);var o=0,a=s.events;for(var h in a)a.hasOwnProperty(h)&&o++;0==o&&delete this.listeners[n]}},removeAllListeners:function(){this.listeners=[]},trigger:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var r=s.events[e];if(r)for(var o=0,a=r.length;a>o;o++)r[o](i)}}};s.prototype.on=function(t,e,i){var n=t instanceof RegExp?t:new RegExp(t.replace("*","\\w+")),s={id:A.randomUUID(),event:t,regexp:n,callback:"function"==typeof e?e:null,target:i};return this.subscriptions.push(s),s.id},s.prototype.off=function(t){for(var e=0;er;r++)i=s._addItem(t[r]),n.push(i);else if(A.isDataTable(t))for(var a=this._getColumnNames(t),h=0,d=t.getNumberOfRows();d>h;h++){for(var c={},u=0,l=a.length;l>u;u++){var p=a[u];c[p]=t.getValue(h,u)}i=s._addItem(c),n.push(i)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");i=s._addItem(t),n.push(i)}return n.length&&this._trigger("add",{items:n},e),n},r.prototype.update=function(t,e){var i=[],n=[],s=this,r=s.fieldId,o=function(t){var e=t[r];s.data[e]?(e=s._updateItem(t),n.push(e)):(e=s._addItem(t),i.push(e))};if(t instanceof Array)for(var a=0,h=t.length;h>a;a++)o(t[a]);else if(A.isDataTable(t))for(var d=this._getColumnNames(t),c=0,u=t.getNumberOfRows();u>c;c++){for(var l={},p=0,f=d.length;f>p;p++){var m=d[p];l[m]=t.getValue(c,p)}o(l)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");o(t)}return i.length&&this._trigger("add",{items:i},e),n.length&&this._trigger("update",{items:n},e),i.concat(n)},r.prototype.get=function(){var t,e,i,n,s=this,r=A.getType(arguments[0]);"String"==r||"Number"==r?(t=arguments[0],i=arguments[1],n=arguments[2]):"Array"==r?(e=arguments[0],i=arguments[1],n=arguments[2]):(i=arguments[0],n=arguments[1]);var o;if(i&&i.type){if(o="DataTable"==i.type?"DataTable":"Array",n&&o!=A.getType(n))throw new Error('Type of parameter "data" ('+A.getType(n)+") does not correspond with specified options.type ("+i.type+")");if("DataTable"==o&&!A.isDataTable(n))throw new Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else o=n?"DataTable"==A.getType(n)?"DataTable":"Array":"Array";var a,h,d,c,u=i&&i.convert||this.options.convert,l=i&&i.filter,p=[];if(void 0!=t)a=s._getItem(t,u),l&&!l(a)&&(a=null);else if(void 0!=e)for(d=0,c=e.length;c>d;d++)a=s._getItem(e[d],u),(!l||l(a))&&p.push(a);else for(h in this.data)this.data.hasOwnProperty(h)&&(a=s._getItem(h,u),(!l||l(a))&&p.push(a));if(i&&i.order&&void 0==t&&this._sort(p,i.order),i&&i.fields){var f=i.fields;if(void 0!=t)a=this._filterFields(a,f);else for(d=0,c=p.length;c>d;d++)p[d]=this._filterFields(p[d],f)}if("DataTable"==o){var m=this._getColumnNames(n);if(void 0!=t)s._appendRow(n,m,a);else for(d=0,c=p.length;c>d;d++)s._appendRow(n,m,p[d]);return n}if(void 0!=t)return a;if(n){for(d=0,c=p.length;c>d;d++)n.push(p[d]);return n}return p},r.prototype.getIds=function(t){var e,i,n,s,r,o=this.data,a=t&&t.filter,h=t&&t.order,d=t&&t.convert||this.options.convert,c=[];if(a)if(h){r=[];for(n in o)o.hasOwnProperty(n)&&(s=this._getItem(n,d),a(s)&&r.push(s));for(this._sort(r,h),e=0,i=r.length;i>e;e++)c[e]=r[e][this.fieldId]}else for(n in o)o.hasOwnProperty(n)&&(s=this._getItem(n,d),a(s)&&c.push(s[this.fieldId]));else if(h){r=[];for(n in o)o.hasOwnProperty(n)&&r.push(o[n]);for(this._sort(r,h),e=0,i=r.length;i>e;e++)c[e]=r[e][this.fieldId]}else for(n in o)o.hasOwnProperty(n)&&(s=o[n],c.push(s[this.fieldId]));return c},r.prototype.forEach=function(t,e){var i,n,s=e&&e.filter,r=e&&e.convert||this.options.convert,o=this.data;if(e&&e.order)for(var a=this.get(e),h=0,d=a.length;d>h;h++)i=a[h],n=i[this.fieldId],t(i,n);else for(n in o)o.hasOwnProperty(n)&&(i=this._getItem(n,r),(!s||s(i))&&t(i,n))},r.prototype.map=function(t,e){var i,n=e&&e.filter,s=e&&e.convert||this.options.convert,r=[],o=this.data;for(var a in o)o.hasOwnProperty(a)&&(i=this._getItem(a,s),(!n||n(i))&&r.push(t(i,a)));return e&&e.order&&this._sort(r,e.order),r},r.prototype._filterFields=function(t,e){var i={};for(var n in t)t.hasOwnProperty(n)&&-1!=e.indexOf(n)&&(i[n]=t[n]);return i},r.prototype._sort=function(t,e){if(A.isString(e)){var i=e;t.sort(function(t,e){var n=t[i],s=e[i];return n>s?1:s>n?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},r.prototype.remove=function(t,e){var i,n,s,r=[];if(t instanceof Array)for(i=0,n=t.length;n>i;i++)s=this._remove(t[i]),null!=s&&r.push(s);else s=this._remove(t),null!=s&&r.push(s);return r.length&&this._trigger("remove",{items:r},e),r},r.prototype._remove=function(t){if(A.isNumber(t)||A.isString(t)){if(this.data[t])return delete this.data[t],delete this.internalIds[t],t}else if(t instanceof Object){var e=t[this.fieldId];if(e&&this.data[e])return delete this.data[e],delete this.internalIds[e],e}return null},r.prototype.clear=function(t){var e=Object.keys(this.data);return this.data={},this.internalIds={},this._trigger("remove",{items:e},t),e},r.prototype.max=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var r=e[s],o=r[t];null!=o&&(!i||o>n)&&(i=r,n=o)}return i},r.prototype.min=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var r=e[s],o=r[t];null!=o&&(!i||n>o)&&(i=r,n=o)}return i},r.prototype.distinct=function(t){var e=this.data,i=[],n=this.options.convert[t],s=0;for(var r in e)if(e.hasOwnProperty(r)){for(var o=e[r],a=A.convert(o[t],n),h=!1,d=0;s>d;d++)if(i[d]==a){h=!0;break}h||(i[s]=a,s++)}return i},r.prototype._addItem=function(t){var e=t[this.fieldId];if(void 0!=e){if(this.data[e])throw new Error("Cannot add item: item with id "+e+" already exists")}else e=A.randomUUID(),t[this.fieldId]=e,this.internalIds[e]=t;var i={};for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=A.convert(t[n],s)}return this.data[e]=i,e},r.prototype._getItem=function(t,e){var i,n,s=this.data[t];if(!s)return null;var r={},o=this.fieldId,a=this.internalIds;if(e)for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==o&&n in a||(r[i]=A.convert(n,e[i])));else for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==o&&n in a||(r[i]=n));return r},r.prototype._updateItem=function(t){var e=t[this.fieldId];if(void 0==e)throw new Error("Cannot update item: item has no id (item: "+JSON.stringify(t)+")");var i=this.data[e];if(!i)throw new Error("Cannot update item: no item with id "+e+" found");for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=A.convert(t[n],s)}return e},r.prototype._getColumnNames=function(t){for(var e=[],i=0,n=t.getNumberOfColumns();n>i;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},r.prototype._appendRow=function(t,e,i){for(var n=t.addRow(),s=0,r=e.length;r>s;s++){var o=e[s];t.setValue(n,s,i[o])}},o.prototype.setData=function(t){var e,i,n;if(this.data){this.data.unsubscribe&&this.data.unsubscribe("*",this.listener),e=[];for(var s in this.ids)this.ids.hasOwnProperty(s)&&e.push(s);this.ids={},this._trigger("remove",{items:e})}if(this.data=t,this.data){for(this.fieldId=this.options.fieldId||this.data&&this.data.options&&this.data.options.fieldId||"id",e=this.data.getIds({filter:this.options&&this.options.filter}),i=0,n=e.length;n>i;i++)s=e[i],this.ids[s]=!0;this._trigger("add",{items:e}),this.data.subscribe&&this.data.subscribe("*",this.listener)}},o.prototype.get=function(){var t,e,i,n=this,s=A.getType(arguments[0]);"String"==s||"Number"==s||"Array"==s?(t=arguments[0],e=arguments[1],i=arguments[2]):(e=arguments[0],i=arguments[1]);var r=A.extend({},this.options,e);this.options.filter&&e&&e.filter&&(r.filter=function(t){return n.options.filter(t)&&e.filter(t)});var o=[];return void 0!=t&&o.push(t),o.push(r),o.push(i),this.data&&this.data.get.apply(this.data,o)},o.prototype.getIds=function(t){var e;if(this.data){var i,n=this.options.filter;i=t&&t.filter?n?function(e){return n(e)&&t.filter(e)}:t.filter:n,e=this.data.getIds({filter:i,order:t&&t.order})}else e=[];return e},o.prototype._onEvent=function(t,e,i){var n,s,r,o,a=e&&e.items,h=this.data,d=[],c=[],u=[];if(a&&h){switch(t){case"add":for(n=0,s=a.length;s>n;n++)r=a[n],o=this.get(r),o&&(this.ids[r]=!0,d.push(r));break;case"update":for(n=0,s=a.length;s>n;n++)r=a[n],o=this.get(r),o?this.ids[r]?c.push(r):(this.ids[r]=!0,d.push(r)):this.ids[r]&&(delete this.ids[r],u.push(r));break;case"remove":for(n=0,s=a.length;s>n;n++)r=a[n],this.ids[r]&&(delete this.ids[r],u.push(r))}d.length&&this._trigger("add",{items:d},i),c.length&&this._trigger("update",{items:c},i),u.length&&this._trigger("remove",{items:u},i)}},o.prototype.subscribe=r.prototype.subscribe,o.prototype.unsubscribe=r.prototype.unsubscribe,o.prototype._trigger=r.prototype._trigger,TimeStep=function(t,e,i){this.current=new Date,this._start=new Date,this._end=new Date,this.autoScale=!0,this.scale=TimeStep.SCALE.DAY,this.step=1,this.setRange(t,e,i)},TimeStep.SCALE={MILLISECOND:1,SECOND:2,MINUTE:3,HOUR:4,DAY:5,WEEKDAY:6,MONTH:7,YEAR:8},TimeStep.prototype.setRange=function(t,e,i){if(!(t instanceof Date&&e instanceof Date))throw"No legal start or end date in method setRange";this._start=void 0!=t?new Date(t.valueOf()):new Date,this._end=void 0!=e?new Date(e.valueOf()):new Date,this.autoScale&&this.setMinimumStep(i)},TimeStep.prototype.first=function(){this.current=new Date(this._start.valueOf()),this.roundToMinor()},TimeStep.prototype.roundToMinor=function(){switch(this.scale){case TimeStep.SCALE.YEAR:this.current.setFullYear(this.step*Math.floor(this.current.getFullYear()/this.step)),this.current.setMonth(0);case TimeStep.SCALE.MONTH:this.current.setDate(1);case TimeStep.SCALE.DAY:case TimeStep.SCALE.WEEKDAY:this.current.setHours(0);case TimeStep.SCALE.HOUR:this.current.setMinutes(0);case TimeStep.SCALE.MINUTE:this.current.setSeconds(0);case TimeStep.SCALE.SECOND:this.current.setMilliseconds(0)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.setMilliseconds(this.current.getMilliseconds()-this.current.getMilliseconds()%this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()-this.current.getSeconds()%this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()-this.current.getMinutes()%this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()-this.current.getHours()%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()-1-(this.current.getDate()-1)%this.step+1);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()-this.current.getMonth()%this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()-this.current.getFullYear()%this.step)}},TimeStep.prototype.hasNext=function(){return this.current.valueOf()<=this._end.valueOf()},TimeStep.prototype.next=function(){var t=this.current.valueOf();if(this.current.getMonth()<6)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current=new Date(this.current.valueOf()+1e3*this.step);break;case TimeStep.SCALE.MINUTE:this.current=new Date(this.current.valueOf()+1e3*this.step*60);break;case TimeStep.SCALE.HOUR:this.current=new Date(this.current.valueOf()+1e3*this.step*60*60);var e=this.current.getHours();this.current.setHours(e-e%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}else switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()+this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()+this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()+this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.getMilliseconds()0&&(this.step=e),this.autoScale=!1},TimeStep.prototype.setAutoScale=function(t){this.autoScale=t},TimeStep.prototype.setMinimumStep=function(t){if(void 0!=t){var e=31104e6,i=2592e6,n=864e5,s=36e5,r=6e4,o=1e3,a=1;1e3*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1e3),500*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=500),100*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=100),50*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=50),10*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=10),5*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=5),e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1),3*i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=3),i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=1),5*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=5),2*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=2),n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=1),n/2>t&&(this.scale=TimeStep.SCALE.WEEKDAY,this.step=1),4*s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=4),s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=1),15*r>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=15),10*r>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=10),5*r>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=5),r>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=1),15*o>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=15),10*o>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=10),5*o>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=5),o>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=1),200*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=200),100*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=100),50*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=50),10*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=10),5*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=5),a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=1)}},TimeStep.prototype.snap=function(t){if(this.scale==TimeStep.SCALE.YEAR){var e=t.getFullYear()+Math.round(t.getMonth()/12);t.setFullYear(Math.round(e/this.step)*this.step),t.setMonth(0),t.setDate(0),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MONTH)t.getDate()>15?(t.setDate(1),t.setMonth(t.getMonth()+1)):t.setDate(1),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0);else if(this.scale==TimeStep.SCALE.DAY||this.scale==TimeStep.SCALE.WEEKDAY){switch(this.step){case 5:case 2:t.setHours(24*Math.round(t.getHours()/24));break;default:t.setHours(12*Math.round(t.getHours()/12))}t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.HOUR){switch(this.step){case 4:t.setMinutes(60*Math.round(t.getMinutes()/60));break;default:t.setMinutes(30*Math.round(t.getMinutes()/30))}t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MINUTE){switch(this.step){case 15:case 10:t.setMinutes(5*Math.round(t.getMinutes()/5)),t.setSeconds(0);break;case 5:t.setSeconds(60*Math.round(t.getSeconds()/60));break;default:t.setSeconds(30*Math.round(t.getSeconds()/30))}t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.SECOND)switch(this.step){case 15:case 10:t.setSeconds(5*Math.round(t.getSeconds()/5)),t.setMilliseconds(0);break;case 5:t.setMilliseconds(1e3*Math.round(t.getMilliseconds()/1e3));break;default:t.setMilliseconds(500*Math.round(t.getMilliseconds()/500))}else if(this.scale==TimeStep.SCALE.MILLISECOND){var i=this.step>5?this.step/2:1;t.setMilliseconds(Math.round(t.getMilliseconds()/i)*i)}},TimeStep.prototype.isMajor=function(){switch(this.scale){case TimeStep.SCALE.MILLISECOND:return 0==this.current.getMilliseconds();case TimeStep.SCALE.SECOND:return 0==this.current.getSeconds();case TimeStep.SCALE.MINUTE:return 0==this.current.getHours()&&0==this.current.getMinutes();case TimeStep.SCALE.HOUR:return 0==this.current.getHours();case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return 1==this.current.getDate();case TimeStep.SCALE.MONTH:return 0==this.current.getMonth();case TimeStep.SCALE.YEAR:return!1;default:return!1}},TimeStep.prototype.getLabelMinor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return I(t).format("SSS");case TimeStep.SCALE.SECOND:return I(t).format("s");case TimeStep.SCALE.MINUTE:return I(t).format("HH:mm");case TimeStep.SCALE.HOUR:return I(t).format("HH:mm");case TimeStep.SCALE.WEEKDAY:return I(t).format("ddd D");case TimeStep.SCALE.DAY:return I(t).format("D");case TimeStep.SCALE.MONTH:return I(t).format("MMM");case TimeStep.SCALE.YEAR:return I(t).format("YYYY");default:return""}},TimeStep.prototype.getLabelMajor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return I(t).format("HH:mm:ss");case TimeStep.SCALE.SECOND:return I(t).format("D MMMM HH:mm");case TimeStep.SCALE.MINUTE:case TimeStep.SCALE.HOUR:return I(t).format("ddd D MMMM");case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return I(t).format("MMMM YYYY");case TimeStep.SCALE.MONTH:return I(t).format("YYYY");case TimeStep.SCALE.YEAR:return"";default:return""}},a.prototype.setOptions=function(t){A.extend(this.options,t)},a.prototype.update=function(){this._order(),this._stack()},a.prototype._order=function(){var t=this.parent.items;if(!t)throw new Error("Cannot stack items: parent does not contain items");var e=[],i=0;A.forEach(t,function(t){t.visible&&(e[i]=t,i++)});var n=this.options.order||this.defaultOptions.order;if("function"!=typeof n)throw new Error("Option order must be a function");e.sort(n),this.ordered=e},a.prototype._stack=function(){var t,e,i,n=this.ordered,s=this.options,r=s.orientation||this.defaultOptions.orientation,o="top"==r;for(i=s.margin&&void 0!==s.margin.item?s.margin.item:this.defaultOptions.margin.item,t=0,e=n.length;e>t;t++){var a=n[t],h=null;do h=this.checkOverlap(n,t,0,t-1,i),null!=h&&(a.top=o?h.top+h.height+i:h.top-a.height-i);while(h)}},a.prototype.checkOverlap=function(t,e,i,n,s){for(var r=this.collision,o=t[e],a=n;a>=i;a--){var h=t[a];if(r(o,h,s)&&a!=e)return h}return null},a.prototype.collision=function(t,e,i){return t.left-ie.left&&t.top-ie.top},h.prototype.setOptions=function(t){A.extend(this.options,t),null!==this.start&&null!==this.end&&this.setRange(this.start,this.end)},h.prototype.subscribe=function(t,e,i){function n(e){s._onMouseWheel(e,t,i)}var s=this;if("move"==e)t.on("dragstart",function(e){s._onDragStart(e,t)}),t.on("drag",function(e){s._onDrag(e,t,i)}),t.on("dragend",function(e){s._onDragEnd(e,t)});else{if("zoom"!=e)throw new TypeError('Unknown event "'+e+'". Choose "move" or "zoom".');t.on("mousewheel",n),t.on("DOMMouseScroll",n),t.on("touch",function(){s._onTouch()}),t.on("pinch",function(e){s._onPinch(e,t,i)})}},h.prototype.on=function(t,e){Y.addListener(this,t,e)},h.prototype._trigger=function(t){Y.trigger(this,t,{start:this.start,end:this.end})},h.prototype.setRange=function(t,e){var i=this._applyRange(t,e);i&&(this._trigger("rangechange"),this._trigger("rangechanged"))},h.prototype._applyRange=function(t,e){var i,n=null!=t?A.convert(t,"Number"):this.start,s=null!=e?A.convert(e,"Number"):this.end,r=null!=this.options.max?A.convert(this.options.max,"Date").valueOf():null,o=null!=this.options.min?A.convert(this.options.min,"Date").valueOf():null;if(isNaN(n)||null===n)throw new Error('Invalid start "'+t+'"');if(isNaN(s)||null===s)throw new Error('Invalid end "'+e+'"');if(n>s&&(s=n),null!==o&&o>n&&(i=o-n,n+=i,s+=i,null!=r&&s>r&&(s=r)),null!==r&&s>r&&(i=s-r,n-=i,s-=i,null!=o&&o>n&&(n=o)),null!==this.options.zoomMin){var a=parseFloat(this.options.zoomMin);0>a&&(a=0),a>s-n&&(this.end-this.start===a?(n=this.start,s=this.end):(i=a-(s-n),n-=i/2,s+=i/2))}if(null!==this.options.zoomMax){var h=parseFloat(this.options.zoomMax);0>h&&(h=0),s-n>h&&(this.end-this.start===h?(n=this.start,s=this.end):(i=s-n-h,n+=i/2,s-=i/2))}var d=this.start!=n||this.end!=s;return this.start=n,this.end=s,d},h.prototype.getRange=function(){return{start:this.start,end:this.end}},h.prototype.conversion=function(t){return h.conversion(this.start,this.end,t)},h.conversion=function(t,e,i){return 0!=i&&e-t!=0?{offset:t,scale:i/(e-t)}:{offset:0,scale:1}};var F={};h.prototype._onDragStart=function(t,e){if(!F.pinching){F.start=this.start,F.end=this.end;var i=e.frame;i&&(i.style.cursor="move")}},h.prototype._onDrag=function(t,e,i){if(d(i),!F.pinching){var n="horizontal"==i?t.gesture.deltaX:t.gesture.deltaY,s=F.end-F.start,r="horizontal"==i?e.width:e.height,o=-n/r*s;this._applyRange(F.start+o,F.end+o),this._trigger("rangechange")}},h.prototype._onDragEnd=function(t,e){F.pinching||(e.frame&&(e.frame.style.cursor="auto"),this._trigger("rangechanged"))},h.prototype._onMouseWheel=function(t,e,i){d(i);var n=0;if(t.wheelDelta?n=t.wheelDelta/120:t.detail&&(n=-t.detail/3),n){var s;s=0>n?1-n/5:1/(1+n/5);var r=A.fakeGesture(this,t),o=c(r.touches[0],e.frame),a=this._pointerToDate(e,i,o);this.zoom(s,a)}A.preventDefault(t)},h.prototype._onTouch=function(){F.start=this.start,F.end=this.end,F.pinching=!1,F.center=null},h.prototype._onPinch=function(t,e,i){if(F.pinching=!0,t.gesture.touches.length>1){F.center||(F.center=c(t.gesture.center,e.frame));var n=1/t.gesture.scale,s=this._pointerToDate(e,i,F.center),r=c(t.gesture.center,e.frame),o=(this._pointerToDate(e,i,r),parseInt(s+(F.start-s)*n)),a=parseInt(s+(F.end-s)*n);this.setRange(o,a)}},h.prototype._pointerToDate=function(t,e,i){var n;if("horizontal"==e){var s=t.width;return n=this.conversion(s),i.x/n.scale+n.offset}var r=t.height;return n=this.conversion(r),i.y/n.scale+n.offset},h.prototype.zoom=function(t,e){null==e&&(e=(this.start+this.end)/2);var i=e+(this.start-e)*t,n=e+(this.end-e)*t;this.setRange(i,n)},h.prototype.move=function(t){var e=this.end-this.start,i=this.start+e*t,n=this.end+e*t;this.start=i,this.end=n},h.prototype.moveTo=function(t){var e=(this.start+this.end)/2,i=e-t,n=this.start-i,s=this.end-i;this.setRange(n,s)},u.prototype.add=function(t){if(void 0==t.id)throw new Error("Component has no field id");if(!(t instanceof l||t instanceof u))throw new TypeError("Component must be an instance of prototype Component or Controller");t.controller=this,this.components[t.id]=t},u.prototype.remove=function(t){var e;for(e in this.components)if(this.components.hasOwnProperty(e)&&(e==t||this.components[e]==t))break;e&&delete this.components[e]},u.prototype.requestReflow=function(t){if(t)this.reflow();else if(!this.reflowTimer){var e=this;this.reflowTimer=setTimeout(function(){e.reflowTimer=void 0,e.reflow()},0)}},u.prototype.requestRepaint=function(t){if(t)this.repaint();else if(!this.repaintTimer){var e=this;this.repaintTimer=setTimeout(function(){e.repaintTimer=void 0,e.repaint()},0)}},u.prototype.repaint=function H(){function H(i,n){n in e||(i.depends&&i.depends.forEach(function(t){H(t,t.id)}),i.parent&&H(i.parent,i.parent.id),t=i.repaint()||t,e[n]=!0)}var t=!1;this.repaintTimer&&(clearTimeout(this.repaintTimer),this.repaintTimer=void 0);var e={};A.forEach(this.components,H),t&&this.reflow()},u.prototype.reflow=function z(){function z(i,n){n in e||(i.depends&&i.depends.forEach(function(t){z(t,t.id)}),i.parent&&z(i.parent,i.parent.id),t=i.reflow()||t,e[n]=!0)}var t=!1;this.reflowTimer&&(clearTimeout(this.reflowTimer),this.reflowTimer=void 0);var e={};A.forEach(this.components,z),t&&this.repaint()},l.prototype.setOptions=function(t){t&&(A.extend(this.options,t),this.controller&&(this.requestRepaint(),this.requestReflow()))},l.prototype.getOption=function(t){var e;return this.options&&(e=this.options[t]),void 0===e&&this.defaultOptions&&(e=this.defaultOptions[t]),e},l.prototype.getContainer=function(){return null},l.prototype.getFrame=function(){return this.frame},l.prototype.repaint=function(){return!1},l.prototype.reflow=function(){return!1},l.prototype.hide=function(){return this.frame&&this.frame.parentNode?(this.frame.parentNode.removeChild(this.frame),!0):!1},l.prototype.show=function(){return this.frame&&this.frame.parentNode?!1:this.repaint()},l.prototype.requestRepaint=function(){if(!this.controller)throw new Error("Cannot request a repaint: no controller configured");this.controller.requestRepaint()},l.prototype.requestReflow=function(){if(!this.controller)throw new Error("Cannot request a reflow: no controller configured");this.controller.requestReflow()},p.prototype=new l,p.prototype.setOptions=l.prototype.setOptions,p.prototype.getContainer=function(){return this.frame},p.prototype.repaint=function(){var t=0,e=A.updateProperty,i=A.option.asSize,n=this.options,s=this.frame;if(!s){s=document.createElement("div"),s.className="panel";var r=n.className;r&&("function"==typeof r?A.addClassName(s,String(r())):A.addClassName(s,String(r))),this.frame=s,t+=1}if(!s.parentNode){if(!this.parent)throw new Error("Cannot repaint panel: no parent attached");var o=this.parent.getContainer();if(!o)throw new Error("Cannot repaint panel: parent has no container element");o.appendChild(s),t+=1}return t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),t>0},p.prototype.reflow=function(){var t=0,e=A.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},f.prototype=new p,f.prototype.setOptions=l.prototype.setOptions,f.prototype.repaint=function(){var t=0,e=A.updateProperty,i=A.option.asSize,n=this.options,s=this.frame;if(s||(s=document.createElement("div"),this.frame=s,t+=1),!s.parentNode){if(!this.container)throw new Error("Cannot repaint root panel: no container attached");this.container.appendChild(s),t+=1}s.className="vis timeline rootpanel "+n.orientation;var r=n.className;return r&&A.addClassName(s,A.option.asString(r)),t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),this._updateEventEmitters(),this._updateWatch(),t>0},f.prototype.reflow=function(){var t=0,e=A.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},f.prototype._updateWatch=function(){var t=this.getOption("autoResize");t?this._watch():this._unwatch()},f.prototype._watch=function(){var t=this;this._unwatch();var e=function(){var e=t.getOption("autoResize");return e?(t.frame&&(t.frame.clientWidth!=t.width||t.frame.clientHeight!=t.height)&&t.requestReflow(),void 0):(t._unwatch(),void 0)};A.addEventListener(window,"resize",e),this.watchTimer=setInterval(e,1e3)},f.prototype._unwatch=function(){this.watchTimer&&(clearInterval(this.watchTimer),this.watchTimer=void 0)},f.prototype.on=function(t,e){var i=this.listeners[t];i||(i=[],this.listeners[t]=i),i.push(e),this._updateEventEmitters()},f.prototype._updateEventEmitters=function(){if(this.listeners){var t=this;A.forEach(this.listeners,function(e,i){if(t.emitters||(t.emitters={}),!(i in t.emitters)){var n=t.frame;if(n){var s=function(t){e.forEach(function(e){e(t)})};t.emitters[i]=s,t.hammer||(t.hammer=L(n,{prevent_default:!0})),t.hammer.on(i,s)}}})}},m.prototype=new l,m.prototype.setOptions=l.prototype.setOptions,m.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},m.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},m.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},m.prototype.repaint=function(){var t=0,e=A.updateProperty,i=A.option.asSize,n=this.options,s=this.getOption("orientation"),r=this.props,o=this.step,a=this.frame;if(a||(a=document.createElement("div"),this.frame=a,t+=1),a.className="axis",!a.parentNode){if(!this.parent)throw new Error("Cannot repaint time axis: no parent attached");var h=this.parent.getContainer();if(!h)throw new Error("Cannot repaint time axis: parent has no container element");h.appendChild(a),t+=1}var d=a.parentNode;if(d){var c=a.nextSibling;d.removeChild(a);var u="bottom"==s&&this.props.parentHeight&&this.height?this.props.parentHeight-this.height+"px":"0px";if(t+=e(a.style,"top",i(n.top,u)),t+=e(a.style,"left",i(n.left,"0px")),t+=e(a.style,"width",i(n.width,"100%")),t+=e(a.style,"height",i(n.height,this.height+"px")),this._repaintMeasureChars(),this.step){this._repaintStart(),o.first();for(var l=void 0,p=0;o.hasNext()&&1e3>p;){p++;var f=o.getCurrent(),m=this.toScreen(f),g=o.isMajor();this.getOption("showMinorLabels")&&this._repaintMinorText(m,o.getLabelMinor()),g&&this.getOption("showMajorLabels")?(m>0&&(void 0==l&&(l=m),this._repaintMajorText(m,o.getLabelMajor())),this._repaintMajorLine(m)):this._repaintMinorLine(m),o.next()}if(this.getOption("showMajorLabels")){var v=this.toTime(0),y=o.getLabelMajor(v),w=y.length*(r.majorCharWidth||10)+10;(void 0==l||l>w)&&this._repaintMajorText(0,y)}this._repaintEnd()}this._repaintLine(),c?d.insertBefore(a,c):d.appendChild(a)}return t>0},m.prototype._repaintStart=function(){var t=this.dom,e=t.redundant;e.majorLines=t.majorLines,e.majorTexts=t.majorTexts,e.minorLines=t.minorLines,e.minorTexts=t.minorTexts,t.majorLines=[],t.majorTexts=[],t.minorLines=[],t.minorTexts=[]},m.prototype._repaintEnd=function(){A.forEach(this.dom.redundant,function(t){for(;t.length;){var e=t.pop();e&&e.parentNode&&e.parentNode.removeChild(e)}})},m.prototype._repaintMinorText=function(t,e){var i=this.dom.redundant.minorTexts.shift();if(!i){var n=document.createTextNode("");i=document.createElement("div"),i.appendChild(n),i.className="text minor",this.frame.appendChild(i)}this.dom.minorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.left=t+"px",i.style.top=this.props.minorLabelTop+"px"},m.prototype._repaintMajorText=function(t,e){var i=this.dom.redundant.majorTexts.shift();if(!i){var n=document.createTextNode(e);i=document.createElement("div"),i.className="text major",i.appendChild(n),this.frame.appendChild(i)}this.dom.majorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.top=this.props.majorLabelTop+"px",i.style.left=t+"px"},m.prototype._repaintMinorLine=function(t){var e=this.dom.redundant.minorLines.shift();e||(e=document.createElement("div"),e.className="grid vertical minor",this.frame.appendChild(e)),this.dom.minorLines.push(e);var i=this.props;e.style.top=i.minorLineTop+"px",e.style.height=i.minorLineHeight+"px",e.style.left=t-i.minorLineWidth/2+"px"},m.prototype._repaintMajorLine=function(t){var e=this.dom.redundant.majorLines.shift();e||(e=document.createElement("DIV"),e.className="grid vertical major",this.frame.appendChild(e)),this.dom.majorLines.push(e);var i=this.props;e.style.top=i.majorLineTop+"px",e.style.left=t-i.majorLineWidth/2+"px",e.style.height=i.majorLineHeight+"px"},m.prototype._repaintLine=function(){{var t=this.dom.line,e=this.frame;this.options}this.getOption("showMinorLabels")||this.getOption("showMajorLabels")?(t?(e.removeChild(t),e.appendChild(t)):(t=document.createElement("div"),t.className="grid horizontal major",e.appendChild(t),this.dom.line=t),t.style.top=this.props.lineTop+"px"):t&&t.parentElement&&(e.removeChild(t.line),delete this.dom.line)},m.prototype._repaintMeasureChars=function(){var t,e=this.dom;if(!e.measureCharMinor){t=document.createTextNode("0");var i=document.createElement("DIV");i.className="text minor measure",i.appendChild(t),this.frame.appendChild(i),e.measureCharMinor=i}if(!e.measureCharMajor){t=document.createTextNode("0");var n=document.createElement("DIV");n.className="text major measure",n.appendChild(t),this.frame.appendChild(n),e.measureCharMajor=n}},m.prototype.reflow=function(){var t=0,e=A.updateProperty,i=this.frame,n=this.range;if(!n)throw new Error("Cannot repaint time axis: no range configured");if(i){t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft);var s=this.props,r=this.getOption("showMinorLabels"),o=this.getOption("showMajorLabels"),a=this.dom.measureCharMinor,h=this.dom.measureCharMajor;a&&(s.minorCharHeight=a.clientHeight,s.minorCharWidth=a.clientWidth),h&&(s.majorCharHeight=h.clientHeight,s.majorCharWidth=h.clientWidth);var d=i.parentNode?i.parentNode.offsetHeight:0;switch(d!=s.parentHeight&&(s.parentHeight=d,t+=1),this.getOption("orientation")){case"bottom":s.minorLabelHeight=r?s.minorCharHeight:0,s.majorLabelHeight=o?s.majorCharHeight:0,s.minorLabelTop=0,s.majorLabelTop=s.minorLabelTop+s.minorLabelHeight,s.minorLineTop=-this.top,s.minorLineHeight=Math.max(this.top+s.majorLabelHeight,0),s.minorLineWidth=1,s.majorLineTop=-this.top,s.majorLineHeight=Math.max(this.top+s.minorLabelHeight+s.majorLabelHeight,0),s.majorLineWidth=1,s.lineTop=0;break;case"top":s.minorLabelHeight=r?s.minorCharHeight:0,s.majorLabelHeight=o?s.majorCharHeight:0,s.majorLabelTop=0,s.minorLabelTop=s.majorLabelTop+s.majorLabelHeight,s.minorLineTop=s.minorLabelTop,s.minorLineHeight=Math.max(d-s.majorLabelHeight-this.top),s.minorLineWidth=1,s.majorLineTop=0,s.majorLineHeight=Math.max(d-this.top),s.majorLineWidth=1,s.lineTop=s.majorLabelHeight+s.minorLabelHeight;break;default:throw new Error('Unkown orientation "'+this.getOption("orientation")+'"')}var c=s.minorLabelHeight+s.majorLabelHeight;t+=e(this,"width",i.offsetWidth),t+=e(this,"height",c),this._updateConversion();var u=A.convert(n.start,"Number"),l=A.convert(n.end,"Number"),p=this.toTime(5*(s.minorCharWidth||10)).valueOf()-this.toTime(0).valueOf();this.step=new TimeStep(new Date(u),new Date(l),p),t+=e(s.range,"start",u),t+=e(s.range,"end",l),t+=e(s.range,"minimumStep",p.valueOf())}return t>0},m.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},g.prototype=new l,g.prototype.setOptions=l.prototype.setOptions,g.prototype.getContainer=function(){return this.frame},g.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCurrentTime"))return t&&(i.removeChild(t),delete this.frame),void 0;t||(t=document.createElement("div"),t.className="currenttime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t),this.frame=t),e.conversion||e._updateConversion();var n=new Date,s=e.toScreen(n);t.style.left=s+"px",t.title="Current time: "+n,void 0!==this.currentTimeTimer&&(clearTimeout(this.currentTimeTimer),delete this.currentTimeTimer);var r=this,o=1/e.conversion.scale/2;return 30>o&&(o=30),this.currentTimeTimer=setTimeout(function(){r.repaint()},o),!1},v.prototype=new l,v.prototype.setOptions=l.prototype.setOptions,v.prototype.getContainer=function(){return this.frame},v.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCustomTime"))return t&&(i.removeChild(t),delete this.frame),void 0;if(!t){t=document.createElement("div"),t.className="customtime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t);var n=document.createElement("div");n.style.position="relative",n.style.top="0px",n.style.left="-10px",n.style.height="100%",n.style.width="20px",t.appendChild(n),this.frame=t,this.subscribe(this,"movetime")}e.conversion||e._updateConversion();var s=e.toScreen(this.customTime);return t.style.left=s+"px",t.title="Time: "+this.customTime,!1},v.prototype._setCustomTime=function(t){this.customTime=new Date(t.valueOf()),this.repaint()},v.prototype._getCustomTime=function(){return new Date(this.customTime.valueOf())},v.prototype.subscribe=function(t,e){var i=this,n={component:t,event:e,callback:function(t){i._onMouseDown(t,n)},params:{}};t.on("mousedown",n.callback),i.listeners.push(n)},v.prototype.on=function(t,e){var i=this.frame;if(!i)throw new Error("Cannot add event listener: no parent attached");Y.addListener(this,t,e),A.addEventListener(i,t,e)},v.prototype._onMouseDown=function(t,e){t=t||window.event;var i=e.params,n=t.which?1==t.which:1==t.button;if(n){i.mouseX=A.getPageX(t),i.moved=!1,i.customTime=this.customTime;var s=this;i.onMouseMove||(i.onMouseMove=function(t){s._onMouseMove(t,e)},A.addEventListener(document,"mousemove",i.onMouseMove)),i.onMouseUp||(i.onMouseUp=function(t){s._onMouseUp(t,e)},A.addEventListener(document,"mouseup",i.onMouseUp)),A.stopPropagation(t),A.preventDefault(t)}},v.prototype._onMouseMove=function(t,e){t=t||window.event;var i=e.params,n=this.parent,s=A.getPageX(t);void 0===i.mouseX&&(i.mouseX=s);var r=s-i.mouseX;Math.abs(r)>=1&&(i.moved=!0);var o=n.toScreen(i.customTime),a=o+r,h=n.toTime(a);this._setCustomTime(h),Y.trigger(this,"timechange",{customTime:this.customTime}),A.preventDefault(t)},v.prototype._onMouseUp=function(t,e){t=t||window.event;var i=e.params;i.onMouseMove&&(A.removeEventListener(document,"mousemove",i.onMouseMove),i.onMouseMove=null),i.onMouseUp&&(A.removeEventListener(document,"mouseup",i.onMouseUp),i.onMouseUp=null),i.moved&&Y.trigger(this,"timechanged",{customTime:this.customTime})},y.prototype=new p,y.types={box:_,range:E,rangeoverflow:T,point:b},y.prototype.setOptions=l.prototype.setOptions,y.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},y.prototype.repaint=function(){var t=0,e=A.updateProperty,i=A.option.asSize,n=this.options,s=this.getOption("orientation"),r=this.defaultOptions,o=this.frame;if(!o){o=document.createElement("div"),o.className="itemset";var a=n.className;a&&A.addClassName(o,A.option.asString(a));var h=document.createElement("div");h.className="background",o.appendChild(h),this.dom.background=h;var d=document.createElement("div");d.className="foreground",o.appendChild(d),this.dom.foreground=d;var c=document.createElement("div");c.className="itemset-axis",this.dom.axis=c,this.frame=o,t+=1}if(!this.parent)throw new Error("Cannot repaint itemset: no parent attached");var u=this.parent.getContainer();if(!u)throw new Error("Cannot repaint itemset: parent has no container element");o.parentNode||(u.appendChild(o),t+=1),this.dom.axis.parentNode||(u.appendChild(this.dom.axis),t+=1),t+=e(o.style,"left",i(n.left,"0px")),t+=e(o.style,"top",i(n.top,"0px")),t+=e(o.style,"width",i(n.width,"100%")),t+=e(o.style,"height",i(n.height,this.height+"px")),t+=e(this.dom.axis.style,"left",i(n.left,"0px")),t+=e(this.dom.axis.style,"width",i(n.width,"100%")),t+="bottom"==s?e(this.dom.axis.style,"top",this.height+this.top+"px"):e(this.dom.axis.style,"top",this.top+"px"),this._updateConversion();var l=this,p=this.queue,f=this.itemsData,m=this.items,g={};return Object.keys(p).forEach(function(e){var i=p[e],s=m[e];switch(i){case"add":case"update":var o=f&&f.get(e,g);if(o){var a=o.type||o.start&&o.end&&"range"||n.type||"box",h=y.types[a];if(s&&(h&&s instanceof h?(s.data=o,t++):(t+=s.hide(),s=null)),!s){if(!h)throw new TypeError('Unknown item type "'+a+'"');s=new h(l,o,n,r),t++}s.repaint(),m[e]=s}delete p[e];break;case"remove":s&&(t+=s.hide()),delete m[e],delete p[e];break;default:console.log('Error: unknown action "'+i+'"')}}),A.forEach(this.items,function(e){e.visible?(t+=e.show(),e.reposition()):t+=e.hide()}),t>0},y.prototype.getForeground=function(){return this.dom.foreground},y.prototype.getBackground=function(){return this.dom.background},y.prototype.getAxis=function(){return this.dom.axis},y.prototype.reflow=function(){var t=0,e=this.options,i=e.margin&&e.margin.axis||this.defaultOptions.margin.axis,n=e.margin&&e.margin.item||this.defaultOptions.margin.item,s=A.updateProperty,r=A.option.asNumber,o=A.option.asSize,a=this.frame;if(a){this._updateConversion(),A.forEach(this.items,function(e){t+=e.reflow()}),this.stack.update();var h,d=r(e.maxHeight),c=null!=o(e.height);if(c)h=a.offsetHeight;else{var u=this.stack.ordered;if(u.length){var l=u[0].top,p=u[0].top+u[0].height;A.forEach(u,function(t){l=Math.min(l,t.top),p=Math.max(p,t.top+t.height)}),h=p-l+i+n}else h=i+n}null!=d&&(h=Math.min(h,d)),t+=s(this,"height",h),t+=s(this,"top",a.offsetTop),t+=s(this,"left",a.offsetLeft),t+=s(this,"width",a.offsetWidth)}else t+=1;return t>0},y.prototype.hide=function(){var t=!1;return this.frame&&this.frame.parentNode&&(this.frame.parentNode.removeChild(this.frame),t=!0),this.dom.axis&&this.dom.axis.parentNode&&(this.dom.axis.parentNode.removeChild(this.dom.axis),t=!0),t},y.prototype.setItems=function(t){var e,i=this,n=this.itemsData;if(t){if(!(t instanceof r||t instanceof o))throw new TypeError("Data must be an instance of DataSet");this.itemsData=t}else this.itemsData=null;if(n&&(A.forEach(this.listeners,function(t,e){n.unsubscribe(e,t)}),e=n.getIds(),this._onRemove(e)),this.itemsData){var s=this.id;A.forEach(this.listeners,function(t,e){i.itemsData.subscribe(e,t,s)}),e=this.itemsData.getIds(),this._onAdd(e)}},y.prototype.getItems=function(){return this.itemsData},y.prototype._onUpdate=function(t){this._toQueue("update",t)},y.prototype._onAdd=function(t){this._toQueue("add",t)},y.prototype._onRemove=function(t){this._toQueue("remove",t)},y.prototype._toQueue=function(t,e){var i=this.queue;e.forEach(function(e){i[e]=t}),this.controller&&this.requestRepaint()},y.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},y.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},y.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},w.prototype.select=function(){this.selected=!0},w.prototype.unselect=function(){this.selected=!1},w.prototype.show=function(){return!1},w.prototype.hide=function(){return!1},w.prototype.repaint=function(){return!1},w.prototype.reflow=function(){return!1},w.prototype.getWidth=function(){return this.width},_.prototype=new w(null,null),_.prototype.select=function(){this.selected=!0},_.prototype.unselect=function(){this.selected=!1},_.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");if(!e.box.parentNode){var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");i.appendChild(e.box),t=!0}if(!e.line.parentNode){var n=this.parent.getBackground();if(!n)throw new Error("Cannot repaint time axis: parent has no background container element");n.appendChild(e.line),t=!0}if(!e.dot.parentNode){var s=this.parent.getAxis();if(!n)throw new Error("Cannot repaint time axis: parent has no axis container element");s.appendChild(e.dot),t=!0}if(this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var r=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=r&&(this.className=r,e.box.className="item box"+r,e.line.className="item line"+r,e.dot.className="item dot"+r,t=!0)}return t},_.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint() -},_.prototype.hide=function(){var t=!1,e=this.dom;return e&&(e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),e.line.parentNode&&e.line.parentNode.removeChild(e.line),e.dot.parentNode&&e.dot.parentNode.removeChild(e.dot)),t},_.prototype.reflow=function(){var t,e,i,n,s,r,o,a,h,d,c,u,l=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(c=this.data,u=this.parent&&this.parent.range,c&&u){var p=u.end-u.start;this.visible=c.start>u.start-p&&c.start0},_.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("DIV"),t.content=document.createElement("DIV"),t.content.className="content",t.box.appendChild(t.content),t.line=document.createElement("DIV"),t.line.className="line",t.dot=document.createElement("DIV"),t.dot.className="dot")},_.prototype.reposition=function(){var t=this.dom,e=this.props,i=this.options.orientation||this.defaultOptions.orientation;if(t){var n=t.box,s=t.line,r=t.dot;n.style.left=this.left+"px",n.style.top=this.top+"px",s.style.left=e.line.left+"px","top"==i?(s.style.top="0px",s.style.height=this.top+"px"):(s.style.top=this.top+this.height+"px",s.style.height=Math.max(this.parent.height-this.top-this.height+this.props.dot.height/2,0)+"px"),r.style.left=e.dot.left+"px",r.style.top=e.dot.top+"px"}},b.prototype=new w(null,null),b.prototype.select=function(){this.selected=!0},b.prototype.unselect=function(){this.selected=!1},b.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.point.parentNode||(i.appendChild(e.point),i.appendChild(e.point),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.point.className="item point"+n,t=!0)}return t},b.prototype.show=function(){return this.dom&&this.dom.point.parentNode?!1:this.repaint()},b.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.point.parentNode&&(e.point.parentNode.removeChild(e.point),t=!0),t},b.prototype.reflow=function(){var t,e,i,n,s,r,o,a,h,d,c=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(h=this.data,d=this.parent&&this.parent.range,h&&d){var u=d.end-d.start;this.visible=h.start>d.start-u&&h.start0},b.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.point=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.point.appendChild(t.content),t.dot=document.createElement("div"),t.dot.className="dot",t.point.appendChild(t.dot))},b.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.point.style.top=this.top+"px",t.point.style.left=this.left+"px",t.content.style.marginLeft=e.content.marginLeft+"px",t.dot.style.top=e.dot.top+"px")},E.prototype=new w(null,null),E.prototype.select=function(){this.selected=!0},E.prototype.unselect=function(){this.selected=!1},E.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=this.data.className?" "+this.data.className:"";this.className!=n&&(this.className=n,e.box.className="item range"+n,t=!0)}return t},E.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},E.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),t},E.prototype.reflow=function(){var t,e,i,n,s,r,o,a,h,d,c,u,l,p,f,m,g=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(void 0==this.data.end)throw new Error('Property "end" missing in item '+this.data.id);return h=this.data,d=this.parent&&this.parent.range,this.visible=h&&d?h.startd.start:!1,this.visible&&(t=this.dom,t?(e=this.props,i=this.options,r=this.parent,o=r.toScreen(this.data.start),a=r.toScreen(this.data.end),c=A.updateProperty,u=t.box,l=r.width,f=i.orientation||this.defaultOptions.orientation,n=i.margin&&i.margin.axis||this.defaultOptions.margin.axis,s=i.padding||this.defaultOptions.padding,g+=c(e.content,"width",t.content.offsetWidth),g+=c(this,"height",u.offsetHeight),-l>o&&(o=-l),a>2*l&&(a=2*l),p=0>o?Math.min(-o,a-o-e.content.width-2*s):0,g+=c(e.content,"left",p),"top"==f?(m=n,g+=c(this,"top",m)):(m=r.height-this.height-n,g+=c(this,"top",m)),g+=c(this,"left",o),g+=c(this,"width",Math.max(a-o,1))):g+=1),g>0},E.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content))},E.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.box.style.top=this.top+"px",t.box.style.left=this.left+"px",t.box.style.width=this.width+"px",t.content.style.left=e.content.left+"px")},T.prototype=new E(null,null),T.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=this.data.className?" "+this.data.className:"";this.className!=n&&(this.className=n,e.box.className="item rangeoverflow"+n,t=!0)}return t},T.prototype.getWidth=function(){return void 0!==this.props.content&&this.width0},x.prototype=new p,x.prototype.setOptions=l.prototype.setOptions,x.prototype.setRange=function(){},x.prototype.setItems=function(t){this.itemsData=t;for(var e in this.groups)if(this.groups.hasOwnProperty(e)){var i=this.groups[e];i.setItems(t)}},x.prototype.getItems=function(){return this.itemsData},x.prototype.setRange=function(t){this.range=t},x.prototype.setGroups=function(t){var e,i=this;if(this.groupsData&&(A.forEach(this.listeners,function(t,e){i.groupsData.unsubscribe(e,t)}),e=this.groupsData.getIds(),this._onRemove(e)),t?t instanceof r?this.groupsData=t:(this.groupsData=new r({convert:{start:"Date",end:"Date"}}),this.groupsData.add(t)):this.groupsData=null,this.groupsData){var n=this.id;A.forEach(this.listeners,function(t,e){i.groupsData.subscribe(e,t,n)}),e=this.groupsData.getIds(),this._onAdd(e)}},x.prototype.getGroups=function(){return this.groupsData},x.prototype.repaint=function(){var t,e,i,n,s=0,r=A.updateProperty,o=A.option.asSize,a=A.option.asElement,h=this.options,d=this.dom.frame,c=this.dom.labels,u=this.dom.labelSet;if(!this.parent)throw new Error("Cannot repaint groupset: no parent attached");var l=this.parent.getContainer();if(!l)throw new Error("Cannot repaint groupset: parent has no container element");if(!d){d=document.createElement("div"),d.className="groupset",this.dom.frame=d;var p=h.className;p&&A.addClassName(d,A.option.asString(p)),s+=1}d.parentNode||(l.appendChild(d),s+=1);var f=a(h.labelContainer);if(!f)throw new Error('Cannot repaint groupset: option "labelContainer" not defined');c||(c=document.createElement("div"),c.className="labels",this.dom.labels=c),u||(u=document.createElement("div"),u.className="label-set",c.appendChild(u),this.dom.labelSet=u),c.parentNode&&c.parentNode==f||(c.parentNode&&c.parentNode.removeChild(c.parentNode),f.appendChild(c)),s+=r(d.style,"height",o(h.height,this.height+"px")),s+=r(d.style,"top",o(h.top,"0px")),s+=r(d.style,"left",o(h.left,"0px")),s+=r(d.style,"width",o(h.width,"100%")),s+=r(u.style,"top",o(h.top,"0px")),s+=r(u.style,"height",o(h.height,this.height+"px"));var m=this,g=this.queue,v=this.groups,y=this.groupsData,w=Object.keys(g);if(w.length){w.forEach(function(t){var e=g[t],i=v[t];switch(e){case"add":case"update":if(!i){var n=Object.create(m.options);A.extend(n,{height:null,maxHeight:null}),i=new S(m,t,n),i.setItems(m.itemsData),v[t]=i,m.controller.add(i)}i.data=y.get(t),delete g[t];break;case"remove":i&&(i.setItems(),delete v[t],m.controller.remove(i)),delete g[t];break;default:console.log('Error: unknown action "'+e+'"')}});var _=this.groupsData.getIds({order:this.options.groupOrder});for(t=0;t<_.length;t++)!function(t,e){var i=0;e&&(i=function(){return e.top+e.height}),t.setOptions({top:i})}(v[_[t]],v[_[t-1]]);for(;u.firstChild;)u.removeChild(u.firstChild);for(t=0;t<_.length;t++)e=_[t],n=this._createLabel(e),u.appendChild(n);s++}for(e in v)v.hasOwnProperty(e)&&(i=v[e],n=i.label,n&&(n.style.top=i.top+"px",n.style.height=i.height+"px"));return s>0},x.prototype._createLabel=function(t){var e=this.groups[t],i=document.createElement("div");i.className="label";var n=document.createElement("div");n.className="inner",i.appendChild(n);var s=e.data&&e.data.content;s instanceof Element?n.appendChild(s):void 0!=s&&(n.innerHTML=s);var r=e.data&&e.data.className;return r&&A.addClassName(i,r),e.label=i,i},x.prototype.getContainer=function(){return this.dom.frame},x.prototype.getLabelsWidth=function(){return this.props.labels.width},x.prototype.reflow=function(){var t,e,i=0,n=this.options,s=A.updateProperty,r=A.option.asNumber,o=A.option.asSize,a=this.dom.frame;if(a){var h,d=r(n.maxHeight),c=null!=o(n.height);if(c)h=a.offsetHeight;else{h=0;for(t in this.groups)this.groups.hasOwnProperty(t)&&(e=this.groups[t],h+=e.height)}null!=d&&(h=Math.min(h,d)),i+=s(this,"height",h),i+=s(this,"top",a.offsetTop),i+=s(this,"left",a.offsetLeft),i+=s(this,"width",a.offsetWidth)}var u=0;for(t in this.groups)if(this.groups.hasOwnProperty(t)){e=this.groups[t];var l=e.props&&e.props.label&&e.props.label.width||0;u=Math.max(u,l)}return i+=s(this.props.labels,"width",u),i>0},x.prototype.hide=function(){return this.dom.frame&&this.dom.frame.parentNode?(this.dom.frame.parentNode.removeChild(this.dom.frame),!0):!1},x.prototype.show=function(){return this.dom.frame&&this.dom.frame.parentNode?!1:this.repaint()},x.prototype._onUpdate=function(t){this._toQueue(t,"update")},x.prototype._onAdd=function(t){this._toQueue(t,"add")},x.prototype._onRemove=function(t){this._toQueue(t,"remove")},x.prototype._toQueue=function(t,e){var i=this.queue;t.forEach(function(t){i[t]=e}),this.controller&&this.requestRepaint()},D.prototype.setOptions=function(t){A.extend(this.options,t),this.range.setRange(),this.controller.reflow(),this.controller.repaint()},D.prototype.setCustomTime=function(t){this.customtime._setCustomTime(t)},D.prototype.getCustomTime=function(){return new Date(this.customtime.customTime.valueOf())},D.prototype.setItems=function(t){var e,i=null==this.itemsData;if(t?t instanceof r&&(e=t):e=null,t instanceof r||(e=new r({convert:{start:"Date",end:"Date"}}),e.add(t)),this.itemsData=e,this.content.setItems(e),i&&(void 0==this.options.start||void 0==this.options.end)){var n=this.getItemRange(),s=n.min,o=n.max;if(null!=s&&null!=o){var a=o.valueOf()-s.valueOf();0>=a&&(a=864e5),s=new Date(s.valueOf()-.05*a),o=new Date(o.valueOf()+.05*a)}void 0!=this.options.start&&(s=A.convert(this.options.start,"Date")),void 0!=this.options.end&&(o=A.convert(this.options.end,"Date")),(null!=s||null!=o)&&this.range.setRange(s,o)}},D.prototype.setGroups=function(t){var e=this;this.groupsData=t;var i=this.groupsData?x:y;if(!(this.content instanceof i)){this.content&&(this.content.hide(),this.content.setItems&&this.content.setItems(),this.content.setGroups&&this.content.setGroups(),this.controller.remove(this.content));var n=Object.create(this.options);A.extend(n,{top:function(){return"top"==e.options.orientation?e.timeaxis.height:e.itemPanel.height-e.timeaxis.height-e.content.height},left:null,width:"100%",height:function(){return e.options.height?e.itemPanel.height-e.timeaxis.height:null},maxHeight:function(){if(e.options.maxHeight){if(!A.isNumber(e.options.maxHeight))throw new TypeError("Number expected for property maxHeight");return e.options.maxHeight-e.timeaxis.height}return null},labelContainer:function(){return e.labelPanel.getContainer()}}),this.content=new i(this.itemPanel,[this.timeaxis],n),this.content.setRange&&this.content.setRange(this.range),this.content.setItems&&this.content.setItems(this.itemsData),this.content.setGroups&&this.content.setGroups(this.groupsData),this.controller.add(this.content)}},D.prototype.getItemRange=function(){var t=this.itemsData,e=null,i=null;if(t){var n=t.min("start");e=n?n.start.valueOf():null;var s=t.max("start");s&&(i=s.start.valueOf());var r=t.max("end");r&&(i=null==i?r.end.valueOf():Math.max(i,r.end.valueOf()))}return{min:null!=e?new Date(e):null,max:null!=i?new Date(i):null}},function(t){function e(t){return D=t,l()}function i(){M=0,C=D.charAt(0)}function n(){M++,C=D.charAt(M)}function s(){return D.charAt(M+1)}function r(t){return L.test(t)}function o(t,e){if(t||(t={}),e)for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function a(t,e,i){for(var n=e.split("."),s=t;n.length;){var r=n.shift();n.length?(s[r]||(s[r]={}),s=s[r]):s[r]=i}}function h(t,e){for(var i,n,s=null,r=[t],a=t;a.parent;)r.push(a.parent),a=a.parent;if(a.nodes)for(i=0,n=a.nodes.length;n>i;i++)if(e.id===a.nodes[i].id){s=a.nodes[i];break}for(s||(s={id:e.id},t.node&&(s.attr=o(s.attr,t.node))),i=r.length-1;i>=0;i--){var h=r[i];h.nodes||(h.nodes=[]),-1==h.nodes.indexOf(s)&&h.nodes.push(s)}e.attr&&(s.attr=o(s.attr,e.attr))}function d(t,e){if(t.edges||(t.edges=[]),t.edges.push(e),t.edge){var i=o({},t.edge);e.attr=o(i,e.attr)}}function c(t,e,i,n,s){var r={from:e,to:i,type:n};return t.edge&&(r.attr=o({},t.edge)),r.attr=o(r.attr||{},s),r}function u(){for(N=S.NULL,O="";" "==C||" "==C||"\n"==C||"\r"==C;)n();do{var t=!1;if("#"==C){for(var e=M-1;" "==D.charAt(e)||" "==D.charAt(e);)e--;if("\n"==D.charAt(e)||""==D.charAt(e)){for(;""!=C&&"\n"!=C;)n();t=!0}}if("/"==C&&"/"==s()){for(;""!=C&&"\n"!=C;)n();t=!0}if("/"==C&&"*"==s()){for(;""!=C;){if("*"==C&&"/"==s()){n(),n();break}n()}t=!0}for(;" "==C||" "==C||"\n"==C||"\r"==C;)n()}while(t);if(""==C)return N=S.DELIMITER,void 0;var i=C+s();if(x[i])return N=S.DELIMITER,O=i,n(),n(),void 0;if(x[C])return N=S.DELIMITER,O=C,n(),void 0;if(r(C)||"-"==C){for(O+=C,n();r(C);)O+=C,n();return"false"==O?O=!1:"true"==O?O=!0:isNaN(Number(O))||(O=Number(O)),N=S.IDENTIFIER,void 0}if('"'==C){for(n();""!=C&&('"'!=C||'"'==C&&'"'==s());)O+=C,'"'==C&&n(),n();if('"'!=C)throw _('End of string " expected');return n(),N=S.IDENTIFIER,void 0}for(N=S.UNKNOWN;""!=C;)O+=C,n();throw new SyntaxError('Syntax error in part "'+b(O,30)+'"')}function l(){var t={};if(i(),u(),"strict"==O&&(t.strict=!0,u()),("graph"==O||"digraph"==O)&&(t.type=O,u()),N==S.IDENTIFIER&&(t.id=O,u()),"{"!=O)throw _("Angle bracket { expected");if(u(),p(t),"}"!=O)throw _("Angle bracket } expected");if(u(),""!==O)throw _("End of file expected");return u(),delete t.node,delete t.edge,delete t.graph,t}function p(t){for(;""!==O&&"}"!=O;)f(t),";"==O&&u()}function f(t){var e=m(t);if(e)return y(t,e),void 0;var i=g(t);if(!i){if(N!=S.IDENTIFIER)throw _("Identifier expected");var n=O;if(u(),"="==O){if(u(),N!=S.IDENTIFIER)throw _("Identifier expected");t[n]=O,u()}else v(t,n)}}function m(t){var e=null;if("subgraph"==O&&(e={},e.type="subgraph",u(),N==S.IDENTIFIER&&(e.id=O,u())),"{"==O){if(u(),e||(e={}),e.parent=t,e.node=t.node,e.edge=t.edge,e.graph=t.graph,p(e),"}"!=O)throw _("Angle bracket } expected");u(),delete e.node,delete e.edge,delete e.graph,delete e.parent,t.subgraphs||(t.subgraphs=[]),t.subgraphs.push(e)}return e}function g(t){return"node"==O?(u(),t.node=w(),"node"):"edge"==O?(u(),t.edge=w(),"edge"):"graph"==O?(u(),t.graph=w(),"graph"):null}function v(t,e){var i={id:e},n=w();n&&(i.attr=n),h(t,i),y(t,e)}function y(t,e){for(;"->"==O||"--"==O;){var i,n=O;u();var s=m(t);if(s)i=s;else{if(N!=S.IDENTIFIER)throw _("Identifier or subgraph expected");i=O,h(t,{id:i}),u()}var r=w(),o=c(t,e,i,n,r);d(t,o),e=i}}function w(){for(var t=null;"["==O;){for(u(),t={};""!==O&&"]"!=O;){if(N!=S.IDENTIFIER)throw _("Attribute name expected");var e=O;if(u(),"="!=O)throw _("Equal sign = expected");if(u(),N!=S.IDENTIFIER)throw _("Attribute value expected");var i=O;a(t,e,i),u(),","==O&&u()}if("]"!=O)throw _("Bracket ] expected");u()}return t}function _(t){return new SyntaxError(t+', got "'+b(O,30)+'" (char '+M+")")}function b(t,e){return t.length<=e?t:t.substr(0,27)+"..."}function E(t,e,i){t instanceof Array?t.forEach(function(t){e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}):e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}function T(t){function i(t){var e={from:t.from,to:t.to};return o(e,t.attr),e.style="->"==t.type?"arrow":"line",e}var n=e(t),s={nodes:[],edges:[],options:{}};return n.nodes&&n.nodes.forEach(function(t){var e={id:t.id,label:String(t.label||t.id)};o(e,t.attr),e.image&&(e.shape="image"),s.nodes.push(e)}),n.edges&&n.edges.forEach(function(t){var e,n;e=t.from instanceof Object?t.from.nodes:{id:t.from},n=t.to instanceof Object?t.to.nodes:{id:t.to},t.from instanceof Object&&t.from.edges&&t.from.edges.forEach(function(t){var e=i(t);s.edges.push(e)}),E(e,n,function(e,n){var r=c(s,e.id,n.id,t.type,t.attr),o=i(r);s.edges.push(o)}),t.to instanceof Object&&t.to.edges&&t.to.edges.forEach(function(t){var e=i(t);s.edges.push(e)})}),n.attr&&(s.options=n.attr),s}var S={NULL:0,DELIMITER:1,IDENTIFIER:2,UNKNOWN:3},x={"{":!0,"}":!0,"[":!0,"]":!0,";":!0,"=":!0,",":!0,"->":!0,"--":!0},D="",M=0,C="",O="",N=S.NULL,L=/[a-zA-Z_0-9.:#]/;t.parseDOT=e,t.DOTToGraph=T}("undefined"!=typeof A?A:n),"undefined"!=typeof CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.circle=function(t,e,i){this.beginPath(),this.arc(t,e,i,0,2*Math.PI,!1)},CanvasRenderingContext2D.prototype.square=function(t,e,i){this.beginPath(),this.rect(t-i,e-i,2*i,2*i)},CanvasRenderingContext2D.prototype.triangle=function(t,e,i){this.beginPath();var n=2*i,s=n/2,r=Math.sqrt(3)/6*n,o=Math.sqrt(n*n-s*s);this.moveTo(t,e-(o-r)),this.lineTo(t+s,e+r),this.lineTo(t-s,e+r),this.lineTo(t,e-(o-r)),this.closePath()},CanvasRenderingContext2D.prototype.triangleDown=function(t,e,i){this.beginPath();var n=2*i,s=n/2,r=Math.sqrt(3)/6*n,o=Math.sqrt(n*n-s*s);this.moveTo(t,e+(o-r)),this.lineTo(t+s,e-r),this.lineTo(t-s,e-r),this.lineTo(t,e+(o-r)),this.closePath()},CanvasRenderingContext2D.prototype.star=function(t,e,i){this.beginPath();for(var n=0;10>n;n++){var s=n%2===0?1.3*i:.5*i;this.lineTo(t+s*Math.sin(2*n*Math.PI/10),e-s*Math.cos(2*n*Math.PI/10))}this.closePath()},CanvasRenderingContext2D.prototype.roundRect=function(t,e,i,n,s){var r=Math.PI/180;0>i-2*s&&(s=i/2),0>n-2*s&&(s=n/2),this.beginPath(),this.moveTo(t+s,e),this.lineTo(t+i-s,e),this.arc(t+i-s,e+s,s,270*r,360*r,!1),this.lineTo(t+i,e+n-s),this.arc(t+i-s,e+n-s,s,0,90*r,!1),this.lineTo(t+s,e+n),this.arc(t+s,e+n-s,s,90*r,180*r,!1),this.lineTo(t,e+s),this.arc(t+s,e+s,s,180*r,270*r,!1)},CanvasRenderingContext2D.prototype.ellipse=function(t,e,i,n){var s=.5522848,r=i/2*s,o=n/2*s,a=t+i,h=e+n,d=t+i/2,c=e+n/2;this.beginPath(),this.moveTo(t,c),this.bezierCurveTo(t,c-o,d-r,e,d,e),this.bezierCurveTo(d+r,e,a,c-o,a,c),this.bezierCurveTo(a,c+o,d+r,h,d,h),this.bezierCurveTo(d-r,h,t,c+o,t,c)},CanvasRenderingContext2D.prototype.database=function(t,e,i,n){var s=1/3,r=i,o=n*s,a=.5522848,h=r/2*a,d=o/2*a,c=t+r,u=e+o,l=t+r/2,p=e+o/2,f=e+(n-o/2),m=e+n;this.beginPath(),this.moveTo(c,p),this.bezierCurveTo(c,p+d,l+h,u,l,u),this.bezierCurveTo(l-h,u,t,p+d,t,p),this.bezierCurveTo(t,p-d,l-h,e,l,e),this.bezierCurveTo(l+h,e,c,p-d,c,p),this.lineTo(c,f),this.bezierCurveTo(c,f+d,l+h,m,l,m),this.bezierCurveTo(l-h,m,t,f+d,t,f),this.lineTo(t,p)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,n){var s=t-n*Math.cos(i),r=e-n*Math.sin(i),o=t-.9*n*Math.cos(i),a=e-.9*n*Math.sin(i),h=s+n/3*Math.cos(i+.5*Math.PI),d=r+n/3*Math.sin(i+.5*Math.PI),c=s+n/3*Math.cos(i-.5*Math.PI),u=r+n/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,d),this.lineTo(o,a),this.lineTo(c,u),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,n,s){s||(s=[10,5]),0==l&&(l=.001);var r=s.length;this.moveTo(t,e);for(var o=i-t,a=n-e,h=a/o,d=Math.sqrt(o*o+a*a),c=0,u=!0;d>=.1;){var l=s[c++%r];l>d&&(l=d);var p=Math.sqrt(l*l/(1+h*h));0>o&&(p=-p),t+=p,e+=h*p,this[u?"lineTo":"moveTo"](t,e),d-=l,u=!u}}),M.prototype.attachEdge=function(t){-1==this.edges.indexOf(t)&&this.edges.push(t),this._updateMass()},M.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&this.edges.splice(e,1),this._updateMass()},M.prototype._updateMass=function(){this.mass=50+20*this.edges.length},M.prototype.setProperties=function(t,e){if(t){if(void 0!=t.id&&(this.id=t.id),void 0!=t.label&&(this.label=t.label),void 0!=t.title&&(this.title=t.title),void 0!=t.group&&(this.group=t.group),void 0!=t.x&&(this.x=t.x),void 0!=t.y&&(this.y=t.y),void 0!=t.value&&(this.value=t.value),void 0===this.id)throw"Node must have an id";if(this.group){var i=this.grouplist.get(this.group);for(var n in i)i.hasOwnProperty(n)&&(this[n]=i[n])}if(void 0!=t.shape&&(this.shape=t.shape),void 0!=t.image&&(this.image=t.image),void 0!=t.radius&&(this.radius=t.radius),void 0!=t.color&&(this.color=M.parseColor(t.color)),void 0!=t.fontColor&&(this.fontColor=t.fontColor),void 0!=t.fontSize&&(this.fontSize=t.fontSize),void 0!=t.fontFace&&(this.fontFace=t.fontFace),void 0!=this.image){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.image)}switch(this.xFixed=this.xFixed||void 0!=t.x,this.yFixed=this.yFixed||void 0!=t.y,this.radiusFixed=this.radiusFixed||void 0!=t.radius,"image"==this.shape&&(this.radiusMin=e.nodes.widthMin,this.radiusMax=e.nodes.widthMax),this.shape){case"database":this.draw=this._drawDatabase,this.resize=this._resizeDatabase;break;case"box":this.draw=this._drawBox,this.resize=this._resizeBox;break;case"circle":this.draw=this._drawCircle,this.resize=this._resizeCircle;break;case"ellipse":this.draw=this._drawEllipse,this.resize=this._resizeEllipse;break;case"image":this.draw=this._drawImage,this.resize=this._resizeImage;break;case"text":this.draw=this._drawText,this.resize=this._resizeText;break;case"dot":this.draw=this._drawDot,this.resize=this._resizeShape;break;case"square":this.draw=this._drawSquare,this.resize=this._resizeShape;break;case"triangle":this.draw=this._drawTriangle,this.resize=this._resizeShape;break;case"triangleDown":this.draw=this._drawTriangleDown,this.resize=this._resizeShape;break;case"star":this.draw=this._drawStar,this.resize=this._resizeShape;break;default:this.draw=this._drawEllipse,this.resize=this._resizeEllipse}this._reset()}},M.parseColor=function(t){var e;return A.isString(t)?e={border:t,background:t,highlight:{border:t,background:t}}:(e={},e.background=t.background||"white",e.border=t.border||e.background,A.isString(t.highlight)?e.highlight={border:t.highlight,background:t.highlight}:(e.highlight={},e.highlight.background=t.highlight&&t.highlight.background||e.background,e.highlight.border=t.highlight&&t.highlight.border||e.border)),e},M.prototype.select=function(){this.selected=!0,this._reset()},M.prototype.unselect=function(){this.selected=!1,this._reset()},M.prototype._reset=function(){this.width=void 0,this.height=void 0},M.prototype.getTitle=function(){return this.title},M.prototype.distanceToBorder=function(t,e){var i=1;switch(this.width||this.resize(t),this.shape){case"circle":case"dot":return this.radius+i;case"ellipse":var n=this.width/2,s=this.height/2,r=Math.sin(e)*n,o=Math.cos(e)*s;return n*s/Math.sqrt(r*r+o*o);case"box":case"image":case"text":default:return this.width?Math.min(Math.abs(this.width/2/Math.cos(e)),Math.abs(this.height/2/Math.sin(e)))+i:0}},M.prototype._setForce=function(t,e){this.fx=t,this.fy=e},M.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},M.prototype.discreteStep=function(t){if(!this.xFixed){var e=-this.damping*this.vx,i=(this.fx+e)/this.mass;this.vx+=i/t,this.x+=this.vx/t}if(!this.yFixed){var n=-this.damping*this.vy,s=(this.fy+n)/this.mass;this.vy+=s/t,this.y+=this.vy/t}},M.prototype.isFixed=function(){return this.xFixed&&this.yFixed},M.prototype.isMoving=function(t){return Math.abs(this.vx)>t||Math.abs(this.vy)>t||!this.xFixed&&Math.abs(this.fx)>this.minForce||!this.yFixed&&Math.abs(this.fy)>this.minForce},M.prototype.isSelected=function(){return this.selected},M.prototype.getValue=function(){return this.value},M.prototype.getDistance=function(t,e){var i=this.x-t,n=this.y-e;return Math.sqrt(i*i+n*n)},M.prototype.setValueRange=function(t,e){if(!this.radiusFixed&&void 0!==this.value)if(e==t)this.radius=(this.radiusMin+this.radiusMax)/2;else{var i=(this.radiusMax-this.radiusMin)/(e-t);this.radius=(this.value-t)*i+this.radiusMin}},M.prototype.draw=function(){throw"Draw method not initialized for node"},M.prototype.resize=function(){throw"Resize method not initialized for node"},M.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},M.prototype._resizeImage=function(){if(!this.width){var t,e;if(this.value){var i=this.imageObj.height/this.imageObj.width;t=this.radius||this.imageObj.width,e=this.radius*i||this.imageObj.height}else t=this.imageObj.width,e=this.imageObj.height;this.width=t,this.height=e}},M.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e;this.imageObj?(t.drawImage(this.imageObj,this.left,this.top,this.width,this.height),e=this.y+this.height/2):e=this.y,this._label(t,this.label,this.x,e,void 0,"top")},M.prototype._resizeBox=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e}},M.prototype._drawBox=function(t){this._resizeBox(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,t.roundRect(this.left,this.top,this.width,this.height,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeDatabase=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=i.width+2*e;this.width=n,this.height=n}},M.prototype._drawDatabase=function(t){this._resizeDatabase(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,t.database(this.x-this.width/2,this.y-.5*this.height,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=Math.max(i.width,i.height)+2*e;this.radius=n/2,this.width=n,this.height=n}},M.prototype._drawCircle=function(t){this._resizeCircle(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,t.circle(this.x,this.y,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeEllipse=function(t){if(!this.width){var e=this.getTextSize(t);this.width=1.5*e.width,this.height=2*e.height,this.widthc;c++)t.fillText(o[c],i,d),d+=h}},M.prototype.getTextSize=function(t){if(void 0!=this.label){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace;for(var e=this.label.split("\n"),i=(this.fontSize+4)*e.length,n=0,s=0,r=e.length;r>s;s++)n=Math.max(n,t.measureText(e[s]).width);return{width:n,height:i}}return{width:0,height:0}},C.prototype.setProperties=function(t,e){if(t)switch(void 0!=t.from&&(this.fromId=t.from),void 0!=t.to&&(this.toId=t.to),void 0!=t.id&&(this.id=t.id),void 0!=t.style&&(this.style=t.style),void 0!=t.label&&(this.label=t.label),this.label&&(this.fontSize=e.edges.fontSize,this.fontFace=e.edges.fontFace,this.fontColor=e.edges.fontColor,void 0!=t.fontColor&&(this.fontColor=t.fontColor),void 0!=t.fontSize&&(this.fontSize=t.fontSize),void 0!=t.fontFace&&(this.fontFace=t.fontFace)),void 0!=t.title&&(this.title=t.title),void 0!=t.width&&(this.width=t.width),void 0!=t.value&&(this.value=t.value),void 0!=t.length&&(this.length=t.length),t.dash&&(void 0!=t.dash.length&&(this.dash.length=t.dash.length),void 0!=t.dash.gap&&(this.dash.gap=t.dash.gap),void 0!=t.dash.altLength&&(this.dash.altLength=t.dash.altLength)),void 0!=t.color&&(this.color=t.color),this.connect(),this.widthFixed=this.widthFixed||void 0!=t.width,this.lengthFixed=this.lengthFixed||void 0!=t.length,this.stiffness=1/this.length,this.style){case"line":this.draw=this._drawLine;break;case"arrow":this.draw=this._drawArrow;break;case"arrow-center":this.draw=this._drawArrowCenter;break;case"dash-line":this.draw=this._drawDashLine;break;default:this.draw=this._drawLine}},C.prototype.connect=function(){this.disconnect(),this.from=this.graph.nodes[this.fromId]||null,this.to=this.graph.nodes[this.toId]||null,this.connected=this.from&&this.to,this.connected?(this.from.attachEdge(this),this.to.attachEdge(this)):(this.from&&this.from.detachEdge(this),this.to&&this.to.detachEdge(this))},C.prototype.disconnect=function(){this.from&&(this.from.detachEdge(this),this.from=null),this.to&&(this.to.detachEdge(this),this.to=null),this.connected=!1},C.prototype.getTitle=function(){return this.title},C.prototype.getValue=function(){return this.value},C.prototype.setValueRange=function(t,e){if(!this.widthFixed&&void 0!==this.value){var i=(this.widthMax-this.widthMin)/(e-t);this.width=(this.value-t)*i+this.widthMin}},C.prototype.draw=function(){throw"Method draw not initialized in edge"},C.prototype.isOverlappingWith=function(t){var e=10,i=this.from.x,n=this.from.y,s=this.to.x,r=this.to.y,o=t.left,a=t.top,h=C._dist(i,n,s,r,o,a);return e>h},C.prototype._drawLine=function(t){t.strokeStyle=this.color,t.lineWidth=this._getLineWidth();var e;if(this.from!=this.to)this._line(t),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y));else{var i,n,s=this.length/4,r=this.from;r.width||r.resize(t),r.width>r.height?(i=r.x+r.width/2,n=r.y-s):(i=r.x+s,n=r.y-r.height/2),this._circle(t,i,n,s),e=this._pointOnCircle(i,n,s,.5),this._label(t,this.label,e.x,e.y)}},C.prototype._getLineWidth=function(){return this.from.selected||this.to.selected?Math.min(2*this.width,this.widthMax):this.width},C.prototype._line=function(t){t.beginPath(),t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y),t.stroke()},C.prototype._circle=function(t,e,i,n){t.beginPath(),t.arc(e,i,n,0,2*Math.PI,!1),t.stroke()},C.prototype._label=function(t,e,i,n){if(e){t.font=(this.from.selected||this.to.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle="white";var s=t.measureText(e).width,r=this.fontSize,o=i-s/2,a=n-r/2;t.fillRect(o,a,s,r),t.fillStyle=this.fontColor||"black",t.textAlign="left",t.textBaseline="top",t.fillText(e,o,a)}},C.prototype._drawDashLine=function(t){if(t.strokeStyle=this.color,t.lineWidth=this._getLineWidth(),t.beginPath(),t.lineCap="round",void 0!=this.dash.altLength?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]):void 0!=this.dash.length&&void 0!=this.dash.gap?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap]):(t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y)),t.stroke(),this.label){var e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}},C.prototype._pointOnLine=function(t){return{x:(1-t)*this.from.x+t*this.to.x,y:(1-t)*this.from.y+t*this.to.y}},C.prototype._pointOnCircle=function(t,e,i,n){var s=2*(n-3/8)*Math.PI;return{x:t+i*Math.cos(s),y:e-i*Math.sin(s)}},C.prototype._drawArrowCenter=function(t){var e;if(t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth(),this.from!=this.to){this._line(t);var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),n=10+5*this.width;e=this._pointOnLine(.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y))}else{var s,r,o=this.length/4,a=this.from;a.width||a.resize(t),a.width>a.height?(s=a.x+a.width/2,r=a.y-o):(s=a.x+o,r=a.y-a.height/2),this._circle(t,s,r,o);var i=.2*Math.PI,n=10+5*this.width;e=this._pointOnCircle(s,r,o,.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(s,r,o,.5),this._label(t,this.label,e.x,e.y))}},C.prototype._drawArrow=function(t){t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth();var e,i;if(this.from!=this.to){e=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x);var n=this.to.x-this.from.x,s=this.to.y-this.from.y,r=Math.sqrt(n*n+s*s),o=this.from.distanceToBorder(t,e+Math.PI),a=(r-o)/r,h=a*this.from.x+(1-a)*this.to.x,d=a*this.from.y+(1-a)*this.to.y,c=this.to.distanceToBorder(t,e),u=(r-c)/r,l=(1-u)*this.from.x+u*this.to.x,p=(1-u)*this.from.y+u*this.to.y;if(t.beginPath(),t.moveTo(h,d),t.lineTo(l,p),t.stroke(),i=10+5*this.width,t.arrow(l,p,e,i),t.fill(),t.stroke(),this.label){var f=this._pointOnLine(.5);this._label(t,this.label,f.x,f.y)}}else{var m,g,v,y=this.from,w=this.length/4;y.width||y.resize(t),y.width>y.height?(m=y.x+y.width/2,g=y.y-w,v={x:m,y:y.y,angle:.9*Math.PI}):(m=y.x+w,g=y.y-y.height/2,v={x:y.x,y:g,angle:.6*Math.PI}),t.beginPath(),t.arc(m,g,w,0,2*Math.PI,!1),t.stroke(),i=10+5*this.width,t.arrow(v.x,v.y,v.angle,i),t.fill(),t.stroke(),this.label&&(f=this._pointOnCircle(m,g,w,.5),this._label(t,this.label,f.x,f.y))}},C._dist=function(t,e,i,n,s,r){var o=i-t,a=n-e,h=o*o+a*a,d=((s-t)*o+(r-e)*a)/h;d>1?d=1:0>d&&(d=0);var c=t+d*o,u=e+d*a,l=c-s,p=u-r;return Math.sqrt(l*l+p*p)},O.prototype.setPosition=function(t,e){this.x=parseInt(t),this.y=parseInt(e)},O.prototype.setText=function(t){this.frame.innerHTML=t},O.prototype.show=function(t){if(void 0===t&&(t=!0),t){var e=this.frame.clientHeight,i=this.frame.clientWidth,n=this.frame.parentNode.clientHeight,s=this.frame.parentNode.clientWidth,r=this.y-e;r+e+this.padding>n&&(r=n-e-this.padding),rs&&(o=s-i-this.padding),o0?s[s.length-1]:null},N.prototype._getPointer=function(t){return{x:t.pageX-R.util.getAbsoluteLeft(this.frame.canvas),y:t.pageY-R.util.getAbsoluteTop(this.frame.canvas)}},N.prototype._onTouch=function(t){this.drag.pointer=this._getPointer(t.gesture.touches[0]),this.drag.pinched=!1,this.pinch.scale=this._getScale()},N.prototype._onDragStart=function(){var t=this.drag;t.selection=[],t.translation=this._getTranslation(),t.nodeId=this._getNodeAt(t.pointer);var e=this.nodes[t.nodeId];if(e){e.isSelected()||this._selectNodes([t.nodeId]);var i=this;this.selection.forEach(function(e){var n=i.nodes[e];if(n){var s={id:e,node:n,x:n.x,y:n.y,xFixed:n.xFixed,yFixed:n.yFixed};n.xFixed=!0,n.yFixed=!0,t.selection.push(s)}})}},N.prototype._onDrag=function(t){if(!this.drag.pinched){var e=this._getPointer(t.gesture.touches[0]),i=this,n=this.drag,s=n.selection;if(s&&s.length){var r=e.x-n.pointer.x,o=e.y-n.pointer.y;s.forEach(function(t){var e=t.node;t.xFixed||(e.x=i._canvasToX(i._xToCanvas(t.x)+r)),t.yFixed||(e.y=i._canvasToY(i._yToCanvas(t.y)+o))}),this.moving||(this.moving=!0,this.start())}else{var a=e.x-this.drag.pointer.x,h=e.y-this.drag.pointer.y;this._setTranslation(this.drag.translation.x+a,this.drag.translation.y+h),this._redraw(),this.moved=!0}}},N.prototype._onDragEnd=function(){var t=this.drag.selection;t&&t.forEach(function(t){t.node.xFixed=t.xFixed,t.node.yFixed=t.yFixed})},N.prototype._onTap=function(t){var e=this._getPointer(t.gesture.touches[0]),i=this._getNodeAt(e),n=this.nodes[i];n?(this._selectNodes([i]),this.moving||this._redraw()):(this._unselectNodes(),this._redraw())},N.prototype._onHold=function(t){var e=this._getPointer(t.gesture.touches[0]),i=this._getNodeAt(e),n=this.nodes[i];if(n){if(n.isSelected())this._unselectNodes([i]);else{var s=!0;this._selectNodes([i],s)}this.moving||this._redraw()}},N.prototype._onPinch=function(t){var e=this._getPointer(t.gesture.center);this.drag.pinched=!0,"scale"in this.pinch||(this.pinch.scale=1);var i=this.pinch.scale*t.gesture.scale;this._zoom(i,e)},N.prototype._zoom=function(t,e){var i=this._getScale();.01>t&&(t=.01),t>10&&(t=10);var n=this._getTranslation(),s=t/i,r=(1-s)*e.x+n.x*s,o=(1-s)*e.y+n.y*s;return this._setScale(t),this._setTranslation(r,o),this._redraw(),t},N.prototype._onMouseWheel=function(t){var e=0;if(t.wheelDelta?e=t.wheelDelta/120:t.detail&&(e=-t.detail/3),e){"mouswheelScale"in this.pinch||(this.pinch.mouswheelScale=1);var i=this.pinch.mouswheelScale,n=e/10;0>e&&(n/=1-n),i*=1+n;var s=A.fakeGesture(this,t),r=this._getPointer(s.center);i=this._zoom(i,r),this.pinch.mouswheelScale=i}t.preventDefault()},N.prototype._onMouseMoveTitle=function(t){var e=A.fakeGesture(this,t),i=this._getPointer(e.center);this.popupNode&&this._checkHidePopup(i);var n=this,s=function(){n._checkShowPopup(i)};this.popupTimer&&clearInterval(this.popupTimer),this.leftButtonDown||(this.popupTimer=setTimeout(s,300))},N.prototype._checkShowPopup=function(t){var e,i={left:this._canvasToX(t.x),top:this._canvasToY(t.y),right:this._canvasToX(t.x),bottom:this._canvasToY(t.y)},n=this.popupNode;if(void 0==this.popupNode){var s=this.nodes;for(e in s)if(s.hasOwnProperty(e)){var r=s[e];if(void 0!=r.getTitle()&&r.isOverlappingWith(i)){this.popupNode=r;break}}}if(void 0==this.popupNode){var o=this.edges;for(e in o)if(o.hasOwnProperty(e)){var a=o[e];if(a.connected&&void 0!=a.getTitle()&&a.isOverlappingWith(i)){this.popupNode=a;break}}}if(this.popupNode){if(this.popupNode!=n){var h=this;h.popup||(h.popup=new O(h.frame)),h.popup.setPosition(t.x-3,t.y-3),h.popup.setText(h.popupNode.getTitle()),h.popup.show()}}else this.popup&&this.popup.hide()},N.prototype._checkHidePopup=function(t){this.popupNode&&this._getNodeAt(t)||(this.popupNode=void 0,this.popup&&this.popup.hide())},N.prototype._unselectNodes=function(t,e){var i,n,s,r=!1;if(t)for(i=0,n=t.length;n>i;i++){s=t[i],this.nodes[s].unselect();for(var o=0;oi;i++)s=this.selection[i],this.nodes[s].unselect(),r=!0;this.selection=[]}return!r||1!=e&&void 0!=e||this._trigger("select"),r},N.prototype._selectNodes=function(t,e){var i,n,s=!1,r=!0;if(t.length!=this.selection.length)r=!1;else for(i=0,n=Math.min(t.length,this.selection.length);n>i;i++)if(t[i]!=this.selection[i]){r=!1;break}if(r)return s;if(void 0==e||0==e){var o=!1;s=this._unselectNodes(void 0,o)}for(i=0,n=t.length;n>i;i++){var a=t[i],h=-1!=this.selection.indexOf(a);h||(this.nodes[a].select(),this.selection.push(a),s=!0)}return s&&this._trigger("select"),s},N.prototype._getNodesOverlappingWith=function(t){var e=this.nodes,i=[];for(var n in e)e.hasOwnProperty(n)&&e[n].isOverlappingWith(t)&&i.push(n);return i},N.prototype.getSelection=function(){return this.selection.concat([])},N.prototype.setSelection=function(t){var e,i,n;if(!t||void 0==t.length)throw"Selection must be an array with ids";for(e=0,i=this.selection.length;i>e;e++)n=this.selection[e],this.nodes[n].unselect();for(this.selection=[],e=0,i=t.length;i>e;e++){n=t[e];var s=this.nodes[n];if(!s)throw new RangeError('Node with id "'+n+'" not found');s.select(),this.selection.push(n)}this.redraw()},N.prototype._updateSelection=function(){for(var t=0;ti;i++)for(var s=t[i],r=s.edges,o=0,a=r.length;a>o;o++){var h=r[o],d=null;h.from==s?d=h.to:h.to==s&&(d=h.from);var c,u;if(d)for(c=0,u=t.length;u>c;c++)if(t[c]==d){d=null;break}if(d)for(c=0,u=e.length;u>c;c++)if(e[c]==d){d=null;break}d&&e.push(d)}return e}void 0==t&&(t=1);var i=[],n=this.nodes;for(var s in n)if(n.hasOwnProperty(s)){for(var r=[n[s]],o=0;t>o;o++)r=r.concat(e(r));i.push(r)}for(var a=[],h=0,d=i.length;d>h;h++)a.push(i[h].length);return a},N.prototype.setSize=function(t,e){this.frame.style.width=t,this.frame.style.height=e,this.frame.canvas.style.width="100%",this.frame.canvas.style.height="100%",this.frame.canvas.width=this.frame.canvas.clientWidth,this.frame.canvas.height=this.frame.canvas.clientHeight},N.prototype._setNodes=function(t){var e=this.nodesData;if(t instanceof r||t instanceof o)this.nodesData=t;else if(t instanceof Array)this.nodesData=new r,this.nodesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.nodesData=new r}if(e&&A.forEach(this.nodesListeners,function(t,i){e.unsubscribe(i,t)}),this.nodes={},this.nodesData){var i=this;A.forEach(this.nodesListeners,function(t,e){i.nodesData.subscribe(e,t)});var n=this.nodesData.getIds();this._addNodes(n)}this._updateSelection()},N.prototype._addNodes=function(t){for(var e,i=0,n=t.length;n>i;i++){e=t[i];var s=this.nodesData.get(e),r=new M(s,this.images,this.groups,this.constants);if(this.nodes[e]=r,!r.isFixed()){var o=2*this.constants.edges.length,a=t.length,h=2*Math.PI*(i/a);r.x=o*Math.cos(h),r.y=o*Math.sin(h),this.moving=!0}}this._reconnectEdges(),this._updateValueRange(this.nodes)},N.prototype._updateNodes=function(t){for(var e=this.nodes,i=this.nodesData,n=0,s=t.length;s>n;n++){var r=t[n],o=e[r],a=i.get(r);o?o.setProperties(a,this.constants):(o=new M(properties,this.images,this.groups,this.constants),e[r]=o,o.isFixed()||(this.moving=!0))}this._reconnectEdges(),this._updateValueRange(e)},N.prototype._removeNodes=function(t){for(var e=this.nodes,i=0,n=t.length;n>i;i++){var s=t[i];delete e[s]}this._reconnectEdges(),this._updateSelection(),this._updateValueRange(e)},N.prototype._setEdges=function(t){var e=this.edgesData;if(t instanceof r||t instanceof o)this.edgesData=t;else if(t instanceof Array)this.edgesData=new r,this.edgesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.edgesData=new r}if(e&&A.forEach(this.edgesListeners,function(t,i){e.unsubscribe(i,t)}),this.edges={},this.edgesData){var i=this;A.forEach(this.edgesListeners,function(t,e){i.edgesData.subscribe(e,t)});var n=this.edgesData.getIds();this._addEdges(n)}this._reconnectEdges()},N.prototype._addEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var r=t[n],o=e[r];o&&o.disconnect();var a=i.get(r);e[r]=new C(a,this,this.constants)}this.moving=!0,this._updateValueRange(e)},N.prototype._updateEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var r=t[n],o=i.get(r),a=e[r];a?(a.disconnect(),a.setProperties(o,this.constants),a.connect()):(a=new C(o,this,this.constants),this.edges[r]=a)}this.moving=!0,this._updateValueRange(e)},N.prototype._removeEdges=function(t){for(var e=this.edges,i=0,n=t.length;n>i;i++){var s=t[i],r=e[s];r&&(r.disconnect(),delete e[s])}this.moving=!0,this._updateValueRange(e)},N.prototype._reconnectEdges=function(){var t,e=this.nodes,i=this.edges;for(t in e)e.hasOwnProperty(t)&&(e[t].edges=[]);for(t in i)if(i.hasOwnProperty(t)){var n=i[t];n.from=null,n.to=null,n.connect()}},N.prototype._updateValueRange=function(t){var e,i=void 0,n=void 0;for(e in t)if(t.hasOwnProperty(e)){var s=t[e].getValue();void 0!==s&&(i=void 0===i?s:Math.min(s,i),n=void 0===n?s:Math.max(s,n))}if(void 0!==i&&void 0!==n)for(e in t)t.hasOwnProperty(e)&&t[e].setValueRange(i,n)},N.prototype.redraw=function(){this.setSize(this.width,this.height),this._redraw()},N.prototype._redraw=function(){var t=this.frame.canvas.getContext("2d"),e=this.frame.canvas.width,i=this.frame.canvas.height;t.clearRect(0,0,e,i),t.save(),t.translate(this.translation.x,this.translation.y),t.scale(this.scale,this.scale),this._drawEdges(t),this._drawNodes(t),t.restore()},N.prototype._setTranslation=function(t,e){void 0===this.translation&&(this.translation={x:0,y:0}),void 0!==t&&(this.translation.x=t),void 0!==e&&(this.translation.y=e)},N.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},N.prototype._setScale=function(t){this.scale=t},N.prototype._getScale=function(){return this.scale},N.prototype._canvasToX=function(t){return(t-this.translation.x)/this.scale},N.prototype._xToCanvas=function(t){return t*this.scale+this.translation.x},N.prototype._canvasToY=function(t){return(t-this.translation.y)/this.scale},N.prototype._yToCanvas=function(t){return t*this.scale+this.translation.y},N.prototype._drawNodes=function(t){var e=this.nodes,i=[];for(var n in e)e.hasOwnProperty(n)&&(e[n].isSelected()?i.push(n):e[n].draw(t));for(var s=0,r=i.length;r>s;s++)e[i[s]].draw(t)},N.prototype._drawEdges=function(t){var e=this.edges;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];n.connected&&e[i].draw(t)}},N.prototype._doStabilize=function(){for(var t=(new Date,0),e=this.constants.minVelocity,i=!1;!i&&t0&&e==s.EVENT_END?e=s.EVENT_MOVE:c||(e=s.EVENT_END),c||null===r?r=h:h=r,i.call(s.detection,n.collectEventData(t,e,h)),s.HAS_POINTEREVENTS&&e==s.EVENT_END&&(c=s.PointerEvent.updatePointer(e,h))),c||(r=null,o=!1,a=!1,s.PointerEvent.reset())}})},determineEventTypes:function(){var t;t=s.HAS_POINTEREVENTS?s.PointerEvent.getEvents():s.NO_MOUSEEVENTS?["touchstart","touchmove","touchend touchcancel"]:["touchstart mousedown","touchmove mousemove","touchend touchcancel mouseup"],s.EVENT_TYPES[s.EVENT_START]=t[0],s.EVENT_TYPES[s.EVENT_MOVE]=t[1],s.EVENT_TYPES[s.EVENT_END]=t[2]},getTouchList:function(t){return s.HAS_POINTEREVENTS?s.PointerEvent.getTouchList():t.touches?t.touches:[{identifier:1,pageX:t.pageX,pageY:t.pageY,target:t.target}]},collectEventData:function(t,e,i){var n=this.getTouchList(i,e),r=s.POINTER_TOUCH;return(i.type.match(/mouse/)||s.PointerEvent.matchType(s.POINTER_MOUSE,i))&&(r=s.POINTER_MOUSE),{center:s.utils.getCenter(n),timeStamp:(new Date).getTime(),target:i.target,touches:n,eventType:e,pointerType:r,srcEvent:i,preventDefault:function(){this.srcEvent.preventManipulation&&this.srcEvent.preventManipulation(),this.srcEvent.preventDefault&&this.srcEvent.preventDefault()},stopPropagation:function(){this.srcEvent.stopPropagation()},stopDetect:function(){return s.detection.stopDetect()}}}},s.PointerEvent={pointers:{},getTouchList:function(){var t=this,e=[];return Object.keys(t.pointers).sort().forEach(function(i){e.push(t.pointers[i])}),e},updatePointer:function(t,e){return t==s.EVENT_END?this.pointers={}:(e.identifier=e.pointerId,this.pointers[e.pointerId]=e),Object.keys(this.pointers).length},matchType:function(t,e){if(!e.pointerType)return!1;var i={};return i[s.POINTER_MOUSE]=e.pointerType==e.MSPOINTER_TYPE_MOUSE||e.pointerType==s.POINTER_MOUSE,i[s.POINTER_TOUCH]=e.pointerType==e.MSPOINTER_TYPE_TOUCH||e.pointerType==s.POINTER_TOUCH,i[s.POINTER_PEN]=e.pointerType==e.MSPOINTER_TYPE_PEN||e.pointerType==s.POINTER_PEN,i[t]},getEvents:function(){return["pointerdown MSPointerDown","pointermove MSPointerMove","pointerup pointercancel MSPointerUp MSPointerCancel"]},reset:function(){this.pointers={}}},s.utils={extend:function(t,e,n){for(var s in e)t[s]!==i&&n||(t[s]=e[s]);return t},hasParent:function(t,e){for(;t;){if(t==e)return!0;t=t.parentNode}return!1},getCenter:function(t){for(var e=[],i=[],n=0,s=t.length;s>n;n++)e.push(t[n].pageX),i.push(t[n].pageY);return{pageX:(Math.min.apply(Math,e)+Math.max.apply(Math,e))/2,pageY:(Math.min.apply(Math,i)+Math.max.apply(Math,i))/2}},getVelocity:function(t,e,i){return{x:Math.abs(e/t)||0,y:Math.abs(i/t)||0}},getAngle:function(t,e){var i=e.pageY-t.pageY,n=e.pageX-t.pageX;return 180*Math.atan2(i,n)/Math.PI},getDirection:function(t,e){var i=Math.abs(t.pageX-e.pageX),n=Math.abs(t.pageY-e.pageY);return i>=n?t.pageX-e.pageX>0?s.DIRECTION_LEFT:s.DIRECTION_RIGHT:t.pageY-e.pageY>0?s.DIRECTION_UP:s.DIRECTION_DOWN},getDistance:function(t,e){var i=e.pageX-t.pageX,n=e.pageY-t.pageY;return Math.sqrt(i*i+n*n)},getScale:function(t,e){return t.length>=2&&e.length>=2?this.getDistance(e[0],e[1])/this.getDistance(t[0],t[1]):1},getRotation:function(t,e){return t.length>=2&&e.length>=2?this.getAngle(e[1],e[0])-this.getAngle(t[1],t[0]):0},isVertical:function(t){return t==s.DIRECTION_UP||t==s.DIRECTION_DOWN},stopDefaultBrowserBehavior:function(t,e){var i,n=["webkit","khtml","moz","ms","o",""];if(e&&t.style){for(var s=0;si;i++){var r=this.gestures[i];if(!this.stopped&&e[r.name]!==!1&&r.handler.call(r,t,this.current.inst)===!1){this.stopDetect();break}}return this.current&&(this.current.lastEvent=t),t.eventType==s.EVENT_END&&!t.touches.length-1&&this.stopDetect(),t}},stopDetect:function(){this.previous=s.utils.extend({},this.current),this.current=null,this.stopped=!0},extendEventData:function(t){var e=this.current.startEvent; -if(e&&(t.touches.length!=e.touches.length||t.touches===e.touches)){e.touches=[];for(var i=0,n=t.touches.length;n>i;i++)e.touches.push(s.utils.extend({},t.touches[i]))}var r=t.timeStamp-e.timeStamp,o=t.center.pageX-e.center.pageX,a=t.center.pageY-e.center.pageY,h=s.utils.getVelocity(r,o,a);return s.utils.extend(t,{deltaTime:r,deltaX:o,deltaY:a,velocityX:h.x,velocityY:h.y,distance:s.utils.getDistance(e.center,t.center),angle:s.utils.getAngle(e.center,t.center),direction:s.utils.getDirection(e.center,t.center),scale:s.utils.getScale(e.touches,t.touches),rotation:s.utils.getRotation(e.touches,t.touches),startEvent:e}),t},register:function(t){var e=t.defaults||{};return e[t.name]===i&&(e[t.name]=!0),s.utils.extend(s.defaults,e,!0),t.index=t.index||1e3,this.gestures.push(t),this.gestures.sort(function(t,e){return t.indexe.index?1:0}),this.gestures}},s.gestures=s.gestures||{},s.gestures.Hold={name:"hold",index:10,defaults:{hold_timeout:500,hold_threshold:1},timer:null,handler:function(t,e){switch(t.eventType){case s.EVENT_START:clearTimeout(this.timer),s.detection.current.name=this.name,this.timer=setTimeout(function(){"hold"==s.detection.current.name&&e.trigger("hold",t)},e.options.hold_timeout);break;case s.EVENT_MOVE:t.distance>e.options.hold_threshold&&clearTimeout(this.timer);break;case s.EVENT_END:clearTimeout(this.timer)}}},s.gestures.Tap={name:"tap",index:100,defaults:{tap_max_touchtime:250,tap_max_distance:10,tap_always:!0,doubletap_distance:20,doubletap_interval:300},handler:function(t,e){if(t.eventType==s.EVENT_END){var i=s.detection.previous,n=!1;if(t.deltaTime>e.options.tap_max_touchtime||t.distance>e.options.tap_max_distance)return;i&&"tap"==i.name&&t.timeStamp-i.lastEvent.timeStamp0&&t.touches.length>e.options.swipe_max_touches)return;(t.velocityX>e.options.swipe_velocity||t.velocityY>e.options.swipe_velocity)&&(e.trigger(this.name,t),e.trigger(this.name+t.direction,t))}}},s.gestures.Drag={name:"drag",index:50,defaults:{drag_min_distance:10,drag_max_touches:1,drag_block_horizontal:!1,drag_block_vertical:!1,drag_lock_to_axis:!1,drag_lock_min_distance:25},triggered:!1,handler:function(t,e){if(s.detection.current.name!=this.name&&this.triggered)return e.trigger(this.name+"end",t),this.triggered=!1,void 0;if(!(e.options.drag_max_touches>0&&t.touches.length>e.options.drag_max_touches))switch(t.eventType){case s.EVENT_START:this.triggered=!1;break;case s.EVENT_MOVE:if(t.distancee.options.transform_min_rotation&&e.trigger("rotate",t),i>e.options.transform_min_scale&&(e.trigger("pinch",t),e.trigger("pinch"+(t.scale<1?"in":"out"),t));break;case s.EVENT_END:this.triggered&&e.trigger(this.name+"end",t),this.triggered=!1}}},s.gestures.Touch={name:"touch",index:-1/0,defaults:{prevent_default:!1,prevent_mouseevents:!1},handler:function(t,e){return e.options.prevent_mouseevents&&t.pointerType==s.POINTER_MOUSE?(t.stopDetect(),void 0):(e.options.prevent_default&&t.preventDefault(),t.eventType==s.EVENT_START&&e.trigger(this.name,t),void 0)}},s.gestures.Release={name:"release",index:1/0,handler:function(t,e){t.eventType==s.EVENT_END&&e.trigger(this.name,t)}},"object"==typeof e&&"object"==typeof e.exports?e.exports=s:(t.Hammer=s,"function"==typeof t.define&&t.define.amd&&t.define("hammer",[],function(){return s}))}(this)},{}],3:[function(e,i){(function(n){function s(t,e){return function(i){return u(t.call(this,i),e)}}function r(t,e){return function(i){return this.lang().ordinal(t.call(this,i),e)}}function o(){}function a(t){T(t),d(this,t)}function h(t){var e=v(t),i=e.year||0,n=e.month||0,s=e.week||0,r=e.day||0,o=e.hour||0,a=e.minute||0,h=e.second||0,d=e.millisecond||0;this._milliseconds=+d+1e3*h+6e4*a+36e5*o,this._days=+r+7*s,this._months=+n+12*i,this._data={},this._bubble()}function d(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return e.hasOwnProperty("toString")&&(t.toString=e.toString),e.hasOwnProperty("valueOf")&&(t.valueOf=e.valueOf),t}function c(t){return 0>t?Math.ceil(t):Math.floor(t)}function u(t,e,i){for(var n=Math.abs(t)+"",s=t>=0;n.lengthn;n++)(i&&t[n]!==e[n]||!i&&w(t[n])!==w(e[n]))&&o++;return o+r}function g(t){if(t){var e=t.toLowerCase().replace(/(.)s$/,"$1");t=Ge[t]||Be[e]||e}return t}function v(t){var e,i,n={};for(i in t)t.hasOwnProperty(i)&&(e=g(i),e&&(n[e]=t[i]));return n}function y(t){var e,i;if(0===t.indexOf("week"))e=7,i="day";else{if(0!==t.indexOf("month"))return;e=12,i="month"}re[t]=function(s,r){var o,a,h=re.fn._lang[t],d=[];if("number"==typeof s&&(r=s,s=n),a=function(t){var e=re().utc().set(i,t);return h.call(re.fn._lang,e,s||"")},null!=r)return a(r);for(o=0;e>o;o++)d.push(a(o));return d}}function w(t){var e=+t,i=0;return 0!==e&&isFinite(e)&&(i=e>=0?Math.floor(e):Math.ceil(e)),i}function _(t,e){return new Date(Date.UTC(t,e+1,0)).getUTCDate()}function b(t){return E(t)?366:365}function E(t){return t%4===0&&t%100!==0||t%400===0}function T(t){var e;t._a&&-2===t._pf.overflow&&(e=t._a[ue]<0||t._a[ue]>11?ue:t._a[le]<1||t._a[le]>_(t._a[ce],t._a[ue])?le:t._a[pe]<0||t._a[pe]>23?pe:t._a[fe]<0||t._a[fe]>59?fe:t._a[me]<0||t._a[me]>59?me:t._a[ge]<0||t._a[ge]>999?ge:-1,t._pf._overflowDayOfYear&&(ce>e||e>le)&&(e=le),t._pf.overflow=e)}function S(t){t._pf={empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function x(t){return null==t._isValid&&(t._isValid=!isNaN(t._d.getTime())&&t._pf.overflow<0&&!t._pf.empty&&!t._pf.invalidMonth&&!t._pf.nullInput&&!t._pf.invalidFormat&&!t._pf.userInvalidated,t._strict&&(t._isValid=t._isValid&&0===t._pf.charsLeftOver&&0===t._pf.unusedTokens.length)),t._isValid}function D(t){return t?t.toLowerCase().replace("_","-"):t}function M(t,e){return e._isUTC?re(t).zone(e._offset||0):re(t).local()}function C(t,e){return e.abbr=t,ve[t]||(ve[t]=new o),ve[t].set(e),ve[t]}function O(t){delete ve[t]}function N(t){var i,n,s,r,o=0,a=function(t){if(!ve[t]&&ye)try{e("./lang/"+t)}catch(i){}return ve[t]};if(!t)return re.fn._lang;if(!p(t)){if(n=a(t))return n;t=[t]}for(;o0;){if(n=a(r.slice(0,i).join("-")))return n;if(s&&s.length>=i&&m(r,s,!0)>=i-1)break;i--}o++}return re.fn._lang}function L(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function I(t){var e,i,n=t.match(Ee);for(e=0,i=n.length;i>e;e++)n[e]=Ke[n[e]]?Ke[n[e]]:L(n[e]);return function(s){var r="";for(e=0;i>e;e++)r+=n[e]instanceof Function?n[e].call(s,t):n[e];return r}}function k(t,e){return t.isValid()?(e=A(e,t.lang()),qe[e]||(qe[e]=I(e)),qe[e](t)):t.lang().invalidDate()}function A(t,e){function i(t){return e.longDateFormat(t)||t}var n=5;for(Te.lastIndex=0;n>=0&&Te.test(t);)t=t.replace(Te,i),Te.lastIndex=0,n-=1;return t}function P(t,e){var i,n=e._strict;switch(t){case"DDDD":return Pe;case"YYYY":case"GGGG":case"gggg":return n?Ye:De;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return n?Fe:Me;case"S":if(n)return ke;case"SS":if(n)return Ae;case"SSS":case"DDD":return n?Pe:xe;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Oe;case"a":case"A":return N(e._l)._meridiemParse;case"X":return Ie;case"Z":case"ZZ":return Ne;case"T":return Le;case"SSSS":return Ce;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return n?Ae:Se;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return n?ke:Se;default:return i=new RegExp(j(W(t.replace("\\","")),"i"))}}function Y(t){t=t||"";var e=t.match(Ne)||[],i=e[e.length-1]||[],n=(i+"").match(We)||["-",0,0],s=+(60*n[1])+w(n[2]);return"+"===n[0]?-s:s}function F(t,e,i){var n,s=i._a;switch(t){case"M":case"MM":null!=e&&(s[ue]=w(e)-1);break;case"MMM":case"MMMM":n=N(i._l).monthsParse(e),null!=n?s[ue]=n:i._pf.invalidMonth=e;break;case"D":case"DD":null!=e&&(s[le]=w(e));break;case"DDD":case"DDDD":null!=e&&(i._dayOfYear=w(e));break;case"YY":s[ce]=w(e)+(w(e)>68?1900:2e3);break;case"YYYY":case"YYYYY":case"YYYYYY":s[ce]=w(e);break;case"a":case"A":i._isPm=N(i._l).isPM(e);break;case"H":case"HH":case"h":case"hh":s[pe]=w(e);break;case"m":case"mm":s[fe]=w(e);break;case"s":case"ss":s[me]=w(e);break;case"S":case"SS":case"SSS":case"SSSS":s[ge]=w(1e3*("0."+e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,i._tzm=Y(e);break;case"w":case"ww":case"W":case"WW":case"d":case"dd":case"ddd":case"dddd":case"e":case"E":t=t.substr(0,1);case"gg":case"gggg":case"GG":case"GGGG":case"GGGGG":t=t.substr(0,2),e&&(i._w=i._w||{},i._w[t]=e)}}function R(t){var e,i,n,s,r,o,a,h,d,c,u=[];if(!t._d){for(n=z(t),t._w&&null==t._a[le]&&null==t._a[ue]&&(r=function(e){var i=parseInt(e,10);return e?e.length<3?i>68?1900+i:2e3+i:i:null==t._a[ce]?re().weekYear():t._a[ce]},o=t._w,null!=o.GG||null!=o.W||null!=o.E?a=J(r(o.GG),o.W||1,o.E,4,1):(h=N(t._l),d=null!=o.d?Z(o.d,h):null!=o.e?parseInt(o.e,10)+h._week.dow:0,c=parseInt(o.w,10)||1,null!=o.d&&db(s)&&(t._pf._overflowDayOfYear=!0),i=X(s,0,t._dayOfYear),t._a[ue]=i.getUTCMonth(),t._a[le]=i.getUTCDate()),e=0;3>e&&null==t._a[e];++e)t._a[e]=u[e]=n[e];for(;7>e;e++)t._a[e]=u[e]=null==t._a[e]?2===e?1:0:t._a[e];u[pe]+=w((t._tzm||0)/60),u[fe]+=w((t._tzm||0)%60),t._d=(t._useUTC?X:q).apply(null,u)}}function H(t){var e;t._d||(e=v(t._i),t._a=[e.year,e.month,e.day,e.hour,e.minute,e.second,e.millisecond],R(t))}function z(t){var e=new Date;return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function U(t){t._a=[],t._pf.empty=!0;var e,i,n,s,r,o=N(t._l),a=""+t._i,h=a.length,d=0;for(n=A(t._f,o).match(Ee)||[],e=0;e0&&t._pf.unusedInput.push(r),a=a.slice(a.indexOf(i)+i.length),d+=i.length),Ke[s]?(i?t._pf.empty=!1:t._pf.unusedTokens.push(s),F(s,i,t)):t._strict&&!i&&t._pf.unusedTokens.push(s);t._pf.charsLeftOver=h-d,a.length>0&&t._pf.unusedInput.push(a),t._isPm&&t._a[pe]<12&&(t._a[pe]+=12),t._isPm===!1&&12===t._a[pe]&&(t._a[pe]=0),R(t),T(t)}function W(t){return t.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,i,n,s){return e||i||n||s})}function j(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function V(t){var e,i,n,s,r;if(0===t._f.length)return t._pf.invalidFormat=!0,t._d=new Date(0/0),void 0;for(s=0;sr)&&(n=r,i=e));d(t,i||e)}function G(t){var e,i=t._i,n=Re.exec(i);if(n){for(t._pf.iso=!0,e=4;e>0;e--)if(n[e]){t._f=ze[e-1]+(n[6]||" ");break}for(e=0;4>e;e++)if(Ue[e][1].exec(i)){t._f+=Ue[e][0];break}i.match(Ne)&&(t._f+="Z"),U(t)}else t._d=new Date(i)}function B(t){var e=t._i,i=we.exec(e);e===n?t._d=new Date:i?t._d=new Date(+i[1]):"string"==typeof e?G(t):p(e)?(t._a=e.slice(0),R(t)):f(e)?t._d=new Date(+e):"object"==typeof e?H(t):t._d=new Date(e)}function q(t,e,i,n,s,r,o){var a=new Date(t,e,i,n,s,r,o);return 1970>t&&a.setFullYear(t),a}function X(t){var e=new Date(Date.UTC.apply(null,arguments));return 1970>t&&e.setUTCFullYear(t),e}function Z(t,e){if("string"==typeof t)if(isNaN(t)){if(t=e.weekdaysParse(t),"number"!=typeof t)return null}else t=parseInt(t,10);return t}function K(t,e,i,n,s){return s.relativeTime(e||1,!!i,t,n)}function Q(t,e,i){var n=de(Math.abs(t)/1e3),s=de(n/60),r=de(s/60),o=de(r/24),a=de(o/365),h=45>n&&["s",n]||1===s&&["m"]||45>s&&["mm",s]||1===r&&["h"]||22>r&&["hh",r]||1===o&&["d"]||25>=o&&["dd",o]||45>=o&&["M"]||345>o&&["MM",de(o/30)]||1===a&&["y"]||["yy",a];return h[2]=e,h[3]=t>0,h[4]=i,K.apply({},h)}function $(t,e,i){var n,s=i-e,r=i-t.day();return r>s&&(r-=7),s-7>r&&(r+=7),n=re(t).add("d",r),{week:Math.ceil(n.dayOfYear()/7),year:n.year()}}function J(t,e,i,n,s){var r,o,a=new Date(u(t,6,!0)+"-01-01").getUTCDay();return i=null!=i?i:s,r=s-a+(a>n?7:0),o=7*(e-1)+(i-s)+r+1,{year:o>0?t:t-1,dayOfYear:o>0?o:b(t-1)+o}}function te(t){var e=t._i,i=t._f;return"undefined"==typeof t._pf&&S(t),null===e?re.invalid({nullInput:!0}):("string"==typeof e&&(t._i=e=N().preparse(e)),re.isMoment(e)?(t=d({},e),t._d=new Date(+e._d)):i?p(i)?V(t):U(t):B(t),new a(t))}function ee(t,e){re.fn[t]=re.fn[t+"s"]=function(t){var i=this._isUTC?"UTC":"";return null!=t?(this._d["set"+i+e](t),re.updateOffset(this),this):this._d["get"+i+e]()}}function ie(t){re.duration.fn[t]=function(){return this._data[t]}}function ne(t,e){re.duration.fn["as"+t]=function(){return+this/e}}function se(t){var e=!1,i=re;"undefined"==typeof ender&&(t?(he.moment=function(){return!e&&console&&console.warn&&(e=!0,console.warn("Accessing Moment through the global scope is deprecated, and will be removed in an upcoming release.")),i.apply(null,arguments)},d(he.moment,i)):he.moment=re)}for(var re,oe,ae="2.5.0",he=this,de=Math.round,ce=0,ue=1,le=2,pe=3,fe=4,me=5,ge=6,ve={},ye="undefined"!=typeof i&&i.exports&&"undefined"!=typeof e,we=/^\/?Date\((\-?\d+)/i,_e=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,be=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,Ee=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g,Te=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,Se=/\d\d?/,xe=/\d{1,3}/,De=/\d{1,4}/,Me=/[+\-]?\d{1,6}/,Ce=/\d+/,Oe=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Ne=/Z|[\+\-]\d\d:?\d\d/gi,Le=/T/i,Ie=/[\+\-]?\d+(\.\d{1,3})?/,ke=/\d/,Ae=/\d\d/,Pe=/\d{3}/,Ye=/\d{4}/,Fe=/[+\-]?\d{6}/,Re=/^\s*\d{4}-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,He="YYYY-MM-DDTHH:mm:ssZ",ze=["YYYY-MM-DD","GGGG-[W]WW","GGGG-[W]WW-E","YYYY-DDD"],Ue=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d{1,3}/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],We=/([\+\-]|\d\d)/gi,je="Date|Hours|Minutes|Seconds|Milliseconds".split("|"),Ve={Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6},Ge={ms:"millisecond",s:"second",m:"minute",h:"hour",d:"day",D:"date",w:"week",W:"isoWeek",M:"month",y:"year",DDD:"dayOfYear",e:"weekday",E:"isoWeekday",gg:"weekYear",GG:"isoWeekYear"},Be={dayofyear:"dayOfYear",isoweekday:"isoWeekday",isoweek:"isoWeek",weekyear:"weekYear",isoweekyear:"isoWeekYear"},qe={},Xe="DDD w W M D d".split(" "),Ze="M D H h m s w W".split(" "),Ke={M:function(){return this.month()+1},MMM:function(t){return this.lang().monthsShort(this,t)},MMMM:function(t){return this.lang().months(this,t)},D:function(){return this.date()},DDD:function(){return this.dayOfYear()},d:function(){return this.day()},dd:function(t){return this.lang().weekdaysMin(this,t)},ddd:function(t){return this.lang().weekdaysShort(this,t)},dddd:function(t){return this.lang().weekdays(this,t)},w:function(){return this.week()},W:function(){return this.isoWeek()},YY:function(){return u(this.year()%100,2)},YYYY:function(){return u(this.year(),4)},YYYYY:function(){return u(this.year(),5)},YYYYYY:function(){var t=this.year(),e=t>=0?"+":"-";return e+u(Math.abs(t),6)},gg:function(){return u(this.weekYear()%100,2)},gggg:function(){return this.weekYear()},ggggg:function(){return u(this.weekYear(),5)},GG:function(){return u(this.isoWeekYear()%100,2)},GGGG:function(){return this.isoWeekYear()},GGGGG:function(){return u(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.lang().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.lang().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return w(this.milliseconds()/100)},SS:function(){return u(w(this.milliseconds()/10),2)},SSS:function(){return u(this.milliseconds(),3)},SSSS:function(){return u(this.milliseconds(),3)},Z:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+u(w(t/60),2)+":"+u(w(t)%60,2)},ZZ:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+u(w(t/60),2)+u(w(t)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},X:function(){return this.unix()},Q:function(){return this.quarter()}},Qe=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"];Xe.length;)oe=Xe.pop(),Ke[oe+"o"]=r(Ke[oe],oe);for(;Ze.length;)oe=Ze.pop(),Ke[oe+oe]=s(Ke[oe],2);for(Ke.DDDD=s(Ke.DDD,3),d(o.prototype,{set:function(t){var e,i;for(i in t)e=t[i],"function"==typeof e?this[i]=e:this["_"+i]=e},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(t){return this._months[t.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(t){return this._monthsShort[t.month()]},monthsParse:function(t){var e,i,n;for(this._monthsParse||(this._monthsParse=[]),e=0;12>e;e++)if(this._monthsParse[e]||(i=re.utc([2e3,e]),n="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[e]=new RegExp(n.replace(".",""),"i")),this._monthsParse[e].test(t))return e},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(t){return this._weekdays[t.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(t){return this._weekdaysShort[t.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(t){return this._weekdaysMin[t.day()]},weekdaysParse:function(t){var e,i,n;for(this._weekdaysParse||(this._weekdaysParse=[]),e=0;7>e;e++)if(this._weekdaysParse[e]||(i=re([2e3,1]).day(e),n="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[e]=new RegExp(n.replace(".",""),"i")),this._weekdaysParse[e].test(t))return e},_longDateFormat:{LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D YYYY",LLL:"MMMM D YYYY LT",LLLL:"dddd, MMMM D YYYY LT"},longDateFormat:function(t){var e=this._longDateFormat[t];return!e&&this._longDateFormat[t.toUpperCase()]&&(e=this._longDateFormat[t.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t]=e),e},isPM:function(t){return"p"===(t+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(t,e,i){return t>11?i?"pm":"PM":i?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(t,e){var i=this._calendar[t];return"function"==typeof i?i.apply(e):i},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(t,e,i,n){var s=this._relativeTime[i];return"function"==typeof s?s(t,e,i,n):s.replace(/%d/i,t)},pastFuture:function(t,e){var i=this._relativeTime[t>0?"future":"past"];return"function"==typeof i?i(e):i.replace(/%s/i,e)},ordinal:function(t){return this._ordinal.replace("%d",t)},_ordinal:"%d",preparse:function(t){return t},postformat:function(t){return t},week:function(t){return $(t,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),re=function(t,e,i,s){return"boolean"==typeof i&&(s=i,i=n),te({_i:t,_f:e,_l:i,_strict:s,_isUTC:!1})},re.utc=function(t,e,i,s){var r;return"boolean"==typeof i&&(s=i,i=n),r=te({_useUTC:!0,_isUTC:!0,_l:i,_i:t,_f:e,_strict:s}).utc()},re.unix=function(t){return re(1e3*t)},re.duration=function(t,e){var i,n,s,r=t,o=null;return re.isDuration(t)?r={ms:t._milliseconds,d:t._days,M:t._months}:"number"==typeof t?(r={},e?r[e]=t:r.milliseconds=t):(o=_e.exec(t))?(i="-"===o[1]?-1:1,r={y:0,d:w(o[le])*i,h:w(o[pe])*i,m:w(o[fe])*i,s:w(o[me])*i,ms:w(o[ge])*i}):(o=be.exec(t))&&(i="-"===o[1]?-1:1,s=function(t){var e=t&&parseFloat(t.replace(",","."));return(isNaN(e)?0:e)*i},r={y:s(o[2]),M:s(o[3]),d:s(o[4]),h:s(o[5]),m:s(o[6]),s:s(o[7]),w:s(o[8])}),n=new h(r),re.isDuration(t)&&t.hasOwnProperty("_lang")&&(n._lang=t._lang),n},re.version=ae,re.defaultFormat=He,re.updateOffset=function(){},re.lang=function(t,e){var i;return t?(e?C(D(t),e):null===e?(O(t),t="en"):ve[t]||N(t),i=re.duration.fn._lang=re.fn._lang=N(t),i._abbr):re.fn._lang._abbr},re.langData=function(t){return t&&t._lang&&t._lang._abbr&&(t=t._lang._abbr),N(t)},re.isMoment=function(t){return t instanceof a},re.isDuration=function(t){return t instanceof h},oe=Qe.length-1;oe>=0;--oe)y(Qe[oe]);for(re.normalizeUnits=function(t){return g(t)},re.invalid=function(t){var e=re.utc(0/0);return null!=t?d(e._pf,t):e._pf.userInvalidated=!0,e},re.parseZone=function(t){return re(t).parseZone()},d(re.fn=a.prototype,{clone:function(){return re(this)},valueOf:function(){return+this._d+6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().lang("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){var t=re(this).utc();return 00:!1},parsingFlags:function(){return d({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(){return this.zone(0)},local:function(){return this.zone(0),this._isUTC=!1,this},format:function(t){var e=k(this,t||re.defaultFormat);return this.lang().postformat(e)},add:function(t,e){var i;return i="string"==typeof t?re.duration(+e,t):re.duration(t,e),l(this,i,1),this},subtract:function(t,e){var i;return i="string"==typeof t?re.duration(+e,t):re.duration(t,e),l(this,i,-1),this},diff:function(t,e,i){var n,s,r=M(t,this),o=6e4*(this.zone()-r.zone());return e=g(e),"year"===e||"month"===e?(n=432e5*(this.daysInMonth()+r.daysInMonth()),s=12*(this.year()-r.year())+(this.month()-r.month()),s+=(this-re(this).startOf("month")-(r-re(r).startOf("month")))/n,s-=6e4*(this.zone()-re(this).startOf("month").zone()-(r.zone()-re(r).startOf("month").zone()))/n,"year"===e&&(s/=12)):(n=this-r,s="second"===e?n/1e3:"minute"===e?n/6e4:"hour"===e?n/36e5:"day"===e?(n-o)/864e5:"week"===e?(n-o)/6048e5:n),i?s:c(s)},from:function(t,e){return re.duration(this.diff(t)).lang(this.lang()._abbr).humanize(!e)},fromNow:function(t){return this.from(re(),t)},calendar:function(){var t=M(re(),this).startOf("day"),e=this.diff(t,"days",!0),i=-6>e?"sameElse":-1>e?"lastWeek":0>e?"lastDay":1>e?"sameDay":2>e?"nextDay":7>e?"nextWeek":"sameElse";return this.format(this.lang().calendar(i,this))},isLeapYear:function(){return E(this.year())},isDST:function(){return this.zone()+re(t).startOf(e)},isBefore:function(t,e){return e="undefined"!=typeof e?e:"millisecond",+this.clone().startOf(e)<+re(t).startOf(e)},isSame:function(t,e){return e=e||"ms",+this.clone().startOf(e)===+M(t,this).startOf(e)},min:function(t){return t=re.apply(null,arguments),this>t?this:t},max:function(t){return t=re.apply(null,arguments),t>this?this:t},zone:function(t){var e=this._offset||0;return null==t?this._isUTC?e:this._d.getTimezoneOffset():("string"==typeof t&&(t=Y(t)),Math.abs(t)<16&&(t=60*t),this._offset=t,this._isUTC=!0,e!==t&&l(this,re.duration(e-t,"m"),1,!0),this)},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.zone(this._tzm):"string"==typeof this._i&&this.zone(this._i),this},hasAlignedHourOffset:function(t){return t=t?re(t).zone():0,(this.zone()-t)%60===0},daysInMonth:function(){return _(this.year(),this.month())},dayOfYear:function(t){var e=de((re(this).startOf("day")-re(this).startOf("year"))/864e5)+1;return null==t?e:this.add("d",t-e)},quarter:function(){return Math.ceil((this.month()+1)/3)},weekYear:function(t){var e=$(this,this.lang()._week.dow,this.lang()._week.doy).year;return null==t?e:this.add("y",t-e)},isoWeekYear:function(t){var e=$(this,1,4).year;return null==t?e:this.add("y",t-e)},week:function(t){var e=this.lang().week(this);return null==t?e:this.add("d",7*(t-e))},isoWeek:function(t){var e=$(this,1,4).week;return null==t?e:this.add("d",7*(t-e))},weekday:function(t){var e=(this.day()+7-this.lang()._week.dow)%7;return null==t?e:this.add("d",t-e)},isoWeekday:function(t){return null==t?this.day()||7:this.day(this.day()%7?t:t-7)},get:function(t){return t=g(t),this[t]()},set:function(t,e){return t=g(t),"function"==typeof this[t]&&this[t](e),this},lang:function(t){return t===n?this._lang:(this._lang=N(t),this)}}),oe=0;oei;++i)t.call(e||this,this[i],i,this)}),Array.prototype.map||(Array.prototype.map=function(t,e){var i,n,s;if(null==this)throw new TypeError(" this is null or not defined");var o=Object(this),r=o.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(e&&(i=e),n=new Array(r),s=0;r>s;){var a,h;s in o&&(a=o[s],h=t.call(i,a,s,o),n[s]=h),s++}return n}),Array.prototype.filter||(Array.prototype.filter=function(t){"use strict";if(null==this)throw new TypeError;var e=Object(this),i=e.length>>>0;if("function"!=typeof t)throw new TypeError;for(var n=[],s=arguments[1],o=0;i>o;o++)if(o in e){var r=e[o];t.call(s,r,o,e)&&n.push(r)}return n}),Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,e=!{toString:null}.propertyIsEnumerable("toString"),i=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],n=i.length;return function(s){if("object"!=typeof s&&"function"!=typeof s||null===s)throw new TypeError("Object.keys called on non-object");var o=[];for(var r in s)t.call(s,r)&&o.push(r);if(e)for(var a=0;n>a;a++)t.call(s,i[a])&&o.push(i[a]);return o}}()),Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s}),Object.create||(Object.create=function(t){function e(){}if(arguments.length>1)throw new Error("Object.create implementation only accepts the first parameter.");return e.prototype=t,new e}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s});var z={};z.isNumber=function(t){return t instanceof Number||"number"==typeof t},z.isString=function(t){return t instanceof String||"string"==typeof t},z.isDate=function(t){if(t instanceof Date)return!0;if(z.isString(t)){var e=P.exec(t);if(e)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},z.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},z.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},z.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var n=arguments[e];for(var s in n)n.hasOwnProperty(s)&&void 0!==n[s]&&(t[s]=n[s])}return t},z.convert=function(t,e){var i;if(void 0===t)return void 0;if(null===t)return null;if(!e)return t;if("string"!=typeof e&&!(e instanceof String))throw new Error("Type must be a string");switch(e){case"boolean":case"Boolean":return Boolean(t);case"number":case"Number":return Number(t.valueOf());case"string":case"String":return String(t);case"Date":if(z.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(L.isMoment(t))return new Date(t.valueOf());if(z.isString(t))return i=P.exec(t),i?new Date(Number(i[1])):L(t).toDate();throw new Error("Cannot convert object of type "+z.getType(t)+" to type Date");case"Moment":if(z.isNumber(t))return L(t);if(t instanceof Date)return L(t.valueOf());if(L.isMoment(t))return L(t);if(z.isString(t))return i=P.exec(t),L(i?Number(i[1]):t);throw new Error("Cannot convert object of type "+z.getType(t)+" to type Date");case"ISODate":if(z.isNumber(t))return new Date(t);if(t instanceof Date)return t.toISOString();if(L.isMoment(t))return t.toDate().toISOString();if(z.isString(t))return i=P.exec(t),i?new Date(Number(i[1])).toISOString():new Date(t).toISOString();throw new Error("Cannot convert object of type "+z.getType(t)+" to type ISODate");case"ASPDate":if(z.isNumber(t))return"/Date("+t+")/";if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(z.isString(t)){i=P.exec(t);var n;return n=i?new Date(Number(i[1])).valueOf():new Date(t).valueOf(),"/Date("+n+")/"}throw new Error("Cannot convert object of type "+z.getType(t)+" to type ASPDate");default:throw new Error("Cannot convert object of type "+z.getType(t)+' to type "'+e+'"')}};var P=/^\/?Date\((\-?\d+)/i;z.getType=function(t){var e=typeof t;return"object"==e?null==t?"null":t instanceof Boolean?"Boolean":t instanceof Number?"Number":t instanceof String?"String":t instanceof Array?"Array":t instanceof Date?"Date":"Object":"number"==e?"Number":"boolean"==e?"Boolean":"string"==e?"String":e},z.getAbsoluteLeft=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetLeft,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetLeft,n-=s.scrollLeft,s=s.offsetParent;return n},z.getAbsoluteTop=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetTop,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetTop,n-=s.scrollTop,s=s.offsetParent;return n},z.getPageY=function(t){if("pageY"in t)return t.pageY;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientY:t.clientY;var i=document.documentElement,n=document.body;return e+(i&&i.scrollTop||n&&n.scrollTop||0)-(i&&i.clientTop||n&&n.clientTop||0)},z.getPageX=function(t){if("pageY"in t)return t.pageX;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientX:t.clientX;var i=document.documentElement,n=document.body;return e+(i&&i.scrollLeft||n&&n.scrollLeft||0)-(i&&i.clientLeft||n&&n.clientLeft||0)},z.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},z.removeClassName=function(t,e){var i=t.className.split(" "),n=i.indexOf(e);-1!=n&&(i.splice(n,1),t.className=i.join(" "))},z.forEach=function(t,e){var i,n;if(t instanceof Array)for(i=0,n=t.length;n>i;i++)e(t[i],i,t);else for(i in t)t.hasOwnProperty(i)&&e(t[i],i,t)},z.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},z.addEventListener=function(t,e,i,n){t.addEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.addEventListener(e,i,n)):t.attachEvent("on"+e,i)},z.removeEventListener=function(t,e,i,n){t.removeEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.removeEventListener(e,i,n)):t.detachEvent("on"+e,i)},z.getTarget=function(t){t||(t=window.event);var e;return t.target?e=t.target:t.srcElement&&(e=t.srcElement),void 0!=e.nodeType&&3==e.nodeType&&(e=e.parentNode),e},z.stopPropagation=function(t){t||(t=window.event),t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},z.fakeGesture=function(t,e){var i=null;return N.event.collectEventData(this,i,e)},z.preventDefault=function(t){t||(t=window.event),t.preventDefault?t.preventDefault():t.returnValue=!1},z.option={},z.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},z.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},z.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?String(t):e||null},z.option.asSize=function(t,e){return"function"==typeof t&&(t=t()),z.isString(t)?t:z.isNumber(t)?t+"px":e||null},z.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null};var F={listeners:[],indexOf:function(t){for(var e=this.listeners,i=0,n=this.listeners.length;n>i;i++){var s=e[i];if(s&&s.object==t)return i}return-1},addListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];s||(s={object:t,events:{}},this.listeners.push(s));var o=s.events[e];o||(o=[],s.events[e]=o),-1==o.indexOf(i)&&o.push(i)},removeListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];o&&(n=o.indexOf(i),-1!=n&&o.splice(n,1),0==o.length&&delete s.events[e]);var r=0,a=s.events;for(var h in a)a.hasOwnProperty(h)&&r++;0==r&&delete this.listeners[n]}},removeAllListeners:function(){this.listeners=[]},trigger:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];if(o)for(var r=0,a=o.length;a>r;r++)o[r](i)}}};s.prototype.on=function(t,e,i){var n=t instanceof RegExp?t:new RegExp(t.replace("*","\\w+")),s={id:z.randomUUID(),event:t,regexp:n,callback:"function"==typeof e?e:null,target:i};return this.subscriptions.push(s),s.id},s.prototype.off=function(t){for(var e=0;eo;o++)i=s._addItem(t[o]),n.push(i);else if(z.isDataTable(t))for(var a=this._getColumnNames(t),h=0,d=t.getNumberOfRows();d>h;h++){for(var c={},l=0,u=a.length;u>l;l++){var p=a[l];c[p]=t.getValue(h,l)}i=s._addItem(c),n.push(i)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");i=s._addItem(t),n.push(i)}return n.length&&this._trigger("add",{items:n},e),n},o.prototype.update=function(t,e){var i=[],n=[],s=this,o=s.fieldId,r=function(t){var e=t[o];s.data[e]?(e=s._updateItem(t),n.push(e)):(e=s._addItem(t),i.push(e))};if(t instanceof Array)for(var a=0,h=t.length;h>a;a++)r(t[a]);else if(z.isDataTable(t))for(var d=this._getColumnNames(t),c=0,l=t.getNumberOfRows();l>c;c++){for(var u={},p=0,f=d.length;f>p;p++){var g=d[p];u[g]=t.getValue(c,p)}r(u)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");r(t)}return i.length&&this._trigger("add",{items:i},e),n.length&&this._trigger("update",{items:n},e),i.concat(n)},o.prototype.get=function(){var t,e,i,n,s=this,o=this.showInternalIds,r=z.getType(arguments[0]);"String"==r||"Number"==r?(t=arguments[0],i=arguments[1],n=arguments[2]):"Array"==r?(e=arguments[0],i=arguments[1],n=arguments[2]):(i=arguments[0],n=arguments[1]);var a;if(i&&i.type){if(a="DataTable"==i.type?"DataTable":"Array",n&&a!=z.getType(n))throw new Error('Type of parameter "data" ('+z.getType(n)+") does not correspond with specified options.type ("+i.type+")");if("DataTable"==a&&!z.isDataTable(n))throw new Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else a=n?"DataTable"==z.getType(n)?"DataTable":"Array":"Array";void 0!=i&&void 0!=i.showInternalIds&&(this.showInternalIds=i.showInternalIds);var h,d,c,l,u=i&&i.convert||this.options.convert,p=i&&i.filter,f=[];if(void 0!=t)h=s._getItem(t,u),p&&!p(h)&&(h=null);else if(void 0!=e)for(c=0,l=e.length;l>c;c++)h=s._getItem(e[c],u),(!p||p(h))&&f.push(h);else for(d in this.data)this.data.hasOwnProperty(d)&&(h=s._getItem(d,u),(!p||p(h))&&f.push(h));if(this.showInternalIds=o,i&&i.order&&void 0==t&&this._sort(f,i.order),i&&i.fields){var g=i.fields;if(void 0!=t)h=this._filterFields(h,g);else for(c=0,l=f.length;l>c;c++)f[c]=this._filterFields(f[c],g)}if("DataTable"==a){var m=this._getColumnNames(n);if(void 0!=t)s._appendRow(n,m,h);else for(c=0,l=f.length;l>c;c++)s._appendRow(n,m,f[c]);return n}if(void 0!=t)return h;if(n){for(c=0,l=f.length;l>c;c++)n.push(f[c]);return n}return f},o.prototype.getIds=function(t){var e,i,n,s,o,r=this.data,a=t&&t.filter,h=t&&t.order,d=t&&t.convert||this.options.convert,c=[];if(a)if(h){o=[];for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,d),a(s)&&o.push(s));for(this._sort(o,h),e=0,i=o.length;i>e;e++)c[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,d),a(s)&&c.push(s[this.fieldId]));else if(h){o=[];for(n in r)r.hasOwnProperty(n)&&o.push(r[n]);for(this._sort(o,h),e=0,i=o.length;i>e;e++)c[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=r[n],c.push(s[this.fieldId]));return c},o.prototype.forEach=function(t,e){var i,n,s=e&&e.filter,o=e&&e.convert||this.options.convert,r=this.data;if(e&&e.order)for(var a=this.get(e),h=0,d=a.length;d>h;h++)i=a[h],n=i[this.fieldId],t(i,n);else for(n in r)r.hasOwnProperty(n)&&(i=this._getItem(n,o),(!s||s(i))&&t(i,n))},o.prototype.map=function(t,e){var i,n=e&&e.filter,s=e&&e.convert||this.options.convert,o=[],r=this.data;for(var a in r)r.hasOwnProperty(a)&&(i=this._getItem(a,s),(!n||n(i))&&o.push(t(i,a)));return e&&e.order&&this._sort(o,e.order),o},o.prototype._filterFields=function(t,e){var i={};for(var n in t)t.hasOwnProperty(n)&&-1!=e.indexOf(n)&&(i[n]=t[n]);return i},o.prototype._sort=function(t,e){if(z.isString(e)){var i=e;t.sort(function(t,e){var n=t[i],s=e[i];return n>s?1:s>n?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},o.prototype.remove=function(t,e){var i,n,s,o=[];if(t instanceof Array)for(i=0,n=t.length;n>i;i++)s=this._remove(t[i]),null!=s&&o.push(s);else s=this._remove(t),null!=s&&o.push(s);return o.length&&this._trigger("remove",{items:o},e),o},o.prototype._remove=function(t){if(z.isNumber(t)||z.isString(t)){if(this.data[t])return delete this.data[t],delete this.internalIds[t],t}else if(t instanceof Object){var e=t[this.fieldId];if(e&&this.data[e])return delete this.data[e],delete this.internalIds[e],e}return null},o.prototype.clear=function(t){var e=Object.keys(this.data);return this.data={},this.internalIds={},this._trigger("remove",{items:e},t),e},o.prototype.max=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||r>n)&&(i=o,n=r)}return i},o.prototype.min=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||n>r)&&(i=o,n=r)}return i},o.prototype.distinct=function(t){var e=this.data,i=[],n=this.options.convert[t],s=0;for(var o in e)if(e.hasOwnProperty(o)){for(var r=e[o],a=z.convert(r[t],n),h=!1,d=0;s>d;d++)if(i[d]==a){h=!0;break}h||(i[s]=a,s++)}return i},o.prototype._addItem=function(t){var e=t[this.fieldId];if(void 0!=e){if(this.data[e])throw new Error("Cannot add item: item with id "+e+" already exists")}else e=z.randomUUID(),t[this.fieldId]=e,this.internalIds[e]=t;var i={};for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=z.convert(t[n],s)}return this.data[e]=i,e},o.prototype._getItem=function(t,e){var i,n,s=this.data[t];if(!s)return null;var o={},r=this.fieldId,a=this.internalIds;if(e)for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a&&!this.showInternalIds||(o[i]=z.convert(n,e[i])));else for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a&&!this.showInternalIds||(o[i]=n));return o},o.prototype._updateItem=function(t){var e=t[this.fieldId];if(void 0==e)throw new Error("Cannot update item: item has no id (item: "+JSON.stringify(t)+")");var i=this.data[e];if(!i)throw new Error("Cannot update item: no item with id "+e+" found");for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=z.convert(t[n],s)}return e},o.prototype.isInternalId=function(t){return t in this.internalIds},o.prototype._getColumnNames=function(t){for(var e=[],i=0,n=t.getNumberOfColumns();n>i;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},o.prototype._appendRow=function(t,e,i){for(var n=t.addRow(),s=0,o=e.length;o>s;s++){var r=e[s];t.setValue(n,s,i[r])}},r.prototype.setData=function(t){var e,i,n;if(this.data){this.data.unsubscribe&&this.data.unsubscribe("*",this.listener),e=[];for(var s in this.ids)this.ids.hasOwnProperty(s)&&e.push(s);this.ids={},this._trigger("remove",{items:e})}if(this.data=t,this.data){for(this.fieldId=this.options.fieldId||this.data&&this.data.options&&this.data.options.fieldId||"id",e=this.data.getIds({filter:this.options&&this.options.filter}),i=0,n=e.length;n>i;i++)s=e[i],this.ids[s]=!0;this._trigger("add",{items:e}),this.data.subscribe&&this.data.subscribe("*",this.listener)}},r.prototype.get=function(){var t,e,i,n=this,s=z.getType(arguments[0]);"String"==s||"Number"==s||"Array"==s?(t=arguments[0],e=arguments[1],i=arguments[2]):(e=arguments[0],i=arguments[1]);var o=z.extend({},this.options,e);this.options.filter&&e&&e.filter&&(o.filter=function(t){return n.options.filter(t)&&e.filter(t)});var r=[];return void 0!=t&&r.push(t),r.push(o),r.push(i),this.data&&this.data.get.apply(this.data,r)},r.prototype.getIds=function(t){var e;if(this.data){var i,n=this.options.filter;i=t&&t.filter?n?function(e){return n(e)&&t.filter(e)}:t.filter:n,e=this.data.getIds({filter:i,order:t&&t.order})}else e=[];return e},r.prototype._onEvent=function(t,e,i){var n,s,o,r,a=e&&e.items,h=this.data,d=[],c=[],l=[];if(a&&h){switch(t){case"add":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r&&(this.ids[o]=!0,d.push(o));break;case"update":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r?this.ids[o]?c.push(o):(this.ids[o]=!0,d.push(o)):this.ids[o]&&(delete this.ids[o],l.push(o));break;case"remove":for(n=0,s=a.length;s>n;n++)o=a[n],this.ids[o]&&(delete this.ids[o],l.push(o))}d.length&&this._trigger("add",{items:d},i),c.length&&this._trigger("update",{items:c},i),l.length&&this._trigger("remove",{items:l},i)}},r.prototype.subscribe=o.prototype.subscribe,r.prototype.unsubscribe=o.prototype.unsubscribe,r.prototype._trigger=o.prototype._trigger,TimeStep=function(t,e,i){this.current=new Date,this._start=new Date,this._end=new Date,this.autoScale=!0,this.scale=TimeStep.SCALE.DAY,this.step=1,this.setRange(t,e,i)},TimeStep.SCALE={MILLISECOND:1,SECOND:2,MINUTE:3,HOUR:4,DAY:5,WEEKDAY:6,MONTH:7,YEAR:8},TimeStep.prototype.setRange=function(t,e,i){if(!(t instanceof Date&&e instanceof Date))throw"No legal start or end date in method setRange";this._start=void 0!=t?new Date(t.valueOf()):new Date,this._end=void 0!=e?new Date(e.valueOf()):new Date,this.autoScale&&this.setMinimumStep(i)},TimeStep.prototype.first=function(){this.current=new Date(this._start.valueOf()),this.roundToMinor()},TimeStep.prototype.roundToMinor=function(){switch(this.scale){case TimeStep.SCALE.YEAR:this.current.setFullYear(this.step*Math.floor(this.current.getFullYear()/this.step)),this.current.setMonth(0);case TimeStep.SCALE.MONTH:this.current.setDate(1);case TimeStep.SCALE.DAY:case TimeStep.SCALE.WEEKDAY:this.current.setHours(0);case TimeStep.SCALE.HOUR:this.current.setMinutes(0);case TimeStep.SCALE.MINUTE:this.current.setSeconds(0);case TimeStep.SCALE.SECOND:this.current.setMilliseconds(0)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.setMilliseconds(this.current.getMilliseconds()-this.current.getMilliseconds()%this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()-this.current.getSeconds()%this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()-this.current.getMinutes()%this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()-this.current.getHours()%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()-1-(this.current.getDate()-1)%this.step+1);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()-this.current.getMonth()%this.step); +break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()-this.current.getFullYear()%this.step)}},TimeStep.prototype.hasNext=function(){return this.current.valueOf()<=this._end.valueOf()},TimeStep.prototype.next=function(){var t=this.current.valueOf();if(this.current.getMonth()<6)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current=new Date(this.current.valueOf()+1e3*this.step);break;case TimeStep.SCALE.MINUTE:this.current=new Date(this.current.valueOf()+1e3*this.step*60);break;case TimeStep.SCALE.HOUR:this.current=new Date(this.current.valueOf()+1e3*this.step*60*60);var e=this.current.getHours();this.current.setHours(e-e%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}else switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()+this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()+this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()+this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.getMilliseconds()0&&(this.step=e),this.autoScale=!1},TimeStep.prototype.setAutoScale=function(t){this.autoScale=t},TimeStep.prototype.setMinimumStep=function(t){if(void 0!=t){var e=31104e6,i=2592e6,n=864e5,s=36e5,o=6e4,r=1e3,a=1;1e3*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1e3),500*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=500),100*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=100),50*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=50),10*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=10),5*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=5),e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1),3*i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=3),i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=1),5*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=5),2*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=2),n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=1),n/2>t&&(this.scale=TimeStep.SCALE.WEEKDAY,this.step=1),4*s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=4),s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=1),15*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=15),10*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=10),5*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=5),o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=1),15*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=15),10*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=10),5*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=5),r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=1),200*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=200),100*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=100),50*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=50),10*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=10),5*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=5),a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=1)}},TimeStep.prototype.snap=function(t){if(this.scale==TimeStep.SCALE.YEAR){var e=t.getFullYear()+Math.round(t.getMonth()/12);t.setFullYear(Math.round(e/this.step)*this.step),t.setMonth(0),t.setDate(0),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MONTH)t.getDate()>15?(t.setDate(1),t.setMonth(t.getMonth()+1)):t.setDate(1),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0);else if(this.scale==TimeStep.SCALE.DAY||this.scale==TimeStep.SCALE.WEEKDAY){switch(this.step){case 5:case 2:t.setHours(24*Math.round(t.getHours()/24));break;default:t.setHours(12*Math.round(t.getHours()/12))}t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.HOUR){switch(this.step){case 4:t.setMinutes(60*Math.round(t.getMinutes()/60));break;default:t.setMinutes(30*Math.round(t.getMinutes()/30))}t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MINUTE){switch(this.step){case 15:case 10:t.setMinutes(5*Math.round(t.getMinutes()/5)),t.setSeconds(0);break;case 5:t.setSeconds(60*Math.round(t.getSeconds()/60));break;default:t.setSeconds(30*Math.round(t.getSeconds()/30))}t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.SECOND)switch(this.step){case 15:case 10:t.setSeconds(5*Math.round(t.getSeconds()/5)),t.setMilliseconds(0);break;case 5:t.setMilliseconds(1e3*Math.round(t.getMilliseconds()/1e3));break;default:t.setMilliseconds(500*Math.round(t.getMilliseconds()/500))}else if(this.scale==TimeStep.SCALE.MILLISECOND){var i=this.step>5?this.step/2:1;t.setMilliseconds(Math.round(t.getMilliseconds()/i)*i)}},TimeStep.prototype.isMajor=function(){switch(this.scale){case TimeStep.SCALE.MILLISECOND:return 0==this.current.getMilliseconds();case TimeStep.SCALE.SECOND:return 0==this.current.getSeconds();case TimeStep.SCALE.MINUTE:return 0==this.current.getHours()&&0==this.current.getMinutes();case TimeStep.SCALE.HOUR:return 0==this.current.getHours();case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return 1==this.current.getDate();case TimeStep.SCALE.MONTH:return 0==this.current.getMonth();case TimeStep.SCALE.YEAR:return!1;default:return!1}},TimeStep.prototype.getLabelMinor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return L(t).format("SSS");case TimeStep.SCALE.SECOND:return L(t).format("s");case TimeStep.SCALE.MINUTE:return L(t).format("HH:mm");case TimeStep.SCALE.HOUR:return L(t).format("HH:mm");case TimeStep.SCALE.WEEKDAY:return L(t).format("ddd D");case TimeStep.SCALE.DAY:return L(t).format("D");case TimeStep.SCALE.MONTH:return L(t).format("MMM");case TimeStep.SCALE.YEAR:return L(t).format("YYYY");default:return""}},TimeStep.prototype.getLabelMajor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return L(t).format("HH:mm:ss");case TimeStep.SCALE.SECOND:return L(t).format("D MMMM HH:mm");case TimeStep.SCALE.MINUTE:case TimeStep.SCALE.HOUR:return L(t).format("ddd D MMMM");case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return L(t).format("MMMM YYYY");case TimeStep.SCALE.MONTH:return L(t).format("YYYY");case TimeStep.SCALE.YEAR:return"";default:return""}},a.prototype.setOptions=function(t){z.extend(this.options,t)},a.prototype.update=function(){this._order(),this._stack()},a.prototype._order=function(){var t=this.parent.items;if(!t)throw new Error("Cannot stack items: parent does not contain items");var e=[],i=0;z.forEach(t,function(t){t.visible&&(e[i]=t,i++)});var n=this.options.order||this.defaultOptions.order;if("function"!=typeof n)throw new Error("Option order must be a function");e.sort(n),this.ordered=e},a.prototype._stack=function(){var t,e,i,n=this.ordered,s=this.options,o=s.orientation||this.defaultOptions.orientation,r="top"==o;for(i=s.margin&&void 0!==s.margin.item?s.margin.item:this.defaultOptions.margin.item,t=0,e=n.length;e>t;t++){var a=n[t],h=null;do h=this.checkOverlap(n,t,0,t-1,i),null!=h&&(a.top=r?h.top+h.height+i:h.top-a.height-i);while(h)}},a.prototype.checkOverlap=function(t,e,i,n,s){for(var o=this.collision,r=t[e],a=n;a>=i;a--){var h=t[a];if(o(r,h,s)&&a!=e)return h}return null},a.prototype.collision=function(t,e,i){return t.left-ie.left&&t.top-ie.top},h.prototype.setOptions=function(t){z.extend(this.options,t),null!==this.start&&null!==this.end&&this.setRange(this.start,this.end)},h.prototype.subscribe=function(t,e,i){function n(e){s._onMouseWheel(e,t,i)}var s=this;if("move"==e)t.on("dragstart",function(e){s._onDragStart(e,t)}),t.on("drag",function(e){s._onDrag(e,t,i)}),t.on("dragend",function(e){s._onDragEnd(e,t)});else{if("zoom"!=e)throw new TypeError('Unknown event "'+e+'". Choose "move" or "zoom".');t.on("mousewheel",n),t.on("DOMMouseScroll",n),t.on("touch",function(){s._onTouch()}),t.on("pinch",function(e){s._onPinch(e,t,i)})}},h.prototype.on=function(t,e){var i=["rangechange","rangechanged"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());F.addListener(this,t,e)},h.prototype.off=function(t,e){F.removeListener(this,t,e)},h.prototype._trigger=function(t){F.trigger(this,t,{start:this.start,end:this.end})},h.prototype.setRange=function(t,e){var i=this._applyRange(t,e);i&&(this._trigger("rangechange"),this._trigger("rangechanged"))},h.prototype._applyRange=function(t,e){var i,n=null!=t?z.convert(t,"Date").valueOf():this.start,s=null!=e?z.convert(e,"Date").valueOf():this.end,o=null!=this.options.max?z.convert(this.options.max,"Date").valueOf():null,r=null!=this.options.min?z.convert(this.options.min,"Date").valueOf():null;if(isNaN(n)||null===n)throw new Error('Invalid start "'+t+'"');if(isNaN(s)||null===s)throw new Error('Invalid end "'+e+'"');if(n>s&&(s=n),null!==r&&r>n&&(i=r-n,n+=i,s+=i,null!=o&&s>o&&(s=o)),null!==o&&s>o&&(i=s-o,n-=i,s-=i,null!=r&&r>n&&(n=r)),null!==this.options.zoomMin){var a=parseFloat(this.options.zoomMin);0>a&&(a=0),a>s-n&&(this.end-this.start===a?(n=this.start,s=this.end):(i=a-(s-n),n-=i/2,s+=i/2))}if(null!==this.options.zoomMax){var h=parseFloat(this.options.zoomMax);0>h&&(h=0),s-n>h&&(this.end-this.start===h?(n=this.start,s=this.end):(i=s-n-h,n+=i/2,s-=i/2))}var d=this.start!=n||this.end!=s;return this.start=n,this.end=s,d},h.prototype.getRange=function(){return{start:this.start,end:this.end}},h.prototype.conversion=function(t){return h.conversion(this.start,this.end,t)},h.conversion=function(t,e,i){return 0!=i&&e-t!=0?{offset:t,scale:i/(e-t)}:{offset:0,scale:1}};var Y={};h.prototype._onDragStart=function(t,e){if(!Y.pinching){Y.start=this.start,Y.end=this.end;var i=e.frame;i&&(i.style.cursor="move")}},h.prototype._onDrag=function(t,e,i){if(d(i),!Y.pinching){var n="horizontal"==i?t.gesture.deltaX:t.gesture.deltaY,s=Y.end-Y.start,o="horizontal"==i?e.width:e.height,r=-n/o*s;this._applyRange(Y.start+r,Y.end+r),this._trigger("rangechange")}},h.prototype._onDragEnd=function(t,e){Y.pinching||(e.frame&&(e.frame.style.cursor="auto"),this._trigger("rangechanged"))},h.prototype._onMouseWheel=function(t,e,i){d(i);var n=0;if(t.wheelDelta?n=t.wheelDelta/120:t.detail&&(n=-t.detail/3),n){var s;s=0>n?1-n/5:1/(1+n/5);var o=z.fakeGesture(this,t),r=c(o.touches[0],e.frame),a=this._pointerToDate(e,i,r);this.zoom(s,a)}z.preventDefault(t)},h.prototype._onTouch=function(){Y.start=this.start,Y.end=this.end,Y.pinching=!1,Y.center=null},h.prototype._onPinch=function(t,e,i){if(Y.pinching=!0,t.gesture.touches.length>1){Y.center||(Y.center=c(t.gesture.center,e.frame));var n=1/t.gesture.scale,s=this._pointerToDate(e,i,Y.center),o=c(t.gesture.center,e.frame),r=(this._pointerToDate(e,i,o),parseInt(s+(Y.start-s)*n)),a=parseInt(s+(Y.end-s)*n);this.setRange(r,a)}},h.prototype._pointerToDate=function(t,e,i){var n;if("horizontal"==e){var s=t.width;return n=this.conversion(s),i.x/n.scale+n.offset}var o=t.height;return n=this.conversion(o),i.y/n.scale+n.offset},h.prototype.zoom=function(t,e){null==e&&(e=(this.start+this.end)/2);var i=e+(this.start-e)*t,n=e+(this.end-e)*t;this.setRange(i,n)},h.prototype.move=function(t){var e=this.end-this.start,i=this.start+e*t,n=this.end+e*t;this.start=i,this.end=n},h.prototype.moveTo=function(t){var e=(this.start+this.end)/2,i=e-t,n=this.start-i,s=this.end-i;this.setRange(n,s)},l.prototype.add=function(t){if(void 0==t.id)throw new Error("Component has no field id");if(!(t instanceof u||t instanceof l))throw new TypeError("Component must be an instance of prototype Component or Controller");t.controller=this,this.components[t.id]=t},l.prototype.remove=function(t){var e;for(e in this.components)if(this.components.hasOwnProperty(e)&&(e==t||this.components[e]==t))break;e&&delete this.components[e]},l.prototype.requestReflow=function(t){if(t)this.reflow();else if(!this.reflowTimer){var e=this;this.reflowTimer=setTimeout(function(){e.reflowTimer=void 0,e.reflow()},0)}},l.prototype.requestRepaint=function(t){if(t)this.repaint();else if(!this.repaintTimer){var e=this;this.repaintTimer=setTimeout(function(){e.repaintTimer=void 0,e.repaint()},0)}},l.prototype.repaint=function V(){function V(i,n){n in e||(i.depends&&i.depends.forEach(function(t){V(t,t.id)}),i.parent&&V(i.parent,i.parent.id),t=i.repaint()||t,e[n]=!0)}var t=!1;this.repaintTimer&&(clearTimeout(this.repaintTimer),this.repaintTimer=void 0);var e={};z.forEach(this.components,V),t&&this.reflow()},l.prototype.reflow=function G(){function G(i,n){n in e||(i.depends&&i.depends.forEach(function(t){G(t,t.id)}),i.parent&&G(i.parent,i.parent.id),t=i.reflow()||t,e[n]=!0)}var t=!1;this.reflowTimer&&(clearTimeout(this.reflowTimer),this.reflowTimer=void 0);var e={};z.forEach(this.components,G),t&&this.repaint()},u.prototype.setOptions=function(t){t&&(z.extend(this.options,t),this.controller&&(this.requestRepaint(),this.requestReflow()))},u.prototype.getOption=function(t){var e;return this.options&&(e=this.options[t]),void 0===e&&this.defaultOptions&&(e=this.defaultOptions[t]),e},u.prototype.getContainer=function(){return null},u.prototype.getFrame=function(){return this.frame},u.prototype.repaint=function(){return!1},u.prototype.reflow=function(){return!1},u.prototype.hide=function(){return this.frame&&this.frame.parentNode?(this.frame.parentNode.removeChild(this.frame),!0):!1},u.prototype.show=function(){return this.frame&&this.frame.parentNode?!1:this.repaint()},u.prototype.requestRepaint=function(){if(!this.controller)throw new Error("Cannot request a repaint: no controller configured");this.controller.requestRepaint()},u.prototype.requestReflow=function(){if(!this.controller)throw new Error("Cannot request a reflow: no controller configured");this.controller.requestReflow()},p.prototype=new u,p.prototype.setOptions=u.prototype.setOptions,p.prototype.getContainer=function(){return this.frame},p.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.frame;if(!s){s=document.createElement("div"),s.className="panel";var o=n.className;o&&("function"==typeof o?z.addClassName(s,String(o())):z.addClassName(s,String(o))),this.frame=s,t+=1}if(!s.parentNode){if(!this.parent)throw new Error("Cannot repaint panel: no parent attached");var r=this.parent.getContainer();if(!r)throw new Error("Cannot repaint panel: parent has no container element");r.appendChild(s),t+=1}return t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),t>0},p.prototype.reflow=function(){var t=0,e=z.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},f.prototype=new p,f.prototype.setOptions=u.prototype.setOptions,f.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.frame;if(s||(s=document.createElement("div"),this.frame=s,t+=1),!s.parentNode){if(!this.container)throw new Error("Cannot repaint root panel: no container attached");this.container.appendChild(s),t+=1}s.className="vis timeline rootpanel "+n.orientation;var o=n.className;return o&&z.addClassName(s,z.option.asString(o)),t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),this._updateEventEmitters(),this._updateWatch(),t>0},f.prototype.reflow=function(){var t=0,e=z.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},f.prototype._updateWatch=function(){var t=this.getOption("autoResize");t?this._watch():this._unwatch()},f.prototype._watch=function(){var t=this;this._unwatch();var e=function(){var e=t.getOption("autoResize");return e?void(t.frame&&(t.frame.clientWidth!=t.width||t.frame.clientHeight!=t.height)&&t.requestReflow()):void t._unwatch()};z.addEventListener(window,"resize",e),this.watchTimer=setInterval(e,1e3)},f.prototype._unwatch=function(){this.watchTimer&&(clearInterval(this.watchTimer),this.watchTimer=void 0)},f.prototype.on=function(t,e){var i=this.listeners[t];i||(i=[],this.listeners[t]=i),i.push(e),this._updateEventEmitters()},f.prototype._updateEventEmitters=function(){if(this.listeners){var t=this;z.forEach(this.listeners,function(e,i){if(t.emitters||(t.emitters={}),!(i in t.emitters)){var n=t.frame;if(n){var s=function(t){e.forEach(function(e){e(t)})};t.emitters[i]=s,t.hammer||(t.hammer=N(n,{prevent_default:!0})),t.hammer.on(i,s)}}})}},g.prototype=new u,g.prototype.setOptions=u.prototype.setOptions,g.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},g.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},g.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},g.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.props,r=this.step,a=this.frame;if(a||(a=document.createElement("div"),this.frame=a,t+=1),a.className="axis",!a.parentNode){if(!this.parent)throw new Error("Cannot repaint time axis: no parent attached");var h=this.parent.getContainer();if(!h)throw new Error("Cannot repaint time axis: parent has no container element");h.appendChild(a),t+=1}var d=a.parentNode;if(d){var c=a.nextSibling;d.removeChild(a);var l="bottom"==s&&this.props.parentHeight&&this.height?this.props.parentHeight-this.height+"px":"0px";if(t+=e(a.style,"top",i(n.top,l)),t+=e(a.style,"left",i(n.left,"0px")),t+=e(a.style,"width",i(n.width,"100%")),t+=e(a.style,"height",i(n.height,this.height+"px")),this._repaintMeasureChars(),this.step){this._repaintStart(),r.first();for(var u=void 0,p=0;r.hasNext()&&1e3>p;){p++;var f=r.getCurrent(),g=this.toScreen(f),m=r.isMajor();this.getOption("showMinorLabels")&&this._repaintMinorText(g,r.getLabelMinor()),m&&this.getOption("showMajorLabels")?(g>0&&(void 0==u&&(u=g),this._repaintMajorText(g,r.getLabelMajor())),this._repaintMajorLine(g)):this._repaintMinorLine(g),r.next()}if(this.getOption("showMajorLabels")){var v=this.toTime(0),y=r.getLabelMajor(v),_=y.length*(o.majorCharWidth||10)+10;(void 0==u||u>_)&&this._repaintMajorText(0,y)}this._repaintEnd()}this._repaintLine(),c?d.insertBefore(a,c):d.appendChild(a)}return t>0},g.prototype._repaintStart=function(){var t=this.dom,e=t.redundant;e.majorLines=t.majorLines,e.majorTexts=t.majorTexts,e.minorLines=t.minorLines,e.minorTexts=t.minorTexts,t.majorLines=[],t.majorTexts=[],t.minorLines=[],t.minorTexts=[]},g.prototype._repaintEnd=function(){z.forEach(this.dom.redundant,function(t){for(;t.length;){var e=t.pop();e&&e.parentNode&&e.parentNode.removeChild(e)}})},g.prototype._repaintMinorText=function(t,e){var i=this.dom.redundant.minorTexts.shift();if(!i){var n=document.createTextNode("");i=document.createElement("div"),i.appendChild(n),i.className="text minor",this.frame.appendChild(i)}this.dom.minorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.left=t+"px",i.style.top=this.props.minorLabelTop+"px"},g.prototype._repaintMajorText=function(t,e){var i=this.dom.redundant.majorTexts.shift();if(!i){var n=document.createTextNode(e);i=document.createElement("div"),i.className="text major",i.appendChild(n),this.frame.appendChild(i)}this.dom.majorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.top=this.props.majorLabelTop+"px",i.style.left=t+"px"},g.prototype._repaintMinorLine=function(t){var e=this.dom.redundant.minorLines.shift();e||(e=document.createElement("div"),e.className="grid vertical minor",this.frame.appendChild(e)),this.dom.minorLines.push(e);var i=this.props;e.style.top=i.minorLineTop+"px",e.style.height=i.minorLineHeight+"px",e.style.left=t-i.minorLineWidth/2+"px"},g.prototype._repaintMajorLine=function(t){var e=this.dom.redundant.majorLines.shift();e||(e=document.createElement("DIV"),e.className="grid vertical major",this.frame.appendChild(e)),this.dom.majorLines.push(e);var i=this.props;e.style.top=i.majorLineTop+"px",e.style.left=t-i.majorLineWidth/2+"px",e.style.height=i.majorLineHeight+"px"},g.prototype._repaintLine=function(){{var t=this.dom.line,e=this.frame;this.options}this.getOption("showMinorLabels")||this.getOption("showMajorLabels")?(t?(e.removeChild(t),e.appendChild(t)):(t=document.createElement("div"),t.className="grid horizontal major",e.appendChild(t),this.dom.line=t),t.style.top=this.props.lineTop+"px"):t&&t.parentElement&&(e.removeChild(t.line),delete this.dom.line)},g.prototype._repaintMeasureChars=function(){var t,e=this.dom;if(!e.measureCharMinor){t=document.createTextNode("0");var i=document.createElement("DIV");i.className="text minor measure",i.appendChild(t),this.frame.appendChild(i),e.measureCharMinor=i}if(!e.measureCharMajor){t=document.createTextNode("0");var n=document.createElement("DIV");n.className="text major measure",n.appendChild(t),this.frame.appendChild(n),e.measureCharMajor=n}},g.prototype.reflow=function(){var t=0,e=z.updateProperty,i=this.frame,n=this.range;if(!n)throw new Error("Cannot repaint time axis: no range configured");if(i){t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft);var s=this.props,o=this.getOption("showMinorLabels"),r=this.getOption("showMajorLabels"),a=this.dom.measureCharMinor,h=this.dom.measureCharMajor;a&&(s.minorCharHeight=a.clientHeight,s.minorCharWidth=a.clientWidth),h&&(s.majorCharHeight=h.clientHeight,s.majorCharWidth=h.clientWidth);var d=i.parentNode?i.parentNode.offsetHeight:0;switch(d!=s.parentHeight&&(s.parentHeight=d,t+=1),this.getOption("orientation")){case"bottom":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.minorLabelTop=0,s.majorLabelTop=s.minorLabelTop+s.minorLabelHeight,s.minorLineTop=-this.top,s.minorLineHeight=Math.max(this.top+s.majorLabelHeight,0),s.minorLineWidth=1,s.majorLineTop=-this.top,s.majorLineHeight=Math.max(this.top+s.minorLabelHeight+s.majorLabelHeight,0),s.majorLineWidth=1,s.lineTop=0;break;case"top":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.majorLabelTop=0,s.minorLabelTop=s.majorLabelTop+s.majorLabelHeight,s.minorLineTop=s.minorLabelTop,s.minorLineHeight=Math.max(d-s.majorLabelHeight-this.top),s.minorLineWidth=1,s.majorLineTop=0,s.majorLineHeight=Math.max(d-this.top),s.majorLineWidth=1,s.lineTop=s.majorLabelHeight+s.minorLabelHeight;break;default:throw new Error('Unkown orientation "'+this.getOption("orientation")+'"')}var c=s.minorLabelHeight+s.majorLabelHeight;t+=e(this,"width",i.offsetWidth),t+=e(this,"height",c),this._updateConversion();var l=z.convert(n.start,"Number"),u=z.convert(n.end,"Number"),p=this.toTime(5*(s.minorCharWidth||10)).valueOf()-this.toTime(0).valueOf();this.step=new TimeStep(new Date(l),new Date(u),p),t+=e(s.range,"start",l),t+=e(s.range,"end",u),t+=e(s.range,"minimumStep",p.valueOf())}return t>0},g.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},m.prototype=new u,m.prototype.setOptions=u.prototype.setOptions,m.prototype.getContainer=function(){return this.frame},m.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCurrentTime"))return void(t&&(i.removeChild(t),delete this.frame));t||(t=document.createElement("div"),t.className="currenttime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t),this.frame=t),e.conversion||e._updateConversion();var n=new Date,s=e.toScreen(n);t.style.left=s+"px",t.title="Current time: "+n,void 0!==this.currentTimeTimer&&(clearTimeout(this.currentTimeTimer),delete this.currentTimeTimer);var o=this,r=1/e.conversion.scale/2;return 30>r&&(r=30),this.currentTimeTimer=setTimeout(function(){o.repaint()},r),!1},v.prototype=new u,v.prototype.setOptions=u.prototype.setOptions,v.prototype.getContainer=function(){return this.frame},v.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCustomTime"))return void(t&&(i.removeChild(t),delete this.frame));if(!t){t=document.createElement("div"),t.className="customtime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t);var n=document.createElement("div");n.style.position="relative",n.style.top="0px",n.style.left="-10px",n.style.height="100%",n.style.width="20px",t.appendChild(n),this.frame=t,this.subscribe(this,"movetime")}e.conversion||e._updateConversion();var s=e.toScreen(this.customTime);return t.style.left=s+"px",t.title="Time: "+this.customTime,!1},v.prototype._setCustomTime=function(t){this.customTime=new Date(t.valueOf()),this.repaint()},v.prototype._getCustomTime=function(){return new Date(this.customTime.valueOf())},v.prototype.subscribe=function(t,e){var i=this,n={component:t,event:e,callback:function(t){i._onMouseDown(t,n)},params:{}};t.on("mousedown",n.callback),i.listeners.push(n)},v.prototype.on=function(t,e){var i=this.frame;if(!i)throw new Error("Cannot add event listener: no parent attached");F.addListener(this,t,e),z.addEventListener(i,t,e)},v.prototype._onMouseDown=function(t,e){t=t||window.event;var i=e.params,n=t.which?1==t.which:1==t.button;if(n){i.mouseX=z.getPageX(t),i.moved=!1,i.customTime=this.customTime;var s=this;i.onMouseMove||(i.onMouseMove=function(t){s._onMouseMove(t,e)},z.addEventListener(document,"mousemove",i.onMouseMove)),i.onMouseUp||(i.onMouseUp=function(t){s._onMouseUp(t,e)},z.addEventListener(document,"mouseup",i.onMouseUp)),z.stopPropagation(t),z.preventDefault(t)}},v.prototype._onMouseMove=function(t,e){t=t||window.event;var i=e.params,n=this.parent,s=z.getPageX(t);void 0===i.mouseX&&(i.mouseX=s);var o=s-i.mouseX;Math.abs(o)>=1&&(i.moved=!0);var r=n.toScreen(i.customTime),a=r+o,h=n.toTime(a);this._setCustomTime(h),F.trigger(this,"timechange",{customTime:this.customTime}),z.preventDefault(t)},v.prototype._onMouseUp=function(t,e){t=t||window.event;var i=e.params;i.onMouseMove&&(z.removeEventListener(document,"mousemove",i.onMouseMove),i.onMouseMove=null),i.onMouseUp&&(z.removeEventListener(document,"mouseup",i.onMouseUp),i.onMouseUp=null),i.moved&&F.trigger(this,"timechanged",{customTime:this.customTime})},y.prototype=new p,y.types={box:w,range:S,rangeoverflow:E,point:b},y.prototype.setOptions=u.prototype.setOptions,y.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},y.prototype.setSelection=function(t){var e,i,n,s,o;if(t){if(!Array.isArray(t))throw new TypeError("Array expected");for(e=0,i=this.selection.length;i>e;e++)n=this.selection[e],s=this.items[n],s&&s.unselect();for(this.selection=[],e=0,i=t.length;i>e;e++)n=t[e],s=this.items[n],s&&(this.selection.push(n),s.select());o=this.selection.concat([]),F.trigger(this,"select",{ids:o}),this.controller&&this.requestRepaint()}},y.prototype.getSelection=function(){return this.selection.concat([])},y.prototype._deselect=function(t){for(var e=this.selection,i=0,n=e.length;n>i;i++)if(e[i]==t){e.splice(i,1);break}},y.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.defaultOptions,r=this.frame;if(!r){r=document.createElement("div"),r.className="itemset";var a=n.className;a&&z.addClassName(r,z.option.asString(a));var h=document.createElement("div");h.className="background",r.appendChild(h),this.dom.background=h;var d=document.createElement("div");d.className="foreground",r.appendChild(d),this.dom.foreground=d;var c=document.createElement("div");c.className="itemset-axis",this.dom.axis=c,this.frame=r,t+=1}if(!this.parent)throw new Error("Cannot repaint itemset: no parent attached");var l=this.parent.getContainer();if(!l)throw new Error("Cannot repaint itemset: parent has no container element");r.parentNode||(l.appendChild(r),t+=1),this.dom.axis.parentNode||(l.appendChild(this.dom.axis),t+=1),t+=e(r.style,"left",i(n.left,"0px")),t+=e(r.style,"top",i(n.top,"0px")),t+=e(r.style,"width",i(n.width,"100%")),t+=e(r.style,"height",i(n.height,this.height+"px")),t+=e(this.dom.axis.style,"left",i(n.left,"0px")),t+=e(this.dom.axis.style,"width",i(n.width,"100%")),t+="bottom"==s?e(this.dom.axis.style,"top",this.height+this.top+"px"):e(this.dom.axis.style,"top",this.top+"px"),this._updateConversion();var u=this,p=this.queue,f=this.itemsData,g=this.items,m={};for(var v in p)if(p.hasOwnProperty(v)){var _=p[v],w=g[v],b=_.action;switch(b){case"add":case"update":var S=f&&f.get(v,m);if(S){var E=S.type||S.start&&S.end&&"range"||n.type||"box",T=y.types[E];if(w&&(T&&w instanceof T?(w.data=S,t++):(t+=w.hide(),w=null)),!w){if(!T)throw new TypeError('Unknown item type "'+E+'"');w=new T(u,S,n,o),w.id=_.id,t++}w.repaint(),g[v]=w}delete p[v];break;case"remove":w&&(w.selected&&u._deselect(v),t+=w.hide()),delete g[v],delete p[v];break;default:console.log('Error: unknown action "'+b+'"')}}return z.forEach(this.items,function(e){e.visible?(t+=e.show(),e.reposition()):t+=e.hide()}),t>0},y.prototype.getForeground=function(){return this.dom.foreground},y.prototype.getBackground=function(){return this.dom.background},y.prototype.getAxis=function(){return this.dom.axis},y.prototype.reflow=function(){var t=0,e=this.options,i=e.margin&&e.margin.axis||this.defaultOptions.margin.axis,n=e.margin&&e.margin.item||this.defaultOptions.margin.item,s=z.updateProperty,o=z.option.asNumber,r=z.option.asSize,a=this.frame;if(a){this._updateConversion(),z.forEach(this.items,function(e){t+=e.reflow()}),this.stack.update();var h,d=o(e.maxHeight),c=null!=r(e.height);if(c)h=a.offsetHeight;else{var l=this.stack.ordered;if(l.length){var u=l[0].top,p=l[0].top+l[0].height;z.forEach(l,function(t){u=Math.min(u,t.top),p=Math.max(p,t.top+t.height)}),h=p-u+i+n}else h=i+n}null!=d&&(h=Math.min(h,d)),t+=s(this,"height",h),t+=s(this,"top",a.offsetTop),t+=s(this,"left",a.offsetLeft),t+=s(this,"width",a.offsetWidth)}else t+=1;return t>0},y.prototype.hide=function(){var t=!1;return this.frame&&this.frame.parentNode&&(this.frame.parentNode.removeChild(this.frame),t=!0),this.dom.axis&&this.dom.axis.parentNode&&(this.dom.axis.parentNode.removeChild(this.dom.axis),t=!0),t +},y.prototype.setItems=function(t){var e,i=this,n=this.itemsData;if(t){if(!(t instanceof o||t instanceof r))throw new TypeError("Data must be an instance of DataSet");this.itemsData=t}else this.itemsData=null;if(n&&(z.forEach(this.listeners,function(t,e){n.unsubscribe(e,t)}),e=n.getIds(),this._onRemove(e)),this.itemsData){var s=this.id;z.forEach(this.listeners,function(t,e){i.itemsData.subscribe(e,t,s)}),e=this.itemsData.getIds(),this._onAdd(e)}},y.prototype.getItems=function(){return this.itemsData},y.prototype._onUpdate=function(t){this._toQueue("update",t)},y.prototype._onAdd=function(t){this._toQueue("add",t)},y.prototype._onRemove=function(t){this._toQueue("remove",t)},y.prototype._toQueue=function(t,e){var i=this.queue;e.forEach(function(e){i[e]={id:e,action:t}}),this.controller&&this.requestRepaint()},y.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},y.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},y.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},_.prototype.select=function(){this.selected=!0,this.visible&&this.repaint()},_.prototype.unselect=function(){this.selected=!1,this.visible&&this.repaint()},_.prototype.show=function(){return!1},_.prototype.hide=function(){return!1},_.prototype.repaint=function(){return!1},_.prototype.reflow=function(){return!1},_.prototype.getWidth=function(){return this.width},w.prototype=new _(null,null),w.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");if(!e.box.parentNode){var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");i.appendChild(e.box),t=!0}if(!e.line.parentNode){var n=this.parent.getBackground();if(!n)throw new Error("Cannot repaint time axis: parent has no background container element");n.appendChild(e.line),t=!0}if(!e.dot.parentNode){var s=this.parent.getAxis();if(!n)throw new Error("Cannot repaint time axis: parent has no axis container element");s.appendChild(e.dot),t=!0}if(this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var o=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=o&&(this.className=o,e.box.className="item box"+o,e.line.className="item line"+o,e.dot.className="item dot"+o,t=!0)}return t},w.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},w.prototype.hide=function(){var t=!1,e=this.dom;return e&&(e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),e.line.parentNode&&e.line.parentNode.removeChild(e.line),e.dot.parentNode&&e.dot.parentNode.removeChild(e.dot)),t},w.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,d,c,l,u=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(c=this.data,l=this.parent&&this.parent.range,c&&l){var p=l.end-l.start;this.visible=c.start>l.start-p&&c.start0},w.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("DIV"),t.content=document.createElement("DIV"),t.content.className="content",t.box.appendChild(t.content),t.line=document.createElement("DIV"),t.line.className="line",t.dot=document.createElement("DIV"),t.dot.className="dot",t.box["timeline-item"]=this)},w.prototype.reposition=function(){var t=this.dom,e=this.props,i=this.options.orientation||this.defaultOptions.orientation;if(t){var n=t.box,s=t.line,o=t.dot;n.style.left=this.left+"px",n.style.top=this.top+"px",s.style.left=e.line.left+"px","top"==i?(s.style.top="0px",s.style.height=this.top+"px"):(s.style.top=this.top+this.height+"px",s.style.height=Math.max(this.parent.height-this.top-this.height+this.props.dot.height/2,0)+"px"),o.style.left=e.dot.left+"px",o.style.top=e.dot.top+"px"}},b.prototype=new _(null,null),b.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.point.parentNode||(i.appendChild(e.point),i.appendChild(e.point),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.point.className="item point"+n,t=!0)}return t},b.prototype.show=function(){return this.dom&&this.dom.point.parentNode?!1:this.repaint()},b.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.point.parentNode&&(e.point.parentNode.removeChild(e.point),t=!0),t},b.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,d,c=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(h=this.data,d=this.parent&&this.parent.range,h&&d){var l=d.end-d.start;this.visible=h.start>d.start-l&&h.start0},b.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.point=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.point.appendChild(t.content),t.dot=document.createElement("div"),t.dot.className="dot",t.point.appendChild(t.dot),t.point["timeline-item"]=this)},b.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.point.style.top=this.top+"px",t.point.style.left=this.left+"px",t.content.style.marginLeft=e.content.marginLeft+"px",t.dot.style.top=e.dot.top+"px")},S.prototype=new _(null,null),S.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.box.className="item range"+n,t=!0)}return t},S.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},S.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),t},S.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,d,c,l,u,p,f,g,m=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(void 0==this.data.end)throw new Error('Property "end" missing in item '+this.data.id);return h=this.data,d=this.parent&&this.parent.range,this.visible=h&&d?h.startd.start:!1,this.visible&&(t=this.dom,t?(e=this.props,i=this.options,o=this.parent,r=o.toScreen(this.data.start),a=o.toScreen(this.data.end),c=z.updateProperty,l=t.box,u=o.width,f=i.orientation||this.defaultOptions.orientation,n=i.margin&&i.margin.axis||this.defaultOptions.margin.axis,s=i.padding||this.defaultOptions.padding,m+=c(e.content,"width",t.content.offsetWidth),m+=c(this,"height",l.offsetHeight),-u>r&&(r=-u),a>2*u&&(a=2*u),p=0>r?Math.min(-r,a-r-e.content.width-2*s):0,m+=c(e.content,"left",p),"top"==f?(g=n,m+=c(this,"top",g)):(g=o.height-this.height-n,m+=c(this,"top",g)),m+=c(this,"left",r),m+=c(this,"width",Math.max(a-r,1))):m+=1),m>0},S.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content),t.box["timeline-item"]=this)},S.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.box.style.top=this.top+"px",t.box.style.left=this.left+"px",t.box.style.width=this.width+"px",t.content.style.left=e.content.left+"px")},E.prototype=new S(null,null),E.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=this.data.className?" "+this.data.className:"";this.className!=n&&(this.className=n,e.box.className="item rangeoverflow"+n,t=!0)}return t},E.prototype.getWidth=function(){return void 0!==this.props.content&&this.width0},x.prototype=new p,x.prototype.setOptions=u.prototype.setOptions,x.prototype.setRange=function(){},x.prototype.setItems=function(t){this.itemsData=t;for(var e in this.groups)if(this.groups.hasOwnProperty(e)){var i=this.groups[e];i.setItems(t)}},x.prototype.getItems=function(){return this.itemsData},x.prototype.setRange=function(t){this.range=t},x.prototype.setGroups=function(t){var e,i=this;if(this.groupsData&&(z.forEach(this.listeners,function(t,e){i.groupsData.unsubscribe(e,t)}),e=this.groupsData.getIds(),this._onRemove(e)),t?t instanceof o?this.groupsData=t:(this.groupsData=new o({convert:{start:"Date",end:"Date"}}),this.groupsData.add(t)):this.groupsData=null,this.groupsData){var n=this.id;z.forEach(this.listeners,function(t,e){i.groupsData.subscribe(e,t,n)}),e=this.groupsData.getIds(),this._onAdd(e)}},x.prototype.getGroups=function(){return this.groupsData},x.prototype.setSelection=function(t){var e=[],i=this.groups;for(var n in i)if(i.hasOwnProperty(n)){var s=i[n];s.setSelection(t)}return e},x.prototype.getSelection=function(){var t=[],e=this.groups;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];t=t.concat(n.getSelection())}return t},x.prototype.repaint=function(){var t,e,i,n,s=0,o=z.updateProperty,r=z.option.asSize,a=z.option.asElement,h=this.options,d=this.dom.frame,c=this.dom.labels,l=this.dom.labelSet;if(!this.parent)throw new Error("Cannot repaint groupset: no parent attached");var u=this.parent.getContainer();if(!u)throw new Error("Cannot repaint groupset: parent has no container element");if(!d){d=document.createElement("div"),d.className="groupset",this.dom.frame=d;var p=h.className;p&&z.addClassName(d,z.option.asString(p)),s+=1}d.parentNode||(u.appendChild(d),s+=1);var f=a(h.labelContainer);if(!f)throw new Error('Cannot repaint groupset: option "labelContainer" not defined');c||(c=document.createElement("div"),c.className="labels",this.dom.labels=c),l||(l=document.createElement("div"),l.className="label-set",c.appendChild(l),this.dom.labelSet=l),c.parentNode&&c.parentNode==f||(c.parentNode&&c.parentNode.removeChild(c.parentNode),f.appendChild(c)),s+=o(d.style,"height",r(h.height,this.height+"px")),s+=o(d.style,"top",r(h.top,"0px")),s+=o(d.style,"left",r(h.left,"0px")),s+=o(d.style,"width",r(h.width,"100%")),s+=o(l.style,"top",r(h.top,"0px")),s+=o(l.style,"height",r(h.height,this.height+"px"));var g=this,m=this.queue,v=this.groups,y=this.groupsData,_=Object.keys(m);if(_.length){_.forEach(function(t){var e=m[t],i=v[t];switch(e){case"add":case"update":if(!i){var n=Object.create(g.options);z.extend(n,{height:null,maxHeight:null}),i=new T(g,t,n),i.setItems(g.itemsData),v[t]=i,g.controller.add(i)}i.data=y.get(t),delete m[t];break;case"remove":i&&(i.setItems(),delete v[t],g.controller.remove(i)),delete m[t];break;default:console.log('Error: unknown action "'+e+'"')}});var w=this.groupsData.getIds({order:this.options.groupOrder});for(t=0;t0},x.prototype._createLabel=function(t){var e=this.groups[t],i=document.createElement("div");i.className="label";var n=document.createElement("div");n.className="inner",i.appendChild(n);var s=e.data&&e.data.content;s instanceof Element?n.appendChild(s):void 0!=s&&(n.innerHTML=s);var o=e.data&&e.data.className;return o&&z.addClassName(i,o),e.label=i,i},x.prototype.getContainer=function(){return this.dom.frame},x.prototype.getLabelsWidth=function(){return this.props.labels.width},x.prototype.reflow=function(){var t,e,i=0,n=this.options,s=z.updateProperty,o=z.option.asNumber,r=z.option.asSize,a=this.dom.frame;if(a){var h,d=o(n.maxHeight),c=null!=r(n.height);if(c)h=a.offsetHeight;else{h=0;for(t in this.groups)this.groups.hasOwnProperty(t)&&(e=this.groups[t],h+=e.height)}null!=d&&(h=Math.min(h,d)),i+=s(this,"height",h),i+=s(this,"top",a.offsetTop),i+=s(this,"left",a.offsetLeft),i+=s(this,"width",a.offsetWidth)}var l=0;for(t in this.groups)if(this.groups.hasOwnProperty(t)){e=this.groups[t];var u=e.props&&e.props.label&&e.props.label.width||0;l=Math.max(l,u)}return i+=s(this.props.labels,"width",l),i>0},x.prototype.hide=function(){return this.dom.frame&&this.dom.frame.parentNode?(this.dom.frame.parentNode.removeChild(this.dom.frame),!0):!1},x.prototype.show=function(){return this.dom.frame&&this.dom.frame.parentNode?!1:this.repaint()},x.prototype._onUpdate=function(t){this._toQueue(t,"update")},x.prototype._onAdd=function(t){this._toQueue(t,"add")},x.prototype._onRemove=function(t){this._toQueue(t,"remove")},x.prototype._toQueue=function(t,e){var i=this.queue;t.forEach(function(t){i[t]=e}),this.controller&&this.requestRepaint()},C.prototype.setOptions=function(t){z.extend(this.options,t),this.range.setRange(t.start,t.end),this.controller.reflow(),this.controller.repaint()},C.prototype.setCustomTime=function(t){this.customtime._setCustomTime(t)},C.prototype.getCustomTime=function(){return new Date(this.customtime.customTime.valueOf())},C.prototype.setItems=function(t){var e,i=null==this.itemsData;if(t?t instanceof o&&(e=t):e=null,t instanceof o||(e=new o({convert:{start:"Date",end:"Date"}}),e.add(t)),this.itemsData=e,this.content.setItems(e),i&&(void 0==this.options.start||void 0==this.options.end)){var n=this.getItemRange(),s=n.min,r=n.max;if(null!=s&&null!=r){var a=r.valueOf()-s.valueOf();0>=a&&(a=864e5),s=new Date(s.valueOf()-.05*a),r=new Date(r.valueOf()+.05*a)}void 0!=this.options.start&&(s=z.convert(this.options.start,"Date")),void 0!=this.options.end&&(r=z.convert(this.options.end,"Date")),(null!=s||null!=r)&&this.range.setRange(s,r)}},C.prototype.setGroups=function(t){var e=this;this.groupsData=t;var i=this.groupsData?x:y;if(!(this.content instanceof i)){this.content&&(this.content.hide(),this.content.setItems&&this.content.setItems(),this.content.setGroups&&this.content.setGroups(),this.controller.remove(this.content));var n=Object.create(this.options);z.extend(n,{top:function(){return"top"==e.options.orientation?e.timeaxis.height:e.itemPanel.height-e.timeaxis.height-e.content.height},left:null,width:"100%",height:function(){return e.options.height?e.itemPanel.height-e.timeaxis.height:null},maxHeight:function(){if(e.options.maxHeight){if(!z.isNumber(e.options.maxHeight))throw new TypeError("Number expected for property maxHeight");return e.options.maxHeight-e.timeaxis.height}return null},labelContainer:function(){return e.labelPanel.getContainer()}}),this.content=new i(this.itemPanel,[this.timeaxis],n),this.content.setRange&&this.content.setRange(this.range),this.content.setItems&&this.content.setItems(this.itemsData),this.content.setGroups&&this.content.setGroups(this.groupsData),this.controller.add(this.content)}},C.prototype.getItemRange=function(){var t=this.itemsData,e=null,i=null;if(t){var n=t.min("start");e=n?n.start.valueOf():null;var s=t.max("start");s&&(i=s.start.valueOf());var o=t.max("end");o&&(i=null==i?o.end.valueOf():Math.max(i,o.end.valueOf()))}return{min:null!=e?new Date(e):null,max:null!=i?new Date(i):null}},C.prototype.setSelection=function(t){this.content&&this.content.setSelection(t)},C.prototype.getSelection=function(){return this.content?this.content.getSelection():[]},C.prototype.on=function(t,e){var i=["rangechange","rangechanged","select"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());F.addListener(this,t,e)},C.prototype.off=function(t,e){F.removeListener(this,t,e)},C.prototype._trigger=function(t,e){F.trigger(this,t,e||{})},C.prototype._onSelectItem=function(t){var e=this._itemFromTarget(t),i=e?[e.id]:[];this.setSelection(i),this._trigger("select",{items:this.getSelection()}),t.stopPropagation()},C.prototype._onMultiSelectItem=function(t){var e,i=this._itemFromTarget(t);if(i){e=this.getSelection();var n=e.indexOf(i.id);-1==n?e.push(i.id):e.splice(n,1),this.setSelection(e),this._trigger("select",{items:this.getSelection()}),t.stopPropagation()}},C.prototype._itemFromTarget=function(t){for(var e=t.target;e;){if(e.hasOwnProperty("timeline-item"))return e["timeline-item"];e=e.parentNode}return null},function(t){function e(t){return C=t,u()}function i(){M=0,D=C.charAt(0)}function n(){M++,D=C.charAt(M)}function s(){return C.charAt(M+1)}function o(t){return N.test(t)}function r(t,e){if(t||(t={}),e)for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function a(t,e,i){for(var n=e.split("."),s=t;n.length;){var o=n.shift();n.length?(s[o]||(s[o]={}),s=s[o]):s[o]=i}}function h(t,e){for(var i,n,s=null,o=[t],a=t;a.parent;)o.push(a.parent),a=a.parent;if(a.nodes)for(i=0,n=a.nodes.length;n>i;i++)if(e.id===a.nodes[i].id){s=a.nodes[i];break}for(s||(s={id:e.id},t.node&&(s.attr=r(s.attr,t.node))),i=o.length-1;i>=0;i--){var h=o[i];h.nodes||(h.nodes=[]),-1==h.nodes.indexOf(s)&&h.nodes.push(s)}e.attr&&(s.attr=r(s.attr,e.attr))}function d(t,e){if(t.edges||(t.edges=[]),t.edges.push(e),t.edge){var i=r({},t.edge);e.attr=r(i,e.attr)}}function c(t,e,i,n,s){var o={from:e,to:i,type:n};return t.edge&&(o.attr=r({},t.edge)),o.attr=r(o.attr||{},s),o}function l(){for(O=T.NULL,I="";" "==D||" "==D||"\n"==D||"\r"==D;)n();do{var t=!1;if("#"==D){for(var e=M-1;" "==C.charAt(e)||" "==C.charAt(e);)e--;if("\n"==C.charAt(e)||""==C.charAt(e)){for(;""!=D&&"\n"!=D;)n();t=!0}}if("/"==D&&"/"==s()){for(;""!=D&&"\n"!=D;)n();t=!0}if("/"==D&&"*"==s()){for(;""!=D;){if("*"==D&&"/"==s()){n(),n();break}n()}t=!0}for(;" "==D||" "==D||"\n"==D||"\r"==D;)n()}while(t);if(""==D)return void(O=T.DELIMITER);var i=D+s();if(x[i])return O=T.DELIMITER,I=i,n(),void n();if(x[D])return O=T.DELIMITER,I=D,void n();if(o(D)||"-"==D){for(I+=D,n();o(D);)I+=D,n();return"false"==I?I=!1:"true"==I?I=!0:isNaN(Number(I))||(I=Number(I)),void(O=T.IDENTIFIER)}if('"'==D){for(n();""!=D&&('"'!=D||'"'==D&&'"'==s());)I+=D,'"'==D&&n(),n();if('"'!=D)throw w('End of string " expected');return n(),void(O=T.IDENTIFIER)}for(O=T.UNKNOWN;""!=D;)I+=D,n();throw new SyntaxError('Syntax error in part "'+b(I,30)+'"')}function u(){var t={};if(i(),l(),"strict"==I&&(t.strict=!0,l()),("graph"==I||"digraph"==I)&&(t.type=I,l()),O==T.IDENTIFIER&&(t.id=I,l()),"{"!=I)throw w("Angle bracket { expected");if(l(),p(t),"}"!=I)throw w("Angle bracket } expected");if(l(),""!==I)throw w("End of file expected");return l(),delete t.node,delete t.edge,delete t.graph,t}function p(t){for(;""!==I&&"}"!=I;)f(t),";"==I&&l()}function f(t){var e=g(t);if(e)return void y(t,e);var i=m(t);if(!i){if(O!=T.IDENTIFIER)throw w("Identifier expected");var n=I;if(l(),"="==I){if(l(),O!=T.IDENTIFIER)throw w("Identifier expected");t[n]=I,l()}else v(t,n)}}function g(t){var e=null;if("subgraph"==I&&(e={},e.type="subgraph",l(),O==T.IDENTIFIER&&(e.id=I,l())),"{"==I){if(l(),e||(e={}),e.parent=t,e.node=t.node,e.edge=t.edge,e.graph=t.graph,p(e),"}"!=I)throw w("Angle bracket } expected");l(),delete e.node,delete e.edge,delete e.graph,delete e.parent,t.subgraphs||(t.subgraphs=[]),t.subgraphs.push(e)}return e}function m(t){return"node"==I?(l(),t.node=_(),"node"):"edge"==I?(l(),t.edge=_(),"edge"):"graph"==I?(l(),t.graph=_(),"graph"):null}function v(t,e){var i={id:e},n=_();n&&(i.attr=n),h(t,i),y(t,e)}function y(t,e){for(;"->"==I||"--"==I;){var i,n=I;l();var s=g(t);if(s)i=s;else{if(O!=T.IDENTIFIER)throw w("Identifier or subgraph expected");i=I,h(t,{id:i}),l()}var o=_(),r=c(t,e,i,n,o);d(t,r),e=i}}function _(){for(var t=null;"["==I;){for(l(),t={};""!==I&&"]"!=I;){if(O!=T.IDENTIFIER)throw w("Attribute name expected");var e=I;if(l(),"="!=I)throw w("Equal sign = expected");if(l(),O!=T.IDENTIFIER)throw w("Attribute value expected");var i=I;a(t,e,i),l(),","==I&&l()}if("]"!=I)throw w("Bracket ] expected");l()}return t}function w(t){return new SyntaxError(t+', got "'+b(I,30)+'" (char '+M+")")}function b(t,e){return t.length<=e?t:t.substr(0,27)+"..."}function S(t,e,i){t instanceof Array?t.forEach(function(t){e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}):e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}function E(t){function i(t){var e={from:t.from,to:t.to};return r(e,t.attr),e.style="->"==t.type?"arrow":"line",e}var n=e(t),s={nodes:[],edges:[],options:{}};return n.nodes&&n.nodes.forEach(function(t){var e={id:t.id,label:String(t.label||t.id)};r(e,t.attr),e.image&&(e.shape="image"),s.nodes.push(e)}),n.edges&&n.edges.forEach(function(t){var e,n;e=t.from instanceof Object?t.from.nodes:{id:t.from},n=t.to instanceof Object?t.to.nodes:{id:t.to},t.from instanceof Object&&t.from.edges&&t.from.edges.forEach(function(t){var e=i(t);s.edges.push(e)}),S(e,n,function(e,n){var o=c(s,e.id,n.id,t.type,t.attr),r=i(o);s.edges.push(r)}),t.to instanceof Object&&t.to.edges&&t.to.edges.forEach(function(t){var e=i(t);s.edges.push(e)})}),n.attr&&(s.options=n.attr),s}var T={NULL:0,DELIMITER:1,IDENTIFIER:2,UNKNOWN:3},x={"{":!0,"}":!0,"[":!0,"]":!0,";":!0,"=":!0,",":!0,"->":!0,"--":!0},C="",M=0,D="",I="",O=T.NULL,N=/[a-zA-Z_0-9.:#]/;t.parseDOT=e,t.DOTToGraph=E}("undefined"!=typeof z?z:n),"undefined"!=typeof CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.circle=function(t,e,i){this.beginPath(),this.arc(t,e,i,0,2*Math.PI,!1)},CanvasRenderingContext2D.prototype.square=function(t,e,i){this.beginPath(),this.rect(t-i,e-i,2*i,2*i)},CanvasRenderingContext2D.prototype.triangle=function(t,e,i){this.beginPath();var n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e-(r-o)),this.lineTo(t+s,e+o),this.lineTo(t-s,e+o),this.lineTo(t,e-(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.triangleDown=function(t,e,i){this.beginPath();var n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e+(r-o)),this.lineTo(t+s,e-o),this.lineTo(t-s,e-o),this.lineTo(t,e+(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.star=function(t,e,i){this.beginPath();for(var n=0;10>n;n++){var s=n%2===0?1.3*i:.5*i;this.lineTo(t+s*Math.sin(2*n*Math.PI/10),e-s*Math.cos(2*n*Math.PI/10))}this.closePath()},CanvasRenderingContext2D.prototype.roundRect=function(t,e,i,n,s){var o=Math.PI/180;0>i-2*s&&(s=i/2),0>n-2*s&&(s=n/2),this.beginPath(),this.moveTo(t+s,e),this.lineTo(t+i-s,e),this.arc(t+i-s,e+s,s,270*o,360*o,!1),this.lineTo(t+i,e+n-s),this.arc(t+i-s,e+n-s,s,0,90*o,!1),this.lineTo(t+s,e+n),this.arc(t+s,e+n-s,s,90*o,180*o,!1),this.lineTo(t,e+s),this.arc(t+s,e+s,s,180*o,270*o,!1)},CanvasRenderingContext2D.prototype.ellipse=function(t,e,i,n){var s=.5522848,o=i/2*s,r=n/2*s,a=t+i,h=e+n,d=t+i/2,c=e+n/2;this.beginPath(),this.moveTo(t,c),this.bezierCurveTo(t,c-r,d-o,e,d,e),this.bezierCurveTo(d+o,e,a,c-r,a,c),this.bezierCurveTo(a,c+r,d+o,h,d,h),this.bezierCurveTo(d-o,h,t,c+r,t,c)},CanvasRenderingContext2D.prototype.database=function(t,e,i,n){var s=1/3,o=i,r=n*s,a=.5522848,h=o/2*a,d=r/2*a,c=t+o,l=e+r,u=t+o/2,p=e+r/2,f=e+(n-r/2),g=e+n;this.beginPath(),this.moveTo(c,p),this.bezierCurveTo(c,p+d,u+h,l,u,l),this.bezierCurveTo(u-h,l,t,p+d,t,p),this.bezierCurveTo(t,p-d,u-h,e,u,e),this.bezierCurveTo(u+h,e,c,p-d,c,p),this.lineTo(c,f),this.bezierCurveTo(c,f+d,u+h,g,u,g),this.bezierCurveTo(u-h,g,t,f+d,t,f),this.lineTo(t,p)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,n){var s=t-n*Math.cos(i),o=e-n*Math.sin(i),r=t-.9*n*Math.cos(i),a=e-.9*n*Math.sin(i),h=s+n/3*Math.cos(i+.5*Math.PI),d=o+n/3*Math.sin(i+.5*Math.PI),c=s+n/3*Math.cos(i-.5*Math.PI),l=o+n/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,d),this.lineTo(r,a),this.lineTo(c,l),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,n,s){s||(s=[10,5]),0==u&&(u=.001);var o=s.length;this.moveTo(t,e);for(var r=i-t,a=n-e,h=a/r,d=Math.sqrt(r*r+a*a),c=0,l=!0;d>=.1;){var u=s[c++%o];u>d&&(u=d);var p=Math.sqrt(u*u/(1+h*h));0>r&&(p=-p),t+=p,e+=h*p,this[l?"lineTo":"moveTo"](t,e),d-=u,l=!l}}),M.prototype.resetCluster=function(){this.formationScale=void 0,this.clusterSize=1,this.containedNodes={},this.containedEdges={},this.clusterSessions=[]},M.prototype.attachEdge=function(t){-1==this.edges.indexOf(t)&&this.edges.push(t),-1==this.dynamicEdges.indexOf(t)&&this.dynamicEdges.push(t),this.dynamicEdgesLength=this.dynamicEdges.length,this._updateMass()},M.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&(this.edges.splice(e,1),this.dynamicEdges.splice(e,1)),this.dynamicEdgesLength=this.dynamicEdges.length,this._updateMass()},M.prototype._updateMass=function(){this.mass=1+.6*this.edges.length},M.prototype.setProperties=function(t,e){if(t){if(this.originalLabel=void 0,void 0!==t.id&&(this.id=t.id),void 0!==t.label&&(this.label=t.label,this.originalLabel=t.label),void 0!==t.title&&(this.title=t.title),void 0!==t.group&&(this.group=t.group),void 0!==t.x&&(this.x=t.x),void 0!==t.y&&(this.y=t.y),void 0!==t.value&&(this.value=t.value),void 0!==t.horizontalAlignLeft&&(this.horizontalAlignLeft=t.horizontalAlignLeft),void 0!==t.verticalAlignTop&&(this.verticalAlignTop=t.verticalAlignTop),void 0!==t.triggerFunction&&(this.triggerFunction=t.triggerFunction),void 0===this.id)throw"Node must have an id";if(this.group){var i=this.grouplist.get(this.group);for(var n in i)i.hasOwnProperty(n)&&(this[n]=i[n])}if(void 0!==t.shape&&(this.shape=t.shape),void 0!==t.image&&(this.image=t.image),void 0!==t.radius&&(this.radius=t.radius),void 0!==t.color&&(this.color=M.parseColor(t.color)),void 0!==t.fontColor&&(this.fontColor=t.fontColor),void 0!==t.fontSize&&(this.fontSize=t.fontSize),void 0!==t.fontFace&&(this.fontFace=t.fontFace),void 0!==this.image){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.image)}switch(this.xFixed=this.xFixed||void 0!==t.x,this.yFixed=this.yFixed||void 0!==t.y,this.radiusFixed=this.radiusFixed||void 0!==t.radius,"image"==this.shape&&(this.radiusMin=e.nodes.widthMin,this.radiusMax=e.nodes.widthMax),this.shape){case"database":this.draw=this._drawDatabase,this.resize=this._resizeDatabase;break;case"box":this.draw=this._drawBox,this.resize=this._resizeBox;break;case"circle":this.draw=this._drawCircle,this.resize=this._resizeCircle;break;case"ellipse":this.draw=this._drawEllipse,this.resize=this._resizeEllipse;break;case"image":this.draw=this._drawImage,this.resize=this._resizeImage;break;case"text":this.draw=this._drawText,this.resize=this._resizeText;break;case"dot":this.draw=this._drawDot,this.resize=this._resizeShape;break;case"square":this.draw=this._drawSquare,this.resize=this._resizeShape;break;case"triangle":this.draw=this._drawTriangle,this.resize=this._resizeShape;break;case"triangleDown":this.draw=this._drawTriangleDown,this.resize=this._resizeShape;break;case"star":this.draw=this._drawStar,this.resize=this._resizeShape;break;default:this.draw=this._drawEllipse,this.resize=this._resizeEllipse}this._reset()}},M.parseColor=function(t){var e;return z.isString(t)?e={border:t,background:t,highlight:{border:t,background:t}}:(e={},e.background=t.background||"white",e.border=t.border||e.background,z.isString(t.highlight)?e.highlight={border:t.highlight,background:t.highlight}:(e.highlight={},e.highlight.background=t.highlight&&t.highlight.background||e.background,e.highlight.border=t.highlight&&t.highlight.border||e.border)),e},M.prototype.select=function(){this.selected=!0,this._reset()},M.prototype.unselect=function(){this.selected=!1,this._reset()},M.prototype.clearSizeCache=function(){this._reset()},M.prototype._reset=function(){this.width=void 0,this.height=void 0},M.prototype.getTitle=function(){return this.title},M.prototype.distanceToBorder=function(t,e){var i=1;switch(this.width||this.resize(t),this.shape){case"circle":case"dot":return this.radius+i;case"ellipse":var n=this.width/2,s=this.height/2,o=Math.sin(e)*n,r=Math.cos(e)*s; +return n*s/Math.sqrt(o*o+r*r);case"box":case"image":case"text":default:return this.width?Math.min(Math.abs(this.width/2/Math.cos(e)),Math.abs(this.height/2/Math.sin(e)))+i:0}},M.prototype._setForce=function(t,e){this.fx=t,this.fy=e},M.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},M.prototype.discreteStep=function(t){if(!this.xFixed){var e=-this.damping*this.vx,i=(this.fx+e)/this.mass;this.vx+=i*t,this.x+=this.vx*t}if(!this.yFixed){var n=-this.damping*this.vy,s=(this.fy+n)/this.mass;this.vy+=s*t,this.y+=this.vy*t}},M.prototype.isFixed=function(){return this.xFixed&&this.yFixed},M.prototype.isMoving=function(t){return Math.abs(this.vx)>t||Math.abs(this.vy)>t?!0:(this.vx=0,this.vy=0,!1)},M.prototype.isSelected=function(){return this.selected},M.prototype.getValue=function(){return this.value},M.prototype.getDistance=function(t,e){var i=this.x-t,n=this.y-e;return Math.sqrt(i*i+n*n)},M.prototype.setValueRange=function(t,e){if(!this.radiusFixed&&void 0!==this.value)if(e==t)this.radius=(this.radiusMin+this.radiusMax)/2;else{var i=(this.radiusMax-this.radiusMin)/(e-t);this.radius=(this.value-t)*i+this.radiusMin}this.baseRadiusValue=this.radius},M.prototype.draw=function(){throw"Draw method not initialized for node"},M.prototype.resize=function(){throw"Resize method not initialized for node"},M.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},M.prototype._resizeImage=function(){if(!this.width||!this.height){var t,e;if(this.value){this.radius=this.baseRadiusValue;var i=this.imageObj.height/this.imageObj.width;void 0!==i?(t=this.radius||this.imageObj.width,e=this.radius*i||this.imageObj.height):(t=0,e=0)}else t=this.imageObj.width,e=this.imageObj.height;this.width=t,this.height=e,this.width>0&&this.height>0&&(this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor)}},M.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e;if(0!=this.imageObj.width){if(this.clusterSize>1){var i=this.clusterSize>1?10:0;i*=this.graphScaleInv,i=Math.min(.2*this.width,i),t.globalAlpha=.5,t.drawImage(this.imageObj,this.left-i,this.top-i,this.width+2*i,this.height+2*i)}t.globalAlpha=1,t.drawImage(this.imageObj,this.left,this.top,this.width,this.height),e=this.y+this.height/2}else e=this.y;this._label(t,this.label,this.x,e,void 0,"top")},M.prototype._resizeBox=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=.5*(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=.5*(this.clusterSize-1)*this.clusterSizeHeightFactor}},M.prototype._drawBox=function(t){this._resizeBox(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.roundRect(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth,this.radius),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.roundRect(this.left,this.top,this.width,this.height,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeDatabase=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=i.width+2*e;this.width=n,this.height=n,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawDatabase=function(t){this._resizeDatabase(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.database(this.x-this.width/2-2*t.lineWidth,this.y-.5*this.height-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.database(this.x-this.width/2,this.y-.5*this.height,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=Math.max(i.width,i.height)+2*e;this.radius=n/2,this.width=n,this.height=n,this.radius+=.5*(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawCircle=function(t){this._resizeCircle(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.circle(this.x,this.y,this.radius+2*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.circle(this.x,this.y,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeEllipse=function(t){if(!this.width){var e=this.getTextSize(t);this.width=1.5*e.width,this.height=2*e.height,this.width1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.ellipse(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.ellipse(this.left,this.top,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._drawDot=function(t){this._drawShape(t,"circle")},M.prototype._drawTriangle=function(t){this._drawShape(t,"triangle")},M.prototype._drawTriangleDown=function(t){this._drawShape(t,"triangleDown")},M.prototype._drawSquare=function(t){this._drawShape(t,"square")},M.prototype._drawStar=function(t){this._drawShape(t,"star")},M.prototype._resizeShape=function(){if(!this.width){this.radius=this.baseRadiusValue;var t=2*this.radius;this.width=t,this.height=t,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=.5*(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawShape=function(t,e){this._resizeShape(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var i=2.5,n=2,s=2;switch(e){case"dot":s=2;break;case"square":s=2;break;case"triangle":s=3;break;case"triangleDown":s=3;break;case"star":s=4}t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?n:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t[e](this.x,this.y,this.radius+s*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?n:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t[e](this.x,this.y,this.radius),t.fill(),t.stroke(),this.label&&this._label(t,this.label,this.x,this.y+this.height/2,void 0,"top")},M.prototype._resizeText=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawText=function(t){this._resizeText(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,this._label(t,this.label,this.x,this.y)},M.prototype._label=function(t,e,i,n,s,o){if(e){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle=this.fontColor||"black",t.textAlign=s||"center",t.textBaseline=o||"middle";for(var r=e.split("\n"),a=r.length,h=this.fontSize+4,d=n+(1-a)/2*h,c=0;a>c;c++)t.fillText(r[c],i,d),d+=h}},M.prototype.getTextSize=function(t){if(void 0!==this.label){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace;for(var e=this.label.split("\n"),i=(this.fontSize+4)*e.length,n=0,s=0,o=e.length;o>s;s++)n=Math.max(n,t.measureText(e[s]).width);return{width:n,height:i}}return{width:0,height:0}},M.prototype.inArea=function(){return void 0!==this.width?this.x+this.width*this.graphScaleInv>=this.canvasTopLeft.x&&this.x-this.width*this.graphScaleInv=this.canvasTopLeft.y&&this.y-this.height*this.graphScaleInv=this.canvasTopLeft.x&&this.x=this.canvasTopLeft.y&&this.yh},D.prototype._drawLine=function(t){t.strokeStyle=this.color,t.lineWidth=this._getLineWidth();var e;if(this.from!=this.to)this._line(t),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y));else{var i,n,s=this.length/4,o=this.from;o.width||o.resize(t),o.width>o.height?(i=o.x+o.width/2,n=o.y-s):(i=o.x+s,n=o.y-o.height/2),this._circle(t,i,n,s),e=this._pointOnCircle(i,n,s,.5),this._label(t,this.label,e.x,e.y)}},D.prototype._getLineWidth=function(){return this.from.selected||this.to.selected?Math.min(2*this.width,this.widthMax)*this.graphScaleInv:this.width*this.graphScaleInv},D.prototype._line=function(t){t.beginPath(),t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y),t.stroke()},D.prototype._circle=function(t,e,i,n){t.beginPath(),t.arc(e,i,n,0,2*Math.PI,!1),t.stroke()},D.prototype._label=function(t,e,i,n){if(e){t.font=(this.from.selected||this.to.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle="white";var s=t.measureText(e).width,o=this.fontSize,r=i-s/2,a=n-o/2;t.fillRect(r,a,s,o),t.fillStyle=this.fontColor||"black",t.textAlign="left",t.textBaseline="top",t.fillText(e,r,a)}},D.prototype._drawDashLine=function(t){if(t.strokeStyle=this.color,t.lineWidth=this._getLineWidth(),t.beginPath(),t.lineCap="round",void 0!==this.dash.altLength?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]):void 0!==this.dash.length&&void 0!==this.dash.gap?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap]):(t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y)),t.stroke(),this.label){var e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}},D.prototype._pointOnLine=function(t){return{x:(1-t)*this.from.x+t*this.to.x,y:(1-t)*this.from.y+t*this.to.y}},D.prototype._pointOnCircle=function(t,e,i,n){var s=2*(n-3/8)*Math.PI;return{x:t+i*Math.cos(s),y:e-i*Math.sin(s)}},D.prototype._drawArrowCenter=function(t){var e;if(t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth(),this.from!=this.to){this._line(t);var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),n=10+5*this.width;e=this._pointOnLine(.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y))}else{var s,o,r=this.length/4,a=this.from;a.width||a.resize(t),a.width>a.height?(s=a.x+a.width/2,o=a.y-r):(s=a.x+r,o=a.y-a.height/2),this._circle(t,s,o,r);var i=.2*Math.PI,n=10+5*this.width;e=this._pointOnCircle(s,o,r,.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(s,o,r,.5),this._label(t,this.label,e.x,e.y))}},D.prototype._drawArrow=function(t){t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth();var e,i;if(this.from!=this.to){e=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x);var n=this.to.x-this.from.x,s=this.to.y-this.from.y,o=Math.sqrt(n*n+s*s),r=this.from.distanceToBorder(t,e+Math.PI),a=(o-r)/o,h=a*this.from.x+(1-a)*this.to.x,d=a*this.from.y+(1-a)*this.to.y,c=this.to.distanceToBorder(t,e),l=(o-c)/o,u=(1-l)*this.from.x+l*this.to.x,p=(1-l)*this.from.y+l*this.to.y;if(t.beginPath(),t.moveTo(h,d),t.lineTo(u,p),t.stroke(),i=10+5*this.width,t.arrow(u,p,e,i),t.fill(),t.stroke(),this.label){var f=this._pointOnLine(.5);this._label(t,this.label,f.x,f.y)}}else{var g,m,v,y=this.from,_=this.length/4;y.width||y.resize(t),y.width>y.height?(g=y.x+y.width/2,m=y.y-_,v={x:g,y:y.y,angle:.9*Math.PI}):(g=y.x+_,m=y.y-y.height/2,v={x:y.x,y:m,angle:.6*Math.PI}),t.beginPath(),t.arc(g,m,_,0,2*Math.PI,!1),t.stroke(),i=10+5*this.width,t.arrow(v.x,v.y,v.angle,i),t.fill(),t.stroke(),this.label&&(f=this._pointOnCircle(g,m,_,.5),this._label(t,this.label,f.x,f.y))}},D._dist=function(t,e,i,n,s,o){var r=i-t,a=n-e,h=r*r+a*a,d=((s-t)*r+(o-e)*a)/h;d>1?d=1:0>d&&(d=0);var c=t+d*r,l=e+d*a,u=c-s,p=l-o;return Math.sqrt(u*u+p*p)},D.prototype.setScale=function(t){this.graphScaleInv=1/t},I.prototype.setPosition=function(t,e){this.x=parseInt(t),this.y=parseInt(e)},I.prototype.setText=function(t){this.frame.innerHTML=t},I.prototype.show=function(t){if(void 0===t&&(t=!0),t){var e=this.frame.clientHeight,i=this.frame.clientWidth,n=this.frame.parentNode.clientHeight,s=this.frame.parentNode.clientWidth,o=this.y-e;o+e+this.padding>n&&(o=n-e-this.padding),os&&(r=s-i-this.padding),r1)return this.activeSector[this.activeSector.length-2];throw new TypeError("there are not enough sectors in the this.activeSector array.")},_setActiveSector:function(t){this.activeSector.push(t)},_forgetLastSector:function(){this.activeSector.pop()},_createNewSector:function(t){this.sectors.active[t]={nodes:{},edges:{},nodeIndices:[],formationScale:this.scale,drawingNode:void 0},this.sectors.active[t].drawingNode=new M({id:t,color:{background:"#eaefef",border:"495c5e"}},{},{},this.constants),this.sectors.active[t].drawingNode.clusterSize=2},_deleteActiveSector:function(t){delete this.sectors.active[t]},_deleteFrozenSector:function(t){delete this.sectors.frozen[t]},_freezeSector:function(t){this.sectors.frozen[t]=this.sectors.active[t],this._deleteActiveSector(t)},_activateSector:function(t){this.sectors.active[t]=this.sectors.frozen[t],this._deleteFrozenSector(t)},_mergeThisWithFrozen:function(t){for(var e in this.nodes)this.nodes.hasOwnProperty(e)&&(this.sectors.frozen[t].nodes[e]=this.nodes[e]);for(var i in this.edges)this.edges.hasOwnProperty(i)&&(this.sectors.frozen[t].edges[i]=this.edges[i]);for(var n=0;n1?this[t](n[0],n[1]):this[t](e)}this._loadLatestSector()},_doInAllFrozenSectors:function(t,e){if(void 0===e)for(var i in this.sectors.frozen)this.sectors.frozen.hasOwnProperty(i)&&(this._switchToFrozenSector(i),this[t]());else for(var i in this.sectors.frozen)if(this.sectors.frozen.hasOwnProperty(i)){this._switchToFrozenSector(i);var n=Array.prototype.splice.call(arguments,1);n.length>1?this[t](n[0],n[1]):this[t](e)}this._loadLatestSector()},_doInNavigationSector:function(t,e){if(this._switchToNavigationSector(),void 0===e)this[t]();else{var i=Array.prototype.splice.call(arguments,1);i.length>1?this[t](i[0],i[1]):this[t](e)}this._loadLatestSector()},_doInAllSectors:function(t,e){var i=Array.prototype.splice.call(arguments,1);void 0===e?(this._doInAllActiveSectors(t),this._doInAllFrozenSectors(t)):i.length>1?(this._doInAllActiveSectors(t,i[0],i[1]),this._doInAllFrozenSectors(t,i[0],i[1])):(this._doInAllActiveSectors(t,e),this._doInAllFrozenSectors(t,e))},_clearNodeIndexList:function(){var t=this._sector();this.sectors.active[t].nodeIndices=[],this.nodeIndices=this.sectors.active[t].nodeIndices},_drawSectorNodes:function(t,e){var i,n=1e9,s=-1e9,o=1e9,r=-1e9;for(var a in this.sectors[e])if(this.sectors[e].hasOwnProperty(a)&&void 0!==this.sectors[e][a].drawingNode){this._switchToSector(a,e),n=1e9,s=-1e9,o=1e9,r=-1e9;for(var h in this.nodes)this.nodes.hasOwnProperty(h)&&(i=this.nodes[h],i.resize(t),o>i.x-.5*i.width&&(o=i.x-.5*i.width),ri.y-.5*i.height&&(n=i.y-.5*i.height),st&&n>s;)s%3==0?this.forceAggregateHubs():this.increaseClusterLevel(),i=this.nodeIndices.length,s+=1;s>1&&1==e&&this.repositionNodes()},openCluster:function(t){var e=this.moving;if(t.clusterSize>this.constants.clustering.sectorThreshold&&this._nodeInActiveArea(t)&&("default"!=this._sector()||1!=this.nodeIndices.length)){this._addSector(t);for(var i=0;this.nodeIndices.lengthi;)this.decreaseClusterLevel(),i+=1}else this._expandClusterNode(t,!1,!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels();this.moving!=e&&this.start()},updateClustersDefault:function(){1==this.constants.clustering.enabled&&this.updateClusters(0,!1,!1)},increaseClusterLevel:function(){this.updateClusters(-1,!1,!0)},decreaseClusterLevel:function(){this.updateClusters(1,!1,!0)},updateClusters:function(t,e,i){var n=this.moving,s=this.nodeIndices.length;this.previousScale>this.scale&&0==t&&this._collapseSector(),this.previousScale>this.scale||-1==t?this._formClusters(i):(this.previousScalethis.scale||-1==t)&&(this._aggregateHubs(i),this._updateNodeIndexList()),(this.previousScale>this.scale||-1==t)&&(this.handleChains(),this._updateNodeIndexList()),this.previousScale=this.scale,this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.lengththis.constants.clustering.chainThreshold&&this._reduceAmountOfChains(1-this.constants.clustering.chainThreshold/t)},_aggregateHubs:function(t){this._getHubSize(),this._formClustersByHub(t,!1)},forceAggregateHubs:function(){var t=this.moving,e=this.nodeIndices.length;this._aggregateHubs(!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.length!=e&&(this.clusterSession+=1),this.moving!=t&&this.start()},_openClustersBySize:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];1==e.inView()&&(e.width*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientWidth||e.height*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientHeight)&&this.openCluster(e)}},_openClusters:function(t,e){for(var i=0;i1&&(t.clusterSizei)){var r=o.from,a=o.to;o.to.mass>o.from.mass&&(r=o.to,a=o.from),1==a.dynamicEdgesLength?this._addToCluster(r,a,!1):1==r.dynamicEdgesLength&&this._addToCluster(a,r,!1)}}},_forceClustersByZoom:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];if(1==e.dynamicEdgesLength&&0!=e.dynamicEdges.length){var i=e.dynamicEdges[0],n=i.toId==e.id?this.nodes[i.fromId]:this.nodes[i.toId];e.id!=n.id&&(n.mass>e.mass?this._addToCluster(n,e,!0):this._addToCluster(e,n,!0))}}},_formClustersByHub:function(t,e){for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&this._formClusterFromHub(this.nodes[i],t,e)},_formClusterFromHub:function(t,e,i,n){if(void 0===n&&(n=0),t.dynamicEdgesLength>=this.hubThreshold&&0==i||t.dynamicEdgesLength==this.hubThreshold&&1==i){for(var s,o,r,a=this.constants.clustering.clusterEdgeThreshold/this.scale,h=!1,d=[],c=t.dynamicEdges.length,l=0;c>l;l++)d.push(t.dynamicEdges[l].id);if(0==e)for(h=!1,l=0;c>l;l++){var u=this.edges[d[l]];if(void 0!==u&&u.connected&&u.toId!=u.fromId&&(s=u.to.x-u.from.x,o=u.to.y-u.from.y,r=Math.sqrt(s*s+o*o),a>r)){h=!0;break}}if(!e&&h||e)for(l=0;c>l;l++)if(u=this.edges[d[l]],void 0!==u){var p=this.nodes[u.fromId==t.id?u.toId:u.fromId];p.dynamicEdges.length<=this.hubThreshold+n&&p.id!=t.id&&this._addToCluster(t,p,e)}}},_addToCluster:function(t,e,i){t.containedNodes[e.id]=e;for(var n=0;n1)for(var n=0;n1&&(e.label="[".concat(String(e.clusterSize),"]"))}for(t in this.nodes)this.nodes.hasOwnProperty(t)&&(e=this.nodes[t],1==e.clusterSize&&(e.label=void 0!==e.originalLabel?e.originalLabel:String(e.id)))},_nodeInActiveArea:function(t){return Math.abs(t.x-this.areaCenter.x)<=this.constants.clustering.activeAreaBoxSize/this.scale&&Math.abs(t.y-this.areaCenter.y)<=this.constants.clustering.activeAreaBoxSize/this.scale},repositionNodes:function(){for(var t=0;tn&&(n=o.dynamicEdgesLength),t+=o.dynamicEdgesLength,e+=Math.pow(o.dynamicEdgesLength,2),i+=1}t/=i,e/=i;var r=e-Math.pow(t,2),a=Math.sqrt(r);this.hubThreshold=Math.floor(t+2*a),this.hubThreshold>n&&(this.hubThreshold=n)},_reduceAmountOfChains:function(t){this.hubThreshold=2;var e=Math.floor(this.nodeIndices.length*t);for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&e>0&&(this._formClusterFromHub(this.nodes[i],!0,!0,1),e-=1)},_getChainFraction:function(){var t=0,e=0;for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&(2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&(t+=1),e+=1);return t/e}},W={_getNodesOverlappingWith:function(t,e){var i=this.nodes;for(var n in i)i.hasOwnProperty(n)&&i[n].isOverlappingWith(t)&&e.push(n)},_getAllNodesOverlappingWith:function(t){var e=[];return this._doInAllActiveSectors("_getNodesOverlappingWith",t,e),e},_getAllNavigationNodesOverlappingWith:function(t){var e=[];return this._doInNavigationSector("_getNodesOverlappingWith",t,e),e},_pointerToPositionObject:function(t){var e=this._canvasToX(t.x),i=this._canvasToY(t.y);return{left:e,top:i,right:e,bottom:i}},_pointerToScreenPositionObject:function(t){var e=t.x,i=t.y;return{left:e,top:i,right:e,bottom:i}},_getNavigationNodeAt:function(t){var e=this._pointerToScreenPositionObject(t),i=this._getAllNavigationNodesOverlappingWith(e);return i.length>0?this.sectors.navigation.nodes[i[i.length-1]]:null},_getNodeAt:function(t){var e=this._pointerToPositionObject(t);return overlappingNodes=this._getAllNodesOverlappingWith(e),overlappingNodes.length>0?this.nodes[overlappingNodes[overlappingNodes.length-1]]:null},_getEdgeAt:function(){return null},_addToSelection:function(t){this.selection.push(t.id),this.selectionObj[t.id]=t},_removeFromSelection:function(t){for(var e=0;ee;e++){n=t[e];var s=this.nodes[n];if(!s)throw new RangeError('Node with id "'+n+'" not found');this._selectNode(s,!0,!0)}this.redraw()},_updateSelection:function(){for(var t=0;tt.x-t.width&&(n=t.x-t.width),st.y-t.height&&(e=t.y-t.height),i=this.constants.clustering.initialMaxNodes)var n=38.8467/(e-14.50184)+.0116;else var n=42.54117319/(e+39.31966387)+.1944405;else{var s=1.1*(Math.abs(i.minX)+Math.abs(i.maxX)),o=1.1*(Math.abs(i.minY)+Math.abs(i.maxY)),r=this.frame.canvas.clientWidth/s,a=this.frame.canvas.clientHeight/o;n=a>=r?r:a}n>1&&(n=1),this.pinch.mousewheelScale=n,this._setScale(n),this._centerGraph(i),this.start()},O.prototype._updateNodeIndexList=function(){this._clearNodeIndexList();for(var t in this.nodes)this.nodes.hasOwnProperty(t)&&this.nodeIndices.push(t)},O.prototype.setData=function(t,e){if(void 0===e&&(e=!1),t&&t.dot&&(t.nodes||t.edges))throw new SyntaxError('Data must contain either parameter "dot" or parameter pair "nodes" and "edges", but not both.');if(this.setOptions(t&&t.options),t&&t.dot){if(t&&t.dot){var i=U.util.DOTToGraph(t.dot);return void this.setData(i)}}else this._setNodes(t&&t.nodes),this._setEdges(t&&t.edges);this._putDataInSector(),e||(this.stabilize&&this._doStabilize(),this.moving=!0,this.start())},O.prototype.setOptions=function(t){if(t){if(void 0!==t.width&&(this.width=t.width),void 0!==t.height&&(this.height=t.height),void 0!==t.stabilize&&(this.stabilize=t.stabilize),void 0!==t.selectable&&(this.selectable=t.selectable),t.clustering){this.constants.clustering.enabled=!0;for(var e in t.clustering)t.clustering.hasOwnProperty(e)&&(this.constants.clustering[e]=t.clustering[e])}else void 0!==t.clustering&&(this.constants.clustering.enabled=!1);if(t.navigation){this.constants.navigation.enabled=!0;for(var e in t.navigation)t.navigation.hasOwnProperty(e)&&(this.constants.navigation[e]=t.navigation[e])}else void 0!==t.navigation&&(this.constants.navigation.enabled=!1);if(t.keyboard){this.constants.keyboard.enabled=!0;for(var e in t.keyboard)t.keyboard.hasOwnProperty(e)&&(this.constants.keyboard[e]=t.keyboard[e])}else void 0!==t.keyboard&&(this.constants.keyboard.enabled=!1);if(t.edges){for(e in t.edges)t.edges.hasOwnProperty(e)&&(this.constants.edges[e]=t.edges[e]);void 0!==t.edges.length&&t.nodes&&void 0===t.nodes.distance&&(this.constants.edges.length=t.edges.length,this.constants.nodes.distance=1.25*t.edges.length),t.edges.fontColor||(this.constants.edges.fontColor=t.edges.color),t.edges.dash&&(void 0!==t.edges.dash.length&&(this.constants.edges.dash.length=t.edges.dash.length),void 0!==t.edges.dash.gap&&(this.constants.edges.dash.gap=t.edges.dash.gap),void 0!==t.edges.dash.altLength&&(this.constants.edges.dash.altLength=t.edges.dash.altLength))}if(t.nodes){for(e in t.nodes)t.nodes.hasOwnProperty(e)&&(this.constants.nodes[e]=t.nodes[e]);t.nodes.color&&(this.constants.nodes.color=M.parseColor(t.nodes.color))}if(t.groups)for(var i in t.groups)if(t.groups.hasOwnProperty(i)){var n=t.groups[i];this.groups.add(i,n)}}this.setSize(this.width,this.height),this._setTranslation(this.frame.clientWidth/2,this.frame.clientHeight/2),this._setScale(1),this._loadNavigationControls(),this._createKeyBinds(),this._redraw()},O.prototype.on=function(t,e){var i=["select"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());F.addListener(this,t,e)},O.prototype.off=function(t,e){F.removeListener(this,t,e)},O.prototype._trigger=function(t,e){F.trigger(this,t,e)},O.prototype._create=function(){for(;this.containerElement.hasChildNodes();)this.containerElement.removeChild(this.containerElement.firstChild);if(this.frame=document.createElement("div"),this.frame.className="graph-frame",this.frame.style.position="relative",this.frame.style.overflow="hidden",this.frame.canvas=document.createElement("canvas"),this.frame.canvas.style.position="relative",this.frame.appendChild(this.frame.canvas),!this.frame.canvas.getContext){var t=document.createElement("DIV");t.style.color="red",t.style.fontWeight="bold",t.style.padding="10px",t.innerHTML="Error: your browser does not support HTML canvas",this.frame.canvas.appendChild(t)}var e=this;this.drag={},this.pinch={},this.hammer=N(this.frame.canvas,{prevent_default:!0}),this.hammer.on("tap",e._onTap.bind(e)),this.hammer.on("doubletap",e._onDoubleTap.bind(e)),this.hammer.on("hold",e._onHold.bind(e)),this.hammer.on("pinch",e._onPinch.bind(e)),this.hammer.on("touch",e._onTouch.bind(e)),this.hammer.on("dragstart",e._onDragStart.bind(e)),this.hammer.on("drag",e._onDrag.bind(e)),this.hammer.on("dragend",e._onDragEnd.bind(e)),this.hammer.on("release",e._onRelease.bind(e)),this.hammer.on("mousewheel",e._onMouseWheel.bind(e)),this.hammer.on("DOMMouseScroll",e._onMouseWheel.bind(e)),this.hammer.on("mousemove",e._onMouseMoveTitle.bind(e)),this.containerElement.appendChild(this.frame)},O.prototype._createKeyBinds=function(){var t=this;this.mousetrap=A,this.mousetrap.reset(),1==this.constants.keyboard.enabled&&(this.mousetrap.bind("up",this._moveUp.bind(t),"keydown"),this.mousetrap.bind("up",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("down",this._moveDown.bind(t),"keydown"),this.mousetrap.bind("down",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("left",this._moveLeft.bind(t),"keydown"),this.mousetrap.bind("left",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("right",this._moveRight.bind(t),"keydown"),this.mousetrap.bind("right",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("=",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("=",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("-",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("-",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("[",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("[",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("]",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("]",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pageup",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("pageup",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pagedown",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("pagedown",this._stopZoom.bind(t),"keyup"))},O.prototype._getPointer=function(t){return{x:t.pageX-U.util.getAbsoluteLeft(this.frame.canvas),y:t.pageY-U.util.getAbsoluteTop(this.frame.canvas)}},O.prototype._onTouch=function(t){this.drag.pointer=this._getPointer(t.gesture.touches[0]),this.drag.pinched=!1,this.pinch.scale=this._getScale(),this._handleTouch(this.drag.pointer)},O.prototype._onDragStart=function(){var t=this.drag,e=this._getNodeAt(t.pointer);if(t.dragging=!0,t.selection=[],t.translation=this._getTranslation(),t.nodeId=null,null!=e){t.nodeId=e.id,e.isSelected()||this._selectNode(e,!1);var i=this;this.selection.forEach(function(e){var n=i.nodes[e];if(n){var s={id:e,node:n,x:n.x,y:n.y,xFixed:n.xFixed,yFixed:n.yFixed};n.xFixed=!0,n.yFixed=!0,t.selection.push(s)}})}},O.prototype._onDrag=function(t){if(!this.drag.pinched){var e=this._getPointer(t.gesture.touches[0]),i=this,n=this.drag,s=n.selection;if(s&&s.length){var o=e.x-n.pointer.x,r=e.y-n.pointer.y;s.forEach(function(t){var e=t.node;t.xFixed||(e.x=i._canvasToX(i._xToCanvas(t.x)+o)),t.yFixed||(e.y=i._canvasToY(i._yToCanvas(t.y)+r))}),this.moving||(this.moving=!0,this.start())}else{var a=e.x-this.drag.pointer.x,h=e.y-this.drag.pointer.y;this._setTranslation(this.drag.translation.x+a,this.drag.translation.y+h),this._redraw(),this.moved=!0}}},O.prototype._onDragEnd=function(){this.drag.dragging=!1;var t=this.drag.selection;t&&t.forEach(function(t){t.node.xFixed=t.xFixed,t.node.yFixed=t.yFixed})},O.prototype._onTap=function(t){var e=this._getPointer(t.gesture.touches[0]);this._handleTap(e)},O.prototype._onDoubleTap=function(t){var e=this._getPointer(t.gesture.touches[0]);this._handleDoubleTap(e)},O.prototype._onHold=function(t){var e=this._getPointer(t.gesture.touches[0]);this._handleOnHold(e)},O.prototype._onRelease=function(){this._handleOnRelease()},O.prototype._onPinch=function(t){var e=this._getPointer(t.gesture.center);this.drag.pinched=!0,"scale"in this.pinch||(this.pinch.scale=1);var i=this.pinch.scale*t.gesture.scale;this._zoom(i,e)},O.prototype._zoom=function(t,e){var i=this._getScale();1e-5>t&&(t=1e-5),t>10&&(t=10);var n=this._getTranslation(),s=t/i,o=(1-s)*e.x+n.x*s,r=(1-s)*e.y+n.y*s;return this.areaCenter={x:this._canvasToX(e.x),y:this._canvasToY(e.y)},this.pinch.mousewheelScale=t,this._setScale(t),this._setTranslation(o,r),this.updateClustersDefault(),this._redraw(),t},O.prototype._onMouseWheel=function(t){var e=0;if(t.wheelDelta?e=t.wheelDelta/120:t.detail&&(e=-t.detail/3),e){"mousewheelScale"in this.pinch||(this.pinch.mousewheelScale=1);var i=this.pinch.mousewheelScale,n=e/10;0>e&&(n/=1-n),i*=1+n;var s=z.fakeGesture(this,t),o=this._getPointer(s.center);i=this._zoom(i,o)}t.preventDefault()},O.prototype._onMouseMoveTitle=function(t){var e=z.fakeGesture(this,t),i=this._getPointer(e.center);this.popupNode&&this._checkHidePopup(i);var n=this,s=function(){n._checkShowPopup(i)};this.popupTimer&&clearInterval(this.popupTimer),this.drag.dragging||(this.popupTimer=setTimeout(s,300))},O.prototype._checkShowPopup=function(t){var e,i={left:this._canvasToX(t.x),top:this._canvasToY(t.y),right:this._canvasToX(t.x),bottom:this._canvasToY(t.y)},n=this.popupNode;if(void 0==this.popupNode){var s=this.nodes;for(e in s)if(s.hasOwnProperty(e)){var o=s[e];if(void 0!==o.getTitle()&&o.isOverlappingWith(i)){this.popupNode=o;break}}}if(void 0===this.popupNode){var r=this.edges;for(e in r)if(r.hasOwnProperty(e)){var a=r[e];if(a.connected&&void 0!==a.getTitle()&&a.isOverlappingWith(i)){this.popupNode=a;break}}}if(this.popupNode){if(this.popupNode!=n){var h=this;h.popup||(h.popup=new I(h.frame)),h.popup.setPosition(t.x-3,t.y-3),h.popup.setText(h.popupNode.getTitle()),h.popup.show()}}else this.popup&&this.popup.hide()},O.prototype._checkHidePopup=function(t){this.popupNode&&this._getNodeAt(t)||(this.popupNode=void 0,this.popup&&this.popup.hide())},O.prototype._getConnectionCount=function(t){function e(t){for(var e=[],i=0,n=t.length;n>i;i++)for(var s=t[i],o=s.edges,r=0,a=o.length;a>r;r++){var h=o[r],d=null;h.from==s?d=h.to:h.to==s&&(d=h.from);var c,l;if(d)for(c=0,l=t.length;l>c;c++)if(t[c]==d){d=null;break}if(d)for(c=0,l=e.length;l>c;c++)if(e[c]==d){d=null;break}d&&e.push(d)}return e}void 0==t&&(t=1);var i=[],n=this.nodes;for(var s in n)if(n.hasOwnProperty(s)){for(var o=[n[s]],r=0;t>r;r++)o=o.concat(e(o));i.push(o)}for(var a=[],h=0,d=i.length;d>h;h++)a.push(i[h].length);return a},O.prototype.setSize=function(t,e){this.frame.style.width=t,this.frame.style.height=e,this.frame.canvas.style.width="100%",this.frame.canvas.style.height="100%",this.frame.canvas.width=this.frame.canvas.clientWidth,this.frame.canvas.height=this.frame.canvas.clientHeight,1==this.constants.navigation.enabled&&this._relocateNavigation()},O.prototype._setNodes=function(t){var e=this.nodesData;if(t instanceof o||t instanceof r)this.nodesData=t;else if(t instanceof Array)this.nodesData=new o,this.nodesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.nodesData=new o}if(e&&z.forEach(this.nodesListeners,function(t,i){e.unsubscribe(i,t)}),this.nodes={},this.nodesData){var i=this;z.forEach(this.nodesListeners,function(t,e){i.nodesData.subscribe(e,t)});var n=this.nodesData.getIds();this._addNodes(n)}this._updateSelection()},O.prototype._addNodes=function(t){for(var e,i=0,n=t.length;n>i;i++){e=t[i];var s=this.nodesData.get(e),o=new M(s,this.images,this.groups,this.constants);if(this.nodes[e]=o,!o.isFixed()){var r=2*this.constants.edges.length,a=t.length,h=2*Math.PI*(i/a);o.x=r*Math.cos(h),o.y=r*Math.sin(h),this.moving=!0}}this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(this.nodes)},O.prototype._updateNodes=function(t){for(var e=this.nodes,i=this.nodesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o],a=i.get(o);r?r.setProperties(a,this.constants):(r=new M(properties,this.images,this.groups,this.constants),e[o]=r,r.isFixed()||(this.moving=!0))}this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(e)},O.prototype._removeNodes=function(t){for(var e=this.nodes,i=0,n=t.length;n>i;i++){var s=t[i];delete e[s]}this._updateNodeIndexList(),this._reconnectEdges(),this._updateSelection(),this._updateValueRange(e)},O.prototype._setEdges=function(t){var e=this.edgesData;if(t instanceof o||t instanceof r)this.edgesData=t;else if(t instanceof Array)this.edgesData=new o,this.edgesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.edgesData=new o}if(e&&z.forEach(this.edgesListeners,function(t,i){e.unsubscribe(i,t)}),this.edges={},this.edgesData){var i=this;z.forEach(this.edgesListeners,function(t,e){i.edgesData.subscribe(e,t)});var n=this.edgesData.getIds();this._addEdges(n)}this._reconnectEdges()},O.prototype._addEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o];r&&r.disconnect();var a=i.get(o,{showInternalIds:!0});e[o]=new D(a,this,this.constants)}this.moving=!0,this._updateValueRange(e)},O.prototype._updateEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=i.get(o),a=e[o];a?(a.disconnect(),a.setProperties(r,this.constants),a.connect()):(a=new D(r,this,this.constants),this.edges[o]=a)}this.moving=!0,this._updateValueRange(e)},O.prototype._removeEdges=function(t){for(var e=this.edges,i=0,n=t.length;n>i;i++){var s=t[i],o=e[s];o&&(o.disconnect(),delete e[s])}this.moving=!0,this._updateValueRange(e)},O.prototype._reconnectEdges=function(){var t,e=this.nodes,i=this.edges;for(t in e)e.hasOwnProperty(t)&&(e[t].edges=[]);for(t in i)if(i.hasOwnProperty(t)){var n=i[t];n.from=null,n.to=null,n.connect()}},O.prototype._updateValueRange=function(t){var e,i=void 0,n=void 0;for(e in t)if(t.hasOwnProperty(e)){var s=t[e].getValue();void 0!==s&&(i=void 0===i?s:Math.min(s,i),n=void 0===n?s:Math.max(s,n))}if(void 0!==i&&void 0!==n)for(e in t)t.hasOwnProperty(e)&&t[e].setValueRange(i,n)},O.prototype.redraw=function(){this.setSize(this.width,this.height),this._redraw()},O.prototype._redraw=function(){var t=this.frame.canvas.getContext("2d"),e=this.frame.canvas.width,i=this.frame.canvas.height;t.clearRect(0,0,e,i),t.save(),t.translate(this.translation.x,this.translation.y),t.scale(this.scale,this.scale),this.canvasTopLeft={x:this._canvasToX(0),y:this._canvasToY(0)},this.canvasBottomRight={x:this._canvasToX(this.frame.canvas.clientWidth),y:this._canvasToY(this.frame.canvas.clientHeight)},this._doInAllSectors("_drawAllSectorNodes",t),this._doInAllSectors("_drawEdges",t),this._doInAllSectors("_drawNodes",t),t.restore(),1==this.constants.navigation.enabled&&this._doInNavigationSector("_drawNodes",t,!0)},O.prototype._setTranslation=function(t,e){void 0===this.translation&&(this.translation={x:0,y:0}),void 0!==t&&(this.translation.x=t),void 0!==e&&(this.translation.y=e)},O.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},O.prototype._setScale=function(t){this.scale=t},O.prototype._getScale=function(){return this.scale},O.prototype._canvasToX=function(t){return(t-this.translation.x)/this.scale},O.prototype._xToCanvas=function(t){return t*this.scale+this.translation.x},O.prototype._canvasToY=function(t){return(t-this.translation.y)/this.scale},O.prototype._yToCanvas=function(t){return t*this.scale+this.translation.y},O.prototype._drawNodes=function(t,e){void 0===e&&(e=!1);var i=this.nodes,n=[];for(var s in i)i.hasOwnProperty(s)&&(i[s].setScaleAndPos(this.scale,this.canvasTopLeft,this.canvasBottomRight),i[s].isSelected()?n.push(s):(i[s].inArea()||e)&&i[s].draw(t));for(var o=0,r=n.length;r>o;o++)(i[n[o]].inArea()||e)&&i[n[o]].draw(t)},O.prototype._drawEdges=function(t){var e=this.edges;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];n.setScale(this.scale),n.connected&&e[i].draw(t)}},O.prototype._doStabilize=function(){for(var t=0,e=this.constants.minVelocity,i=!1;!i&&tthis.constants.clustering.clusterThreshold&&1==this.constants.clustering.enabled&&this.clusterToFit(this.constants.clustering.reduceToNodes,!1),this._calculateForces())},O.prototype._calculateForces=function(){var t,e,i,n,s,o,r,a,h,d,c,l,u,p,f,g,m,v,y=this.nodes,_=this.edges,w=.08*this.forceFactor;for(g=0;gn&&(i=Math.atan2(e,t),r=.5*b>n?1:1/(1+Math.exp((n/b-1)*S)),r*=0==v?1:1+v*this.constants.clustering.forceAmplification,r*=this.forceFactor,s=Math.cos(i)*r,o=Math.sin(i)*r,l._addForce(-s,-o),u._addForce(s,o));for(f in _)_.hasOwnProperty(f)&&(p=_[f],p.connected&&this.nodes.hasOwnProperty(p.toId)&&this.nodes.hasOwnProperty(p.fromId)&&(v=p.to.clusterSize+p.from.clusterSize-2,t=p.to.x-p.from.x,e=p.to.y-p.from.y,d=p.length,d+=v*this.constants.clustering.edgeGrowth,h=Math.sqrt(t*t+e*e),i=Math.atan2(e,t),a=p.stiffness*(d-h)*this.forceFactor,s=Math.cos(i)*a,o=Math.sin(i)*a,p.from._addForce(-s,-o),p.to._addForce(s,o)))},O.prototype._isMoving=function(t){var e=t/this.scale,i=this.nodes;for(var n in i)if(i.hasOwnProperty(n)&&i[n].isMoving(e))return!0;return!1},O.prototype._discreteStepNodes=function(){var t=.01,e=this.nodes;for(var i in e)e.hasOwnProperty(i)&&e[i].discreteStep(t);var n=this.constants.minVelocity;this.moving=this._isMoving(n)},O.prototype.start=function(){if(!this.freezeSimulation)if(this.moving&&(this._doInAllActiveSectors("_initializeForceCalculation"),this._doInAllActiveSectors("_discreteStepNodes"),this._findCenter(this._getRange())),this.moving||0!=this.xIncrement||0!=this.yIncrement||0!=this.zoomIncrement){if(!this.timer){var t=this;this.timer=window.setTimeout(function(){if(t.timer=void 0,0!=t.xIncrement||0!=t.yIncrement){var e=t._getTranslation();t._setTranslation(e.x+t.xIncrement,e.y+t.yIncrement)}if(0!=t.zoomIncrement){var i={x:t.frame.canvas.clientWidth/2,y:t.frame.canvas.clientHeight/2};t._zoom(t.scale*(1+t.zoomIncrement),i)}t.start(),t._redraw()},this.renderTimestep)}}else this._redraw()},O.prototype.singleStep=function(){if(this.moving){this._initializeForceCalculation(),this._discreteStepNodes();var t=this.constants.minVelocity;this.moving=this._isMoving(t),this._redraw()}},O.prototype.toggleFreeze=function(){0==this.freezeSimulation?this.freezeSimulation=!0:(this.freezeSimulation=!1,this.start())},O.prototype._loadClusterSystem=function(){this.clusterSession=0,this.hubThreshold=5;for(var t in H)H.hasOwnProperty(t)&&(O.prototype[t]=H[t])},O.prototype._loadSectorSystem=function(){this.sectors={},this.activeSector=["default"],this.sectors.active={},this.sectors.active["default"]={nodes:{},edges:{},nodeIndices:[],formationScale:1,drawingNode:void 0},this.sectors.frozen={},this.sectors.navigation={nodes:{},edges:{},nodeIndices:[],formationScale:1,drawingNode:void 0},this.nodeIndices=this.sectors.active["default"].nodeIndices;for(var t in R)R.hasOwnProperty(t)&&(O.prototype[t]=R[t])},O.prototype._loadSelectionSystem=function(){this.selection=[],this.selectionObj={};for(var t in W)W.hasOwnProperty(t)&&(O.prototype[t]=W[t])},O.prototype._loadNavigationControls=function(){for(var t in j)j.hasOwnProperty(t)&&(O.prototype[t]=j[t]);1==this.constants.navigation.enabled&&this._loadNavigationElements()},O.prototype._relocateNavigation=function(){},O.prototype._unHighlightAll=function(){};var U={util:z,events:F,Controller:l,DataSet:o,DataView:r,Range:h,Stack:a,TimeStep:TimeStep,EventBus:s,components:{items:{Item:_,ItemBox:w,ItemPoint:b,ItemRange:S},Component:u,Panel:p,RootPanel:f,ItemSet:y,TimeAxis:g},graph:{Node:M,Edge:D,Popup:I,Groups:Groups,Images:Images},Timeline:C,Graph:O};"undefined"!=typeof n&&(n=U),"undefined"!=typeof i&&"undefined"!=typeof i.exports&&(i.exports=U),"function"==typeof t&&t(function(){return U}),"undefined"!=typeof window&&(window.vis=U)},{hammerjs:2,moment:3,mousetrap:4}],2:[function(t,e){!function(t,i){"use strict";function n(){if(!s.READY){s.event.determineEventTypes();for(var t in s.gestures)s.gestures.hasOwnProperty(t)&&s.detection.register(s.gestures[t]);s.event.onTouch(s.DOCUMENT,s.EVENT_MOVE,s.detection.detect),s.event.onTouch(s.DOCUMENT,s.EVENT_END,s.detection.detect),s.READY=!0}}var s=function(t,e){return new s.Instance(t,e||{})};s.defaults={stop_browser_behavior:{userSelect:"none",touchAction:"none",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}},s.HAS_POINTEREVENTS=navigator.pointerEnabled||navigator.msPointerEnabled,s.HAS_TOUCHEVENTS="ontouchstart"in t,s.MOBILE_REGEX=/mobile|tablet|ip(ad|hone|od)|android/i,s.NO_MOUSEEVENTS=s.HAS_TOUCHEVENTS&&navigator.userAgent.match(s.MOBILE_REGEX),s.EVENT_TYPES={},s.DIRECTION_DOWN="down",s.DIRECTION_LEFT="left",s.DIRECTION_UP="up",s.DIRECTION_RIGHT="right",s.POINTER_MOUSE="mouse",s.POINTER_TOUCH="touch",s.POINTER_PEN="pen",s.EVENT_START="start",s.EVENT_MOVE="move",s.EVENT_END="end",s.DOCUMENT=document,s.plugins={},s.READY=!1,s.Instance=function(t,e){var i=this; +return n(),this.element=t,this.enabled=!0,this.options=s.utils.extend(s.utils.extend({},s.defaults),e||{}),this.options.stop_browser_behavior&&s.utils.stopDefaultBrowserBehavior(this.element,this.options.stop_browser_behavior),s.event.onTouch(t,s.EVENT_START,function(t){i.enabled&&s.detection.startDetect(i,t)}),this},s.Instance.prototype={on:function(t,e){for(var i=t.split(" "),n=0;n0&&e==s.EVENT_END?e=s.EVENT_MOVE:c||(e=s.EVENT_END),c||null===o?o=h:h=o,i.call(s.detection,n.collectEventData(t,e,h)),s.HAS_POINTEREVENTS&&e==s.EVENT_END&&(c=s.PointerEvent.updatePointer(e,h))),c||(o=null,r=!1,a=!1,s.PointerEvent.reset())}})},determineEventTypes:function(){var t;t=s.HAS_POINTEREVENTS?s.PointerEvent.getEvents():s.NO_MOUSEEVENTS?["touchstart","touchmove","touchend touchcancel"]:["touchstart mousedown","touchmove mousemove","touchend touchcancel mouseup"],s.EVENT_TYPES[s.EVENT_START]=t[0],s.EVENT_TYPES[s.EVENT_MOVE]=t[1],s.EVENT_TYPES[s.EVENT_END]=t[2]},getTouchList:function(t){return s.HAS_POINTEREVENTS?s.PointerEvent.getTouchList():t.touches?t.touches:[{identifier:1,pageX:t.pageX,pageY:t.pageY,target:t.target}]},collectEventData:function(t,e,i){var n=this.getTouchList(i,e),o=s.POINTER_TOUCH;return(i.type.match(/mouse/)||s.PointerEvent.matchType(s.POINTER_MOUSE,i))&&(o=s.POINTER_MOUSE),{center:s.utils.getCenter(n),timeStamp:(new Date).getTime(),target:i.target,touches:n,eventType:e,pointerType:o,srcEvent:i,preventDefault:function(){this.srcEvent.preventManipulation&&this.srcEvent.preventManipulation(),this.srcEvent.preventDefault&&this.srcEvent.preventDefault()},stopPropagation:function(){this.srcEvent.stopPropagation()},stopDetect:function(){return s.detection.stopDetect()}}}},s.PointerEvent={pointers:{},getTouchList:function(){var t=this,e=[];return Object.keys(t.pointers).sort().forEach(function(i){e.push(t.pointers[i])}),e},updatePointer:function(t,e){return t==s.EVENT_END?this.pointers={}:(e.identifier=e.pointerId,this.pointers[e.pointerId]=e),Object.keys(this.pointers).length},matchType:function(t,e){if(!e.pointerType)return!1;var i={};return i[s.POINTER_MOUSE]=e.pointerType==e.MSPOINTER_TYPE_MOUSE||e.pointerType==s.POINTER_MOUSE,i[s.POINTER_TOUCH]=e.pointerType==e.MSPOINTER_TYPE_TOUCH||e.pointerType==s.POINTER_TOUCH,i[s.POINTER_PEN]=e.pointerType==e.MSPOINTER_TYPE_PEN||e.pointerType==s.POINTER_PEN,i[t]},getEvents:function(){return["pointerdown MSPointerDown","pointermove MSPointerMove","pointerup pointercancel MSPointerUp MSPointerCancel"]},reset:function(){this.pointers={}}},s.utils={extend:function(t,e,n){for(var s in e)t[s]!==i&&n||(t[s]=e[s]);return t},hasParent:function(t,e){for(;t;){if(t==e)return!0;t=t.parentNode}return!1},getCenter:function(t){for(var e=[],i=[],n=0,s=t.length;s>n;n++)e.push(t[n].pageX),i.push(t[n].pageY);return{pageX:(Math.min.apply(Math,e)+Math.max.apply(Math,e))/2,pageY:(Math.min.apply(Math,i)+Math.max.apply(Math,i))/2}},getVelocity:function(t,e,i){return{x:Math.abs(e/t)||0,y:Math.abs(i/t)||0}},getAngle:function(t,e){var i=e.pageY-t.pageY,n=e.pageX-t.pageX;return 180*Math.atan2(i,n)/Math.PI},getDirection:function(t,e){var i=Math.abs(t.pageX-e.pageX),n=Math.abs(t.pageY-e.pageY);return i>=n?t.pageX-e.pageX>0?s.DIRECTION_LEFT:s.DIRECTION_RIGHT:t.pageY-e.pageY>0?s.DIRECTION_UP:s.DIRECTION_DOWN},getDistance:function(t,e){var i=e.pageX-t.pageX,n=e.pageY-t.pageY;return Math.sqrt(i*i+n*n)},getScale:function(t,e){return t.length>=2&&e.length>=2?this.getDistance(e[0],e[1])/this.getDistance(t[0],t[1]):1},getRotation:function(t,e){return t.length>=2&&e.length>=2?this.getAngle(e[1],e[0])-this.getAngle(t[1],t[0]):0},isVertical:function(t){return t==s.DIRECTION_UP||t==s.DIRECTION_DOWN},stopDefaultBrowserBehavior:function(t,e){var i,n=["webkit","khtml","moz","ms","o",""];if(e&&t.style){for(var s=0;si;i++){var o=this.gestures[i];if(!this.stopped&&e[o.name]!==!1&&o.handler.call(o,t,this.current.inst)===!1){this.stopDetect();break}}return this.current&&(this.current.lastEvent=t),t.eventType==s.EVENT_END&&!t.touches.length-1&&this.stopDetect(),t}},stopDetect:function(){this.previous=s.utils.extend({},this.current),this.current=null,this.stopped=!0},extendEventData:function(t){var e=this.current.startEvent;if(e&&(t.touches.length!=e.touches.length||t.touches===e.touches)){e.touches=[];for(var i=0,n=t.touches.length;n>i;i++)e.touches.push(s.utils.extend({},t.touches[i]))}var o=t.timeStamp-e.timeStamp,r=t.center.pageX-e.center.pageX,a=t.center.pageY-e.center.pageY,h=s.utils.getVelocity(o,r,a);return s.utils.extend(t,{deltaTime:o,deltaX:r,deltaY:a,velocityX:h.x,velocityY:h.y,distance:s.utils.getDistance(e.center,t.center),angle:s.utils.getAngle(e.center,t.center),direction:s.utils.getDirection(e.center,t.center),scale:s.utils.getScale(e.touches,t.touches),rotation:s.utils.getRotation(e.touches,t.touches),startEvent:e}),t},register:function(t){var e=t.defaults||{};return e[t.name]===i&&(e[t.name]=!0),s.utils.extend(s.defaults,e,!0),t.index=t.index||1e3,this.gestures.push(t),this.gestures.sort(function(t,e){return t.indexe.index?1:0}),this.gestures}},s.gestures=s.gestures||{},s.gestures.Hold={name:"hold",index:10,defaults:{hold_timeout:500,hold_threshold:1},timer:null,handler:function(t,e){switch(t.eventType){case s.EVENT_START:clearTimeout(this.timer),s.detection.current.name=this.name,this.timer=setTimeout(function(){"hold"==s.detection.current.name&&e.trigger("hold",t)},e.options.hold_timeout);break;case s.EVENT_MOVE:t.distance>e.options.hold_threshold&&clearTimeout(this.timer);break;case s.EVENT_END:clearTimeout(this.timer)}}},s.gestures.Tap={name:"tap",index:100,defaults:{tap_max_touchtime:250,tap_max_distance:10,tap_always:!0,doubletap_distance:20,doubletap_interval:300},handler:function(t,e){if(t.eventType==s.EVENT_END){var i=s.detection.previous,n=!1;if(t.deltaTime>e.options.tap_max_touchtime||t.distance>e.options.tap_max_distance)return;i&&"tap"==i.name&&t.timeStamp-i.lastEvent.timeStamp0&&t.touches.length>e.options.swipe_max_touches)return;(t.velocityX>e.options.swipe_velocity||t.velocityY>e.options.swipe_velocity)&&(e.trigger(this.name,t),e.trigger(this.name+t.direction,t))}}},s.gestures.Drag={name:"drag",index:50,defaults:{drag_min_distance:10,drag_max_touches:1,drag_block_horizontal:!1,drag_block_vertical:!1,drag_lock_to_axis:!1,drag_lock_min_distance:25},triggered:!1,handler:function(t,e){if(s.detection.current.name!=this.name&&this.triggered)return e.trigger(this.name+"end",t),void(this.triggered=!1);if(!(e.options.drag_max_touches>0&&t.touches.length>e.options.drag_max_touches))switch(t.eventType){case s.EVENT_START:this.triggered=!1;break;case s.EVENT_MOVE:if(t.distancee.options.transform_min_rotation&&e.trigger("rotate",t),i>e.options.transform_min_scale&&(e.trigger("pinch",t),e.trigger("pinch"+(t.scale<1?"in":"out"),t));break;case s.EVENT_END:this.triggered&&e.trigger(this.name+"end",t),this.triggered=!1}}},s.gestures.Touch={name:"touch",index:-1/0,defaults:{prevent_default:!1,prevent_mouseevents:!1},handler:function(t,e){return e.options.prevent_mouseevents&&t.pointerType==s.POINTER_MOUSE?void t.stopDetect():(e.options.prevent_default&&t.preventDefault(),void(t.eventType==s.EVENT_START&&e.trigger(this.name,t)))}},s.gestures.Release={name:"release",index:1/0,handler:function(t,e){t.eventType==s.EVENT_END&&e.trigger(this.name,t)}},"object"==typeof e&&"object"==typeof e.exports?e.exports=s:(t.Hammer=s,"function"==typeof t.define&&t.define.amd&&t.define("hammer",[],function(){return s}))}(this)},{}],3:[function(e,i){(function(n){function s(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function o(t,e){return function(i){return p(t.call(this,i),e)}}function r(t,e){return function(i){return this.lang().ordinal(t.call(this,i),e)}}function a(){}function h(t){x(t),c(this,t)}function d(t){var e=_(t),i=e.year||0,n=e.month||0,s=e.week||0,o=e.day||0,r=e.hour||0,a=e.minute||0,h=e.second||0,d=e.millisecond||0;this._milliseconds=+d+1e3*h+6e4*a+36e5*r,this._days=+o+7*s,this._months=+n+12*i,this._data={},this._bubble()}function c(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return e.hasOwnProperty("toString")&&(t.toString=e.toString),e.hasOwnProperty("valueOf")&&(t.valueOf=e.valueOf),t}function l(t){var e,i={};for(e in t)t.hasOwnProperty(e)&&_e.hasOwnProperty(e)&&(i[e]=t[e]);return i}function u(t){return 0>t?Math.ceil(t):Math.floor(t)}function p(t,e,i){for(var n=""+Math.abs(t),s=t>=0;n.lengthn;n++)(i&&t[n]!==e[n]||!i&&b(t[n])!==b(e[n]))&&r++;return r+o}function y(t){if(t){var e=t.toLowerCase().replace(/(.)s$/,"$1");t=Xe[t]||Ze[e]||e}return t}function _(t){var e,i,n={};for(i in t)t.hasOwnProperty(i)&&(e=y(i),e&&(n[e]=t[i]));return n}function w(t){var e,i;if(0===t.indexOf("week"))e=7,i="day";else{if(0!==t.indexOf("month"))return;e=12,i="month"}re[t]=function(s,o){var r,a,h=re.fn._lang[t],d=[];if("number"==typeof s&&(o=s,s=n),a=function(t){var e=re().utc().set(i,t);return h.call(re.fn._lang,e,s||"")},null!=o)return a(o);for(r=0;e>r;r++)d.push(a(r));return d}}function b(t){var e=+t,i=0;return 0!==e&&isFinite(e)&&(i=e>=0?Math.floor(e):Math.ceil(e)),i}function S(t,e){return new Date(Date.UTC(t,e+1,0)).getUTCDate()}function E(t){return T(t)?366:365}function T(t){return t%4===0&&t%100!==0||t%400===0}function x(t){var e;t._a&&-2===t._pf.overflow&&(e=t._a[ue]<0||t._a[ue]>11?ue:t._a[pe]<1||t._a[pe]>S(t._a[le],t._a[ue])?pe:t._a[fe]<0||t._a[fe]>23?fe:t._a[ge]<0||t._a[ge]>59?ge:t._a[me]<0||t._a[me]>59?me:t._a[ve]<0||t._a[ve]>999?ve:-1,t._pf._overflowDayOfYear&&(le>e||e>pe)&&(e=pe),t._pf.overflow=e)}function C(t){return null==t._isValid&&(t._isValid=!isNaN(t._d.getTime())&&t._pf.overflow<0&&!t._pf.empty&&!t._pf.invalidMonth&&!t._pf.nullInput&&!t._pf.invalidFormat&&!t._pf.userInvalidated,t._strict&&(t._isValid=t._isValid&&0===t._pf.charsLeftOver&&0===t._pf.unusedTokens.length)),t._isValid}function M(t){return t?t.toLowerCase().replace("_","-"):t}function D(t,e){return e._isUTC?re(t).zone(e._offset||0):re(t).local()}function I(t,e){return e.abbr=t,ye[t]||(ye[t]=new a),ye[t].set(e),ye[t]}function O(t){delete ye[t]}function N(t){var i,n,s,o,r=0,a=function(t){if(!ye[t]&&we)try{e("./lang/"+t)}catch(i){}return ye[t]};if(!t)return re.fn._lang;if(!g(t)){if(n=a(t))return n;t=[t]}for(;r0;){if(n=a(o.slice(0,i).join("-")))return n;if(s&&s.length>=i&&v(o,s,!0)>=i-1)break;i--}r++}return re.fn._lang}function L(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function A(t){var e,i,n=t.match(Te);for(e=0,i=n.length;i>e;e++)n[e]=Je[n[e]]?Je[n[e]]:L(n[e]);return function(s){var o="";for(e=0;i>e;e++)o+=n[e]instanceof Function?n[e].call(s,t):n[e];return o}}function k(t,e){return t.isValid()?(e=z(e,t.lang()),Ke[e]||(Ke[e]=A(e)),Ke[e](t)):t.lang().invalidDate()}function z(t,e){function i(t){return e.longDateFormat(t)||t}var n=5;for(xe.lastIndex=0;n>=0&&xe.test(t);)t=t.replace(xe,i),xe.lastIndex=0,n-=1;return t}function P(t,e){var i,n=e._strict;switch(t){case"DDDD":return Fe;case"YYYY":case"GGGG":case"gggg":return n?Ye:De;case"Y":case"G":case"g":return He;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return n?Re:Ie;case"S":if(n)return ze;case"SS":if(n)return Pe;case"SSS":if(n)return Fe;case"DDD":return Me;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Ne;case"a":case"A":return N(e._l)._meridiemParse;case"X":return ke;case"Z":case"ZZ":return Le;case"T":return Ae;case"SSSS":return Oe;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return n?Pe:Ce;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return Ce;default:return i=new RegExp(V(U(t.replace("\\","")),"i"))}}function F(t){t=t||"";var e=t.match(Le)||[],i=e[e.length-1]||[],n=(i+"").match(Ge)||["-",0,0],s=+(60*n[1])+b(n[2]);return"+"===n[0]?-s:s}function Y(t,e,i){var n,s=i._a;switch(t){case"M":case"MM":null!=e&&(s[ue]=b(e)-1);break;case"MMM":case"MMMM":n=N(i._l).monthsParse(e),null!=n?s[ue]=n:i._pf.invalidMonth=e;break;case"D":case"DD":null!=e&&(s[pe]=b(e));break;case"DDD":case"DDDD":null!=e&&(i._dayOfYear=b(e));break;case"YY":s[le]=b(e)+(b(e)>68?1900:2e3);break;case"YYYY":case"YYYYY":case"YYYYYY":s[le]=b(e);break;case"a":case"A":i._isPm=N(i._l).isPM(e);break;case"H":case"HH":case"h":case"hh":s[fe]=b(e);break;case"m":case"mm":s[ge]=b(e);break;case"s":case"ss":s[me]=b(e);break;case"S":case"SS":case"SSS":case"SSSS":s[ve]=b(1e3*("0."+e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,i._tzm=F(e);break;case"w":case"ww":case"W":case"WW":case"d":case"dd":case"ddd":case"dddd":case"e":case"E":t=t.substr(0,1);case"gg":case"gggg":case"GG":case"GGGG":case"GGGGG":t=t.substr(0,2),e&&(i._w=i._w||{},i._w[t]=e)}}function R(t){var e,i,n,s,o,r,a,h,d,c,l=[];if(!t._d){for(n=W(t),t._w&&null==t._a[pe]&&null==t._a[ue]&&(o=function(e){var i=parseInt(e,10);return e?e.length<3?i>68?1900+i:2e3+i:i:null==t._a[le]?re().weekYear():t._a[le]},r=t._w,null!=r.GG||null!=r.W||null!=r.E?a=te(o(r.GG),r.W||1,r.E,4,1):(h=N(t._l),d=null!=r.d?K(r.d,h):null!=r.e?parseInt(r.e,10)+h._week.dow:0,c=parseInt(r.w,10)||1,null!=r.d&&dE(s)&&(t._pf._overflowDayOfYear=!0),i=Z(s,0,t._dayOfYear),t._a[ue]=i.getUTCMonth(),t._a[pe]=i.getUTCDate()),e=0;3>e&&null==t._a[e];++e)t._a[e]=l[e]=n[e];for(;7>e;e++)t._a[e]=l[e]=null==t._a[e]?2===e?1:0:t._a[e];l[fe]+=b((t._tzm||0)/60),l[ge]+=b((t._tzm||0)%60),t._d=(t._useUTC?Z:X).apply(null,l)}}function H(t){var e;t._d||(e=_(t._i),t._a=[e.year,e.month,e.day,e.hour,e.minute,e.second,e.millisecond],R(t))}function W(t){var e=new Date;return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function j(t){t._a=[],t._pf.empty=!0;var e,i,n,s,o,r=N(t._l),a=""+t._i,h=a.length,d=0;for(n=z(t._f,r).match(Te)||[],e=0;e0&&t._pf.unusedInput.push(o),a=a.slice(a.indexOf(i)+i.length),d+=i.length),Je[s]?(i?t._pf.empty=!1:t._pf.unusedTokens.push(s),Y(s,i,t)):t._strict&&!i&&t._pf.unusedTokens.push(s);t._pf.charsLeftOver=h-d,a.length>0&&t._pf.unusedInput.push(a),t._isPm&&t._a[fe]<12&&(t._a[fe]+=12),t._isPm===!1&&12===t._a[fe]&&(t._a[fe]=0),R(t),x(t)}function U(t){return t.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,i,n,s){return e||i||n||s})}function V(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function G(t){var e,i,n,o,r;if(0===t._f.length)return t._pf.invalidFormat=!0,void(t._d=new Date(0/0));for(o=0;or)&&(n=r,i=e));c(t,i||e)}function B(t){var e,i,n=t._i,s=We.exec(n);if(s){for(t._pf.iso=!0,e=0,i=Ue.length;i>e;e++)if(Ue[e][1].exec(n)){t._f=Ue[e][0]+(s[6]||" ");break}for(e=0,i=Ve.length;i>e;e++)if(Ve[e][1].exec(n)){t._f+=Ve[e][0];break}n.match(Le)&&(t._f+="Z"),j(t)}else t._d=new Date(n)}function q(t){var e=t._i,i=be.exec(e);e===n?t._d=new Date:i?t._d=new Date(+i[1]):"string"==typeof e?B(t):g(e)?(t._a=e.slice(0),R(t)):m(e)?t._d=new Date(+e):"object"==typeof e?H(t):t._d=new Date(e)}function X(t,e,i,n,s,o,r){var a=new Date(t,e,i,n,s,o,r);return 1970>t&&a.setFullYear(t),a}function Z(t){var e=new Date(Date.UTC.apply(null,arguments));return 1970>t&&e.setUTCFullYear(t),e}function K(t,e){if("string"==typeof t)if(isNaN(t)){if(t=e.weekdaysParse(t),"number"!=typeof t)return null}else t=parseInt(t,10);return t}function $(t,e,i,n,s){return s.relativeTime(e||1,!!i,t,n)}function Q(t,e,i){var n=ce(Math.abs(t)/1e3),s=ce(n/60),o=ce(s/60),r=ce(o/24),a=ce(r/365),h=45>n&&["s",n]||1===s&&["m"]||45>s&&["mm",s]||1===o&&["h"]||22>o&&["hh",o]||1===r&&["d"]||25>=r&&["dd",r]||45>=r&&["M"]||345>r&&["MM",ce(r/30)]||1===a&&["y"]||["yy",a];return h[2]=e,h[3]=t>0,h[4]=i,$.apply({},h)}function J(t,e,i){var n,s=i-e,o=i-t.day();return o>s&&(o-=7),s-7>o&&(o+=7),n=re(t).add("d",o),{week:Math.ceil(n.dayOfYear()/7),year:n.year()}}function te(t,e,i,n,s){var o,r,a=Z(t,0,1).getUTCDay();return i=null!=i?i:s,o=s-a+(a>n?7:0)-(s>a?7:0),r=7*(e-1)+(i-s)+o+1,{year:r>0?t:t-1,dayOfYear:r>0?r:E(t-1)+r}}function ee(t){var e=t._i,i=t._f;return null===e?re.invalid({nullInput:!0}):("string"==typeof e&&(t._i=e=N().preparse(e)),re.isMoment(e)?(t=l(e),t._d=new Date(+e._d)):i?g(i)?G(t):j(t):q(t),new h(t))}function ie(t,e){re.fn[t]=re.fn[t+"s"]=function(t){var i=this._isUTC?"UTC":"";return null!=t?(this._d["set"+i+e](t),re.updateOffset(this),this):this._d["get"+i+e]()}}function ne(t){re.duration.fn[t]=function(){return this._data[t]}}function se(t,e){re.duration.fn["as"+t]=function(){return+this/e}}function oe(t){var e=!1,i=re;"undefined"==typeof ender&&(t?(de.moment=function(){return!e&&console&&console.warn&&(e=!0,console.warn("Accessing Moment through the global scope is deprecated, and will be removed in an upcoming release.")),i.apply(null,arguments)},c(de.moment,i)):de.moment=re)}for(var re,ae,he="2.5.1",de=this,ce=Math.round,le=0,ue=1,pe=2,fe=3,ge=4,me=5,ve=6,ye={},_e={_isAMomentObject:null,_i:null,_f:null,_l:null,_strict:null,_isUTC:null,_offset:null,_pf:null,_lang:null},we="undefined"!=typeof i&&i.exports&&"undefined"!=typeof e,be=/^\/?Date\((\-?\d+)/i,Se=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,Ee=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,Te=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g,xe=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,Ce=/\d\d?/,Me=/\d{1,3}/,De=/\d{1,4}/,Ie=/[+\-]?\d{1,6}/,Oe=/\d+/,Ne=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Le=/Z|[\+\-]\d\d:?\d\d/gi,Ae=/T/i,ke=/[\+\-]?\d+(\.\d{1,3})?/,ze=/\d/,Pe=/\d\d/,Fe=/\d{3}/,Ye=/\d{4}/,Re=/[+-]?\d{6}/,He=/[+-]?\d+/,We=/^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,je="YYYY-MM-DDTHH:mm:ssZ",Ue=[["YYYYYY-MM-DD",/[+-]\d{6}-\d{2}-\d{2}/],["YYYY-MM-DD",/\d{4}-\d{2}-\d{2}/],["GGGG-[W]WW-E",/\d{4}-W\d{2}-\d/],["GGGG-[W]WW",/\d{4}-W\d{2}/],["YYYY-DDD",/\d{4}-\d{3}/]],Ve=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d{1,3}/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],Ge=/([\+\-]|\d\d)/gi,Be="Date|Hours|Minutes|Seconds|Milliseconds".split("|"),qe={Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6},Xe={ms:"millisecond",s:"second",m:"minute",h:"hour",d:"day",D:"date",w:"week",W:"isoWeek",M:"month",y:"year",DDD:"dayOfYear",e:"weekday",E:"isoWeekday",gg:"weekYear",GG:"isoWeekYear"},Ze={dayofyear:"dayOfYear",isoweekday:"isoWeekday",isoweek:"isoWeek",weekyear:"weekYear",isoweekyear:"isoWeekYear"},Ke={},$e="DDD w W M D d".split(" "),Qe="M D H h m s w W".split(" "),Je={M:function(){return this.month()+1},MMM:function(t){return this.lang().monthsShort(this,t)},MMMM:function(t){return this.lang().months(this,t)},D:function(){return this.date()},DDD:function(){return this.dayOfYear()},d:function(){return this.day()},dd:function(t){return this.lang().weekdaysMin(this,t)},ddd:function(t){return this.lang().weekdaysShort(this,t)},dddd:function(t){return this.lang().weekdays(this,t)},w:function(){return this.week()},W:function(){return this.isoWeek()},YY:function(){return p(this.year()%100,2)},YYYY:function(){return p(this.year(),4)},YYYYY:function(){return p(this.year(),5)},YYYYYY:function(){var t=this.year(),e=t>=0?"+":"-";return e+p(Math.abs(t),6)},gg:function(){return p(this.weekYear()%100,2)},gggg:function(){return p(this.weekYear(),4)},ggggg:function(){return p(this.weekYear(),5)},GG:function(){return p(this.isoWeekYear()%100,2)},GGGG:function(){return p(this.isoWeekYear(),4)},GGGGG:function(){return p(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.lang().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.lang().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return b(this.milliseconds()/100)},SS:function(){return p(b(this.milliseconds()/10),2)},SSS:function(){return p(this.milliseconds(),3)},SSSS:function(){return p(this.milliseconds(),3)},Z:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(b(t/60),2)+":"+p(b(t)%60,2)},ZZ:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(b(t/60),2)+p(b(t)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},X:function(){return this.unix()},Q:function(){return this.quarter()}},ti=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"];$e.length;)ae=$e.pop(),Je[ae+"o"]=r(Je[ae],ae);for(;Qe.length;)ae=Qe.pop(),Je[ae+ae]=o(Je[ae],2);for(Je.DDDD=o(Je.DDD,3),c(a.prototype,{set:function(t){var e,i;for(i in t)e=t[i],"function"==typeof e?this[i]=e:this["_"+i]=e},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(t){return this._months[t.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(t){return this._monthsShort[t.month()]},monthsParse:function(t){var e,i,n;for(this._monthsParse||(this._monthsParse=[]),e=0;12>e;e++)if(this._monthsParse[e]||(i=re.utc([2e3,e]),n="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[e]=new RegExp(n.replace(".",""),"i")),this._monthsParse[e].test(t))return e},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(t){return this._weekdays[t.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(t){return this._weekdaysShort[t.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(t){return this._weekdaysMin[t.day()]},weekdaysParse:function(t){var e,i,n;for(this._weekdaysParse||(this._weekdaysParse=[]),e=0;7>e;e++)if(this._weekdaysParse[e]||(i=re([2e3,1]).day(e),n="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[e]=new RegExp(n.replace(".",""),"i")),this._weekdaysParse[e].test(t))return e},_longDateFormat:{LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D YYYY",LLL:"MMMM D YYYY LT",LLLL:"dddd, MMMM D YYYY LT"},longDateFormat:function(t){var e=this._longDateFormat[t];return!e&&this._longDateFormat[t.toUpperCase()]&&(e=this._longDateFormat[t.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t]=e),e},isPM:function(t){return"p"===(t+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(t,e,i){return t>11?i?"pm":"PM":i?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(t,e){var i=this._calendar[t];return"function"==typeof i?i.apply(e):i},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(t,e,i,n){var s=this._relativeTime[i];return"function"==typeof s?s(t,e,i,n):s.replace(/%d/i,t)},pastFuture:function(t,e){var i=this._relativeTime[t>0?"future":"past"];return"function"==typeof i?i(e):i.replace(/%s/i,e)},ordinal:function(t){return this._ordinal.replace("%d",t)},_ordinal:"%d",preparse:function(t){return t},postformat:function(t){return t},week:function(t){return J(t,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),re=function(t,e,i,o){var r;return"boolean"==typeof i&&(o=i,i=n),r={},r._isAMomentObject=!0,r._i=t,r._f=e,r._l=i,r._strict=o,r._isUTC=!1,r._pf=s(),ee(r)},re.utc=function(t,e,i,o){var r;return"boolean"==typeof i&&(o=i,i=n),r={},r._isAMomentObject=!0,r._useUTC=!0,r._isUTC=!0,r._l=i,r._i=t,r._f=e,r._strict=o,r._pf=s(),ee(r).utc()},re.unix=function(t){return re(1e3*t)},re.duration=function(t,e){var i,n,s,o=t,r=null;return re.isDuration(t)?o={ms:t._milliseconds,d:t._days,M:t._months}:"number"==typeof t?(o={},e?o[e]=t:o.milliseconds=t):(r=Se.exec(t))?(i="-"===r[1]?-1:1,o={y:0,d:b(r[pe])*i,h:b(r[fe])*i,m:b(r[ge])*i,s:b(r[me])*i,ms:b(r[ve])*i}):(r=Ee.exec(t))&&(i="-"===r[1]?-1:1,s=function(t){var e=t&&parseFloat(t.replace(",","."));return(isNaN(e)?0:e)*i},o={y:s(r[2]),M:s(r[3]),d:s(r[4]),h:s(r[5]),m:s(r[6]),s:s(r[7]),w:s(r[8])}),n=new d(o),re.isDuration(t)&&t.hasOwnProperty("_lang")&&(n._lang=t._lang),n},re.version=he,re.defaultFormat=je,re.updateOffset=function(){},re.lang=function(t,e){var i;return t?(e?I(M(t),e):null===e?(O(t),t="en"):ye[t]||N(t),i=re.duration.fn._lang=re.fn._lang=N(t),i._abbr):re.fn._lang._abbr},re.langData=function(t){return t&&t._lang&&t._lang._abbr&&(t=t._lang._abbr),N(t)},re.isMoment=function(t){return t instanceof h||null!=t&&t.hasOwnProperty("_isAMomentObject")},re.isDuration=function(t){return t instanceof d},ae=ti.length-1;ae>=0;--ae)w(ti[ae]);for(re.normalizeUnits=function(t){return y(t)},re.invalid=function(t){var e=re.utc(0/0);return null!=t?c(e._pf,t):e._pf.userInvalidated=!0,e},re.parseZone=function(t){return re(t).parseZone()},c(re.fn=h.prototype,{clone:function(){return re(this)},valueOf:function(){return+this._d+6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().lang("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){var t=re(this).utc();return 00:!1},parsingFlags:function(){return c({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(){return this.zone(0)},local:function(){return this.zone(0),this._isUTC=!1,this},format:function(t){var e=k(this,t||re.defaultFormat);return this.lang().postformat(e)},add:function(t,e){var i;return i="string"==typeof t?re.duration(+e,t):re.duration(t,e),f(this,i,1),this},subtract:function(t,e){var i;return i="string"==typeof t?re.duration(+e,t):re.duration(t,e),f(this,i,-1),this},diff:function(t,e,i){var n,s,o=D(t,this),r=6e4*(this.zone()-o.zone());return e=y(e),"year"===e||"month"===e?(n=432e5*(this.daysInMonth()+o.daysInMonth()),s=12*(this.year()-o.year())+(this.month()-o.month()),s+=(this-re(this).startOf("month")-(o-re(o).startOf("month")))/n,s-=6e4*(this.zone()-re(this).startOf("month").zone()-(o.zone()-re(o).startOf("month").zone()))/n,"year"===e&&(s/=12)):(n=this-o,s="second"===e?n/1e3:"minute"===e?n/6e4:"hour"===e?n/36e5:"day"===e?(n-r)/864e5:"week"===e?(n-r)/6048e5:n),i?s:u(s)},from:function(t,e){return re.duration(this.diff(t)).lang(this.lang()._abbr).humanize(!e)},fromNow:function(t){return this.from(re(),t)},calendar:function(){var t=D(re(),this).startOf("day"),e=this.diff(t,"days",!0),i=-6>e?"sameElse":-1>e?"lastWeek":0>e?"lastDay":1>e?"sameDay":2>e?"nextDay":7>e?"nextWeek":"sameElse";return this.format(this.lang().calendar(i,this))},isLeapYear:function(){return T(this.year())},isDST:function(){return this.zone()+re(t).startOf(e)},isBefore:function(t,e){return e="undefined"!=typeof e?e:"millisecond",+this.clone().startOf(e)<+re(t).startOf(e)},isSame:function(t,e){return e=e||"ms",+this.clone().startOf(e)===+D(t,this).startOf(e)},min:function(t){return t=re.apply(null,arguments),this>t?this:t},max:function(t){return t=re.apply(null,arguments),t>this?this:t},zone:function(t){var e=this._offset||0;return null==t?this._isUTC?e:this._d.getTimezoneOffset():("string"==typeof t&&(t=F(t)),Math.abs(t)<16&&(t=60*t),this._offset=t,this._isUTC=!0,e!==t&&f(this,re.duration(e-t,"m"),1,!0),this)},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.zone(this._tzm):"string"==typeof this._i&&this.zone(this._i),this},hasAlignedHourOffset:function(t){return t=t?re(t).zone():0,(this.zone()-t)%60===0},daysInMonth:function(){return S(this.year(),this.month())},dayOfYear:function(t){var e=ce((re(this).startOf("day")-re(this).startOf("year"))/864e5)+1;return null==t?e:this.add("d",t-e)},quarter:function(){return Math.ceil((this.month()+1)/3)},weekYear:function(t){var e=J(this,this.lang()._week.dow,this.lang()._week.doy).year;return null==t?e:this.add("y",t-e)},isoWeekYear:function(t){var e=J(this,1,4).year;return null==t?e:this.add("y",t-e)},week:function(t){var e=this.lang().week(this);return null==t?e:this.add("d",7*(t-e))},isoWeek:function(t){var e=J(this,1,4).week;return null==t?e:this.add("d",7*(t-e))},weekday:function(t){var e=(this.day()+7-this.lang()._week.dow)%7;return null==t?e:this.add("d",t-e)},isoWeekday:function(t){return null==t?this.day()||7:this.day(this.day()%7?t:t-7)},get:function(t){return t=y(t),this[t]()},set:function(t,e){return t=y(t),"function"==typeof this[t]&&this[t](e),this},lang:function(t){return t===n?this._lang:(this._lang=N(t),this)}}),ae=0;ae-1?!1:"INPUT"==i||"SELECT"==i||"TEXTAREA"==i||e.contentEditable&&"true"==e.contentEditable}function o(t,e){return t.sort().join(",")===e.sort().join(",")}function r(t){t=t||{};var e,i=!1;for(e in M)t[e]?i=!0:M[e]=0;i||(I=!1)}function a(t,e,i,n,s){var r,a,h=[];if(!x[t])return[];for("keyup"==i&&u(t)&&(e=[t]),r=0;r95&&112>t||b.hasOwnProperty(t)&&(_[b[t]]=t)}return _}function g(t,e,i){return i||(i=f()[t]?"keydown":"keypress"),"keypress"==i&&e.length&&(i="keydown"),i}function m(t,e,i,s){M[t]=0,s||(s=g(e[0],[]));var o,a=function(){I=s,++M[t],p()},h=function(t){d(i,t),"keyup"!==s&&(D=n(t)),setTimeout(r,10)};for(o=0;o1)return m(t,d,e,i);for(h="+"===t?["+"]:t.split("+"),o=0;o":".","?":"/","|":"\\"},T={option:"alt",command:"meta","return":"enter",escape:"esc"},x={},C={},M={},D=!1,I=!1,O=1;20>O;++O)b[111+O]="f"+O;for(O=0;9>=O;++O)b[O+96]=O;i(document,"keypress",l),i(document,"keydown",l),i(document,"keyup",l);var N={bind:function(t,e,i){return y(t instanceof Array?t:[t],e,i),C[t+":"+i]=e,this},unbind:function(t,e){return C[t+":"+e]&&(delete C[t+":"+e],this.bind(t,function(){},e)),this},trigger:function(t,e){return C[t+":"+e](),this},reset:function(){return x={},C={},this}};e.exports=N},{}]},{},[1])(1)}); \ No newline at end of file diff --git a/docs/graph.html b/docs/graph.html index 2c679bc1..8dfe2594 100644 --- a/docs/graph.html +++ b/docs/graph.html @@ -15,25 +15,6 @@

    Graph documentation

    -

    Contents

    - -

    Overview

    Graph is a visualization to display graphs and networks consisting of nodes @@ -51,6 +32,37 @@ vis.js library.

    + +

    Contents

    + + +

    Example

    Here a basic graph example. Note that unlike the @@ -147,7 +159,7 @@ The constructor accepts three parameters: -

    Data Format

    +

    Data format

    The data parameter of the Graph constructor is an object which can contain different types of data. @@ -605,7 +617,7 @@ var graph = new vis.Graph(container, data); -

    Configuration Options

    +

    Configuration options

    Options can be used to customize the graph. Options are defined as a JSON object. @@ -628,239 +640,353 @@ var options = {

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDefaultDescription
    edges.colorString"#2B7CE9"The default color of a edge.
    edges.dashObjectObject - Object containing default properties for dashed lines. - Available properties: length, gap, - altLength. -
    edges.dash.altLengthnumbernoneDefault length of the alternated dash in pixels on a dashed line. - Specifying dash.altLength allows for creating - a dashed line with a dash-dot style, for example when - dash.length=10 and dash.altLength=5. - See also the option dahs.length. - Only applicable when the line style is dash-line.
    edges.dash.lengthnumber10Default length of a dash in pixels on a dashed line. - Only applicable when the line style is dash-line.
    edges.dash.gapnumber5Default length of a gap in pixels on a dashed line. - Only applicable when the line style is dash-line.
    edges.lengthNumber100The default length of a edge.
    edges.styleString"line"The default style of a edge. - Choose from line (default), arrow, - arrow-center, dash-line.
    edges.widthNumber1The default width of a edge.
    groupsObjectnoneIt is possible to specify custom styles for groups. - Each node assigned a group gets the specified style. - See Groups for an overview of the available styles - and an example. -
    heightString"400px"The height of the graph in pixels or as a percentage.
    nodes.colorString | ObjectObjectDefault color of the nodes. When color is a string, the color is applied - to both background as well as the border of the node.
    nodes.color.backgroundString"#97C2FC"Default background color of the nodes
    nodes.color.borderString"#2B7CE9"Default border color of the nodes
    nodes.color.highlightString | ObjectObjectDefault color of the node when the node is selected. Applied to - both border and background of the node.
    nodes.color.highlight.backgroundString"#D2E5FF"Default background color of the node when selected.
    nodes.color.highlight.borderString"#2B7CE9"Default border color of the node when selected.
    nodes.fontColorString"black"Default font color for the text label in the nodes.
    nodes.fontFaceString"sans"Default font face for the text label in the nodes, for example "verdana" or "arial".
    nodes.fontSizeNumber14Default font size in pixels for the text label in the nodes.
    nodes.groupStringnoneDefault group for the nodes.
    nodes.imageStringnoneDefault image url for the nodes. only applicable with shape image.
    nodes.widthMinNumber16The minimum width for a scaled image. Only applicable with shape image.
    nodes.widthMaxNumber64The maximum width for a scaled image. Only applicable with shape image.
    nodes.shapeString"ellipse"The default shape for all nodes. - Choose from - ellipse (default), circle, box, - database, image, label, dot, - star, triangle, triangleDown, and square. - This shape can be overridden by a group shape, or by a shape of an individual node.
    nodes.radiusNumber5The default radius for a node. Only applicable with shape dot.
    nodes.radiusMinNumber5The minimum radius for a scaled node. Only applicable with shape dot.
    nodes.radiusMaxNumber20The maximum radius for a scaled node. Only applicable with shape dot.
    selectableBooleantrueIf true, nodes in the graph can be selected by clicking them. - Long press can be used to select multiple nodes.
    stabilizeBooleantrueIf true, the graph is stabilized before displaying it. If false, - the nodes move to a stabe position visibly in an animated way.
    widthString"400px"The width of the graph in pixels or as a percentage.
    NameTypeDefaultDescription
    clusteringObjectnone + Clustering configuration. Clustering is turned off by default. See section Clustering for an overview of the available options. +
    edgesObjectnone + Configuration options applied to all edges. See section Edges configuration for an overview of the available options. +
    groupsObjectnoneIt is possible to specify custom styles for groups. + Each node assigned a group gets the specified style. + See Groups configuration for an overview of the available styles + and an example. +
    heightString"400px"The height of the graph in pixels or as a percentage.
    keyboardObjectnone + Configuration options for shortcuts keys. Sortcut keys are turned off by default. See section Keyboard navigation for an overview of the available options. +
    navigationObjectnone + Configuration options for the navigation controls. See section Navigation controls for an overview of the available options. +
    nodesObjectnone + Configuration options applied to all nodes. See section Nodes configuration for an overview of the available options. +
    selectableBooleantrueIf true, nodes in the graph can be selected by clicking them. + Long press can be used to select multiple nodes.
    stabilizeBooleantrueIf true, the graph is stabilized before displaying it. If false, + the nodes move to a stabe position visibly in an animated way.
    widthString"400px"The width of the graph in pixels or as a percentage.

    -

    Groups

    +

    Nodes configuration

    +

    + Nodes can be configured with different styles and shapes. To configure nodes, provide an object named nodes in the options for the Graph. +

    + +

    + For example to give the nodes a custom color, shape, and size: +

    +
    +var options = {
    +  // ...
    +  nodes: {
    +    color: {
    +      background: 'white',
    +      border: 'red',
    +      highlight: {
    +        background: 'pink',
    +        border: 'red'
    +      }
    +    },
    +    shape: 'star',
    +    radius: 24
    +  }
    +};
    +
    + +

    + The following options are available for nodes. These options must be created + inside an object nodes in the graphs options object.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    colorString | ObjectObjectDefault color of the nodes. When color is a string, the color is applied + to both background as well as the border of the node.
    color.backgroundString"#97C2FC"Default background color of the nodes
    color.borderString"#2B7CE9"Default border color of the nodes
    color.highlightString | ObjectObjectDefault color of the node when the node is selected. In case of a string, the color is applied to + both border and background of the node.
    color.highlight.backgroundString"#D2E5FF"Default background color of the node when selected.
    color.highlight.borderString"#2B7CE9"Default border color of the node when selected.
    fontColorString"black"Default font color for the text label in the nodes.
    fontFaceString"sans"Default font face for the text label in the nodes, for example "verdana" or "arial".
    fontSizeNumber14Default font size in pixels for the text label in the nodes.
    groupStringnoneDefault group for the nodes.
    imageStringnoneDefault image url for the nodes. only applicable to shape image.
    widthMinNumber16The minimum width for a scaled image. Only applicable to shape image.
    widthMaxNumber64The maximum width for a scaled image. Only applicable to shape image.
    shapeString"ellipse"The default shape for all nodes. + Choose from + ellipse (default), circle, box, + database, image, label, dot, + star, triangle, triangleDown, and square. + This shape can be overridden by a group shape, or by a shape of an individual node.
    radiusNumber5The default radius for a node. Only applicable to shapes dot, + star, triangle, triangleDown, and square.
    radiusMinNumber5The minimum radius for a scaled node. Only applicable to shapes dot, + star, triangle, triangleDown, and square.
    radiusMaxNumber20The maximum radius for a scaled node. Only applicable to shapes dot, + star, triangle, triangleDown, and square.
    + + +

    Edges configuration

    + +

    + Edges can be configured with different length and styling. To configure edges, provide an object named edges in the options for the Graph. +

    + +

    + For example to set the width of all edges to 2 pixels and give them a red color: +

    +
    +var options = {
    +  // ...
    +  edges: {
    +    color: 'red',
    +    width: 2
    +  }
    +};
    +
    + +

    + The following options are available for edges. These options must be created + inside an object edges in the graphs options object. +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDefaultDescription
    colorString"#2B7CE9"The default color of a edge.
    dashObjectObject + Object containing default properties for dashed lines. + Available properties: length, gap, + altLength. +
    dash.altLengthnumbernoneDefault length of the alternated dash in pixels on a dashed line. + Specifying dash.altLength allows for creating + a dashed line with a dash-dot style, for example when + dash.length=10 and dash.altLength=5. + See also the option dahs.length. + Only applicable when the line style is dash-line.
    dash.lengthnumber10Default length of a dash in pixels on a dashed line. + Only applicable when the line style is dash-line.
    dash.gapnumber5Default length of a gap in pixels on a dashed line. + Only applicable when the line style is dash-line.
    lengthNumber100The default length of a edge.
    styleString"line"The default style of a edge. + Choose from line (default), arrow, + arrow-center, dash-line.
    widthNumber1The default width of a edge.
    + +

    Groups configuration

    It is possible to specify custom styles for groups of nodes. Each node having assigned to this group gets the specified style. @@ -932,9 +1058,10 @@ var nodes = [ color.highlight - String + String | Object "#D2E5FF" - Color of the node when selected. + Default color of the node when the node is selected. In case of a string, the color is applied to + both border and background of the node. color.highlight.background @@ -995,35 +1122,267 @@ var nodes = [ +

    Clustering

    +

    + The graph now supports dynamic clustering of nodes. This allows a user to view a very large dataset (> 50.000 nodes) without + sacrificing performance. When loading a large dataset, the nodes are clustered initially (this may take a small while) to have a + responsive visualization to work with. The clustering is both outside-in and inside-out. Outside-in means that nodes with only one + connection will be contained, or clustered, in the node it is connected to. Inside-out clustering first determines which nodes are hubs. + Hubs are defined as the nodes with the top 3% highest amount of connections (assuming normal distribution). These hubs then "grow", meaning + they contain the nodes they are connected to within themselves. The edges that were connected to the nodes that are absorbed will be reconnected to the cluster. +
    +
    + A cluster is just a node that has references to the nodes and edges it contains. It has an internal counter to keep track of its size, which is then used + to calculate the required forces. The contained nodes are removed from the global nodes index, greatly speeding up the system. +
    +
    + The clustering has the following user-configurable settings. The default values have been tested with the Graph examples and work well. + The default state for clustering is off. +

    -

    Methods

    +
    +// These variables must be defined in an options object named clustering.
    +// If a variable is not supplied, the default value is used.
    +var options = {
    +    clustering: {
    +      initialMaxNodes: 100,
    +      clusterThreshold:500,
    +      reduceToNodes:300,
    +      chainThreshold: 0.4,
    +      clusterEdgeThreshold: 20,
    +      sectorThreshold: 50,
    +      screenSizeThreshold: 0.2,
    +      fontSizeMultiplier:  4.0,
    +      forceAmplification:  0.6,
    +      distanceAmplification: 0.2,
    +      edgeGrowth: 11,
    +      nodeScaling: {width:  10,
    +                    height: 10,
    +                    radius: 10},
    +      activeAreaBoxSize: 100
    +    }
    +}
    +// OR to just load the module with default values:
    +var options: {
    +    clustering: true
    +}
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDefaultDescription
    initialMaxNodesNumber100If the initial amount of nodes is larger than this value, clustering starts until the total number of nodes is less than this value.
    clusterThresholdNumber500While zooming in and out, clusters can open up. Once there are more than absoluteMaxNumberOfNodes nodes, + clustering starts until reduceToMaxNumberOfNodes nodes are left. This is done to ensure performance is continuously fluid.
    reduceToNodesNumber300While zooming in and out, clusters can open up. Once there are more than absoluteMaxNumberOfNodes nodes, + clustering starts until reduceToMaxNumberOfNodes nodes are left. This is done to ensure performance is continiously fluid.
    chainThresholdNumber0.4Because of the clustering methods used, long chains of nodes can be formed. To reduce these chains, this threshold is used. + A chainThreshold of 0.4 means that no more than 40% of all nodes are allowed to be a chain node (two connections). + If there are more, they are clustered together.
    clusterEdgeThresholdNumber20This is the absolute edge length threshold in pixels. If the edge is smaller on screen (that means zooming out reduces this length) + the node will be clustered. This is triggered when zooming out.
    sectorThresholdInteger50If a cluster larger than sectorThreshold is opened, a seperate instance called a sector, will be created. All the simulation of + nodes outside of this instance will be paused. This is to maintain performance and clarity when examining large clusters. + A sector is collapsed when zooming out far enough. Also, when opening a cluster, if this cluster is smaller than this value, it is fully unpacked.
    screenSizeThresholdNumber0.2When zooming in, the clusters become bigger. A screenSizeThreshold of 0.2 means that if the width or height of this cluster + becomes bigger than 20% of the width or height of the canvas, the cluster is opened. If a sector has been created, if the sector is smaller than + 20%, we collapse this sector.
    fontSizeMultiplierNumber4.0This parameter denotes the increase in fontSize of the cluster when a single node is added to it.
    forceAmplificationNumber0.6This factor is used to calculate the increase of the repulsive force of a cluster. It is calculated by the following + formula: repulsingForce *= 1 + (clusterSize * forceAmplification).
    distanceAmplificationNumber0.2This factor is used to calculate the increase in effective range of the repulsive force of the cluster. + A larger cluster has a longer range. It is calculated by the following + formula: minDistance *= 1 + (clusterSize * distanceAmplification).
    edgeGrowthNumber11This factor determines the elongation of edges connected to a cluster.
    nodeScaling.widthNumber10This factor determines how much the width of a cluster increases in pixels per added node.
    nodeScaling.heightNumber10This factor determines how much the height of a cluster increases in pixels per added node.
    nodeScaling.radiusNumber10This factor determines how much the radius of a cluster increases in pixels per added node.
    activeAreaBoxSizeNumber100Imagine a square with an edge length of activeAreaBoxSize pixels around your cursor. + If a cluster is in this box as you zoom in, the cluster can be opened in a seperate sector. + This is regardless of the zoom level.
    + +

    - Graph supports the following methods. + Graph has a menu with navigation controls, which is disabled by default. + It can be configured with the following settings.

    +
    +// simple use of navigation controls
    +var options: {
    +  navigation: true
    +}
    +
    +// advanced use of navigation controls
    +var options: {
    +  navigation: {
    +    iconPath: '/path/to/navigation/icons/'
    +  }
    +}
    +
    + - - + + + - - - + + + + + +
    MethodReturn TypeNameTypeDefault Description
    setData(data)noneLoads data. Parameter data is an object containing - nodes, edges, and options. Parameters nodes, edges are an Array. - Options is a name-value map and is optional. - iconPathstring"/img"The path to the icon images can be defined here. If custom icons are used, they have to have the same filename as the ones originally packaged with vis.js.
    + +

    Keyboard navigation

    +

    + The graph can be navigated using shortcut keys. + It can be configured with the following user-configurable settings. + The default state for the keyboard navigation is off. The predefined keys can be found in the example 20_navigation.html. +

    + +
    +// simple use of keyboard controls
    +var options: {
    +    keyboard: true
    +}
    +
    +// advanced configuration for keyboard controls
    +var options: {
    +  keyboard: {
    +    speed: {
    +      x: 10,
    +      y: 10,
    +      zoom: 0.02
    +    }
    +  }
    +}
    +
    + + + + + + + - - - + + + + + + + + + + + + + + + +
    NameTypeDefaultDescription
    setOptions(options)noneSet options for the graph. The available options are described in - the section Configuration Options. + speed.xNumber10This defines the speed of the camera movement in the x direction when using the keyboard navigation.
    speed.yNumber10This defines the speed of the camera movement in the y direction when using the keyboard navigation.
    speed.zoomNumber0.02This defines the zoomspeed when using the keyboard navigation.
    + +

    Methods

    +

    + Graph supports the following methods. +

    + + + + + + + @@ -1034,12 +1393,43 @@ var nodes = [ + + + + + + + + + + + + + + + + + + + + + + + + @@ -1063,7 +1453,7 @@ var nodes = [

    Events

    - Graph fires events after one or multiple nodes are selected. + Graph fires events after one or multiple nodes are selected or deselected. The event can be catched by creating a listener.

    @@ -1072,22 +1462,35 @@ var nodes = [

    -function onSelect() {
    -  alert('selected nodes: ' + graph.getSelection());
    +graph.on('select', function (properties) {
    +  alert('selected nodes: ' + properties.nodes);
    +});
    +
    + +

    + A listener can be removed via the function off: +

    + +
    +function onSelect (properties) {
    +  alert('selected nodes: ' + properties.nodes);
     }
     
    -vis.events.addListener(graph, 'select', onSelect);
    +// add event listener
    +graph.on('select', onSelect);
    +
    +// do stuff...
    +
    +// remove event listener
    +graph.off('select', onSelect);
     
    +

    The following events are available.

    MethodReturn TypeDescription
    getSelection()
    on(event, callback)noneCreate an event listener. The callback function is invoked every time the event is triggered. Avialable events: select. The callback function is invoked as callback(properties), where properties is an object containing event specific properties. See section Events for more information.
    off(event, callback)noneRemove an event listener created before via function on(event, callback). See section Events for more information.
    redraw() none Redraw the graph. Useful when the layout of the webpage changed.
    setData(data,[disableStart])noneLoads data. Parameter data is an object containing + nodes, edges, and options. Parameters nodes, edges are an Array. + Options is a name-value map and is optional. Parameter disableStart is + an optional Boolean and can disable the start of the simulation that would begin at the end + of this function by default. +
    setOptions(options)noneSet options for the graph. The available options are described in + the section Configuration Options. +
    setSelection(selection) none
    - - - - @@ -1096,18 +1499,19 @@ vis.events.addListener(graph, 'select', onSelect); - + -
    name Description
    selectFired after the user selects or unselects a node by clicking it, - or when selecting a number of nodes by dragging a selection area - around them. Not fired when the method setSelection - is executed. The ids of the selected nodes can be retrieved via the - method getSelection. + Fired after the user selects or deselects a node by clicking it. + Not fired when the method setSelectionis executed. + +
      +
    • nodes: an array with the ids of the selected nodes
    • +
    none
    -

    Data Policy

    +

    Data policy

    All code and data is processed and rendered in the browser. No data is sent to any server. diff --git a/docs/img/vis_overview.odg b/docs/img/vis_overview.odg index 7659955f2fb858c383c3b5b082a352ee45b32523..0be797e9e3bd0fe567a4911f67019ebb0d433bb6 100644 GIT binary patch delta 13414 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 delta 28389 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 KqiY`jwEusXp{gqY diff --git a/docs/img/vis_overview.png b/docs/img/vis_overview.png index ea53362dde056ff701afa980594f3706e1793cb5..d2de2359ad74df648068623ba60fbffecd43db72 100644 GIT binary patch literal 64008 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

    $yjCu6Q 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 XrM8|M{4^DcZ?&AX;>%*mH~#+tnUvxd literal 49562 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 V>_4#~vI3+(k&#doFBdiX@*f7Yf4cwx diff --git a/docs/index.html b/docs/index.html index bbaf818b..0fcc85ca 100644 --- a/docs/index.html +++ b/docs/index.html @@ -179,7 +179,7 @@ var timeline = new vis.Timeline(container, data, options);

    License

    - Copyright (C) 2010-2013 Almende B.V. + Copyright (C) 2010-2014 Almende B.V.

    diff --git a/docs/timeline.html b/docs/timeline.html index c2335c60..eaaf2339 100644 --- a/docs/timeline.html +++ b/docs/timeline.html @@ -14,6 +14,16 @@

    Timeline documentation

    +

    Overview

    +

    + The Timeline is an interactive visualization chart to visualize data in time. + The data items can take place on a single date, or have a start and end date (a range). + You can freely move and zoom in the timeline by dragging and scrolling in the + Timeline. Items can be created, edited, and deleted in the timeline. + The time scale on the axis is adjusted automatically, and supports scales ranging + from milliseconds to years. +

    +

    Contents

    -

    Overview

    -

    - The Timeline is an interactive visualization chart to visualize data in time. - The data items can take place on a single date, or have a start and end date (a range). - You can freely move and zoom in the timeline by dragging and scrolling in the - Timeline. Items can be created, edited, and deleted in the timeline. - The time scale on the axis is adjusted automatically, and supports scales ranging - from milliseconds to years. -

    -

    Example

    The following code shows how to create a Timeline and provide it with data. @@ -342,7 +343,7 @@ var options = { end - Date + Date | Number | String none The initial end date for the axis of the timeline. If not provided, the latest date present in the items set is taken as @@ -387,7 +388,7 @@ var options = { max - Date + Date | Number | String none Set a maximum Date for the visible range. It will not be possible to move beyond this maximum. @@ -404,7 +405,7 @@ var options = { min - Date + Date | Number | String none Set a minimum Date for the visible range. It will not be possible to move beyond this minimum. @@ -482,7 +483,7 @@ var options = { start - Date + Date | Number | String none The initial start date for the axis of the timeline. If not provided, the earliest date present in the events is taken as start date. @@ -544,12 +545,32 @@ var options = { Retrieve the custom time. Only applicable when the option showCustomTime is true. + setCustomTime(time) none Adjust the custom time bar. Only applicable when the option showCustomTime is true. time is a Date object. + + + getSelection() + ids + Get an array with the ids of the currently selected items. + + + + on(event, callback) + none + Create an event listener. The callback function is invoked every time the event is triggered. Avialable events: rangechange, rangechanged, select. The callback function is invoked as callback(properties), where properties is an object containing event specific properties. See section Events for more information. + + + + off(event, callback) + none + Remove an event listener created before via function on(event, callback). See section Events for more information. + + setGroups(groups) none @@ -560,6 +581,7 @@ var options = { must correspond with the id of the group. + setItems(items) none @@ -572,12 +594,107 @@ var options = { setOptions(options) none - Set or update options. It is possible to change any option - of the timeline at any time. You can for example switch orientation - on the fly. + Set or update options. It is possible to change any option of the timeline at any time. You can for example switch orientation on the fly. + + + + + setSelection([ids]) + none + Select or deselect items. Currently selected items will be unselected. + + + + + + +

    Events

    +

    + Timeline fires events when changing the visible window by dragging, or when + selecting items. +

    + +

    + Here an example on how to listen for a select event. +

    + +
    +timeline.on('select', function (properties) {
    +  alert('selected items: ' + properties.nodes);
    +});
    +
    + +

    + A listener can be removed via the function off: +

    + +
    +function onSelect (properties) {
    +  alert('selected items: ' + properties.nodes);
    +}
    +
    +// add event listener
    +timeline.on('select', onSelect);
    +
    +// do stuff...
    +
    +// remove event listener
    +timeline.off('select', onSelect);
    +
    + + +

    + The following events are available. +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    nameDescriptionProperties
    rangechangeFired repeatedly when the user is dragging the timeline window. + +
      +
    • start (Number): timestamp of the current start of the window.
    • +
    • end (Number): timestamp of the current end of the window.
    • +
    +
    rangechangedFired once after the user has dragging the timeline window. + +
      +
    • start (Number): timestamp of the current start of the window.
    • +
    • end (Number): timestamp of the current end of the window.
    • +
    selectFired after the user selects or deselects items by tapping or holding them. + Not fired when the method setSelectionis executed. + +
      +
    • items: an array with the ids of the selected items
    • +
    +
    diff --git a/download/vis.zip b/download/vis.zip index 687e8b81a0b7339e38cf01ba138e178b604a5700..be2fa4b4cb946f730738f41a96555c79c60451d4 100644 GIT binary patch delta 323359 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

    7`xA>PxSa;Fu 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 z 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

    ma zoNQGL=u}4;LP0%EYay8=wMMy#MwAko@qP~z!5H#wJO@;GEE5HqXmh97Dz@GK?(Y;N z4#YYyE+DJwxN^h0Gp;_r{(rEX*)1TCrBe+7)2$?0KOF}1@l<=@XjLUGB z6l5Y7i{A72>8Eran>(DeQ?|wvVsM#Y|2=LxC5i>y%Yn&kf0Vs+li|2pl%N2rkN^S^ zGE=DpjeY>vn#1oj{x&ptYe^ncncd>(Dje=8;nFqj&=nc$umasa_n2JxL;!od@f>}lOa`Nkb8ai!G)a(+T8WsIX9 zxRgnvrq+pke*Mx&m~!SAE#&`NZd!1Qzk2aXC~)xvxM*A%96TVs3ko-}m|KY_Y#Rt% z!fTi3`a&E9jMpvi=tdE9kAYMrJeZ}t(2W%*ks~A$e~L$^AQB#Z5QKuw96XOF)gv4x z&zN=1H#41mGaY}>z=8>M-G-f9#wm6RYZE9V2t!E9u^}(3reVUS6P!K?p^0~S;R)l? z0;vyPgMPy94o)dDh~4vW23gtIzXrdngdG7OJNXl|vt*1(Jy!>;-mfEyMoh4P*0Dg` zqGX6gfBZ;!;sXxp8j+u%(P1JK$3y8FEcn`ENwIi1sTMfq(|O6`dHGk|rc3;VbyfNm zlOco&9x|lyP2G{Kf;~Dcw&E3RthFA_!X6HXzGzx-Erq&qBm%~?a9>?(8550%7i?oZ zxejRbBo>6loc8M<9e?PMT0@YC{WQ2} z;1FRTBX)%aq(b#JlbH`oQRm*Ftn%yjxHtP4{3?<2o&5wm|GOdDXIY}}jN;osu)P-Y zk9@?3#Fd+^@4Un*U6{KBA1V%%bh*UvMl}=l^lx=_NeY9QbKpn<-sr*l)_1Bg-p%iy ze}4wXpyI=fobl>cpfbl8YC#mpg5PdJ;A=;(liBRN!IU{ZGMIWgBnFmGLndt@%$qWz z9P74AEQ_LH8qhye~a`0FRM z*+()G&fdZ#olJ{R?>3^tmabNm52hWwhLe3bnH+EjxR)Ht!k+{UlU!Ze4hE5Ve>H*E zx;2tu0<88*`Hda=frm6MJwdYj=fH!wg<^^?gmV0Q7|4kz_7v$f46d@WqvFA~dE#28))~JgRFzvC&U<8X&s$9G z;b~uMeug#ODQKZp`!fAADRH0Sf9feMgLzG9i)3~5NZ}eoftX6c@(YhdZ?Pz_OTH%| zR}=_7QBx?3@^zaQ>iP}sa~FY z{uCoA`=hUQHF*Tndg|8pH4bDEUvzTuGd`37VoULMtLChmtD&z`3mZS3jBWcbw~(cz zr=e+HeD&qui$@Q?{PM};f8yykFP>*!9`nS96p-A8Y64FQtPr6#V%EO)s?TDzwk~AI@@tdl9NE2YoU$~{`7Yle=&=f2VSwwg)O5^AV9!NJ04+bef zR1ZY48_UKRMsRv6v~SvCk#wvu0p)}dRdHJY@ilFCUl^G}f3x~dur@hluapGdDCu$>mN3nKz5bvpxd z7Kip&pEq69^FUc8Ru#P{#&|i7Xaw=md>j$0eahjZ0b5McHR4gi# zSEKOe0oVq{_}oqJ)eNC+`Dky;NsU5SA6VRN@z}^sgJGn4f4r8^LUTHnsg_f-iB(m`kwZ?7bq4b?D5h(QHYcv%nUg`&9v1)p@tJ1+8 zKF^cc5giXif5Ut`tH)%+E*Fq8Uh`0XIalHQz*8^U(aOx#ZQ%CkBX9`=hqF!cJ-kue*Qgio_T{SSjYd&0KzY;&*zYmcVJCuA4U!3b*pJDOhtrK!HkU}QxM z$)$=nTHTD)h9aYFLaXB0{G^=LO%m^^65DHX6>GUd4(=>Z!3QH4=cz*P#U#4q08JL z)*ylc<(?%L5!4P>f!4^6#HO-7na<|o^Jq=~e~1f2$vD?-ymyhAh7pXiW*}qbEja)p z%lmrKM0WRWI+qq+#Z&cG%in4!5QvAOTb(l&_C9%*j zX2yBBaW%8Y#N2#pHUmE7#GUC3(vFLC^xQOW)-n_FZ-0*Q*iYjf!VlZ|jK_}WWL15R z>kJ&U>^#E1)i8Sr7u0_;eg?S49L#S|by9LRC&qbIdf4VQj0Hj+}<0D`$WSu+%(T!z{7D`^y``QOOa?e4lPMTOy~r9N1($h=ZADQ$R_VBxjJGrf-16j~khWSH z<4nnmO`Si`Y?fW@G(-T!Q2-KMWt_`Ny)RrxF-bi1vj}sJ!cMeUV=159e;-AuEw#6K zSfFa;ZCPW870B&!R2knwjH$^MIEJ9(A#i%P#bpVJ4+;P<2u_ijFnqd48Aq07PtBP% zMq@3Z9wb;1V|F=+5#!D$VSXa@n5$!SV?W_)eA+59c955hf#f2Mg|jm&;nWr!@_zJ!hocNx|o}|=LY`>Y0*3ze^XjLAFDF7(SJs} zMg8v=x#Ni9-zb9p2bqih!*~?g-du^b6)l4KP?pr(Xs`cq0CYo6Ov#`L7uaIo#yg8P z!vL!Tjcg=FMxf(6#Ux&_&ty?eXBQ`@kr{4ZfG}@Bn?$E*0S_s~O(brTml;V0cK1B*qupR>rn~x9U0qdOmj$!|@L5J9faRCa z3czPk&46ETQRP5n5yOiD`UKYn^zmid<-|&h!ZF+1;@%H-{Hul~3aWsTxLD*G^oN-I`PYD5~O%A=pe8PB?Z= z%`kL&C)mjqf6}aR5Zz(k)j4=q<7|ltYh^!yOep4IA?Z#tM?x#)cqT8lL(IQ(q%YO9 z_T)6T-#WLVH8yB-mU^|f#DSqj2fQ5bs{*}QwJBL>N0yK&nGKpkjho!W7lmd7+zU7# zvc<;`GV7S>mV+*wh4mAgrC20pb#^hfmT2>h&0^MBe`uwR?IH^D!+w4qW0?r5Tk$F_!|WZTPN$05%pU;%&G`7 z)~7@8Vbjr5JvPNPYeXwb+jwrA_T%-E=+sw;C9qicSP!r93Y)V z(fF1|Kv4UU->7S#V-2xt%nc%*u@C)?iHgS6f6r$ZR$;QWT5GZuGbO9-(=w)HdI8>N z*+`LI47lmgQ8q165>DX+u#)B{5M2fBkv;!k8_MHTTo4q?z6p`_V=HC}Qk?+{2#vAI zzNH2S7cyEOx-o&#BBqn$DcOx+{4wJ&WyV=!aa!pGv|~ezL!^V|W@lr4Q~lFwNBX>a zf7cL~I*5*<#-V6+wS-23vOt3df0EU>L?NeuHN2_(jK(&#rZ&30Ql}g)Mr#mZi)?_k z`9F4l*^@V%pUSzj{TNRB{rrq{y+AQBTaIEniY~`KG~KZ#5XJ=Z0&eBH)}u2ZVQTb$ zV_0s0?hI)m=f*}ErcL_T@dp!>JsT=Pe_)pM^6tdM1UEe+Lvtd-!L-w3)3PPIEjQ@R zk_KBbbFE~a{Smn#j7I&LV*?Bk(M<9rmrv{w3pkOXuY4jWU29Q&S!QTJEHX;LDuM8e zNQI2#+9iyMxk(Z4j+k*pE3{wmM7S2~(C1(dM(ij$aS%t^^TNR>In)g`#&KXGe@tr_ zk)rk{_MhOiJ*-mDhHoOq#dOhIj3KrY`SA?sIMdwjNU_-@Rx#3nS+Tu67Tsnj#>$Z1 znD7WOrL=qfAJbh{RaJ*ojfU+IIpDA|s4sy#_U~<>&Qs=#W+BR#kW2 zSNB)F^!qA9LO89xKQn&B)i1zgvtVe0y1(m zeHKv&RHHN4+Z*Wf%qUT3pjarBW?U=T7easFyNOhIZ#h!6@2rpCB6;atnZLRmcF}x3 zCNO5NTwHK=1g{0;XOx&kh77*lP+SIHL9hcGsZ4rBMoN>JI`6Y9xc{Ite_ndf7;fx# z)ad(3%-qeff@sCrN(Vq7r5_!8!d{Q9RfLU=y>DI+F7d7`Q$}Pl7mp$iih&qrHKVQs zRtc1mPJoLYB6GY(+_R*{081SppcCNz?3sd8HA0ySn|WJi)OEDyi{5dwoNxDN+-Eec z*ZJ9VAH=HC%2n1B&=r>)f8fThvl!>+`7rG(`bM{33u*|f_jFY4S5q9O_xdK3Af_)_ zo)nNNv8UfKyW3GIMQ@E3QU?X?SBg$Sqps=HAKdFuQzdNL3Y~_uSVuOlu3fO$TT>*w79OzuI;?u8`OkkQUe}Ad$LXilJNAmLKK zX1~V86o2xpu2qrEMPGrqUqn5-6p0o3*=kCwXR&sxExOr0ZM*q7&u+>&c}}hWn;0ht zZ~tX{6Wt@?MUG_#_zJ_DT&ocT;U6lfmM$+m<=_a-5J#DfV(74CV>#*@aAi*Y2va7h z`C`?gJeTFF{*}!ob8j6N=TJoZRXRvhO3=dWb zELzIFg4D0Aq#T$>M|hcN7nnt0M#UA%=f zfg4^zY;rJAXp-ig>wz+c@7=|eUqwLdtGR>iu& z&Z%c-5C*|#e+Q`@_fmUl+U(O@C!j{0)YhqnzZ}cy;c#wE|0b;Li@y!I&Lxxr3kPu3 z0e7OxxM+NqUV(XwIARrEt_<9g)Q%f`8ggL)Ml!KL*JR_{w1}j?fOKDl8qxSM3!lbw zu%%X~wFLIm!9i@Yq(_JJAto&h<`Zbel9)n_of;Pce;ll3rLn?7$4Wgq`z4K@v6|$1 zh;0-n)ol6j+;(J=$&hdX{Hk~pxz$WnZK}d zoaKr70y>c7^gG(FI%89s{5#1Wpmy?7F%x5OszH=iYcg;4p~zD6PZj2@fGp$>k761X zYH~&B_*P5f;L7$&J6c4iuVasgd@B*vGNk5(lhCV)wkQ3R(k zJuPVxuXHLD7{z1kWap{{w%66>V5w>HhvEu0knlV*7-`J0-S%dY_GX{nUaNAMb5v}k zf4y`xaSS!|-W2()-Q>JVxA~`$V?$qM;qiBw%A*vAPO&L5 zl9w75$MGHa)SOsMfwlHhYX7SZF;M451gU(QUuC^!a4L<{UOqKRS1RM0H8+#hWTW%o zPH?(Bbik!(ZM~ChsXB;Iub$~|IuM$zf53>nqdUO`yG7YVIDXMtP_)d4UeUmc-xU`# zOGQLVB$Kxl@&OJDQl{pEQ8AvdKSjsXhYTZRccu2cnv|_O8C2l+UpRLZ;pWQs4J}I$zfvR|%R2?Cdy@~Bz#KVJse@s)@ z2hKay(Z}FrgAPgJIeYMf7pjfW_0LA$q0bE)GacJKiP27{D=Pa}VS2_^=hpD1aaGuF zR@7{78N?LxEYtAF9_*NJ>!SF>TamVR{0D9gvx?}^3Qp-kg*DrGeuJGgHGvNF(s6Gu z`;ez>LS;SUG+bRH^#9?~XZ@lWe>cq><96`?3uSxSSHzcthozGQ!CY#BGLEIQh_TY>-VZiXQvA+fb3*Fy9B6xPbrFEJi6RfV!h_iIL#cc z-N)oKn_PmS#0GX`lY&9J$((dXJDqpDTJI62m~&!DaLZ0AHV<*OEP<5ZTx_qPh!C_+ zH}TLVr=MBAaw}-ozQSjIe+zVOb4u$Ge6Na!0+=%s-}_N(mWx$^5x?;tUmxwXvgXb3Kob;1o0WY2Dd1fnFEY=qULr#zsliY{G;yP*2yz(1dEei@eBfRe^TCUTRtR?kxN+c zukNR#k>V;*(5OKReE-sx$AJ3+I|zC^0O>2voWzV}C8|WQWEli;S3CDR&b{^QeEqJI z%9LBER(u77L9P5a&pybY`~o!X-g7144x=V>FY(#6Hor)Abup@lr81N-``H=9!7N7Y zWDGg#+He;zDF%*We?gy!N5>E|XIC3{P^{5j!>FBQ4~KJbL803mbV&3Ji`Dn1S6EjN zWoJw#4F}_MbEOLTR@#hm0meO)`_F&-@K(qIMHWma+e<&>=c%@vn2d}5|BY*D2Kl8{ z)wV#(`o&gNEb412nI>A5Vhoy)mVQXfas=V$brdRc@J6Q)e<(t}dRQbRrC5s9dqRWv z2dv^YM|Hy0v_EiF?N3@={rkF7>BlV{7O!{|gi_8m8x@g@a%HkE(?}1CUv)7P;{?jh zf^u(6ITNHr;~otzNv>@8TRH_t@HCmZk9oX)X+7@Q_5b}#c7Xj^dg07Mx$9)sW!|y` z3lc0vxCn9;e|}`9R>6tVKUBZ4&y6zM3yjzg3KRY@aCRejtMljOJikEso8@uNYR1e0PvK$E9#Eb|uQ!aGVq30spretQaF?dWQGOgaWms@axym_?gRyCi zP3X@kKW-$$ExCHuuf7;oJv1}%MWA&lsU`w^>18WD-ho&qB8Aj^| zhN`3tDR{q_WI1}|@is$?IR2hboK*DVjQJb%_`x`6mZU?5O9&V^Y)p*Vj5ecJ$EG^V zFy06m76$brdp0nQ@%J)8|GXQWI)vP!XHV1S_S(r8-SsxRu#Z{_pY(>o$eA>^e^q-( zP^_j18Gn7tHiN5gLTrbC#CyBjg;Sp0duVS|iL(eNq#Fb&a=3-y{`HhYW+AdjFMYNq z#k70T<^)q}6V=E7q~})K6sjN-P2GkFEfjuil8)Mx9G4#e2dX$pxGvRsqPYkkn3ymQ1Rd4X?x0@KCZLotgh9ZtNC9NYtqrfPhO97G)IpVOlxd1 ztEW=ZBdALBP$s3RO#LOvkW*IgevlLC&GM6H1E%5e15Tl(8x@sAhfkg0e?4sH3r({Q zL{o*2q-%iKTdXNDmXisd$R!C^FnB*^6h%GlcBf;xCIY}tlKio9wW4#eMAgHt!q)w) z%)+`-Wqj?>dg!8#b?K3Kf9-!F_i-H95UHMv0pW@+w2&_e*1ur0I7jd@_|J3jnv*_f zA0SsMn-1tvkRupkgN{%ae>;5!MQ_>{PP(-dr5lX!v)J{kXT$E86d~r0A79L>UVtHV z)jLHee#*};`k!{y(TDK?M{&f&_;VpQVao}tlY zPhX%Buq8fjUpi)TCD##~SXXDOWd*i@KRPy(a-%5$V^Y$`__IT_f3W;l&j@#8;fZ-^ z6)SyEG9QJgJ9w3_iS8%G&Cs2nR{<46SCAH z)jwwr%L=SAU6I5sS5vT`Ua5b3LMp#)yZ!NFVrvRH)t*e6U7lQwi_4^8+a4&=4*I&( zyNNCvR@Y2A^QqD4e+)e|bx1-W!Qfj|f1rYk#-hGO)LY4S_|jK&^<-)3@fWuw&U>NN zyQ?OFIT&V_$!kysKN*h;C49UnbZi^d-by1`g}We~w96Zchl5Z(zwQl$oIj zfnfjwHKwzYOBtC}DLoUZ^{iBGvfYut;GXA~!qZTrc3q(h^=JX;XVmt}AV#$m!ecuz7`W>rqrrW(3Rd2g9;F)7$Cmj7!HT4e;3h4)|5ylRMcd4 zOAu&0eZDHqWp>L%m{bIu)+n|KZ-ssilY zhk3*@LZHyEW{?kqPP8k!P)EGvSQOa`$KlK5&95wo2ENHv*QfmQy38rtc<*?R-H;(qxjm> zf9Zs7b#y4gneo{%L_-X>lCi;;<({E4JHf4Ru7-Q{@(j*1z@fEG=bGcTs2m6<_OJ_& zx|o@Z6H21)1PqV4f49>LnPzmNxuuV-#~8a3^BwH=vnx2YHrKbd);I5UkQAf4jlEl1 z#NP(kpR!W5s>vnlz$rP24aQ8p?eHbKe?p$=Io<+NGan#1Q8(S~=jX%2f^IS{igErs z#L?;F<~keXFmsfP%vf-7?2s*wbei`h*vz5!8)F%DDn(OGck6iN`|aP14u9 zBnol{AZK+T=ik^O<;ZQEkSdFJa^IwrfK6R>I%Ei5E3e_mZBri^>Dd{bl8QD_QXvc! z2r0iP#SQfXj~Q}UPrN&5Yh%mie?8DQFzPWB#`;TC4+2bdGi0B&VuaH#RqlyI+t*cM zJf=N9>!;^&0;b04uOm@3X}du2b1?298XRjeLlZfsdpfCV7Nu&2YNM4Cl4G5;S`zAd z=huFb_AJaNY`Rh90=xI@br|kMm_6j`>8n&zmQSTjpH7#oL>=!%oaWc|e|uvws_Ens zLo-HA^EdAc*#<6K2U#yyYhn(CukHJx>p}s7Ik)~t-rG(Z_Wj9pq?iu%DKFAdre5WP z^gL6K@b5OR+-lNTpDI}t6py3fIhOaf-FC8a0!+ZqqZNB4?&I^eKBAMW?d0Bl1(yf6 z8X1r(HQSzZ&?y*e8pc`#f5vsYYSg{ratPy?GioR%$6Yb%Jyqr@7d9d$IkQ5MhuH=c9otLX&>7>l1_t@^Sh^PcCCK=jWPo|h3h<9Md9YHLx z8bP3eTy4Wi%!l`!ZVN}bDw_8i$KWjkN)@`*4hpfx4cD^dALrv@I?_K3KUHHe_5quLkq1q^V>hg-4r>%!uh$uFIyKiim4pdnN7MT$(os zzPQi1z)}cm1()YQGFo(HQ)7a@z}$JxPJxqIh2BDt?}jB7QIDj$3X7U$)ULK4t|bus zPt*nmmE|5;4LH~V&n0HygDP#9DbR5t%KpaQ3qLCVhL?(y&hu|+e;Qm6RI4#e2yf0Y zJslY`IW0Ajf6TQprXsYtBC%Q8LqzKJD6Hfe#P;O)2HJ;HC@PSMVxI3a)i(+^Pp#xc zuT8>Ya@#A0|CP;vUY0a6>&TD~_>Ak%w8v|zsB_6bOu4gh_KzvrHnPG%Cpt!|YtkII z$q~u#uMXlud4(anL%sY@!d@jt5b{-1=;n$eg6de=f1!=6r!#n;%}$GS-0PI1Or0z< zQ4M>p5XN!Z&OsqX>N`E(tRd!v*{D5H+aFHBUNMv=b{;Cy_+sW{K0bleST}DVE`FYw zgO;l2ZtZ{LQ3~hCRhaSyt9Y%4bHkYF0}H1!ul;T5I{iT0~sDDz8cP zqHI*ofSO=*JSS%4P14KtJuc13PtKf7=|Z^ff4rRm*nNWf>67AdDvMXt2X)0sz37De zS~DSieT{^axsq62ebxyH&d|lHnggWb1fe-mQv%itY`XBDxRJ+G5RH-_$LZ+88Z;=L z{2ZPnAM$dV_VeGF5AWsWsGrVE$R3;{3blVLxg+iDxR=)^m(N&r44Cu1m-|{Ygq5Hx ze@0jj>;m4t%`vZ|58Tj^@kJ+jf%1HRrn=qBKWOkB*&pqO38Cr@3>y}adx^PuOmM`x z{m>?eZ0){aY0haBiPngA=p~gVqx2H3NX#uG%~8|LX`4gub4`;Yg;T0xIPcRwuM=qc z*k)b5QIZspK26dIo>pD#*kyaD3tjT%e_La7W8=>a^Y}vFw%O;9b+kb1O_0CF8~`It zhB?I0>reAuKAEBHRAx%#*4nNy+!2p8%{B*ubu~RJ#$DTKD*ienGtf1X?{<1NuV z5;QwDv9j%8NjL91&qSGWGV8-q^c8r2B^v*6_a6MuS?|X+@8Y;nx!~*T0cM*@bbZ0k z69--|EidGn+M;$T&(o3EKuMDJC(pTXxj~O6Gz_2&4K7=M)f19_Q7aw)z!D6^xoSh}*Wj;}dG^k@mwj{m3DJhX!+!sV; zc%Ez<|Dl6wyKS%~Bi9$9?1{6;OXns9C>tIbI_82ZoKuo|3Wv_xL#PIdKT}El!|4xn zj~RkZS#f{C9`~krI_cv;A4t?KY0U2QsBT1PNQGXKZEs+dEud$!e?lAL;zfXN zkFMN_=h??hoa}>OfAJEgyaWaoBLQFJ9O_o){?aYeO@?Un{)RVU|6v1(bL|$iY*I8( za7Vdbw4m)IyBaCRizOsbt5Rd8Y1E4WVRaU4%MKdXitNBzV$kCZcqa%86t)eRcByUt zn3cpUChjjz1f;BjM4L1>gQ>Nkr#`hs);zS&^bUf3#qs7Ne@JYxo!sl_38Q5~a_Mgp z%&awKxkN(-XfyX zxxj6QS0@l2%Kvs4-}oG6PURb zINIm+?HmWBQIxPdhAo|2N#sMDV0-z7c=s&akY?^TH?G@DHN+|GY8na>DLPz14ShT< zt}yJ7Ol#Sljv@5yCF&1tmP0U!C`O}4u z61rBj&V!A5SXJnX&}T+}Kw}8|d}GUDFbDbYZ(z`@WN~$N8P;~4#-$F}XA_XkL9eh) z0yE0Re|+#-#vs?lU>h097xYb9Rz)7w=pwY3N|rZlvGXJTU~REXRY9e69WveFI?wP& zqz;vG>nJgM@^T24){oUe3j$Fy3mnpCqI z1ddZ(^Mpz?O{ZW$bQ0oO&EYjVFqq~5lDDacf3tRSHU;e%7zpjU?LFx`^90u88241fg*WC1WGUa80;iaje5L*@Xc`rlQg}q?7zy(ou(0 z0@x{H{iS+KwpUU_U6(|AI}LZXjrD|eDXIMYy1+e~x<+@!vE4>^H4UE~3>>HES9@g! ze-J9{m7*9cW)*XCaQSNn$3kfK>01` z(!lS;oDP^7aDwIqbLdav6%vV=F}4C*!ydVrbDmhUsR$9DERhZX0A6JD9w?>19W8DudEk!Ko7Z zidwQo4T>AJXd6`e2F*~MlSP}M(#teM447Q%Po7N774hXK^9Ie_WHOg&Msl+wvJ=fM z*@rtgJ=1*0tWS2{P&$MML@#jm0Xbd{MK}cQQmFw>@&O(Nri8=N;B{sbe>;(vNP)@d z&=6#O;uw1zHpJ1vk*z}4usZ5+f=%1Rt3}V`L+F1Qg5iOXLYD<8>!4fM^jSX9lz@~q zk_krl2oZ9REJcKwJot{%xO#1mHzM#je>miBMZ!Zmdwf0LXFPd_Ly?@C1@PsiyPW2BM$Xis02o7n%Po-|p55KfYS zKnMgFWA_?18H4(D=w+|SKvy_fRY!H)}l>M~4=mcS7kl|J5bTKI=vr*=Wrhw9} zfdl8VQtyGH^os5jZ`~oI3v(ks%nsA@7Ygf|NrOr@60_0@nR|NXe}<||PfwT{GJI2q zyZUu2?qkC3#(Yb#TjMUo#-Kt+`Ef@*upXU*6s|LNu+(4vlB~a7f2100LW`|OZ&jmz zTJL06S+}VQh$y^R&5KoqQ6gyF)!Zs3MB)RC%INE{qypH16B5_Esbq6_U~&jy14kRj zCK8M#J}_ra8XOEmf5B+@G}o#U;_-a1>~n40F?YE!wq$&z)#SVZ?lAkd4N3s`zD7Ut z;jiMwujU0%xQ7+%=SwxQg$#pa`nA-`9*gyXj(pGA2Cme6;uqAvfiXY#GxGM~wOC^{ zfbR^9RUZb8FY;ExfSJ<$nCX^CJ;xn+qk(v@-JZNLJ(=mYe*_d-gV^hbgfcc&9}ImP z7mAi>8~??ndxOv4(3;}&H`gw9X)Be2tyIR0Bg;c|XdWo3hBm93O>Q_3O@VG00m&dL z_R3;w*GN#RndV04z5+{SI=F_b3I9;NZ$%=H&my(n$Xah&6mwh$ioy2WiQ_)V9r(HD zGcrBY>W{2{f0#Qzq};G`$_0@~Qz3=ucN}rezL{0N!Jr#7fmJaAOppNsY;F}DR=_A_ z)KPzE{Vtkoy7jjHHY4pI$lK{eiSQfF3LRd^z&pT^lnK)C0{Irh$rL)rXL6dB6bHk* zuJ+c}CWqncZ7?J~20b%!Nd}5)WkT{gur+Y<;q(AgK&-#FDSwvV4!>_3vn}hE6Ipu0 zQOR`|?bGT5Z4nRS@fVx|))fekA#}*X-TLxOM?|P1=UiN)xY2myIm7C+utQF|j)hn^ z6aMfoe=%Fx?c?`>wYPxc*)X_~hhSQtD`^5!%-{W{^Ub{nUnlE|E<51YlFfUa`x~3z z+yf2%MrUJl^MAoZsnjS=(VUJGsKdIFO&s7CU?)DlPss&Jj(m%nl0G!eaZ36{@m_&A zFABa8j)b7|yL@k}bN}Av=GS*OzYV*+n%w=iquxAtaQB<9spp&D-n(~iIDcNfV>zrKe?6kZaXV|FNQz>P)g zk-h8+HGfm{c?qk%c?PvWLlSbo+M{T3=^RmV|dV3)=ZMJ$=C!ba+el!|I zbv$Cvk7c~?#cZh;0F6`OfHsEL3xL)x;77e;a(~Qe7vwzPT&d;WdwGb*ce;=et^o6$ znS#u#a;#?=`)DrNqM7DM7jgibMR5~qyn2zhjsAz7Y5Kx$np8p>t2@!Hpp_;9`^mIi zwrM#C`83W#xFtLu0zp7?O8kbu9W~1s)EIvdI)D5~uW;2`Rym{dARNrpVq9?|1nfJe zg@52R(zyn0sP`4s#tN`ljbzm@2@O$Tl;)}wxy<7ZTEV7QC@?3ch%MA<(P)`rFlSkP zG3t!bza>Sclv&J*IT2}~RX@v&&@Jz0Ojs%_(7B@?@S=i3Wje|G9R=X9AQEiqJe0)8 zX#c3Lc}aqfq(aWgZOA|AsGWWhHGJrnBY*X)Q;t^JJ$p_@Q|!mHAze)irtx-&npUxt zqA5aOhNv6!Mo5SGfcy$D7=%~OCE3QF!B4x?D-QIlNV+kj1-4;M-D6HuaY4i*JKu8* zsoJ=VZDQ{xO~)eyv+l|VT6;yweC!r5H(yR2cKz_;5eS;*_=h-^ghE3z&G(kEM=WZ02LY ztD0Ya=55_z=KWVo&b%;bst7i+$bS^oPrSBWtAuI1h?ku75OBQVH|O`D+1AcJ}Gk z#^%=A#y9H!m5T@9>ahz-MAvveiaB-tA&Yk*x>a`MJRRMv7f>%l%yIA|ihwNs( zu+^h|F|Vr$TzI^?debNo@qfxh0Nmhg#CyTuShP2y#m!|fD> z74D`x8hF^ecARX*+cj>x{zy&5hx1^kSM{(lrA54=fsLULWJ(ZSo=mkpBp_p0^#U%# zB{uk_W3YUDFn~OyFpY@b6NDpE#fc&>4A47iuV(?b2~K_PZ6ln5wto`@Kr8=nAW6Qa zb@Zb0qDtz39p&*>I|<$y#qgF3kQA+(p^dX(>)6QIRC7a(Kjsi9){yxWWM{>BkY}Q_ zy~#_mxWQ~B1z0knTfflmqG8~FWwRd?3=NWAS%Z2Z^X@`66vv8CioPZUBbK1g6Z{U# z)Jb+fq;3W}ggn!AYM&~W3ZiH3<>O0teO(%FmuUK=myh}Os3Xc?Ab9L|;m`enWHXpQ! zApsg)?$KQgl26XrV~h0l%z=^Md+KR=MV^TOj1J)W6UZjna{f#t7?DoV_z0MUyf!wE z4Vj~}RBATC2@C@V@?&s-BQ3Ac%Et;*+gQE=947a|0)L*`m)1&H719`W?4w36|Io0f zp*}6svV1}H8fbB|hA$dkISe$>F?!)0Fdrrl<#7Xj zar39c{pb1z&uz==ExoK9V$z@zXfYY7xx_Fiy_#4D2?wFuM8!@M=h*~UgzU;m`Z_Eg z&+Yr(vwy#F#}iYYd#u@K)!kkrS^^~0U$g=^X`B}QUL%Q?9B~L)D7LvVy7J-WLxpU( z7El6@qwQo?OvlM7_;6=qV?t|0Td{Htp}BYFMNX)0%OY^xpFwdz=j73&pWwB+`{*Ja zkhS+u_$6E|ozskC;hnHy&^D^fZs{~;0+u@cn}3Z-Ix@lg!2rG(9;TxX@On+fODEAf zy<)14V5&)V_VCI4n&8~8o1>aPfxCZwC7cYdMU`Hm)j@r&Nip?m9m11&LsLtEH!*f- z>Iq&WEl|@P8q{2%l0p}(XDdA!&YKdooxz1()O$@&=G3!>8jUv9+lME=z>_&u_g?N} z*?)ts5)0;3$E!BAlb=4V>I3>@=qW}Z`|8PIKIywdxMi{Q>cZ6DM*W zO8}yYc3=Z32M1sjvqHNKr+R7qP08O}s}1d^`-+ytOYP)nv(oR+s*dTIpEff(&(tsj3UPMSA z3O3UgeSz4|wl@p*#es6;zF@3I*%$CvUAiw0l&hQeg@Qk}ZC}uD)q^p&FAkI&_hknc znny%_?gD`NEYueVijKn?!kN>THNP(}rxORrLVa2LEPXlpEc0^oS^9GPS?1;Vvw!qu zq>e_Q4wVzLP+wdq(atQ`7orXoQ?qbiB$P;RWM4p`NIK!Foj}}UM)7pm8x1Wh4Mgfr z753tD9gk<(`X$$g*bHE4lZ_Usb-}gBypr22IdJnL0J?hil(5iGM~We#P*e+4J>#mA z;#~FkDTY<>>OmIYz=scwmldC3@_#_0l$<8WVw$H?9r6b(^{?B>3-)4xpKtWf>uaj% z7jn^h#r>4hKDI>XxNZs&6f#C3Ka4$1)~p$r0v>kH{$_3UreL>8XEJc6g?~D$ZgQCU z5A{gGj2C$E&d5w5A(@?3POQSc>R=zU@@V7Oa?1n(WE1yF-imZ4l7fLwntG`bzetBY zB})PPX3#NLsYgW3y)`t0qA1NwMG0C4p8g60+atc+Gci(d?L4XFDgqa$tPEl_z$tb&UULNp^ zrf>9pV$;!Mm)eL~ZdP&;B4{Y%zSzJvI;>Y{ z*kNwBbRu^pB|S+Mrdk}zz4Y9SF>3eI-D_^MHtRW-S9a*5Yr+t4x!$(=PrBkkt!@0* zq`IZ-c5?L;(+FWe6#NSAa;#RRID*+=RE*Pc-k&8{KmfhkX0J}!ff+xX z$%oX8E=~=}I`Z|*ZGYzap&f^)?pZt~vTh<`Let0H4&)$ULl^KhWoTk5$;eU!q>7#z z5mQn`y~x&D*r>#AMsW)BQ}76(4_fWJZDGXZ>N zfWL{Lx*^Qcz8mgxEI}Smhjg`?NNqRSX?v77V!R!iZ%2*bAwHf?Bcx-zGlt}6XFh@i z=f2K_q$~JH5`R|Em=ZNIFmr6{iQ^Le*RfmeIR$52@QoCEoFI92;v8aDNq=s@#ylDJ zB20|!u;3dEONOV6pa-^eHBr#Gu;6yW8#ezm^3NennmR7c*L&@u`+jEM&&2y`l0HdC z>&S=DjBaz^*QY~fR8rh!3o+2BWsH*ho0D*l=S@dVmw(UoF+^WHEP){UX5veC-ZUhJ z5E}yqoi;<*rueg(Z!{im^M(c2CSQ6)FR_(oo#a9Be(~nPjl1l+5iY!1e2Y;lr8>ETX&5PE z?yZ&he1BNcr9IYCKObr0Ck0Un@=oIR--K_lny)54YwI~^$>~QweS7IGBJf%52rDB zLw>AvhPKA{YSR3|o9w}@&}B7pf9=~9awiuPrsas9j#CP>1kJ9SQR>5Y0$gKrQ?V|l zG&t8=CTKNrIg&fJpn)-~g)#GB%v=~6rQN8SD_1Ltj=yXfTGOpaJQ)0}%))AKOto1H z#eX{vn-Fc$N&^JS4nkE`6)|pR(a$>l;=Jk1Oxqb_+X6Bm+Bj-U->aPVy{&HSNWJQT z#j29ACo}s#s@iRe`j$VmT1jqOP!h7SBVs?s+gR*zf?d|uT{^bp@0#pDOg!*CAlJz( zxtL5w+w1FTuNWxoF2?8U?^3lo7=>#M0e`L`z;$g|2^C6J<6Q0f>1n514A!5(X4r@9 z!0UXE{jOZk%W|5P>s$99NV0@i+1T^zWbxC+-l9u_Ax<3Wl8K_uEg@Yd96;J;f5s8* z!8=twS-+D!d$Rr#0;G1diMFojmtWu9BKlyRl&DBgv0Zte!R;5n=lwp|v6Yztsek(T zY^YzglQKU?nUq?>XnkjA*_eEdQcQ&W>`6!0-0hb|+m_`>?8sEy?KnMNll@u0E04ct zqP1Z${5=~hn9Qlb{I8m zT8u#xASL&#e_*&*% zO#WaRxg3c!HbQlr`4TvC0}KINmBFWV>}rKEj^+)oIwrYL$Vt8Es2EL0FNEfsIR}9J zQ{Ky7!FwTjiJ%gs$HH@tTz@*#33*>Q-JC;3^7)=FAevASK&<-xp zv^B_HiV8VhAkx=|!B`=|qH&+Xcsb9Y_=mI~6yh|A#Rx;QEkw38nnRcG`5{TF7KMv^rQ86HHXiCV%e(u%7RoXDxJ{ zfs+nS5rmu@BVe`5O1)RwP`QNJPZR9ETH>KPRXB;oq_kVg6N;=%wEPvayQIz@3#69f z^qsk+0b8YQi^P>&vs%;bBq%4@WGXkNG&ghMQB3_hw)>X8SfMCP8oB#vIeDeGpg9or z1J_D!WXnbTDe=lL9e;D`Bf4J$DhWiepN`t{LJ&}zNqv_UCWg8qeeSc+uwvC`p=CfUnt%M5 z-1ZG*Or?-D;SDOH_8N|M1)pc#zeFlN1eXw!V(>By1;}Ajq(Y6Vc=z9bfBu zssiRt@qZ0r>}$%cvRGU`a(+y^7Yp8%k!ut;^cedgc<4TbmIPzXiKSE00yVI|M5{kS( zhJWEk8jz!=g>c__+zfoKZ^gb}-(V>2{#blWZoPlX;3A_FCB1>5eHaz;3}*A$?t_l@lD+>q6>UPnMj%yjeg)yVRXveMyXk}h_+|s#YU|EWh^Tsh z_&Y^;f}Fo`bQde-YoolW|7U zly!`(2z5%4Zz;o%zI_9V?br`jKW1(LShm(su~8J z=oQ%=m_)phm{Ngct0hN8Hz*Dc2$2f%d~%@sA;|%B$q)n5HpkfjRj~H>&wEtJ$Rc>x zAEPQTN5CT4Vp`-PJ6eYy{dF=G4^Wa_QaqCFaxNn8^g`qWjebp_&?4uA0%z@qGN77 z6m_~Rg^P(7Z&Pq!RByN7))TURym|(AH+iy76%9XV%-y*UT)bP9O@D;p7MukI%Y0}G z+F76}9TuGGI@20&^xr;Yc@o%7VqFg@~+1wq=IX)b`QV3g&MQojc z&3-t;V}i55N1BB_V0dzuGTk}4amZfSy*BmuQ@{7b5cP@P}L^%uqZ2*PtTIv3&b%9yaM zMu!Dyk5eq*_X$!_8Z-`4Y<$R+?IyLVL5x63Y{j>f2t4IuZ-@ zE-tY|-vttj%qMPiw~iDMzzHQ5Cnz#3HkXNQuR{-<=QpGfOOH#y?GBaT9kh zDzTWxKTTrM34hvcPa+aa78&TLODs1S_aGC9@%bed3%f#MA<|n4mXiIQEQHI1Wallzr959+x)qn86oWSj$&HsK8r1|_fQ?bB8 zGLD<(=))(*0mE}Km&}bEorw~jC-80&d~|oVXGcWu*_;69aEYiAq+=SG->5d-$565hhYf%gl=aPL_!HQ z!!NX6wc>Lqnnug7ixdJ+Yw=Z4YQ$WHQXJm8;(t?eK|=9CKE$l&tp#px{QV&j8H^_# zwJq_xJ%~}R+F&o|$TV^loM+0t;n;B5cW6c6yc2k7nrHUr^xa&Xq?O%)s)+t}0yVw? zBq~*z21azdX}`OrA8}LLq`y?NK}Fl9wrMeuV{O{+^#Ic=7hrm20D6|F)`-(t4iPE+ zmVX#Fj3uyKHl2#jNqk8bTa?5sg^QxPFLQ?H5NVV-tOvCZPK8v{~Voe$VsodiN&5vze)gj$oXPlswVwcd=&LGhzhs{1WZ8v2wK%Iy!H#YsJbe zc=<-Xyv5Ev0_+cH4gH#}2x>sr8Yk2>TW^_QeLSdMuXr}x?e{4vWZ7If0gN&a@PDLQ zX{*T-+P-KNJlqy4>A=*w5-;#eJvwml>Hy7)npr^qtceAu#r1pH#(EEZ%5%V`rP9@( z&%40vLdQ-ZJNjRt13#&;{tirnwyv)({|3tc4TPnxS9*>*^U#SxU=MKWMO%aSf{;0} z3u2T%EM*A$)wbH*{C%dr6VY}xdVf3z(L*KN&~R*14Xs+VK;A3}WM+W836}B4MV3)p zPHT2g7IxS^q~kVYOL9f74Q*n6 z9Pq|GOJT1ho1G1~DV+}SeQzPG)NZ+Mqz`$zx_-Nn#nPuFl~l`Bv0k6M_kZV+-a89o z`|tEy9k?Gd^h3R{+a6sUv_po>a>Am?)f(}Bg?3R@@@~w{;7Sa+G>;c>+0aLg9L<$8 zoTdq`=HONGHhgoGrMV zvrk;kH*%CScR6RV<(w_HoPV>*<(xYOpL3YA*kZcFoXuU#SrTK%jdumQ1F0cw^-zvi ztTF{!ma7V`YA8ogm=TN`P|ac6@l)qtXX?-by&V_a+PhAWw~w11h- zN^mtko7oJDsO1Qv2U_;6yzL$>Hfn{F-R9i4Rmb+|juQgxtw z{FwM_r9ZYbij|t(c3TNm0cMH3*v7C|i;0UI(F1$8L-H@6*NV|>B!ABm7Rfh zKsw@LdMlV91%LQ5vo3s>5J8B%BD)k(4Zgn5vQaV}fuD@3G{8LZAeiZz(1;9NGN5Qg zkXm-g#-3nSmSeg~RI2Ld*m_Tq1`(1;C-k-9M(Pl|dck9OPLWno^hu4qzo%v)$i~9&BWkf!ujjr#W*V=cOGoP>e3aeA+4@sShyvsfsC`> zw3{6kFUZ<9o@xNFQgKj3pbYBDWfVKxAQH}aDII?dTkeGaQl}CcWAKK+a8}mU-_X~m z{1$f-2YaZ~4W|7PWn(I)UDMf$SjpBO6zy9?3~_qz<1mElqS$JH4iwcrMldXCM_k2Rd>FG5%<(z$pIQk;1{EVW zMSq+%^a(8@v$RK$6e|d3T=?de&TUT}#3-=eXh9L1dx}aSd)tUi0h%;akRs1F-mxhU z$Y^d|Zy_!Lcf;gNr677}oODSf6n#2IMfW}CK!L6a{){LEJ#J#s@D+~qup*hY9`NvM z!>E9oMO8m^2Z); z`jEFInbr^m?vldeY&6VD*l3#@$RS-Qx|HebZ1QWtQtDaRS8{;XEz#-1@u95=gn!qO zTRe!%jCK=l$DHF4!Y%2P&MF8&r1-#z!Ue|=f@;6R%DkEL)lE$pp;m_yf?q;RkxZN8 zQ&4*51c621PUkeuK&sHfXeW8M_*PuobT%W>!v*#tLWfu#s^b)xqjIai^SAm|HT-vW zuM4^g_x#wgj(oUEz?^4m$(A*8(tp7rwlJCz0WiB3_bk1gnYU)g^eoEJ?)t}g((Hk* zvxg}wKvCAiU0^8__oLJ{C;fB`0fffcIp2)r!!w0`!>%^63(>pj40;CwpFXO``D8o1 z!gCAUp)jZt@|_yiPS@KVjQaUmPC=(yj)-eOf0u0C@dkl$d)E_nl5cf3uz#UUk5e4p zcB?5Qr=a5Z?k_|j9R-l+2yiKtT~RL=?aH^`-o3l=wNM+myaiB{jv$#fB8Ep>h1X%X z7?0tGi?2>#=Xli5sTDM6oCUM1QF9GO(iDr^GoxKs&p`rL&p=*vWka>T#Q@fx5-BXv zylr~(i#8ojGzIuwwLP$nuYU)dXANYsJC^phmhXdIOh6mN|Cy}7su#V_JGUyjey3t1 zZ>r6@%vQwSIs5QoO_L!zW;aU(JK+ME%T;)7dU?b)JBDLyt^t>@b~Y0n4Ut+~#PAVv z?pg7QxkxROVDFWQeU{=G+3{J$A93r8E5NCItAZD$w=(ieQ*-gpVt?@)YqX41$BUil zXd0=+v6xmT5EsP;mNOyBU70BV##*#>Ee0S~Ym*6j8s~hIxHU`zsq6*lbZCAG`9f&zX3GQ;Sd~1 zvUQgaK>cD441a6JAw(?Gru93g`MH&p0XHemZoIM8orRfYsP*HxxO6+EZ)}o<`Gf_} zZ=qt=Q&LXyvolmX-Jyl#L98V@t!qqYDqvQSVbPTAXaxm!N_(>!p{zce9wVv&rH;{1 z&9f6OjMka4V_T0Wki-HX!8s`hS5c z-yHDddyla=k@^#RU%FsHQ`T3Ay7>^keYk|CGjHH^pBDO9Dh3jZ5AW$S%{xD>6XYrI%c7ZhERzk zubY5raBAhfY)pbggMc&~+xt^(y^0?&uz-$GNw$+9_I?=jO!lePbcRivq>%wyIT-^x z`1P1JC0d!{m|Sb;FA;%R=Y7%EqQU~p^hQV++Ib)d9mg-&z)Y?z|9M3QO=$C@Ey7@@ zjDG_2Iiotk> zP1-AOw+lHLt#4knA=-)?9-|6CfGvJKFn_}&H7FY}oM#hq{B5;(&0_rrHVA)SJsYY9 zkQ=|PP|ZA_RXhiiM)#EywWO5GR}4F(gP^B={xs+lng7X@0Gw@2=s0L)CNh0nk{HvI zk@l6fQiv^|>~K1uj!3#@19Z3w2?S>9314|vmVKYiP9g3Z#QYf8*q6Gu1SK-9^nYSj zHFM)wqzK6<7M&toj{myP1hs{r**`$>b>Okim|pYw`?xde5tE?s%0; zE@&J4Y{#>jN>0vb(fR0PVfIY=j>py=WS=4fQ@oK$zbI!UKpjMLcWJmSC*83Atgn;Q zhUUPGrox(5k@w4{r;;+5Z7ju9Wq?=jl2%-KAmf*KELN9dkEq3s;lh)|@HYv`}A-OmfubvwJl!J?Cva*%46_zsWR1l6ZUVq$J@h1XB zBT@JF^D9rHVh+k zF+H_*&^yU}*S%^0qj;(h7d0Sm4M!*0G5Or*${ZkqLGy-lAS?limjV-E+3h8`Q|guyaZcM#lyL`8#QVET&hD9BZ{7-pltjyt6}53fG6j; z=tqVaYBn9|XspoF{bMW!;X<;^Dohkw-C7B?dQ0KNNW{ z$sn$CX~U}mRFgBvE;g-gRWvI<=~2`JE*p#{vo^ZBL0Vtc4p}*bt=PW*6M8=#{-gxD zJ_vQY{r*xtkGFDttMbF6`k}O?jfydZbyK}V&VN5IS&oIE(A)Sg97Gt# zx!mTzc)P+oqMwbo#dj#o;kmc<7yS%EmT#MH@Dvp}+w=#1A57Bj`)&FIzd^(T5oOza zgQriR6F*EPTy5(w^7$(WOtEdh%6Hsv z^Og1$T{@}B;D3H>+pkplRXWVnq~afX^13J{{M3A3q zKW;dX!Jrua^&p0FNP*N&fZK6;jM14IhNWrHKF}|B0DnOrDl8Wj8LU?ijdo;#PHh8T z8Pkr56TZJ!-~T4TYhgr;hTg^uo!&+Ca;&TWK*~LchHabt1@#eC(?!~f_+Zd-a*}eE zcJ4O2*igMT5-YfdNx@4)3AE$nUHTz~pzWiHV%H$80+&5%sO~k6#hl!_ZvU}zkq!pg z_?_Zxw}09zg97OP%JyCOs@TJcLV}g;d)LS9t?eU2)A;ypQ;*s_veqAJ#J7{55MD>& z$y)M3vA>=BUZD@3%6rgpH;K6jE*$Mp8~Twmu}1)p5|xV3I)%>^M5=g>o`6MsGvNOxXrc(>>)Au z`+s}TgDRjV{^MH5wOrSkrXiZ+1kDN=06*7f5l1G4a166P-0JOhFh*PO}SjmKNg{S)r@iS8PZ z_OHIuwq~lX8nr_3b6{)>4x)qlryT+eeCe|%Mu=3XHYWCaJ82Bnq10##aD((cC%n?L zc&hlS_ZU@tsK9J)B;U7_Suq74ynYWeZ;W#+Xu^=9c@e=ZGio1WBIvaz8@aNaW`7TH zE0=07iw*n)W@;a{wcX3>SiD@{y0>WtGAX9ri(N!XITC#QIPLd~sTiTIgljXL{8khL zHKy=A%+B68jl59{X?V29MIY9oF+M*{A*uoVuhn3tTCXmSStB&s`RVYuU~i?)QMFq# zFm30rz>eAdFac8#91F2pdPn@Udw+29>gBT+hfiKV`P-8hhX>#%K0UG=UE#4{@8K{lab4_`CruoE8}Gl` z5X__nYOkFJGMOz5L~cs(;Z?t1xUl4BtP0^7Ihi_p`G}?ETNL;O%r2d-wX;k3V5$ zJSZE~C&ne@o^%z)JX#Q_fCykg>i4)V@E)f#eE;eRj%Ab$xiKt9YvE4;&Dg==?rZEK zq2xpN?f%QZad$ps{<|kH_TZITKW>YtibCSF6bRXEM)41epajv6phnV1=S z`S|C31yjM(wRx`k({puTD+C;5woM#$IB3~IWa@Y(Mm`I(vPu@_CkZ{2IAzEalO%+-rKVSo84O+lHI7sy|j(5RLn z26ip$pS2Uk_>fga_ae>lOzYJ0%E^NKGJKAhS=ssH`uGNnvsY*l?wLaxo*5$#!6m9K zPY{(<Dp5aRvmX_h<+|P@NyRN>i>$J6WI&pMsNll31@{V%fZE zieZ`zPvo{h><=E@1#H$RFqgh!7xwUHleV{l7f@BPc7IG6Ed5BFK+0@w=WRr*bF~sB zP$u}?NlxK_vuCR$I=YA@8k9PTi3abwu#{H0W4Q~pTl?D4r=F%@iFN!7;*B}NiyVHQVYWPTF@1>c=&zk})Xyi)M$(WmcK95f>})(tCf}J8QhQcRWZV+^NF0Q`kJufZ zA+Tvq#ed1M>6#nY%r0iIVEBry;^neThySJvb9N?I=Ird>X=ylB*Oy-%);$=37MJO! ztKyu*2x$*A8#r*0k zBBXE==`{`qBK<4M={el7eG^t^aGLXEGY>g|_5u3x1PV83a`(4l^|HLQT!7JPLWZVKpy?C6eJEX<=_+2G(j5h8mAKyts5;sPVPUU`M)VSxR%n_|SR%HP zv)hQ2#4t+LDL7l6fi=M5O(B#M-i)|1rhhTXK*e~B5}iU5|Kto&tV+@EmvabfLfV?3 zkaODk=N;iBoUwbwU^^nI08D$Fd6wy<2G~i+UUmLShUM#yu}bCwYc6tjMUN@D@TjUL zTsz~0#Gh>eGOgm!5BmB0EEL^uv_`xK9e&Vb(M|Ktf_?Q>T)Z?ihF8CW)kk&Zk$(Yw zED}L;#h1DtAN=LShKuRAYn4Ap=R0i2`@Fc!#*fo7^Nhwhumi5rbVQdeb_)ZEQYVer zy*5f9hfj7P$zu;8u#y_$ZY#t<2^ru(rbKGeNJkmQSF#@vZQKE|l6f6#u2Y~0mqhrp z0w1Ymvk2^W9AT=#Pe8v8(W6f@B!7&M3o?~x?QJ6TkZbx=uX~F1*3n6rrbliMRDEL1 zeH(l^=zRrX)*3?(3B1)L8wOrA6@Xh{N)^t~V(n1)X*)fzuu51j%gkM=RygVYDPjHQ zs+T|pRTUG}rVBja!|)dTiSL` z2ko_5i;@i1eJ~u89aakBWh3>Y6sm+Hyk?gfg+Zs_99GF=R>GfW2V-K>X>(XhL=TEt zMmfC0L+sYn@%B!jl8rSBAAf&#^)(A$^r28eed9+>aXvT-7Q60|;l;PCrZM#-X3?(0 zi9kOhkyUE?hKpO-x7!QQ;aG1f#xxzRLm0yi2xA!QU#x?aSilgFOsg`)k#-3-(#V^G zFD`9`)H`(;8lo@wUL*6G4U6gd1rZ{PKnkk?SPTQ*ael8x;-KEn;(w?oDuvw5f@?P{ zG!KUqDRc9DW_fU;$(ZxH>FcOx_bjWTq)hW&()SD{;vcCK;tq zXv@z_nsJ~NPf7#JEU0h9VkCz#rUX90%)sLM!WUSIf%sKDYY^_jt+e2BQXbC8Fyadt zZ$A_kvk!}|mR65I7k?c7S$z0;r>hwMrmu!>Bahtaf(dJvR5mc{QTAGqPoHDuZtz}~ zrvcp?z%A*`&xIv6=a)Vg0`8!vSk!a>BuG|Ql9g3Ef+&M;w)~|I*RRTtDG7>y6wlxH zRjLNRT!pg0FIFk&`vqeYjHB@#m_-;qeLWMARxdN6@4fu&EPumnmCQV&)($K>Nqkx7 zD<56Y=26FcdY#Y)h!pdx1Fa;C*rRCke@Etw+}#WLGkUY{2Iq5gyBpI1=$xjPn3I-2 zMyKFvK1X6^!A$Ku??zOR!43*^GyC_x))$ z9?#l*FibcEeGOr(6&^A47ENQSUgGfsU&x%X zaa=J0fPN5kMcW23Rx%cnxH8DEKm_7Pj_w&%A>E5HT)7t7rmXyiIi7wxqI_~e!Xm@W-JsAT?-4p^A9Vx(Gc%C$@Aj!m2hwBF?;e*YwNN zJuf$9wt!cN7m*5S0o5rY@p4a@-}t$*|fUZ?CtV{@jV0Q)xrAv}3R~He7m?9j?8f4)c)+ndR5R zg_u{-mkHn#5ooLWz#~|yd9D+0+4(hp9Z`LHIz2t@YcE$?SFkNC&?;_(1_1tQy2}Aj zzy>!Z(}Owd;SS2H8^~Dm$B+-uacq)d(0?v99&LKzUHaP^1N0#~%>WtCru`&6LzBy- zyv#wENwtRByMmBW4ewmfoe{Etn==_Mw;^rlG=LhZQ(6i{sA}xanv4j*x|FGbJt@5l ze=#aubUXP&uZI8$Uf=r;BfHc%N=zLj+{ehMIF7A zSW>b=kkveU)5(HLGNdJX4oxf=o`1tS_E)yuu^g`g;k@A=&w3B5n>~uxIQC%GaU&AF z9M~=A0wuEMCgE}RAwebze4nUt+jzdt6Gn}Kj#xo;~=tq%W zIP_I1va$LqKf{Vg>cuf$w3$EvaFb&IsghrTBXT|js|)qR>p?LL9 zK@lB-cykCZVZF zQ(?JMmlt_I!?&I#kXk6pa<>3iK&ZbHspZXY%r-{;66x|f1PsEh)GU}dlB#H%o9zxb zZ=)T|BCFtY$ytPx7Q28T`;>o^G#0L6)ze~lOf@?Cm%k$C+~!|zd_LNmeGT7G^eXxu(+7D<99D7GLVhy`@*9R6h;uP*r^$GMK^b)PeVt!sa#?@S=@h}I7aYYu z0b!PQA+O)lF>#pc8vj_v=F8S3qXXiLA8PHX- zE(T7iRNTd!1$AbTI?FE;r3;a3)Gdl}FCVG`k%dChS8V*v`9-$E`4?-1?fa9z3lH6y z$49i!Hrou?Cl8PkgWiA8E`<2aSRtn4zj6!z>K6Vr;1)$bm03Hvf@B+;-)yKgz!$Hc zRZlogF=`XtpbKAWdWH04o78vhZRc*l4d>vm!=A3~u7!C#XFW_Z6F^!yxq7a7>OHzO ztEl$It@g%EP2IdozTZh^6;fGE>u8krC_W)p&+f&pSWtiuTlaqlQPuj-uVQUOOpb*v zo}4{y($&aqUU{~E_ARcP53!4$`^d#1oaW_7J@fL!gGVcq zmw)5OVqxsVrU4(}M(s!23rLJao^S4+XGCO^rPa5sU`wKNJ z^>1m03xw+9!Hd~!Z@$+b;-3r4(n~`g9_(U$@ zc~DyMit8RNd6>0V zy2LgppiE>KH0)x-knVJh=F=|73THAdyp1;F79QbmrpV8<^Z{{oY*Uv9)wh~NH6&1r zo20r1gbw?m`zF-mx{Tiic9743E$J46tmJ?A5sFDQvqXUj$83K9By^O4W*b&2dM3bX zSItZ06z~EX0LBgHDD4fVMeW!`$RCIH+dx3jfQ-}OvNSr8+Uc~M5p_+g*IE4^?jz*c zl~@xSUWz3MI;Z);Nf!S9&TGBEenK!9mj1q-&>+!m1a1AhsGOjIm;hpzSwjuyvKW8A z=LDq=K%6tS#_~+jM0_kek8K+a%6b;TS)^sdvJEzBGF+|xfP;m$`_jmTrrqH2qg<=dC*z!cH6-qos@r&5pFrggD>!e)hn?gHYb=O9;aZ&i2`KXDk$V^ zTSU>3U=XY@H5Jn?n>W#DWV|={Q1;Jqa$@7Y$w7DEoeps3f&||!e+k*IE99Tfclh3c zL=P{H(mCBeoX2h-Y)~U(7|Q{a&W~fRO#PXSWa5un`)g7t7bN9Q6eNG;HEDlQl9-&M zBYk*a*h#!&bn=;beZq@Bo|!}oG`wlGBeaRzTw(e~z0&PE?sH)%rFOW46biqxm+&zo zj$5zk vK?{CUQk#k~N+H;sTgzKO<=Rj}rl<=uWLGAYjUE5k7y(xn*11jE*Ee<>3{XH@c`cMM=nG=~$+>j@m{>rqn?= z0C_+o27!-y)BzJso!DKnv+U7+N7&r!oJ zx#DTSlGtf-SrB6IG?hl$%JJz8y2V&O3BugDQ&89`27phEL28>#4)uT3sR^QCxkpzJ z6oHIBbi470ntxoo+tnl7*4%{OS8+ES&B@(tK)r5Pu}dObbu1{CII#9yFAX;iaK#ZU zJdh%HjGp0{cZ>z5Ao73kf72VjC~d|)?b!P+@j z1c{9$;`*qQO{$_KjR}99IiB@^8}zfC5axLpIi^rEqkgJT595`P)=-P{Pk!Bfe3+EL z*kO`ZCk9BHW9o3eV@0&VTuJzAf?xd<%xjb+1Jz3iUw4rz+!%5klv9P{w#_kj9;10g zJ0R($UKB+Sn?X)^S&5-$O(Iw!8u?6#6y$LpTCW{N^{uW>2?*2w<+ z%Wh7Imxi0GK6*_oaX5??3Dc_C5F%)83>PU9nvhn3L*0L;(fbv7E9RZ<+P0PYB#vei zjh`#{nxS3~wLKKv({zy~F*=6F868k$2o9f@Zgv7H*R#V2$p}y>nwB5j{CDKwBvE5m)z@EF}9}B;8X7Q(1nBUH%85^gw|7ki6FyT%KiT? zIi+tk`tY^Qs^igz_Wc6TYJs`8q4++s$(;em?7c-CYX1o%xk=ooSV1K+*}ZuO(7Wct znb&@FNCP}si+teu;e{@hP#OiS2D%Gwbelo`fy#fx?W8f7@tXz)vQ22Yx0B7gcfaN* z8lf>2;vJkDQ;XFp+a}U0PBQ#q{YKz-1m`ztGYm8laL5aOP47{E#U)6q0G-$IbxfPE z&nuj5pu7p?%Na3F$zB1Ks(iCxM8!VD((I-sR-%y5EKLLJ?0M0yGkFvcFawg&TtP&< z{M>)$oR64v9^tg_!1g|-j%KtHLDwkB4)y6A(LlT)x8%+l^j|^=XF{BVM;hI9 z#t@li!(;(-XQjhI!fdJ`FSxy_h$sz)MXY}m2k~$`?Q(qkB`Kh38U2|IPP~+I`u=w^#GqrXGBx!@k6S{Z4p6WB7kg z$}KJG3kQDR9fIG9%rv%|aOsz9l6*r1u=-Qgs^xx5+6GB3Tfw+_BbjU<9ZpO`<-6#nVTy3I2!%z+Qt^JdMt|eqS@$ zQtb0#z&jCq!U$<#V^=0yR#7M5Nx{#DXWq>LC`cZBWHb+dUcIRk5vV>w81K9C%6n)Es;#nWK_>-~)_z$qn6qf)$-{E)RB zaCILz&rrFKG(8{dtCfy9I>f>VuVjNU z@-wucpVJ5M$Y!$wGC<^Q2&iu?c7EW=@Ba(>1YU=H1weP>Qj?!gSHyE5kh_u^40|WmITcKBk zdtkw~q}#9|Kk@Yz1cz6h2uH}T>Nw;Y0S&yLjT3ZeP(emC)}o>fq@uI@Fw9kRI0}8e z6OIHgm%VGk$S6>>Fw%cdrG=cmZtWJ3!bG8J(!{GGcrjM&Yl_s>a8xZV1y!MsCQWc5 zT#Ryz^=>SmL~(tK**1~|k#aP#gNZkL3U>_Mp-$3~7CM3YkokL&yob>6g#7@`znDcn zH--CGo*0|6I-Q7oF|hqOZlM*INi<{Or5Dgtn}!_#zhRQ7X>xzM7)5Tb7#+q6n_Zw# zhAI?7T|%GSrDrn{g}P0PlqnSI3Bg6nR+i|SysV3m{a^5=ekf^)Bh&gyCao}L$$YAc zX{|1?Vtms_=`WqlsgsWyvGd!=zun7@&>N@}=zN*q#8=YctUk!!;Sfkf;lwtf) zr_KZuz*sXCU&9HSsR&299jHOkvI6W$Aa3q>IwVOQ`dEJkWwGEP4VtuUSg;~Ax4vsP z_Pd3S@?_3w$v1p#EYzyO?l892+3!1)jFCGYZX7;gjQQ)fLrOam;UhrUUd+F< zH+n?MxG;a#(Z{U`6VA{a)CDmr#9RtuX#~vgWBt{eurhdiB}UJmq1ceazANc3?E2!( zdUkly+Fz5%!*sO1hX?T?o~6nEndWMHacT=-n~6x`?I7Ab1q9Tgns}U>lRZj5RYN}c zMAKoHde)FnRr+L*UQu{?7`vj9TlWPG)dlqOeno%e_^Yqr1tm=S>Z`A|y|h23*RtN$ zMyvoT+&-jzRp9Q%h9uA-JyzxG$T1<}Qpp1#%DTr7wPTiP+8|A*5W0`^wluuSi z1dM-FQ6vLD0}k(WqkZ(YdVoyH$B)5Asv#9VuH8I=n34GG68Zzd1^LTgaA7Pthux!| z2F*4-s~)UnBozCqm3-%pDMa)bcsVJR0OYg)vbZOUDW{K@7(PXFUa4~6K?KpHK=kG5 zqR>vaT?ijPhAT!yKzC{$dw?_iFzkPAJv)D*>sktY09pW)mq(@+-7OFj&@&K!G%B=uM;NT+x!H1-)QKi$4L%0A|8~z;; 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

    V5ve&zBoKkSbGwabuwzqE`=37H~ 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 oMl2rJm_`D< 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 delta 243256 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

  • WHUOO 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

    I=wxCQhInRyc1+ATr}`| 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 diff --git a/examples/graph/02_random_nodes.html b/examples/graph/02_random_nodes.html index 24e5926a..f5a05364 100755 --- a/examples/graph/02_random_nodes.html +++ b/examples/graph/02_random_nodes.html @@ -74,6 +74,7 @@ nodes: nodes, edges: edges }; + /* var options = { nodes: { shape: 'circle' @@ -83,12 +84,18 @@ }, stabilize: false }; + */ + var options = { + edges: { + length: 50 + }, + stabilize: false + }; graph = new vis.Graph(container, data, options); // add event listeners - vis.events.addListener(graph, 'select', function(params) { - document.getElementById('selection').innerHTML = - 'Selection: ' + graph.getSelection(); + graph.on('select', function(params) { + document.getElementById('selection').innerHTML = 'Selection: ' + params.nodes; }); } diff --git a/examples/graph/07_selections.html b/examples/graph/07_selections.html index 25faf4c9..98e44ade 100644 --- a/examples/graph/07_selections.html +++ b/examples/graph/07_selections.html @@ -51,11 +51,9 @@ graph = new vis.Graph(container, data, options); // add event listener - function onSelect() { - document.getElementById('info').innerHTML += - 'selection: ' + graph.getSelection().join(', ') + '
    '; - } - vis.events.addListener(graph, 'select', onSelect); + graph.on('select', function(params) { + document.getElementById('info').innerHTML += 'selection: ' + params.nodes + '
    '; + }); // set initial selection (id's of some nodes) graph.setSelection([3, 4, 5]); diff --git a/examples/graph/17_network_info.html b/examples/graph/17_network_info.html index ec4379e2..0b7e033f 100644 --- a/examples/graph/17_network_info.html +++ b/examples/graph/17_network_info.html @@ -17,7 +17,7 @@ } - + + + + + + +

    Clustering - Fully random graph

    +
    + This example shows a fully randomly generated set of nodes and connected edges. + By clicking the checkbox you can turn clustering on and off. If you increase the number of nodes to + a value higher than 100, automatic clustering is used before the initial draw (assuming the checkbox is checked). +
    +
    + Clustering is done automatically when zooming out. When zooming in over the cluster, the cluster pops open. When the cluster is very big, a special instance + will be created and the cluster contents will only be simulated in there. Double click will also open a cluster. +
    +
    + Try values of 500 and 5000 with and without clustering. All thresholds can be changed to suit your dataset. +
    +
    +
    + + + + + +
    +
    + +
    + +

    + + diff --git a/examples/graph/19_scale_free_graph_clustering.html b/examples/graph/19_scale_free_graph_clustering.html new file mode 100644 index 00000000..cced805b --- /dev/null +++ b/examples/graph/19_scale_free_graph_clustering.html @@ -0,0 +1,141 @@ + + + + Graph | Scale free graph clustering + + + + + + + + + +

    Clustering - Scale-Free-Graph

    +
    + This example shows therandomly generated scale-free-graph set of nodes and connected edges from example 2. + By clicking the checkbox you can turn clustering on and off. If you increase the number of nodes to + a value higher than 100, automatic clustering is used before the initial draw (assuming the checkbox is checked). +
    +
    + Clustering is done automatically when zooming out. When zooming in over the cluster, the cluster pops open. When the cluster is very big, a special instance + will be created and the cluster contents will only be simulated in there. Double click will also open a cluster. +
    +
    + Try values of 500 and 5000 with and without clustering. All thresholds can be changed to suit your dataset. + Experiment with the clusterEdgeThreshold, which increases the formation of clusters when zoomed out (assuming the checkbox is checked). +
    +
    +
    + + + + + + + +
    +
    + +
    + +

    + + diff --git a/examples/graph/20_navigation.html b/examples/graph/20_navigation.html new file mode 100644 index 00000000..cc9ed615 --- /dev/null +++ b/examples/graph/20_navigation.html @@ -0,0 +1,181 @@ + + + + Graph | Navigation + + + + + + + + + +

    Navigation controls and keyboad navigation

    +
    + This example is the same as example 2, except for the navigation controls that has been activated. The navigation controls are described below.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Icons:
    Keyboard shortcuts:
    Up arrow
    Down arrow
    Left arrow
    Right arrow
    =
    [
    Page up
    -
    ]
    Page down
    None
    Description:
    Move up
    Move down
    Move left
    Move right
    Zoom in
    Zoom out
    Zoom extends
    +
    + Apart from clicking the icons, you can also navigate using the keyboard. The buttons are in table above. + Zoom Extends changes the zoom and position of the camera to encompass all visible nodes. + + +
    +
    + +
    + + + +
    +
    + +
    + +

    + + diff --git a/examples/graph/index.html b/examples/graph/index.html index 7cb11657..d48f7c87 100644 --- a/examples/graph/index.html +++ b/examples/graph/index.html @@ -29,6 +29,9 @@

    15_dot_language_playground.html

    16_dynamic_data.html

    17_network_info.html

    +

    18_fully_random_nodes_clustering.html

    +

    19_scale_free_graph_clustering.html

    +

    20_navigation.html

    graphviz_gallery.html

    diff --git a/examples/timeline/02_dataset.html b/examples/timeline/02_dataset.html index e493663d..c15e9c7b 100644 --- a/examples/timeline/02_dataset.html +++ b/examples/timeline/02_dataset.html @@ -39,18 +39,18 @@ } }); items.add([ - {id: 1, content: 'item 1
    start', start: now.clone().add('days', 4)}, - {id: 2, content: 'item 2', start: now.clone().add('days', -2)}, - {id: 3, content: 'item 3', start: now.clone().add('days', 2)}, - {id: 4, content: 'item 4', start: now.clone().add('days', 0), end: now.clone().add('days', 3).toDate()}, - {id: 5, content: 'item 5', start: now.clone().add('days', 9), type:'point'}, - {id: 6, content: 'item 6', start: now.clone().add('days', 11)} + {id: 1, content: 'item 1
    start', start: '2014-01-23'}, + {id: 2, content: 'item 2', start: '2014-01-18'}, + {id: 3, content: 'item 3', start: '2014-01-21'}, + {id: 4, content: 'item 4', start: '2014-01-19', end: '2014-01-24'}, + {id: 5, content: 'item 5', start: '2014-01-28', type:'point'}, + {id: 6, content: 'item 6', start: '2014-01-26'} ]); var container = document.getElementById('visualization'); var options = { - start: now.clone().add('days', -3), - end: now.clone().add('days', 7), + start: '2014-01-10', + end: '2014-02-10', orientation: 'top', height: '100%', showCurrentTime: true diff --git a/examples/timeline/06_event_listeners.html b/examples/timeline/06_event_listeners.html new file mode 100644 index 00000000..8ea72e1b --- /dev/null +++ b/examples/timeline/06_event_listeners.html @@ -0,0 +1,53 @@ + + + + Timeline | Event listeners + + + + + + + +
    +

    +
    + + + + \ No newline at end of file diff --git a/examples/timeline/index.html b/examples/timeline/index.html index 91b28ffe..2ff3984b 100644 --- a/examples/timeline/index.html +++ b/examples/timeline/index.html @@ -17,6 +17,7 @@

    03_much_data.html

    04_html_data.html

    05_groups.html

    +

    06_event_listeners.html

    diff --git a/index.html b/index.html index ae57caf3..a0c18d7f 100644 --- a/index.html +++ b/index.html @@ -73,7 +73,7 @@ bower install vis

    download

    Click here to download vis.js -(version 0.3.0) +(version 0.4.0)

    Example

    From e8597bcbeb79fec8441bb40e89549121b9758069 Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Tue, 4 Feb 2014 17:04:04 +0100 Subject: [PATCH 28/52] WIP manipulate dataset for graph --- Jakefile.js | 1 + dist/UI_icons/addNodeIcon.png | Bin 0 -> 20998 bytes dist/UI_icons/backIcon.png | Bin 0 -> 20802 bytes dist/UI_icons/connectIcon.png | Bin 0 -> 20764 bytes dist/UI_icons/deleteIcon.png | Bin 0 -> 20981 bytes dist/vis.js | 222 ++++++++++++++++++++++++++---- examples/graph/20_UI_example.html | 83 +++++++++++ src/graph/Graph.js | 66 ++++++--- src/graph/Node.js | 4 +- src/graph/SelectionMixin.js | 24 ++-- src/graph/manipulationMixin.js | 128 +++++++++++++++++ 11 files changed, 468 insertions(+), 60 deletions(-) create mode 100644 dist/UI_icons/addNodeIcon.png create mode 100644 dist/UI_icons/backIcon.png create mode 100644 dist/UI_icons/connectIcon.png create mode 100644 dist/UI_icons/deleteIcon.png create mode 100644 src/graph/manipulationMixin.js diff --git a/Jakefile.js b/Jakefile.js index a4795eab..a4a9aa54 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -82,6 +82,7 @@ task('build', {async: true}, function () { './src/graph/Popup.js', './src/graph/Groups.js', './src/graph/Images.js', + './src/graph/manipulationMixin.js', './src/graph/SectorsMixin.js', './src/graph/ClusterMixin.js', './src/graph/SelectionMixin.js', diff --git a/dist/UI_icons/addNodeIcon.png b/dist/UI_icons/addNodeIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..6fa30613f9b3d97508534c69421eca60f1126746 GIT binary patch literal 20998 zcmeI42{@GN`^R4qLa3}sXGpd%t6|1i$C@oWl^8Q)Ow5d!vJ}x`tCJ+z9WC~yqR3W6 zR78|yiAqumr&N^fKT?y^an5gk%YVDBnd=&Jd*1v0KF|Akp68zXedoH~=xtUetNGUR z0RXVt%+%19@hP$J=H+JmeHx%W#rRm|YwF?;0Q~C~-W)(m8pDInnvBJ6+vY{1)BL?? zz92I!7Ub(k^CbHa0U)p^-Hv2$_gYMQvj2mDc~sbGbDFIvFUZ#5SeQthyt2$H;jK|J zXS+ph>ed(;aY^0IjN&|TBJ8-Rjfy}F-(#K^GUrYlJ|7ixclz1>^WKlDCtu#1yV|8Q zTsV~5#`8?13>GDQHFq*7Esvc7-IxDLjVy^^9B^~ zSQUVnIeD4_m&$?KR$=}UfL8#3*hC#w0=V`A?zcB>3IvWM10u%noiOjV6blb4Ge{+u zU@GKLM&UbnRrl~XIjL<_Y&8?#B7(%Nz@_M^-3&^WgoPu7o=&s?KxUjM<7_8p16u`) zTU(JQ$^_k1M{aP>%X)YW&JDE{`04?`GkR$IoC>&feV7(^7-jC<<}og>UHqAQCy#lS z2gmmv4;EP)+D@%H;?egq)?}ufe||>#foy}BM}@Pp$e_*IJtquPj!(d{WTOpE zDc#!KF;93tpfb&=GoTJ!+O5N}KTb8*70>y}TtV2GUi*9!0Nz*8>K-cca)x;we%2N+ zKdw7#lDQcO^E5lP2LN^%%Bk7kE!Az}1pvd$aOF$-QXlFhRBE|5)UE8R zxM?74z()w%;ODMXc*sC8;@%}`Wq0sHJ!wR(jaNjxub|pZhiih`zCvGcycubl>J;=dS`n|T_3RL7y zbR9O{|Z@w&BC{WP2{*q%MXI1n^eB0#!uC?JtwX2X^ z0R|x4MtxIf3umjxrn#UEa)>oOt29<|9a+@I%k85t z(qGiSfWMG>A@hC*U%H3ho(ofU&lPR&?%panBs_!|;wC1+^c~Kp*gnZUYrjT4cDq5* z*)rRUHj%mO5PMTl_YRAhnP(N9OL(x}OWbRceDM{%a?O*3jaG^GojRIdo4iVV#rYvX zV0DD(;if2(qGYNBj|53FK;mMOMYiOFW0Fnw5Dn;?q~TE_Idf)`ThC)4igT|_OW@p>_Uo-9pH9@d8;0tDR9V7-}c5%%8rz$l^dB)%B9)s zUI=xWjplZ#x2U(qUa-l$>^4~42;#>}mIkWGc&{#q*c-0iAb}0NLSy>AOme1~e zmn>(8?XIQ9Md?MGA5|4q<*do6u!^@T$aqAmzx1x`PFY^Lh4>n^J}g-2Z<4ZR}H

    |#V-x46+1BId1SnF`o)!|KGJUGs&sOwUB zRzUtFZd_dFlaAkSgF1s4jec0ai(89EZTao;X6t%dhTG8r?7>a*g!$n4b|5EgGY5$? zI$S?|$BOBx-~%!@PUxb0iJwZkNA-_qR_KfB#~vy=G*nk4<8}M($s(D_;iT5MR-6;L=DdDJOF_k?eh^ZIsZqIy7kAJ%`s@QdLY!~Rqf)EaeBb*s9v zPQKc1Opit-qEfd}&C{i&(>dMQ%*T8KN=>;KN%grtFf%$4`8@qO|KNV{B=Bul-=MRt zH$NQB5zA9stAakGXAxzkdHQ#KVdY%0qt$y; zWy|1GZ{w=fgXC_(vs8vEjws}vthQKf@gxCf#;5Q>B+*CE~9I?jEYU%HjQn-+^!FXvmwsu2ENOXRyn_Ros_|bSWLt=$K-W zUhzcHgO3&a0*9m`X?JfV_np3ySI|&FX!GpweEqUtHDib1nf%0;iGtMC-91-U4>(>K z{rJhK7o2!cvA61Q8Mfm54a~J_V$Pk`ds@2o7wkXSf3Zi7bv(I>>zbmrk4f#X{)Bkj z*}J29a#rWg^+PU5uLbm^pSadiIcsWa0Q*CH#*p3x@G4$fJgO@d`z6%RY5 zJGAX>V;^mKVHS404S{h9+B#u>hurh}(1Uo=`?llh z3F#rBYM=Yud(V~aAI7&1>=vSpR|?agbr{Vb8`i4UYTfz%8vT7q@6bA@YfdQ_(QcFx z`Uqw&{(*HYcg*!Y9`8H2yEY(mqP@>#lKbf4wz;^E zu|n9DvB|N`5vwEKWN7N3P|tP!W?#?bVA}|7@)_cD=jNJ=#l^s(Q=M+|K0cK36p z<0a$c=eanOCT8$()m{M57bM#|)156X(0Cd}4M(7P5Y+-HzKlW?05H0NzBs%$kq+`8 zlE_qT+3~6yvLG@+Th>Y45@P9#C3=xfgZ+qh!B+P8U~fE%AgimxhY3V81Smv04irf7 zq57i(wPnBRq8au=Ggub%)rIb@EvvuKA;{Ts8wgADBZAb`)K&2i7!;&|QiG}^P*A7} z2nK<|!B7YohEjz>(FhGR6bbtFlGWj3SQtNoC)(D~_*-|3|FmVj=yYE+7#t7~pcVjE zqxq4*P!tLUhQPoum@30V)jxOKwPj@& zI%2-QofpNI*%8(M8#@L?a3IbX3{``GmkT1`nK8b5{d~R-jerLeeTWnymF~}ogDxA# zKx%2p3|+Q63T4?yf4b2=#uzZ1eY7B!q8tX^I(P@76 zG@6gj;&T0QA;!24Q*f_KCZN>`>K+gz0ivqz z34^F=;t&W`9Gqc!dP1RaI0AyuKzMw`VQINE{7=$`H2mI$z4J|)z>qf5*FeIIQAiDh zCfo=Pg`yCe28K|$5zN3y1BKFuewSSm`X^ayKQbfd;e3|(ER1|XUIT7`gz4)WqM&~- zzl_A6x-ljDGZt6Sl10Z@dS5e|9dXYeTfZOhA%D$GzBoUB;=;z&mi@kSnW>DKsTN|s zCIB=JzmU^(@C&P%NWg&q(E4Lo%*bzHkoh{tNiw3)u*&iH2x=&m;dk_G)2RE1e*a9SW8_mDqdX=0`RjQ4(I_CCudfdok6Xx^;C)oWxB8A*ntGeMAGYB)b;7?=F)j{lN$7IQ zw11~)TPi61?EC%y#ik`e{OOipMl&4=b^Nh1(-81=w%%}X?Y9A^Bkv~BTcB^`fT z69bT$5f%wWA(5&uHAc<6tltuyg)1*KqvmDQU|+MQ4kPAIZ9n@vFVwC+d%xDE8ZZb1 z1z}w4GhW|9mmdB()aCC(mmdB(^hcxvl}y)xee3O~<|R=Jmxqf`?HIR2hzqCobJNe> z+sJ`LA7?`{GUziowRk3MHlw8y6D=D+U`EE0mZ%Y+OtftQc%utWaY5uyHX_uwt-ru|kRI!^Xu# z!HU7g#R?^+4;vQ~1uF&{7b}#QK5Se}6s#C*T&z%H`mk{^QLtjLaj`;)>BGjwM8S%| z#>EOHrVkqz69p><8y72-m_BS=OcbmbY+S5RV*0RgF;TE$uyL_MiRr_}#YDl1!N$c3 zC8iG>7ZU|51{)VEl$btjTucGUzit)F&_aHMRr?~)AdpVY1@nJk8=NI2DPE);xh>d12?K`1Ues{O)lsTQFJ z77tsU>p>4}IcMY0JyyL(E~n=b8ldhcA}G58KG+a5>tJ`>Sgh7P^FZsD)(#i% z1Lo3OR&)njB>^9fUVm8J=WXuIe}#}y*?T%tLWHAJ7gK&7dOgM+!rN21cMD^<@WH9O zvsD6(8|B^i8fTTu2TWdF`6O1E9S@~rgR&xdn{#-P?dMpa!I`}bOJ(BtFdbHBQM zPxV_p^;PQ)!z{=0kI~e0`o=D`#xyEaBK#U{LWXWRtaf`?gb5lR6e!QoI*n_t{B5`8 zvEr1PI`Om(v2*)pcFRZItt{=~tl%7|5&6|v=JV&zUM_nf(#P%OYMZ;Y)W){cYqhkS zpG9juqKv-jdJ+P8wT)00NPieAbAM#J773py{{;&uZr%U##Hx-sB_EgG(cQEIB>{Vq zk|l-T5;z>&Lh7c!oD1nUA!}+sd?8@m^!C`PiD_`cz~?u1cg(+FVcvxo;Zz93s&5d3mYO2OtzI0BX0~V zN?jAyOi)nq7FmTcJU;XA+!|o2>$ZytrO7(uAVfV*?gGdsoP*OqnWI)%cvb({tX+jH z$F1C8+EZGb>p;+(UxJiAZxSne$}vSILeeabtAyxF0R6A>!O4(~azi;{lO<#~2sBAz z;^WbJ;AHCCcM3`&9X?r)=OD$g2ggFIXtX=mH=D$UOISR&Hw-(u)%O+uN3^KY29>GY zq23mU(x+Y0vD5SCt@+EJoDk5I6p&fDIYvYxRKE3<(By8aw#J7G+D+s919V5%JQWhG z^L(Z|kVJFStj5>9k^WWth8s+H%v_^XK>{iRk?^Ou%QDRy^~(C1(;%9H=-OA2jYGQhFBzQjiWe>InzSB>tc$Yt{$(1`Mu-3MtdoQkgil$@Hr8cux8Va4JhrZA zIxat-^)ha%b}}HgTYhy`;+BZ+ov_iBVWsu=GD6(OK69J;=(Sj7$G?Wg|MGhNSWd`? zLnfwrnKg!7^0JsNNA(stb*`Hx<^3+9nbYO-oF$l|7G1k6uKifoVsYIa6-D5_(Ud&f zL(R74GY=GK(z~}?WgB|mt(J-e^!WJsq4-9D7gJ|kNA8S-ojm=7cURkt@qgI7UWuF-<)?i-Qn}&TolNZqXNC@Ty3V%+ZQtjs65JL%RWRG!%Cnu{ zCwXsUr=y3n=BmHP;~C?>X~&o%l6Q z*0M6oWB>q=wY4F;f}bjax3nbq_gRR^DEKii$i|BY0P~duZwVkH3-pk2W?5LQS>wmy zb9jE7Ac(Dn1tf^e@nr=t03h^fwj0ykt#^sZNXL7UeO%;0dyea3X^1Onf8?TM9X-u? z@^*2Wxlb0m)F@b5&QZO2G;VfcVr0T%7ySkMWFAX(Y33zHAB)>}d+ho4WBv~-M_%2X zxbTSBb80BNv`MO3dO@mzJC zUInd|x&laq-k&cGR6Ax?Bh_Lj7rr5-Z;*)GBT>yyHnNwFTm+bfCz4J8W>ylB*@t!9 zfTME&?*^LBOJEHQ@LsX&)qNl`do+E!1hD>~=3PGqb=K$#i0MaEcW+gCZJK%j&ODh!ElMXDhdgp2Uc2$Xd zj~+-W{hV>RHr_I7y)hFF{@83{ry+1=3sGWwGOS=DZT9c>E95Es>K7vb@UDVW^NX(Z z>`1@p=S?A#gQnxwN0$SUzP1Op0>CD+Hr)MoscF450FaMH>76lGeP5%ZUoELtGq%H>SZj$cayJyt(yb-^csbi{L{Pv~<$-%FAT#_>hTKJJF zol~P*88vT?`Aumhs^-%;37>rwtwd?%^q5i28k;$a`?Vpr;ug6;?UM~{P_FyjAs#mB z?@YL}@Ua`LE+?+FNOjIv91%#pIU-7c9yPaLe{s<;}lG=c6)`mK@Ez$34Hy zBmtY-bFav6;nO6dMLn|mwThI%^#CNiu9kGxNPk`mt>G;6)PkbAWoOo&nq3h;OlvwD zGDk7WvU(nNP6!D?)iAfAI8dA(+Y~_5v@r@#=i%nf-s5s@1vI6={=Cj*g%8(Ne9)*^ zijBV3L&YQ|g#7k6i|aUT#dr(!it?Xk*`EE`y+yIbs)g;U)vJFp6JxVXE9KTxy8k&T z{6T%ls+%!g*bB|*guI&Z6 z?h1xU>qy19Wv-`PVhfZo+cNNXqnFs)A1}^3bbpzjvfl{n^lScQh4w=lPHFc%TN-+; zU#GpE{XS%Y?B2!E^>IwyrI{*HD$J!JDyI)SoLG8)|I&JQBo5VgxF>yKI>&>eSEjdP zaq?}MLw1LB4yo!P+)oysDC{Vl?=j@j;GT4HliSV`D-Q#=mnY}_l3L_Zn7yXYP1TKg za&v&GLYN6&74Sy=~}Pg`0Vs;}uUTeNpul;L%qvv;5D z2-d4OJg#1`-=y$lF5bex&cL(Ob?Bh4snpBETSv3_PV;(n^V5bR_H`^8T=`<9>IsZP zIf}8tzc4i|l~QC=UFbUfvVyWp z4BK;E>rQwLlvT20*5SR5Q#{sfEVU}mE?)kyqPQYoA-~)y#i=OgA+z?(+p=3_Coe8N z)BRYowWKVtY$uiJqs+W`qoj5qr7C6T<()r{n@GvVK9MU@U#A|yJI`H2SWD>0Xv`Wg z-Ff4EYA=FGX_9YxZ1A#7sbS@HR<>K_eQTyNvz!+_6t_R#es=>rjR?vxy$S#k2GN(Who_Dn*~l8j(TAligb zg^E6q{L@xap{8R>8S@SEm2YsvDMrk>i5u+w7ZDnVq;C0_{&Z@t7fhy%bmF!9I^9Ql zQsVPDI<*CV&UkBB ztIW&Ab64$MD|yQJ(!Mgizz5Dn{hnzh5mh?jj{Z@bYHshYxgg=+H{V01J7#BJ+oS%C z&J=`K=LPD=z1gb7#qs+}7PTs;E#CE5w=J|=HI{SxYI@tj^Cye0m(!bkTYP(8b-;4g z%cT~ky-Jf~%RYH}Ubb`X`TpVGEn5+3cXeAUqRTAGk6kssRLRJ{)p&Qcsr%3F@7+JT zV+UH=FHj$ivYQ7~w^#m-`Sn5T`pS`U;;k#K9ugjo4}2dm#%#w*M@&oN3wuXX#{xGN zI|Xj-ub+xe&-3zTCa#&aI z$h^)G4Ozm|;Dqg`o=e^TAy}QMj@UxVc$Z<7>6S6J-e>(~=R3sahi^K=kA=%s5Th9QcO+#&{y-zH@y=Rz*fh`3C>;f$*ve+kHoRRdaBS?eD9? z-Y%JZ_#g*w(q1(b&KbEeGTgbOJ%YPpys@F;Nyv(U;!5Yr&F{_n&7WAb$38G!KhgGh zux;0t>X4&D&282rk}=Uu6UoC#3oYg*r6)D)mEGHyV?@N`Uzl>odq3q{G|`)Ma+D|X zCK^hVmmnfWAM`zHY(CtaoAxd(jS$vLwR4}GE;z*+&oT#n^V;ZqzP2sBP0oJ!~T zFyNtqL0};Y0LG@FK~$PQgAegxFj;I9=wQWFD1=2ffqEJ`A{~P)7=A39a4y3w+{v95 z?oY$hp{7I`<4^)95Xj(DA)$c*Y#t%h1o~N*0NR3P1Qhbwh3{_yH5YUUp*XIASa7%u zh#}k%Mnj@e5F8$kGQ{9fD18VTi84T-kO(v$hC&fAI06a_`SOAiWkAcAOZO$XlC8dU z2mWUQ_2ct{2na+-NC-T{0M6ku5hy$!k3gakXfzD;fbqiEd}=6+&C{9^`Km)^@Mv6C z5TC_iLj<~1AI>(u2^1>mNcj44UV%Zvj@Y~}>_Cc$P-+kY1xF%g3Zm15F+tn70iTCP zry&>tj6epP&jaI7Gsb~P9UXp){>4B9NB%O55z6|DFu{?ju+M91 zYO0Mv>I4fegUaV{-8q~9;?#2eb|D5{hv|B<*mO<^Z>2Hfd+%>+=9>_MOyx6(;F`w3 zkSG`$?T*3|&=`UtY84ViKq9A!OnH8%;Rx;@I+ahIrhA0UF8qH-|KMb zEZ;DZRK9sm)1cD`z8r2Kl}}^^Qke`y5SwX?_|`bh^Yg+b*s^(iDx1czB@@90IEzIm z_+Wi7NVFjxo_`bJSPaX`z3Tb>_0boJS3q<|7!nKptm6 z!lKR1$#~S?%g-S3r*3RmJaBP^OARDzh#34lPQ333{dCRoi3x-sGpt>18PLW)o%4{NI{18iyUs;Qlk24$P-iusmgOc|>0>ClEpn3JPG+sDiAC2xim2)OW(t z1j6S)rhWHK5t^p)Ke#~Y3@+=RNh;GuDZ~W%e|FCQb{Z9}{Fs_n@uq}KeIx#{Ciz-M z{ket_)VpBWMxI)jR)Xy$_(J{1B@0+}fY%I!X~4ghi=rmc@52AE4Zo<<|CNeyYGBhs zXHw?;J4NGE4>L%7>**`;X<(<7D8|C%M6lolaJY^fI)ez-12Z*G)BJWA{9S3y)Xz#p zo~tzpVryxEMd7hn7#a@N%rp8;(-B;G5x|-ktie8KO(Gccr?&6?DT3NHVB6=~6o*D4 z@ksDmAAEfYoqqWHP_MraoqqWH&~K3*Y!;u0{?glb&C{X;mxohO-N0KS48f^=-}Jrr z8dfMHfI?=0*Csqc<&DOCiTVD(jDcQ%6*%p{m%yp5Iqk;9=Or=K3f>k0@5ms8w`8WR z7Gb6TpEtgp(SKfBs3`74h(Z)Yj7tS26eZ;tgC`2*DxJ02O^bz9{q7cOp;}V6E z&_|3*h(Z)Yj7t&L4=q09fBc5G)tTfaE9Xi<-_}5uDeWvEYu3I_ zLDi`+e+x{mR~SLprf_uh4?|GKw-QkM>6%tLtBU1T+eNMltXbmb$Fa}t)OcurxPkuB zp3T0JGBn;;UVgO`-}N?h4TT~Ncqc@mBmoHYXV;U8&^N$6E3zS(UehV9&^!oeNQ~N^ zeq{YtB2GGvr#9H2zwP=vD47d(9Xld;}@T^+7b{oIpxZ*p%d48hP+nj=oCuu zm0U(zT3QyDK55H0)ZPPZtPE9%iHY$}&{UJ#Wlc6A?}?UL7;d7`MECOYn)QRZ?jk)E z4UOO{J3h3ekL9h`NjWJ6to8J)>3j1A(tw60-&|ZrLC_Wy7Z=mg;2W29mh+gBt<~O0 zdK>#Vku60VaJ8l>MT1O$b zs%pISmSL80SW5#wR@)YLzn6cKOjgfWhdJbDbKLb)O|+DprHg)dcXuwYr_nLMvzm@x zt}YkbG&thPEPW!kk_lBa3i94$zi$0{+Q>jVPij`wJ~GsWOr}sMXSOyrcXV6{RH$et zPQH0iw59RG*7&$A@}AqbZ>siYE9baC-v17FJd3jJBTSY7utEQ-szLbW{ynBn;l;brvHs*}1TeE4?m3t2# z{+?G>hE+?d@6OHDEGXPE8uW93NzDw2|t_Z~bLwl6v3_4KJZME;Dtf}A?xeO_tl z5bj5_(~p=X8!NC!e>^aGt-T_o2@ZpK#Yt!JP6G zuXj1v4$c>1i@$$uJlUr{dv!>o-GTR~b1!W(Qd9tktGn#SC0#Ex2e{>l=sLaPwSBF% zu?tsO9YdjUxQqT_VPTKDy6A_RdJKBHyO-ymIB}(=Z+O**4U!)%vvfd8GXVGvL^km@2*2}uao6pTaJ!D;B}NsM3N zoMSXQD$-yinxmu;>gJ|oXJ>byu&^%f_2{Qhl^z}s6582GJM=zWzkdA@p0N=Iheu@C z9j{hZRn5KMd-PG?k)lGG#t#aXE~k=h==B{{+m*Kw+Ux4$l;ZaoqtUK|BV&Es>`wHu zAFIfF_ypO@5#xk?`}S3<%`~7b9`3BXd|76tM$%+$d=~HKIpcc#)nupqt4+S8*`&C&Q0}b9 zusxCTK2dR%q_`vCq+SK*77F#-ur4apIPt0^5WvH~?e?vd5=td1 zA&RmTLQ*e^MA`l`sY$)w_cy=gzg^eNb&a{5=f1z^JfCyUJ@@m>bv*~|Y)r*P=3HQXI)nj(xKFqpv<0Sw@AQu%tT32!kAq4u?y}u2xqPS!fZZbgo&( z{*Dw5C!p})Y!rWVbodb&dyNH$L|+JXE1i$tdm-x3qw&s=3p<-iN8i*;U3-q{%^6N9 ztP?61UU13`VXqawAk%2MRL9<`iptJz&GiwYD`~(&;Xfb9=dR04s0iGZ}pkc-~OwRsDB)mfwxujm!8 zMBySf34?uwTwFAltJRt>Su3rLpNCIcuX#5pQ4St~lZddyh4SI+1jD_j&aWB}@Z2hP)_?S{#}&!- z*MPHqEiS_}HXGczW5vzQJ>A_eEGmpP;UBr|nj+ubR_-$C^(9PiVsxbA*6WoK@GTLh z0%IL_AAhpCw5;y9$UgVBH!-FY*TtqM6rUuiG`o`7!NUK*0_SUq~!CV+(=*v!&`nS4R2kQ2-b!q276>Cd?o1xwo^9IX!4F zX?k`Q5bj}q+!p}08n4uJdQ@moB@6(@XCu@L3>7}zS*lSkxa`jSwmV`I+qL%@t*p3f zw9rVD7{1JJ`2uLM1elD1d2jMXxOIUI5VIh!dC>HEz?9oTGg zGj`nr0KR8pf2k?#M8p+){bviVVT&_#;EQ&n7?dyDG1LMEhLtlWb4P zmKY4S3R?blsSu*V3#wUp&*-wQhDaQt`m%D)g6vB9f(<$RB?m_cb(fg}iz0C4BH98> zBM^SMp_!|dtIZ3u4A8QbNU0VP9TEP0_IFj4<1#F-uD&VtrDCZ&9CpCfOhctCk;n16kw@s*}OR zFt^Erf^PS$?%855+Mm6=t*f*WBu0=c4AfBCDW1LGKSHZw_2ru8&;a$4gh|Dc!}?j7 z=TKOL1;VA!VfciHflyb1@7QUEjYzLrdi-$Mp;yv_YhJHWNJCl`!$_NVW}S*Z<(h4l zZJ%xWzDzr>KRqR_3|Hbd9wA{^WudxR)s!4lJ3pn@vDxuux@fwrwLW?zPcv)hC53Y( z#?0G3=>rL=x3-3-T2a$q1(o%FUA7A{=``v6HGRZ%fvaHQf|Y`;3u>3@-PiJ^>M261 zT0h!jx7=Hgy@WrBkMGs!HUEY=6l^0eEu2x!YY5mT6Aj!eH zIBiYZI;(Y7RW*-m&et?0Y9;H#p2K^Sdy}6hw_o4BF>s?sQAW`XlKGYHjcINJMWsHG z8&PhTT%9*=DKyDV$z9b{l3S84m0oNUXOo@UM7~$>vFKq@=5@J(o)?0xc}3nuyYOW9 zCFJY(^X?7AmBsD4x$EepzL5BVW{GUYjf!FPtA5hx4d_=%wWkLRcHRGUst-bTty@_4 z0?}2pxOzfi1`f2Hd5k=>Ce;l=e{$~uw!^-s-azckN$Ae@oG@FgZ3OvRuL^_!iFL_+ zUU2;qGiww-xCHYV<9DVD)1{~L3jWG%+hd*b>kqD1+uoz5Zi{Tk?pB#5P6tod1L@(b z_{jVRBMc)p%^M#J4pq7xZGdhieZJD%Z+PTvv7wA%%%0pmJ$G`IJRkgVELUl?H=#DR zmLd^p7xuR4i4gt`{_wr91*(w;B3NdOuTx%&b%iWRfIQej z3p!VO_furLY^LTS4fLt?R#7&(Cq5W1RL_t-vTA5Cb5*ox&|Ss5WMxRbc74}K`l zHbZ9W*1^aBh%MC$T6rIFNu#HDpK9i@QY&$*m&xc<*`xrFH(VcG2HSf)_L#3xmXdW` z5&0eYjYmLr4k_}=)P0}B*CESK3O(Fecr0hW8(6f+DDAD&Mz!baLRZKn7mwRD2OptM zWv8yK>3>}KsP&l6>A^G8{fq7{>O5X_X}_flSkd)OS zkvVuMPr7wUyv*(wYHfi%3J0i#xSE+=QB17!Xz=KJ^9r20N#ayi{F`_QAMxgv ztK#h&uJ(_7#AM`P2_6 zgp__p{?XXFsdRJ_^YB)yGoQ0{qemlY+K^9Y#q*NhZmTN#mQ`H{G;-jHz#W_bPb8v~`8#X{4T8kj1dmLrP2Eo~Lo- zp}Hd}CsTHXX?|(j-g>?$q?b_JzC)5acyl46vjI1KxOZLYy4uY{HyA@#T6-3|+;B}b!uOJDhv83JKfZniqd~sHXKYH zy+1nAF8eafPj#}kx}=$@I*?mxTe|Jj`hLS^?8^g<2AihZUJSPF-cimxJ6zvpIw}~s zw{9wSBt{ZDKPEAzdcXMo_o=!V6za8s-(=rJI<}5jw>ovn)cL9Eyd|=bu(8JX&ui-w z>d(aw#mC+D4!tz_uKc}Rerx63%H_8n1|ncvKW!NAzr$=}Dh^&~m$dB;1?^Uw_WW{r z#PLb`c${2Z+_V6H!tewE0d55VLkWtLE5p^=3QeGTYvPGicamnHH;q+@0)U=DAPrC0 zNn(K9No0zTzVcwnZDkOJsITmzWev5aVM(48vtU1xW3Y`AA$TVNMN~Gxi0TERSpwc9 z1|AgX?d3y92kI+-(?zpvb~8j7^v#8_Q(xJT-66=;+75)J`jJ3dnp$826b=LFpfq7x zNE8gF0fIwe2nY-cfuq1M7#gXAhG~PozmzeeEKARi=z(@HHu>Hi>py*EPX>dAhCrB1 zrX~}iN%bQ`U?>y{0)<21a4^dQOb_y5-~+)vbd?#AA3DY)I>C=ZV^F9*Ahs^vo$Alf zS5{_s#Cd%`FK-&BBOm&Ab}WjJKs*fs(}Y6i3L+9XF*JWauWv&m5+Ecmk~hhRL1)Fm z=8R(@wYKJj&e@%}_neV*1}=bg2H%Oy8A*2vqLCmDBs$gKk3hl&utuUX*Wl?42hvZt zTu8Cp=Ma>hdaSgXgCtB z1zQV+p`p-OA~T-9X;`!N4-wD6&r*Sdp-3kf5{=MBYw65Z`Nj8l9V(IH5yX|sPtREz zL;~7_>gSDTU?|>rG6_QSA?rbYHqP?=ws6trK6D1&hd?qn#;_VRDHI|a<>9Ucg=!(e zcpY6B7)C_uf>9(C39O|}BBBVoBzGNx_BR~X*0aO^ByCJ3__O!UcWEL^8fU1Z4L3n) z>mYRzI0OuaLh2eB!w@*Q5l#n%GKBq*ofY~gSzA8}E9c?8X8Ev3&X(6f7-_=|4UJK- zzn7mw;!oX}QRuA26*Oznv6kMqjOIx4{k8SS0WZq8%tXWc(Mjx$tFQcH=WIT(tyGybqZ~#6W(W)sKe% zPcx=NBI4n2BoqwCBVk|!3CYTN1Z@P^T?gTgXVoRFOo#t*e*f&O&6)lG6SMZqHyby5 z=Kt2D5vV=^B)@+q)3Nd?o>iWb{OA}DKdLtfPosHJ2zYkZgar5yzt?x1(gehyf@Xd9 z%@CTU@jtjgi6lSDKa*5ujgo^2^#AOf|Lru&UHLIHt-MVMn)ycjwI=ydM*X>lVb{B? zvdwsAVVbbF6Z;GGAD1kws)KdSfSv{XN4dyt68$awmu>i6o%pX*j57n96*`wP_1`HP zXL^`J;%84kh|dB$t3=V`BqubM>P7XlrV>dQRy{CR^DNDuhgrWX+0Fc{grPf_8iCAl zSZx?eTN@15WYx@b`pwc|UwNTfH7~0M`<68^te8Kw{qFC|u3f$SztyHXa3~Z7WnJsD zUf)A!AO1bm?e9ZpAO1b`XQZ$V8%jtqozOJ>$;;Z*wn zdE@69{pYngio8xZD7Z0rxVWLj@!{d(py0;f;o^o8$A^cDgMu4_hl?9Z93LJo4hn7z z9xiSuaeR2VI4HO=c(}Ns#PQ+b;-KKh;Njwi632&!i-Uq2gNKV7N*o^^E)EKA3?43S zC~9xe_FZVVnSZYXhl zc(^zyxG{LRxS_=H;o;(-;KtzL;)W8(hlh)Uf*XT}iyKNDA093a3T_M@E^a7se0aDx zD7Z0rxVWLj@!{d(py0;f;o^o8$A^cDgMu4_hl?9Z93LJo4hn9Jzr`i`^C1T$AJ&r% zn5;(_Xi^n0tj8aK2xbn}01&(i0K)eIz?W&(XCDCgLjmC3b^t&p0KgLJ@oo1_0AN1Y z+}O}5u;s|9-CoZ|8hABl7N( z3&-9Pl$bX-{rb@q{uV*mNd2TyQc}`~;4(*=ROhu-$wq=j$`g;e`GJ}}y0m#4hCv`p zev5ll+uOstjrth!6fduf1qC0_p?#G#NtbY|gtja`Ul^dhOR{eJ*zz-$plJG5nIdJXN^LVe8^G18+13PV^uR9IrFOsDA5R@eQ z8kN3Qt~O&vJD!W~IU@sE9)@i4RgQbuEl>mr$u#cB5S^INj2=ui9q%s}+MiH34Hx@7 zQuyKanu*qdGy)QPlW!zt0R)-C0kT;LH~H=^g}4#eyelibJCq{U8}HkviO=0xC8^2aq~9esn8`c%N07e zUf3S)VEIR9Gs9*4U|D1Jp;ciw+i#sI5;LE$4ZSDW8-DJwVw2K)8CS*g!yX@=2?U3p z2oa0)+7*@mZm_#elDvq2tR`sr2i=4fAPH#xv5Fy3${CYPrT0y1?NrMjHGg`QgTz>V zuEH@yJQ;h+8|0b;!v?#rJBbt^%hyk}#(31P4bRGRAX~XckZ{IS|IAneCcCs=y+&L z(d2Ocy_Nu`qe3!htVe54 zWk-&YH>@|UYN@ZQ)M?mxoBp$azWIdCK26Rbu0JcR#p94+4 zcH%>~=0}@k7DL_Ao)S*TMfzVl-R7U#@}hCsME`jHJ*vm#nhDjeXG{4AJ^H)6&uS?@ z@|m9$LRa+d)DUdEv*N3(l=L&ZU|q{7?e+c9V%Ma zpqwYIp13KZi&7c_x%@|=nq)?}?yHIBj&u7nV~d%CTjxapS%_6`^TkumzrIoRpmWaeUH|*0^~e zY=2XSBh$4pJ>`ML1x+u-9+UYpU!6U#Kf?PCl=-WySYW+-s2dz>_Te@k5Zw6g?VX!D REZGm4F~`{$=NWC^^ItUJ)cF7a literal 0 HcmV?d00001 diff --git a/dist/UI_icons/deleteIcon.png b/dist/UI_icons/deleteIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..540256479106ed2f9263ec5df22fd7f0c75231e4 GIT binary patch literal 20981 zcmeI42{=^k`^S%xJ!!EeHH45ci?Pf!#xmBBFtW6cF~)=$W+tSvl(mIdWR0}gvXqDy zDN-u3Raz`bNC<^e+5RInd3(L@Z+^>vyRMn*8gqNjeSe?l`JCsu=RRky>qKndX1rWr ztpET3%S}xTteKw@b8kK#=HFL7+Mk&p{GKKbbN~=sJ@@7UlFl+c1T4u|?Dp-hR0fsq zO7#SpVzD4k8r6mDP6Pno))X5O&Zb{Xd*bD|zFBx+tQpl>ln-RBezsS~b zne#71t*TZU8gfhBPYYif85wv|)JjF@xWIGX9+?Y~$1a8+ubu2VbkXhUjfpq)GuNMC z`f|ro3LAMV`Gn$3)U4D4g|hY6uY7gv-kqAR9#!2S0Xa`Vgs;$9hCaQK3;67hMsJp_ z*a8C+^}34Cbn2L~EJx1+D>f{UY@<09_-lz?1|98z7Av z*jGnz>ISxhfqk0--aG~ZQ$8mi;sSQY%7}8MMFXJK#Bc+^bqkQ&xZ}7XU=Ib>xR~8R z0?)w!)YQ(!1h`rPR5pkRUIX}q0H{@Xh!Vhk2-tUj<3?W~I1yN5G-`+busL6(Pnk(7 z@fx~R4rv&)lMn30YiFmrUa`SceDfL&{1SYUuIlZBiIVUj#EMsA4*?)8T9i54v1#81 z;rxaMjmTo*z2JdcJhQS+PTe!TjX9pW0MNzoZ=O+s6s`^2!V~B*b3uNX+jWm%+JT7^ zF4tD*UI)_pTkXa?=hzsY|E=`Ji{74|=UeaS@5I;I9ho8B-dkxm?f%6dJvH(1)y>y( zLGax{#@wG@-F`T3p1!W}G=H#D`QlL4A-G(aMo_Z(obfaMC=)ruO|Rtw47S?M3HZ4pzE=& zMxWUcooVAVc_7fm^t2ZM>@kp2#nl$-+~WfPgR~&!t9nx7RT3(dJnO2KwO0vF?b8U> zm%DRYUqoNPIdC0qpHl8oeZ|oFtJ2E*AWw9q5tUZ1p)sDqs<&-_7uNP%@fFXPTBUd+ zh@V^UKHqA*Olvro({cNak$mEbA)jTcOt@E_kOMskUt=X}7Oidqvp$Xk*_ud?YSWe= z!*&^!MQ^zez>iLa-Y|y623@n#ej;=oTbiZ0HrVKbV3RWgmJ}tHmfS=uTC06h<9uIJ zj_ZonC=B)e+;3nKsHw>r)KTd9l1-(BR&!u3w*d&1sPWI zYjFGMgYfJ1Ozh3=w>>w>0{cVY9!6n?IRga7wQLH!it7Io5OxA9UdC=c-m*e8& z>~lU+lGE*`t49guRgM{_&ZQZnMlQAi(VOdI_%?q23Oo2=>3vJZLeAUZt z=~Cy*4Sa425TpO)v9XRgdF-4?SgC-o_*`s#<`2gTVXl2?15^R(p`dlVnR zlbpm!C3o|yhhr*Yj+7laHLcCNJnV&Vjy2DJnAGO6M0u+EXY<8l2El6|8{ z<8!s{;?;FZcgQI=$&Zam;-pggv9a(I5oSm0RO2zK$x<~P_bYm~GCq3k?(%!|F(tV$ z`Sws&+m&IBVe)WT`?-gRb4sZWYV@Y+``A}jz0Ep;=gvUgI&=Lkv6exk>wOy`1W2@9 z-m|ME={}by@FU`wPZ-*{ZcH~?^CkSH!`_FQl_mE}>MX0Nse3~@u>l)rooD@Kn}N(g zc`nk@h#UewXNqrFvmGOqXE{gx*)(U;H= z-9Q!&+3x@LX%jF04gN&6ztEd6bQKnO)>f-RQ#XiN})ZJ_yQdK!$gW`U(b82WT>~+d(!R|xi36T4{ zJrAC5xIG?{DVD9eN(B|CYaYH$EB3vfh;o+LN%_&$KJt+Q2X9N?CdopYHJZbpV|OX9 z-!^KZY~gqMUGxq0gK~G((p7p(gEwXWcEfzRc}FrTRV>LH!4a{vnz>u0>hIVwI==DkKD+PU1SkElh) z<)m(|A9`3=+xDC0*^zUzL#uAD>N;JV9%^O>mbQOWk-Hyx4efQXO`uzJ+2+t4Jh|xK zj~6R@v{>d0*~RDkS19;dxCQO0sy$kDoy%=d&{m)~-evsDN-2G zh~xQd+Qj2U1D-3k`}RtOQEP7{w#OD_=iDiEZghF%(*NcqICZCR+~xQ;@xqklFItP1 zckU<}`uNGP4H93k*j9e57+ZSr7W(%a#LNc`^;>jsmvG~_uQ-k2M;+Jk&puO{houhP z_=I@Z(zf%)#5Cr?%{E&uTZlZ}c=c*wa73-#M{Y8bN>qJNSO$u>yhE?iM}m2wlwS-{hcv-t*v*p-S2iu zS5SLB1{eeAnV83x_sY+fC*_y!aw{G7tGIs1WujjyRkNXEyyD;ovDv3BsYvaPiZMUx z#NCOHonjsSv`y0ub>%O7HVx<9u)MK%Tz5$C1-2usMQ7(s`}2|Zfc=#|X=Bap#uGdt z#~Np%KSr&-$jS8vaGZ$v+^2Nm<{-0Y0pEWcm zG@p+jjgPtIaX5W?pmI?1N?XnCn)Npy_^QG7jPIBns`6>~ksi6&xx%vNFepHA*7Zxl zN1LY1$r#C)m|5viByHD zBakqd3J4B`sX<^+2pkE9!B7ZI6ifs3{UwVLU|MLJvkS`F!03B-%>T4yT^S5d6a?bq zxlLGJ}(bXR!0>2cXmvQ5MR6}1f~jwEEeQUV8wVIpt*k=nlk}HbSHWcDGWL@ z4z_3<6RCv-D|FHBJUkYSq%#b?nKSrKWYI`E?w}_TVojt|56}oiLvQ9tHZC@JI>Vay z6D}K4O!q~FJbzruEIuyQ;lISlAiMm6uVQEA> zgG$3usqUEh<@)nNjCmcVXh)_vQ+?=4XvnYLKiAApA)*1ELBufEGy)8Tf#Gl*42gmx zQ0lPFP#6jdT_7^=`HO}HbN@Kw8TbV%a4-~sgCS4|W;|k{${&1x)uB3*T@JFP^3!vH zhBE=>LZx}&85pt$oPqLOYGBfAl-52=GjeJgCQ%zq3uBT^! zg#EqzA`*Y<#)M2~F0O+M79DfxeamPzM6W-#{y5-H{+5|M@iaPdZsTgp{@A&!RL06w zb1~l%018i-%V`+G+-fE|qalB2{W&aFS;jr;0Qw) zbIZ&vZao7%BSRxY4MQw*%NRn{ew^BW0l(T@HiBuPpqfAO$o~%hpR1POil>l>&KSs# zS^a4E|8&Nn8hA~07pNLo3#y3+6V(tdU?-%y3z*p;Tz<^&pFL}fX8-@h zS^L8`8#{aE|JF$(P$}L-+CP)&nE4dXEKi9vI>v=Y^#I{LJ>AI!{9M+AcvGCe*LSSa z1jL|%7JT>36I!70Ke#}hi8S&*lT;Rrl7$KM|7_0xb{b``{FpzjoJ|Ru|3>^{P4c5U z`*RI5SMM^*HiP+vX*9Q;=Dtw>amm80I+)iCs0F}(l#A>p(O<&0 z!l6(klzFYse0>jHc=*>)hrbV9c=*@QpOLl{G6Mtu-rFzD3!>&O59guUFmH(v=ce{+ z)34s!$-YE)djm4_+Jrt=dBYLkV}3obXrRMi1ui)7J#c<&F1T^=ZAr|xGH;78@5n${ zw`3Nq7FMPIpErKa=s&N`Qsi{PLcxx~!Nm?GmJbIP3k5p{2Nye(SUwzFEEMb*99-;B zV)<}zu~4vMaB#6hiRHt=#X`Z3!NJ82C6*5d7YhYD1_u{Alvq9-Tr3pq7#v*eP-6LT zaIsLZV{mY>Ly6_X!No$sj={mj4keZk2Nw$kI|c_AJCs;H99%3E>=+ze>`-F)aB#6u zuw!s=u|tXF!@@@7dw<#J{(*u6zmurT;dp z_4MAmMgYLWV``v>^KFfdJG4EvPqZdrN9d^|XUA?{&dTCTuIC91Pm5imt7O=GfAg4Oq4X)^ z4iZvU5P-hjq*CwN0J~dGMf)Qfl9< zA0doAN%C3x<<_m+OZj7_u7saTmUG*=p?fyzQi+meI<0VtI@WIW*xJmDjHbb-d4#=m ztFuQP^D1jMyY4e43hox~qs=^Vn)#4%qAOJ*uIJ%Qbl*#pi)AV)y3f|#DYI;dq$n6E z^q0n+BziOmJi#F_MH;T*e6nk{O61-vF1}hQtM9KeQXZ_oWG%%nwb@<>Xuuo7YZ9f_mvK$X%`+O&4`)8zB_ z7tTHD<#JMya5V!!GtnT))IkXz#p}C)75IITG*s=rjfj zEPXmO)}=IVV>@u^(b6#n+1Q-v$FR) z%3uh0zZX%D44!OwZ)5YOXNq4lgUjq`arDlnm3K4q*BhB{pNN-~IDN@HC|JJAVYl`B zK0p5n6~>dYtUSg=gs;FffZO0>9Z-8JNg<&4n!lL0|9%mhV+s#I+~FU3wN(X*fXB5Y zSwsce0DJOFr&f9;RM&uiE00J}Rn$=7>6c%vgj4p2hjI;0e7V2nRp!^6(OgL-X zmS5N}{_KL-CF(o9amCiNpy_Olr|~MLsCnbb0xVp_zdh@Z%MMZ1Es;lUl zdtZdX>zbEXzT5w*9}Aw+>B@W9Q^WfrI74?_kYqg?poT&n|Ky9dk2AD+ZF4Gzry}jt zuCG+N)oy7$^YiPbhbWMP0DXiAKoS{3-=x;N(y3E@Z2ujj4E8+-eO1n-ECmkC@ISP`%{b}x($iHeN8 zP+M15@WS0S&uXiT?7O#q9xKnk7jzv2g)R$?G%te7+CXZ?V+Ze#u09}?UaMo$(V=Ez zueDA=Lg+%|dhO%YUEw#CT~bvY-BQc##G>$1fV|Xp<<$>E64u`Ss#ZkdnqKL+ZPv@~ literal 0 HcmV?d00001 diff --git a/dist/vis.js b/dist/vis.js index 5c4efb78..5dc6d8e6 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -8956,8 +8956,8 @@ Node.prototype.setProperties = function(properties, constants) { } } - this.xFixed = this.xFixed || (properties.x !== undefined); - this.yFixed = this.yFixed || (properties.y !== undefined); + this.xFixed = this.xFixed || (properties.x !== undefined && properties.fixed); + this.yFixed = this.yFixed || (properties.y !== undefined && properties.fixed); this.radiusFixed = this.radiusFixed || (properties.radius !== undefined); if (this.shape == 'image') { @@ -10604,6 +10604,134 @@ Images.prototype.load = function(url) { return img; }; +/** + * Created by Alex on 2/4/14. + */ + +var manipulationMixin = { + + _createManipulatorBar : function() { + while (this.manipulationDiv.hasChildNodes()) { + this.manipulationDiv.removeChild(this.manipulationDiv.firstChild); + } + // add the icons to the manipulator div + this.manipulationDiv.innerHTML = "" + + "Add Node" + + "

    " + + "Connect Node" + + "
    " + + "Delete selected"; + + // bind the icons + var addButton = document.getElementById("manipulate-addNode"); + addButton.onclick = this._createAddToolbar.bind(this); + var connectButton = document.getElementById("manipulate-connectNode"); + connectButton.onclick = this._createConnectToolbar.bind(this); + var deleteButton = document.getElementById("manipulate-delete"); + deleteButton.onclick = this._deleteSelected.bind(this); + }, + + _createAddToolbar : function() { + while (this.manipulationDiv.hasChildNodes()) { + this.manipulationDiv.removeChild(this.manipulationDiv.firstChild); + } + + this.manipulationDiv.innerHTML = "" + + "Back" + + "
    " + + "Click in an empty space to place a new node"; + + // bind the icon + var backButton = document.getElementById("manipulate-back"); + backButton.onclick = this._createManipulatorBar.bind(this); + + + var me = this; + events.addListener(me, 'select', me._addNode.bind(me)); + }, + + + _createConnectToolbar : function() { + while (this.manipulationDiv.hasChildNodes()) { + this.manipulationDiv.removeChild(this.manipulationDiv.firstChild); + } + var message = "hello"; + if (!this._selectionIsEmpty()) { + message = "Select the node you want to connect to other nodes"; + } + + this.manipulationDiv.innerHTML = "" + + "Back" + + "
    " + + ""+message+""; + + // bind the icon + var backButton = document.getElementById("manipulate-back"); + backButton.onclick = this._createManipulatorBar.bind(this); + + var self = this; + events.addListener(self, 'select', function(params) {alert(self.selectForConnect)}); + }, + + _continueConnect : function() { + if (this._clusterInSelection()) { + this._unselectAll(); + this._createConnectToolbar("Select the node you want to connect (Clusters are not allowed)."); + return true; + } + else if (!this._selectionIsEmpty()) { + this._connectNodes(); + return true; + } + else { + var manipulatorLabel = document.getElementById['manipolatorLabel']; + manipulatorLabel + return false; + } + }, + + + /** + * Adds a node on the specified location + * + * @param {Object} pointer + */ + _addNode : function(pointer) { + console.log("HERE",this) + if (this._selectionIsEmpty()) { + var positionObject = this._pointerToPositionObject(pointer); + this.nodesData.add({id:util.randomUUID(),x:positionObject.left,y:positionObject.top,label:"new",fixed:false}); + this.moving = true; + this.start(); + } + }, + + _connectNodes : function() { + console.log(this.selectionObj) + }, + + + /** + * delete everything in the selection + * + * @private + */ + _deleteSelected : function() { + if (!this._clusterInSelection()) { + var selectedNodes = this.getSelectedNodes(); + var selectedEdges = this.getSelectedEdges(); + this._removeEdges(selectedEdges); + this._removeNodes(selectedNodes); + this._redraw(); + } + else { + alert("Clusters cannot be deleted.") + } + } + + + +} /** * Creation of the SectorMixin var. * @@ -12413,6 +12541,19 @@ var SelectionMixin = { return true; }, + _clusterInSelection : function() { + for(var objectId in this.selectionObj) { + if(this.selectionObj.hasOwnProperty(objectId)) { + if (this.selectionObj[objectId] instanceof Node) { + if (this.selectionObj[objectId].clusterSize > 1) { + return true; + } + } + } + } + return false; + }, + /** * select the edges connected to the node that is being selected * @@ -12583,9 +12724,7 @@ var SelectionMixin = { */ getSelection : function() { var nodeIds = this.getSelectedNodes(); - var edgeIds = this.getSelectedEdges(); - return {nodes:nodeIds, edges:edgeIds}; }, @@ -12625,15 +12764,6 @@ var SelectionMixin = { return idArray }, - /** - * - * retrieve the currently selected nodes as objects - * @return {Objects} selection An array with the ids of the - * selected nodes. - */ - getSelectionObjects : function() { - return this.selectionObj; - }, /** * select zero or more nodes @@ -13048,21 +13178,31 @@ function Graph (container, data, options) { this.yIncrement = 0; this.zoomIncrement = 0; + // create a frame and canvas this._create(); // load the sector system. (mandatory, fully integrated with Graph) this._loadSectorSystem(); - // apply options - this.setOptions(options); - // load the cluster system. (mandatory, even when not using the cluster system, there are function calls to it) this._loadClusterSystem(); // load the selection system. (mandatory, required by Graph) this._loadSelectionSystem(); + // load the data manipulation system + this._loadManipulationSystem(); + + // apply options + this.setOptions(options); + + + + + + + // other vars var graph = this; this.freezeSimulation = false;// freeze the simulation @@ -13457,6 +13597,7 @@ Graph.prototype._create = function () { this.frame.className = 'graph-frame'; this.frame.style.position = 'relative'; this.frame.style.overflow = 'hidden'; + this.frame.style.zIndex = "1"; // create the graph canvas (HTML canvas element) this.frame.canvas = document.createElement( 'canvas' ); @@ -13492,6 +13633,7 @@ Graph.prototype._create = function () { // add the frame to the container element this.containerElement.appendChild(this.frame); + }; @@ -13527,14 +13669,6 @@ Graph.prototype._createKeyBinds = function() { this.mousetrap.bind("pagedown",this._zoomOut.bind(me),"keydown"); this.mousetrap.bind("pagedown",this._stopZoom.bind(me), "keyup"); } - /* - this.mousetrap.bind("=",this.decreaseClusterLevel.bind(me)); - this.mousetrap.bind("-",this.increaseClusterLevel.bind(me)); - this.mousetrap.bind("s",this.singleStep.bind(me)); - this.mousetrap.bind("h",this.updateClustersDefault.bind(me)); - this.mousetrap.bind("c",this._collapseSector.bind(me)); - this.mousetrap.bind("f",this.toggleFreeze.bind(me)); - */ } /** @@ -13580,7 +13714,7 @@ Graph.prototype._onDragStart = function () { drag.nodeId = node.id; // select the clicked node if not yet selected if (!node.isSelected()) { - this._selectNode(node,false); + this._selectObject(node,false); } // create an array with the selected nodes and their original location and status @@ -13682,6 +13816,7 @@ Graph.prototype._onDragEnd = function () { Graph.prototype._onTap = function (event) { var pointer = this._getPointer(event.gesture.touches[0]); this._handleTap(pointer); + }; @@ -14032,6 +14167,8 @@ Graph.prototype.setSize = function(width, height) { this.frame.canvas.width = this.frame.canvas.clientWidth; this.frame.canvas.height = this.frame.canvas.clientHeight; + this.manipulationDiv.style.width = this.frame.canvas.clientWidth; + if (this.constants.navigationUI.enabled == true) { this._relocateUI(); } @@ -14096,7 +14233,7 @@ Graph.prototype._addNodes = function(ids) { var node = new Node(data, this.images, this.groups, this.constants); this.nodes[id] = node; // note: this may replace an existing node - if (!node.isFixed()) { + if (!node.isFixed() && this.createNodeOnClick != true) { // TODO: position new nodes in a smarter way! var radius = this.constants.edges.length * 2; var count = ids.length; @@ -14112,6 +14249,7 @@ Graph.prototype._addNodes = function(ids) { this._updateNodeIndexList(); this._reconnectEdges(); this._updateValueRange(this.nodes); + this.updateLabels(); }; /** @@ -14376,7 +14514,7 @@ Graph.prototype._redraw = function() { this._doInAllSectors("_drawAllSectorNodes",ctx); this._doInAllSectors("_drawEdges",ctx); - this._doInAllSectors("_drawNodes",ctx); + this._doInAllSectors("_drawNodes",ctx,true); // restore original scaling and translation ctx.restore(); @@ -14867,9 +15005,9 @@ Graph.prototype.start = function() { } }; - - - +/** + * Debug function, does one step of the graph + */ Graph.prototype.singleStep = function() { if (this.moving) { this._initializeForceCalculation(); @@ -14958,6 +15096,30 @@ Graph.prototype._loadSelectionSystem = function() { } + +/** + * Mixin the navigationUI (User Interface) system and initialize the parameters required + * + * @private + */ +Graph.prototype._loadManipulationSystem = function() { + // load the manipulator HTML elements. All styling done in css. + this.manipulationDiv = document.createElement('div'); + this.manipulationDiv.className = 'graph-manipulationDiv'; + this.containerElement.insertBefore(this.manipulationDiv, this.frame); + + + // load the manipulation functions + for (var mixinFunction in manipulationMixin) { + if (manipulationMixin.hasOwnProperty(mixinFunction)) { + Graph.prototype[mixinFunction] = manipulationMixin[mixinFunction]; + } + } + + this._createManipulatorBar(); + +} + /** * Mixin the navigationUI (User Interface) system and initialize the parameters required * diff --git a/examples/graph/20_UI_example.html b/examples/graph/20_UI_example.html index f3bdc458..89e620a6 100644 --- a/examples/graph/20_UI_example.html +++ b/examples/graph/20_UI_example.html @@ -31,6 +31,89 @@ div.table_description { width:100px; } + div.graph-manipulationDiv { + border-width:0px; + border-bottom: 1px; + border-style:solid; + border-color: #d6d9d8; + background: #ffffff; /* Old browsers */ + background: -moz-linear-gradient(top, #ffffff 0%, #f3f3f3 50%, #ededed 51%, #ffffff 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(50%,#f3f3f3), color-stop(51%,#ededed), color-stop(100%,#ffffff)); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, #ffffff 0%,#f3f3f3 50%,#ededed 51%,#ffffff 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(top, #ffffff 0%,#f3f3f3 50%,#ededed 51%,#ffffff 100%); /* Opera 11.10+ */ + background: -ms-linear-gradient(top, #ffffff 0%,#f3f3f3 50%,#ededed 51%,#ffffff 100%); /* IE10+ */ + background: linear-gradient(to bottom, #ffffff 0%,#f3f3f3 50%,#ededed 51%,#ffffff 100%); /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#ffffff',GradientType=0 ); /* IE6-9 */ + width: 600px; + height:30px; + z-index:10; + position:absolute; + } + + span.manipulationUI { + -moz-border-radius: 15px; + border-radius: 15px; + display:inline-block; + background-position: 4px 0px; + background-repeat:no-repeat; + height:24px; + margin: -14px 0px 0px 10px; + vertical-align:middle; + cursor: pointer; + padding: 0px 8px 0px 8px; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + } + + span.manipulationUI:hover { + box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.20); + } + + span.manipulationUI:active { + box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.50); + } + + span.manipulationUI.back { + background-image: url("../../dist/UI_icons/backIcon.png"); + } + + span.manipulationUI.none:hover { + box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.0); + cursor: default; + } + span.manipulationUI.none:active { + box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.0); + } + + span.manipulationUI.add { + background-image: url("../../dist/UI_icons/addNodeIcon.png"); + } + + span.manipulationUI.connect { + background-image: url("../../dist/UI_icons/connectIcon.png"); + } + + span.manipulationUI.delete { + background-image: url("../../dist/UI_icons/deleteIcon.png"); + } + /* top right bottom left */ + span.manipulationLabel { + margin: 0px 0px 0px 25px; + line-height: 25px; + } + + div.seperatorLine { + display:inline-block; + width:1px; + height:20px; + background-color: #bdbdbd; + margin: 5px 7px 0px 15px; + + } diff --git a/src/graph/Graph.js b/src/graph/Graph.js index e36e15d8..1f0c1ee0 100644 --- a/src/graph/Graph.js +++ b/src/graph/Graph.js @@ -110,21 +110,31 @@ function Graph (container, data, options) { this.yIncrement = 0; this.zoomIncrement = 0; + // create a frame and canvas this._create(); // load the sector system. (mandatory, fully integrated with Graph) this._loadSectorSystem(); - // apply options - this.setOptions(options); - // load the cluster system. (mandatory, even when not using the cluster system, there are function calls to it) this._loadClusterSystem(); // load the selection system. (mandatory, required by Graph) this._loadSelectionSystem(); + // load the data manipulation system + this._loadManipulationSystem(); + + // apply options + this.setOptions(options); + + + + + + + // other vars var graph = this; this.freezeSimulation = false;// freeze the simulation @@ -519,6 +529,7 @@ Graph.prototype._create = function () { this.frame.className = 'graph-frame'; this.frame.style.position = 'relative'; this.frame.style.overflow = 'hidden'; + this.frame.style.zIndex = "1"; // create the graph canvas (HTML canvas element) this.frame.canvas = document.createElement( 'canvas' ); @@ -554,6 +565,7 @@ Graph.prototype._create = function () { // add the frame to the container element this.containerElement.appendChild(this.frame); + }; @@ -589,14 +601,6 @@ Graph.prototype._createKeyBinds = function() { this.mousetrap.bind("pagedown",this._zoomOut.bind(me),"keydown"); this.mousetrap.bind("pagedown",this._stopZoom.bind(me), "keyup"); } - /* - this.mousetrap.bind("=",this.decreaseClusterLevel.bind(me)); - this.mousetrap.bind("-",this.increaseClusterLevel.bind(me)); - this.mousetrap.bind("s",this.singleStep.bind(me)); - this.mousetrap.bind("h",this.updateClustersDefault.bind(me)); - this.mousetrap.bind("c",this._collapseSector.bind(me)); - this.mousetrap.bind("f",this.toggleFreeze.bind(me)); - */ } /** @@ -642,7 +646,7 @@ Graph.prototype._onDragStart = function () { drag.nodeId = node.id; // select the clicked node if not yet selected if (!node.isSelected()) { - this._selectNode(node,false); + this._selectObject(node,false); } // create an array with the selected nodes and their original location and status @@ -744,6 +748,7 @@ Graph.prototype._onDragEnd = function () { Graph.prototype._onTap = function (event) { var pointer = this._getPointer(event.gesture.touches[0]); this._handleTap(pointer); + }; @@ -1094,6 +1099,8 @@ Graph.prototype.setSize = function(width, height) { this.frame.canvas.width = this.frame.canvas.clientWidth; this.frame.canvas.height = this.frame.canvas.clientHeight; + this.manipulationDiv.style.width = this.frame.canvas.clientWidth; + if (this.constants.navigationUI.enabled == true) { this._relocateUI(); } @@ -1158,7 +1165,7 @@ Graph.prototype._addNodes = function(ids) { var node = new Node(data, this.images, this.groups, this.constants); this.nodes[id] = node; // note: this may replace an existing node - if (!node.isFixed()) { + if (!node.isFixed() && this.createNodeOnClick != true) { // TODO: position new nodes in a smarter way! var radius = this.constants.edges.length * 2; var count = ids.length; @@ -1174,6 +1181,7 @@ Graph.prototype._addNodes = function(ids) { this._updateNodeIndexList(); this._reconnectEdges(); this._updateValueRange(this.nodes); + this.updateLabels(); }; /** @@ -1438,7 +1446,7 @@ Graph.prototype._redraw = function() { this._doInAllSectors("_drawAllSectorNodes",ctx); this._doInAllSectors("_drawEdges",ctx); - this._doInAllSectors("_drawNodes",ctx); + this._doInAllSectors("_drawNodes",ctx,true); // restore original scaling and translation ctx.restore(); @@ -1929,9 +1937,9 @@ Graph.prototype.start = function() { } }; - - - +/** + * Debug function, does one step of the graph + */ Graph.prototype.singleStep = function() { if (this.moving) { this._initializeForceCalculation(); @@ -2020,6 +2028,30 @@ Graph.prototype._loadSelectionSystem = function() { } + +/** + * Mixin the navigationUI (User Interface) system and initialize the parameters required + * + * @private + */ +Graph.prototype._loadManipulationSystem = function() { + // load the manipulator HTML elements. All styling done in css. + this.manipulationDiv = document.createElement('div'); + this.manipulationDiv.className = 'graph-manipulationDiv'; + this.containerElement.insertBefore(this.manipulationDiv, this.frame); + + + // load the manipulation functions + for (var mixinFunction in manipulationMixin) { + if (manipulationMixin.hasOwnProperty(mixinFunction)) { + Graph.prototype[mixinFunction] = manipulationMixin[mixinFunction]; + } + } + + this._createManipulatorBar(); + +} + /** * Mixin the navigationUI (User Interface) system and initialize the parameters required * diff --git a/src/graph/Node.js b/src/graph/Node.js index 3aea901d..924be40f 100644 --- a/src/graph/Node.js +++ b/src/graph/Node.js @@ -188,8 +188,8 @@ Node.prototype.setProperties = function(properties, constants) { } } - this.xFixed = this.xFixed || (properties.x !== undefined); - this.yFixed = this.yFixed || (properties.y !== undefined); + this.xFixed = this.xFixed || (properties.x !== undefined && properties.fixed); + this.yFixed = this.yFixed || (properties.y !== undefined && properties.fixed); this.radiusFixed = this.radiusFixed || (properties.radius !== undefined); if (this.shape == 'image') { diff --git a/src/graph/SelectionMixin.js b/src/graph/SelectionMixin.js index 4b6bebd5..42b58d56 100644 --- a/src/graph/SelectionMixin.js +++ b/src/graph/SelectionMixin.js @@ -233,6 +233,19 @@ var SelectionMixin = { return true; }, + _clusterInSelection : function() { + for(var objectId in this.selectionObj) { + if(this.selectionObj.hasOwnProperty(objectId)) { + if (this.selectionObj[objectId] instanceof Node) { + if (this.selectionObj[objectId].clusterSize > 1) { + return true; + } + } + } + } + return false; + }, + /** * select the edges connected to the node that is being selected * @@ -403,9 +416,7 @@ var SelectionMixin = { */ getSelection : function() { var nodeIds = this.getSelectedNodes(); - var edgeIds = this.getSelectedEdges(); - return {nodes:nodeIds, edges:edgeIds}; }, @@ -445,15 +456,6 @@ var SelectionMixin = { return idArray }, - /** - * - * retrieve the currently selected nodes as objects - * @return {Objects} selection An array with the ids of the - * selected nodes. - */ - getSelectionObjects : function() { - return this.selectionObj; - }, /** * select zero or more nodes diff --git a/src/graph/manipulationMixin.js b/src/graph/manipulationMixin.js new file mode 100644 index 00000000..9ba8f20f --- /dev/null +++ b/src/graph/manipulationMixin.js @@ -0,0 +1,128 @@ +/** + * Created by Alex on 2/4/14. + */ + +var manipulationMixin = { + + _createManipulatorBar : function() { + while (this.manipulationDiv.hasChildNodes()) { + this.manipulationDiv.removeChild(this.manipulationDiv.firstChild); + } + // add the icons to the manipulator div + this.manipulationDiv.innerHTML = "" + + "Add Node" + + "
    " + + "Connect Node" + + "
    " + + "Delete selected"; + + // bind the icons + var addButton = document.getElementById("manipulate-addNode"); + addButton.onclick = this._createAddToolbar.bind(this); + var connectButton = document.getElementById("manipulate-connectNode"); + connectButton.onclick = this._createConnectToolbar.bind(this); + var deleteButton = document.getElementById("manipulate-delete"); + deleteButton.onclick = this._deleteSelected.bind(this); + }, + + _createAddToolbar : function() { + while (this.manipulationDiv.hasChildNodes()) { + this.manipulationDiv.removeChild(this.manipulationDiv.firstChild); + } + + this.manipulationDiv.innerHTML = "" + + "Back" + + "
    " + + "Click in an empty space to place a new node"; + + // bind the icon + var backButton = document.getElementById("manipulate-back"); + backButton.onclick = this._createManipulatorBar.bind(this); + + + var me = this; + events.addListener(me, 'select', me._addNode.bind(me)); + }, + + + _createConnectToolbar : function() { + while (this.manipulationDiv.hasChildNodes()) { + this.manipulationDiv.removeChild(this.manipulationDiv.firstChild); + } + var message = "hello"; + if (!this._selectionIsEmpty()) { + message = "Select the node you want to connect to other nodes"; + } + + this.manipulationDiv.innerHTML = "" + + "Back" + + "
    " + + ""+message+""; + + // bind the icon + var backButton = document.getElementById("manipulate-back"); + backButton.onclick = this._createManipulatorBar.bind(this); + + var self = this; + events.addListener(self, 'select', function(params) {alert(self.selectForConnect)}); + }, + + _continueConnect : function() { + if (this._clusterInSelection()) { + this._unselectAll(); + this._createConnectToolbar("Select the node you want to connect (Clusters are not allowed)."); + return true; + } + else if (!this._selectionIsEmpty()) { + this._connectNodes(); + return true; + } + else { + var manipulatorLabel = document.getElementById['manipolatorLabel']; + manipulatorLabel + return false; + } + }, + + + /** + * Adds a node on the specified location + * + * @param {Object} pointer + */ + _addNode : function(pointer) { + console.log("HERE",this) + if (this._selectionIsEmpty()) { + var positionObject = this._pointerToPositionObject(pointer); + this.nodesData.add({id:util.randomUUID(),x:positionObject.left,y:positionObject.top,label:"new",fixed:false}); + this.moving = true; + this.start(); + } + }, + + _connectNodes : function() { + console.log(this.selectionObj) + }, + + + /** + * delete everything in the selection + * + * @private + */ + _deleteSelected : function() { + if (!this._clusterInSelection()) { + var selectedNodes = this.getSelectedNodes(); + var selectedEdges = this.getSelectedEdges(); + this._removeEdges(selectedEdges); + this._removeNodes(selectedNodes); + this._redraw(); + } + else { + alert("Clusters cannot be deleted.") + } + } + + + +} \ No newline at end of file From 544a4f32fd8be630e70693a5d6d7ef3a2414c000 Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Tue, 4 Feb 2014 17:16:22 +0100 Subject: [PATCH 29/52] fixed merge --- dist/{UI_icons => img}/addNodeIcon.png | Bin dist/{UI_icons => img}/backIcon.png | Bin dist/{UI_icons => img}/connectIcon.png | Bin dist/{UI_icons => img}/deleteIcon.png | Bin dist/vis.js | 34 ++++++------------------- dist/vis.min.js | 18 ++++++------- examples/graph/20_UI_example.html | 22 ++++++++-------- src/graph/Graph.js | 5 ---- src/graph/SelectionMixin.js | 12 ++++----- 9 files changed, 34 insertions(+), 57 deletions(-) rename dist/{UI_icons => img}/addNodeIcon.png (100%) rename dist/{UI_icons => img}/backIcon.png (100%) rename dist/{UI_icons => img}/connectIcon.png (100%) rename dist/{UI_icons => img}/deleteIcon.png (100%) diff --git a/dist/UI_icons/addNodeIcon.png b/dist/img/addNodeIcon.png similarity index 100% rename from dist/UI_icons/addNodeIcon.png rename to dist/img/addNodeIcon.png diff --git a/dist/UI_icons/backIcon.png b/dist/img/backIcon.png similarity index 100% rename from dist/UI_icons/backIcon.png rename to dist/img/backIcon.png diff --git a/dist/UI_icons/connectIcon.png b/dist/img/connectIcon.png similarity index 100% rename from dist/UI_icons/connectIcon.png rename to dist/img/connectIcon.png diff --git a/dist/UI_icons/deleteIcon.png b/dist/img/deleteIcon.png similarity index 100% rename from dist/UI_icons/deleteIcon.png rename to dist/img/deleteIcon.png diff --git a/dist/vis.js b/dist/vis.js index 96f50036..09281c11 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -4,8 +4,8 @@ * * A dynamic, browser-based visualization library. * - * @version 0.4.0 - * @date 2014-01-31 + * @version 0.5.0-SNAPSHOT + * @date 2014-02-04 * * @license * Copyright (C) 2011-2014 Almende B.V, http://almende.com @@ -12970,24 +12970,14 @@ var SelectionMixin = { delete this.selectionObj[objectId]; } } -<<<<<<< HEAD else { // assuming only edges and nodes are selected if (!this.edges.hasOwnProperty(objectId)) { delete this.selectionObj[objectId]; } -======= - } - } - else if (this.selection && this.selection.length) { - // remove all selections - for (i = 0, iMax = this.selection.length; i < iMax; i++) { - id = this.selection[i]; - if (this.nodes.hasOwnProperty(id)) { - this.nodes[id].unselect(); + changed = true; } - changed = true; - } this.selection = []; + } } if (changed && (triggerSelect == true || triggerSelect == undefined)) { @@ -12998,8 +12988,9 @@ var SelectionMixin = { } return changed; - }, -*/ + } + +} /** * select all nodes on given location x, y * @param {Array} selection an array with node ids @@ -13031,7 +13022,6 @@ var SelectionMixin = { } - <<<<<<< HEAD ======= if (changed) { @@ -13040,11 +13030,8 @@ var SelectionMixin = { nodes: this.getSelection() }); } - - return changed; - }, - */ >>>>>>> develop + }; @@ -14424,15 +14411,10 @@ Graph.prototype.setSize = function(width, height) { this.frame.canvas.width = this.frame.canvas.clientWidth; this.frame.canvas.height = this.frame.canvas.clientHeight; -<<<<<<< HEAD this.manipulationDiv.style.width = this.frame.canvas.clientWidth; - if (this.constants.navigationUI.enabled == true) { - this._relocateUI(); -======= if (this.constants.navigation.enabled == true) { this._relocateNavigation(); ->>>>>>> develop } }; diff --git a/dist/vis.min.js b/dist/vis.min.js index 083f0f1f..43c82509 100644 --- a/dist/vis.min.js +++ b/dist/vis.min.js @@ -4,8 +4,8 @@ * * A dynamic, browser-based visualization library. * - * @version 0.4.0 - * @date 2014-01-31 + * @version 0.5.0-SNAPSHOT + * @date 2014-02-04 * * @license * Copyright (C) 2011-2014 Almende B.V, http://almende.com @@ -22,10 +22,10 @@ * License for the specific language governing permissions and limitations under * the License. */ -!function(t){if("object"==typeof exports)module.exports=t();else if("function"==typeof define&&define.amd)define(t);else{var e;"undefined"!=typeof window?e=window:"undefined"!=typeof global?e=global:"undefined"!=typeof self&&(e=self),e.vis=t()}}(function(){var t;return function e(t,i,n){function s(r,a){if(!i[r]){if(!t[r]){var h="function"==typeof require&&require;if(!a&&h)return h(r,!0);if(o)return o(r,!0);throw new Error("Cannot find module '"+r+"'")}var d=i[r]={exports:{}};t[r][0].call(d.exports,function(e){var i=t[r][1][e];return s(i?i:e)},d,d.exports,e,t,i,n)}return i[r].exports}for(var o="function"==typeof require&&require,r=0;ri;++i)t.call(e||this,this[i],i,this)}),Array.prototype.map||(Array.prototype.map=function(t,e){var i,n,s;if(null==this)throw new TypeError(" this is null or not defined");var o=Object(this),r=o.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(e&&(i=e),n=new Array(r),s=0;r>s;){var a,h;s in o&&(a=o[s],h=t.call(i,a,s,o),n[s]=h),s++}return n}),Array.prototype.filter||(Array.prototype.filter=function(t){"use strict";if(null==this)throw new TypeError;var e=Object(this),i=e.length>>>0;if("function"!=typeof t)throw new TypeError;for(var n=[],s=arguments[1],o=0;i>o;o++)if(o in e){var r=e[o];t.call(s,r,o,e)&&n.push(r)}return n}),Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,e=!{toString:null}.propertyIsEnumerable("toString"),i=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],n=i.length;return function(s){if("object"!=typeof s&&"function"!=typeof s||null===s)throw new TypeError("Object.keys called on non-object");var o=[];for(var r in s)t.call(s,r)&&o.push(r);if(e)for(var a=0;n>a;a++)t.call(s,i[a])&&o.push(i[a]);return o}}()),Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s}),Object.create||(Object.create=function(t){function e(){}if(arguments.length>1)throw new Error("Object.create implementation only accepts the first parameter.");return e.prototype=t,new e}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s});var z={};z.isNumber=function(t){return t instanceof Number||"number"==typeof t},z.isString=function(t){return t instanceof String||"string"==typeof t},z.isDate=function(t){if(t instanceof Date)return!0;if(z.isString(t)){var e=P.exec(t);if(e)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},z.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},z.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},z.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var n=arguments[e];for(var s in n)n.hasOwnProperty(s)&&void 0!==n[s]&&(t[s]=n[s])}return t},z.convert=function(t,e){var i;if(void 0===t)return void 0;if(null===t)return null;if(!e)return t;if("string"!=typeof e&&!(e instanceof String))throw new Error("Type must be a string");switch(e){case"boolean":case"Boolean":return Boolean(t);case"number":case"Number":return Number(t.valueOf());case"string":case"String":return String(t);case"Date":if(z.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(L.isMoment(t))return new Date(t.valueOf());if(z.isString(t))return i=P.exec(t),i?new Date(Number(i[1])):L(t).toDate();throw new Error("Cannot convert object of type "+z.getType(t)+" to type Date");case"Moment":if(z.isNumber(t))return L(t);if(t instanceof Date)return L(t.valueOf());if(L.isMoment(t))return L(t);if(z.isString(t))return i=P.exec(t),L(i?Number(i[1]):t);throw new Error("Cannot convert object of type "+z.getType(t)+" to type Date");case"ISODate":if(z.isNumber(t))return new Date(t);if(t instanceof Date)return t.toISOString();if(L.isMoment(t))return t.toDate().toISOString();if(z.isString(t))return i=P.exec(t),i?new Date(Number(i[1])).toISOString():new Date(t).toISOString();throw new Error("Cannot convert object of type "+z.getType(t)+" to type ISODate");case"ASPDate":if(z.isNumber(t))return"/Date("+t+")/";if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(z.isString(t)){i=P.exec(t);var n;return n=i?new Date(Number(i[1])).valueOf():new Date(t).valueOf(),"/Date("+n+")/"}throw new Error("Cannot convert object of type "+z.getType(t)+" to type ASPDate");default:throw new Error("Cannot convert object of type "+z.getType(t)+' to type "'+e+'"')}};var P=/^\/?Date\((\-?\d+)/i;z.getType=function(t){var e=typeof t;return"object"==e?null==t?"null":t instanceof Boolean?"Boolean":t instanceof Number?"Number":t instanceof String?"String":t instanceof Array?"Array":t instanceof Date?"Date":"Object":"number"==e?"Number":"boolean"==e?"Boolean":"string"==e?"String":e},z.getAbsoluteLeft=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetLeft,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetLeft,n-=s.scrollLeft,s=s.offsetParent;return n},z.getAbsoluteTop=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetTop,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetTop,n-=s.scrollTop,s=s.offsetParent;return n},z.getPageY=function(t){if("pageY"in t)return t.pageY;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientY:t.clientY;var i=document.documentElement,n=document.body;return e+(i&&i.scrollTop||n&&n.scrollTop||0)-(i&&i.clientTop||n&&n.clientTop||0)},z.getPageX=function(t){if("pageY"in t)return t.pageX;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientX:t.clientX;var i=document.documentElement,n=document.body;return e+(i&&i.scrollLeft||n&&n.scrollLeft||0)-(i&&i.clientLeft||n&&n.clientLeft||0)},z.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},z.removeClassName=function(t,e){var i=t.className.split(" "),n=i.indexOf(e);-1!=n&&(i.splice(n,1),t.className=i.join(" "))},z.forEach=function(t,e){var i,n;if(t instanceof Array)for(i=0,n=t.length;n>i;i++)e(t[i],i,t);else for(i in t)t.hasOwnProperty(i)&&e(t[i],i,t)},z.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},z.addEventListener=function(t,e,i,n){t.addEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.addEventListener(e,i,n)):t.attachEvent("on"+e,i)},z.removeEventListener=function(t,e,i,n){t.removeEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.removeEventListener(e,i,n)):t.detachEvent("on"+e,i)},z.getTarget=function(t){t||(t=window.event);var e;return t.target?e=t.target:t.srcElement&&(e=t.srcElement),void 0!=e.nodeType&&3==e.nodeType&&(e=e.parentNode),e},z.stopPropagation=function(t){t||(t=window.event),t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},z.fakeGesture=function(t,e){var i=null;return N.event.collectEventData(this,i,e)},z.preventDefault=function(t){t||(t=window.event),t.preventDefault?t.preventDefault():t.returnValue=!1},z.option={},z.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},z.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},z.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?String(t):e||null},z.option.asSize=function(t,e){return"function"==typeof t&&(t=t()),z.isString(t)?t:z.isNumber(t)?t+"px":e||null},z.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null};var F={listeners:[],indexOf:function(t){for(var e=this.listeners,i=0,n=this.listeners.length;n>i;i++){var s=e[i];if(s&&s.object==t)return i}return-1},addListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];s||(s={object:t,events:{}},this.listeners.push(s));var o=s.events[e];o||(o=[],s.events[e]=o),-1==o.indexOf(i)&&o.push(i)},removeListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];o&&(n=o.indexOf(i),-1!=n&&o.splice(n,1),0==o.length&&delete s.events[e]);var r=0,a=s.events;for(var h in a)a.hasOwnProperty(h)&&r++;0==r&&delete this.listeners[n]}},removeAllListeners:function(){this.listeners=[]},trigger:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];if(o)for(var r=0,a=o.length;a>r;r++)o[r](i)}}};s.prototype.on=function(t,e,i){var n=t instanceof RegExp?t:new RegExp(t.replace("*","\\w+")),s={id:z.randomUUID(),event:t,regexp:n,callback:"function"==typeof e?e:null,target:i};return this.subscriptions.push(s),s.id},s.prototype.off=function(t){for(var e=0;eo;o++)i=s._addItem(t[o]),n.push(i);else if(z.isDataTable(t))for(var a=this._getColumnNames(t),h=0,d=t.getNumberOfRows();d>h;h++){for(var c={},l=0,u=a.length;u>l;l++){var p=a[l];c[p]=t.getValue(h,l)}i=s._addItem(c),n.push(i)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");i=s._addItem(t),n.push(i)}return n.length&&this._trigger("add",{items:n},e),n},o.prototype.update=function(t,e){var i=[],n=[],s=this,o=s.fieldId,r=function(t){var e=t[o];s.data[e]?(e=s._updateItem(t),n.push(e)):(e=s._addItem(t),i.push(e))};if(t instanceof Array)for(var a=0,h=t.length;h>a;a++)r(t[a]);else if(z.isDataTable(t))for(var d=this._getColumnNames(t),c=0,l=t.getNumberOfRows();l>c;c++){for(var u={},p=0,f=d.length;f>p;p++){var g=d[p];u[g]=t.getValue(c,p)}r(u)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");r(t)}return i.length&&this._trigger("add",{items:i},e),n.length&&this._trigger("update",{items:n},e),i.concat(n)},o.prototype.get=function(){var t,e,i,n,s=this,o=this.showInternalIds,r=z.getType(arguments[0]);"String"==r||"Number"==r?(t=arguments[0],i=arguments[1],n=arguments[2]):"Array"==r?(e=arguments[0],i=arguments[1],n=arguments[2]):(i=arguments[0],n=arguments[1]);var a;if(i&&i.type){if(a="DataTable"==i.type?"DataTable":"Array",n&&a!=z.getType(n))throw new Error('Type of parameter "data" ('+z.getType(n)+") does not correspond with specified options.type ("+i.type+")");if("DataTable"==a&&!z.isDataTable(n))throw new Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else a=n?"DataTable"==z.getType(n)?"DataTable":"Array":"Array";void 0!=i&&void 0!=i.showInternalIds&&(this.showInternalIds=i.showInternalIds);var h,d,c,l,u=i&&i.convert||this.options.convert,p=i&&i.filter,f=[];if(void 0!=t)h=s._getItem(t,u),p&&!p(h)&&(h=null);else if(void 0!=e)for(c=0,l=e.length;l>c;c++)h=s._getItem(e[c],u),(!p||p(h))&&f.push(h);else for(d in this.data)this.data.hasOwnProperty(d)&&(h=s._getItem(d,u),(!p||p(h))&&f.push(h));if(this.showInternalIds=o,i&&i.order&&void 0==t&&this._sort(f,i.order),i&&i.fields){var g=i.fields;if(void 0!=t)h=this._filterFields(h,g);else for(c=0,l=f.length;l>c;c++)f[c]=this._filterFields(f[c],g)}if("DataTable"==a){var m=this._getColumnNames(n);if(void 0!=t)s._appendRow(n,m,h);else for(c=0,l=f.length;l>c;c++)s._appendRow(n,m,f[c]);return n}if(void 0!=t)return h;if(n){for(c=0,l=f.length;l>c;c++)n.push(f[c]);return n}return f},o.prototype.getIds=function(t){var e,i,n,s,o,r=this.data,a=t&&t.filter,h=t&&t.order,d=t&&t.convert||this.options.convert,c=[];if(a)if(h){o=[];for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,d),a(s)&&o.push(s));for(this._sort(o,h),e=0,i=o.length;i>e;e++)c[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,d),a(s)&&c.push(s[this.fieldId]));else if(h){o=[];for(n in r)r.hasOwnProperty(n)&&o.push(r[n]);for(this._sort(o,h),e=0,i=o.length;i>e;e++)c[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=r[n],c.push(s[this.fieldId]));return c},o.prototype.forEach=function(t,e){var i,n,s=e&&e.filter,o=e&&e.convert||this.options.convert,r=this.data;if(e&&e.order)for(var a=this.get(e),h=0,d=a.length;d>h;h++)i=a[h],n=i[this.fieldId],t(i,n);else for(n in r)r.hasOwnProperty(n)&&(i=this._getItem(n,o),(!s||s(i))&&t(i,n))},o.prototype.map=function(t,e){var i,n=e&&e.filter,s=e&&e.convert||this.options.convert,o=[],r=this.data;for(var a in r)r.hasOwnProperty(a)&&(i=this._getItem(a,s),(!n||n(i))&&o.push(t(i,a)));return e&&e.order&&this._sort(o,e.order),o},o.prototype._filterFields=function(t,e){var i={};for(var n in t)t.hasOwnProperty(n)&&-1!=e.indexOf(n)&&(i[n]=t[n]);return i},o.prototype._sort=function(t,e){if(z.isString(e)){var i=e;t.sort(function(t,e){var n=t[i],s=e[i];return n>s?1:s>n?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},o.prototype.remove=function(t,e){var i,n,s,o=[];if(t instanceof Array)for(i=0,n=t.length;n>i;i++)s=this._remove(t[i]),null!=s&&o.push(s);else s=this._remove(t),null!=s&&o.push(s);return o.length&&this._trigger("remove",{items:o},e),o},o.prototype._remove=function(t){if(z.isNumber(t)||z.isString(t)){if(this.data[t])return delete this.data[t],delete this.internalIds[t],t}else if(t instanceof Object){var e=t[this.fieldId];if(e&&this.data[e])return delete this.data[e],delete this.internalIds[e],e}return null},o.prototype.clear=function(t){var e=Object.keys(this.data);return this.data={},this.internalIds={},this._trigger("remove",{items:e},t),e},o.prototype.max=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||r>n)&&(i=o,n=r)}return i},o.prototype.min=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||n>r)&&(i=o,n=r)}return i},o.prototype.distinct=function(t){var e=this.data,i=[],n=this.options.convert[t],s=0;for(var o in e)if(e.hasOwnProperty(o)){for(var r=e[o],a=z.convert(r[t],n),h=!1,d=0;s>d;d++)if(i[d]==a){h=!0;break}h||(i[s]=a,s++)}return i},o.prototype._addItem=function(t){var e=t[this.fieldId];if(void 0!=e){if(this.data[e])throw new Error("Cannot add item: item with id "+e+" already exists")}else e=z.randomUUID(),t[this.fieldId]=e,this.internalIds[e]=t;var i={};for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=z.convert(t[n],s)}return this.data[e]=i,e},o.prototype._getItem=function(t,e){var i,n,s=this.data[t];if(!s)return null;var o={},r=this.fieldId,a=this.internalIds;if(e)for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a&&!this.showInternalIds||(o[i]=z.convert(n,e[i])));else for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a&&!this.showInternalIds||(o[i]=n));return o},o.prototype._updateItem=function(t){var e=t[this.fieldId];if(void 0==e)throw new Error("Cannot update item: item has no id (item: "+JSON.stringify(t)+")");var i=this.data[e];if(!i)throw new Error("Cannot update item: no item with id "+e+" found");for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=z.convert(t[n],s)}return e},o.prototype.isInternalId=function(t){return t in this.internalIds},o.prototype._getColumnNames=function(t){for(var e=[],i=0,n=t.getNumberOfColumns();n>i;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},o.prototype._appendRow=function(t,e,i){for(var n=t.addRow(),s=0,o=e.length;o>s;s++){var r=e[s];t.setValue(n,s,i[r])}},r.prototype.setData=function(t){var e,i,n;if(this.data){this.data.unsubscribe&&this.data.unsubscribe("*",this.listener),e=[];for(var s in this.ids)this.ids.hasOwnProperty(s)&&e.push(s);this.ids={},this._trigger("remove",{items:e})}if(this.data=t,this.data){for(this.fieldId=this.options.fieldId||this.data&&this.data.options&&this.data.options.fieldId||"id",e=this.data.getIds({filter:this.options&&this.options.filter}),i=0,n=e.length;n>i;i++)s=e[i],this.ids[s]=!0;this._trigger("add",{items:e}),this.data.subscribe&&this.data.subscribe("*",this.listener)}},r.prototype.get=function(){var t,e,i,n=this,s=z.getType(arguments[0]);"String"==s||"Number"==s||"Array"==s?(t=arguments[0],e=arguments[1],i=arguments[2]):(e=arguments[0],i=arguments[1]);var o=z.extend({},this.options,e);this.options.filter&&e&&e.filter&&(o.filter=function(t){return n.options.filter(t)&&e.filter(t)});var r=[];return void 0!=t&&r.push(t),r.push(o),r.push(i),this.data&&this.data.get.apply(this.data,r)},r.prototype.getIds=function(t){var e;if(this.data){var i,n=this.options.filter;i=t&&t.filter?n?function(e){return n(e)&&t.filter(e)}:t.filter:n,e=this.data.getIds({filter:i,order:t&&t.order})}else e=[];return e},r.prototype._onEvent=function(t,e,i){var n,s,o,r,a=e&&e.items,h=this.data,d=[],c=[],l=[];if(a&&h){switch(t){case"add":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r&&(this.ids[o]=!0,d.push(o));break;case"update":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r?this.ids[o]?c.push(o):(this.ids[o]=!0,d.push(o)):this.ids[o]&&(delete this.ids[o],l.push(o));break;case"remove":for(n=0,s=a.length;s>n;n++)o=a[n],this.ids[o]&&(delete this.ids[o],l.push(o))}d.length&&this._trigger("add",{items:d},i),c.length&&this._trigger("update",{items:c},i),l.length&&this._trigger("remove",{items:l},i)}},r.prototype.subscribe=o.prototype.subscribe,r.prototype.unsubscribe=o.prototype.unsubscribe,r.prototype._trigger=o.prototype._trigger,TimeStep=function(t,e,i){this.current=new Date,this._start=new Date,this._end=new Date,this.autoScale=!0,this.scale=TimeStep.SCALE.DAY,this.step=1,this.setRange(t,e,i)},TimeStep.SCALE={MILLISECOND:1,SECOND:2,MINUTE:3,HOUR:4,DAY:5,WEEKDAY:6,MONTH:7,YEAR:8},TimeStep.prototype.setRange=function(t,e,i){if(!(t instanceof Date&&e instanceof Date))throw"No legal start or end date in method setRange";this._start=void 0!=t?new Date(t.valueOf()):new Date,this._end=void 0!=e?new Date(e.valueOf()):new Date,this.autoScale&&this.setMinimumStep(i)},TimeStep.prototype.first=function(){this.current=new Date(this._start.valueOf()),this.roundToMinor()},TimeStep.prototype.roundToMinor=function(){switch(this.scale){case TimeStep.SCALE.YEAR:this.current.setFullYear(this.step*Math.floor(this.current.getFullYear()/this.step)),this.current.setMonth(0);case TimeStep.SCALE.MONTH:this.current.setDate(1);case TimeStep.SCALE.DAY:case TimeStep.SCALE.WEEKDAY:this.current.setHours(0);case TimeStep.SCALE.HOUR:this.current.setMinutes(0);case TimeStep.SCALE.MINUTE:this.current.setSeconds(0);case TimeStep.SCALE.SECOND:this.current.setMilliseconds(0)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.setMilliseconds(this.current.getMilliseconds()-this.current.getMilliseconds()%this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()-this.current.getSeconds()%this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()-this.current.getMinutes()%this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()-this.current.getHours()%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()-1-(this.current.getDate()-1)%this.step+1);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()-this.current.getMonth()%this.step); -break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()-this.current.getFullYear()%this.step)}},TimeStep.prototype.hasNext=function(){return this.current.valueOf()<=this._end.valueOf()},TimeStep.prototype.next=function(){var t=this.current.valueOf();if(this.current.getMonth()<6)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current=new Date(this.current.valueOf()+1e3*this.step);break;case TimeStep.SCALE.MINUTE:this.current=new Date(this.current.valueOf()+1e3*this.step*60);break;case TimeStep.SCALE.HOUR:this.current=new Date(this.current.valueOf()+1e3*this.step*60*60);var e=this.current.getHours();this.current.setHours(e-e%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}else switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()+this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()+this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()+this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.getMilliseconds()0&&(this.step=e),this.autoScale=!1},TimeStep.prototype.setAutoScale=function(t){this.autoScale=t},TimeStep.prototype.setMinimumStep=function(t){if(void 0!=t){var e=31104e6,i=2592e6,n=864e5,s=36e5,o=6e4,r=1e3,a=1;1e3*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1e3),500*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=500),100*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=100),50*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=50),10*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=10),5*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=5),e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1),3*i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=3),i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=1),5*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=5),2*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=2),n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=1),n/2>t&&(this.scale=TimeStep.SCALE.WEEKDAY,this.step=1),4*s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=4),s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=1),15*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=15),10*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=10),5*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=5),o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=1),15*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=15),10*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=10),5*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=5),r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=1),200*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=200),100*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=100),50*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=50),10*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=10),5*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=5),a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=1)}},TimeStep.prototype.snap=function(t){if(this.scale==TimeStep.SCALE.YEAR){var e=t.getFullYear()+Math.round(t.getMonth()/12);t.setFullYear(Math.round(e/this.step)*this.step),t.setMonth(0),t.setDate(0),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MONTH)t.getDate()>15?(t.setDate(1),t.setMonth(t.getMonth()+1)):t.setDate(1),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0);else if(this.scale==TimeStep.SCALE.DAY||this.scale==TimeStep.SCALE.WEEKDAY){switch(this.step){case 5:case 2:t.setHours(24*Math.round(t.getHours()/24));break;default:t.setHours(12*Math.round(t.getHours()/12))}t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.HOUR){switch(this.step){case 4:t.setMinutes(60*Math.round(t.getMinutes()/60));break;default:t.setMinutes(30*Math.round(t.getMinutes()/30))}t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MINUTE){switch(this.step){case 15:case 10:t.setMinutes(5*Math.round(t.getMinutes()/5)),t.setSeconds(0);break;case 5:t.setSeconds(60*Math.round(t.getSeconds()/60));break;default:t.setSeconds(30*Math.round(t.getSeconds()/30))}t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.SECOND)switch(this.step){case 15:case 10:t.setSeconds(5*Math.round(t.getSeconds()/5)),t.setMilliseconds(0);break;case 5:t.setMilliseconds(1e3*Math.round(t.getMilliseconds()/1e3));break;default:t.setMilliseconds(500*Math.round(t.getMilliseconds()/500))}else if(this.scale==TimeStep.SCALE.MILLISECOND){var i=this.step>5?this.step/2:1;t.setMilliseconds(Math.round(t.getMilliseconds()/i)*i)}},TimeStep.prototype.isMajor=function(){switch(this.scale){case TimeStep.SCALE.MILLISECOND:return 0==this.current.getMilliseconds();case TimeStep.SCALE.SECOND:return 0==this.current.getSeconds();case TimeStep.SCALE.MINUTE:return 0==this.current.getHours()&&0==this.current.getMinutes();case TimeStep.SCALE.HOUR:return 0==this.current.getHours();case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return 1==this.current.getDate();case TimeStep.SCALE.MONTH:return 0==this.current.getMonth();case TimeStep.SCALE.YEAR:return!1;default:return!1}},TimeStep.prototype.getLabelMinor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return L(t).format("SSS");case TimeStep.SCALE.SECOND:return L(t).format("s");case TimeStep.SCALE.MINUTE:return L(t).format("HH:mm");case TimeStep.SCALE.HOUR:return L(t).format("HH:mm");case TimeStep.SCALE.WEEKDAY:return L(t).format("ddd D");case TimeStep.SCALE.DAY:return L(t).format("D");case TimeStep.SCALE.MONTH:return L(t).format("MMM");case TimeStep.SCALE.YEAR:return L(t).format("YYYY");default:return""}},TimeStep.prototype.getLabelMajor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return L(t).format("HH:mm:ss");case TimeStep.SCALE.SECOND:return L(t).format("D MMMM HH:mm");case TimeStep.SCALE.MINUTE:case TimeStep.SCALE.HOUR:return L(t).format("ddd D MMMM");case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return L(t).format("MMMM YYYY");case TimeStep.SCALE.MONTH:return L(t).format("YYYY");case TimeStep.SCALE.YEAR:return"";default:return""}},a.prototype.setOptions=function(t){z.extend(this.options,t)},a.prototype.update=function(){this._order(),this._stack()},a.prototype._order=function(){var t=this.parent.items;if(!t)throw new Error("Cannot stack items: parent does not contain items");var e=[],i=0;z.forEach(t,function(t){t.visible&&(e[i]=t,i++)});var n=this.options.order||this.defaultOptions.order;if("function"!=typeof n)throw new Error("Option order must be a function");e.sort(n),this.ordered=e},a.prototype._stack=function(){var t,e,i,n=this.ordered,s=this.options,o=s.orientation||this.defaultOptions.orientation,r="top"==o;for(i=s.margin&&void 0!==s.margin.item?s.margin.item:this.defaultOptions.margin.item,t=0,e=n.length;e>t;t++){var a=n[t],h=null;do h=this.checkOverlap(n,t,0,t-1,i),null!=h&&(a.top=r?h.top+h.height+i:h.top-a.height-i);while(h)}},a.prototype.checkOverlap=function(t,e,i,n,s){for(var o=this.collision,r=t[e],a=n;a>=i;a--){var h=t[a];if(o(r,h,s)&&a!=e)return h}return null},a.prototype.collision=function(t,e,i){return t.left-ie.left&&t.top-ie.top},h.prototype.setOptions=function(t){z.extend(this.options,t),null!==this.start&&null!==this.end&&this.setRange(this.start,this.end)},h.prototype.subscribe=function(t,e,i){function n(e){s._onMouseWheel(e,t,i)}var s=this;if("move"==e)t.on("dragstart",function(e){s._onDragStart(e,t)}),t.on("drag",function(e){s._onDrag(e,t,i)}),t.on("dragend",function(e){s._onDragEnd(e,t)});else{if("zoom"!=e)throw new TypeError('Unknown event "'+e+'". Choose "move" or "zoom".');t.on("mousewheel",n),t.on("DOMMouseScroll",n),t.on("touch",function(){s._onTouch()}),t.on("pinch",function(e){s._onPinch(e,t,i)})}},h.prototype.on=function(t,e){var i=["rangechange","rangechanged"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());F.addListener(this,t,e)},h.prototype.off=function(t,e){F.removeListener(this,t,e)},h.prototype._trigger=function(t){F.trigger(this,t,{start:this.start,end:this.end})},h.prototype.setRange=function(t,e){var i=this._applyRange(t,e);i&&(this._trigger("rangechange"),this._trigger("rangechanged"))},h.prototype._applyRange=function(t,e){var i,n=null!=t?z.convert(t,"Date").valueOf():this.start,s=null!=e?z.convert(e,"Date").valueOf():this.end,o=null!=this.options.max?z.convert(this.options.max,"Date").valueOf():null,r=null!=this.options.min?z.convert(this.options.min,"Date").valueOf():null;if(isNaN(n)||null===n)throw new Error('Invalid start "'+t+'"');if(isNaN(s)||null===s)throw new Error('Invalid end "'+e+'"');if(n>s&&(s=n),null!==r&&r>n&&(i=r-n,n+=i,s+=i,null!=o&&s>o&&(s=o)),null!==o&&s>o&&(i=s-o,n-=i,s-=i,null!=r&&r>n&&(n=r)),null!==this.options.zoomMin){var a=parseFloat(this.options.zoomMin);0>a&&(a=0),a>s-n&&(this.end-this.start===a?(n=this.start,s=this.end):(i=a-(s-n),n-=i/2,s+=i/2))}if(null!==this.options.zoomMax){var h=parseFloat(this.options.zoomMax);0>h&&(h=0),s-n>h&&(this.end-this.start===h?(n=this.start,s=this.end):(i=s-n-h,n+=i/2,s-=i/2))}var d=this.start!=n||this.end!=s;return this.start=n,this.end=s,d},h.prototype.getRange=function(){return{start:this.start,end:this.end}},h.prototype.conversion=function(t){return h.conversion(this.start,this.end,t)},h.conversion=function(t,e,i){return 0!=i&&e-t!=0?{offset:t,scale:i/(e-t)}:{offset:0,scale:1}};var Y={};h.prototype._onDragStart=function(t,e){if(!Y.pinching){Y.start=this.start,Y.end=this.end;var i=e.frame;i&&(i.style.cursor="move")}},h.prototype._onDrag=function(t,e,i){if(d(i),!Y.pinching){var n="horizontal"==i?t.gesture.deltaX:t.gesture.deltaY,s=Y.end-Y.start,o="horizontal"==i?e.width:e.height,r=-n/o*s;this._applyRange(Y.start+r,Y.end+r),this._trigger("rangechange")}},h.prototype._onDragEnd=function(t,e){Y.pinching||(e.frame&&(e.frame.style.cursor="auto"),this._trigger("rangechanged"))},h.prototype._onMouseWheel=function(t,e,i){d(i);var n=0;if(t.wheelDelta?n=t.wheelDelta/120:t.detail&&(n=-t.detail/3),n){var s;s=0>n?1-n/5:1/(1+n/5);var o=z.fakeGesture(this,t),r=c(o.touches[0],e.frame),a=this._pointerToDate(e,i,r);this.zoom(s,a)}z.preventDefault(t)},h.prototype._onTouch=function(){Y.start=this.start,Y.end=this.end,Y.pinching=!1,Y.center=null},h.prototype._onPinch=function(t,e,i){if(Y.pinching=!0,t.gesture.touches.length>1){Y.center||(Y.center=c(t.gesture.center,e.frame));var n=1/t.gesture.scale,s=this._pointerToDate(e,i,Y.center),o=c(t.gesture.center,e.frame),r=(this._pointerToDate(e,i,o),parseInt(s+(Y.start-s)*n)),a=parseInt(s+(Y.end-s)*n);this.setRange(r,a)}},h.prototype._pointerToDate=function(t,e,i){var n;if("horizontal"==e){var s=t.width;return n=this.conversion(s),i.x/n.scale+n.offset}var o=t.height;return n=this.conversion(o),i.y/n.scale+n.offset},h.prototype.zoom=function(t,e){null==e&&(e=(this.start+this.end)/2);var i=e+(this.start-e)*t,n=e+(this.end-e)*t;this.setRange(i,n)},h.prototype.move=function(t){var e=this.end-this.start,i=this.start+e*t,n=this.end+e*t;this.start=i,this.end=n},h.prototype.moveTo=function(t){var e=(this.start+this.end)/2,i=e-t,n=this.start-i,s=this.end-i;this.setRange(n,s)},l.prototype.add=function(t){if(void 0==t.id)throw new Error("Component has no field id");if(!(t instanceof u||t instanceof l))throw new TypeError("Component must be an instance of prototype Component or Controller");t.controller=this,this.components[t.id]=t},l.prototype.remove=function(t){var e;for(e in this.components)if(this.components.hasOwnProperty(e)&&(e==t||this.components[e]==t))break;e&&delete this.components[e]},l.prototype.requestReflow=function(t){if(t)this.reflow();else if(!this.reflowTimer){var e=this;this.reflowTimer=setTimeout(function(){e.reflowTimer=void 0,e.reflow()},0)}},l.prototype.requestRepaint=function(t){if(t)this.repaint();else if(!this.repaintTimer){var e=this;this.repaintTimer=setTimeout(function(){e.repaintTimer=void 0,e.repaint()},0)}},l.prototype.repaint=function V(){function V(i,n){n in e||(i.depends&&i.depends.forEach(function(t){V(t,t.id)}),i.parent&&V(i.parent,i.parent.id),t=i.repaint()||t,e[n]=!0)}var t=!1;this.repaintTimer&&(clearTimeout(this.repaintTimer),this.repaintTimer=void 0);var e={};z.forEach(this.components,V),t&&this.reflow()},l.prototype.reflow=function G(){function G(i,n){n in e||(i.depends&&i.depends.forEach(function(t){G(t,t.id)}),i.parent&&G(i.parent,i.parent.id),t=i.reflow()||t,e[n]=!0)}var t=!1;this.reflowTimer&&(clearTimeout(this.reflowTimer),this.reflowTimer=void 0);var e={};z.forEach(this.components,G),t&&this.repaint()},u.prototype.setOptions=function(t){t&&(z.extend(this.options,t),this.controller&&(this.requestRepaint(),this.requestReflow()))},u.prototype.getOption=function(t){var e;return this.options&&(e=this.options[t]),void 0===e&&this.defaultOptions&&(e=this.defaultOptions[t]),e},u.prototype.getContainer=function(){return null},u.prototype.getFrame=function(){return this.frame},u.prototype.repaint=function(){return!1},u.prototype.reflow=function(){return!1},u.prototype.hide=function(){return this.frame&&this.frame.parentNode?(this.frame.parentNode.removeChild(this.frame),!0):!1},u.prototype.show=function(){return this.frame&&this.frame.parentNode?!1:this.repaint()},u.prototype.requestRepaint=function(){if(!this.controller)throw new Error("Cannot request a repaint: no controller configured");this.controller.requestRepaint()},u.prototype.requestReflow=function(){if(!this.controller)throw new Error("Cannot request a reflow: no controller configured");this.controller.requestReflow()},p.prototype=new u,p.prototype.setOptions=u.prototype.setOptions,p.prototype.getContainer=function(){return this.frame},p.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.frame;if(!s){s=document.createElement("div"),s.className="panel";var o=n.className;o&&("function"==typeof o?z.addClassName(s,String(o())):z.addClassName(s,String(o))),this.frame=s,t+=1}if(!s.parentNode){if(!this.parent)throw new Error("Cannot repaint panel: no parent attached");var r=this.parent.getContainer();if(!r)throw new Error("Cannot repaint panel: parent has no container element");r.appendChild(s),t+=1}return t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),t>0},p.prototype.reflow=function(){var t=0,e=z.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},f.prototype=new p,f.prototype.setOptions=u.prototype.setOptions,f.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.frame;if(s||(s=document.createElement("div"),this.frame=s,t+=1),!s.parentNode){if(!this.container)throw new Error("Cannot repaint root panel: no container attached");this.container.appendChild(s),t+=1}s.className="vis timeline rootpanel "+n.orientation;var o=n.className;return o&&z.addClassName(s,z.option.asString(o)),t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),this._updateEventEmitters(),this._updateWatch(),t>0},f.prototype.reflow=function(){var t=0,e=z.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},f.prototype._updateWatch=function(){var t=this.getOption("autoResize");t?this._watch():this._unwatch()},f.prototype._watch=function(){var t=this;this._unwatch();var e=function(){var e=t.getOption("autoResize");return e?void(t.frame&&(t.frame.clientWidth!=t.width||t.frame.clientHeight!=t.height)&&t.requestReflow()):void t._unwatch()};z.addEventListener(window,"resize",e),this.watchTimer=setInterval(e,1e3)},f.prototype._unwatch=function(){this.watchTimer&&(clearInterval(this.watchTimer),this.watchTimer=void 0)},f.prototype.on=function(t,e){var i=this.listeners[t];i||(i=[],this.listeners[t]=i),i.push(e),this._updateEventEmitters()},f.prototype._updateEventEmitters=function(){if(this.listeners){var t=this;z.forEach(this.listeners,function(e,i){if(t.emitters||(t.emitters={}),!(i in t.emitters)){var n=t.frame;if(n){var s=function(t){e.forEach(function(e){e(t)})};t.emitters[i]=s,t.hammer||(t.hammer=N(n,{prevent_default:!0})),t.hammer.on(i,s)}}})}},g.prototype=new u,g.prototype.setOptions=u.prototype.setOptions,g.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},g.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},g.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},g.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.props,r=this.step,a=this.frame;if(a||(a=document.createElement("div"),this.frame=a,t+=1),a.className="axis",!a.parentNode){if(!this.parent)throw new Error("Cannot repaint time axis: no parent attached");var h=this.parent.getContainer();if(!h)throw new Error("Cannot repaint time axis: parent has no container element");h.appendChild(a),t+=1}var d=a.parentNode;if(d){var c=a.nextSibling;d.removeChild(a);var l="bottom"==s&&this.props.parentHeight&&this.height?this.props.parentHeight-this.height+"px":"0px";if(t+=e(a.style,"top",i(n.top,l)),t+=e(a.style,"left",i(n.left,"0px")),t+=e(a.style,"width",i(n.width,"100%")),t+=e(a.style,"height",i(n.height,this.height+"px")),this._repaintMeasureChars(),this.step){this._repaintStart(),r.first();for(var u=void 0,p=0;r.hasNext()&&1e3>p;){p++;var f=r.getCurrent(),g=this.toScreen(f),m=r.isMajor();this.getOption("showMinorLabels")&&this._repaintMinorText(g,r.getLabelMinor()),m&&this.getOption("showMajorLabels")?(g>0&&(void 0==u&&(u=g),this._repaintMajorText(g,r.getLabelMajor())),this._repaintMajorLine(g)):this._repaintMinorLine(g),r.next()}if(this.getOption("showMajorLabels")){var v=this.toTime(0),y=r.getLabelMajor(v),_=y.length*(o.majorCharWidth||10)+10;(void 0==u||u>_)&&this._repaintMajorText(0,y)}this._repaintEnd()}this._repaintLine(),c?d.insertBefore(a,c):d.appendChild(a)}return t>0},g.prototype._repaintStart=function(){var t=this.dom,e=t.redundant;e.majorLines=t.majorLines,e.majorTexts=t.majorTexts,e.minorLines=t.minorLines,e.minorTexts=t.minorTexts,t.majorLines=[],t.majorTexts=[],t.minorLines=[],t.minorTexts=[]},g.prototype._repaintEnd=function(){z.forEach(this.dom.redundant,function(t){for(;t.length;){var e=t.pop();e&&e.parentNode&&e.parentNode.removeChild(e)}})},g.prototype._repaintMinorText=function(t,e){var i=this.dom.redundant.minorTexts.shift();if(!i){var n=document.createTextNode("");i=document.createElement("div"),i.appendChild(n),i.className="text minor",this.frame.appendChild(i)}this.dom.minorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.left=t+"px",i.style.top=this.props.minorLabelTop+"px"},g.prototype._repaintMajorText=function(t,e){var i=this.dom.redundant.majorTexts.shift();if(!i){var n=document.createTextNode(e);i=document.createElement("div"),i.className="text major",i.appendChild(n),this.frame.appendChild(i)}this.dom.majorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.top=this.props.majorLabelTop+"px",i.style.left=t+"px"},g.prototype._repaintMinorLine=function(t){var e=this.dom.redundant.minorLines.shift();e||(e=document.createElement("div"),e.className="grid vertical minor",this.frame.appendChild(e)),this.dom.minorLines.push(e);var i=this.props;e.style.top=i.minorLineTop+"px",e.style.height=i.minorLineHeight+"px",e.style.left=t-i.minorLineWidth/2+"px"},g.prototype._repaintMajorLine=function(t){var e=this.dom.redundant.majorLines.shift();e||(e=document.createElement("DIV"),e.className="grid vertical major",this.frame.appendChild(e)),this.dom.majorLines.push(e);var i=this.props;e.style.top=i.majorLineTop+"px",e.style.left=t-i.majorLineWidth/2+"px",e.style.height=i.majorLineHeight+"px"},g.prototype._repaintLine=function(){{var t=this.dom.line,e=this.frame;this.options}this.getOption("showMinorLabels")||this.getOption("showMajorLabels")?(t?(e.removeChild(t),e.appendChild(t)):(t=document.createElement("div"),t.className="grid horizontal major",e.appendChild(t),this.dom.line=t),t.style.top=this.props.lineTop+"px"):t&&t.parentElement&&(e.removeChild(t.line),delete this.dom.line)},g.prototype._repaintMeasureChars=function(){var t,e=this.dom;if(!e.measureCharMinor){t=document.createTextNode("0");var i=document.createElement("DIV");i.className="text minor measure",i.appendChild(t),this.frame.appendChild(i),e.measureCharMinor=i}if(!e.measureCharMajor){t=document.createTextNode("0");var n=document.createElement("DIV");n.className="text major measure",n.appendChild(t),this.frame.appendChild(n),e.measureCharMajor=n}},g.prototype.reflow=function(){var t=0,e=z.updateProperty,i=this.frame,n=this.range;if(!n)throw new Error("Cannot repaint time axis: no range configured");if(i){t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft);var s=this.props,o=this.getOption("showMinorLabels"),r=this.getOption("showMajorLabels"),a=this.dom.measureCharMinor,h=this.dom.measureCharMajor;a&&(s.minorCharHeight=a.clientHeight,s.minorCharWidth=a.clientWidth),h&&(s.majorCharHeight=h.clientHeight,s.majorCharWidth=h.clientWidth);var d=i.parentNode?i.parentNode.offsetHeight:0;switch(d!=s.parentHeight&&(s.parentHeight=d,t+=1),this.getOption("orientation")){case"bottom":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.minorLabelTop=0,s.majorLabelTop=s.minorLabelTop+s.minorLabelHeight,s.minorLineTop=-this.top,s.minorLineHeight=Math.max(this.top+s.majorLabelHeight,0),s.minorLineWidth=1,s.majorLineTop=-this.top,s.majorLineHeight=Math.max(this.top+s.minorLabelHeight+s.majorLabelHeight,0),s.majorLineWidth=1,s.lineTop=0;break;case"top":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.majorLabelTop=0,s.minorLabelTop=s.majorLabelTop+s.majorLabelHeight,s.minorLineTop=s.minorLabelTop,s.minorLineHeight=Math.max(d-s.majorLabelHeight-this.top),s.minorLineWidth=1,s.majorLineTop=0,s.majorLineHeight=Math.max(d-this.top),s.majorLineWidth=1,s.lineTop=s.majorLabelHeight+s.minorLabelHeight;break;default:throw new Error('Unkown orientation "'+this.getOption("orientation")+'"')}var c=s.minorLabelHeight+s.majorLabelHeight;t+=e(this,"width",i.offsetWidth),t+=e(this,"height",c),this._updateConversion();var l=z.convert(n.start,"Number"),u=z.convert(n.end,"Number"),p=this.toTime(5*(s.minorCharWidth||10)).valueOf()-this.toTime(0).valueOf();this.step=new TimeStep(new Date(l),new Date(u),p),t+=e(s.range,"start",l),t+=e(s.range,"end",u),t+=e(s.range,"minimumStep",p.valueOf())}return t>0},g.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},m.prototype=new u,m.prototype.setOptions=u.prototype.setOptions,m.prototype.getContainer=function(){return this.frame},m.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCurrentTime"))return void(t&&(i.removeChild(t),delete this.frame));t||(t=document.createElement("div"),t.className="currenttime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t),this.frame=t),e.conversion||e._updateConversion();var n=new Date,s=e.toScreen(n);t.style.left=s+"px",t.title="Current time: "+n,void 0!==this.currentTimeTimer&&(clearTimeout(this.currentTimeTimer),delete this.currentTimeTimer);var o=this,r=1/e.conversion.scale/2;return 30>r&&(r=30),this.currentTimeTimer=setTimeout(function(){o.repaint()},r),!1},v.prototype=new u,v.prototype.setOptions=u.prototype.setOptions,v.prototype.getContainer=function(){return this.frame},v.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCustomTime"))return void(t&&(i.removeChild(t),delete this.frame));if(!t){t=document.createElement("div"),t.className="customtime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t);var n=document.createElement("div");n.style.position="relative",n.style.top="0px",n.style.left="-10px",n.style.height="100%",n.style.width="20px",t.appendChild(n),this.frame=t,this.subscribe(this,"movetime")}e.conversion||e._updateConversion();var s=e.toScreen(this.customTime);return t.style.left=s+"px",t.title="Time: "+this.customTime,!1},v.prototype._setCustomTime=function(t){this.customTime=new Date(t.valueOf()),this.repaint()},v.prototype._getCustomTime=function(){return new Date(this.customTime.valueOf())},v.prototype.subscribe=function(t,e){var i=this,n={component:t,event:e,callback:function(t){i._onMouseDown(t,n)},params:{}};t.on("mousedown",n.callback),i.listeners.push(n)},v.prototype.on=function(t,e){var i=this.frame;if(!i)throw new Error("Cannot add event listener: no parent attached");F.addListener(this,t,e),z.addEventListener(i,t,e)},v.prototype._onMouseDown=function(t,e){t=t||window.event;var i=e.params,n=t.which?1==t.which:1==t.button;if(n){i.mouseX=z.getPageX(t),i.moved=!1,i.customTime=this.customTime;var s=this;i.onMouseMove||(i.onMouseMove=function(t){s._onMouseMove(t,e)},z.addEventListener(document,"mousemove",i.onMouseMove)),i.onMouseUp||(i.onMouseUp=function(t){s._onMouseUp(t,e)},z.addEventListener(document,"mouseup",i.onMouseUp)),z.stopPropagation(t),z.preventDefault(t)}},v.prototype._onMouseMove=function(t,e){t=t||window.event;var i=e.params,n=this.parent,s=z.getPageX(t);void 0===i.mouseX&&(i.mouseX=s);var o=s-i.mouseX;Math.abs(o)>=1&&(i.moved=!0);var r=n.toScreen(i.customTime),a=r+o,h=n.toTime(a);this._setCustomTime(h),F.trigger(this,"timechange",{customTime:this.customTime}),z.preventDefault(t)},v.prototype._onMouseUp=function(t,e){t=t||window.event;var i=e.params;i.onMouseMove&&(z.removeEventListener(document,"mousemove",i.onMouseMove),i.onMouseMove=null),i.onMouseUp&&(z.removeEventListener(document,"mouseup",i.onMouseUp),i.onMouseUp=null),i.moved&&F.trigger(this,"timechanged",{customTime:this.customTime})},y.prototype=new p,y.types={box:w,range:S,rangeoverflow:E,point:b},y.prototype.setOptions=u.prototype.setOptions,y.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},y.prototype.setSelection=function(t){var e,i,n,s,o;if(t){if(!Array.isArray(t))throw new TypeError("Array expected");for(e=0,i=this.selection.length;i>e;e++)n=this.selection[e],s=this.items[n],s&&s.unselect();for(this.selection=[],e=0,i=t.length;i>e;e++)n=t[e],s=this.items[n],s&&(this.selection.push(n),s.select());o=this.selection.concat([]),F.trigger(this,"select",{ids:o}),this.controller&&this.requestRepaint()}},y.prototype.getSelection=function(){return this.selection.concat([])},y.prototype._deselect=function(t){for(var e=this.selection,i=0,n=e.length;n>i;i++)if(e[i]==t){e.splice(i,1);break}},y.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.defaultOptions,r=this.frame;if(!r){r=document.createElement("div"),r.className="itemset";var a=n.className;a&&z.addClassName(r,z.option.asString(a));var h=document.createElement("div");h.className="background",r.appendChild(h),this.dom.background=h;var d=document.createElement("div");d.className="foreground",r.appendChild(d),this.dom.foreground=d;var c=document.createElement("div");c.className="itemset-axis",this.dom.axis=c,this.frame=r,t+=1}if(!this.parent)throw new Error("Cannot repaint itemset: no parent attached");var l=this.parent.getContainer();if(!l)throw new Error("Cannot repaint itemset: parent has no container element");r.parentNode||(l.appendChild(r),t+=1),this.dom.axis.parentNode||(l.appendChild(this.dom.axis),t+=1),t+=e(r.style,"left",i(n.left,"0px")),t+=e(r.style,"top",i(n.top,"0px")),t+=e(r.style,"width",i(n.width,"100%")),t+=e(r.style,"height",i(n.height,this.height+"px")),t+=e(this.dom.axis.style,"left",i(n.left,"0px")),t+=e(this.dom.axis.style,"width",i(n.width,"100%")),t+="bottom"==s?e(this.dom.axis.style,"top",this.height+this.top+"px"):e(this.dom.axis.style,"top",this.top+"px"),this._updateConversion();var u=this,p=this.queue,f=this.itemsData,g=this.items,m={};for(var v in p)if(p.hasOwnProperty(v)){var _=p[v],w=g[v],b=_.action;switch(b){case"add":case"update":var S=f&&f.get(v,m);if(S){var E=S.type||S.start&&S.end&&"range"||n.type||"box",T=y.types[E];if(w&&(T&&w instanceof T?(w.data=S,t++):(t+=w.hide(),w=null)),!w){if(!T)throw new TypeError('Unknown item type "'+E+'"');w=new T(u,S,n,o),w.id=_.id,t++}w.repaint(),g[v]=w}delete p[v];break;case"remove":w&&(w.selected&&u._deselect(v),t+=w.hide()),delete g[v],delete p[v];break;default:console.log('Error: unknown action "'+b+'"')}}return z.forEach(this.items,function(e){e.visible?(t+=e.show(),e.reposition()):t+=e.hide()}),t>0},y.prototype.getForeground=function(){return this.dom.foreground},y.prototype.getBackground=function(){return this.dom.background},y.prototype.getAxis=function(){return this.dom.axis},y.prototype.reflow=function(){var t=0,e=this.options,i=e.margin&&e.margin.axis||this.defaultOptions.margin.axis,n=e.margin&&e.margin.item||this.defaultOptions.margin.item,s=z.updateProperty,o=z.option.asNumber,r=z.option.asSize,a=this.frame;if(a){this._updateConversion(),z.forEach(this.items,function(e){t+=e.reflow()}),this.stack.update();var h,d=o(e.maxHeight),c=null!=r(e.height);if(c)h=a.offsetHeight;else{var l=this.stack.ordered;if(l.length){var u=l[0].top,p=l[0].top+l[0].height;z.forEach(l,function(t){u=Math.min(u,t.top),p=Math.max(p,t.top+t.height)}),h=p-u+i+n}else h=i+n}null!=d&&(h=Math.min(h,d)),t+=s(this,"height",h),t+=s(this,"top",a.offsetTop),t+=s(this,"left",a.offsetLeft),t+=s(this,"width",a.offsetWidth)}else t+=1;return t>0},y.prototype.hide=function(){var t=!1;return this.frame&&this.frame.parentNode&&(this.frame.parentNode.removeChild(this.frame),t=!0),this.dom.axis&&this.dom.axis.parentNode&&(this.dom.axis.parentNode.removeChild(this.dom.axis),t=!0),t -},y.prototype.setItems=function(t){var e,i=this,n=this.itemsData;if(t){if(!(t instanceof o||t instanceof r))throw new TypeError("Data must be an instance of DataSet");this.itemsData=t}else this.itemsData=null;if(n&&(z.forEach(this.listeners,function(t,e){n.unsubscribe(e,t)}),e=n.getIds(),this._onRemove(e)),this.itemsData){var s=this.id;z.forEach(this.listeners,function(t,e){i.itemsData.subscribe(e,t,s)}),e=this.itemsData.getIds(),this._onAdd(e)}},y.prototype.getItems=function(){return this.itemsData},y.prototype._onUpdate=function(t){this._toQueue("update",t)},y.prototype._onAdd=function(t){this._toQueue("add",t)},y.prototype._onRemove=function(t){this._toQueue("remove",t)},y.prototype._toQueue=function(t,e){var i=this.queue;e.forEach(function(e){i[e]={id:e,action:t}}),this.controller&&this.requestRepaint()},y.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},y.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},y.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},_.prototype.select=function(){this.selected=!0,this.visible&&this.repaint()},_.prototype.unselect=function(){this.selected=!1,this.visible&&this.repaint()},_.prototype.show=function(){return!1},_.prototype.hide=function(){return!1},_.prototype.repaint=function(){return!1},_.prototype.reflow=function(){return!1},_.prototype.getWidth=function(){return this.width},w.prototype=new _(null,null),w.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");if(!e.box.parentNode){var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");i.appendChild(e.box),t=!0}if(!e.line.parentNode){var n=this.parent.getBackground();if(!n)throw new Error("Cannot repaint time axis: parent has no background container element");n.appendChild(e.line),t=!0}if(!e.dot.parentNode){var s=this.parent.getAxis();if(!n)throw new Error("Cannot repaint time axis: parent has no axis container element");s.appendChild(e.dot),t=!0}if(this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var o=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=o&&(this.className=o,e.box.className="item box"+o,e.line.className="item line"+o,e.dot.className="item dot"+o,t=!0)}return t},w.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},w.prototype.hide=function(){var t=!1,e=this.dom;return e&&(e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),e.line.parentNode&&e.line.parentNode.removeChild(e.line),e.dot.parentNode&&e.dot.parentNode.removeChild(e.dot)),t},w.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,d,c,l,u=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(c=this.data,l=this.parent&&this.parent.range,c&&l){var p=l.end-l.start;this.visible=c.start>l.start-p&&c.start0},w.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("DIV"),t.content=document.createElement("DIV"),t.content.className="content",t.box.appendChild(t.content),t.line=document.createElement("DIV"),t.line.className="line",t.dot=document.createElement("DIV"),t.dot.className="dot",t.box["timeline-item"]=this)},w.prototype.reposition=function(){var t=this.dom,e=this.props,i=this.options.orientation||this.defaultOptions.orientation;if(t){var n=t.box,s=t.line,o=t.dot;n.style.left=this.left+"px",n.style.top=this.top+"px",s.style.left=e.line.left+"px","top"==i?(s.style.top="0px",s.style.height=this.top+"px"):(s.style.top=this.top+this.height+"px",s.style.height=Math.max(this.parent.height-this.top-this.height+this.props.dot.height/2,0)+"px"),o.style.left=e.dot.left+"px",o.style.top=e.dot.top+"px"}},b.prototype=new _(null,null),b.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.point.parentNode||(i.appendChild(e.point),i.appendChild(e.point),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.point.className="item point"+n,t=!0)}return t},b.prototype.show=function(){return this.dom&&this.dom.point.parentNode?!1:this.repaint()},b.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.point.parentNode&&(e.point.parentNode.removeChild(e.point),t=!0),t},b.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,d,c=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(h=this.data,d=this.parent&&this.parent.range,h&&d){var l=d.end-d.start;this.visible=h.start>d.start-l&&h.start0},b.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.point=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.point.appendChild(t.content),t.dot=document.createElement("div"),t.dot.className="dot",t.point.appendChild(t.dot),t.point["timeline-item"]=this)},b.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.point.style.top=this.top+"px",t.point.style.left=this.left+"px",t.content.style.marginLeft=e.content.marginLeft+"px",t.dot.style.top=e.dot.top+"px")},S.prototype=new _(null,null),S.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.box.className="item range"+n,t=!0)}return t},S.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},S.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),t},S.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,d,c,l,u,p,f,g,m=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(void 0==this.data.end)throw new Error('Property "end" missing in item '+this.data.id);return h=this.data,d=this.parent&&this.parent.range,this.visible=h&&d?h.startd.start:!1,this.visible&&(t=this.dom,t?(e=this.props,i=this.options,o=this.parent,r=o.toScreen(this.data.start),a=o.toScreen(this.data.end),c=z.updateProperty,l=t.box,u=o.width,f=i.orientation||this.defaultOptions.orientation,n=i.margin&&i.margin.axis||this.defaultOptions.margin.axis,s=i.padding||this.defaultOptions.padding,m+=c(e.content,"width",t.content.offsetWidth),m+=c(this,"height",l.offsetHeight),-u>r&&(r=-u),a>2*u&&(a=2*u),p=0>r?Math.min(-r,a-r-e.content.width-2*s):0,m+=c(e.content,"left",p),"top"==f?(g=n,m+=c(this,"top",g)):(g=o.height-this.height-n,m+=c(this,"top",g)),m+=c(this,"left",r),m+=c(this,"width",Math.max(a-r,1))):m+=1),m>0},S.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content),t.box["timeline-item"]=this)},S.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.box.style.top=this.top+"px",t.box.style.left=this.left+"px",t.box.style.width=this.width+"px",t.content.style.left=e.content.left+"px")},E.prototype=new S(null,null),E.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=this.data.className?" "+this.data.className:"";this.className!=n&&(this.className=n,e.box.className="item rangeoverflow"+n,t=!0)}return t},E.prototype.getWidth=function(){return void 0!==this.props.content&&this.width0},x.prototype=new p,x.prototype.setOptions=u.prototype.setOptions,x.prototype.setRange=function(){},x.prototype.setItems=function(t){this.itemsData=t;for(var e in this.groups)if(this.groups.hasOwnProperty(e)){var i=this.groups[e];i.setItems(t)}},x.prototype.getItems=function(){return this.itemsData},x.prototype.setRange=function(t){this.range=t},x.prototype.setGroups=function(t){var e,i=this;if(this.groupsData&&(z.forEach(this.listeners,function(t,e){i.groupsData.unsubscribe(e,t)}),e=this.groupsData.getIds(),this._onRemove(e)),t?t instanceof o?this.groupsData=t:(this.groupsData=new o({convert:{start:"Date",end:"Date"}}),this.groupsData.add(t)):this.groupsData=null,this.groupsData){var n=this.id;z.forEach(this.listeners,function(t,e){i.groupsData.subscribe(e,t,n)}),e=this.groupsData.getIds(),this._onAdd(e)}},x.prototype.getGroups=function(){return this.groupsData},x.prototype.setSelection=function(t){var e=[],i=this.groups;for(var n in i)if(i.hasOwnProperty(n)){var s=i[n];s.setSelection(t)}return e},x.prototype.getSelection=function(){var t=[],e=this.groups;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];t=t.concat(n.getSelection())}return t},x.prototype.repaint=function(){var t,e,i,n,s=0,o=z.updateProperty,r=z.option.asSize,a=z.option.asElement,h=this.options,d=this.dom.frame,c=this.dom.labels,l=this.dom.labelSet;if(!this.parent)throw new Error("Cannot repaint groupset: no parent attached");var u=this.parent.getContainer();if(!u)throw new Error("Cannot repaint groupset: parent has no container element");if(!d){d=document.createElement("div"),d.className="groupset",this.dom.frame=d;var p=h.className;p&&z.addClassName(d,z.option.asString(p)),s+=1}d.parentNode||(u.appendChild(d),s+=1);var f=a(h.labelContainer);if(!f)throw new Error('Cannot repaint groupset: option "labelContainer" not defined');c||(c=document.createElement("div"),c.className="labels",this.dom.labels=c),l||(l=document.createElement("div"),l.className="label-set",c.appendChild(l),this.dom.labelSet=l),c.parentNode&&c.parentNode==f||(c.parentNode&&c.parentNode.removeChild(c.parentNode),f.appendChild(c)),s+=o(d.style,"height",r(h.height,this.height+"px")),s+=o(d.style,"top",r(h.top,"0px")),s+=o(d.style,"left",r(h.left,"0px")),s+=o(d.style,"width",r(h.width,"100%")),s+=o(l.style,"top",r(h.top,"0px")),s+=o(l.style,"height",r(h.height,this.height+"px"));var g=this,m=this.queue,v=this.groups,y=this.groupsData,_=Object.keys(m);if(_.length){_.forEach(function(t){var e=m[t],i=v[t];switch(e){case"add":case"update":if(!i){var n=Object.create(g.options);z.extend(n,{height:null,maxHeight:null}),i=new T(g,t,n),i.setItems(g.itemsData),v[t]=i,g.controller.add(i)}i.data=y.get(t),delete m[t];break;case"remove":i&&(i.setItems(),delete v[t],g.controller.remove(i)),delete m[t];break;default:console.log('Error: unknown action "'+e+'"')}});var w=this.groupsData.getIds({order:this.options.groupOrder});for(t=0;t0},x.prototype._createLabel=function(t){var e=this.groups[t],i=document.createElement("div");i.className="label";var n=document.createElement("div");n.className="inner",i.appendChild(n);var s=e.data&&e.data.content;s instanceof Element?n.appendChild(s):void 0!=s&&(n.innerHTML=s);var o=e.data&&e.data.className;return o&&z.addClassName(i,o),e.label=i,i},x.prototype.getContainer=function(){return this.dom.frame},x.prototype.getLabelsWidth=function(){return this.props.labels.width},x.prototype.reflow=function(){var t,e,i=0,n=this.options,s=z.updateProperty,o=z.option.asNumber,r=z.option.asSize,a=this.dom.frame;if(a){var h,d=o(n.maxHeight),c=null!=r(n.height);if(c)h=a.offsetHeight;else{h=0;for(t in this.groups)this.groups.hasOwnProperty(t)&&(e=this.groups[t],h+=e.height)}null!=d&&(h=Math.min(h,d)),i+=s(this,"height",h),i+=s(this,"top",a.offsetTop),i+=s(this,"left",a.offsetLeft),i+=s(this,"width",a.offsetWidth)}var l=0;for(t in this.groups)if(this.groups.hasOwnProperty(t)){e=this.groups[t];var u=e.props&&e.props.label&&e.props.label.width||0;l=Math.max(l,u)}return i+=s(this.props.labels,"width",l),i>0},x.prototype.hide=function(){return this.dom.frame&&this.dom.frame.parentNode?(this.dom.frame.parentNode.removeChild(this.dom.frame),!0):!1},x.prototype.show=function(){return this.dom.frame&&this.dom.frame.parentNode?!1:this.repaint()},x.prototype._onUpdate=function(t){this._toQueue(t,"update")},x.prototype._onAdd=function(t){this._toQueue(t,"add")},x.prototype._onRemove=function(t){this._toQueue(t,"remove")},x.prototype._toQueue=function(t,e){var i=this.queue;t.forEach(function(t){i[t]=e}),this.controller&&this.requestRepaint()},C.prototype.setOptions=function(t){z.extend(this.options,t),this.range.setRange(t.start,t.end),this.controller.reflow(),this.controller.repaint()},C.prototype.setCustomTime=function(t){this.customtime._setCustomTime(t)},C.prototype.getCustomTime=function(){return new Date(this.customtime.customTime.valueOf())},C.prototype.setItems=function(t){var e,i=null==this.itemsData;if(t?t instanceof o&&(e=t):e=null,t instanceof o||(e=new o({convert:{start:"Date",end:"Date"}}),e.add(t)),this.itemsData=e,this.content.setItems(e),i&&(void 0==this.options.start||void 0==this.options.end)){var n=this.getItemRange(),s=n.min,r=n.max;if(null!=s&&null!=r){var a=r.valueOf()-s.valueOf();0>=a&&(a=864e5),s=new Date(s.valueOf()-.05*a),r=new Date(r.valueOf()+.05*a)}void 0!=this.options.start&&(s=z.convert(this.options.start,"Date")),void 0!=this.options.end&&(r=z.convert(this.options.end,"Date")),(null!=s||null!=r)&&this.range.setRange(s,r)}},C.prototype.setGroups=function(t){var e=this;this.groupsData=t;var i=this.groupsData?x:y;if(!(this.content instanceof i)){this.content&&(this.content.hide(),this.content.setItems&&this.content.setItems(),this.content.setGroups&&this.content.setGroups(),this.controller.remove(this.content));var n=Object.create(this.options);z.extend(n,{top:function(){return"top"==e.options.orientation?e.timeaxis.height:e.itemPanel.height-e.timeaxis.height-e.content.height},left:null,width:"100%",height:function(){return e.options.height?e.itemPanel.height-e.timeaxis.height:null},maxHeight:function(){if(e.options.maxHeight){if(!z.isNumber(e.options.maxHeight))throw new TypeError("Number expected for property maxHeight");return e.options.maxHeight-e.timeaxis.height}return null},labelContainer:function(){return e.labelPanel.getContainer()}}),this.content=new i(this.itemPanel,[this.timeaxis],n),this.content.setRange&&this.content.setRange(this.range),this.content.setItems&&this.content.setItems(this.itemsData),this.content.setGroups&&this.content.setGroups(this.groupsData),this.controller.add(this.content)}},C.prototype.getItemRange=function(){var t=this.itemsData,e=null,i=null;if(t){var n=t.min("start");e=n?n.start.valueOf():null;var s=t.max("start");s&&(i=s.start.valueOf());var o=t.max("end");o&&(i=null==i?o.end.valueOf():Math.max(i,o.end.valueOf()))}return{min:null!=e?new Date(e):null,max:null!=i?new Date(i):null}},C.prototype.setSelection=function(t){this.content&&this.content.setSelection(t)},C.prototype.getSelection=function(){return this.content?this.content.getSelection():[]},C.prototype.on=function(t,e){var i=["rangechange","rangechanged","select"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());F.addListener(this,t,e)},C.prototype.off=function(t,e){F.removeListener(this,t,e)},C.prototype._trigger=function(t,e){F.trigger(this,t,e||{})},C.prototype._onSelectItem=function(t){var e=this._itemFromTarget(t),i=e?[e.id]:[];this.setSelection(i),this._trigger("select",{items:this.getSelection()}),t.stopPropagation()},C.prototype._onMultiSelectItem=function(t){var e,i=this._itemFromTarget(t);if(i){e=this.getSelection();var n=e.indexOf(i.id);-1==n?e.push(i.id):e.splice(n,1),this.setSelection(e),this._trigger("select",{items:this.getSelection()}),t.stopPropagation()}},C.prototype._itemFromTarget=function(t){for(var e=t.target;e;){if(e.hasOwnProperty("timeline-item"))return e["timeline-item"];e=e.parentNode}return null},function(t){function e(t){return C=t,u()}function i(){M=0,D=C.charAt(0)}function n(){M++,D=C.charAt(M)}function s(){return C.charAt(M+1)}function o(t){return N.test(t)}function r(t,e){if(t||(t={}),e)for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function a(t,e,i){for(var n=e.split("."),s=t;n.length;){var o=n.shift();n.length?(s[o]||(s[o]={}),s=s[o]):s[o]=i}}function h(t,e){for(var i,n,s=null,o=[t],a=t;a.parent;)o.push(a.parent),a=a.parent;if(a.nodes)for(i=0,n=a.nodes.length;n>i;i++)if(e.id===a.nodes[i].id){s=a.nodes[i];break}for(s||(s={id:e.id},t.node&&(s.attr=r(s.attr,t.node))),i=o.length-1;i>=0;i--){var h=o[i];h.nodes||(h.nodes=[]),-1==h.nodes.indexOf(s)&&h.nodes.push(s)}e.attr&&(s.attr=r(s.attr,e.attr))}function d(t,e){if(t.edges||(t.edges=[]),t.edges.push(e),t.edge){var i=r({},t.edge);e.attr=r(i,e.attr)}}function c(t,e,i,n,s){var o={from:e,to:i,type:n};return t.edge&&(o.attr=r({},t.edge)),o.attr=r(o.attr||{},s),o}function l(){for(O=T.NULL,I="";" "==D||" "==D||"\n"==D||"\r"==D;)n();do{var t=!1;if("#"==D){for(var e=M-1;" "==C.charAt(e)||" "==C.charAt(e);)e--;if("\n"==C.charAt(e)||""==C.charAt(e)){for(;""!=D&&"\n"!=D;)n();t=!0}}if("/"==D&&"/"==s()){for(;""!=D&&"\n"!=D;)n();t=!0}if("/"==D&&"*"==s()){for(;""!=D;){if("*"==D&&"/"==s()){n(),n();break}n()}t=!0}for(;" "==D||" "==D||"\n"==D||"\r"==D;)n()}while(t);if(""==D)return void(O=T.DELIMITER);var i=D+s();if(x[i])return O=T.DELIMITER,I=i,n(),void n();if(x[D])return O=T.DELIMITER,I=D,void n();if(o(D)||"-"==D){for(I+=D,n();o(D);)I+=D,n();return"false"==I?I=!1:"true"==I?I=!0:isNaN(Number(I))||(I=Number(I)),void(O=T.IDENTIFIER)}if('"'==D){for(n();""!=D&&('"'!=D||'"'==D&&'"'==s());)I+=D,'"'==D&&n(),n();if('"'!=D)throw w('End of string " expected');return n(),void(O=T.IDENTIFIER)}for(O=T.UNKNOWN;""!=D;)I+=D,n();throw new SyntaxError('Syntax error in part "'+b(I,30)+'"')}function u(){var t={};if(i(),l(),"strict"==I&&(t.strict=!0,l()),("graph"==I||"digraph"==I)&&(t.type=I,l()),O==T.IDENTIFIER&&(t.id=I,l()),"{"!=I)throw w("Angle bracket { expected");if(l(),p(t),"}"!=I)throw w("Angle bracket } expected");if(l(),""!==I)throw w("End of file expected");return l(),delete t.node,delete t.edge,delete t.graph,t}function p(t){for(;""!==I&&"}"!=I;)f(t),";"==I&&l()}function f(t){var e=g(t);if(e)return void y(t,e);var i=m(t);if(!i){if(O!=T.IDENTIFIER)throw w("Identifier expected");var n=I;if(l(),"="==I){if(l(),O!=T.IDENTIFIER)throw w("Identifier expected");t[n]=I,l()}else v(t,n)}}function g(t){var e=null;if("subgraph"==I&&(e={},e.type="subgraph",l(),O==T.IDENTIFIER&&(e.id=I,l())),"{"==I){if(l(),e||(e={}),e.parent=t,e.node=t.node,e.edge=t.edge,e.graph=t.graph,p(e),"}"!=I)throw w("Angle bracket } expected");l(),delete e.node,delete e.edge,delete e.graph,delete e.parent,t.subgraphs||(t.subgraphs=[]),t.subgraphs.push(e)}return e}function m(t){return"node"==I?(l(),t.node=_(),"node"):"edge"==I?(l(),t.edge=_(),"edge"):"graph"==I?(l(),t.graph=_(),"graph"):null}function v(t,e){var i={id:e},n=_();n&&(i.attr=n),h(t,i),y(t,e)}function y(t,e){for(;"->"==I||"--"==I;){var i,n=I;l();var s=g(t);if(s)i=s;else{if(O!=T.IDENTIFIER)throw w("Identifier or subgraph expected");i=I,h(t,{id:i}),l()}var o=_(),r=c(t,e,i,n,o);d(t,r),e=i}}function _(){for(var t=null;"["==I;){for(l(),t={};""!==I&&"]"!=I;){if(O!=T.IDENTIFIER)throw w("Attribute name expected");var e=I;if(l(),"="!=I)throw w("Equal sign = expected");if(l(),O!=T.IDENTIFIER)throw w("Attribute value expected");var i=I;a(t,e,i),l(),","==I&&l()}if("]"!=I)throw w("Bracket ] expected");l()}return t}function w(t){return new SyntaxError(t+', got "'+b(I,30)+'" (char '+M+")")}function b(t,e){return t.length<=e?t:t.substr(0,27)+"..."}function S(t,e,i){t instanceof Array?t.forEach(function(t){e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}):e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}function E(t){function i(t){var e={from:t.from,to:t.to};return r(e,t.attr),e.style="->"==t.type?"arrow":"line",e}var n=e(t),s={nodes:[],edges:[],options:{}};return n.nodes&&n.nodes.forEach(function(t){var e={id:t.id,label:String(t.label||t.id)};r(e,t.attr),e.image&&(e.shape="image"),s.nodes.push(e)}),n.edges&&n.edges.forEach(function(t){var e,n;e=t.from instanceof Object?t.from.nodes:{id:t.from},n=t.to instanceof Object?t.to.nodes:{id:t.to},t.from instanceof Object&&t.from.edges&&t.from.edges.forEach(function(t){var e=i(t);s.edges.push(e)}),S(e,n,function(e,n){var o=c(s,e.id,n.id,t.type,t.attr),r=i(o);s.edges.push(r)}),t.to instanceof Object&&t.to.edges&&t.to.edges.forEach(function(t){var e=i(t);s.edges.push(e)})}),n.attr&&(s.options=n.attr),s}var T={NULL:0,DELIMITER:1,IDENTIFIER:2,UNKNOWN:3},x={"{":!0,"}":!0,"[":!0,"]":!0,";":!0,"=":!0,",":!0,"->":!0,"--":!0},C="",M=0,D="",I="",O=T.NULL,N=/[a-zA-Z_0-9.:#]/;t.parseDOT=e,t.DOTToGraph=E}("undefined"!=typeof z?z:n),"undefined"!=typeof CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.circle=function(t,e,i){this.beginPath(),this.arc(t,e,i,0,2*Math.PI,!1)},CanvasRenderingContext2D.prototype.square=function(t,e,i){this.beginPath(),this.rect(t-i,e-i,2*i,2*i)},CanvasRenderingContext2D.prototype.triangle=function(t,e,i){this.beginPath();var n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e-(r-o)),this.lineTo(t+s,e+o),this.lineTo(t-s,e+o),this.lineTo(t,e-(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.triangleDown=function(t,e,i){this.beginPath();var n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e+(r-o)),this.lineTo(t+s,e-o),this.lineTo(t-s,e-o),this.lineTo(t,e+(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.star=function(t,e,i){this.beginPath();for(var n=0;10>n;n++){var s=n%2===0?1.3*i:.5*i;this.lineTo(t+s*Math.sin(2*n*Math.PI/10),e-s*Math.cos(2*n*Math.PI/10))}this.closePath()},CanvasRenderingContext2D.prototype.roundRect=function(t,e,i,n,s){var o=Math.PI/180;0>i-2*s&&(s=i/2),0>n-2*s&&(s=n/2),this.beginPath(),this.moveTo(t+s,e),this.lineTo(t+i-s,e),this.arc(t+i-s,e+s,s,270*o,360*o,!1),this.lineTo(t+i,e+n-s),this.arc(t+i-s,e+n-s,s,0,90*o,!1),this.lineTo(t+s,e+n),this.arc(t+s,e+n-s,s,90*o,180*o,!1),this.lineTo(t,e+s),this.arc(t+s,e+s,s,180*o,270*o,!1)},CanvasRenderingContext2D.prototype.ellipse=function(t,e,i,n){var s=.5522848,o=i/2*s,r=n/2*s,a=t+i,h=e+n,d=t+i/2,c=e+n/2;this.beginPath(),this.moveTo(t,c),this.bezierCurveTo(t,c-r,d-o,e,d,e),this.bezierCurveTo(d+o,e,a,c-r,a,c),this.bezierCurveTo(a,c+r,d+o,h,d,h),this.bezierCurveTo(d-o,h,t,c+r,t,c)},CanvasRenderingContext2D.prototype.database=function(t,e,i,n){var s=1/3,o=i,r=n*s,a=.5522848,h=o/2*a,d=r/2*a,c=t+o,l=e+r,u=t+o/2,p=e+r/2,f=e+(n-r/2),g=e+n;this.beginPath(),this.moveTo(c,p),this.bezierCurveTo(c,p+d,u+h,l,u,l),this.bezierCurveTo(u-h,l,t,p+d,t,p),this.bezierCurveTo(t,p-d,u-h,e,u,e),this.bezierCurveTo(u+h,e,c,p-d,c,p),this.lineTo(c,f),this.bezierCurveTo(c,f+d,u+h,g,u,g),this.bezierCurveTo(u-h,g,t,f+d,t,f),this.lineTo(t,p)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,n){var s=t-n*Math.cos(i),o=e-n*Math.sin(i),r=t-.9*n*Math.cos(i),a=e-.9*n*Math.sin(i),h=s+n/3*Math.cos(i+.5*Math.PI),d=o+n/3*Math.sin(i+.5*Math.PI),c=s+n/3*Math.cos(i-.5*Math.PI),l=o+n/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,d),this.lineTo(r,a),this.lineTo(c,l),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,n,s){s||(s=[10,5]),0==u&&(u=.001);var o=s.length;this.moveTo(t,e);for(var r=i-t,a=n-e,h=a/r,d=Math.sqrt(r*r+a*a),c=0,l=!0;d>=.1;){var u=s[c++%o];u>d&&(u=d);var p=Math.sqrt(u*u/(1+h*h));0>r&&(p=-p),t+=p,e+=h*p,this[l?"lineTo":"moveTo"](t,e),d-=u,l=!l}}),M.prototype.resetCluster=function(){this.formationScale=void 0,this.clusterSize=1,this.containedNodes={},this.containedEdges={},this.clusterSessions=[]},M.prototype.attachEdge=function(t){-1==this.edges.indexOf(t)&&this.edges.push(t),-1==this.dynamicEdges.indexOf(t)&&this.dynamicEdges.push(t),this.dynamicEdgesLength=this.dynamicEdges.length,this._updateMass()},M.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&(this.edges.splice(e,1),this.dynamicEdges.splice(e,1)),this.dynamicEdgesLength=this.dynamicEdges.length,this._updateMass()},M.prototype._updateMass=function(){this.mass=1+.6*this.edges.length},M.prototype.setProperties=function(t,e){if(t){if(this.originalLabel=void 0,void 0!==t.id&&(this.id=t.id),void 0!==t.label&&(this.label=t.label,this.originalLabel=t.label),void 0!==t.title&&(this.title=t.title),void 0!==t.group&&(this.group=t.group),void 0!==t.x&&(this.x=t.x),void 0!==t.y&&(this.y=t.y),void 0!==t.value&&(this.value=t.value),void 0!==t.horizontalAlignLeft&&(this.horizontalAlignLeft=t.horizontalAlignLeft),void 0!==t.verticalAlignTop&&(this.verticalAlignTop=t.verticalAlignTop),void 0!==t.triggerFunction&&(this.triggerFunction=t.triggerFunction),void 0===this.id)throw"Node must have an id";if(this.group){var i=this.grouplist.get(this.group);for(var n in i)i.hasOwnProperty(n)&&(this[n]=i[n])}if(void 0!==t.shape&&(this.shape=t.shape),void 0!==t.image&&(this.image=t.image),void 0!==t.radius&&(this.radius=t.radius),void 0!==t.color&&(this.color=M.parseColor(t.color)),void 0!==t.fontColor&&(this.fontColor=t.fontColor),void 0!==t.fontSize&&(this.fontSize=t.fontSize),void 0!==t.fontFace&&(this.fontFace=t.fontFace),void 0!==this.image){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.image)}switch(this.xFixed=this.xFixed||void 0!==t.x,this.yFixed=this.yFixed||void 0!==t.y,this.radiusFixed=this.radiusFixed||void 0!==t.radius,"image"==this.shape&&(this.radiusMin=e.nodes.widthMin,this.radiusMax=e.nodes.widthMax),this.shape){case"database":this.draw=this._drawDatabase,this.resize=this._resizeDatabase;break;case"box":this.draw=this._drawBox,this.resize=this._resizeBox;break;case"circle":this.draw=this._drawCircle,this.resize=this._resizeCircle;break;case"ellipse":this.draw=this._drawEllipse,this.resize=this._resizeEllipse;break;case"image":this.draw=this._drawImage,this.resize=this._resizeImage;break;case"text":this.draw=this._drawText,this.resize=this._resizeText;break;case"dot":this.draw=this._drawDot,this.resize=this._resizeShape;break;case"square":this.draw=this._drawSquare,this.resize=this._resizeShape;break;case"triangle":this.draw=this._drawTriangle,this.resize=this._resizeShape;break;case"triangleDown":this.draw=this._drawTriangleDown,this.resize=this._resizeShape;break;case"star":this.draw=this._drawStar,this.resize=this._resizeShape;break;default:this.draw=this._drawEllipse,this.resize=this._resizeEllipse}this._reset()}},M.parseColor=function(t){var e;return z.isString(t)?e={border:t,background:t,highlight:{border:t,background:t}}:(e={},e.background=t.background||"white",e.border=t.border||e.background,z.isString(t.highlight)?e.highlight={border:t.highlight,background:t.highlight}:(e.highlight={},e.highlight.background=t.highlight&&t.highlight.background||e.background,e.highlight.border=t.highlight&&t.highlight.border||e.border)),e},M.prototype.select=function(){this.selected=!0,this._reset()},M.prototype.unselect=function(){this.selected=!1,this._reset()},M.prototype.clearSizeCache=function(){this._reset()},M.prototype._reset=function(){this.width=void 0,this.height=void 0},M.prototype.getTitle=function(){return this.title},M.prototype.distanceToBorder=function(t,e){var i=1;switch(this.width||this.resize(t),this.shape){case"circle":case"dot":return this.radius+i;case"ellipse":var n=this.width/2,s=this.height/2,o=Math.sin(e)*n,r=Math.cos(e)*s; -return n*s/Math.sqrt(o*o+r*r);case"box":case"image":case"text":default:return this.width?Math.min(Math.abs(this.width/2/Math.cos(e)),Math.abs(this.height/2/Math.sin(e)))+i:0}},M.prototype._setForce=function(t,e){this.fx=t,this.fy=e},M.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},M.prototype.discreteStep=function(t){if(!this.xFixed){var e=-this.damping*this.vx,i=(this.fx+e)/this.mass;this.vx+=i*t,this.x+=this.vx*t}if(!this.yFixed){var n=-this.damping*this.vy,s=(this.fy+n)/this.mass;this.vy+=s*t,this.y+=this.vy*t}},M.prototype.isFixed=function(){return this.xFixed&&this.yFixed},M.prototype.isMoving=function(t){return Math.abs(this.vx)>t||Math.abs(this.vy)>t?!0:(this.vx=0,this.vy=0,!1)},M.prototype.isSelected=function(){return this.selected},M.prototype.getValue=function(){return this.value},M.prototype.getDistance=function(t,e){var i=this.x-t,n=this.y-e;return Math.sqrt(i*i+n*n)},M.prototype.setValueRange=function(t,e){if(!this.radiusFixed&&void 0!==this.value)if(e==t)this.radius=(this.radiusMin+this.radiusMax)/2;else{var i=(this.radiusMax-this.radiusMin)/(e-t);this.radius=(this.value-t)*i+this.radiusMin}this.baseRadiusValue=this.radius},M.prototype.draw=function(){throw"Draw method not initialized for node"},M.prototype.resize=function(){throw"Resize method not initialized for node"},M.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},M.prototype._resizeImage=function(){if(!this.width||!this.height){var t,e;if(this.value){this.radius=this.baseRadiusValue;var i=this.imageObj.height/this.imageObj.width;void 0!==i?(t=this.radius||this.imageObj.width,e=this.radius*i||this.imageObj.height):(t=0,e=0)}else t=this.imageObj.width,e=this.imageObj.height;this.width=t,this.height=e,this.width>0&&this.height>0&&(this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor)}},M.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e;if(0!=this.imageObj.width){if(this.clusterSize>1){var i=this.clusterSize>1?10:0;i*=this.graphScaleInv,i=Math.min(.2*this.width,i),t.globalAlpha=.5,t.drawImage(this.imageObj,this.left-i,this.top-i,this.width+2*i,this.height+2*i)}t.globalAlpha=1,t.drawImage(this.imageObj,this.left,this.top,this.width,this.height),e=this.y+this.height/2}else e=this.y;this._label(t,this.label,this.x,e,void 0,"top")},M.prototype._resizeBox=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=.5*(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=.5*(this.clusterSize-1)*this.clusterSizeHeightFactor}},M.prototype._drawBox=function(t){this._resizeBox(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.roundRect(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth,this.radius),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.roundRect(this.left,this.top,this.width,this.height,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeDatabase=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=i.width+2*e;this.width=n,this.height=n,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawDatabase=function(t){this._resizeDatabase(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.database(this.x-this.width/2-2*t.lineWidth,this.y-.5*this.height-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.database(this.x-this.width/2,this.y-.5*this.height,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=Math.max(i.width,i.height)+2*e;this.radius=n/2,this.width=n,this.height=n,this.radius+=.5*(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawCircle=function(t){this._resizeCircle(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.circle(this.x,this.y,this.radius+2*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.circle(this.x,this.y,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeEllipse=function(t){if(!this.width){var e=this.getTextSize(t);this.width=1.5*e.width,this.height=2*e.height,this.width1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.ellipse(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.ellipse(this.left,this.top,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._drawDot=function(t){this._drawShape(t,"circle")},M.prototype._drawTriangle=function(t){this._drawShape(t,"triangle")},M.prototype._drawTriangleDown=function(t){this._drawShape(t,"triangleDown")},M.prototype._drawSquare=function(t){this._drawShape(t,"square")},M.prototype._drawStar=function(t){this._drawShape(t,"star")},M.prototype._resizeShape=function(){if(!this.width){this.radius=this.baseRadiusValue;var t=2*this.radius;this.width=t,this.height=t,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=.5*(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawShape=function(t,e){this._resizeShape(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var i=2.5,n=2,s=2;switch(e){case"dot":s=2;break;case"square":s=2;break;case"triangle":s=3;break;case"triangleDown":s=3;break;case"star":s=4}t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?n:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t[e](this.x,this.y,this.radius+s*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?n:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t[e](this.x,this.y,this.radius),t.fill(),t.stroke(),this.label&&this._label(t,this.label,this.x,this.y+this.height/2,void 0,"top")},M.prototype._resizeText=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawText=function(t){this._resizeText(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,this._label(t,this.label,this.x,this.y)},M.prototype._label=function(t,e,i,n,s,o){if(e){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle=this.fontColor||"black",t.textAlign=s||"center",t.textBaseline=o||"middle";for(var r=e.split("\n"),a=r.length,h=this.fontSize+4,d=n+(1-a)/2*h,c=0;a>c;c++)t.fillText(r[c],i,d),d+=h}},M.prototype.getTextSize=function(t){if(void 0!==this.label){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace;for(var e=this.label.split("\n"),i=(this.fontSize+4)*e.length,n=0,s=0,o=e.length;o>s;s++)n=Math.max(n,t.measureText(e[s]).width);return{width:n,height:i}}return{width:0,height:0}},M.prototype.inArea=function(){return void 0!==this.width?this.x+this.width*this.graphScaleInv>=this.canvasTopLeft.x&&this.x-this.width*this.graphScaleInv=this.canvasTopLeft.y&&this.y-this.height*this.graphScaleInv=this.canvasTopLeft.x&&this.x=this.canvasTopLeft.y&&this.yh},D.prototype._drawLine=function(t){t.strokeStyle=this.color,t.lineWidth=this._getLineWidth();var e;if(this.from!=this.to)this._line(t),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y));else{var i,n,s=this.length/4,o=this.from;o.width||o.resize(t),o.width>o.height?(i=o.x+o.width/2,n=o.y-s):(i=o.x+s,n=o.y-o.height/2),this._circle(t,i,n,s),e=this._pointOnCircle(i,n,s,.5),this._label(t,this.label,e.x,e.y)}},D.prototype._getLineWidth=function(){return this.from.selected||this.to.selected?Math.min(2*this.width,this.widthMax)*this.graphScaleInv:this.width*this.graphScaleInv},D.prototype._line=function(t){t.beginPath(),t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y),t.stroke()},D.prototype._circle=function(t,e,i,n){t.beginPath(),t.arc(e,i,n,0,2*Math.PI,!1),t.stroke()},D.prototype._label=function(t,e,i,n){if(e){t.font=(this.from.selected||this.to.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle="white";var s=t.measureText(e).width,o=this.fontSize,r=i-s/2,a=n-o/2;t.fillRect(r,a,s,o),t.fillStyle=this.fontColor||"black",t.textAlign="left",t.textBaseline="top",t.fillText(e,r,a)}},D.prototype._drawDashLine=function(t){if(t.strokeStyle=this.color,t.lineWidth=this._getLineWidth(),t.beginPath(),t.lineCap="round",void 0!==this.dash.altLength?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]):void 0!==this.dash.length&&void 0!==this.dash.gap?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap]):(t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y)),t.stroke(),this.label){var e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}},D.prototype._pointOnLine=function(t){return{x:(1-t)*this.from.x+t*this.to.x,y:(1-t)*this.from.y+t*this.to.y}},D.prototype._pointOnCircle=function(t,e,i,n){var s=2*(n-3/8)*Math.PI;return{x:t+i*Math.cos(s),y:e-i*Math.sin(s)}},D.prototype._drawArrowCenter=function(t){var e;if(t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth(),this.from!=this.to){this._line(t);var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),n=10+5*this.width;e=this._pointOnLine(.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y))}else{var s,o,r=this.length/4,a=this.from;a.width||a.resize(t),a.width>a.height?(s=a.x+a.width/2,o=a.y-r):(s=a.x+r,o=a.y-a.height/2),this._circle(t,s,o,r);var i=.2*Math.PI,n=10+5*this.width;e=this._pointOnCircle(s,o,r,.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(s,o,r,.5),this._label(t,this.label,e.x,e.y))}},D.prototype._drawArrow=function(t){t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth();var e,i;if(this.from!=this.to){e=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x);var n=this.to.x-this.from.x,s=this.to.y-this.from.y,o=Math.sqrt(n*n+s*s),r=this.from.distanceToBorder(t,e+Math.PI),a=(o-r)/o,h=a*this.from.x+(1-a)*this.to.x,d=a*this.from.y+(1-a)*this.to.y,c=this.to.distanceToBorder(t,e),l=(o-c)/o,u=(1-l)*this.from.x+l*this.to.x,p=(1-l)*this.from.y+l*this.to.y;if(t.beginPath(),t.moveTo(h,d),t.lineTo(u,p),t.stroke(),i=10+5*this.width,t.arrow(u,p,e,i),t.fill(),t.stroke(),this.label){var f=this._pointOnLine(.5);this._label(t,this.label,f.x,f.y)}}else{var g,m,v,y=this.from,_=this.length/4;y.width||y.resize(t),y.width>y.height?(g=y.x+y.width/2,m=y.y-_,v={x:g,y:y.y,angle:.9*Math.PI}):(g=y.x+_,m=y.y-y.height/2,v={x:y.x,y:m,angle:.6*Math.PI}),t.beginPath(),t.arc(g,m,_,0,2*Math.PI,!1),t.stroke(),i=10+5*this.width,t.arrow(v.x,v.y,v.angle,i),t.fill(),t.stroke(),this.label&&(f=this._pointOnCircle(g,m,_,.5),this._label(t,this.label,f.x,f.y))}},D._dist=function(t,e,i,n,s,o){var r=i-t,a=n-e,h=r*r+a*a,d=((s-t)*r+(o-e)*a)/h;d>1?d=1:0>d&&(d=0);var c=t+d*r,l=e+d*a,u=c-s,p=l-o;return Math.sqrt(u*u+p*p)},D.prototype.setScale=function(t){this.graphScaleInv=1/t},I.prototype.setPosition=function(t,e){this.x=parseInt(t),this.y=parseInt(e)},I.prototype.setText=function(t){this.frame.innerHTML=t},I.prototype.show=function(t){if(void 0===t&&(t=!0),t){var e=this.frame.clientHeight,i=this.frame.clientWidth,n=this.frame.parentNode.clientHeight,s=this.frame.parentNode.clientWidth,o=this.y-e;o+e+this.padding>n&&(o=n-e-this.padding),os&&(r=s-i-this.padding),r1)return this.activeSector[this.activeSector.length-2];throw new TypeError("there are not enough sectors in the this.activeSector array.")},_setActiveSector:function(t){this.activeSector.push(t)},_forgetLastSector:function(){this.activeSector.pop()},_createNewSector:function(t){this.sectors.active[t]={nodes:{},edges:{},nodeIndices:[],formationScale:this.scale,drawingNode:void 0},this.sectors.active[t].drawingNode=new M({id:t,color:{background:"#eaefef",border:"495c5e"}},{},{},this.constants),this.sectors.active[t].drawingNode.clusterSize=2},_deleteActiveSector:function(t){delete this.sectors.active[t]},_deleteFrozenSector:function(t){delete this.sectors.frozen[t]},_freezeSector:function(t){this.sectors.frozen[t]=this.sectors.active[t],this._deleteActiveSector(t)},_activateSector:function(t){this.sectors.active[t]=this.sectors.frozen[t],this._deleteFrozenSector(t)},_mergeThisWithFrozen:function(t){for(var e in this.nodes)this.nodes.hasOwnProperty(e)&&(this.sectors.frozen[t].nodes[e]=this.nodes[e]);for(var i in this.edges)this.edges.hasOwnProperty(i)&&(this.sectors.frozen[t].edges[i]=this.edges[i]);for(var n=0;n1?this[t](n[0],n[1]):this[t](e)}this._loadLatestSector()},_doInAllFrozenSectors:function(t,e){if(void 0===e)for(var i in this.sectors.frozen)this.sectors.frozen.hasOwnProperty(i)&&(this._switchToFrozenSector(i),this[t]());else for(var i in this.sectors.frozen)if(this.sectors.frozen.hasOwnProperty(i)){this._switchToFrozenSector(i);var n=Array.prototype.splice.call(arguments,1);n.length>1?this[t](n[0],n[1]):this[t](e)}this._loadLatestSector()},_doInNavigationSector:function(t,e){if(this._switchToNavigationSector(),void 0===e)this[t]();else{var i=Array.prototype.splice.call(arguments,1);i.length>1?this[t](i[0],i[1]):this[t](e)}this._loadLatestSector()},_doInAllSectors:function(t,e){var i=Array.prototype.splice.call(arguments,1);void 0===e?(this._doInAllActiveSectors(t),this._doInAllFrozenSectors(t)):i.length>1?(this._doInAllActiveSectors(t,i[0],i[1]),this._doInAllFrozenSectors(t,i[0],i[1])):(this._doInAllActiveSectors(t,e),this._doInAllFrozenSectors(t,e))},_clearNodeIndexList:function(){var t=this._sector();this.sectors.active[t].nodeIndices=[],this.nodeIndices=this.sectors.active[t].nodeIndices},_drawSectorNodes:function(t,e){var i,n=1e9,s=-1e9,o=1e9,r=-1e9;for(var a in this.sectors[e])if(this.sectors[e].hasOwnProperty(a)&&void 0!==this.sectors[e][a].drawingNode){this._switchToSector(a,e),n=1e9,s=-1e9,o=1e9,r=-1e9;for(var h in this.nodes)this.nodes.hasOwnProperty(h)&&(i=this.nodes[h],i.resize(t),o>i.x-.5*i.width&&(o=i.x-.5*i.width),ri.y-.5*i.height&&(n=i.y-.5*i.height),st&&n>s;)s%3==0?this.forceAggregateHubs():this.increaseClusterLevel(),i=this.nodeIndices.length,s+=1;s>1&&1==e&&this.repositionNodes()},openCluster:function(t){var e=this.moving;if(t.clusterSize>this.constants.clustering.sectorThreshold&&this._nodeInActiveArea(t)&&("default"!=this._sector()||1!=this.nodeIndices.length)){this._addSector(t);for(var i=0;this.nodeIndices.lengthi;)this.decreaseClusterLevel(),i+=1}else this._expandClusterNode(t,!1,!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels();this.moving!=e&&this.start()},updateClustersDefault:function(){1==this.constants.clustering.enabled&&this.updateClusters(0,!1,!1)},increaseClusterLevel:function(){this.updateClusters(-1,!1,!0)},decreaseClusterLevel:function(){this.updateClusters(1,!1,!0)},updateClusters:function(t,e,i){var n=this.moving,s=this.nodeIndices.length;this.previousScale>this.scale&&0==t&&this._collapseSector(),this.previousScale>this.scale||-1==t?this._formClusters(i):(this.previousScalethis.scale||-1==t)&&(this._aggregateHubs(i),this._updateNodeIndexList()),(this.previousScale>this.scale||-1==t)&&(this.handleChains(),this._updateNodeIndexList()),this.previousScale=this.scale,this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.lengththis.constants.clustering.chainThreshold&&this._reduceAmountOfChains(1-this.constants.clustering.chainThreshold/t)},_aggregateHubs:function(t){this._getHubSize(),this._formClustersByHub(t,!1)},forceAggregateHubs:function(){var t=this.moving,e=this.nodeIndices.length;this._aggregateHubs(!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.length!=e&&(this.clusterSession+=1),this.moving!=t&&this.start()},_openClustersBySize:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];1==e.inView()&&(e.width*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientWidth||e.height*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientHeight)&&this.openCluster(e)}},_openClusters:function(t,e){for(var i=0;i1&&(t.clusterSizei)){var r=o.from,a=o.to;o.to.mass>o.from.mass&&(r=o.to,a=o.from),1==a.dynamicEdgesLength?this._addToCluster(r,a,!1):1==r.dynamicEdgesLength&&this._addToCluster(a,r,!1)}}},_forceClustersByZoom:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];if(1==e.dynamicEdgesLength&&0!=e.dynamicEdges.length){var i=e.dynamicEdges[0],n=i.toId==e.id?this.nodes[i.fromId]:this.nodes[i.toId];e.id!=n.id&&(n.mass>e.mass?this._addToCluster(n,e,!0):this._addToCluster(e,n,!0))}}},_formClustersByHub:function(t,e){for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&this._formClusterFromHub(this.nodes[i],t,e)},_formClusterFromHub:function(t,e,i,n){if(void 0===n&&(n=0),t.dynamicEdgesLength>=this.hubThreshold&&0==i||t.dynamicEdgesLength==this.hubThreshold&&1==i){for(var s,o,r,a=this.constants.clustering.clusterEdgeThreshold/this.scale,h=!1,d=[],c=t.dynamicEdges.length,l=0;c>l;l++)d.push(t.dynamicEdges[l].id);if(0==e)for(h=!1,l=0;c>l;l++){var u=this.edges[d[l]];if(void 0!==u&&u.connected&&u.toId!=u.fromId&&(s=u.to.x-u.from.x,o=u.to.y-u.from.y,r=Math.sqrt(s*s+o*o),a>r)){h=!0;break}}if(!e&&h||e)for(l=0;c>l;l++)if(u=this.edges[d[l]],void 0!==u){var p=this.nodes[u.fromId==t.id?u.toId:u.fromId];p.dynamicEdges.length<=this.hubThreshold+n&&p.id!=t.id&&this._addToCluster(t,p,e)}}},_addToCluster:function(t,e,i){t.containedNodes[e.id]=e;for(var n=0;n1)for(var n=0;n1&&(e.label="[".concat(String(e.clusterSize),"]"))}for(t in this.nodes)this.nodes.hasOwnProperty(t)&&(e=this.nodes[t],1==e.clusterSize&&(e.label=void 0!==e.originalLabel?e.originalLabel:String(e.id)))},_nodeInActiveArea:function(t){return Math.abs(t.x-this.areaCenter.x)<=this.constants.clustering.activeAreaBoxSize/this.scale&&Math.abs(t.y-this.areaCenter.y)<=this.constants.clustering.activeAreaBoxSize/this.scale},repositionNodes:function(){for(var t=0;tn&&(n=o.dynamicEdgesLength),t+=o.dynamicEdgesLength,e+=Math.pow(o.dynamicEdgesLength,2),i+=1}t/=i,e/=i;var r=e-Math.pow(t,2),a=Math.sqrt(r);this.hubThreshold=Math.floor(t+2*a),this.hubThreshold>n&&(this.hubThreshold=n)},_reduceAmountOfChains:function(t){this.hubThreshold=2;var e=Math.floor(this.nodeIndices.length*t);for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&e>0&&(this._formClusterFromHub(this.nodes[i],!0,!0,1),e-=1)},_getChainFraction:function(){var t=0,e=0;for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&(2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&(t+=1),e+=1);return t/e}},W={_getNodesOverlappingWith:function(t,e){var i=this.nodes;for(var n in i)i.hasOwnProperty(n)&&i[n].isOverlappingWith(t)&&e.push(n)},_getAllNodesOverlappingWith:function(t){var e=[];return this._doInAllActiveSectors("_getNodesOverlappingWith",t,e),e},_getAllNavigationNodesOverlappingWith:function(t){var e=[];return this._doInNavigationSector("_getNodesOverlappingWith",t,e),e},_pointerToPositionObject:function(t){var e=this._canvasToX(t.x),i=this._canvasToY(t.y);return{left:e,top:i,right:e,bottom:i}},_pointerToScreenPositionObject:function(t){var e=t.x,i=t.y;return{left:e,top:i,right:e,bottom:i}},_getNavigationNodeAt:function(t){var e=this._pointerToScreenPositionObject(t),i=this._getAllNavigationNodesOverlappingWith(e);return i.length>0?this.sectors.navigation.nodes[i[i.length-1]]:null},_getNodeAt:function(t){var e=this._pointerToPositionObject(t);return overlappingNodes=this._getAllNodesOverlappingWith(e),overlappingNodes.length>0?this.nodes[overlappingNodes[overlappingNodes.length-1]]:null},_getEdgeAt:function(){return null},_addToSelection:function(t){this.selection.push(t.id),this.selectionObj[t.id]=t},_removeFromSelection:function(t){for(var e=0;ee;e++){n=t[e];var s=this.nodes[n];if(!s)throw new RangeError('Node with id "'+n+'" not found');this._selectNode(s,!0,!0)}this.redraw()},_updateSelection:function(){for(var t=0;tt.x-t.width&&(n=t.x-t.width),st.y-t.height&&(e=t.y-t.height),i=this.constants.clustering.initialMaxNodes)var n=38.8467/(e-14.50184)+.0116;else var n=42.54117319/(e+39.31966387)+.1944405;else{var s=1.1*(Math.abs(i.minX)+Math.abs(i.maxX)),o=1.1*(Math.abs(i.minY)+Math.abs(i.maxY)),r=this.frame.canvas.clientWidth/s,a=this.frame.canvas.clientHeight/o;n=a>=r?r:a}n>1&&(n=1),this.pinch.mousewheelScale=n,this._setScale(n),this._centerGraph(i),this.start()},O.prototype._updateNodeIndexList=function(){this._clearNodeIndexList();for(var t in this.nodes)this.nodes.hasOwnProperty(t)&&this.nodeIndices.push(t)},O.prototype.setData=function(t,e){if(void 0===e&&(e=!1),t&&t.dot&&(t.nodes||t.edges))throw new SyntaxError('Data must contain either parameter "dot" or parameter pair "nodes" and "edges", but not both.');if(this.setOptions(t&&t.options),t&&t.dot){if(t&&t.dot){var i=U.util.DOTToGraph(t.dot);return void this.setData(i)}}else this._setNodes(t&&t.nodes),this._setEdges(t&&t.edges);this._putDataInSector(),e||(this.stabilize&&this._doStabilize(),this.moving=!0,this.start())},O.prototype.setOptions=function(t){if(t){if(void 0!==t.width&&(this.width=t.width),void 0!==t.height&&(this.height=t.height),void 0!==t.stabilize&&(this.stabilize=t.stabilize),void 0!==t.selectable&&(this.selectable=t.selectable),t.clustering){this.constants.clustering.enabled=!0;for(var e in t.clustering)t.clustering.hasOwnProperty(e)&&(this.constants.clustering[e]=t.clustering[e])}else void 0!==t.clustering&&(this.constants.clustering.enabled=!1);if(t.navigation){this.constants.navigation.enabled=!0;for(var e in t.navigation)t.navigation.hasOwnProperty(e)&&(this.constants.navigation[e]=t.navigation[e])}else void 0!==t.navigation&&(this.constants.navigation.enabled=!1);if(t.keyboard){this.constants.keyboard.enabled=!0;for(var e in t.keyboard)t.keyboard.hasOwnProperty(e)&&(this.constants.keyboard[e]=t.keyboard[e])}else void 0!==t.keyboard&&(this.constants.keyboard.enabled=!1);if(t.edges){for(e in t.edges)t.edges.hasOwnProperty(e)&&(this.constants.edges[e]=t.edges[e]);void 0!==t.edges.length&&t.nodes&&void 0===t.nodes.distance&&(this.constants.edges.length=t.edges.length,this.constants.nodes.distance=1.25*t.edges.length),t.edges.fontColor||(this.constants.edges.fontColor=t.edges.color),t.edges.dash&&(void 0!==t.edges.dash.length&&(this.constants.edges.dash.length=t.edges.dash.length),void 0!==t.edges.dash.gap&&(this.constants.edges.dash.gap=t.edges.dash.gap),void 0!==t.edges.dash.altLength&&(this.constants.edges.dash.altLength=t.edges.dash.altLength))}if(t.nodes){for(e in t.nodes)t.nodes.hasOwnProperty(e)&&(this.constants.nodes[e]=t.nodes[e]);t.nodes.color&&(this.constants.nodes.color=M.parseColor(t.nodes.color))}if(t.groups)for(var i in t.groups)if(t.groups.hasOwnProperty(i)){var n=t.groups[i];this.groups.add(i,n)}}this.setSize(this.width,this.height),this._setTranslation(this.frame.clientWidth/2,this.frame.clientHeight/2),this._setScale(1),this._loadNavigationControls(),this._createKeyBinds(),this._redraw()},O.prototype.on=function(t,e){var i=["select"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());F.addListener(this,t,e)},O.prototype.off=function(t,e){F.removeListener(this,t,e)},O.prototype._trigger=function(t,e){F.trigger(this,t,e)},O.prototype._create=function(){for(;this.containerElement.hasChildNodes();)this.containerElement.removeChild(this.containerElement.firstChild);if(this.frame=document.createElement("div"),this.frame.className="graph-frame",this.frame.style.position="relative",this.frame.style.overflow="hidden",this.frame.canvas=document.createElement("canvas"),this.frame.canvas.style.position="relative",this.frame.appendChild(this.frame.canvas),!this.frame.canvas.getContext){var t=document.createElement("DIV");t.style.color="red",t.style.fontWeight="bold",t.style.padding="10px",t.innerHTML="Error: your browser does not support HTML canvas",this.frame.canvas.appendChild(t)}var e=this;this.drag={},this.pinch={},this.hammer=N(this.frame.canvas,{prevent_default:!0}),this.hammer.on("tap",e._onTap.bind(e)),this.hammer.on("doubletap",e._onDoubleTap.bind(e)),this.hammer.on("hold",e._onHold.bind(e)),this.hammer.on("pinch",e._onPinch.bind(e)),this.hammer.on("touch",e._onTouch.bind(e)),this.hammer.on("dragstart",e._onDragStart.bind(e)),this.hammer.on("drag",e._onDrag.bind(e)),this.hammer.on("dragend",e._onDragEnd.bind(e)),this.hammer.on("release",e._onRelease.bind(e)),this.hammer.on("mousewheel",e._onMouseWheel.bind(e)),this.hammer.on("DOMMouseScroll",e._onMouseWheel.bind(e)),this.hammer.on("mousemove",e._onMouseMoveTitle.bind(e)),this.containerElement.appendChild(this.frame)},O.prototype._createKeyBinds=function(){var t=this;this.mousetrap=A,this.mousetrap.reset(),1==this.constants.keyboard.enabled&&(this.mousetrap.bind("up",this._moveUp.bind(t),"keydown"),this.mousetrap.bind("up",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("down",this._moveDown.bind(t),"keydown"),this.mousetrap.bind("down",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("left",this._moveLeft.bind(t),"keydown"),this.mousetrap.bind("left",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("right",this._moveRight.bind(t),"keydown"),this.mousetrap.bind("right",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("=",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("=",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("-",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("-",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("[",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("[",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("]",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("]",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pageup",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("pageup",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pagedown",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("pagedown",this._stopZoom.bind(t),"keyup"))},O.prototype._getPointer=function(t){return{x:t.pageX-U.util.getAbsoluteLeft(this.frame.canvas),y:t.pageY-U.util.getAbsoluteTop(this.frame.canvas)}},O.prototype._onTouch=function(t){this.drag.pointer=this._getPointer(t.gesture.touches[0]),this.drag.pinched=!1,this.pinch.scale=this._getScale(),this._handleTouch(this.drag.pointer)},O.prototype._onDragStart=function(){var t=this.drag,e=this._getNodeAt(t.pointer);if(t.dragging=!0,t.selection=[],t.translation=this._getTranslation(),t.nodeId=null,null!=e){t.nodeId=e.id,e.isSelected()||this._selectNode(e,!1);var i=this;this.selection.forEach(function(e){var n=i.nodes[e];if(n){var s={id:e,node:n,x:n.x,y:n.y,xFixed:n.xFixed,yFixed:n.yFixed};n.xFixed=!0,n.yFixed=!0,t.selection.push(s)}})}},O.prototype._onDrag=function(t){if(!this.drag.pinched){var e=this._getPointer(t.gesture.touches[0]),i=this,n=this.drag,s=n.selection;if(s&&s.length){var o=e.x-n.pointer.x,r=e.y-n.pointer.y;s.forEach(function(t){var e=t.node;t.xFixed||(e.x=i._canvasToX(i._xToCanvas(t.x)+o)),t.yFixed||(e.y=i._canvasToY(i._yToCanvas(t.y)+r))}),this.moving||(this.moving=!0,this.start())}else{var a=e.x-this.drag.pointer.x,h=e.y-this.drag.pointer.y;this._setTranslation(this.drag.translation.x+a,this.drag.translation.y+h),this._redraw(),this.moved=!0}}},O.prototype._onDragEnd=function(){this.drag.dragging=!1;var t=this.drag.selection;t&&t.forEach(function(t){t.node.xFixed=t.xFixed,t.node.yFixed=t.yFixed})},O.prototype._onTap=function(t){var e=this._getPointer(t.gesture.touches[0]);this._handleTap(e)},O.prototype._onDoubleTap=function(t){var e=this._getPointer(t.gesture.touches[0]);this._handleDoubleTap(e)},O.prototype._onHold=function(t){var e=this._getPointer(t.gesture.touches[0]);this._handleOnHold(e)},O.prototype._onRelease=function(){this._handleOnRelease()},O.prototype._onPinch=function(t){var e=this._getPointer(t.gesture.center);this.drag.pinched=!0,"scale"in this.pinch||(this.pinch.scale=1);var i=this.pinch.scale*t.gesture.scale;this._zoom(i,e)},O.prototype._zoom=function(t,e){var i=this._getScale();1e-5>t&&(t=1e-5),t>10&&(t=10);var n=this._getTranslation(),s=t/i,o=(1-s)*e.x+n.x*s,r=(1-s)*e.y+n.y*s;return this.areaCenter={x:this._canvasToX(e.x),y:this._canvasToY(e.y)},this.pinch.mousewheelScale=t,this._setScale(t),this._setTranslation(o,r),this.updateClustersDefault(),this._redraw(),t},O.prototype._onMouseWheel=function(t){var e=0;if(t.wheelDelta?e=t.wheelDelta/120:t.detail&&(e=-t.detail/3),e){"mousewheelScale"in this.pinch||(this.pinch.mousewheelScale=1);var i=this.pinch.mousewheelScale,n=e/10;0>e&&(n/=1-n),i*=1+n;var s=z.fakeGesture(this,t),o=this._getPointer(s.center);i=this._zoom(i,o)}t.preventDefault()},O.prototype._onMouseMoveTitle=function(t){var e=z.fakeGesture(this,t),i=this._getPointer(e.center);this.popupNode&&this._checkHidePopup(i);var n=this,s=function(){n._checkShowPopup(i)};this.popupTimer&&clearInterval(this.popupTimer),this.drag.dragging||(this.popupTimer=setTimeout(s,300))},O.prototype._checkShowPopup=function(t){var e,i={left:this._canvasToX(t.x),top:this._canvasToY(t.y),right:this._canvasToX(t.x),bottom:this._canvasToY(t.y)},n=this.popupNode;if(void 0==this.popupNode){var s=this.nodes;for(e in s)if(s.hasOwnProperty(e)){var o=s[e];if(void 0!==o.getTitle()&&o.isOverlappingWith(i)){this.popupNode=o;break}}}if(void 0===this.popupNode){var r=this.edges;for(e in r)if(r.hasOwnProperty(e)){var a=r[e];if(a.connected&&void 0!==a.getTitle()&&a.isOverlappingWith(i)){this.popupNode=a;break}}}if(this.popupNode){if(this.popupNode!=n){var h=this;h.popup||(h.popup=new I(h.frame)),h.popup.setPosition(t.x-3,t.y-3),h.popup.setText(h.popupNode.getTitle()),h.popup.show()}}else this.popup&&this.popup.hide()},O.prototype._checkHidePopup=function(t){this.popupNode&&this._getNodeAt(t)||(this.popupNode=void 0,this.popup&&this.popup.hide())},O.prototype._getConnectionCount=function(t){function e(t){for(var e=[],i=0,n=t.length;n>i;i++)for(var s=t[i],o=s.edges,r=0,a=o.length;a>r;r++){var h=o[r],d=null;h.from==s?d=h.to:h.to==s&&(d=h.from);var c,l;if(d)for(c=0,l=t.length;l>c;c++)if(t[c]==d){d=null;break}if(d)for(c=0,l=e.length;l>c;c++)if(e[c]==d){d=null;break}d&&e.push(d)}return e}void 0==t&&(t=1);var i=[],n=this.nodes;for(var s in n)if(n.hasOwnProperty(s)){for(var o=[n[s]],r=0;t>r;r++)o=o.concat(e(o));i.push(o)}for(var a=[],h=0,d=i.length;d>h;h++)a.push(i[h].length);return a},O.prototype.setSize=function(t,e){this.frame.style.width=t,this.frame.style.height=e,this.frame.canvas.style.width="100%",this.frame.canvas.style.height="100%",this.frame.canvas.width=this.frame.canvas.clientWidth,this.frame.canvas.height=this.frame.canvas.clientHeight,1==this.constants.navigation.enabled&&this._relocateNavigation()},O.prototype._setNodes=function(t){var e=this.nodesData;if(t instanceof o||t instanceof r)this.nodesData=t;else if(t instanceof Array)this.nodesData=new o,this.nodesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.nodesData=new o}if(e&&z.forEach(this.nodesListeners,function(t,i){e.unsubscribe(i,t)}),this.nodes={},this.nodesData){var i=this;z.forEach(this.nodesListeners,function(t,e){i.nodesData.subscribe(e,t)});var n=this.nodesData.getIds();this._addNodes(n)}this._updateSelection()},O.prototype._addNodes=function(t){for(var e,i=0,n=t.length;n>i;i++){e=t[i];var s=this.nodesData.get(e),o=new M(s,this.images,this.groups,this.constants);if(this.nodes[e]=o,!o.isFixed()){var r=2*this.constants.edges.length,a=t.length,h=2*Math.PI*(i/a);o.x=r*Math.cos(h),o.y=r*Math.sin(h),this.moving=!0}}this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(this.nodes)},O.prototype._updateNodes=function(t){for(var e=this.nodes,i=this.nodesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o],a=i.get(o);r?r.setProperties(a,this.constants):(r=new M(properties,this.images,this.groups,this.constants),e[o]=r,r.isFixed()||(this.moving=!0))}this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(e)},O.prototype._removeNodes=function(t){for(var e=this.nodes,i=0,n=t.length;n>i;i++){var s=t[i];delete e[s]}this._updateNodeIndexList(),this._reconnectEdges(),this._updateSelection(),this._updateValueRange(e)},O.prototype._setEdges=function(t){var e=this.edgesData;if(t instanceof o||t instanceof r)this.edgesData=t;else if(t instanceof Array)this.edgesData=new o,this.edgesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.edgesData=new o}if(e&&z.forEach(this.edgesListeners,function(t,i){e.unsubscribe(i,t)}),this.edges={},this.edgesData){var i=this;z.forEach(this.edgesListeners,function(t,e){i.edgesData.subscribe(e,t)});var n=this.edgesData.getIds();this._addEdges(n)}this._reconnectEdges()},O.prototype._addEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o];r&&r.disconnect();var a=i.get(o,{showInternalIds:!0});e[o]=new D(a,this,this.constants)}this.moving=!0,this._updateValueRange(e)},O.prototype._updateEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=i.get(o),a=e[o];a?(a.disconnect(),a.setProperties(r,this.constants),a.connect()):(a=new D(r,this,this.constants),this.edges[o]=a)}this.moving=!0,this._updateValueRange(e)},O.prototype._removeEdges=function(t){for(var e=this.edges,i=0,n=t.length;n>i;i++){var s=t[i],o=e[s];o&&(o.disconnect(),delete e[s])}this.moving=!0,this._updateValueRange(e)},O.prototype._reconnectEdges=function(){var t,e=this.nodes,i=this.edges;for(t in e)e.hasOwnProperty(t)&&(e[t].edges=[]);for(t in i)if(i.hasOwnProperty(t)){var n=i[t];n.from=null,n.to=null,n.connect()}},O.prototype._updateValueRange=function(t){var e,i=void 0,n=void 0;for(e in t)if(t.hasOwnProperty(e)){var s=t[e].getValue();void 0!==s&&(i=void 0===i?s:Math.min(s,i),n=void 0===n?s:Math.max(s,n))}if(void 0!==i&&void 0!==n)for(e in t)t.hasOwnProperty(e)&&t[e].setValueRange(i,n)},O.prototype.redraw=function(){this.setSize(this.width,this.height),this._redraw()},O.prototype._redraw=function(){var t=this.frame.canvas.getContext("2d"),e=this.frame.canvas.width,i=this.frame.canvas.height;t.clearRect(0,0,e,i),t.save(),t.translate(this.translation.x,this.translation.y),t.scale(this.scale,this.scale),this.canvasTopLeft={x:this._canvasToX(0),y:this._canvasToY(0)},this.canvasBottomRight={x:this._canvasToX(this.frame.canvas.clientWidth),y:this._canvasToY(this.frame.canvas.clientHeight)},this._doInAllSectors("_drawAllSectorNodes",t),this._doInAllSectors("_drawEdges",t),this._doInAllSectors("_drawNodes",t),t.restore(),1==this.constants.navigation.enabled&&this._doInNavigationSector("_drawNodes",t,!0)},O.prototype._setTranslation=function(t,e){void 0===this.translation&&(this.translation={x:0,y:0}),void 0!==t&&(this.translation.x=t),void 0!==e&&(this.translation.y=e)},O.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},O.prototype._setScale=function(t){this.scale=t},O.prototype._getScale=function(){return this.scale},O.prototype._canvasToX=function(t){return(t-this.translation.x)/this.scale},O.prototype._xToCanvas=function(t){return t*this.scale+this.translation.x},O.prototype._canvasToY=function(t){return(t-this.translation.y)/this.scale},O.prototype._yToCanvas=function(t){return t*this.scale+this.translation.y},O.prototype._drawNodes=function(t,e){void 0===e&&(e=!1);var i=this.nodes,n=[];for(var s in i)i.hasOwnProperty(s)&&(i[s].setScaleAndPos(this.scale,this.canvasTopLeft,this.canvasBottomRight),i[s].isSelected()?n.push(s):(i[s].inArea()||e)&&i[s].draw(t));for(var o=0,r=n.length;r>o;o++)(i[n[o]].inArea()||e)&&i[n[o]].draw(t)},O.prototype._drawEdges=function(t){var e=this.edges;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];n.setScale(this.scale),n.connected&&e[i].draw(t)}},O.prototype._doStabilize=function(){for(var t=0,e=this.constants.minVelocity,i=!1;!i&&tthis.constants.clustering.clusterThreshold&&1==this.constants.clustering.enabled&&this.clusterToFit(this.constants.clustering.reduceToNodes,!1),this._calculateForces())},O.prototype._calculateForces=function(){var t,e,i,n,s,o,r,a,h,d,c,l,u,p,f,g,m,v,y=this.nodes,_=this.edges,w=.08*this.forceFactor;for(g=0;gn&&(i=Math.atan2(e,t),r=.5*b>n?1:1/(1+Math.exp((n/b-1)*S)),r*=0==v?1:1+v*this.constants.clustering.forceAmplification,r*=this.forceFactor,s=Math.cos(i)*r,o=Math.sin(i)*r,l._addForce(-s,-o),u._addForce(s,o));for(f in _)_.hasOwnProperty(f)&&(p=_[f],p.connected&&this.nodes.hasOwnProperty(p.toId)&&this.nodes.hasOwnProperty(p.fromId)&&(v=p.to.clusterSize+p.from.clusterSize-2,t=p.to.x-p.from.x,e=p.to.y-p.from.y,d=p.length,d+=v*this.constants.clustering.edgeGrowth,h=Math.sqrt(t*t+e*e),i=Math.atan2(e,t),a=p.stiffness*(d-h)*this.forceFactor,s=Math.cos(i)*a,o=Math.sin(i)*a,p.from._addForce(-s,-o),p.to._addForce(s,o)))},O.prototype._isMoving=function(t){var e=t/this.scale,i=this.nodes;for(var n in i)if(i.hasOwnProperty(n)&&i[n].isMoving(e))return!0;return!1},O.prototype._discreteStepNodes=function(){var t=.01,e=this.nodes;for(var i in e)e.hasOwnProperty(i)&&e[i].discreteStep(t);var n=this.constants.minVelocity;this.moving=this._isMoving(n)},O.prototype.start=function(){if(!this.freezeSimulation)if(this.moving&&(this._doInAllActiveSectors("_initializeForceCalculation"),this._doInAllActiveSectors("_discreteStepNodes"),this._findCenter(this._getRange())),this.moving||0!=this.xIncrement||0!=this.yIncrement||0!=this.zoomIncrement){if(!this.timer){var t=this;this.timer=window.setTimeout(function(){if(t.timer=void 0,0!=t.xIncrement||0!=t.yIncrement){var e=t._getTranslation();t._setTranslation(e.x+t.xIncrement,e.y+t.yIncrement)}if(0!=t.zoomIncrement){var i={x:t.frame.canvas.clientWidth/2,y:t.frame.canvas.clientHeight/2};t._zoom(t.scale*(1+t.zoomIncrement),i)}t.start(),t._redraw()},this.renderTimestep)}}else this._redraw()},O.prototype.singleStep=function(){if(this.moving){this._initializeForceCalculation(),this._discreteStepNodes();var t=this.constants.minVelocity;this.moving=this._isMoving(t),this._redraw()}},O.prototype.toggleFreeze=function(){0==this.freezeSimulation?this.freezeSimulation=!0:(this.freezeSimulation=!1,this.start())},O.prototype._loadClusterSystem=function(){this.clusterSession=0,this.hubThreshold=5;for(var t in H)H.hasOwnProperty(t)&&(O.prototype[t]=H[t])},O.prototype._loadSectorSystem=function(){this.sectors={},this.activeSector=["default"],this.sectors.active={},this.sectors.active["default"]={nodes:{},edges:{},nodeIndices:[],formationScale:1,drawingNode:void 0},this.sectors.frozen={},this.sectors.navigation={nodes:{},edges:{},nodeIndices:[],formationScale:1,drawingNode:void 0},this.nodeIndices=this.sectors.active["default"].nodeIndices;for(var t in R)R.hasOwnProperty(t)&&(O.prototype[t]=R[t])},O.prototype._loadSelectionSystem=function(){this.selection=[],this.selectionObj={};for(var t in W)W.hasOwnProperty(t)&&(O.prototype[t]=W[t])},O.prototype._loadNavigationControls=function(){for(var t in j)j.hasOwnProperty(t)&&(O.prototype[t]=j[t]);1==this.constants.navigation.enabled&&this._loadNavigationElements()},O.prototype._relocateNavigation=function(){},O.prototype._unHighlightAll=function(){};var U={util:z,events:F,Controller:l,DataSet:o,DataView:r,Range:h,Stack:a,TimeStep:TimeStep,EventBus:s,components:{items:{Item:_,ItemBox:w,ItemPoint:b,ItemRange:S},Component:u,Panel:p,RootPanel:f,ItemSet:y,TimeAxis:g},graph:{Node:M,Edge:D,Popup:I,Groups:Groups,Images:Images},Timeline:C,Graph:O};"undefined"!=typeof n&&(n=U),"undefined"!=typeof i&&"undefined"!=typeof i.exports&&(i.exports=U),"function"==typeof t&&t(function(){return U}),"undefined"!=typeof window&&(window.vis=U)},{hammerjs:2,moment:3,mousetrap:4}],2:[function(t,e){!function(t,i){"use strict";function n(){if(!s.READY){s.event.determineEventTypes();for(var t in s.gestures)s.gestures.hasOwnProperty(t)&&s.detection.register(s.gestures[t]);s.event.onTouch(s.DOCUMENT,s.EVENT_MOVE,s.detection.detect),s.event.onTouch(s.DOCUMENT,s.EVENT_END,s.detection.detect),s.READY=!0}}var s=function(t,e){return new s.Instance(t,e||{})};s.defaults={stop_browser_behavior:{userSelect:"none",touchAction:"none",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}},s.HAS_POINTEREVENTS=navigator.pointerEnabled||navigator.msPointerEnabled,s.HAS_TOUCHEVENTS="ontouchstart"in t,s.MOBILE_REGEX=/mobile|tablet|ip(ad|hone|od)|android/i,s.NO_MOUSEEVENTS=s.HAS_TOUCHEVENTS&&navigator.userAgent.match(s.MOBILE_REGEX),s.EVENT_TYPES={},s.DIRECTION_DOWN="down",s.DIRECTION_LEFT="left",s.DIRECTION_UP="up",s.DIRECTION_RIGHT="right",s.POINTER_MOUSE="mouse",s.POINTER_TOUCH="touch",s.POINTER_PEN="pen",s.EVENT_START="start",s.EVENT_MOVE="move",s.EVENT_END="end",s.DOCUMENT=document,s.plugins={},s.READY=!1,s.Instance=function(t,e){var i=this; -return n(),this.element=t,this.enabled=!0,this.options=s.utils.extend(s.utils.extend({},s.defaults),e||{}),this.options.stop_browser_behavior&&s.utils.stopDefaultBrowserBehavior(this.element,this.options.stop_browser_behavior),s.event.onTouch(t,s.EVENT_START,function(t){i.enabled&&s.detection.startDetect(i,t)}),this},s.Instance.prototype={on:function(t,e){for(var i=t.split(" "),n=0;n0&&e==s.EVENT_END?e=s.EVENT_MOVE:c||(e=s.EVENT_END),c||null===o?o=h:h=o,i.call(s.detection,n.collectEventData(t,e,h)),s.HAS_POINTEREVENTS&&e==s.EVENT_END&&(c=s.PointerEvent.updatePointer(e,h))),c||(o=null,r=!1,a=!1,s.PointerEvent.reset())}})},determineEventTypes:function(){var t;t=s.HAS_POINTEREVENTS?s.PointerEvent.getEvents():s.NO_MOUSEEVENTS?["touchstart","touchmove","touchend touchcancel"]:["touchstart mousedown","touchmove mousemove","touchend touchcancel mouseup"],s.EVENT_TYPES[s.EVENT_START]=t[0],s.EVENT_TYPES[s.EVENT_MOVE]=t[1],s.EVENT_TYPES[s.EVENT_END]=t[2]},getTouchList:function(t){return s.HAS_POINTEREVENTS?s.PointerEvent.getTouchList():t.touches?t.touches:[{identifier:1,pageX:t.pageX,pageY:t.pageY,target:t.target}]},collectEventData:function(t,e,i){var n=this.getTouchList(i,e),o=s.POINTER_TOUCH;return(i.type.match(/mouse/)||s.PointerEvent.matchType(s.POINTER_MOUSE,i))&&(o=s.POINTER_MOUSE),{center:s.utils.getCenter(n),timeStamp:(new Date).getTime(),target:i.target,touches:n,eventType:e,pointerType:o,srcEvent:i,preventDefault:function(){this.srcEvent.preventManipulation&&this.srcEvent.preventManipulation(),this.srcEvent.preventDefault&&this.srcEvent.preventDefault()},stopPropagation:function(){this.srcEvent.stopPropagation()},stopDetect:function(){return s.detection.stopDetect()}}}},s.PointerEvent={pointers:{},getTouchList:function(){var t=this,e=[];return Object.keys(t.pointers).sort().forEach(function(i){e.push(t.pointers[i])}),e},updatePointer:function(t,e){return t==s.EVENT_END?this.pointers={}:(e.identifier=e.pointerId,this.pointers[e.pointerId]=e),Object.keys(this.pointers).length},matchType:function(t,e){if(!e.pointerType)return!1;var i={};return i[s.POINTER_MOUSE]=e.pointerType==e.MSPOINTER_TYPE_MOUSE||e.pointerType==s.POINTER_MOUSE,i[s.POINTER_TOUCH]=e.pointerType==e.MSPOINTER_TYPE_TOUCH||e.pointerType==s.POINTER_TOUCH,i[s.POINTER_PEN]=e.pointerType==e.MSPOINTER_TYPE_PEN||e.pointerType==s.POINTER_PEN,i[t]},getEvents:function(){return["pointerdown MSPointerDown","pointermove MSPointerMove","pointerup pointercancel MSPointerUp MSPointerCancel"]},reset:function(){this.pointers={}}},s.utils={extend:function(t,e,n){for(var s in e)t[s]!==i&&n||(t[s]=e[s]);return t},hasParent:function(t,e){for(;t;){if(t==e)return!0;t=t.parentNode}return!1},getCenter:function(t){for(var e=[],i=[],n=0,s=t.length;s>n;n++)e.push(t[n].pageX),i.push(t[n].pageY);return{pageX:(Math.min.apply(Math,e)+Math.max.apply(Math,e))/2,pageY:(Math.min.apply(Math,i)+Math.max.apply(Math,i))/2}},getVelocity:function(t,e,i){return{x:Math.abs(e/t)||0,y:Math.abs(i/t)||0}},getAngle:function(t,e){var i=e.pageY-t.pageY,n=e.pageX-t.pageX;return 180*Math.atan2(i,n)/Math.PI},getDirection:function(t,e){var i=Math.abs(t.pageX-e.pageX),n=Math.abs(t.pageY-e.pageY);return i>=n?t.pageX-e.pageX>0?s.DIRECTION_LEFT:s.DIRECTION_RIGHT:t.pageY-e.pageY>0?s.DIRECTION_UP:s.DIRECTION_DOWN},getDistance:function(t,e){var i=e.pageX-t.pageX,n=e.pageY-t.pageY;return Math.sqrt(i*i+n*n)},getScale:function(t,e){return t.length>=2&&e.length>=2?this.getDistance(e[0],e[1])/this.getDistance(t[0],t[1]):1},getRotation:function(t,e){return t.length>=2&&e.length>=2?this.getAngle(e[1],e[0])-this.getAngle(t[1],t[0]):0},isVertical:function(t){return t==s.DIRECTION_UP||t==s.DIRECTION_DOWN},stopDefaultBrowserBehavior:function(t,e){var i,n=["webkit","khtml","moz","ms","o",""];if(e&&t.style){for(var s=0;si;i++){var o=this.gestures[i];if(!this.stopped&&e[o.name]!==!1&&o.handler.call(o,t,this.current.inst)===!1){this.stopDetect();break}}return this.current&&(this.current.lastEvent=t),t.eventType==s.EVENT_END&&!t.touches.length-1&&this.stopDetect(),t}},stopDetect:function(){this.previous=s.utils.extend({},this.current),this.current=null,this.stopped=!0},extendEventData:function(t){var e=this.current.startEvent;if(e&&(t.touches.length!=e.touches.length||t.touches===e.touches)){e.touches=[];for(var i=0,n=t.touches.length;n>i;i++)e.touches.push(s.utils.extend({},t.touches[i]))}var o=t.timeStamp-e.timeStamp,r=t.center.pageX-e.center.pageX,a=t.center.pageY-e.center.pageY,h=s.utils.getVelocity(o,r,a);return s.utils.extend(t,{deltaTime:o,deltaX:r,deltaY:a,velocityX:h.x,velocityY:h.y,distance:s.utils.getDistance(e.center,t.center),angle:s.utils.getAngle(e.center,t.center),direction:s.utils.getDirection(e.center,t.center),scale:s.utils.getScale(e.touches,t.touches),rotation:s.utils.getRotation(e.touches,t.touches),startEvent:e}),t},register:function(t){var e=t.defaults||{};return e[t.name]===i&&(e[t.name]=!0),s.utils.extend(s.defaults,e,!0),t.index=t.index||1e3,this.gestures.push(t),this.gestures.sort(function(t,e){return t.indexe.index?1:0}),this.gestures}},s.gestures=s.gestures||{},s.gestures.Hold={name:"hold",index:10,defaults:{hold_timeout:500,hold_threshold:1},timer:null,handler:function(t,e){switch(t.eventType){case s.EVENT_START:clearTimeout(this.timer),s.detection.current.name=this.name,this.timer=setTimeout(function(){"hold"==s.detection.current.name&&e.trigger("hold",t)},e.options.hold_timeout);break;case s.EVENT_MOVE:t.distance>e.options.hold_threshold&&clearTimeout(this.timer);break;case s.EVENT_END:clearTimeout(this.timer)}}},s.gestures.Tap={name:"tap",index:100,defaults:{tap_max_touchtime:250,tap_max_distance:10,tap_always:!0,doubletap_distance:20,doubletap_interval:300},handler:function(t,e){if(t.eventType==s.EVENT_END){var i=s.detection.previous,n=!1;if(t.deltaTime>e.options.tap_max_touchtime||t.distance>e.options.tap_max_distance)return;i&&"tap"==i.name&&t.timeStamp-i.lastEvent.timeStamp0&&t.touches.length>e.options.swipe_max_touches)return;(t.velocityX>e.options.swipe_velocity||t.velocityY>e.options.swipe_velocity)&&(e.trigger(this.name,t),e.trigger(this.name+t.direction,t))}}},s.gestures.Drag={name:"drag",index:50,defaults:{drag_min_distance:10,drag_max_touches:1,drag_block_horizontal:!1,drag_block_vertical:!1,drag_lock_to_axis:!1,drag_lock_min_distance:25},triggered:!1,handler:function(t,e){if(s.detection.current.name!=this.name&&this.triggered)return e.trigger(this.name+"end",t),void(this.triggered=!1);if(!(e.options.drag_max_touches>0&&t.touches.length>e.options.drag_max_touches))switch(t.eventType){case s.EVENT_START:this.triggered=!1;break;case s.EVENT_MOVE:if(t.distancee.options.transform_min_rotation&&e.trigger("rotate",t),i>e.options.transform_min_scale&&(e.trigger("pinch",t),e.trigger("pinch"+(t.scale<1?"in":"out"),t));break;case s.EVENT_END:this.triggered&&e.trigger(this.name+"end",t),this.triggered=!1}}},s.gestures.Touch={name:"touch",index:-1/0,defaults:{prevent_default:!1,prevent_mouseevents:!1},handler:function(t,e){return e.options.prevent_mouseevents&&t.pointerType==s.POINTER_MOUSE?void t.stopDetect():(e.options.prevent_default&&t.preventDefault(),void(t.eventType==s.EVENT_START&&e.trigger(this.name,t)))}},s.gestures.Release={name:"release",index:1/0,handler:function(t,e){t.eventType==s.EVENT_END&&e.trigger(this.name,t)}},"object"==typeof e&&"object"==typeof e.exports?e.exports=s:(t.Hammer=s,"function"==typeof t.define&&t.define.amd&&t.define("hammer",[],function(){return s}))}(this)},{}],3:[function(e,i){(function(n){function s(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function o(t,e){return function(i){return p(t.call(this,i),e)}}function r(t,e){return function(i){return this.lang().ordinal(t.call(this,i),e)}}function a(){}function h(t){x(t),c(this,t)}function d(t){var e=_(t),i=e.year||0,n=e.month||0,s=e.week||0,o=e.day||0,r=e.hour||0,a=e.minute||0,h=e.second||0,d=e.millisecond||0;this._milliseconds=+d+1e3*h+6e4*a+36e5*r,this._days=+o+7*s,this._months=+n+12*i,this._data={},this._bubble()}function c(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return e.hasOwnProperty("toString")&&(t.toString=e.toString),e.hasOwnProperty("valueOf")&&(t.valueOf=e.valueOf),t}function l(t){var e,i={};for(e in t)t.hasOwnProperty(e)&&_e.hasOwnProperty(e)&&(i[e]=t[e]);return i}function u(t){return 0>t?Math.ceil(t):Math.floor(t)}function p(t,e,i){for(var n=""+Math.abs(t),s=t>=0;n.lengthn;n++)(i&&t[n]!==e[n]||!i&&b(t[n])!==b(e[n]))&&r++;return r+o}function y(t){if(t){var e=t.toLowerCase().replace(/(.)s$/,"$1");t=Xe[t]||Ze[e]||e}return t}function _(t){var e,i,n={};for(i in t)t.hasOwnProperty(i)&&(e=y(i),e&&(n[e]=t[i]));return n}function w(t){var e,i;if(0===t.indexOf("week"))e=7,i="day";else{if(0!==t.indexOf("month"))return;e=12,i="month"}re[t]=function(s,o){var r,a,h=re.fn._lang[t],d=[];if("number"==typeof s&&(o=s,s=n),a=function(t){var e=re().utc().set(i,t);return h.call(re.fn._lang,e,s||"")},null!=o)return a(o);for(r=0;e>r;r++)d.push(a(r));return d}}function b(t){var e=+t,i=0;return 0!==e&&isFinite(e)&&(i=e>=0?Math.floor(e):Math.ceil(e)),i}function S(t,e){return new Date(Date.UTC(t,e+1,0)).getUTCDate()}function E(t){return T(t)?366:365}function T(t){return t%4===0&&t%100!==0||t%400===0}function x(t){var e;t._a&&-2===t._pf.overflow&&(e=t._a[ue]<0||t._a[ue]>11?ue:t._a[pe]<1||t._a[pe]>S(t._a[le],t._a[ue])?pe:t._a[fe]<0||t._a[fe]>23?fe:t._a[ge]<0||t._a[ge]>59?ge:t._a[me]<0||t._a[me]>59?me:t._a[ve]<0||t._a[ve]>999?ve:-1,t._pf._overflowDayOfYear&&(le>e||e>pe)&&(e=pe),t._pf.overflow=e)}function C(t){return null==t._isValid&&(t._isValid=!isNaN(t._d.getTime())&&t._pf.overflow<0&&!t._pf.empty&&!t._pf.invalidMonth&&!t._pf.nullInput&&!t._pf.invalidFormat&&!t._pf.userInvalidated,t._strict&&(t._isValid=t._isValid&&0===t._pf.charsLeftOver&&0===t._pf.unusedTokens.length)),t._isValid}function M(t){return t?t.toLowerCase().replace("_","-"):t}function D(t,e){return e._isUTC?re(t).zone(e._offset||0):re(t).local()}function I(t,e){return e.abbr=t,ye[t]||(ye[t]=new a),ye[t].set(e),ye[t]}function O(t){delete ye[t]}function N(t){var i,n,s,o,r=0,a=function(t){if(!ye[t]&&we)try{e("./lang/"+t)}catch(i){}return ye[t]};if(!t)return re.fn._lang;if(!g(t)){if(n=a(t))return n;t=[t]}for(;r0;){if(n=a(o.slice(0,i).join("-")))return n;if(s&&s.length>=i&&v(o,s,!0)>=i-1)break;i--}r++}return re.fn._lang}function L(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function A(t){var e,i,n=t.match(Te);for(e=0,i=n.length;i>e;e++)n[e]=Je[n[e]]?Je[n[e]]:L(n[e]);return function(s){var o="";for(e=0;i>e;e++)o+=n[e]instanceof Function?n[e].call(s,t):n[e];return o}}function k(t,e){return t.isValid()?(e=z(e,t.lang()),Ke[e]||(Ke[e]=A(e)),Ke[e](t)):t.lang().invalidDate()}function z(t,e){function i(t){return e.longDateFormat(t)||t}var n=5;for(xe.lastIndex=0;n>=0&&xe.test(t);)t=t.replace(xe,i),xe.lastIndex=0,n-=1;return t}function P(t,e){var i,n=e._strict;switch(t){case"DDDD":return Fe;case"YYYY":case"GGGG":case"gggg":return n?Ye:De;case"Y":case"G":case"g":return He;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return n?Re:Ie;case"S":if(n)return ze;case"SS":if(n)return Pe;case"SSS":if(n)return Fe;case"DDD":return Me;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Ne;case"a":case"A":return N(e._l)._meridiemParse;case"X":return ke;case"Z":case"ZZ":return Le;case"T":return Ae;case"SSSS":return Oe;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return n?Pe:Ce;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return Ce;default:return i=new RegExp(V(U(t.replace("\\","")),"i"))}}function F(t){t=t||"";var e=t.match(Le)||[],i=e[e.length-1]||[],n=(i+"").match(Ge)||["-",0,0],s=+(60*n[1])+b(n[2]);return"+"===n[0]?-s:s}function Y(t,e,i){var n,s=i._a;switch(t){case"M":case"MM":null!=e&&(s[ue]=b(e)-1);break;case"MMM":case"MMMM":n=N(i._l).monthsParse(e),null!=n?s[ue]=n:i._pf.invalidMonth=e;break;case"D":case"DD":null!=e&&(s[pe]=b(e));break;case"DDD":case"DDDD":null!=e&&(i._dayOfYear=b(e));break;case"YY":s[le]=b(e)+(b(e)>68?1900:2e3);break;case"YYYY":case"YYYYY":case"YYYYYY":s[le]=b(e);break;case"a":case"A":i._isPm=N(i._l).isPM(e);break;case"H":case"HH":case"h":case"hh":s[fe]=b(e);break;case"m":case"mm":s[ge]=b(e);break;case"s":case"ss":s[me]=b(e);break;case"S":case"SS":case"SSS":case"SSSS":s[ve]=b(1e3*("0."+e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,i._tzm=F(e);break;case"w":case"ww":case"W":case"WW":case"d":case"dd":case"ddd":case"dddd":case"e":case"E":t=t.substr(0,1);case"gg":case"gggg":case"GG":case"GGGG":case"GGGGG":t=t.substr(0,2),e&&(i._w=i._w||{},i._w[t]=e)}}function R(t){var e,i,n,s,o,r,a,h,d,c,l=[];if(!t._d){for(n=W(t),t._w&&null==t._a[pe]&&null==t._a[ue]&&(o=function(e){var i=parseInt(e,10);return e?e.length<3?i>68?1900+i:2e3+i:i:null==t._a[le]?re().weekYear():t._a[le]},r=t._w,null!=r.GG||null!=r.W||null!=r.E?a=te(o(r.GG),r.W||1,r.E,4,1):(h=N(t._l),d=null!=r.d?K(r.d,h):null!=r.e?parseInt(r.e,10)+h._week.dow:0,c=parseInt(r.w,10)||1,null!=r.d&&dE(s)&&(t._pf._overflowDayOfYear=!0),i=Z(s,0,t._dayOfYear),t._a[ue]=i.getUTCMonth(),t._a[pe]=i.getUTCDate()),e=0;3>e&&null==t._a[e];++e)t._a[e]=l[e]=n[e];for(;7>e;e++)t._a[e]=l[e]=null==t._a[e]?2===e?1:0:t._a[e];l[fe]+=b((t._tzm||0)/60),l[ge]+=b((t._tzm||0)%60),t._d=(t._useUTC?Z:X).apply(null,l)}}function H(t){var e;t._d||(e=_(t._i),t._a=[e.year,e.month,e.day,e.hour,e.minute,e.second,e.millisecond],R(t))}function W(t){var e=new Date;return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function j(t){t._a=[],t._pf.empty=!0;var e,i,n,s,o,r=N(t._l),a=""+t._i,h=a.length,d=0;for(n=z(t._f,r).match(Te)||[],e=0;e0&&t._pf.unusedInput.push(o),a=a.slice(a.indexOf(i)+i.length),d+=i.length),Je[s]?(i?t._pf.empty=!1:t._pf.unusedTokens.push(s),Y(s,i,t)):t._strict&&!i&&t._pf.unusedTokens.push(s);t._pf.charsLeftOver=h-d,a.length>0&&t._pf.unusedInput.push(a),t._isPm&&t._a[fe]<12&&(t._a[fe]+=12),t._isPm===!1&&12===t._a[fe]&&(t._a[fe]=0),R(t),x(t)}function U(t){return t.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,i,n,s){return e||i||n||s})}function V(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function G(t){var e,i,n,o,r;if(0===t._f.length)return t._pf.invalidFormat=!0,void(t._d=new Date(0/0));for(o=0;or)&&(n=r,i=e));c(t,i||e)}function B(t){var e,i,n=t._i,s=We.exec(n);if(s){for(t._pf.iso=!0,e=0,i=Ue.length;i>e;e++)if(Ue[e][1].exec(n)){t._f=Ue[e][0]+(s[6]||" ");break}for(e=0,i=Ve.length;i>e;e++)if(Ve[e][1].exec(n)){t._f+=Ve[e][0];break}n.match(Le)&&(t._f+="Z"),j(t)}else t._d=new Date(n)}function q(t){var e=t._i,i=be.exec(e);e===n?t._d=new Date:i?t._d=new Date(+i[1]):"string"==typeof e?B(t):g(e)?(t._a=e.slice(0),R(t)):m(e)?t._d=new Date(+e):"object"==typeof e?H(t):t._d=new Date(e)}function X(t,e,i,n,s,o,r){var a=new Date(t,e,i,n,s,o,r);return 1970>t&&a.setFullYear(t),a}function Z(t){var e=new Date(Date.UTC.apply(null,arguments));return 1970>t&&e.setUTCFullYear(t),e}function K(t,e){if("string"==typeof t)if(isNaN(t)){if(t=e.weekdaysParse(t),"number"!=typeof t)return null}else t=parseInt(t,10);return t}function $(t,e,i,n,s){return s.relativeTime(e||1,!!i,t,n)}function Q(t,e,i){var n=ce(Math.abs(t)/1e3),s=ce(n/60),o=ce(s/60),r=ce(o/24),a=ce(r/365),h=45>n&&["s",n]||1===s&&["m"]||45>s&&["mm",s]||1===o&&["h"]||22>o&&["hh",o]||1===r&&["d"]||25>=r&&["dd",r]||45>=r&&["M"]||345>r&&["MM",ce(r/30)]||1===a&&["y"]||["yy",a];return h[2]=e,h[3]=t>0,h[4]=i,$.apply({},h)}function J(t,e,i){var n,s=i-e,o=i-t.day();return o>s&&(o-=7),s-7>o&&(o+=7),n=re(t).add("d",o),{week:Math.ceil(n.dayOfYear()/7),year:n.year()}}function te(t,e,i,n,s){var o,r,a=Z(t,0,1).getUTCDay();return i=null!=i?i:s,o=s-a+(a>n?7:0)-(s>a?7:0),r=7*(e-1)+(i-s)+o+1,{year:r>0?t:t-1,dayOfYear:r>0?r:E(t-1)+r}}function ee(t){var e=t._i,i=t._f;return null===e?re.invalid({nullInput:!0}):("string"==typeof e&&(t._i=e=N().preparse(e)),re.isMoment(e)?(t=l(e),t._d=new Date(+e._d)):i?g(i)?G(t):j(t):q(t),new h(t))}function ie(t,e){re.fn[t]=re.fn[t+"s"]=function(t){var i=this._isUTC?"UTC":"";return null!=t?(this._d["set"+i+e](t),re.updateOffset(this),this):this._d["get"+i+e]()}}function ne(t){re.duration.fn[t]=function(){return this._data[t]}}function se(t,e){re.duration.fn["as"+t]=function(){return+this/e}}function oe(t){var e=!1,i=re;"undefined"==typeof ender&&(t?(de.moment=function(){return!e&&console&&console.warn&&(e=!0,console.warn("Accessing Moment through the global scope is deprecated, and will be removed in an upcoming release.")),i.apply(null,arguments)},c(de.moment,i)):de.moment=re)}for(var re,ae,he="2.5.1",de=this,ce=Math.round,le=0,ue=1,pe=2,fe=3,ge=4,me=5,ve=6,ye={},_e={_isAMomentObject:null,_i:null,_f:null,_l:null,_strict:null,_isUTC:null,_offset:null,_pf:null,_lang:null},we="undefined"!=typeof i&&i.exports&&"undefined"!=typeof e,be=/^\/?Date\((\-?\d+)/i,Se=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,Ee=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,Te=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g,xe=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,Ce=/\d\d?/,Me=/\d{1,3}/,De=/\d{1,4}/,Ie=/[+\-]?\d{1,6}/,Oe=/\d+/,Ne=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Le=/Z|[\+\-]\d\d:?\d\d/gi,Ae=/T/i,ke=/[\+\-]?\d+(\.\d{1,3})?/,ze=/\d/,Pe=/\d\d/,Fe=/\d{3}/,Ye=/\d{4}/,Re=/[+-]?\d{6}/,He=/[+-]?\d+/,We=/^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,je="YYYY-MM-DDTHH:mm:ssZ",Ue=[["YYYYYY-MM-DD",/[+-]\d{6}-\d{2}-\d{2}/],["YYYY-MM-DD",/\d{4}-\d{2}-\d{2}/],["GGGG-[W]WW-E",/\d{4}-W\d{2}-\d/],["GGGG-[W]WW",/\d{4}-W\d{2}/],["YYYY-DDD",/\d{4}-\d{3}/]],Ve=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d{1,3}/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],Ge=/([\+\-]|\d\d)/gi,Be="Date|Hours|Minutes|Seconds|Milliseconds".split("|"),qe={Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6},Xe={ms:"millisecond",s:"second",m:"minute",h:"hour",d:"day",D:"date",w:"week",W:"isoWeek",M:"month",y:"year",DDD:"dayOfYear",e:"weekday",E:"isoWeekday",gg:"weekYear",GG:"isoWeekYear"},Ze={dayofyear:"dayOfYear",isoweekday:"isoWeekday",isoweek:"isoWeek",weekyear:"weekYear",isoweekyear:"isoWeekYear"},Ke={},$e="DDD w W M D d".split(" "),Qe="M D H h m s w W".split(" "),Je={M:function(){return this.month()+1},MMM:function(t){return this.lang().monthsShort(this,t)},MMMM:function(t){return this.lang().months(this,t)},D:function(){return this.date()},DDD:function(){return this.dayOfYear()},d:function(){return this.day()},dd:function(t){return this.lang().weekdaysMin(this,t)},ddd:function(t){return this.lang().weekdaysShort(this,t)},dddd:function(t){return this.lang().weekdays(this,t)},w:function(){return this.week()},W:function(){return this.isoWeek()},YY:function(){return p(this.year()%100,2)},YYYY:function(){return p(this.year(),4)},YYYYY:function(){return p(this.year(),5)},YYYYYY:function(){var t=this.year(),e=t>=0?"+":"-";return e+p(Math.abs(t),6)},gg:function(){return p(this.weekYear()%100,2)},gggg:function(){return p(this.weekYear(),4)},ggggg:function(){return p(this.weekYear(),5)},GG:function(){return p(this.isoWeekYear()%100,2)},GGGG:function(){return p(this.isoWeekYear(),4)},GGGGG:function(){return p(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.lang().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.lang().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return b(this.milliseconds()/100)},SS:function(){return p(b(this.milliseconds()/10),2)},SSS:function(){return p(this.milliseconds(),3)},SSSS:function(){return p(this.milliseconds(),3)},Z:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(b(t/60),2)+":"+p(b(t)%60,2)},ZZ:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(b(t/60),2)+p(b(t)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},X:function(){return this.unix()},Q:function(){return this.quarter()}},ti=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"];$e.length;)ae=$e.pop(),Je[ae+"o"]=r(Je[ae],ae);for(;Qe.length;)ae=Qe.pop(),Je[ae+ae]=o(Je[ae],2);for(Je.DDDD=o(Je.DDD,3),c(a.prototype,{set:function(t){var e,i;for(i in t)e=t[i],"function"==typeof e?this[i]=e:this["_"+i]=e},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(t){return this._months[t.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(t){return this._monthsShort[t.month()]},monthsParse:function(t){var e,i,n;for(this._monthsParse||(this._monthsParse=[]),e=0;12>e;e++)if(this._monthsParse[e]||(i=re.utc([2e3,e]),n="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[e]=new RegExp(n.replace(".",""),"i")),this._monthsParse[e].test(t))return e},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(t){return this._weekdays[t.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(t){return this._weekdaysShort[t.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(t){return this._weekdaysMin[t.day()]},weekdaysParse:function(t){var e,i,n;for(this._weekdaysParse||(this._weekdaysParse=[]),e=0;7>e;e++)if(this._weekdaysParse[e]||(i=re([2e3,1]).day(e),n="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[e]=new RegExp(n.replace(".",""),"i")),this._weekdaysParse[e].test(t))return e},_longDateFormat:{LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D YYYY",LLL:"MMMM D YYYY LT",LLLL:"dddd, MMMM D YYYY LT"},longDateFormat:function(t){var e=this._longDateFormat[t];return!e&&this._longDateFormat[t.toUpperCase()]&&(e=this._longDateFormat[t.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t]=e),e},isPM:function(t){return"p"===(t+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(t,e,i){return t>11?i?"pm":"PM":i?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(t,e){var i=this._calendar[t];return"function"==typeof i?i.apply(e):i},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(t,e,i,n){var s=this._relativeTime[i];return"function"==typeof s?s(t,e,i,n):s.replace(/%d/i,t)},pastFuture:function(t,e){var i=this._relativeTime[t>0?"future":"past"];return"function"==typeof i?i(e):i.replace(/%s/i,e)},ordinal:function(t){return this._ordinal.replace("%d",t)},_ordinal:"%d",preparse:function(t){return t},postformat:function(t){return t},week:function(t){return J(t,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),re=function(t,e,i,o){var r;return"boolean"==typeof i&&(o=i,i=n),r={},r._isAMomentObject=!0,r._i=t,r._f=e,r._l=i,r._strict=o,r._isUTC=!1,r._pf=s(),ee(r)},re.utc=function(t,e,i,o){var r;return"boolean"==typeof i&&(o=i,i=n),r={},r._isAMomentObject=!0,r._useUTC=!0,r._isUTC=!0,r._l=i,r._i=t,r._f=e,r._strict=o,r._pf=s(),ee(r).utc()},re.unix=function(t){return re(1e3*t)},re.duration=function(t,e){var i,n,s,o=t,r=null;return re.isDuration(t)?o={ms:t._milliseconds,d:t._days,M:t._months}:"number"==typeof t?(o={},e?o[e]=t:o.milliseconds=t):(r=Se.exec(t))?(i="-"===r[1]?-1:1,o={y:0,d:b(r[pe])*i,h:b(r[fe])*i,m:b(r[ge])*i,s:b(r[me])*i,ms:b(r[ve])*i}):(r=Ee.exec(t))&&(i="-"===r[1]?-1:1,s=function(t){var e=t&&parseFloat(t.replace(",","."));return(isNaN(e)?0:e)*i},o={y:s(r[2]),M:s(r[3]),d:s(r[4]),h:s(r[5]),m:s(r[6]),s:s(r[7]),w:s(r[8])}),n=new d(o),re.isDuration(t)&&t.hasOwnProperty("_lang")&&(n._lang=t._lang),n},re.version=he,re.defaultFormat=je,re.updateOffset=function(){},re.lang=function(t,e){var i;return t?(e?I(M(t),e):null===e?(O(t),t="en"):ye[t]||N(t),i=re.duration.fn._lang=re.fn._lang=N(t),i._abbr):re.fn._lang._abbr},re.langData=function(t){return t&&t._lang&&t._lang._abbr&&(t=t._lang._abbr),N(t)},re.isMoment=function(t){return t instanceof h||null!=t&&t.hasOwnProperty("_isAMomentObject")},re.isDuration=function(t){return t instanceof d},ae=ti.length-1;ae>=0;--ae)w(ti[ae]);for(re.normalizeUnits=function(t){return y(t)},re.invalid=function(t){var e=re.utc(0/0);return null!=t?c(e._pf,t):e._pf.userInvalidated=!0,e},re.parseZone=function(t){return re(t).parseZone()},c(re.fn=h.prototype,{clone:function(){return re(this)},valueOf:function(){return+this._d+6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().lang("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){var t=re(this).utc();return 00:!1},parsingFlags:function(){return c({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(){return this.zone(0)},local:function(){return this.zone(0),this._isUTC=!1,this},format:function(t){var e=k(this,t||re.defaultFormat);return this.lang().postformat(e)},add:function(t,e){var i;return i="string"==typeof t?re.duration(+e,t):re.duration(t,e),f(this,i,1),this},subtract:function(t,e){var i;return i="string"==typeof t?re.duration(+e,t):re.duration(t,e),f(this,i,-1),this},diff:function(t,e,i){var n,s,o=D(t,this),r=6e4*(this.zone()-o.zone());return e=y(e),"year"===e||"month"===e?(n=432e5*(this.daysInMonth()+o.daysInMonth()),s=12*(this.year()-o.year())+(this.month()-o.month()),s+=(this-re(this).startOf("month")-(o-re(o).startOf("month")))/n,s-=6e4*(this.zone()-re(this).startOf("month").zone()-(o.zone()-re(o).startOf("month").zone()))/n,"year"===e&&(s/=12)):(n=this-o,s="second"===e?n/1e3:"minute"===e?n/6e4:"hour"===e?n/36e5:"day"===e?(n-r)/864e5:"week"===e?(n-r)/6048e5:n),i?s:u(s)},from:function(t,e){return re.duration(this.diff(t)).lang(this.lang()._abbr).humanize(!e)},fromNow:function(t){return this.from(re(),t)},calendar:function(){var t=D(re(),this).startOf("day"),e=this.diff(t,"days",!0),i=-6>e?"sameElse":-1>e?"lastWeek":0>e?"lastDay":1>e?"sameDay":2>e?"nextDay":7>e?"nextWeek":"sameElse";return this.format(this.lang().calendar(i,this))},isLeapYear:function(){return T(this.year())},isDST:function(){return this.zone()+re(t).startOf(e)},isBefore:function(t,e){return e="undefined"!=typeof e?e:"millisecond",+this.clone().startOf(e)<+re(t).startOf(e)},isSame:function(t,e){return e=e||"ms",+this.clone().startOf(e)===+D(t,this).startOf(e)},min:function(t){return t=re.apply(null,arguments),this>t?this:t},max:function(t){return t=re.apply(null,arguments),t>this?this:t},zone:function(t){var e=this._offset||0;return null==t?this._isUTC?e:this._d.getTimezoneOffset():("string"==typeof t&&(t=F(t)),Math.abs(t)<16&&(t=60*t),this._offset=t,this._isUTC=!0,e!==t&&f(this,re.duration(e-t,"m"),1,!0),this)},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.zone(this._tzm):"string"==typeof this._i&&this.zone(this._i),this},hasAlignedHourOffset:function(t){return t=t?re(t).zone():0,(this.zone()-t)%60===0},daysInMonth:function(){return S(this.year(),this.month())},dayOfYear:function(t){var e=ce((re(this).startOf("day")-re(this).startOf("year"))/864e5)+1;return null==t?e:this.add("d",t-e)},quarter:function(){return Math.ceil((this.month()+1)/3)},weekYear:function(t){var e=J(this,this.lang()._week.dow,this.lang()._week.doy).year;return null==t?e:this.add("y",t-e)},isoWeekYear:function(t){var e=J(this,1,4).year;return null==t?e:this.add("y",t-e)},week:function(t){var e=this.lang().week(this);return null==t?e:this.add("d",7*(t-e))},isoWeek:function(t){var e=J(this,1,4).week;return null==t?e:this.add("d",7*(t-e))},weekday:function(t){var e=(this.day()+7-this.lang()._week.dow)%7;return null==t?e:this.add("d",t-e)},isoWeekday:function(t){return null==t?this.day()||7:this.day(this.day()%7?t:t-7)},get:function(t){return t=y(t),this[t]()},set:function(t,e){return t=y(t),"function"==typeof this[t]&&this[t](e),this},lang:function(t){return t===n?this._lang:(this._lang=N(t),this)}}),ae=0;ae-1?!1:"INPUT"==i||"SELECT"==i||"TEXTAREA"==i||e.contentEditable&&"true"==e.contentEditable}function o(t,e){return t.sort().join(",")===e.sort().join(",")}function r(t){t=t||{};var e,i=!1;for(e in M)t[e]?i=!0:M[e]=0;i||(I=!1)}function a(t,e,i,n,s){var r,a,h=[];if(!x[t])return[];for("keyup"==i&&u(t)&&(e=[t]),r=0;r95&&112>t||b.hasOwnProperty(t)&&(_[b[t]]=t)}return _}function g(t,e,i){return i||(i=f()[t]?"keydown":"keypress"),"keypress"==i&&e.length&&(i="keydown"),i}function m(t,e,i,s){M[t]=0,s||(s=g(e[0],[]));var o,a=function(){I=s,++M[t],p()},h=function(t){d(i,t),"keyup"!==s&&(D=n(t)),setTimeout(r,10)};for(o=0;o1)return m(t,d,e,i);for(h="+"===t?["+"]:t.split("+"),o=0;o":".","?":"/","|":"\\"},T={option:"alt",command:"meta","return":"enter",escape:"esc"},x={},C={},M={},D=!1,I=!1,O=1;20>O;++O)b[111+O]="f"+O;for(O=0;9>=O;++O)b[O+96]=O;i(document,"keypress",l),i(document,"keydown",l),i(document,"keyup",l);var N={bind:function(t,e,i){return y(t instanceof Array?t:[t],e,i),C[t+":"+i]=e,this},unbind:function(t,e){return C[t+":"+e]&&(delete C[t+":"+e],this.bind(t,function(){},e)),this},trigger:function(t,e){return C[t+":"+e](),this},reset:function(){return x={},C={},this}};e.exports=N},{}]},{},[1])(1)}); \ No newline at end of file +!function(t){if("object"==typeof exports)module.exports=t();else if("function"==typeof define&&define.amd)define(t);else{var e;"undefined"!=typeof window?e=window:"undefined"!=typeof global?e=global:"undefined"!=typeof self&&(e=self),e.vis=t()}}(function(){var t;return function e(t,i,n){function s(r,a){if(!i[r]){if(!t[r]){var h="function"==typeof require&&require;if(!a&&h)return h(r,!0);if(o)return o(r,!0);throw new Error("Cannot find module '"+r+"'")}var d=i[r]={exports:{}};t[r][0].call(d.exports,function(e){var i=t[r][1][e];return s(i?i:e)},d,d.exports,e,t,i,n)}return i[r].exports}for(var o="function"==typeof require&&require,r=0;ri;++i)t.call(e||this,this[i],i,this)}),Array.prototype.map||(Array.prototype.map=function(t,e){var i,n,s;if(null==this)throw new TypeError(" this is null or not defined");var o=Object(this),r=o.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(e&&(i=e),n=new Array(r),s=0;r>s;){var a,h;s in o&&(a=o[s],h=t.call(i,a,s,o),n[s]=h),s++}return n}),Array.prototype.filter||(Array.prototype.filter=function(t){"use strict";if(null==this)throw new TypeError;var e=Object(this),i=e.length>>>0;if("function"!=typeof t)throw new TypeError;for(var n=[],s=arguments[1],o=0;i>o;o++)if(o in e){var r=e[o];t.call(s,r,o,e)&&n.push(r)}return n}),Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,e=!{toString:null}.propertyIsEnumerable("toString"),i=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],n=i.length;return function(s){if("object"!=typeof s&&"function"!=typeof s||null===s)throw new TypeError("Object.keys called on non-object");var o=[];for(var r in s)t.call(s,r)&&o.push(r);if(e)for(var a=0;n>a;a++)t.call(s,i[a])&&o.push(i[a]);return o}}()),Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s}),Object.create||(Object.create=function(t){function e(){}if(arguments.length>1)throw new Error("Object.create implementation only accepts the first parameter.");return e.prototype=t,new e}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s});var z={};z.isNumber=function(t){return t instanceof Number||"number"==typeof t},z.isString=function(t){return t instanceof String||"string"==typeof t},z.isDate=function(t){if(t instanceof Date)return!0;if(z.isString(t)){var e=P.exec(t);if(e)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},z.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},z.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},z.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var n=arguments[e];for(var s in n)n.hasOwnProperty(s)&&void 0!==n[s]&&(t[s]=n[s])}return t},z.convert=function(t,e){var i;if(void 0===t)return void 0;if(null===t)return null;if(!e)return t;if("string"!=typeof e&&!(e instanceof String))throw new Error("Type must be a string");switch(e){case"boolean":case"Boolean":return Boolean(t);case"number":case"Number":return Number(t.valueOf());case"string":case"String":return String(t);case"Date":if(z.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(L.isMoment(t))return new Date(t.valueOf());if(z.isString(t))return i=P.exec(t),i?new Date(Number(i[1])):L(t).toDate();throw new Error("Cannot convert object of type "+z.getType(t)+" to type Date");case"Moment":if(z.isNumber(t))return L(t);if(t instanceof Date)return L(t.valueOf());if(L.isMoment(t))return L(t);if(z.isString(t))return i=P.exec(t),L(i?Number(i[1]):t);throw new Error("Cannot convert object of type "+z.getType(t)+" to type Date");case"ISODate":if(z.isNumber(t))return new Date(t);if(t instanceof Date)return t.toISOString();if(L.isMoment(t))return t.toDate().toISOString();if(z.isString(t))return i=P.exec(t),i?new Date(Number(i[1])).toISOString():new Date(t).toISOString();throw new Error("Cannot convert object of type "+z.getType(t)+" to type ISODate");case"ASPDate":if(z.isNumber(t))return"/Date("+t+")/";if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(z.isString(t)){i=P.exec(t);var n;return n=i?new Date(Number(i[1])).valueOf():new Date(t).valueOf(),"/Date("+n+")/"}throw new Error("Cannot convert object of type "+z.getType(t)+" to type ASPDate");default:throw new Error("Cannot convert object of type "+z.getType(t)+' to type "'+e+'"')}};var P=/^\/?Date\((\-?\d+)/i;z.getType=function(t){var e=typeof t;return"object"==e?null==t?"null":t instanceof Boolean?"Boolean":t instanceof Number?"Number":t instanceof String?"String":t instanceof Array?"Array":t instanceof Date?"Date":"Object":"number"==e?"Number":"boolean"==e?"Boolean":"string"==e?"String":e},z.getAbsoluteLeft=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetLeft,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetLeft,n-=s.scrollLeft,s=s.offsetParent;return n},z.getAbsoluteTop=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetTop,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetTop,n-=s.scrollTop,s=s.offsetParent;return n},z.getPageY=function(t){if("pageY"in t)return t.pageY;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientY:t.clientY;var i=document.documentElement,n=document.body;return e+(i&&i.scrollTop||n&&n.scrollTop||0)-(i&&i.clientTop||n&&n.clientTop||0)},z.getPageX=function(t){if("pageY"in t)return t.pageX;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientX:t.clientX;var i=document.documentElement,n=document.body;return e+(i&&i.scrollLeft||n&&n.scrollLeft||0)-(i&&i.clientLeft||n&&n.clientLeft||0)},z.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},z.removeClassName=function(t,e){var i=t.className.split(" "),n=i.indexOf(e);-1!=n&&(i.splice(n,1),t.className=i.join(" "))},z.forEach=function(t,e){var i,n;if(t instanceof Array)for(i=0,n=t.length;n>i;i++)e(t[i],i,t);else for(i in t)t.hasOwnProperty(i)&&e(t[i],i,t)},z.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},z.addEventListener=function(t,e,i,n){t.addEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.addEventListener(e,i,n)):t.attachEvent("on"+e,i)},z.removeEventListener=function(t,e,i,n){t.removeEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.removeEventListener(e,i,n)):t.detachEvent("on"+e,i)},z.getTarget=function(t){t||(t=window.event);var e;return t.target?e=t.target:t.srcElement&&(e=t.srcElement),void 0!=e.nodeType&&3==e.nodeType&&(e=e.parentNode),e},z.stopPropagation=function(t){t||(t=window.event),t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},z.fakeGesture=function(t,e){var i=null;return N.event.collectEventData(this,i,e)},z.preventDefault=function(t){t||(t=window.event),t.preventDefault?t.preventDefault():t.returnValue=!1},z.option={},z.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},z.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},z.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?String(t):e||null},z.option.asSize=function(t,e){return"function"==typeof t&&(t=t()),z.isString(t)?t:z.isNumber(t)?t+"px":e||null},z.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null};var F={listeners:[],indexOf:function(t){for(var e=this.listeners,i=0,n=this.listeners.length;n>i;i++){var s=e[i];if(s&&s.object==t)return i}return-1},addListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];s||(s={object:t,events:{}},this.listeners.push(s));var o=s.events[e];o||(o=[],s.events[e]=o),-1==o.indexOf(i)&&o.push(i)},removeListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];o&&(n=o.indexOf(i),-1!=n&&o.splice(n,1),0==o.length&&delete s.events[e]);var r=0,a=s.events;for(var h in a)a.hasOwnProperty(h)&&r++;0==r&&delete this.listeners[n]}},removeAllListeners:function(){this.listeners=[]},trigger:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];if(o)for(var r=0,a=o.length;a>r;r++)o[r](i)}}};s.prototype.on=function(t,e,i){var n=t instanceof RegExp?t:new RegExp(t.replace("*","\\w+")),s={id:z.randomUUID(),event:t,regexp:n,callback:"function"==typeof e?e:null,target:i};return this.subscriptions.push(s),s.id},s.prototype.off=function(t){for(var e=0;eo;o++)i=s._addItem(t[o]),n.push(i);else if(z.isDataTable(t))for(var a=this._getColumnNames(t),h=0,d=t.getNumberOfRows();d>h;h++){for(var c={},l=0,u=a.length;u>l;l++){var p=a[l];c[p]=t.getValue(h,l)}i=s._addItem(c),n.push(i)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");i=s._addItem(t),n.push(i)}return n.length&&this._trigger("add",{items:n},e),n},o.prototype.update=function(t,e){var i=[],n=[],s=this,o=s.fieldId,r=function(t){var e=t[o];s.data[e]?(e=s._updateItem(t),n.push(e)):(e=s._addItem(t),i.push(e))};if(t instanceof Array)for(var a=0,h=t.length;h>a;a++)r(t[a]);else if(z.isDataTable(t))for(var d=this._getColumnNames(t),c=0,l=t.getNumberOfRows();l>c;c++){for(var u={},p=0,f=d.length;f>p;p++){var g=d[p];u[g]=t.getValue(c,p)}r(u)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");r(t)}return i.length&&this._trigger("add",{items:i},e),n.length&&this._trigger("update",{items:n},e),i.concat(n)},o.prototype.get=function(){var t,e,i,n,s=this,o=this.showInternalIds,r=z.getType(arguments[0]);"String"==r||"Number"==r?(t=arguments[0],i=arguments[1],n=arguments[2]):"Array"==r?(e=arguments[0],i=arguments[1],n=arguments[2]):(i=arguments[0],n=arguments[1]);var a;if(i&&i.type){if(a="DataTable"==i.type?"DataTable":"Array",n&&a!=z.getType(n))throw new Error('Type of parameter "data" ('+z.getType(n)+") does not correspond with specified options.type ("+i.type+")");if("DataTable"==a&&!z.isDataTable(n))throw new Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else a=n?"DataTable"==z.getType(n)?"DataTable":"Array":"Array";void 0!=i&&void 0!=i.showInternalIds&&(this.showInternalIds=i.showInternalIds);var h,d,c,l,u=i&&i.convert||this.options.convert,p=i&&i.filter,f=[];if(void 0!=t)h=s._getItem(t,u),p&&!p(h)&&(h=null);else if(void 0!=e)for(c=0,l=e.length;l>c;c++)h=s._getItem(e[c],u),(!p||p(h))&&f.push(h);else for(d in this.data)this.data.hasOwnProperty(d)&&(h=s._getItem(d,u),(!p||p(h))&&f.push(h));if(this.showInternalIds=o,i&&i.order&&void 0==t&&this._sort(f,i.order),i&&i.fields){var g=i.fields;if(void 0!=t)h=this._filterFields(h,g);else for(c=0,l=f.length;l>c;c++)f[c]=this._filterFields(f[c],g)}if("DataTable"==a){var m=this._getColumnNames(n);if(void 0!=t)s._appendRow(n,m,h);else for(c=0,l=f.length;l>c;c++)s._appendRow(n,m,f[c]);return n}if(void 0!=t)return h;if(n){for(c=0,l=f.length;l>c;c++)n.push(f[c]);return n}return f},o.prototype.getIds=function(t){var e,i,n,s,o,r=this.data,a=t&&t.filter,h=t&&t.order,d=t&&t.convert||this.options.convert,c=[];if(a)if(h){o=[];for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,d),a(s)&&o.push(s));for(this._sort(o,h),e=0,i=o.length;i>e;e++)c[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,d),a(s)&&c.push(s[this.fieldId]));else if(h){o=[];for(n in r)r.hasOwnProperty(n)&&o.push(r[n]);for(this._sort(o,h),e=0,i=o.length;i>e;e++)c[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=r[n],c.push(s[this.fieldId]));return c},o.prototype.forEach=function(t,e){var i,n,s=e&&e.filter,o=e&&e.convert||this.options.convert,r=this.data;if(e&&e.order)for(var a=this.get(e),h=0,d=a.length;d>h;h++)i=a[h],n=i[this.fieldId],t(i,n);else for(n in r)r.hasOwnProperty(n)&&(i=this._getItem(n,o),(!s||s(i))&&t(i,n))},o.prototype.map=function(t,e){var i,n=e&&e.filter,s=e&&e.convert||this.options.convert,o=[],r=this.data;for(var a in r)r.hasOwnProperty(a)&&(i=this._getItem(a,s),(!n||n(i))&&o.push(t(i,a)));return e&&e.order&&this._sort(o,e.order),o},o.prototype._filterFields=function(t,e){var i={};for(var n in t)t.hasOwnProperty(n)&&-1!=e.indexOf(n)&&(i[n]=t[n]);return i},o.prototype._sort=function(t,e){if(z.isString(e)){var i=e;t.sort(function(t,e){var n=t[i],s=e[i];return n>s?1:s>n?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},o.prototype.remove=function(t,e){var i,n,s,o=[];if(t instanceof Array)for(i=0,n=t.length;n>i;i++)s=this._remove(t[i]),null!=s&&o.push(s);else s=this._remove(t),null!=s&&o.push(s);return o.length&&this._trigger("remove",{items:o},e),o},o.prototype._remove=function(t){if(z.isNumber(t)||z.isString(t)){if(this.data[t])return delete this.data[t],delete this.internalIds[t],t}else if(t instanceof Object){var e=t[this.fieldId];if(e&&this.data[e])return delete this.data[e],delete this.internalIds[e],e}return null},o.prototype.clear=function(t){var e=Object.keys(this.data);return this.data={},this.internalIds={},this._trigger("remove",{items:e},t),e},o.prototype.max=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||r>n)&&(i=o,n=r)}return i},o.prototype.min=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||n>r)&&(i=o,n=r)}return i},o.prototype.distinct=function(t){var e=this.data,i=[],n=this.options.convert[t],s=0;for(var o in e)if(e.hasOwnProperty(o)){for(var r=e[o],a=z.convert(r[t],n),h=!1,d=0;s>d;d++)if(i[d]==a){h=!0;break}h||(i[s]=a,s++)}return i},o.prototype._addItem=function(t){var e=t[this.fieldId];if(void 0!=e){if(this.data[e])throw new Error("Cannot add item: item with id "+e+" already exists")}else e=z.randomUUID(),t[this.fieldId]=e,this.internalIds[e]=t;var i={};for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=z.convert(t[n],s)}return this.data[e]=i,e},o.prototype._getItem=function(t,e){var i,n,s=this.data[t];if(!s)return null;var o={},r=this.fieldId,a=this.internalIds;if(e)for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a&&!this.showInternalIds||(o[i]=z.convert(n,e[i])));else for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a&&!this.showInternalIds||(o[i]=n));return o},o.prototype._updateItem=function(t){var e=t[this.fieldId];if(void 0==e)throw new Error("Cannot update item: item has no id (item: "+JSON.stringify(t)+")");var i=this.data[e];if(!i)throw new Error("Cannot update item: no item with id "+e+" found");for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=z.convert(t[n],s)}return e},o.prototype.isInternalId=function(t){return t in this.internalIds},o.prototype._getColumnNames=function(t){for(var e=[],i=0,n=t.getNumberOfColumns();n>i;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},o.prototype._appendRow=function(t,e,i){for(var n=t.addRow(),s=0,o=e.length;o>s;s++){var r=e[s];t.setValue(n,s,i[r])}},r.prototype.setData=function(t){var e,i,n;if(this.data){this.data.unsubscribe&&this.data.unsubscribe("*",this.listener),e=[];for(var s in this.ids)this.ids.hasOwnProperty(s)&&e.push(s);this.ids={},this._trigger("remove",{items:e})}if(this.data=t,this.data){for(this.fieldId=this.options.fieldId||this.data&&this.data.options&&this.data.options.fieldId||"id",e=this.data.getIds({filter:this.options&&this.options.filter}),i=0,n=e.length;n>i;i++)s=e[i],this.ids[s]=!0;this._trigger("add",{items:e}),this.data.subscribe&&this.data.subscribe("*",this.listener)}},r.prototype.get=function(){var t,e,i,n=this,s=z.getType(arguments[0]);"String"==s||"Number"==s||"Array"==s?(t=arguments[0],e=arguments[1],i=arguments[2]):(e=arguments[0],i=arguments[1]);var o=z.extend({},this.options,e);this.options.filter&&e&&e.filter&&(o.filter=function(t){return n.options.filter(t)&&e.filter(t)});var r=[];return void 0!=t&&r.push(t),r.push(o),r.push(i),this.data&&this.data.get.apply(this.data,r)},r.prototype.getIds=function(t){var e;if(this.data){var i,n=this.options.filter;i=t&&t.filter?n?function(e){return n(e)&&t.filter(e)}:t.filter:n,e=this.data.getIds({filter:i,order:t&&t.order})}else e=[];return e},r.prototype._onEvent=function(t,e,i){var n,s,o,r,a=e&&e.items,h=this.data,d=[],c=[],l=[];if(a&&h){switch(t){case"add":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r&&(this.ids[o]=!0,d.push(o));break;case"update":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r?this.ids[o]?c.push(o):(this.ids[o]=!0,d.push(o)):this.ids[o]&&(delete this.ids[o],l.push(o));break;case"remove":for(n=0,s=a.length;s>n;n++)o=a[n],this.ids[o]&&(delete this.ids[o],l.push(o))}d.length&&this._trigger("add",{items:d},i),c.length&&this._trigger("update",{items:c},i),l.length&&this._trigger("remove",{items:l},i)}},r.prototype.subscribe=o.prototype.subscribe,r.prototype.unsubscribe=o.prototype.unsubscribe,r.prototype._trigger=o.prototype._trigger,TimeStep=function(t,e,i){this.current=new Date,this._start=new Date,this._end=new Date,this.autoScale=!0,this.scale=TimeStep.SCALE.DAY,this.step=1,this.setRange(t,e,i)},TimeStep.SCALE={MILLISECOND:1,SECOND:2,MINUTE:3,HOUR:4,DAY:5,WEEKDAY:6,MONTH:7,YEAR:8},TimeStep.prototype.setRange=function(t,e,i){if(!(t instanceof Date&&e instanceof Date))throw"No legal start or end date in method setRange";this._start=void 0!=t?new Date(t.valueOf()):new Date,this._end=void 0!=e?new Date(e.valueOf()):new Date,this.autoScale&&this.setMinimumStep(i)},TimeStep.prototype.first=function(){this.current=new Date(this._start.valueOf()),this.roundToMinor()},TimeStep.prototype.roundToMinor=function(){switch(this.scale){case TimeStep.SCALE.YEAR:this.current.setFullYear(this.step*Math.floor(this.current.getFullYear()/this.step)),this.current.setMonth(0);case TimeStep.SCALE.MONTH:this.current.setDate(1);case TimeStep.SCALE.DAY:case TimeStep.SCALE.WEEKDAY:this.current.setHours(0);case TimeStep.SCALE.HOUR:this.current.setMinutes(0);case TimeStep.SCALE.MINUTE:this.current.setSeconds(0);case TimeStep.SCALE.SECOND:this.current.setMilliseconds(0)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.setMilliseconds(this.current.getMilliseconds()-this.current.getMilliseconds()%this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()-this.current.getSeconds()%this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()-this.current.getMinutes()%this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()-this.current.getHours()%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()-1-(this.current.getDate()-1)%this.step+1);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()-this.current.getMonth()%this.step); +break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()-this.current.getFullYear()%this.step)}},TimeStep.prototype.hasNext=function(){return this.current.valueOf()<=this._end.valueOf()},TimeStep.prototype.next=function(){var t=this.current.valueOf();if(this.current.getMonth()<6)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current=new Date(this.current.valueOf()+1e3*this.step);break;case TimeStep.SCALE.MINUTE:this.current=new Date(this.current.valueOf()+1e3*this.step*60);break;case TimeStep.SCALE.HOUR:this.current=new Date(this.current.valueOf()+1e3*this.step*60*60);var e=this.current.getHours();this.current.setHours(e-e%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}else switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()+this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()+this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()+this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.getMilliseconds()0&&(this.step=e),this.autoScale=!1},TimeStep.prototype.setAutoScale=function(t){this.autoScale=t},TimeStep.prototype.setMinimumStep=function(t){if(void 0!=t){var e=31104e6,i=2592e6,n=864e5,s=36e5,o=6e4,r=1e3,a=1;1e3*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1e3),500*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=500),100*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=100),50*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=50),10*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=10),5*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=5),e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1),3*i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=3),i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=1),5*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=5),2*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=2),n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=1),n/2>t&&(this.scale=TimeStep.SCALE.WEEKDAY,this.step=1),4*s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=4),s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=1),15*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=15),10*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=10),5*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=5),o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=1),15*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=15),10*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=10),5*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=5),r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=1),200*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=200),100*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=100),50*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=50),10*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=10),5*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=5),a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=1)}},TimeStep.prototype.snap=function(t){if(this.scale==TimeStep.SCALE.YEAR){var e=t.getFullYear()+Math.round(t.getMonth()/12);t.setFullYear(Math.round(e/this.step)*this.step),t.setMonth(0),t.setDate(0),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MONTH)t.getDate()>15?(t.setDate(1),t.setMonth(t.getMonth()+1)):t.setDate(1),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0);else if(this.scale==TimeStep.SCALE.DAY||this.scale==TimeStep.SCALE.WEEKDAY){switch(this.step){case 5:case 2:t.setHours(24*Math.round(t.getHours()/24));break;default:t.setHours(12*Math.round(t.getHours()/12))}t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.HOUR){switch(this.step){case 4:t.setMinutes(60*Math.round(t.getMinutes()/60));break;default:t.setMinutes(30*Math.round(t.getMinutes()/30))}t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MINUTE){switch(this.step){case 15:case 10:t.setMinutes(5*Math.round(t.getMinutes()/5)),t.setSeconds(0);break;case 5:t.setSeconds(60*Math.round(t.getSeconds()/60));break;default:t.setSeconds(30*Math.round(t.getSeconds()/30))}t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.SECOND)switch(this.step){case 15:case 10:t.setSeconds(5*Math.round(t.getSeconds()/5)),t.setMilliseconds(0);break;case 5:t.setMilliseconds(1e3*Math.round(t.getMilliseconds()/1e3));break;default:t.setMilliseconds(500*Math.round(t.getMilliseconds()/500))}else if(this.scale==TimeStep.SCALE.MILLISECOND){var i=this.step>5?this.step/2:1;t.setMilliseconds(Math.round(t.getMilliseconds()/i)*i)}},TimeStep.prototype.isMajor=function(){switch(this.scale){case TimeStep.SCALE.MILLISECOND:return 0==this.current.getMilliseconds();case TimeStep.SCALE.SECOND:return 0==this.current.getSeconds();case TimeStep.SCALE.MINUTE:return 0==this.current.getHours()&&0==this.current.getMinutes();case TimeStep.SCALE.HOUR:return 0==this.current.getHours();case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return 1==this.current.getDate();case TimeStep.SCALE.MONTH:return 0==this.current.getMonth();case TimeStep.SCALE.YEAR:return!1;default:return!1}},TimeStep.prototype.getLabelMinor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return L(t).format("SSS");case TimeStep.SCALE.SECOND:return L(t).format("s");case TimeStep.SCALE.MINUTE:return L(t).format("HH:mm");case TimeStep.SCALE.HOUR:return L(t).format("HH:mm");case TimeStep.SCALE.WEEKDAY:return L(t).format("ddd D");case TimeStep.SCALE.DAY:return L(t).format("D");case TimeStep.SCALE.MONTH:return L(t).format("MMM");case TimeStep.SCALE.YEAR:return L(t).format("YYYY");default:return""}},TimeStep.prototype.getLabelMajor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return L(t).format("HH:mm:ss");case TimeStep.SCALE.SECOND:return L(t).format("D MMMM HH:mm");case TimeStep.SCALE.MINUTE:case TimeStep.SCALE.HOUR:return L(t).format("ddd D MMMM");case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return L(t).format("MMMM YYYY");case TimeStep.SCALE.MONTH:return L(t).format("YYYY");case TimeStep.SCALE.YEAR:return"";default:return""}},a.prototype.setOptions=function(t){z.extend(this.options,t)},a.prototype.update=function(){this._order(),this._stack()},a.prototype._order=function(){var t=this.parent.items;if(!t)throw new Error("Cannot stack items: parent does not contain items");var e=[],i=0;z.forEach(t,function(t){t.visible&&(e[i]=t,i++)});var n=this.options.order||this.defaultOptions.order;if("function"!=typeof n)throw new Error("Option order must be a function");e.sort(n),this.ordered=e},a.prototype._stack=function(){var t,e,i,n=this.ordered,s=this.options,o=s.orientation||this.defaultOptions.orientation,r="top"==o;for(i=s.margin&&void 0!==s.margin.item?s.margin.item:this.defaultOptions.margin.item,t=0,e=n.length;e>t;t++){var a=n[t],h=null;do h=this.checkOverlap(n,t,0,t-1,i),null!=h&&(a.top=r?h.top+h.height+i:h.top-a.height-i);while(h)}},a.prototype.checkOverlap=function(t,e,i,n,s){for(var o=this.collision,r=t[e],a=n;a>=i;a--){var h=t[a];if(o(r,h,s)&&a!=e)return h}return null},a.prototype.collision=function(t,e,i){return t.left-ie.left&&t.top-ie.top},h.prototype.setOptions=function(t){z.extend(this.options,t),null!==this.start&&null!==this.end&&this.setRange(this.start,this.end)},h.prototype.subscribe=function(t,e,i){function n(e){s._onMouseWheel(e,t,i)}var s=this;if("move"==e)t.on("dragstart",function(e){s._onDragStart(e,t)}),t.on("drag",function(e){s._onDrag(e,t,i)}),t.on("dragend",function(e){s._onDragEnd(e,t)});else{if("zoom"!=e)throw new TypeError('Unknown event "'+e+'". Choose "move" or "zoom".');t.on("mousewheel",n),t.on("DOMMouseScroll",n),t.on("touch",function(){s._onTouch()}),t.on("pinch",function(e){s._onPinch(e,t,i)})}},h.prototype.on=function(t,e){var i=["rangechange","rangechanged"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());F.addListener(this,t,e)},h.prototype.off=function(t,e){F.removeListener(this,t,e)},h.prototype._trigger=function(t){F.trigger(this,t,{start:this.start,end:this.end})},h.prototype.setRange=function(t,e){var i=this._applyRange(t,e);i&&(this._trigger("rangechange"),this._trigger("rangechanged"))},h.prototype._applyRange=function(t,e){var i,n=null!=t?z.convert(t,"Date").valueOf():this.start,s=null!=e?z.convert(e,"Date").valueOf():this.end,o=null!=this.options.max?z.convert(this.options.max,"Date").valueOf():null,r=null!=this.options.min?z.convert(this.options.min,"Date").valueOf():null;if(isNaN(n)||null===n)throw new Error('Invalid start "'+t+'"');if(isNaN(s)||null===s)throw new Error('Invalid end "'+e+'"');if(n>s&&(s=n),null!==r&&r>n&&(i=r-n,n+=i,s+=i,null!=o&&s>o&&(s=o)),null!==o&&s>o&&(i=s-o,n-=i,s-=i,null!=r&&r>n&&(n=r)),null!==this.options.zoomMin){var a=parseFloat(this.options.zoomMin);0>a&&(a=0),a>s-n&&(this.end-this.start===a?(n=this.start,s=this.end):(i=a-(s-n),n-=i/2,s+=i/2))}if(null!==this.options.zoomMax){var h=parseFloat(this.options.zoomMax);0>h&&(h=0),s-n>h&&(this.end-this.start===h?(n=this.start,s=this.end):(i=s-n-h,n+=i/2,s-=i/2))}var d=this.start!=n||this.end!=s;return this.start=n,this.end=s,d},h.prototype.getRange=function(){return{start:this.start,end:this.end}},h.prototype.conversion=function(t){return h.conversion(this.start,this.end,t)},h.conversion=function(t,e,i){return 0!=i&&e-t!=0?{offset:t,scale:i/(e-t)}:{offset:0,scale:1}};var Y={};h.prototype._onDragStart=function(t,e){if(!Y.pinching){Y.start=this.start,Y.end=this.end;var i=e.frame;i&&(i.style.cursor="move")}},h.prototype._onDrag=function(t,e,i){if(d(i),!Y.pinching){var n="horizontal"==i?t.gesture.deltaX:t.gesture.deltaY,s=Y.end-Y.start,o="horizontal"==i?e.width:e.height,r=-n/o*s;this._applyRange(Y.start+r,Y.end+r),this._trigger("rangechange")}},h.prototype._onDragEnd=function(t,e){Y.pinching||(e.frame&&(e.frame.style.cursor="auto"),this._trigger("rangechanged"))},h.prototype._onMouseWheel=function(t,e,i){d(i);var n=0;if(t.wheelDelta?n=t.wheelDelta/120:t.detail&&(n=-t.detail/3),n){var s;s=0>n?1-n/5:1/(1+n/5);var o=z.fakeGesture(this,t),r=c(o.touches[0],e.frame),a=this._pointerToDate(e,i,r);this.zoom(s,a)}z.preventDefault(t)},h.prototype._onTouch=function(){Y.start=this.start,Y.end=this.end,Y.pinching=!1,Y.center=null},h.prototype._onPinch=function(t,e,i){if(Y.pinching=!0,t.gesture.touches.length>1){Y.center||(Y.center=c(t.gesture.center,e.frame));var n=1/t.gesture.scale,s=this._pointerToDate(e,i,Y.center),o=c(t.gesture.center,e.frame),r=(this._pointerToDate(e,i,o),parseInt(s+(Y.start-s)*n)),a=parseInt(s+(Y.end-s)*n);this.setRange(r,a)}},h.prototype._pointerToDate=function(t,e,i){var n;if("horizontal"==e){var s=t.width;return n=this.conversion(s),i.x/n.scale+n.offset}var o=t.height;return n=this.conversion(o),i.y/n.scale+n.offset},h.prototype.zoom=function(t,e){null==e&&(e=(this.start+this.end)/2);var i=e+(this.start-e)*t,n=e+(this.end-e)*t;this.setRange(i,n)},h.prototype.move=function(t){var e=this.end-this.start,i=this.start+e*t,n=this.end+e*t;this.start=i,this.end=n},h.prototype.moveTo=function(t){var e=(this.start+this.end)/2,i=e-t,n=this.start-i,s=this.end-i;this.setRange(n,s)},l.prototype.add=function(t){if(void 0==t.id)throw new Error("Component has no field id");if(!(t instanceof u||t instanceof l))throw new TypeError("Component must be an instance of prototype Component or Controller");t.controller=this,this.components[t.id]=t},l.prototype.remove=function(t){var e;for(e in this.components)if(this.components.hasOwnProperty(e)&&(e==t||this.components[e]==t))break;e&&delete this.components[e]},l.prototype.requestReflow=function(t){if(t)this.reflow();else if(!this.reflowTimer){var e=this;this.reflowTimer=setTimeout(function(){e.reflowTimer=void 0,e.reflow()},0)}},l.prototype.requestRepaint=function(t){if(t)this.repaint();else if(!this.repaintTimer){var e=this;this.repaintTimer=setTimeout(function(){e.repaintTimer=void 0,e.repaint()},0)}},l.prototype.repaint=function G(){function G(i,n){n in e||(i.depends&&i.depends.forEach(function(t){G(t,t.id)}),i.parent&&G(i.parent,i.parent.id),t=i.repaint()||t,e[n]=!0)}var t=!1;this.repaintTimer&&(clearTimeout(this.repaintTimer),this.repaintTimer=void 0);var e={};z.forEach(this.components,G),t&&this.reflow()},l.prototype.reflow=function B(){function B(i,n){n in e||(i.depends&&i.depends.forEach(function(t){B(t,t.id)}),i.parent&&B(i.parent,i.parent.id),t=i.reflow()||t,e[n]=!0)}var t=!1;this.reflowTimer&&(clearTimeout(this.reflowTimer),this.reflowTimer=void 0);var e={};z.forEach(this.components,B),t&&this.repaint()},u.prototype.setOptions=function(t){t&&(z.extend(this.options,t),this.controller&&(this.requestRepaint(),this.requestReflow()))},u.prototype.getOption=function(t){var e;return this.options&&(e=this.options[t]),void 0===e&&this.defaultOptions&&(e=this.defaultOptions[t]),e},u.prototype.getContainer=function(){return null},u.prototype.getFrame=function(){return this.frame},u.prototype.repaint=function(){return!1},u.prototype.reflow=function(){return!1},u.prototype.hide=function(){return this.frame&&this.frame.parentNode?(this.frame.parentNode.removeChild(this.frame),!0):!1},u.prototype.show=function(){return this.frame&&this.frame.parentNode?!1:this.repaint()},u.prototype.requestRepaint=function(){if(!this.controller)throw new Error("Cannot request a repaint: no controller configured");this.controller.requestRepaint()},u.prototype.requestReflow=function(){if(!this.controller)throw new Error("Cannot request a reflow: no controller configured");this.controller.requestReflow()},p.prototype=new u,p.prototype.setOptions=u.prototype.setOptions,p.prototype.getContainer=function(){return this.frame},p.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.frame;if(!s){s=document.createElement("div"),s.className="panel";var o=n.className;o&&("function"==typeof o?z.addClassName(s,String(o())):z.addClassName(s,String(o))),this.frame=s,t+=1}if(!s.parentNode){if(!this.parent)throw new Error("Cannot repaint panel: no parent attached");var r=this.parent.getContainer();if(!r)throw new Error("Cannot repaint panel: parent has no container element");r.appendChild(s),t+=1}return t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),t>0},p.prototype.reflow=function(){var t=0,e=z.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},f.prototype=new p,f.prototype.setOptions=u.prototype.setOptions,f.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.frame;if(s||(s=document.createElement("div"),this.frame=s,t+=1),!s.parentNode){if(!this.container)throw new Error("Cannot repaint root panel: no container attached");this.container.appendChild(s),t+=1}s.className="vis timeline rootpanel "+n.orientation;var o=n.className;return o&&z.addClassName(s,z.option.asString(o)),t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),this._updateEventEmitters(),this._updateWatch(),t>0},f.prototype.reflow=function(){var t=0,e=z.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},f.prototype._updateWatch=function(){var t=this.getOption("autoResize");t?this._watch():this._unwatch()},f.prototype._watch=function(){var t=this;this._unwatch();var e=function(){var e=t.getOption("autoResize");return e?void(t.frame&&(t.frame.clientWidth!=t.width||t.frame.clientHeight!=t.height)&&t.requestReflow()):void t._unwatch()};z.addEventListener(window,"resize",e),this.watchTimer=setInterval(e,1e3)},f.prototype._unwatch=function(){this.watchTimer&&(clearInterval(this.watchTimer),this.watchTimer=void 0)},f.prototype.on=function(t,e){var i=this.listeners[t];i||(i=[],this.listeners[t]=i),i.push(e),this._updateEventEmitters()},f.prototype._updateEventEmitters=function(){if(this.listeners){var t=this;z.forEach(this.listeners,function(e,i){if(t.emitters||(t.emitters={}),!(i in t.emitters)){var n=t.frame;if(n){var s=function(t){e.forEach(function(e){e(t)})};t.emitters[i]=s,t.hammer||(t.hammer=N(n,{prevent_default:!0})),t.hammer.on(i,s)}}})}},g.prototype=new u,g.prototype.setOptions=u.prototype.setOptions,g.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},g.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},g.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},g.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.props,r=this.step,a=this.frame;if(a||(a=document.createElement("div"),this.frame=a,t+=1),a.className="axis",!a.parentNode){if(!this.parent)throw new Error("Cannot repaint time axis: no parent attached");var h=this.parent.getContainer();if(!h)throw new Error("Cannot repaint time axis: parent has no container element");h.appendChild(a),t+=1}var d=a.parentNode;if(d){var c=a.nextSibling;d.removeChild(a);var l="bottom"==s&&this.props.parentHeight&&this.height?this.props.parentHeight-this.height+"px":"0px";if(t+=e(a.style,"top",i(n.top,l)),t+=e(a.style,"left",i(n.left,"0px")),t+=e(a.style,"width",i(n.width,"100%")),t+=e(a.style,"height",i(n.height,this.height+"px")),this._repaintMeasureChars(),this.step){this._repaintStart(),r.first();for(var u=void 0,p=0;r.hasNext()&&1e3>p;){p++;var f=r.getCurrent(),g=this.toScreen(f),m=r.isMajor();this.getOption("showMinorLabels")&&this._repaintMinorText(g,r.getLabelMinor()),m&&this.getOption("showMajorLabels")?(g>0&&(void 0==u&&(u=g),this._repaintMajorText(g,r.getLabelMajor())),this._repaintMajorLine(g)):this._repaintMinorLine(g),r.next()}if(this.getOption("showMajorLabels")){var v=this.toTime(0),y=r.getLabelMajor(v),_=y.length*(o.majorCharWidth||10)+10;(void 0==u||u>_)&&this._repaintMajorText(0,y)}this._repaintEnd()}this._repaintLine(),c?d.insertBefore(a,c):d.appendChild(a)}return t>0},g.prototype._repaintStart=function(){var t=this.dom,e=t.redundant;e.majorLines=t.majorLines,e.majorTexts=t.majorTexts,e.minorLines=t.minorLines,e.minorTexts=t.minorTexts,t.majorLines=[],t.majorTexts=[],t.minorLines=[],t.minorTexts=[]},g.prototype._repaintEnd=function(){z.forEach(this.dom.redundant,function(t){for(;t.length;){var e=t.pop();e&&e.parentNode&&e.parentNode.removeChild(e)}})},g.prototype._repaintMinorText=function(t,e){var i=this.dom.redundant.minorTexts.shift();if(!i){var n=document.createTextNode("");i=document.createElement("div"),i.appendChild(n),i.className="text minor",this.frame.appendChild(i)}this.dom.minorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.left=t+"px",i.style.top=this.props.minorLabelTop+"px"},g.prototype._repaintMajorText=function(t,e){var i=this.dom.redundant.majorTexts.shift();if(!i){var n=document.createTextNode(e);i=document.createElement("div"),i.className="text major",i.appendChild(n),this.frame.appendChild(i)}this.dom.majorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.top=this.props.majorLabelTop+"px",i.style.left=t+"px"},g.prototype._repaintMinorLine=function(t){var e=this.dom.redundant.minorLines.shift();e||(e=document.createElement("div"),e.className="grid vertical minor",this.frame.appendChild(e)),this.dom.minorLines.push(e);var i=this.props;e.style.top=i.minorLineTop+"px",e.style.height=i.minorLineHeight+"px",e.style.left=t-i.minorLineWidth/2+"px"},g.prototype._repaintMajorLine=function(t){var e=this.dom.redundant.majorLines.shift();e||(e=document.createElement("DIV"),e.className="grid vertical major",this.frame.appendChild(e)),this.dom.majorLines.push(e);var i=this.props;e.style.top=i.majorLineTop+"px",e.style.left=t-i.majorLineWidth/2+"px",e.style.height=i.majorLineHeight+"px"},g.prototype._repaintLine=function(){{var t=this.dom.line,e=this.frame;this.options}this.getOption("showMinorLabels")||this.getOption("showMajorLabels")?(t?(e.removeChild(t),e.appendChild(t)):(t=document.createElement("div"),t.className="grid horizontal major",e.appendChild(t),this.dom.line=t),t.style.top=this.props.lineTop+"px"):t&&t.parentElement&&(e.removeChild(t.line),delete this.dom.line)},g.prototype._repaintMeasureChars=function(){var t,e=this.dom;if(!e.measureCharMinor){t=document.createTextNode("0");var i=document.createElement("DIV");i.className="text minor measure",i.appendChild(t),this.frame.appendChild(i),e.measureCharMinor=i}if(!e.measureCharMajor){t=document.createTextNode("0");var n=document.createElement("DIV");n.className="text major measure",n.appendChild(t),this.frame.appendChild(n),e.measureCharMajor=n}},g.prototype.reflow=function(){var t=0,e=z.updateProperty,i=this.frame,n=this.range;if(!n)throw new Error("Cannot repaint time axis: no range configured");if(i){t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft);var s=this.props,o=this.getOption("showMinorLabels"),r=this.getOption("showMajorLabels"),a=this.dom.measureCharMinor,h=this.dom.measureCharMajor;a&&(s.minorCharHeight=a.clientHeight,s.minorCharWidth=a.clientWidth),h&&(s.majorCharHeight=h.clientHeight,s.majorCharWidth=h.clientWidth);var d=i.parentNode?i.parentNode.offsetHeight:0;switch(d!=s.parentHeight&&(s.parentHeight=d,t+=1),this.getOption("orientation")){case"bottom":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.minorLabelTop=0,s.majorLabelTop=s.minorLabelTop+s.minorLabelHeight,s.minorLineTop=-this.top,s.minorLineHeight=Math.max(this.top+s.majorLabelHeight,0),s.minorLineWidth=1,s.majorLineTop=-this.top,s.majorLineHeight=Math.max(this.top+s.minorLabelHeight+s.majorLabelHeight,0),s.majorLineWidth=1,s.lineTop=0;break;case"top":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.majorLabelTop=0,s.minorLabelTop=s.majorLabelTop+s.majorLabelHeight,s.minorLineTop=s.minorLabelTop,s.minorLineHeight=Math.max(d-s.majorLabelHeight-this.top),s.minorLineWidth=1,s.majorLineTop=0,s.majorLineHeight=Math.max(d-this.top),s.majorLineWidth=1,s.lineTop=s.majorLabelHeight+s.minorLabelHeight;break;default:throw new Error('Unkown orientation "'+this.getOption("orientation")+'"')}var c=s.minorLabelHeight+s.majorLabelHeight;t+=e(this,"width",i.offsetWidth),t+=e(this,"height",c),this._updateConversion();var l=z.convert(n.start,"Number"),u=z.convert(n.end,"Number"),p=this.toTime(5*(s.minorCharWidth||10)).valueOf()-this.toTime(0).valueOf();this.step=new TimeStep(new Date(l),new Date(u),p),t+=e(s.range,"start",l),t+=e(s.range,"end",u),t+=e(s.range,"minimumStep",p.valueOf())}return t>0},g.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},m.prototype=new u,m.prototype.setOptions=u.prototype.setOptions,m.prototype.getContainer=function(){return this.frame},m.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCurrentTime"))return void(t&&(i.removeChild(t),delete this.frame));t||(t=document.createElement("div"),t.className="currenttime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t),this.frame=t),e.conversion||e._updateConversion();var n=new Date,s=e.toScreen(n);t.style.left=s+"px",t.title="Current time: "+n,void 0!==this.currentTimeTimer&&(clearTimeout(this.currentTimeTimer),delete this.currentTimeTimer);var o=this,r=1/e.conversion.scale/2;return 30>r&&(r=30),this.currentTimeTimer=setTimeout(function(){o.repaint()},r),!1},v.prototype=new u,v.prototype.setOptions=u.prototype.setOptions,v.prototype.getContainer=function(){return this.frame},v.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCustomTime"))return void(t&&(i.removeChild(t),delete this.frame));if(!t){t=document.createElement("div"),t.className="customtime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t);var n=document.createElement("div");n.style.position="relative",n.style.top="0px",n.style.left="-10px",n.style.height="100%",n.style.width="20px",t.appendChild(n),this.frame=t,this.subscribe(this,"movetime")}e.conversion||e._updateConversion();var s=e.toScreen(this.customTime);return t.style.left=s+"px",t.title="Time: "+this.customTime,!1},v.prototype._setCustomTime=function(t){this.customTime=new Date(t.valueOf()),this.repaint()},v.prototype._getCustomTime=function(){return new Date(this.customTime.valueOf())},v.prototype.subscribe=function(t,e){var i=this,n={component:t,event:e,callback:function(t){i._onMouseDown(t,n)},params:{}};t.on("mousedown",n.callback),i.listeners.push(n)},v.prototype.on=function(t,e){var i=this.frame;if(!i)throw new Error("Cannot add event listener: no parent attached");F.addListener(this,t,e),z.addEventListener(i,t,e)},v.prototype._onMouseDown=function(t,e){t=t||window.event;var i=e.params,n=t.which?1==t.which:1==t.button;if(n){i.mouseX=z.getPageX(t),i.moved=!1,i.customTime=this.customTime;var s=this;i.onMouseMove||(i.onMouseMove=function(t){s._onMouseMove(t,e)},z.addEventListener(document,"mousemove",i.onMouseMove)),i.onMouseUp||(i.onMouseUp=function(t){s._onMouseUp(t,e)},z.addEventListener(document,"mouseup",i.onMouseUp)),z.stopPropagation(t),z.preventDefault(t)}},v.prototype._onMouseMove=function(t,e){t=t||window.event;var i=e.params,n=this.parent,s=z.getPageX(t);void 0===i.mouseX&&(i.mouseX=s);var o=s-i.mouseX;Math.abs(o)>=1&&(i.moved=!0);var r=n.toScreen(i.customTime),a=r+o,h=n.toTime(a);this._setCustomTime(h),F.trigger(this,"timechange",{customTime:this.customTime}),z.preventDefault(t)},v.prototype._onMouseUp=function(t,e){t=t||window.event;var i=e.params;i.onMouseMove&&(z.removeEventListener(document,"mousemove",i.onMouseMove),i.onMouseMove=null),i.onMouseUp&&(z.removeEventListener(document,"mouseup",i.onMouseUp),i.onMouseUp=null),i.moved&&F.trigger(this,"timechanged",{customTime:this.customTime})},y.prototype=new p,y.types={box:w,range:S,rangeoverflow:E,point:b},y.prototype.setOptions=u.prototype.setOptions,y.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},y.prototype.setSelection=function(t){var e,i,n,s,o;if(t){if(!Array.isArray(t))throw new TypeError("Array expected");for(e=0,i=this.selection.length;i>e;e++)n=this.selection[e],s=this.items[n],s&&s.unselect();for(this.selection=[],e=0,i=t.length;i>e;e++)n=t[e],s=this.items[n],s&&(this.selection.push(n),s.select());o=this.selection.concat([]),F.trigger(this,"select",{ids:o}),this.controller&&this.requestRepaint()}},y.prototype.getSelection=function(){return this.selection.concat([])},y.prototype._deselect=function(t){for(var e=this.selection,i=0,n=e.length;n>i;i++)if(e[i]==t){e.splice(i,1);break}},y.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.defaultOptions,r=this.frame;if(!r){r=document.createElement("div"),r.className="itemset";var a=n.className;a&&z.addClassName(r,z.option.asString(a));var h=document.createElement("div");h.className="background",r.appendChild(h),this.dom.background=h;var d=document.createElement("div");d.className="foreground",r.appendChild(d),this.dom.foreground=d;var c=document.createElement("div");c.className="itemset-axis",this.dom.axis=c,this.frame=r,t+=1}if(!this.parent)throw new Error("Cannot repaint itemset: no parent attached");var l=this.parent.getContainer();if(!l)throw new Error("Cannot repaint itemset: parent has no container element");r.parentNode||(l.appendChild(r),t+=1),this.dom.axis.parentNode||(l.appendChild(this.dom.axis),t+=1),t+=e(r.style,"left",i(n.left,"0px")),t+=e(r.style,"top",i(n.top,"0px")),t+=e(r.style,"width",i(n.width,"100%")),t+=e(r.style,"height",i(n.height,this.height+"px")),t+=e(this.dom.axis.style,"left",i(n.left,"0px")),t+=e(this.dom.axis.style,"width",i(n.width,"100%")),t+="bottom"==s?e(this.dom.axis.style,"top",this.height+this.top+"px"):e(this.dom.axis.style,"top",this.top+"px"),this._updateConversion();var u=this,p=this.queue,f=this.itemsData,g=this.items,m={};for(var v in p)if(p.hasOwnProperty(v)){var _=p[v],w=g[v],b=_.action;switch(b){case"add":case"update":var S=f&&f.get(v,m);if(S){var E=S.type||S.start&&S.end&&"range"||n.type||"box",T=y.types[E];if(w&&(T&&w instanceof T?(w.data=S,t++):(t+=w.hide(),w=null)),!w){if(!T)throw new TypeError('Unknown item type "'+E+'"');w=new T(u,S,n,o),w.id=_.id,t++}w.repaint(),g[v]=w}delete p[v];break;case"remove":w&&(w.selected&&u._deselect(v),t+=w.hide()),delete g[v],delete p[v];break;default:console.log('Error: unknown action "'+b+'"')}}return z.forEach(this.items,function(e){e.visible?(t+=e.show(),e.reposition()):t+=e.hide()}),t>0},y.prototype.getForeground=function(){return this.dom.foreground},y.prototype.getBackground=function(){return this.dom.background},y.prototype.getAxis=function(){return this.dom.axis},y.prototype.reflow=function(){var t=0,e=this.options,i=e.margin&&e.margin.axis||this.defaultOptions.margin.axis,n=e.margin&&e.margin.item||this.defaultOptions.margin.item,s=z.updateProperty,o=z.option.asNumber,r=z.option.asSize,a=this.frame;if(a){this._updateConversion(),z.forEach(this.items,function(e){t+=e.reflow()}),this.stack.update();var h,d=o(e.maxHeight),c=null!=r(e.height);if(c)h=a.offsetHeight;else{var l=this.stack.ordered;if(l.length){var u=l[0].top,p=l[0].top+l[0].height;z.forEach(l,function(t){u=Math.min(u,t.top),p=Math.max(p,t.top+t.height)}),h=p-u+i+n}else h=i+n}null!=d&&(h=Math.min(h,d)),t+=s(this,"height",h),t+=s(this,"top",a.offsetTop),t+=s(this,"left",a.offsetLeft),t+=s(this,"width",a.offsetWidth)}else t+=1;return t>0},y.prototype.hide=function(){var t=!1;return this.frame&&this.frame.parentNode&&(this.frame.parentNode.removeChild(this.frame),t=!0),this.dom.axis&&this.dom.axis.parentNode&&(this.dom.axis.parentNode.removeChild(this.dom.axis),t=!0),t +},y.prototype.setItems=function(t){var e,i=this,n=this.itemsData;if(t){if(!(t instanceof o||t instanceof r))throw new TypeError("Data must be an instance of DataSet");this.itemsData=t}else this.itemsData=null;if(n&&(z.forEach(this.listeners,function(t,e){n.unsubscribe(e,t)}),e=n.getIds(),this._onRemove(e)),this.itemsData){var s=this.id;z.forEach(this.listeners,function(t,e){i.itemsData.subscribe(e,t,s)}),e=this.itemsData.getIds(),this._onAdd(e)}},y.prototype.getItems=function(){return this.itemsData},y.prototype._onUpdate=function(t){this._toQueue("update",t)},y.prototype._onAdd=function(t){this._toQueue("add",t)},y.prototype._onRemove=function(t){this._toQueue("remove",t)},y.prototype._toQueue=function(t,e){var i=this.queue;e.forEach(function(e){i[e]={id:e,action:t}}),this.controller&&this.requestRepaint()},y.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},y.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},y.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},_.prototype.select=function(){this.selected=!0,this.visible&&this.repaint()},_.prototype.unselect=function(){this.selected=!1,this.visible&&this.repaint()},_.prototype.show=function(){return!1},_.prototype.hide=function(){return!1},_.prototype.repaint=function(){return!1},_.prototype.reflow=function(){return!1},_.prototype.getWidth=function(){return this.width},w.prototype=new _(null,null),w.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");if(!e.box.parentNode){var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");i.appendChild(e.box),t=!0}if(!e.line.parentNode){var n=this.parent.getBackground();if(!n)throw new Error("Cannot repaint time axis: parent has no background container element");n.appendChild(e.line),t=!0}if(!e.dot.parentNode){var s=this.parent.getAxis();if(!n)throw new Error("Cannot repaint time axis: parent has no axis container element");s.appendChild(e.dot),t=!0}if(this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var o=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=o&&(this.className=o,e.box.className="item box"+o,e.line.className="item line"+o,e.dot.className="item dot"+o,t=!0)}return t},w.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},w.prototype.hide=function(){var t=!1,e=this.dom;return e&&(e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),e.line.parentNode&&e.line.parentNode.removeChild(e.line),e.dot.parentNode&&e.dot.parentNode.removeChild(e.dot)),t},w.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,d,c,l,u=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(c=this.data,l=this.parent&&this.parent.range,c&&l){var p=l.end-l.start;this.visible=c.start>l.start-p&&c.start0},w.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("DIV"),t.content=document.createElement("DIV"),t.content.className="content",t.box.appendChild(t.content),t.line=document.createElement("DIV"),t.line.className="line",t.dot=document.createElement("DIV"),t.dot.className="dot",t.box["timeline-item"]=this)},w.prototype.reposition=function(){var t=this.dom,e=this.props,i=this.options.orientation||this.defaultOptions.orientation;if(t){var n=t.box,s=t.line,o=t.dot;n.style.left=this.left+"px",n.style.top=this.top+"px",s.style.left=e.line.left+"px","top"==i?(s.style.top="0px",s.style.height=this.top+"px"):(s.style.top=this.top+this.height+"px",s.style.height=Math.max(this.parent.height-this.top-this.height+this.props.dot.height/2,0)+"px"),o.style.left=e.dot.left+"px",o.style.top=e.dot.top+"px"}},b.prototype=new _(null,null),b.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.point.parentNode||(i.appendChild(e.point),i.appendChild(e.point),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.point.className="item point"+n,t=!0)}return t},b.prototype.show=function(){return this.dom&&this.dom.point.parentNode?!1:this.repaint()},b.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.point.parentNode&&(e.point.parentNode.removeChild(e.point),t=!0),t},b.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,d,c=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(h=this.data,d=this.parent&&this.parent.range,h&&d){var l=d.end-d.start;this.visible=h.start>d.start-l&&h.start0},b.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.point=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.point.appendChild(t.content),t.dot=document.createElement("div"),t.dot.className="dot",t.point.appendChild(t.dot),t.point["timeline-item"]=this)},b.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.point.style.top=this.top+"px",t.point.style.left=this.left+"px",t.content.style.marginLeft=e.content.marginLeft+"px",t.dot.style.top=e.dot.top+"px")},S.prototype=new _(null,null),S.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.box.className="item range"+n,t=!0)}return t},S.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},S.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),t},S.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,d,c,l,u,p,f,g,m=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(void 0==this.data.end)throw new Error('Property "end" missing in item '+this.data.id);return h=this.data,d=this.parent&&this.parent.range,this.visible=h&&d?h.startd.start:!1,this.visible&&(t=this.dom,t?(e=this.props,i=this.options,o=this.parent,r=o.toScreen(this.data.start),a=o.toScreen(this.data.end),c=z.updateProperty,l=t.box,u=o.width,f=i.orientation||this.defaultOptions.orientation,n=i.margin&&i.margin.axis||this.defaultOptions.margin.axis,s=i.padding||this.defaultOptions.padding,m+=c(e.content,"width",t.content.offsetWidth),m+=c(this,"height",l.offsetHeight),-u>r&&(r=-u),a>2*u&&(a=2*u),p=0>r?Math.min(-r,a-r-e.content.width-2*s):0,m+=c(e.content,"left",p),"top"==f?(g=n,m+=c(this,"top",g)):(g=o.height-this.height-n,m+=c(this,"top",g)),m+=c(this,"left",r),m+=c(this,"width",Math.max(a-r,1))):m+=1),m>0},S.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content),t.box["timeline-item"]=this)},S.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.box.style.top=this.top+"px",t.box.style.left=this.left+"px",t.box.style.width=this.width+"px",t.content.style.left=e.content.left+"px")},E.prototype=new S(null,null),E.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=this.data.className?" "+this.data.className:"";this.className!=n&&(this.className=n,e.box.className="item rangeoverflow"+n,t=!0)}return t},E.prototype.getWidth=function(){return void 0!==this.props.content&&this.width0},x.prototype=new p,x.prototype.setOptions=u.prototype.setOptions,x.prototype.setRange=function(){},x.prototype.setItems=function(t){this.itemsData=t;for(var e in this.groups)if(this.groups.hasOwnProperty(e)){var i=this.groups[e];i.setItems(t)}},x.prototype.getItems=function(){return this.itemsData},x.prototype.setRange=function(t){this.range=t},x.prototype.setGroups=function(t){var e,i=this;if(this.groupsData&&(z.forEach(this.listeners,function(t,e){i.groupsData.unsubscribe(e,t)}),e=this.groupsData.getIds(),this._onRemove(e)),t?t instanceof o?this.groupsData=t:(this.groupsData=new o({convert:{start:"Date",end:"Date"}}),this.groupsData.add(t)):this.groupsData=null,this.groupsData){var n=this.id;z.forEach(this.listeners,function(t,e){i.groupsData.subscribe(e,t,n)}),e=this.groupsData.getIds(),this._onAdd(e)}},x.prototype.getGroups=function(){return this.groupsData},x.prototype.setSelection=function(t){var e=[],i=this.groups;for(var n in i)if(i.hasOwnProperty(n)){var s=i[n];s.setSelection(t)}return e},x.prototype.getSelection=function(){var t=[],e=this.groups;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];t=t.concat(n.getSelection())}return t},x.prototype.repaint=function(){var t,e,i,n,s=0,o=z.updateProperty,r=z.option.asSize,a=z.option.asElement,h=this.options,d=this.dom.frame,c=this.dom.labels,l=this.dom.labelSet;if(!this.parent)throw new Error("Cannot repaint groupset: no parent attached");var u=this.parent.getContainer();if(!u)throw new Error("Cannot repaint groupset: parent has no container element");if(!d){d=document.createElement("div"),d.className="groupset",this.dom.frame=d;var p=h.className;p&&z.addClassName(d,z.option.asString(p)),s+=1}d.parentNode||(u.appendChild(d),s+=1);var f=a(h.labelContainer);if(!f)throw new Error('Cannot repaint groupset: option "labelContainer" not defined');c||(c=document.createElement("div"),c.className="labels",this.dom.labels=c),l||(l=document.createElement("div"),l.className="label-set",c.appendChild(l),this.dom.labelSet=l),c.parentNode&&c.parentNode==f||(c.parentNode&&c.parentNode.removeChild(c.parentNode),f.appendChild(c)),s+=o(d.style,"height",r(h.height,this.height+"px")),s+=o(d.style,"top",r(h.top,"0px")),s+=o(d.style,"left",r(h.left,"0px")),s+=o(d.style,"width",r(h.width,"100%")),s+=o(l.style,"top",r(h.top,"0px")),s+=o(l.style,"height",r(h.height,this.height+"px"));var g=this,m=this.queue,v=this.groups,y=this.groupsData,_=Object.keys(m);if(_.length){_.forEach(function(t){var e=m[t],i=v[t];switch(e){case"add":case"update":if(!i){var n=Object.create(g.options);z.extend(n,{height:null,maxHeight:null}),i=new T(g,t,n),i.setItems(g.itemsData),v[t]=i,g.controller.add(i)}i.data=y.get(t),delete m[t];break;case"remove":i&&(i.setItems(),delete v[t],g.controller.remove(i)),delete m[t];break;default:console.log('Error: unknown action "'+e+'"')}});var w=this.groupsData.getIds({order:this.options.groupOrder});for(t=0;t0},x.prototype._createLabel=function(t){var e=this.groups[t],i=document.createElement("div");i.className="label";var n=document.createElement("div");n.className="inner",i.appendChild(n);var s=e.data&&e.data.content;s instanceof Element?n.appendChild(s):void 0!=s&&(n.innerHTML=s);var o=e.data&&e.data.className;return o&&z.addClassName(i,o),e.label=i,i},x.prototype.getContainer=function(){return this.dom.frame},x.prototype.getLabelsWidth=function(){return this.props.labels.width},x.prototype.reflow=function(){var t,e,i=0,n=this.options,s=z.updateProperty,o=z.option.asNumber,r=z.option.asSize,a=this.dom.frame;if(a){var h,d=o(n.maxHeight),c=null!=r(n.height);if(c)h=a.offsetHeight;else{h=0;for(t in this.groups)this.groups.hasOwnProperty(t)&&(e=this.groups[t],h+=e.height)}null!=d&&(h=Math.min(h,d)),i+=s(this,"height",h),i+=s(this,"top",a.offsetTop),i+=s(this,"left",a.offsetLeft),i+=s(this,"width",a.offsetWidth)}var l=0;for(t in this.groups)if(this.groups.hasOwnProperty(t)){e=this.groups[t];var u=e.props&&e.props.label&&e.props.label.width||0;l=Math.max(l,u)}return i+=s(this.props.labels,"width",l),i>0},x.prototype.hide=function(){return this.dom.frame&&this.dom.frame.parentNode?(this.dom.frame.parentNode.removeChild(this.dom.frame),!0):!1},x.prototype.show=function(){return this.dom.frame&&this.dom.frame.parentNode?!1:this.repaint()},x.prototype._onUpdate=function(t){this._toQueue(t,"update")},x.prototype._onAdd=function(t){this._toQueue(t,"add")},x.prototype._onRemove=function(t){this._toQueue(t,"remove")},x.prototype._toQueue=function(t,e){var i=this.queue;t.forEach(function(t){i[t]=e}),this.controller&&this.requestRepaint()},C.prototype.setOptions=function(t){z.extend(this.options,t),this.range.setRange(t.start,t.end),this.controller.reflow(),this.controller.repaint()},C.prototype.setCustomTime=function(t){this.customtime._setCustomTime(t)},C.prototype.getCustomTime=function(){return new Date(this.customtime.customTime.valueOf())},C.prototype.setItems=function(t){var e,i=null==this.itemsData;if(t?t instanceof o&&(e=t):e=null,t instanceof o||(e=new o({convert:{start:"Date",end:"Date"}}),e.add(t)),this.itemsData=e,this.content.setItems(e),i&&(void 0==this.options.start||void 0==this.options.end)){var n=this.getItemRange(),s=n.min,r=n.max;if(null!=s&&null!=r){var a=r.valueOf()-s.valueOf();0>=a&&(a=864e5),s=new Date(s.valueOf()-.05*a),r=new Date(r.valueOf()+.05*a)}void 0!=this.options.start&&(s=z.convert(this.options.start,"Date")),void 0!=this.options.end&&(r=z.convert(this.options.end,"Date")),(null!=s||null!=r)&&this.range.setRange(s,r)}},C.prototype.setGroups=function(t){var e=this;this.groupsData=t;var i=this.groupsData?x:y;if(!(this.content instanceof i)){this.content&&(this.content.hide(),this.content.setItems&&this.content.setItems(),this.content.setGroups&&this.content.setGroups(),this.controller.remove(this.content));var n=Object.create(this.options);z.extend(n,{top:function(){return"top"==e.options.orientation?e.timeaxis.height:e.itemPanel.height-e.timeaxis.height-e.content.height},left:null,width:"100%",height:function(){return e.options.height?e.itemPanel.height-e.timeaxis.height:null},maxHeight:function(){if(e.options.maxHeight){if(!z.isNumber(e.options.maxHeight))throw new TypeError("Number expected for property maxHeight");return e.options.maxHeight-e.timeaxis.height}return null},labelContainer:function(){return e.labelPanel.getContainer()}}),this.content=new i(this.itemPanel,[this.timeaxis],n),this.content.setRange&&this.content.setRange(this.range),this.content.setItems&&this.content.setItems(this.itemsData),this.content.setGroups&&this.content.setGroups(this.groupsData),this.controller.add(this.content)}},C.prototype.getItemRange=function(){var t=this.itemsData,e=null,i=null;if(t){var n=t.min("start");e=n?n.start.valueOf():null;var s=t.max("start");s&&(i=s.start.valueOf());var o=t.max("end");o&&(i=null==i?o.end.valueOf():Math.max(i,o.end.valueOf()))}return{min:null!=e?new Date(e):null,max:null!=i?new Date(i):null}},C.prototype.setSelection=function(t){this.content&&this.content.setSelection(t)},C.prototype.getSelection=function(){return this.content?this.content.getSelection():[]},C.prototype.on=function(t,e){var i=["rangechange","rangechanged","select"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());F.addListener(this,t,e)},C.prototype.off=function(t,e){F.removeListener(this,t,e)},C.prototype._trigger=function(t,e){F.trigger(this,t,e||{})},C.prototype._onSelectItem=function(t){var e=this._itemFromTarget(t),i=e?[e.id]:[];this.setSelection(i),this._trigger("select",{items:this.getSelection()}),t.stopPropagation()},C.prototype._onMultiSelectItem=function(t){var e,i=this._itemFromTarget(t);if(i){e=this.getSelection();var n=e.indexOf(i.id);-1==n?e.push(i.id):e.splice(n,1),this.setSelection(e),this._trigger("select",{items:this.getSelection()}),t.stopPropagation()}},C.prototype._itemFromTarget=function(t){for(var e=t.target;e;){if(e.hasOwnProperty("timeline-item"))return e["timeline-item"];e=e.parentNode}return null},function(t){function e(t){return C=t,u()}function i(){M=0,D=C.charAt(0)}function n(){M++,D=C.charAt(M)}function s(){return C.charAt(M+1)}function o(t){return N.test(t)}function r(t,e){if(t||(t={}),e)for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function a(t,e,i){for(var n=e.split("."),s=t;n.length;){var o=n.shift();n.length?(s[o]||(s[o]={}),s=s[o]):s[o]=i}}function h(t,e){for(var i,n,s=null,o=[t],a=t;a.parent;)o.push(a.parent),a=a.parent;if(a.nodes)for(i=0,n=a.nodes.length;n>i;i++)if(e.id===a.nodes[i].id){s=a.nodes[i];break}for(s||(s={id:e.id},t.node&&(s.attr=r(s.attr,t.node))),i=o.length-1;i>=0;i--){var h=o[i];h.nodes||(h.nodes=[]),-1==h.nodes.indexOf(s)&&h.nodes.push(s)}e.attr&&(s.attr=r(s.attr,e.attr))}function d(t,e){if(t.edges||(t.edges=[]),t.edges.push(e),t.edge){var i=r({},t.edge);e.attr=r(i,e.attr)}}function c(t,e,i,n,s){var o={from:e,to:i,type:n};return t.edge&&(o.attr=r({},t.edge)),o.attr=r(o.attr||{},s),o}function l(){for(I=T.NULL,O="";" "==D||" "==D||"\n"==D||"\r"==D;)n();do{var t=!1;if("#"==D){for(var e=M-1;" "==C.charAt(e)||" "==C.charAt(e);)e--;if("\n"==C.charAt(e)||""==C.charAt(e)){for(;""!=D&&"\n"!=D;)n();t=!0}}if("/"==D&&"/"==s()){for(;""!=D&&"\n"!=D;)n();t=!0}if("/"==D&&"*"==s()){for(;""!=D;){if("*"==D&&"/"==s()){n(),n();break}n()}t=!0}for(;" "==D||" "==D||"\n"==D||"\r"==D;)n()}while(t);if(""==D)return void(I=T.DELIMITER);var i=D+s();if(x[i])return I=T.DELIMITER,O=i,n(),void n();if(x[D])return I=T.DELIMITER,O=D,void n();if(o(D)||"-"==D){for(O+=D,n();o(D);)O+=D,n();return"false"==O?O=!1:"true"==O?O=!0:isNaN(Number(O))||(O=Number(O)),void(I=T.IDENTIFIER)}if('"'==D){for(n();""!=D&&('"'!=D||'"'==D&&'"'==s());)O+=D,'"'==D&&n(),n();if('"'!=D)throw w('End of string " expected');return n(),void(I=T.IDENTIFIER)}for(I=T.UNKNOWN;""!=D;)O+=D,n();throw new SyntaxError('Syntax error in part "'+b(O,30)+'"')}function u(){var t={};if(i(),l(),"strict"==O&&(t.strict=!0,l()),("graph"==O||"digraph"==O)&&(t.type=O,l()),I==T.IDENTIFIER&&(t.id=O,l()),"{"!=O)throw w("Angle bracket { expected");if(l(),p(t),"}"!=O)throw w("Angle bracket } expected");if(l(),""!==O)throw w("End of file expected");return l(),delete t.node,delete t.edge,delete t.graph,t}function p(t){for(;""!==O&&"}"!=O;)f(t),";"==O&&l()}function f(t){var e=g(t);if(e)return void y(t,e);var i=m(t);if(!i){if(I!=T.IDENTIFIER)throw w("Identifier expected");var n=O;if(l(),"="==O){if(l(),I!=T.IDENTIFIER)throw w("Identifier expected");t[n]=O,l()}else v(t,n)}}function g(t){var e=null;if("subgraph"==O&&(e={},e.type="subgraph",l(),I==T.IDENTIFIER&&(e.id=O,l())),"{"==O){if(l(),e||(e={}),e.parent=t,e.node=t.node,e.edge=t.edge,e.graph=t.graph,p(e),"}"!=O)throw w("Angle bracket } expected");l(),delete e.node,delete e.edge,delete e.graph,delete e.parent,t.subgraphs||(t.subgraphs=[]),t.subgraphs.push(e)}return e}function m(t){return"node"==O?(l(),t.node=_(),"node"):"edge"==O?(l(),t.edge=_(),"edge"):"graph"==O?(l(),t.graph=_(),"graph"):null}function v(t,e){var i={id:e},n=_();n&&(i.attr=n),h(t,i),y(t,e)}function y(t,e){for(;"->"==O||"--"==O;){var i,n=O;l();var s=g(t);if(s)i=s;else{if(I!=T.IDENTIFIER)throw w("Identifier or subgraph expected");i=O,h(t,{id:i}),l()}var o=_(),r=c(t,e,i,n,o);d(t,r),e=i}}function _(){for(var t=null;"["==O;){for(l(),t={};""!==O&&"]"!=O;){if(I!=T.IDENTIFIER)throw w("Attribute name expected");var e=O;if(l(),"="!=O)throw w("Equal sign = expected");if(l(),I!=T.IDENTIFIER)throw w("Attribute value expected");var i=O;a(t,e,i),l(),","==O&&l()}if("]"!=O)throw w("Bracket ] expected");l()}return t}function w(t){return new SyntaxError(t+', got "'+b(O,30)+'" (char '+M+")")}function b(t,e){return t.length<=e?t:t.substr(0,27)+"..."}function S(t,e,i){t instanceof Array?t.forEach(function(t){e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}):e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}function E(t){function i(t){var e={from:t.from,to:t.to};return r(e,t.attr),e.style="->"==t.type?"arrow":"line",e}var n=e(t),s={nodes:[],edges:[],options:{}};return n.nodes&&n.nodes.forEach(function(t){var e={id:t.id,label:String(t.label||t.id)};r(e,t.attr),e.image&&(e.shape="image"),s.nodes.push(e)}),n.edges&&n.edges.forEach(function(t){var e,n;e=t.from instanceof Object?t.from.nodes:{id:t.from},n=t.to instanceof Object?t.to.nodes:{id:t.to},t.from instanceof Object&&t.from.edges&&t.from.edges.forEach(function(t){var e=i(t);s.edges.push(e)}),S(e,n,function(e,n){var o=c(s,e.id,n.id,t.type,t.attr),r=i(o);s.edges.push(r)}),t.to instanceof Object&&t.to.edges&&t.to.edges.forEach(function(t){var e=i(t);s.edges.push(e)})}),n.attr&&(s.options=n.attr),s}var T={NULL:0,DELIMITER:1,IDENTIFIER:2,UNKNOWN:3},x={"{":!0,"}":!0,"[":!0,"]":!0,";":!0,"=":!0,",":!0,"->":!0,"--":!0},C="",M=0,D="",O="",I=T.NULL,N=/[a-zA-Z_0-9.:#]/;t.parseDOT=e,t.DOTToGraph=E}("undefined"!=typeof z?z:n),"undefined"!=typeof CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.circle=function(t,e,i){this.beginPath(),this.arc(t,e,i,0,2*Math.PI,!1)},CanvasRenderingContext2D.prototype.square=function(t,e,i){this.beginPath(),this.rect(t-i,e-i,2*i,2*i)},CanvasRenderingContext2D.prototype.triangle=function(t,e,i){this.beginPath();var n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e-(r-o)),this.lineTo(t+s,e+o),this.lineTo(t-s,e+o),this.lineTo(t,e-(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.triangleDown=function(t,e,i){this.beginPath();var n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e+(r-o)),this.lineTo(t+s,e-o),this.lineTo(t-s,e-o),this.lineTo(t,e+(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.star=function(t,e,i){this.beginPath();for(var n=0;10>n;n++){var s=n%2===0?1.3*i:.5*i;this.lineTo(t+s*Math.sin(2*n*Math.PI/10),e-s*Math.cos(2*n*Math.PI/10))}this.closePath()},CanvasRenderingContext2D.prototype.roundRect=function(t,e,i,n,s){var o=Math.PI/180;0>i-2*s&&(s=i/2),0>n-2*s&&(s=n/2),this.beginPath(),this.moveTo(t+s,e),this.lineTo(t+i-s,e),this.arc(t+i-s,e+s,s,270*o,360*o,!1),this.lineTo(t+i,e+n-s),this.arc(t+i-s,e+n-s,s,0,90*o,!1),this.lineTo(t+s,e+n),this.arc(t+s,e+n-s,s,90*o,180*o,!1),this.lineTo(t,e+s),this.arc(t+s,e+s,s,180*o,270*o,!1)},CanvasRenderingContext2D.prototype.ellipse=function(t,e,i,n){var s=.5522848,o=i/2*s,r=n/2*s,a=t+i,h=e+n,d=t+i/2,c=e+n/2;this.beginPath(),this.moveTo(t,c),this.bezierCurveTo(t,c-r,d-o,e,d,e),this.bezierCurveTo(d+o,e,a,c-r,a,c),this.bezierCurveTo(a,c+r,d+o,h,d,h),this.bezierCurveTo(d-o,h,t,c+r,t,c)},CanvasRenderingContext2D.prototype.database=function(t,e,i,n){var s=1/3,o=i,r=n*s,a=.5522848,h=o/2*a,d=r/2*a,c=t+o,l=e+r,u=t+o/2,p=e+r/2,f=e+(n-r/2),g=e+n;this.beginPath(),this.moveTo(c,p),this.bezierCurveTo(c,p+d,u+h,l,u,l),this.bezierCurveTo(u-h,l,t,p+d,t,p),this.bezierCurveTo(t,p-d,u-h,e,u,e),this.bezierCurveTo(u+h,e,c,p-d,c,p),this.lineTo(c,f),this.bezierCurveTo(c,f+d,u+h,g,u,g),this.bezierCurveTo(u-h,g,t,f+d,t,f),this.lineTo(t,p)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,n){var s=t-n*Math.cos(i),o=e-n*Math.sin(i),r=t-.9*n*Math.cos(i),a=e-.9*n*Math.sin(i),h=s+n/3*Math.cos(i+.5*Math.PI),d=o+n/3*Math.sin(i+.5*Math.PI),c=s+n/3*Math.cos(i-.5*Math.PI),l=o+n/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,d),this.lineTo(r,a),this.lineTo(c,l),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,n,s){s||(s=[10,5]),0==u&&(u=.001);var o=s.length;this.moveTo(t,e);for(var r=i-t,a=n-e,h=a/r,d=Math.sqrt(r*r+a*a),c=0,l=!0;d>=.1;){var u=s[c++%o];u>d&&(u=d);var p=Math.sqrt(u*u/(1+h*h));0>r&&(p=-p),t+=p,e+=h*p,this[l?"lineTo":"moveTo"](t,e),d-=u,l=!l}}),M.prototype.resetCluster=function(){this.formationScale=void 0,this.clusterSize=1,this.containedNodes={},this.containedEdges={},this.clusterSessions=[]},M.prototype.attachEdge=function(t){-1==this.edges.indexOf(t)&&this.edges.push(t),-1==this.dynamicEdges.indexOf(t)&&this.dynamicEdges.push(t),this.dynamicEdgesLength=this.dynamicEdges.length,this._updateMass()},M.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&(this.edges.splice(e,1),this.dynamicEdges.splice(e,1)),this.dynamicEdgesLength=this.dynamicEdges.length,this._updateMass()},M.prototype._updateMass=function(){this.mass=1+.6*this.edges.length},M.prototype.setProperties=function(t,e){if(t){if(this.originalLabel=void 0,void 0!==t.id&&(this.id=t.id),void 0!==t.label&&(this.label=t.label,this.originalLabel=t.label),void 0!==t.title&&(this.title=t.title),void 0!==t.group&&(this.group=t.group),void 0!==t.x&&(this.x=t.x),void 0!==t.y&&(this.y=t.y),void 0!==t.value&&(this.value=t.value),void 0!==t.horizontalAlignLeft&&(this.horizontalAlignLeft=t.horizontalAlignLeft),void 0!==t.verticalAlignTop&&(this.verticalAlignTop=t.verticalAlignTop),void 0!==t.triggerFunction&&(this.triggerFunction=t.triggerFunction),void 0===this.id)throw"Node must have an id";if(this.group){var i=this.grouplist.get(this.group);for(var n in i)i.hasOwnProperty(n)&&(this[n]=i[n])}if(void 0!==t.shape&&(this.shape=t.shape),void 0!==t.image&&(this.image=t.image),void 0!==t.radius&&(this.radius=t.radius),void 0!==t.color&&(this.color=M.parseColor(t.color)),void 0!==t.fontColor&&(this.fontColor=t.fontColor),void 0!==t.fontSize&&(this.fontSize=t.fontSize),void 0!==t.fontFace&&(this.fontFace=t.fontFace),void 0!==this.image){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.image)}switch(this.xFixed=this.xFixed||void 0!==t.x&&t.fixed,this.yFixed=this.yFixed||void 0!==t.y&&t.fixed,this.radiusFixed=this.radiusFixed||void 0!==t.radius,"image"==this.shape&&(this.radiusMin=e.nodes.widthMin,this.radiusMax=e.nodes.widthMax),this.shape){case"database":this.draw=this._drawDatabase,this.resize=this._resizeDatabase;break;case"box":this.draw=this._drawBox,this.resize=this._resizeBox;break;case"circle":this.draw=this._drawCircle,this.resize=this._resizeCircle;break;case"ellipse":this.draw=this._drawEllipse,this.resize=this._resizeEllipse;break;case"image":this.draw=this._drawImage,this.resize=this._resizeImage;break;case"text":this.draw=this._drawText,this.resize=this._resizeText;break;case"dot":this.draw=this._drawDot,this.resize=this._resizeShape;break;case"square":this.draw=this._drawSquare,this.resize=this._resizeShape;break;case"triangle":this.draw=this._drawTriangle,this.resize=this._resizeShape;break;case"triangleDown":this.draw=this._drawTriangleDown,this.resize=this._resizeShape;break;case"star":this.draw=this._drawStar,this.resize=this._resizeShape;break;default:this.draw=this._drawEllipse,this.resize=this._resizeEllipse}this._reset()}},M.parseColor=function(t){var e;return z.isString(t)?e={border:t,background:t,highlight:{border:t,background:t}}:(e={},e.background=t.background||"white",e.border=t.border||e.background,z.isString(t.highlight)?e.highlight={border:t.highlight,background:t.highlight}:(e.highlight={},e.highlight.background=t.highlight&&t.highlight.background||e.background,e.highlight.border=t.highlight&&t.highlight.border||e.border)),e},M.prototype.select=function(){this.selected=!0,this._reset()},M.prototype.unselect=function(){this.selected=!1,this._reset()},M.prototype.clearSizeCache=function(){this._reset()},M.prototype._reset=function(){this.width=void 0,this.height=void 0},M.prototype.getTitle=function(){return this.title},M.prototype.distanceToBorder=function(t,e){var i=1;switch(this.width||this.resize(t),this.shape){case"circle":case"dot":return this.radius+i;case"ellipse":var n=this.width/2,s=this.height/2,o=Math.sin(e)*n,r=Math.cos(e)*s; +return n*s/Math.sqrt(o*o+r*r);case"box":case"image":case"text":default:return this.width?Math.min(Math.abs(this.width/2/Math.cos(e)),Math.abs(this.height/2/Math.sin(e)))+i:0}},M.prototype._setForce=function(t,e){this.fx=t,this.fy=e},M.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},M.prototype.discreteStep=function(t){if(!this.xFixed){var e=-this.damping*this.vx,i=(this.fx+e)/this.mass;this.vx+=i*t,this.x+=this.vx*t}if(!this.yFixed){var n=-this.damping*this.vy,s=(this.fy+n)/this.mass;this.vy+=s*t,this.y+=this.vy*t}},M.prototype.isFixed=function(){return this.xFixed&&this.yFixed},M.prototype.isMoving=function(t){return Math.abs(this.vx)>t||Math.abs(this.vy)>t?!0:(this.vx=0,this.vy=0,!1)},M.prototype.isSelected=function(){return this.selected},M.prototype.getValue=function(){return this.value},M.prototype.getDistance=function(t,e){var i=this.x-t,n=this.y-e;return Math.sqrt(i*i+n*n)},M.prototype.setValueRange=function(t,e){if(!this.radiusFixed&&void 0!==this.value)if(e==t)this.radius=(this.radiusMin+this.radiusMax)/2;else{var i=(this.radiusMax-this.radiusMin)/(e-t);this.radius=(this.value-t)*i+this.radiusMin}this.baseRadiusValue=this.radius},M.prototype.draw=function(){throw"Draw method not initialized for node"},M.prototype.resize=function(){throw"Resize method not initialized for node"},M.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},M.prototype._resizeImage=function(){if(!this.width||!this.height){var t,e;if(this.value){this.radius=this.baseRadiusValue;var i=this.imageObj.height/this.imageObj.width;void 0!==i?(t=this.radius||this.imageObj.width,e=this.radius*i||this.imageObj.height):(t=0,e=0)}else t=this.imageObj.width,e=this.imageObj.height;this.width=t,this.height=e,this.width>0&&this.height>0&&(this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor)}},M.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e;if(0!=this.imageObj.width){if(this.clusterSize>1){var i=this.clusterSize>1?10:0;i*=this.graphScaleInv,i=Math.min(.2*this.width,i),t.globalAlpha=.5,t.drawImage(this.imageObj,this.left-i,this.top-i,this.width+2*i,this.height+2*i)}t.globalAlpha=1,t.drawImage(this.imageObj,this.left,this.top,this.width,this.height),e=this.y+this.height/2}else e=this.y;this._label(t,this.label,this.x,e,void 0,"top")},M.prototype._resizeBox=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=.5*(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=.5*(this.clusterSize-1)*this.clusterSizeHeightFactor}},M.prototype._drawBox=function(t){this._resizeBox(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.roundRect(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth,this.radius),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.roundRect(this.left,this.top,this.width,this.height,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeDatabase=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=i.width+2*e;this.width=n,this.height=n,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawDatabase=function(t){this._resizeDatabase(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.database(this.x-this.width/2-2*t.lineWidth,this.y-.5*this.height-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.database(this.x-this.width/2,this.y-.5*this.height,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=Math.max(i.width,i.height)+2*e;this.radius=n/2,this.width=n,this.height=n,this.radius+=.5*(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawCircle=function(t){this._resizeCircle(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.circle(this.x,this.y,this.radius+2*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.circle(this.x,this.y,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeEllipse=function(t){if(!this.width){var e=this.getTextSize(t);this.width=1.5*e.width,this.height=2*e.height,this.width1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.ellipse(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.ellipse(this.left,this.top,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._drawDot=function(t){this._drawShape(t,"circle")},M.prototype._drawTriangle=function(t){this._drawShape(t,"triangle")},M.prototype._drawTriangleDown=function(t){this._drawShape(t,"triangleDown")},M.prototype._drawSquare=function(t){this._drawShape(t,"square")},M.prototype._drawStar=function(t){this._drawShape(t,"star")},M.prototype._resizeShape=function(){if(!this.width){this.radius=this.baseRadiusValue;var t=2*this.radius;this.width=t,this.height=t,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=.5*(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawShape=function(t,e){this._resizeShape(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var i=2.5,n=2,s=2;switch(e){case"dot":s=2;break;case"square":s=2;break;case"triangle":s=3;break;case"triangleDown":s=3;break;case"star":s=4}t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?n:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t[e](this.x,this.y,this.radius+s*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?n:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t[e](this.x,this.y,this.radius),t.fill(),t.stroke(),this.label&&this._label(t,this.label,this.x,this.y+this.height/2,void 0,"top")},M.prototype._resizeText=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawText=function(t){this._resizeText(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,this._label(t,this.label,this.x,this.y)},M.prototype._label=function(t,e,i,n,s,o){if(e){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle=this.fontColor||"black",t.textAlign=s||"center",t.textBaseline=o||"middle";for(var r=e.split("\n"),a=r.length,h=this.fontSize+4,d=n+(1-a)/2*h,c=0;a>c;c++)t.fillText(r[c],i,d),d+=h}},M.prototype.getTextSize=function(t){if(void 0!==this.label){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace;for(var e=this.label.split("\n"),i=(this.fontSize+4)*e.length,n=0,s=0,o=e.length;o>s;s++)n=Math.max(n,t.measureText(e[s]).width);return{width:n,height:i}}return{width:0,height:0}},M.prototype.inArea=function(){return void 0!==this.width?this.x+this.width*this.graphScaleInv>=this.canvasTopLeft.x&&this.x-this.width*this.graphScaleInv=this.canvasTopLeft.y&&this.y-this.height*this.graphScaleInv=this.canvasTopLeft.x&&this.x=this.canvasTopLeft.y&&this.yh},D.prototype._drawLine=function(t){t.strokeStyle=this.color,t.lineWidth=this._getLineWidth();var e;if(this.from!=this.to)this._line(t),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y));else{var i,n,s=this.length/4,o=this.from;o.width||o.resize(t),o.width>o.height?(i=o.x+o.width/2,n=o.y-s):(i=o.x+s,n=o.y-o.height/2),this._circle(t,i,n,s),e=this._pointOnCircle(i,n,s,.5),this._label(t,this.label,e.x,e.y)}},D.prototype._getLineWidth=function(){return 1==this.selected?Math.min(2*this.width,this.widthMax)*this.graphScaleInv:this.width*this.graphScaleInv},D.prototype._line=function(t){t.beginPath(),t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y),t.stroke()},D.prototype._circle=function(t,e,i,n){t.beginPath(),t.arc(e,i,n,0,2*Math.PI,!1),t.stroke()},D.prototype._label=function(t,e,i,n){if(e){t.font=(this.from.selected||this.to.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle="white";var s=t.measureText(e).width,o=this.fontSize,r=i-s/2,a=n-o/2;t.fillRect(r,a,s,o),t.fillStyle=this.fontColor||"black",t.textAlign="left",t.textBaseline="top",t.fillText(e,r,a)}},D.prototype._drawDashLine=function(t){if(t.strokeStyle=this.color,t.lineWidth=this._getLineWidth(),t.beginPath(),t.lineCap="round",void 0!==this.dash.altLength?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]):void 0!==this.dash.length&&void 0!==this.dash.gap?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap]):(t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y)),t.stroke(),this.label){var e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}},D.prototype._pointOnLine=function(t){return{x:(1-t)*this.from.x+t*this.to.x,y:(1-t)*this.from.y+t*this.to.y}},D.prototype._pointOnCircle=function(t,e,i,n){var s=2*(n-3/8)*Math.PI;return{x:t+i*Math.cos(s),y:e-i*Math.sin(s)}},D.prototype._drawArrowCenter=function(t){var e;if(t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth(),this.from!=this.to){this._line(t);var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),n=10+5*this.width;e=this._pointOnLine(.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y))}else{var s,o,r=this.length/4,a=this.from;a.width||a.resize(t),a.width>a.height?(s=a.x+a.width/2,o=a.y-r):(s=a.x+r,o=a.y-a.height/2),this._circle(t,s,o,r);var i=.2*Math.PI,n=10+5*this.width;e=this._pointOnCircle(s,o,r,.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(s,o,r,.5),this._label(t,this.label,e.x,e.y))}},D.prototype._drawArrow=function(t){t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth();var e,i;if(this.from!=this.to){e=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x);var n=this.to.x-this.from.x,s=this.to.y-this.from.y,o=Math.sqrt(n*n+s*s),r=this.from.distanceToBorder(t,e+Math.PI),a=(o-r)/o,h=a*this.from.x+(1-a)*this.to.x,d=a*this.from.y+(1-a)*this.to.y,c=this.to.distanceToBorder(t,e),l=(o-c)/o,u=(1-l)*this.from.x+l*this.to.x,p=(1-l)*this.from.y+l*this.to.y;if(t.beginPath(),t.moveTo(h,d),t.lineTo(u,p),t.stroke(),i=10+5*this.width,t.arrow(u,p,e,i),t.fill(),t.stroke(),this.label){var f=this._pointOnLine(.5);this._label(t,this.label,f.x,f.y)}}else{var g,m,v,y=this.from,_=this.length/4;y.width||y.resize(t),y.width>y.height?(g=y.x+y.width/2,m=y.y-_,v={x:g,y:y.y,angle:.9*Math.PI}):(g=y.x+_,m=y.y-y.height/2,v={x:y.x,y:m,angle:.6*Math.PI}),t.beginPath(),t.arc(g,m,_,0,2*Math.PI,!1),t.stroke(),i=10+5*this.width,t.arrow(v.x,v.y,v.angle,i),t.fill(),t.stroke(),this.label&&(f=this._pointOnCircle(g,m,_,.5),this._label(t,this.label,f.x,f.y))}},D._dist=function(t,e,i,n,s,o){var r=i-t,a=n-e,h=r*r+a*a,d=((s-t)*r+(o-e)*a)/h;d>1?d=1:0>d&&(d=0);var c=t+d*r,l=e+d*a,u=c-s,p=l-o;return Math.sqrt(u*u+p*p)},D.prototype.setScale=function(t){this.graphScaleInv=1/t},D.prototype.select=function(){this.selected=!0},D.prototype.unselect=function(){this.selected=!1},O.prototype.setPosition=function(t,e){this.x=parseInt(t),this.y=parseInt(e)},O.prototype.setText=function(t){this.frame.innerHTML=t},O.prototype.show=function(t){if(void 0===t&&(t=!0),t){var e=this.frame.clientHeight,i=this.frame.clientWidth,n=this.frame.parentNode.clientHeight,s=this.frame.parentNode.clientWidth,o=this.y-e;o+e+this.padding>n&&(o=n-e-this.padding),os&&(r=s-i-this.padding),rAdd Node
    Connect Node
    Delete selected";var t=document.getElementById("manipulate-addNode");t.onclick=this._createAddToolbar.bind(this);var e=document.getElementById("manipulate-connectNode");e.onclick=this._createConnectToolbar.bind(this);var i=document.getElementById("manipulate-delete");i.onclick=this._deleteSelected.bind(this)},_createAddToolbar:function(){for(;this.manipulationDiv.hasChildNodes();)this.manipulationDiv.removeChild(this.manipulationDiv.firstChild);this.manipulationDiv.innerHTML="Back
    Click in an empty space to place a new node";var t=document.getElementById("manipulate-back");t.onclick=this._createManipulatorBar.bind(this);var e=this;F.addListener(e,"select",e._addNode.bind(e))},_createConnectToolbar:function(){for(;this.manipulationDiv.hasChildNodes();)this.manipulationDiv.removeChild(this.manipulationDiv.firstChild);var t="hello";this._selectionIsEmpty()||(t="Select the node you want to connect to other nodes"),this.manipulationDiv.innerHTML="Back
    "+t+"";var e=document.getElementById("manipulate-back");e.onclick=this._createManipulatorBar.bind(this);var i=this;F.addListener(i,"select",function(){alert(i.selectForConnect)})},_continueConnect:function(){if(this._clusterInSelection())return this._unselectAll(),this._createConnectToolbar("Select the node you want to connect (Clusters are not allowed)."),!0;if(this._selectionIsEmpty()){{document.getElementById.manipolatorLabel}return!1}return this._connectNodes(),!0},_addNode:function(t){if(console.log("HERE",this),this._selectionIsEmpty()){var e=this._pointerToPositionObject(t);this.nodesData.add({id:z.randomUUID(),x:e.left,y:e.top,label:"new",fixed:!1}),this.moving=!0,this.start()}},_connectNodes:function(){console.log(this.selectionObj)},_deleteSelected:function(){if(this._clusterInSelection())alert("Clusters cannot be deleted.");else{var t=this.getSelectedNodes(),e=this.getSelectedEdges();this._removeEdges(e),this._removeNodes(t),this._redraw()}}},R={_putDataInSector:function(){this.sectors.active[this._sector()].nodes=this.nodes,this.sectors.active[this._sector()].edges=this.edges,this.sectors.active[this._sector()].nodeIndices=this.nodeIndices},_switchToSector:function(t,e){void 0===e||"active"==e?this._switchToActiveSector(t):this._switchToFrozenSector(t)},_switchToActiveSector:function(t){this.nodeIndices=this.sectors.active[t].nodeIndices,this.nodes=this.sectors.active[t].nodes,this.edges=this.sectors.active[t].edges},_switchToFrozenSector:function(t){this.nodeIndices=this.sectors.frozen[t].nodeIndices,this.nodes=this.sectors.frozen[t].nodes,this.edges=this.sectors.frozen[t].edges},_switchToNavigationSector:function(){this.nodeIndices=this.sectors.navigation.nodeIndices,this.nodes=this.sectors.navigation.nodes,this.edges=this.sectors.navigation.edges},_loadLatestSector:function(){this._switchToSector(this._sector())},_sector:function(){return this.activeSector[this.activeSector.length-1]},_previousSector:function(){if(this.activeSector.length>1)return this.activeSector[this.activeSector.length-2];throw new TypeError("there are not enough sectors in the this.activeSector array.")},_setActiveSector:function(t){this.activeSector.push(t)},_forgetLastSector:function(){this.activeSector.pop()},_createNewSector:function(t){this.sectors.active[t]={nodes:{},edges:{},nodeIndices:[],formationScale:this.scale,drawingNode:void 0},this.sectors.active[t].drawingNode=new M({id:t,color:{background:"#eaefef",border:"495c5e"}},{},{},this.constants),this.sectors.active[t].drawingNode.clusterSize=2},_deleteActiveSector:function(t){delete this.sectors.active[t]},_deleteFrozenSector:function(t){delete this.sectors.frozen[t]},_freezeSector:function(t){this.sectors.frozen[t]=this.sectors.active[t],this._deleteActiveSector(t)},_activateSector:function(t){this.sectors.active[t]=this.sectors.frozen[t],this._deleteFrozenSector(t)},_mergeThisWithFrozen:function(t){for(var e in this.nodes)this.nodes.hasOwnProperty(e)&&(this.sectors.frozen[t].nodes[e]=this.nodes[e]);for(var i in this.edges)this.edges.hasOwnProperty(i)&&(this.sectors.frozen[t].edges[i]=this.edges[i]);for(var n=0;n1?this[t](n[0],n[1]):this[t](e)}this._loadLatestSector()},_doInAllFrozenSectors:function(t,e){if(void 0===e)for(var i in this.sectors.frozen)this.sectors.frozen.hasOwnProperty(i)&&(this._switchToFrozenSector(i),this[t]());else for(var i in this.sectors.frozen)if(this.sectors.frozen.hasOwnProperty(i)){this._switchToFrozenSector(i);var n=Array.prototype.splice.call(arguments,1);n.length>1?this[t](n[0],n[1]):this[t](e)}this._loadLatestSector()},_doInNavigationSector:function(t,e){if(this._switchToNavigationSector(),void 0===e)this[t]();else{var i=Array.prototype.splice.call(arguments,1);i.length>1?this[t](i[0],i[1]):this[t](e)}this._loadLatestSector()},_doInAllSectors:function(t,e){var i=Array.prototype.splice.call(arguments,1);void 0===e?(this._doInAllActiveSectors(t),this._doInAllFrozenSectors(t)):i.length>1?(this._doInAllActiveSectors(t,i[0],i[1]),this._doInAllFrozenSectors(t,i[0],i[1])):(this._doInAllActiveSectors(t,e),this._doInAllFrozenSectors(t,e))},_clearNodeIndexList:function(){var t=this._sector();this.sectors.active[t].nodeIndices=[],this.nodeIndices=this.sectors.active[t].nodeIndices},_drawSectorNodes:function(t,e){var i,n=1e9,s=-1e9,o=1e9,r=-1e9;for(var a in this.sectors[e])if(this.sectors[e].hasOwnProperty(a)&&void 0!==this.sectors[e][a].drawingNode){this._switchToSector(a,e),n=1e9,s=-1e9,o=1e9,r=-1e9;for(var h in this.nodes)this.nodes.hasOwnProperty(h)&&(i=this.nodes[h],i.resize(t),o>i.x-.5*i.width&&(o=i.x-.5*i.width),ri.y-.5*i.height&&(n=i.y-.5*i.height),st&&n>s;)s%3==0?this.forceAggregateHubs():this.increaseClusterLevel(),i=this.nodeIndices.length,s+=1;s>1&&1==e&&this.repositionNodes()},openCluster:function(t){var e=this.moving;if(t.clusterSize>this.constants.clustering.sectorThreshold&&this._nodeInActiveArea(t)&&("default"!=this._sector()||1!=this.nodeIndices.length)){this._addSector(t);for(var i=0;this.nodeIndices.lengthi;)this.decreaseClusterLevel(),i+=1}else this._expandClusterNode(t,!1,!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels();this.moving!=e&&this.start()},updateClustersDefault:function(){1==this.constants.clustering.enabled&&this.updateClusters(0,!1,!1)},increaseClusterLevel:function(){this.updateClusters(-1,!1,!0)},decreaseClusterLevel:function(){this.updateClusters(1,!1,!0)},updateClusters:function(t,e,i){var n=this.moving,s=this.nodeIndices.length;this.previousScale>this.scale&&0==t&&this._collapseSector(),this.previousScale>this.scale||-1==t?this._formClusters(i):(this.previousScalethis.scale||-1==t)&&(this._aggregateHubs(i),this._updateNodeIndexList()),(this.previousScale>this.scale||-1==t)&&(this.handleChains(),this._updateNodeIndexList()),this.previousScale=this.scale,this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.lengththis.constants.clustering.chainThreshold&&this._reduceAmountOfChains(1-this.constants.clustering.chainThreshold/t)},_aggregateHubs:function(t){this._getHubSize(),this._formClustersByHub(t,!1)},forceAggregateHubs:function(){var t=this.moving,e=this.nodeIndices.length;this._aggregateHubs(!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.length!=e&&(this.clusterSession+=1),this.moving!=t&&this.start()},_openClustersBySize:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];1==e.inView()&&(e.width*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientWidth||e.height*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientHeight)&&this.openCluster(e)}},_openClusters:function(t,e){for(var i=0;i1&&(t.clusterSizei)){var r=o.from,a=o.to; +o.to.mass>o.from.mass&&(r=o.to,a=o.from),1==a.dynamicEdgesLength?this._addToCluster(r,a,!1):1==r.dynamicEdgesLength&&this._addToCluster(a,r,!1)}}},_forceClustersByZoom:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];if(1==e.dynamicEdgesLength&&0!=e.dynamicEdges.length){var i=e.dynamicEdges[0],n=i.toId==e.id?this.nodes[i.fromId]:this.nodes[i.toId];e.id!=n.id&&(n.mass>e.mass?this._addToCluster(n,e,!0):this._addToCluster(e,n,!0))}}},_formClustersByHub:function(t,e){for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&this._formClusterFromHub(this.nodes[i],t,e)},_formClusterFromHub:function(t,e,i,n){if(void 0===n&&(n=0),t.dynamicEdgesLength>=this.hubThreshold&&0==i||t.dynamicEdgesLength==this.hubThreshold&&1==i){for(var s,o,r,a=this.constants.clustering.clusterEdgeThreshold/this.scale,h=!1,d=[],c=t.dynamicEdges.length,l=0;c>l;l++)d.push(t.dynamicEdges[l].id);if(0==e)for(h=!1,l=0;c>l;l++){var u=this.edges[d[l]];if(void 0!==u&&u.connected&&u.toId!=u.fromId&&(s=u.to.x-u.from.x,o=u.to.y-u.from.y,r=Math.sqrt(s*s+o*o),a>r)){h=!0;break}}if(!e&&h||e)for(l=0;c>l;l++)if(u=this.edges[d[l]],void 0!==u){var p=this.nodes[u.fromId==t.id?u.toId:u.fromId];p.dynamicEdges.length<=this.hubThreshold+n&&p.id!=t.id&&this._addToCluster(t,p,e)}}},_addToCluster:function(t,e,i){t.containedNodes[e.id]=e;for(var n=0;n1)for(var n=0;n1&&(e.label="[".concat(String(e.clusterSize),"]"))}for(t in this.nodes)this.nodes.hasOwnProperty(t)&&(e=this.nodes[t],1==e.clusterSize&&(e.label=void 0!==e.originalLabel?e.originalLabel:String(e.id)))},_nodeInActiveArea:function(t){return Math.abs(t.x-this.areaCenter.x)<=this.constants.clustering.activeAreaBoxSize/this.scale&&Math.abs(t.y-this.areaCenter.y)<=this.constants.clustering.activeAreaBoxSize/this.scale},repositionNodes:function(){for(var t=0;tn&&(n=o.dynamicEdgesLength),t+=o.dynamicEdgesLength,e+=Math.pow(o.dynamicEdgesLength,2),i+=1}t/=i,e/=i;var r=e-Math.pow(t,2),a=Math.sqrt(r);this.hubThreshold=Math.floor(t+2*a),this.hubThreshold>n&&(this.hubThreshold=n)},_reduceAmountOfChains:function(t){this.hubThreshold=2;var e=Math.floor(this.nodeIndices.length*t);for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&e>0&&(this._formClusterFromHub(this.nodes[i],!0,!0,1),e-=1)},_getChainFraction:function(){var t=0,e=0;for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&(2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&(t+=1),e+=1);return t/e}},j={_getNodesOverlappingWith:function(t,e){var i=this.nodes;for(var n in i)i.hasOwnProperty(n)&&i[n].isOverlappingWith(t)&&e.push(n)},_getAllNodesOverlappingWith:function(t){var e=[];return this._doInAllActiveSectors("_getNodesOverlappingWith",t,e),e},_getAllNavigationNodesOverlappingWith:function(t){var e=[];return this._doInNavigationSector("_getNodesOverlappingWith",t,e),e},_pointerToPositionObject:function(t){var e=this._canvasToX(t.x),i=this._canvasToY(t.y);return{left:e,top:i,right:e,bottom:i}},_pointerToScreenPositionObject:function(t){var e=t.x,i=t.y;return{left:e,top:i,right:e,bottom:i}},_getNavigationNodeAt:function(t){var e=this._pointerToScreenPositionObject(t),i=this._getAllNavigationNodesOverlappingWith(e);return i.length>0?this.sectors.navigation.nodes[i[i.length-1]]:null},_getNodeAt:function(t){var e=this._pointerToPositionObject(t),i=this._getAllNodesOverlappingWith(e);return i.length>0?this.nodes[i[i.length-1]]:null},_getEdgesOverlappingWith:function(t,e){var i=this.edges;for(var n in i)i.hasOwnProperty(n)&&i[n].isOverlappingWith(t)&&e.push(n)},_getAllEdgesOverlappingWith:function(t){var e=[];return this._doInAllActiveSectors("_getEdgesOverlappingWith",t,e),e},_getEdgeAt:function(t){var e=this._pointerToPositionObject(t),i=this._getAllEdgesOverlappingWith(e);return i.length>0?this.edges[i[i.length-1]]:null},_addToSelection:function(t){this.selectionObj[t.id]=t},_removeFromSelection:function(t){delete this.selectionObj[t.id]},_unselectAll:function(t){void 0===t&&(t=!1);for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e].unselect();this.selectionObj={},0==t&&this._trigger("select",{nodes:this.getSelection()})},_selectionIsEmpty:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t))return!1;return!0},_clusterInSelection:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t)&&this.selectionObj[t]instanceof M&&this.selectionObj[t].clusterSize>1)return!0;return!1},_selectConnectedEdges:function(t){for(var e=0;ee;e++){n=t[e];var s=this.nodes[n];if(!s)throw new RangeError('Node with id "'+n+'" not found');this._selectObject(s,!0,!0)}this.redraw()},_updateSelection:function(){for(var t in this.selectionObj)this.selectionObj.hasOwnProperty(t)&&(this.selectionObj[t]instanceof M?this.nodes.hasOwnProperty(t)||delete this.selectionObj[t]:(this.edges.hasOwnProperty(t)||delete this.selectionObj[t],changed=!0),this.selection=[]);return!changed||1!=triggerSelect&&void 0!=triggerSelect||this._trigger("select",{nodes:this.getSelection()}),changed}},U={_relocateNavigation:function(){if(void 0!==this.sectors){var t=this.navigationClientWidth-this.frame.canvas.clientWidth,e=this.navigationClientHeight-this.frame.canvas.clientHeight;this.navigationClientWidth=this.frame.canvas.clientWidth,this.navigationClientHeight=this.frame.canvas.clientHeight;var i=null;for(var n in this.sectors.navigation.nodes)this.sectors.navigation.nodes.hasOwnProperty(n)&&(i=this.sectors.navigation.nodes[n],i.horizontalAlignLeft||(i.x-=t),i.verticalAlignTop||(i.y-=e))}},_loadNavigationElements:function(){var t=this.constants.navigation.iconPath;this.navigationClientWidth=this.frame.canvas.clientWidth,this.navigationClientHeight=this.frame.canvas.clientHeight,void 0===this.navigationClientWidth&&(this.navigationClientWidth=0,this.navigationClientHeight=0);for(var e=15,i=7,n=[{id:"navigation_up",shape:"image",image:t+"/uparrow.png",triggerFunction:"_moveUp",verticalAlignTop:!1,x:45+e+i,y:this.navigationClientHeight-45-e-i},{id:"navigation_down",shape:"image",image:t+"/downarrow.png",triggerFunction:"_moveDown",verticalAlignTop:!1,x:45+e+i,y:this.navigationClientHeight-15-e},{id:"navigation_left",shape:"image",image:t+"/leftarrow.png",triggerFunction:"_moveLeft",verticalAlignTop:!1,x:15+e,y:this.navigationClientHeight-15-e},{id:"navigation_right",shape:"image",image:t+"/rightarrow.png",triggerFunction:"_moveRight",verticalAlignTop:!1,x:75+e+2*i,y:this.navigationClientHeight-15-e},{id:"navigation_plus",shape:"image",image:t+"/plus.png",triggerFunction:"_zoomIn",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-45-e-i,y:this.navigationClientHeight-15-e},{id:"navigation_min",shape:"image",image:t+"/minus.png",triggerFunction:"_zoomOut",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-15-e,y:this.navigationClientHeight-15-e},{id:"navigation_zoomExtends",shape:"image",image:t+"/zoomExtends.png",triggerFunction:"zoomToFit",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-15-e,y:this.navigationClientHeight-45-e-i}],s=null,o=0;ot.x-t.width&&(n=t.x-t.width),st.y-t.height&&(e=t.y-t.height),i=this.constants.clustering.initialMaxNodes)var n=38.8467/(e-14.50184)+.0116;else var n=42.54117319/(e+39.31966387)+.1944405;else{var s=1.1*(Math.abs(i.minX)+Math.abs(i.maxX)),o=1.1*(Math.abs(i.minY)+Math.abs(i.maxY)),r=this.frame.canvas.clientWidth/s,a=this.frame.canvas.clientHeight/o;n=a>=r?r:a}n>1&&(n=1),this.pinch.mousewheelScale=n,this._setScale(n),this._centerGraph(i),this.start()},I.prototype._updateNodeIndexList=function(){this._clearNodeIndexList();for(var t in this.nodes)this.nodes.hasOwnProperty(t)&&this.nodeIndices.push(t)},I.prototype.setData=function(t,e){if(void 0===e&&(e=!1),t&&t.dot&&(t.nodes||t.edges))throw new SyntaxError('Data must contain either parameter "dot" or parameter pair "nodes" and "edges", but not both.');if(this.setOptions(t&&t.options),t&&t.dot){if(t&&t.dot){var i=V.util.DOTToGraph(t.dot);return void this.setData(i)}}else this._setNodes(t&&t.nodes),this._setEdges(t&&t.edges);this._putDataInSector(),e||(this.stabilize&&this._doStabilize(),this.moving=!0,this.start())},I.prototype.setOptions=function(t){if(t){if(void 0!==t.width&&(this.width=t.width),void 0!==t.height&&(this.height=t.height),void 0!==t.stabilize&&(this.stabilize=t.stabilize),void 0!==t.selectable&&(this.selectable=t.selectable),t.clustering){this.constants.clustering.enabled=!0;for(var e in t.clustering)t.clustering.hasOwnProperty(e)&&(this.constants.clustering[e]=t.clustering[e])}else void 0!==t.clustering&&(this.constants.clustering.enabled=!1);if(t.navigation){this.constants.navigation.enabled=!0;for(var e in t.navigation)t.navigation.hasOwnProperty(e)&&(this.constants.navigation[e]=t.navigation[e])}else void 0!==t.navigation&&(this.constants.navigation.enabled=!1);if(t.keyboard){this.constants.keyboard.enabled=!0;for(var e in t.keyboard)t.keyboard.hasOwnProperty(e)&&(this.constants.keyboard[e]=t.keyboard[e])}else void 0!==t.keyboard&&(this.constants.keyboard.enabled=!1);if(t.edges){for(e in t.edges)t.edges.hasOwnProperty(e)&&(this.constants.edges[e]=t.edges[e]);void 0!==t.edges.length&&t.nodes&&void 0===t.nodes.distance&&(this.constants.edges.length=t.edges.length,this.constants.nodes.distance=1.25*t.edges.length),t.edges.fontColor||(this.constants.edges.fontColor=t.edges.color),t.edges.dash&&(void 0!==t.edges.dash.length&&(this.constants.edges.dash.length=t.edges.dash.length),void 0!==t.edges.dash.gap&&(this.constants.edges.dash.gap=t.edges.dash.gap),void 0!==t.edges.dash.altLength&&(this.constants.edges.dash.altLength=t.edges.dash.altLength))}if(t.nodes){for(e in t.nodes)t.nodes.hasOwnProperty(e)&&(this.constants.nodes[e]=t.nodes[e]);t.nodes.color&&(this.constants.nodes.color=M.parseColor(t.nodes.color))}if(t.groups)for(var i in t.groups)if(t.groups.hasOwnProperty(i)){var n=t.groups[i];this.groups.add(i,n)}}this.setSize(this.width,this.height),this._setTranslation(this.frame.clientWidth/2,this.frame.clientHeight/2),this._setScale(1),this._loadNavigationControls(),this._createKeyBinds(),this._redraw()},I.prototype.on=function(t,e){var i=["select"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());F.addListener(this,t,e)},I.prototype.off=function(t,e){F.removeListener(this,t,e)},I.prototype._trigger=function(t,e){F.trigger(this,t,e)},I.prototype._create=function(){for(;this.containerElement.hasChildNodes();)this.containerElement.removeChild(this.containerElement.firstChild);if(this.frame=document.createElement("div"),this.frame.className="graph-frame",this.frame.style.position="relative",this.frame.style.overflow="hidden",this.frame.style.zIndex="1",this.frame.canvas=document.createElement("canvas"),this.frame.canvas.style.position="relative",this.frame.appendChild(this.frame.canvas),!this.frame.canvas.getContext){var t=document.createElement("DIV");t.style.color="red",t.style.fontWeight="bold",t.style.padding="10px",t.innerHTML="Error: your browser does not support HTML canvas",this.frame.canvas.appendChild(t)}var e=this;this.drag={},this.pinch={},this.hammer=N(this.frame.canvas,{prevent_default:!0}),this.hammer.on("tap",e._onTap.bind(e)),this.hammer.on("doubletap",e._onDoubleTap.bind(e)),this.hammer.on("hold",e._onHold.bind(e)),this.hammer.on("pinch",e._onPinch.bind(e)),this.hammer.on("touch",e._onTouch.bind(e)),this.hammer.on("dragstart",e._onDragStart.bind(e)),this.hammer.on("drag",e._onDrag.bind(e)),this.hammer.on("dragend",e._onDragEnd.bind(e)),this.hammer.on("release",e._onRelease.bind(e)),this.hammer.on("mousewheel",e._onMouseWheel.bind(e)),this.hammer.on("DOMMouseScroll",e._onMouseWheel.bind(e)),this.hammer.on("mousemove",e._onMouseMoveTitle.bind(e)),this.containerElement.appendChild(this.frame)},I.prototype._createKeyBinds=function(){var t=this;this.mousetrap=k,this.mousetrap.reset(),1==this.constants.keyboard.enabled&&(this.mousetrap.bind("up",this._moveUp.bind(t),"keydown"),this.mousetrap.bind("up",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("down",this._moveDown.bind(t),"keydown"),this.mousetrap.bind("down",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("left",this._moveLeft.bind(t),"keydown"),this.mousetrap.bind("left",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("right",this._moveRight.bind(t),"keydown"),this.mousetrap.bind("right",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("=",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("=",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("-",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("-",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("[",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("[",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("]",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("]",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pageup",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("pageup",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pagedown",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("pagedown",this._stopZoom.bind(t),"keyup"))},I.prototype._getPointer=function(t){return{x:t.pageX-V.util.getAbsoluteLeft(this.frame.canvas),y:t.pageY-V.util.getAbsoluteTop(this.frame.canvas)}},I.prototype._onTouch=function(t){this.drag.pointer=this._getPointer(t.gesture.touches[0]),this.drag.pinched=!1,this.pinch.scale=this._getScale(),this._handleTouch(this.drag.pointer)},I.prototype._onDragStart=function(){var t=this.drag,e=this._getNodeAt(t.pointer);if(t.dragging=!0,t.selection=[],t.translation=this._getTranslation(),t.nodeId=null,null!=e){t.nodeId=e.id,e.isSelected()||this._selectObject(e,!1);for(var i in this.selectionObj)if(this.selectionObj.hasOwnProperty(i)){var n=this.selectionObj[i];if(n instanceof M){var s={id:n.id,node:n,x:n.x,y:n.y,xFixed:n.xFixed,yFixed:n.yFixed};n.xFixed=!0,n.yFixed=!0,t.selection.push(s)}}}},I.prototype._onDrag=function(t){if(!this.drag.pinched){var e=this._getPointer(t.gesture.touches[0]),i=this,n=this.drag,s=n.selection;if(s&&s.length){var o=e.x-n.pointer.x,r=e.y-n.pointer.y;s.forEach(function(t){var e=t.node;t.xFixed||(e.x=i._canvasToX(i._xToCanvas(t.x)+o)),t.yFixed||(e.y=i._canvasToY(i._yToCanvas(t.y)+r))}),this.moving||(this.moving=!0,this.start())}else{var a=e.x-this.drag.pointer.x,h=e.y-this.drag.pointer.y;this._setTranslation(this.drag.translation.x+a,this.drag.translation.y+h),this._redraw(),this.moved=!0}}},I.prototype._onDragEnd=function(){this.drag.dragging=!1;var t=this.drag.selection;t&&t.forEach(function(t){t.node.xFixed=t.xFixed,t.node.yFixed=t.yFixed})},I.prototype._onTap=function(t){var e=this._getPointer(t.gesture.touches[0]);this._handleTap(e)},I.prototype._onDoubleTap=function(t){var e=this._getPointer(t.gesture.touches[0]);this._handleDoubleTap(e)},I.prototype._onHold=function(t){var e=this._getPointer(t.gesture.touches[0]);this._handleOnHold(e)},I.prototype._onRelease=function(){this._handleOnRelease()},I.prototype._onPinch=function(t){var e=this._getPointer(t.gesture.center);this.drag.pinched=!0,"scale"in this.pinch||(this.pinch.scale=1);var i=this.pinch.scale*t.gesture.scale;this._zoom(i,e)},I.prototype._zoom=function(t,e){var i=this._getScale();1e-5>t&&(t=1e-5),t>10&&(t=10);var n=this._getTranslation(),s=t/i,o=(1-s)*e.x+n.x*s,r=(1-s)*e.y+n.y*s;return this.areaCenter={x:this._canvasToX(e.x),y:this._canvasToY(e.y)},this.pinch.mousewheelScale=t,this._setScale(t),this._setTranslation(o,r),this.updateClustersDefault(),this._redraw(),t},I.prototype._onMouseWheel=function(t){var e=0;if(t.wheelDelta?e=t.wheelDelta/120:t.detail&&(e=-t.detail/3),e){"mousewheelScale"in this.pinch||(this.pinch.mousewheelScale=1);var i=this.pinch.mousewheelScale,n=e/10;0>e&&(n/=1-n),i*=1+n;var s=z.fakeGesture(this,t),o=this._getPointer(s.center);i=this._zoom(i,o)}t.preventDefault()},I.prototype._onMouseMoveTitle=function(t){var e=z.fakeGesture(this,t),i=this._getPointer(e.center);this.popupNode&&this._checkHidePopup(i);var n=this,s=function(){n._checkShowPopup(i)};this.popupTimer&&clearInterval(this.popupTimer),this.drag.dragging||(this.popupTimer=setTimeout(s,300))},I.prototype._checkShowPopup=function(t){var e,i={left:this._canvasToX(t.x),top:this._canvasToY(t.y),right:this._canvasToX(t.x),bottom:this._canvasToY(t.y)},n=this.popupNode;if(void 0==this.popupNode){var s=this.nodes;for(e in s)if(s.hasOwnProperty(e)){var o=s[e];if(void 0!==o.getTitle()&&o.isOverlappingWith(i)){this.popupNode=o;break}}}if(void 0===this.popupNode){var r=this.edges;for(e in r)if(r.hasOwnProperty(e)){var a=r[e];if(a.connected&&void 0!==a.getTitle()&&a.isOverlappingWith(i)){this.popupNode=a;break}}}if(this.popupNode){if(this.popupNode!=n){var h=this;h.popup||(h.popup=new O(h.frame)),h.popup.setPosition(t.x-3,t.y-3),h.popup.setText(h.popupNode.getTitle()),h.popup.show()}}else this.popup&&this.popup.hide()},I.prototype._checkHidePopup=function(t){this.popupNode&&this._getNodeAt(t)||(this.popupNode=void 0,this.popup&&this.popup.hide())},I.prototype._getConnectionCount=function(t){function e(t){for(var e=[],i=0,n=t.length;n>i;i++)for(var s=t[i],o=s.edges,r=0,a=o.length;a>r;r++){var h=o[r],d=null;h.from==s?d=h.to:h.to==s&&(d=h.from);var c,l;if(d)for(c=0,l=t.length;l>c;c++)if(t[c]==d){d=null;break}if(d)for(c=0,l=e.length;l>c;c++)if(e[c]==d){d=null;break}d&&e.push(d)}return e}void 0==t&&(t=1);var i=[],n=this.nodes;for(var s in n)if(n.hasOwnProperty(s)){for(var o=[n[s]],r=0;t>r;r++)o=o.concat(e(o));i.push(o)}for(var a=[],h=0,d=i.length;d>h;h++)a.push(i[h].length);return a},I.prototype.setSize=function(t,e){this.frame.style.width=t,this.frame.style.height=e,this.frame.canvas.style.width="100%",this.frame.canvas.style.height="100%",this.frame.canvas.width=this.frame.canvas.clientWidth,this.frame.canvas.height=this.frame.canvas.clientHeight,this.manipulationDiv.style.width=this.frame.canvas.clientWidth,1==this.constants.navigation.enabled&&this._relocateNavigation()},I.prototype._setNodes=function(t){var e=this.nodesData;if(t instanceof o||t instanceof r)this.nodesData=t;else if(t instanceof Array)this.nodesData=new o,this.nodesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.nodesData=new o}if(e&&z.forEach(this.nodesListeners,function(t,i){e.unsubscribe(i,t)}),this.nodes={},this.nodesData){var i=this;z.forEach(this.nodesListeners,function(t,e){i.nodesData.subscribe(e,t)});var n=this.nodesData.getIds();this._addNodes(n)}this._updateSelection()},I.prototype._addNodes=function(t){for(var e,i=0,n=t.length;n>i;i++){e=t[i];var s=this.nodesData.get(e),o=new M(s,this.images,this.groups,this.constants);if(this.nodes[e]=o,!o.isFixed()&&1!=this.createNodeOnClick){var r=2*this.constants.edges.length,a=t.length,h=2*Math.PI*(i/a);o.x=r*Math.cos(h),o.y=r*Math.sin(h),this.moving=!0}}this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(this.nodes),this.updateLabels()},I.prototype._updateNodes=function(t){for(var e=this.nodes,i=this.nodesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o],a=i.get(o);r?r.setProperties(a,this.constants):(r=new M(properties,this.images,this.groups,this.constants),e[o]=r,r.isFixed()||(this.moving=!0))}this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(e)},I.prototype._removeNodes=function(t){for(var e=this.nodes,i=0,n=t.length;n>i;i++){var s=t[i];delete e[s]}this._updateNodeIndexList(),this._reconnectEdges(),this._updateSelection(),this._updateValueRange(e)},I.prototype._setEdges=function(t){var e=this.edgesData;if(t instanceof o||t instanceof r)this.edgesData=t;else if(t instanceof Array)this.edgesData=new o,this.edgesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.edgesData=new o}if(e&&z.forEach(this.edgesListeners,function(t,i){e.unsubscribe(i,t)}),this.edges={},this.edgesData){var i=this;z.forEach(this.edgesListeners,function(t,e){i.edgesData.subscribe(e,t)});var n=this.edgesData.getIds();this._addEdges(n)}this._reconnectEdges()},I.prototype._addEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o];r&&r.disconnect();var a=i.get(o,{showInternalIds:!0});e[o]=new D(a,this,this.constants)}this.moving=!0,this._updateValueRange(e)},I.prototype._updateEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=i.get(o),a=e[o];a?(a.disconnect(),a.setProperties(r,this.constants),a.connect()):(a=new D(r,this,this.constants),this.edges[o]=a)}this.moving=!0,this._updateValueRange(e)},I.prototype._removeEdges=function(t){for(var e=this.edges,i=0,n=t.length;n>i;i++){var s=t[i],o=e[s];o&&(o.disconnect(),delete e[s])}this.moving=!0,this._updateValueRange(e)},I.prototype._reconnectEdges=function(){var t,e=this.nodes,i=this.edges;for(t in e)e.hasOwnProperty(t)&&(e[t].edges=[]);for(t in i)if(i.hasOwnProperty(t)){var n=i[t];n.from=null,n.to=null,n.connect()}},I.prototype._updateValueRange=function(t){var e,i=void 0,n=void 0;for(e in t)if(t.hasOwnProperty(e)){var s=t[e].getValue();void 0!==s&&(i=void 0===i?s:Math.min(s,i),n=void 0===n?s:Math.max(s,n))}if(void 0!==i&&void 0!==n)for(e in t)t.hasOwnProperty(e)&&t[e].setValueRange(i,n)},I.prototype.redraw=function(){this.setSize(this.width,this.height),this._redraw()},I.prototype._redraw=function(){var t=this.frame.canvas.getContext("2d"),e=this.frame.canvas.width,i=this.frame.canvas.height;t.clearRect(0,0,e,i),t.save(),t.translate(this.translation.x,this.translation.y),t.scale(this.scale,this.scale),this.canvasTopLeft={x:this._canvasToX(0),y:this._canvasToY(0)},this.canvasBottomRight={x:this._canvasToX(this.frame.canvas.clientWidth),y:this._canvasToY(this.frame.canvas.clientHeight)},this._doInAllSectors("_drawAllSectorNodes",t),this._doInAllSectors("_drawEdges",t),this._doInAllSectors("_drawNodes",t,!0),t.restore(),1==this.constants.navigation.enabled&&this._doInNavigationSector("_drawNodes",t,!0)},I.prototype._setTranslation=function(t,e){void 0===this.translation&&(this.translation={x:0,y:0}),void 0!==t&&(this.translation.x=t),void 0!==e&&(this.translation.y=e)},I.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},I.prototype._setScale=function(t){this.scale=t},I.prototype._getScale=function(){return this.scale},I.prototype._canvasToX=function(t){return(t-this.translation.x)/this.scale},I.prototype._xToCanvas=function(t){return t*this.scale+this.translation.x},I.prototype._canvasToY=function(t){return(t-this.translation.y)/this.scale},I.prototype._yToCanvas=function(t){return t*this.scale+this.translation.y},I.prototype._drawNodes=function(t,e){void 0===e&&(e=!1);var i=this.nodes,n=[];for(var s in i)i.hasOwnProperty(s)&&(i[s].setScaleAndPos(this.scale,this.canvasTopLeft,this.canvasBottomRight),i[s].isSelected()?n.push(s):(i[s].inArea()||e)&&i[s].draw(t));for(var o=0,r=n.length;r>o;o++)(i[n[o]].inArea()||e)&&i[n[o]].draw(t)},I.prototype._drawEdges=function(t){var e=this.edges;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];n.setScale(this.scale),n.connected&&e[i].draw(t)}},I.prototype._doStabilize=function(){for(var t=0,e=this.constants.minVelocity,i=!1;!i&&tthis.constants.clustering.clusterThreshold&&1==this.constants.clustering.enabled&&this.clusterToFit(this.constants.clustering.reduceToNodes,!1),this._calculateForces())},I.prototype._calculateForces=function(){var t,e,i,n,s,o,r,a,h,d,c,l,u,p,f,g,m,v,y=this.nodes,_=this.edges,w=.08*this.forceFactor;for(g=0;gn&&(i=Math.atan2(e,t),r=.5*b>n?1:1/(1+Math.exp((n/b-1)*S)),r*=0==v?1:1+v*this.constants.clustering.forceAmplification,r*=this.forceFactor,s=Math.cos(i)*r,o=Math.sin(i)*r,l._addForce(-s,-o),u._addForce(s,o));for(f in _)_.hasOwnProperty(f)&&(p=_[f],p.connected&&this.nodes.hasOwnProperty(p.toId)&&this.nodes.hasOwnProperty(p.fromId)&&(v=p.to.clusterSize+p.from.clusterSize-2,t=p.to.x-p.from.x,e=p.to.y-p.from.y,d=p.length,d+=v*this.constants.clustering.edgeGrowth,h=Math.sqrt(t*t+e*e),i=Math.atan2(e,t),a=p.stiffness*(d-h)*this.forceFactor,s=Math.cos(i)*a,o=Math.sin(i)*a,p.from._addForce(-s,-o),p.to._addForce(s,o)))},I.prototype._isMoving=function(t){var e=t/this.scale,i=this.nodes;for(var n in i)if(i.hasOwnProperty(n)&&i[n].isMoving(e))return!0;return!1},I.prototype._discreteStepNodes=function(){var t=.01,e=this.nodes;for(var i in e)e.hasOwnProperty(i)&&e[i].discreteStep(t);var n=this.constants.minVelocity;this.moving=this._isMoving(n)},I.prototype.start=function(){if(!this.freezeSimulation)if(this.moving&&(this._doInAllActiveSectors("_initializeForceCalculation"),this._doInAllActiveSectors("_discreteStepNodes"),this._findCenter(this._getRange())),this.moving||0!=this.xIncrement||0!=this.yIncrement||0!=this.zoomIncrement){if(!this.timer){var t=this;this.timer=window.setTimeout(function(){if(t.timer=void 0,0!=t.xIncrement||0!=t.yIncrement){var e=t._getTranslation();t._setTranslation(e.x+t.xIncrement,e.y+t.yIncrement)}if(0!=t.zoomIncrement){var i={x:t.frame.canvas.clientWidth/2,y:t.frame.canvas.clientHeight/2};t._zoom(t.scale*(1+t.zoomIncrement),i)}t.start(),t._redraw()},this.renderTimestep)}}else this._redraw()},I.prototype.singleStep=function(){if(this.moving){this._initializeForceCalculation(),this._discreteStepNodes();var t=this.constants.minVelocity;this.moving=this._isMoving(t),this._redraw()}},I.prototype.toggleFreeze=function(){0==this.freezeSimulation?this.freezeSimulation=!0:(this.freezeSimulation=!1,this.start())},I.prototype._loadClusterSystem=function(){this.clusterSession=0,this.hubThreshold=5;for(var t in W)W.hasOwnProperty(t)&&(I.prototype[t]=W[t])},I.prototype._loadSectorSystem=function(){this.sectors={},this.activeSector=["default"],this.sectors.active={},this.sectors.active["default"]={nodes:{},edges:{},nodeIndices:[],formationScale:1,drawingNode:void 0},this.sectors.frozen={},this.sectors.navigation={nodes:{},edges:{},nodeIndices:[],formationScale:1,drawingNode:void 0},this.nodeIndices=this.sectors.active["default"].nodeIndices;for(var t in R)R.hasOwnProperty(t)&&(I.prototype[t]=R[t])},I.prototype._loadSelectionSystem=function(){this.selectionObj={};for(var t in j)j.hasOwnProperty(t)&&(I.prototype[t]=j[t])},I.prototype._loadManipulationSystem=function(){this.manipulationDiv=document.createElement("div"),this.manipulationDiv.className="graph-manipulationDiv",this.containerElement.insertBefore(this.manipulationDiv,this.frame);for(var t in H)H.hasOwnProperty(t)&&(I.prototype[t]=H[t]);this._createManipulatorBar()},I.prototype._loadNavigationControls=function(){for(var t in U)U.hasOwnProperty(t)&&(I.prototype[t]=U[t]);1==this.constants.navigation.enabled&&this._loadNavigationElements()},I.prototype._relocateNavigation=function(){},I.prototype._unHighlightAll=function(){};var V={util:z,events:F,Controller:l,DataSet:o,DataView:r,Range:h,Stack:a,TimeStep:TimeStep,EventBus:s,components:{items:{Item:_,ItemBox:w,ItemPoint:b,ItemRange:S},Component:u,Panel:p,RootPanel:f,ItemSet:y,TimeAxis:g},graph:{Node:M,Edge:D,Popup:O,Groups:Groups,Images:Images},Timeline:C,Graph:I};"undefined"!=typeof n&&(n=V),"undefined"!=typeof i&&"undefined"!=typeof i.exports&&(i.exports=V),"function"==typeof t&&t(function(){return V}),"undefined"!=typeof window&&(window.vis=V)},{hammerjs:2,moment:3,mousetrap:4}],2:[function(t,e){!function(t,i){"use strict";function n(){if(!s.READY){s.event.determineEventTypes();for(var t in s.gestures)s.gestures.hasOwnProperty(t)&&s.detection.register(s.gestures[t]);s.event.onTouch(s.DOCUMENT,s.EVENT_MOVE,s.detection.detect),s.event.onTouch(s.DOCUMENT,s.EVENT_END,s.detection.detect),s.READY=!0}}var s=function(t,e){return new s.Instance(t,e||{})};s.defaults={stop_browser_behavior:{userSelect:"none",touchAction:"none",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}},s.HAS_POINTEREVENTS=navigator.pointerEnabled||navigator.msPointerEnabled,s.HAS_TOUCHEVENTS="ontouchstart"in t,s.MOBILE_REGEX=/mobile|tablet|ip(ad|hone|od)|android/i,s.NO_MOUSEEVENTS=s.HAS_TOUCHEVENTS&&navigator.userAgent.match(s.MOBILE_REGEX),s.EVENT_TYPES={},s.DIRECTION_DOWN="down",s.DIRECTION_LEFT="left",s.DIRECTION_UP="up",s.DIRECTION_RIGHT="right",s.POINTER_MOUSE="mouse",s.POINTER_TOUCH="touch",s.POINTER_PEN="pen",s.EVENT_START="start",s.EVENT_MOVE="move",s.EVENT_END="end",s.DOCUMENT=document,s.plugins={},s.READY=!1,s.Instance=function(t,e){var i=this;return n(),this.element=t,this.enabled=!0,this.options=s.utils.extend(s.utils.extend({},s.defaults),e||{}),this.options.stop_browser_behavior&&s.utils.stopDefaultBrowserBehavior(this.element,this.options.stop_browser_behavior),s.event.onTouch(t,s.EVENT_START,function(t){i.enabled&&s.detection.startDetect(i,t)}),this},s.Instance.prototype={on:function(t,e){for(var i=t.split(" "),n=0;n0&&e==s.EVENT_END?e=s.EVENT_MOVE:c||(e=s.EVENT_END),c||null===o?o=h:h=o,i.call(s.detection,n.collectEventData(t,e,h)),s.HAS_POINTEREVENTS&&e==s.EVENT_END&&(c=s.PointerEvent.updatePointer(e,h))),c||(o=null,r=!1,a=!1,s.PointerEvent.reset())}})},determineEventTypes:function(){var t;t=s.HAS_POINTEREVENTS?s.PointerEvent.getEvents():s.NO_MOUSEEVENTS?["touchstart","touchmove","touchend touchcancel"]:["touchstart mousedown","touchmove mousemove","touchend touchcancel mouseup"],s.EVENT_TYPES[s.EVENT_START]=t[0],s.EVENT_TYPES[s.EVENT_MOVE]=t[1],s.EVENT_TYPES[s.EVENT_END]=t[2]},getTouchList:function(t){return s.HAS_POINTEREVENTS?s.PointerEvent.getTouchList():t.touches?t.touches:[{identifier:1,pageX:t.pageX,pageY:t.pageY,target:t.target}]},collectEventData:function(t,e,i){var n=this.getTouchList(i,e),o=s.POINTER_TOUCH;return(i.type.match(/mouse/)||s.PointerEvent.matchType(s.POINTER_MOUSE,i))&&(o=s.POINTER_MOUSE),{center:s.utils.getCenter(n),timeStamp:(new Date).getTime(),target:i.target,touches:n,eventType:e,pointerType:o,srcEvent:i,preventDefault:function(){this.srcEvent.preventManipulation&&this.srcEvent.preventManipulation(),this.srcEvent.preventDefault&&this.srcEvent.preventDefault()},stopPropagation:function(){this.srcEvent.stopPropagation()},stopDetect:function(){return s.detection.stopDetect()}}}},s.PointerEvent={pointers:{},getTouchList:function(){var t=this,e=[];return Object.keys(t.pointers).sort().forEach(function(i){e.push(t.pointers[i])}),e},updatePointer:function(t,e){return t==s.EVENT_END?this.pointers={}:(e.identifier=e.pointerId,this.pointers[e.pointerId]=e),Object.keys(this.pointers).length},matchType:function(t,e){if(!e.pointerType)return!1;var i={};return i[s.POINTER_MOUSE]=e.pointerType==e.MSPOINTER_TYPE_MOUSE||e.pointerType==s.POINTER_MOUSE,i[s.POINTER_TOUCH]=e.pointerType==e.MSPOINTER_TYPE_TOUCH||e.pointerType==s.POINTER_TOUCH,i[s.POINTER_PEN]=e.pointerType==e.MSPOINTER_TYPE_PEN||e.pointerType==s.POINTER_PEN,i[t]},getEvents:function(){return["pointerdown MSPointerDown","pointermove MSPointerMove","pointerup pointercancel MSPointerUp MSPointerCancel"]},reset:function(){this.pointers={}}},s.utils={extend:function(t,e,n){for(var s in e)t[s]!==i&&n||(t[s]=e[s]);return t},hasParent:function(t,e){for(;t;){if(t==e)return!0;t=t.parentNode}return!1},getCenter:function(t){for(var e=[],i=[],n=0,s=t.length;s>n;n++)e.push(t[n].pageX),i.push(t[n].pageY);return{pageX:(Math.min.apply(Math,e)+Math.max.apply(Math,e))/2,pageY:(Math.min.apply(Math,i)+Math.max.apply(Math,i))/2}},getVelocity:function(t,e,i){return{x:Math.abs(e/t)||0,y:Math.abs(i/t)||0}},getAngle:function(t,e){var i=e.pageY-t.pageY,n=e.pageX-t.pageX;return 180*Math.atan2(i,n)/Math.PI},getDirection:function(t,e){var i=Math.abs(t.pageX-e.pageX),n=Math.abs(t.pageY-e.pageY);return i>=n?t.pageX-e.pageX>0?s.DIRECTION_LEFT:s.DIRECTION_RIGHT:t.pageY-e.pageY>0?s.DIRECTION_UP:s.DIRECTION_DOWN},getDistance:function(t,e){var i=e.pageX-t.pageX,n=e.pageY-t.pageY;return Math.sqrt(i*i+n*n)},getScale:function(t,e){return t.length>=2&&e.length>=2?this.getDistance(e[0],e[1])/this.getDistance(t[0],t[1]):1},getRotation:function(t,e){return t.length>=2&&e.length>=2?this.getAngle(e[1],e[0])-this.getAngle(t[1],t[0]):0},isVertical:function(t){return t==s.DIRECTION_UP||t==s.DIRECTION_DOWN},stopDefaultBrowserBehavior:function(t,e){var i,n=["webkit","khtml","moz","ms","o",""];if(e&&t.style){for(var s=0;si;i++){var o=this.gestures[i];if(!this.stopped&&e[o.name]!==!1&&o.handler.call(o,t,this.current.inst)===!1){this.stopDetect();break}}return this.current&&(this.current.lastEvent=t),t.eventType==s.EVENT_END&&!t.touches.length-1&&this.stopDetect(),t}},stopDetect:function(){this.previous=s.utils.extend({},this.current),this.current=null,this.stopped=!0},extendEventData:function(t){var e=this.current.startEvent;if(e&&(t.touches.length!=e.touches.length||t.touches===e.touches)){e.touches=[];for(var i=0,n=t.touches.length;n>i;i++)e.touches.push(s.utils.extend({},t.touches[i]))}var o=t.timeStamp-e.timeStamp,r=t.center.pageX-e.center.pageX,a=t.center.pageY-e.center.pageY,h=s.utils.getVelocity(o,r,a);return s.utils.extend(t,{deltaTime:o,deltaX:r,deltaY:a,velocityX:h.x,velocityY:h.y,distance:s.utils.getDistance(e.center,t.center),angle:s.utils.getAngle(e.center,t.center),direction:s.utils.getDirection(e.center,t.center),scale:s.utils.getScale(e.touches,t.touches),rotation:s.utils.getRotation(e.touches,t.touches),startEvent:e}),t},register:function(t){var e=t.defaults||{};return e[t.name]===i&&(e[t.name]=!0),s.utils.extend(s.defaults,e,!0),t.index=t.index||1e3,this.gestures.push(t),this.gestures.sort(function(t,e){return t.indexe.index?1:0}),this.gestures}},s.gestures=s.gestures||{},s.gestures.Hold={name:"hold",index:10,defaults:{hold_timeout:500,hold_threshold:1},timer:null,handler:function(t,e){switch(t.eventType){case s.EVENT_START:clearTimeout(this.timer),s.detection.current.name=this.name,this.timer=setTimeout(function(){"hold"==s.detection.current.name&&e.trigger("hold",t)},e.options.hold_timeout);break;case s.EVENT_MOVE:t.distance>e.options.hold_threshold&&clearTimeout(this.timer);break;case s.EVENT_END:clearTimeout(this.timer)}}},s.gestures.Tap={name:"tap",index:100,defaults:{tap_max_touchtime:250,tap_max_distance:10,tap_always:!0,doubletap_distance:20,doubletap_interval:300},handler:function(t,e){if(t.eventType==s.EVENT_END){var i=s.detection.previous,n=!1;if(t.deltaTime>e.options.tap_max_touchtime||t.distance>e.options.tap_max_distance)return;i&&"tap"==i.name&&t.timeStamp-i.lastEvent.timeStamp0&&t.touches.length>e.options.swipe_max_touches)return;(t.velocityX>e.options.swipe_velocity||t.velocityY>e.options.swipe_velocity)&&(e.trigger(this.name,t),e.trigger(this.name+t.direction,t))}}},s.gestures.Drag={name:"drag",index:50,defaults:{drag_min_distance:10,drag_max_touches:1,drag_block_horizontal:!1,drag_block_vertical:!1,drag_lock_to_axis:!1,drag_lock_min_distance:25},triggered:!1,handler:function(t,e){if(s.detection.current.name!=this.name&&this.triggered)return e.trigger(this.name+"end",t),void(this.triggered=!1);if(!(e.options.drag_max_touches>0&&t.touches.length>e.options.drag_max_touches))switch(t.eventType){case s.EVENT_START:this.triggered=!1;break;case s.EVENT_MOVE:if(t.distancee.options.transform_min_rotation&&e.trigger("rotate",t),i>e.options.transform_min_scale&&(e.trigger("pinch",t),e.trigger("pinch"+(t.scale<1?"in":"out"),t));break;case s.EVENT_END:this.triggered&&e.trigger(this.name+"end",t),this.triggered=!1}}},s.gestures.Touch={name:"touch",index:-1/0,defaults:{prevent_default:!1,prevent_mouseevents:!1},handler:function(t,e){return e.options.prevent_mouseevents&&t.pointerType==s.POINTER_MOUSE?void t.stopDetect():(e.options.prevent_default&&t.preventDefault(),void(t.eventType==s.EVENT_START&&e.trigger(this.name,t)))}},s.gestures.Release={name:"release",index:1/0,handler:function(t,e){t.eventType==s.EVENT_END&&e.trigger(this.name,t)}},"object"==typeof e&&"object"==typeof e.exports?e.exports=s:(t.Hammer=s,"function"==typeof t.define&&t.define.amd&&t.define("hammer",[],function(){return s}))}(this)},{}],3:[function(e,i){(function(n){function s(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function o(t,e){return function(i){return p(t.call(this,i),e)}}function r(t,e){return function(i){return this.lang().ordinal(t.call(this,i),e)}}function a(){}function h(t){x(t),c(this,t)}function d(t){var e=_(t),i=e.year||0,n=e.month||0,s=e.week||0,o=e.day||0,r=e.hour||0,a=e.minute||0,h=e.second||0,d=e.millisecond||0;this._milliseconds=+d+1e3*h+6e4*a+36e5*r,this._days=+o+7*s,this._months=+n+12*i,this._data={},this._bubble()}function c(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return e.hasOwnProperty("toString")&&(t.toString=e.toString),e.hasOwnProperty("valueOf")&&(t.valueOf=e.valueOf),t}function l(t){var e,i={};for(e in t)t.hasOwnProperty(e)&&_e.hasOwnProperty(e)&&(i[e]=t[e]);return i}function u(t){return 0>t?Math.ceil(t):Math.floor(t)}function p(t,e,i){for(var n=""+Math.abs(t),s=t>=0;n.lengthn;n++)(i&&t[n]!==e[n]||!i&&b(t[n])!==b(e[n]))&&r++;return r+o}function y(t){if(t){var e=t.toLowerCase().replace(/(.)s$/,"$1");t=Xe[t]||Ze[e]||e}return t}function _(t){var e,i,n={};for(i in t)t.hasOwnProperty(i)&&(e=y(i),e&&(n[e]=t[i]));return n}function w(t){var e,i;if(0===t.indexOf("week"))e=7,i="day";else{if(0!==t.indexOf("month"))return;e=12,i="month"}re[t]=function(s,o){var r,a,h=re.fn._lang[t],d=[];if("number"==typeof s&&(o=s,s=n),a=function(t){var e=re().utc().set(i,t);return h.call(re.fn._lang,e,s||"")},null!=o)return a(o);for(r=0;e>r;r++)d.push(a(r));return d}}function b(t){var e=+t,i=0;return 0!==e&&isFinite(e)&&(i=e>=0?Math.floor(e):Math.ceil(e)),i}function S(t,e){return new Date(Date.UTC(t,e+1,0)).getUTCDate()}function E(t){return T(t)?366:365}function T(t){return t%4===0&&t%100!==0||t%400===0}function x(t){var e;t._a&&-2===t._pf.overflow&&(e=t._a[ue]<0||t._a[ue]>11?ue:t._a[pe]<1||t._a[pe]>S(t._a[le],t._a[ue])?pe:t._a[fe]<0||t._a[fe]>23?fe:t._a[ge]<0||t._a[ge]>59?ge:t._a[me]<0||t._a[me]>59?me:t._a[ve]<0||t._a[ve]>999?ve:-1,t._pf._overflowDayOfYear&&(le>e||e>pe)&&(e=pe),t._pf.overflow=e)}function C(t){return null==t._isValid&&(t._isValid=!isNaN(t._d.getTime())&&t._pf.overflow<0&&!t._pf.empty&&!t._pf.invalidMonth&&!t._pf.nullInput&&!t._pf.invalidFormat&&!t._pf.userInvalidated,t._strict&&(t._isValid=t._isValid&&0===t._pf.charsLeftOver&&0===t._pf.unusedTokens.length)),t._isValid}function M(t){return t?t.toLowerCase().replace("_","-"):t}function D(t,e){return e._isUTC?re(t).zone(e._offset||0):re(t).local()}function O(t,e){return e.abbr=t,ye[t]||(ye[t]=new a),ye[t].set(e),ye[t]}function I(t){delete ye[t]}function N(t){var i,n,s,o,r=0,a=function(t){if(!ye[t]&&we)try{e("./lang/"+t)}catch(i){}return ye[t]};if(!t)return re.fn._lang;if(!g(t)){if(n=a(t))return n;t=[t]}for(;r0;){if(n=a(o.slice(0,i).join("-")))return n;if(s&&s.length>=i&&v(o,s,!0)>=i-1)break;i--}r++}return re.fn._lang}function L(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function k(t){var e,i,n=t.match(Te);for(e=0,i=n.length;i>e;e++)n[e]=Je[n[e]]?Je[n[e]]:L(n[e]);return function(s){var o="";for(e=0;i>e;e++)o+=n[e]instanceof Function?n[e].call(s,t):n[e];return o}}function A(t,e){return t.isValid()?(e=z(e,t.lang()),Ke[e]||(Ke[e]=k(e)),Ke[e](t)):t.lang().invalidDate()}function z(t,e){function i(t){return e.longDateFormat(t)||t}var n=5;for(xe.lastIndex=0;n>=0&&xe.test(t);)t=t.replace(xe,i),xe.lastIndex=0,n-=1;return t}function P(t,e){var i,n=e._strict;switch(t){case"DDDD":return Fe;case"YYYY":case"GGGG":case"gggg":return n?Ye:De;case"Y":case"G":case"g":return Re;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return n?He:Oe;case"S":if(n)return ze;case"SS":if(n)return Pe;case"SSS":if(n)return Fe;case"DDD":return Me;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Ne;case"a":case"A":return N(e._l)._meridiemParse;case"X":return Ae;case"Z":case"ZZ":return Le;case"T":return ke;case"SSSS":return Ie;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return n?Pe:Ce;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return Ce;default:return i=new RegExp(V(U(t.replace("\\","")),"i"))}}function F(t){t=t||"";var e=t.match(Le)||[],i=e[e.length-1]||[],n=(i+"").match(Ge)||["-",0,0],s=+(60*n[1])+b(n[2]);return"+"===n[0]?-s:s}function Y(t,e,i){var n,s=i._a;switch(t){case"M":case"MM":null!=e&&(s[ue]=b(e)-1);break;case"MMM":case"MMMM":n=N(i._l).monthsParse(e),null!=n?s[ue]=n:i._pf.invalidMonth=e;break;case"D":case"DD":null!=e&&(s[pe]=b(e));break;case"DDD":case"DDDD":null!=e&&(i._dayOfYear=b(e));break;case"YY":s[le]=b(e)+(b(e)>68?1900:2e3);break;case"YYYY":case"YYYYY":case"YYYYYY":s[le]=b(e);break;case"a":case"A":i._isPm=N(i._l).isPM(e);break;case"H":case"HH":case"h":case"hh":s[fe]=b(e);break;case"m":case"mm":s[ge]=b(e);break;case"s":case"ss":s[me]=b(e);break;case"S":case"SS":case"SSS":case"SSSS":s[ve]=b(1e3*("0."+e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,i._tzm=F(e);break;case"w":case"ww":case"W":case"WW":case"d":case"dd":case"ddd":case"dddd":case"e":case"E":t=t.substr(0,1);case"gg":case"gggg":case"GG":case"GGGG":case"GGGGG":t=t.substr(0,2),e&&(i._w=i._w||{},i._w[t]=e)}}function H(t){var e,i,n,s,o,r,a,h,d,c,l=[];if(!t._d){for(n=W(t),t._w&&null==t._a[pe]&&null==t._a[ue]&&(o=function(e){var i=parseInt(e,10);return e?e.length<3?i>68?1900+i:2e3+i:i:null==t._a[le]?re().weekYear():t._a[le]},r=t._w,null!=r.GG||null!=r.W||null!=r.E?a=te(o(r.GG),r.W||1,r.E,4,1):(h=N(t._l),d=null!=r.d?K(r.d,h):null!=r.e?parseInt(r.e,10)+h._week.dow:0,c=parseInt(r.w,10)||1,null!=r.d&&dE(s)&&(t._pf._overflowDayOfYear=!0),i=Z(s,0,t._dayOfYear),t._a[ue]=i.getUTCMonth(),t._a[pe]=i.getUTCDate()),e=0;3>e&&null==t._a[e];++e)t._a[e]=l[e]=n[e];for(;7>e;e++)t._a[e]=l[e]=null==t._a[e]?2===e?1:0:t._a[e];l[fe]+=b((t._tzm||0)/60),l[ge]+=b((t._tzm||0)%60),t._d=(t._useUTC?Z:X).apply(null,l)}}function R(t){var e;t._d||(e=_(t._i),t._a=[e.year,e.month,e.day,e.hour,e.minute,e.second,e.millisecond],H(t))}function W(t){var e=new Date;return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function j(t){t._a=[],t._pf.empty=!0;var e,i,n,s,o,r=N(t._l),a=""+t._i,h=a.length,d=0;for(n=z(t._f,r).match(Te)||[],e=0;e0&&t._pf.unusedInput.push(o),a=a.slice(a.indexOf(i)+i.length),d+=i.length),Je[s]?(i?t._pf.empty=!1:t._pf.unusedTokens.push(s),Y(s,i,t)):t._strict&&!i&&t._pf.unusedTokens.push(s);t._pf.charsLeftOver=h-d,a.length>0&&t._pf.unusedInput.push(a),t._isPm&&t._a[fe]<12&&(t._a[fe]+=12),t._isPm===!1&&12===t._a[fe]&&(t._a[fe]=0),H(t),x(t)}function U(t){return t.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,i,n,s){return e||i||n||s})}function V(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function G(t){var e,i,n,o,r;if(0===t._f.length)return t._pf.invalidFormat=!0,void(t._d=new Date(0/0));for(o=0;or)&&(n=r,i=e));c(t,i||e)}function B(t){var e,i,n=t._i,s=We.exec(n);if(s){for(t._pf.iso=!0,e=0,i=Ue.length;i>e;e++)if(Ue[e][1].exec(n)){t._f=Ue[e][0]+(s[6]||" ");break}for(e=0,i=Ve.length;i>e;e++)if(Ve[e][1].exec(n)){t._f+=Ve[e][0];break}n.match(Le)&&(t._f+="Z"),j(t)}else t._d=new Date(n)}function q(t){var e=t._i,i=be.exec(e);e===n?t._d=new Date:i?t._d=new Date(+i[1]):"string"==typeof e?B(t):g(e)?(t._a=e.slice(0),H(t)):m(e)?t._d=new Date(+e):"object"==typeof e?R(t):t._d=new Date(e)}function X(t,e,i,n,s,o,r){var a=new Date(t,e,i,n,s,o,r);return 1970>t&&a.setFullYear(t),a}function Z(t){var e=new Date(Date.UTC.apply(null,arguments));return 1970>t&&e.setUTCFullYear(t),e}function K(t,e){if("string"==typeof t)if(isNaN(t)){if(t=e.weekdaysParse(t),"number"!=typeof t)return null}else t=parseInt(t,10);return t}function $(t,e,i,n,s){return s.relativeTime(e||1,!!i,t,n)}function Q(t,e,i){var n=ce(Math.abs(t)/1e3),s=ce(n/60),o=ce(s/60),r=ce(o/24),a=ce(r/365),h=45>n&&["s",n]||1===s&&["m"]||45>s&&["mm",s]||1===o&&["h"]||22>o&&["hh",o]||1===r&&["d"]||25>=r&&["dd",r]||45>=r&&["M"]||345>r&&["MM",ce(r/30)]||1===a&&["y"]||["yy",a];return h[2]=e,h[3]=t>0,h[4]=i,$.apply({},h)}function J(t,e,i){var n,s=i-e,o=i-t.day();return o>s&&(o-=7),s-7>o&&(o+=7),n=re(t).add("d",o),{week:Math.ceil(n.dayOfYear()/7),year:n.year()}}function te(t,e,i,n,s){var o,r,a=Z(t,0,1).getUTCDay();return i=null!=i?i:s,o=s-a+(a>n?7:0)-(s>a?7:0),r=7*(e-1)+(i-s)+o+1,{year:r>0?t:t-1,dayOfYear:r>0?r:E(t-1)+r}}function ee(t){var e=t._i,i=t._f;return null===e?re.invalid({nullInput:!0}):("string"==typeof e&&(t._i=e=N().preparse(e)),re.isMoment(e)?(t=l(e),t._d=new Date(+e._d)):i?g(i)?G(t):j(t):q(t),new h(t))}function ie(t,e){re.fn[t]=re.fn[t+"s"]=function(t){var i=this._isUTC?"UTC":"";return null!=t?(this._d["set"+i+e](t),re.updateOffset(this),this):this._d["get"+i+e]()}}function ne(t){re.duration.fn[t]=function(){return this._data[t]}}function se(t,e){re.duration.fn["as"+t]=function(){return+this/e}}function oe(t){var e=!1,i=re;"undefined"==typeof ender&&(t?(de.moment=function(){return!e&&console&&console.warn&&(e=!0,console.warn("Accessing Moment through the global scope is deprecated, and will be removed in an upcoming release.")),i.apply(null,arguments)},c(de.moment,i)):de.moment=re)}for(var re,ae,he="2.5.1",de=this,ce=Math.round,le=0,ue=1,pe=2,fe=3,ge=4,me=5,ve=6,ye={},_e={_isAMomentObject:null,_i:null,_f:null,_l:null,_strict:null,_isUTC:null,_offset:null,_pf:null,_lang:null},we="undefined"!=typeof i&&i.exports&&"undefined"!=typeof e,be=/^\/?Date\((\-?\d+)/i,Se=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,Ee=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,Te=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g,xe=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,Ce=/\d\d?/,Me=/\d{1,3}/,De=/\d{1,4}/,Oe=/[+\-]?\d{1,6}/,Ie=/\d+/,Ne=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Le=/Z|[\+\-]\d\d:?\d\d/gi,ke=/T/i,Ae=/[\+\-]?\d+(\.\d{1,3})?/,ze=/\d/,Pe=/\d\d/,Fe=/\d{3}/,Ye=/\d{4}/,He=/[+-]?\d{6}/,Re=/[+-]?\d+/,We=/^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,je="YYYY-MM-DDTHH:mm:ssZ",Ue=[["YYYYYY-MM-DD",/[+-]\d{6}-\d{2}-\d{2}/],["YYYY-MM-DD",/\d{4}-\d{2}-\d{2}/],["GGGG-[W]WW-E",/\d{4}-W\d{2}-\d/],["GGGG-[W]WW",/\d{4}-W\d{2}/],["YYYY-DDD",/\d{4}-\d{3}/]],Ve=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d{1,3}/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],Ge=/([\+\-]|\d\d)/gi,Be="Date|Hours|Minutes|Seconds|Milliseconds".split("|"),qe={Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6},Xe={ms:"millisecond",s:"second",m:"minute",h:"hour",d:"day",D:"date",w:"week",W:"isoWeek",M:"month",y:"year",DDD:"dayOfYear",e:"weekday",E:"isoWeekday",gg:"weekYear",GG:"isoWeekYear"},Ze={dayofyear:"dayOfYear",isoweekday:"isoWeekday",isoweek:"isoWeek",weekyear:"weekYear",isoweekyear:"isoWeekYear"},Ke={},$e="DDD w W M D d".split(" "),Qe="M D H h m s w W".split(" "),Je={M:function(){return this.month()+1},MMM:function(t){return this.lang().monthsShort(this,t)},MMMM:function(t){return this.lang().months(this,t)},D:function(){return this.date()},DDD:function(){return this.dayOfYear()},d:function(){return this.day()},dd:function(t){return this.lang().weekdaysMin(this,t)},ddd:function(t){return this.lang().weekdaysShort(this,t)},dddd:function(t){return this.lang().weekdays(this,t)},w:function(){return this.week()},W:function(){return this.isoWeek()},YY:function(){return p(this.year()%100,2)},YYYY:function(){return p(this.year(),4)},YYYYY:function(){return p(this.year(),5)},YYYYYY:function(){var t=this.year(),e=t>=0?"+":"-";return e+p(Math.abs(t),6)},gg:function(){return p(this.weekYear()%100,2)},gggg:function(){return p(this.weekYear(),4)},ggggg:function(){return p(this.weekYear(),5)},GG:function(){return p(this.isoWeekYear()%100,2)},GGGG:function(){return p(this.isoWeekYear(),4)},GGGGG:function(){return p(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.lang().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.lang().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return b(this.milliseconds()/100)},SS:function(){return p(b(this.milliseconds()/10),2)},SSS:function(){return p(this.milliseconds(),3)},SSSS:function(){return p(this.milliseconds(),3)},Z:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(b(t/60),2)+":"+p(b(t)%60,2)},ZZ:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(b(t/60),2)+p(b(t)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},X:function(){return this.unix()},Q:function(){return this.quarter()}},ti=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"];$e.length;)ae=$e.pop(),Je[ae+"o"]=r(Je[ae],ae);for(;Qe.length;)ae=Qe.pop(),Je[ae+ae]=o(Je[ae],2);for(Je.DDDD=o(Je.DDD,3),c(a.prototype,{set:function(t){var e,i;for(i in t)e=t[i],"function"==typeof e?this[i]=e:this["_"+i]=e},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(t){return this._months[t.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(t){return this._monthsShort[t.month()]},monthsParse:function(t){var e,i,n;for(this._monthsParse||(this._monthsParse=[]),e=0;12>e;e++)if(this._monthsParse[e]||(i=re.utc([2e3,e]),n="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[e]=new RegExp(n.replace(".",""),"i")),this._monthsParse[e].test(t))return e},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(t){return this._weekdays[t.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(t){return this._weekdaysShort[t.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(t){return this._weekdaysMin[t.day()]},weekdaysParse:function(t){var e,i,n;for(this._weekdaysParse||(this._weekdaysParse=[]),e=0;7>e;e++)if(this._weekdaysParse[e]||(i=re([2e3,1]).day(e),n="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[e]=new RegExp(n.replace(".",""),"i")),this._weekdaysParse[e].test(t))return e},_longDateFormat:{LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D YYYY",LLL:"MMMM D YYYY LT",LLLL:"dddd, MMMM D YYYY LT"},longDateFormat:function(t){var e=this._longDateFormat[t];return!e&&this._longDateFormat[t.toUpperCase()]&&(e=this._longDateFormat[t.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1) +}),this._longDateFormat[t]=e),e},isPM:function(t){return"p"===(t+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(t,e,i){return t>11?i?"pm":"PM":i?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(t,e){var i=this._calendar[t];return"function"==typeof i?i.apply(e):i},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(t,e,i,n){var s=this._relativeTime[i];return"function"==typeof s?s(t,e,i,n):s.replace(/%d/i,t)},pastFuture:function(t,e){var i=this._relativeTime[t>0?"future":"past"];return"function"==typeof i?i(e):i.replace(/%s/i,e)},ordinal:function(t){return this._ordinal.replace("%d",t)},_ordinal:"%d",preparse:function(t){return t},postformat:function(t){return t},week:function(t){return J(t,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),re=function(t,e,i,o){var r;return"boolean"==typeof i&&(o=i,i=n),r={},r._isAMomentObject=!0,r._i=t,r._f=e,r._l=i,r._strict=o,r._isUTC=!1,r._pf=s(),ee(r)},re.utc=function(t,e,i,o){var r;return"boolean"==typeof i&&(o=i,i=n),r={},r._isAMomentObject=!0,r._useUTC=!0,r._isUTC=!0,r._l=i,r._i=t,r._f=e,r._strict=o,r._pf=s(),ee(r).utc()},re.unix=function(t){return re(1e3*t)},re.duration=function(t,e){var i,n,s,o=t,r=null;return re.isDuration(t)?o={ms:t._milliseconds,d:t._days,M:t._months}:"number"==typeof t?(o={},e?o[e]=t:o.milliseconds=t):(r=Se.exec(t))?(i="-"===r[1]?-1:1,o={y:0,d:b(r[pe])*i,h:b(r[fe])*i,m:b(r[ge])*i,s:b(r[me])*i,ms:b(r[ve])*i}):(r=Ee.exec(t))&&(i="-"===r[1]?-1:1,s=function(t){var e=t&&parseFloat(t.replace(",","."));return(isNaN(e)?0:e)*i},o={y:s(r[2]),M:s(r[3]),d:s(r[4]),h:s(r[5]),m:s(r[6]),s:s(r[7]),w:s(r[8])}),n=new d(o),re.isDuration(t)&&t.hasOwnProperty("_lang")&&(n._lang=t._lang),n},re.version=he,re.defaultFormat=je,re.updateOffset=function(){},re.lang=function(t,e){var i;return t?(e?O(M(t),e):null===e?(I(t),t="en"):ye[t]||N(t),i=re.duration.fn._lang=re.fn._lang=N(t),i._abbr):re.fn._lang._abbr},re.langData=function(t){return t&&t._lang&&t._lang._abbr&&(t=t._lang._abbr),N(t)},re.isMoment=function(t){return t instanceof h||null!=t&&t.hasOwnProperty("_isAMomentObject")},re.isDuration=function(t){return t instanceof d},ae=ti.length-1;ae>=0;--ae)w(ti[ae]);for(re.normalizeUnits=function(t){return y(t)},re.invalid=function(t){var e=re.utc(0/0);return null!=t?c(e._pf,t):e._pf.userInvalidated=!0,e},re.parseZone=function(t){return re(t).parseZone()},c(re.fn=h.prototype,{clone:function(){return re(this)},valueOf:function(){return+this._d+6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().lang("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){var t=re(this).utc();return 00:!1},parsingFlags:function(){return c({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(){return this.zone(0)},local:function(){return this.zone(0),this._isUTC=!1,this},format:function(t){var e=A(this,t||re.defaultFormat);return this.lang().postformat(e)},add:function(t,e){var i;return i="string"==typeof t?re.duration(+e,t):re.duration(t,e),f(this,i,1),this},subtract:function(t,e){var i;return i="string"==typeof t?re.duration(+e,t):re.duration(t,e),f(this,i,-1),this},diff:function(t,e,i){var n,s,o=D(t,this),r=6e4*(this.zone()-o.zone());return e=y(e),"year"===e||"month"===e?(n=432e5*(this.daysInMonth()+o.daysInMonth()),s=12*(this.year()-o.year())+(this.month()-o.month()),s+=(this-re(this).startOf("month")-(o-re(o).startOf("month")))/n,s-=6e4*(this.zone()-re(this).startOf("month").zone()-(o.zone()-re(o).startOf("month").zone()))/n,"year"===e&&(s/=12)):(n=this-o,s="second"===e?n/1e3:"minute"===e?n/6e4:"hour"===e?n/36e5:"day"===e?(n-r)/864e5:"week"===e?(n-r)/6048e5:n),i?s:u(s)},from:function(t,e){return re.duration(this.diff(t)).lang(this.lang()._abbr).humanize(!e)},fromNow:function(t){return this.from(re(),t)},calendar:function(){var t=D(re(),this).startOf("day"),e=this.diff(t,"days",!0),i=-6>e?"sameElse":-1>e?"lastWeek":0>e?"lastDay":1>e?"sameDay":2>e?"nextDay":7>e?"nextWeek":"sameElse";return this.format(this.lang().calendar(i,this))},isLeapYear:function(){return T(this.year())},isDST:function(){return this.zone()+re(t).startOf(e)},isBefore:function(t,e){return e="undefined"!=typeof e?e:"millisecond",+this.clone().startOf(e)<+re(t).startOf(e)},isSame:function(t,e){return e=e||"ms",+this.clone().startOf(e)===+D(t,this).startOf(e)},min:function(t){return t=re.apply(null,arguments),this>t?this:t},max:function(t){return t=re.apply(null,arguments),t>this?this:t},zone:function(t){var e=this._offset||0;return null==t?this._isUTC?e:this._d.getTimezoneOffset():("string"==typeof t&&(t=F(t)),Math.abs(t)<16&&(t=60*t),this._offset=t,this._isUTC=!0,e!==t&&f(this,re.duration(e-t,"m"),1,!0),this)},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.zone(this._tzm):"string"==typeof this._i&&this.zone(this._i),this},hasAlignedHourOffset:function(t){return t=t?re(t).zone():0,(this.zone()-t)%60===0},daysInMonth:function(){return S(this.year(),this.month())},dayOfYear:function(t){var e=ce((re(this).startOf("day")-re(this).startOf("year"))/864e5)+1;return null==t?e:this.add("d",t-e)},quarter:function(){return Math.ceil((this.month()+1)/3)},weekYear:function(t){var e=J(this,this.lang()._week.dow,this.lang()._week.doy).year;return null==t?e:this.add("y",t-e)},isoWeekYear:function(t){var e=J(this,1,4).year;return null==t?e:this.add("y",t-e)},week:function(t){var e=this.lang().week(this);return null==t?e:this.add("d",7*(t-e))},isoWeek:function(t){var e=J(this,1,4).week;return null==t?e:this.add("d",7*(t-e))},weekday:function(t){var e=(this.day()+7-this.lang()._week.dow)%7;return null==t?e:this.add("d",t-e)},isoWeekday:function(t){return null==t?this.day()||7:this.day(this.day()%7?t:t-7)},get:function(t){return t=y(t),this[t]()},set:function(t,e){return t=y(t),"function"==typeof this[t]&&this[t](e),this},lang:function(t){return t===n?this._lang:(this._lang=N(t),this)}}),ae=0;ae-1?!1:"INPUT"==i||"SELECT"==i||"TEXTAREA"==i||e.contentEditable&&"true"==e.contentEditable}function o(t,e){return t.sort().join(",")===e.sort().join(",")}function r(t){t=t||{};var e,i=!1;for(e in M)t[e]?i=!0:M[e]=0;i||(O=!1)}function a(t,e,i,n,s){var r,a,h=[];if(!x[t])return[];for("keyup"==i&&u(t)&&(e=[t]),r=0;r95&&112>t||b.hasOwnProperty(t)&&(_[b[t]]=t)}return _}function g(t,e,i){return i||(i=f()[t]?"keydown":"keypress"),"keypress"==i&&e.length&&(i="keydown"),i}function m(t,e,i,s){M[t]=0,s||(s=g(e[0],[]));var o,a=function(){O=s,++M[t],p()},h=function(t){d(i,t),"keyup"!==s&&(D=n(t)),setTimeout(r,10)};for(o=0;o1)return m(t,d,e,i);for(h="+"===t?["+"]:t.split("+"),o=0;o":".","?":"/","|":"\\"},T={option:"alt",command:"meta","return":"enter",escape:"esc"},x={},C={},M={},D=!1,O=!1,I=1;20>I;++I)b[111+I]="f"+I;for(I=0;9>=I;++I)b[I+96]=I;i(document,"keypress",l),i(document,"keydown",l),i(document,"keyup",l);var N={bind:function(t,e,i){return y(t instanceof Array?t:[t],e,i),C[t+":"+i]=e,this},unbind:function(t,e){return C[t+":"+e]&&(delete C[t+":"+e],this.bind(t,function(){},e)),this},trigger:function(t,e){return C[t+":"+e](),this},reset:function(){return x={},C={},this}};e.exports=N},{}]},{},[1])(1)}); \ No newline at end of file diff --git a/examples/graph/20_UI_example.html b/examples/graph/20_UI_example.html index 89e620a6..ee8f8394 100644 --- a/examples/graph/20_UI_example.html +++ b/examples/graph/20_UI_example.html @@ -78,7 +78,7 @@ } span.manipulationUI.back { - background-image: url("../../dist/UI_icons/backIcon.png"); + background-image: url("../../dist/img/backIcon.png"); } span.manipulationUI.none:hover { @@ -90,15 +90,15 @@ } span.manipulationUI.add { - background-image: url("../../dist/UI_icons/addNodeIcon.png"); + background-image: url("../../dist/img/addNodeIcon.png"); } span.manipulationUI.connect { - background-image: url("../../dist/UI_icons/connectIcon.png"); + background-image: url("../../dist/img/connectIcon.png"); } span.manipulationUI.delete { - background-image: url("../../dist/UI_icons/deleteIcon.png"); + background-image: url("../../dist/img/deleteIcon.png"); } /* top right bottom left */ span.manipulationLabel { @@ -218,13 +218,13 @@ - - - - - - - + + + + + + + diff --git a/src/graph/Graph.js b/src/graph/Graph.js index e35502db..f39a7dbb 100644 --- a/src/graph/Graph.js +++ b/src/graph/Graph.js @@ -1126,15 +1126,10 @@ Graph.prototype.setSize = function(width, height) { this.frame.canvas.width = this.frame.canvas.clientWidth; this.frame.canvas.height = this.frame.canvas.clientHeight; -<<<<<<< HEAD this.manipulationDiv.style.width = this.frame.canvas.clientWidth; - if (this.constants.navigationUI.enabled == true) { - this._relocateUI(); -======= if (this.constants.navigation.enabled == true) { this._relocateNavigation(); ->>>>>>> develop } }; diff --git a/src/graph/SelectionMixin.js b/src/graph/SelectionMixin.js index 2b27ecf2..9d24703b 100644 --- a/src/graph/SelectionMixin.js +++ b/src/graph/SelectionMixin.js @@ -501,15 +501,14 @@ var SelectionMixin = { delete this.selectionObj[objectId]; } } -<<<<<<< HEAD else { // assuming only edges and nodes are selected if (!this.edges.hasOwnProperty(objectId)) { delete this.selectionObj[objectId]; } -======= - changed = true; - } + changed = true; + } this.selection = []; + } } if (changed && (triggerSelect == true || triggerSelect == undefined)) { @@ -520,8 +519,9 @@ var SelectionMixin = { } return changed; - }, -*/ + } + +} /** * select all nodes on given location x, y * @param {Array} selection an array with node ids From 12669bcc54e451ecadd4bd53993a465da47ef01a Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Wed, 5 Feb 2014 17:55:22 +0100 Subject: [PATCH 30/52] Added data manipulation functionality --- dist/img/acceptDeleteIcon.png | Bin 0 -> 20675 bytes dist/img/editIcon.png | Bin 0 -> 21016 bytes dist/vis.js | 1218 ++++++++++------- dist/vis.min.js | 31 +- examples/graph/02_random_nodes.html | 11 - .../18_fully_random_nodes_clustering.html | 11 - .../graph/19_scale_free_graph_clustering.html | 11 - examples/graph/20_navigation.html | 1 - ...example.html => 21_data_manipulation.html} | 171 ++- examples/graph/index.html | 1 + src/graph/Graph.js | 80 +- src/graph/SelectionMixin.js | 109 +- src/graph/img/acceptDeleteIcon.png | Bin 0 -> 20675 bytes src/graph/img/addNodeIcon.png | Bin 0 -> 20998 bytes src/graph/img/backIcon.png | Bin 0 -> 20802 bytes src/graph/img/connectIcon.png | Bin 0 -> 20764 bytes src/graph/img/deleteIcon.png | Bin 0 -> 20981 bytes src/graph/img/editIcon.png | Bin 0 -> 21016 bytes src/graph/manipulationMixin.js | 397 +++++- src/util.js | 154 +++ 20 files changed, 1516 insertions(+), 679 deletions(-) create mode 100644 dist/img/acceptDeleteIcon.png create mode 100644 dist/img/editIcon.png rename examples/graph/{20_UI_example.html => 21_data_manipulation.html} (58%) create mode 100644 src/graph/img/acceptDeleteIcon.png create mode 100644 src/graph/img/addNodeIcon.png create mode 100644 src/graph/img/backIcon.png create mode 100644 src/graph/img/connectIcon.png create mode 100644 src/graph/img/deleteIcon.png create mode 100644 src/graph/img/editIcon.png diff --git a/dist/img/acceptDeleteIcon.png b/dist/img/acceptDeleteIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..02a062852c2a8ea7610b64f5d6f79ce4953c3b42 GIT binary patch literal 20675 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 literal 0 HcmV?d00001 diff --git a/dist/vis.js b/dist/vis.js index 8cd7cd8e..e96a323e 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -4,13 +4,8 @@ * * A dynamic, browser-based visualization library. * -<<<<<<< HEAD * @version 0.5.0-SNAPSHOT - * @date 2014-02-04 -======= - * @version 0.4.0 - * @date 2014-01-31 ->>>>>>> origin/gh-pages + * @date 2014-02-05 * * @license * Copyright (C) 2011-2014 Almende B.V, http://almende.com @@ -988,6 +983,159 @@ util.option.asElement = function (value, defaultValue) { return value || defaultValue || null; }; + + +util.GiveDec = function GiveDec(Hex) +{ + if(Hex == "A") + Value = 10; + else + if(Hex == "B") + Value = 11; + else + if(Hex == "C") + Value = 12; + else + if(Hex == "D") + Value = 13; + else + if(Hex == "E") + Value = 14; + else + if(Hex == "F") + Value = 15; + else + Value = eval(Hex) + return Value; +} + +util.GiveHex = function GiveHex(Dec) +{ + if(Dec == 10) + Value = "A"; + else + if(Dec == 11) + Value = "B"; + else + if(Dec == 12) + Value = "C"; + else + if(Dec == 13) + Value = "D"; + else + if(Dec == 14) + Value = "E"; + else + if(Dec == 15) + Value = "F"; + else + Value = "" + Dec; + return Value; +} + +/** + * http://www.yellowpipe.com/yis/tools/hex-to-rgb/color-converter.php + * + * @param {String} hex + * @returns {{r: *, g: *, b: *}} + */ +util.hexToRGB = function hexToRGB(hex) { + hex = hex.replace("#","").toUpperCase(); + + var a = util.GiveDec(hex.substring(0, 1)); + var b = util.GiveDec(hex.substring(1, 2)); + var c = util.GiveDec(hex.substring(2, 3)); + var d = util.GiveDec(hex.substring(3, 4)); + var e = util.GiveDec(hex.substring(4, 5)); + var f = util.GiveDec(hex.substring(5, 6)); + + var r = (a * 16) + b; + var g = (c * 16) + d; + var b = (e * 16) + f; + + return {r:r,g:g,b:b}; +}; + +util.RGBToHex = function RGBToHex(red,green,blue) { + var a = util.GiveHex(Math.floor(red / 16)); + var b = util.GiveHex(red % 16); + var c = util.GiveHex(Math.floor(green / 16)); + var d = util.GiveHex(green % 16); + var e = util.GiveHex(Math.floor(blue / 16)); + var f = util.GiveHex(blue % 16); + + var hex = a + b + c + d + e + f; + return "#" + hex; +}; + + +/** + * http://www.javascripter.net/faq/rgb2hsv.htm + * + * @param red + * @param green + * @param blue + * @returns {*} + * @constructor + */ +util.RGBToHSV = function RGBToHSV (red,green,blue) { + red=red/255; green=green/255; blue=blue/255; + var minRGB = Math.min(red,Math.min(green,blue)); + var maxRGB = Math.max(red,Math.max(green,blue)); + + // Black-gray-white + if (minRGB == maxRGB) { + return {h:0,s:0,v:minRGB}; + } + + // Colors other than black-gray-white: + var d = (red==minRGB) ? green-blue : ((blue==minRGB) ? red-green : blue-red); + var h = (red==minRGB) ? 3 : ((blue==minRGB) ? 1 : 5); + var hue = 60*(h - d/(maxRGB - minRGB))/360; + var saturation = (maxRGB - minRGB)/maxRGB; + var value = maxRGB; + return {h:hue,s:saturation,v:value}; +}; + + +/** + * https://gist.github.com/mjijackson/5311256 + * @param hue + * @param saturation + * @param value + * @returns {{r: number, g: number, b: number}} + * @constructor + */ +util.HSVToRGB = function HSVToRGB(h, s, v) { + var r, g, b; + + var i = Math.floor(h * 6); + var f = h * 6 - i; + var p = v * (1 - s); + var q = v * (1 - f * s); + var t = v * (1 - (1 - f) * s); + + switch (i % 6) { + case 0: r = v, g = t, b = p; break; + case 1: r = q, g = v, b = p; break; + case 2: r = p, g = v, b = t; break; + case 3: r = p, g = q, b = v; break; + case 4: r = t, g = p, b = v; break; + case 5: r = v, g = p, b = q; break; + } + + return {r:Math.floor(r * 255), g:Math.floor(g * 255), b:Math.floor(b * 255) }; +}; + +util.HSVToHex = function HSVToHex(h,s,v) { + var rgb = util.HSVToRGB(h,s,v); + return util.RGBToHex(rgb.r,rgb.g,rgb.b); +} + +util.hexToHSV = function hexToHSV(hex) { + var rgb = util.hexToRGB(hex); + return util.RGBToHSV(rgb.r,rgb.g,rgb.b); +} /** * Event listener (singleton) */ @@ -9122,13 +9270,8 @@ Node.prototype.setProperties = function(properties, constants) { } } -<<<<<<< HEAD this.xFixed = this.xFixed || (properties.x !== undefined && properties.fixed); this.yFixed = this.yFixed || (properties.y !== undefined && properties.fixed); -======= - this.xFixed = this.xFixed || (properties.x !== undefined); - this.yFixed = this.yFixed || (properties.y !== undefined); ->>>>>>> origin/gh-pages this.radiusFixed = this.radiusFixed || (properties.radius !== undefined); if (this.shape == 'image') { @@ -9950,10 +10093,7 @@ function Edge (properties, graph, constants) { this.width = constants.edges.width; this.value = undefined; this.length = constants.edges.length; -<<<<<<< HEAD this.selected = false; -======= ->>>>>>> origin/gh-pages this.from = null; // a node this.to = null; // a node @@ -10190,11 +10330,7 @@ Edge.prototype._drawLine = function(ctx) { * @private */ Edge.prototype._getLineWidth = function() { -<<<<<<< HEAD if (this.selected == true) { -======= - if (this.from.selected || this.to.selected) { ->>>>>>> origin/gh-pages return Math.min(this.width * 2, this.widthMax)*this.graphScaleInv; } else { @@ -10544,7 +10680,6 @@ Edge._dist = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point Edge.prototype.setScale = function(scale) { this.graphScaleInv = 1.0/scale; }; -<<<<<<< HEAD Edge.prototype.select = function() { @@ -10554,8 +10689,6 @@ Edge.prototype.select = function() { Edge.prototype.unselect = function() { this.selected = false; } -======= ->>>>>>> origin/gh-pages /** * Popup is a class to create a popup window with some text * @param {Element} container The container object. @@ -10786,13 +10919,36 @@ Images.prototype.load = function(url) { }; /** -<<<<<<< HEAD * Created by Alex on 2/4/14. */ var manipulationMixin = { + /** + * clears the toolbar div element of children + * + * @private + */ + _clearManipulatorBar : function() { + while (this.manipulationDiv.hasChildNodes()) { + this.manipulationDiv.removeChild(this.manipulationDiv.firstChild); + } + }, + + + /** + * main function, creates the main toolbar. Removes functions bound to the select event. Binds all the buttons of the toolbar. + * + * @private + */ _createManipulatorBar : function() { + // remove bound functions + this.off('select', this.boundFunction); + + // reset global variables + this.blockConnectingEdgeSelection = false; + this.forceAppendSelection = false + while (this.manipulationDiv.hasChildNodes()) { this.manipulationDiv.removeChild(this.manipulationDiv.firstChild); } @@ -10800,6 +10956,8 @@ var manipulationMixin = { this.manipulationDiv.innerHTML = "" + "Add Node" + "

    " + + "Edit Selected" + + "
    " + "Connect Node" + "
    " + "Delete selected"; @@ -10807,17 +10965,26 @@ var manipulationMixin = { // bind the icons var addButton = document.getElementById("manipulate-addNode"); addButton.onclick = this._createAddToolbar.bind(this); + var editButton = document.getElementById("manipulate-editNode"); + editButton.onclick = this._createEditToolbar.bind(this); var connectButton = document.getElementById("manipulate-connectNode"); connectButton.onclick = this._createConnectToolbar.bind(this); var deleteButton = document.getElementById("manipulate-delete"); - deleteButton.onclick = this._deleteSelected.bind(this); + deleteButton.onclick = this._createDeletionToolbar.bind(this); }, + + /** + * Create the toolbar for adding Nodes + * + * @private + */ _createAddToolbar : function() { - while (this.manipulationDiv.hasChildNodes()) { - this.manipulationDiv.removeChild(this.manipulationDiv.firstChild); - } + // clear the toolbar + this._clearManipulatorBar(); + this.off('select', this.boundFunction); + // create the toolbar contents this.manipulationDiv.innerHTML = "" + "Back" + "
    " + @@ -10827,182 +10994,480 @@ var manipulationMixin = { var backButton = document.getElementById("manipulate-back"); backButton.onclick = this._createManipulatorBar.bind(this); - - var me = this; - events.addListener(me, 'select', me._addNode.bind(me)); + // we use the boundFunction so we can reference it when we unbind it from the "select" event. + this.boundFunction = this._addNode.bind(this); + this.on('select', this.boundFunction); }, - _createConnectToolbar : function() { - while (this.manipulationDiv.hasChildNodes()) { - this.manipulationDiv.removeChild(this.manipulationDiv.firstChild); + /** + * Create the toolbar to edit nodes or edges. + * TODO: edges not implemented yet, unsure what to edit. + * + * @private + */ + _createEditToolbar : function() { + // clear the toolbar + this.blockConnectingEdgeSelection = false; + this._clearManipulatorBar(); + this.off('select', this.boundFunction); + + + var message = ""; + if (this._selectionIsEmpty()) { + message = "Select a node or edge to edit."; + } + else { + if (this._getSelectedObjectCount() > 1) { + message = "Select a single node or edge to edit." + this._unselectAll(true); + } + else { + if (this._clusterInSelection()) { + message = "You cannot edit a cluster." + this._unselectAll(true); + } + else { + if (this._getSelectedNodeCount() > 0) { // the selected item is a node + this._createEditNodeToolbar(); + } + else { // the selected item is an edge + this._createEditEdgeToolbar(); + } + } + } } - var message = "hello"; - if (!this._selectionIsEmpty()) { - message = "Select the node you want to connect to other nodes"; + + if (message != "") { + this.blockConnectingEdgeSelection = true; + // create the toolbar contents + this.manipulationDiv.innerHTML = "" + + "Back" + + "
    " + + ""+message+""; + + // bind the icon + var backButton = document.getElementById("manipulate-back"); + backButton.onclick = this._createManipulatorBar.bind(this); + + // we use the boundFunction so we can reference it when we unbind it from the "select" event. + this.boundFunction = this._createEditToolbar.bind(this); + this.on('select', this.boundFunction); } + }, + + + /** + * Create the toolbar to edit the selected node. The label and the color can be changed. Other colors are derived from the chosen color. + * TODO: change shape or group? + * + * @private + */ + _createEditNodeToolbar : function() { + // clear the toolbar + this.blockConnectingEdgeSelection = false; + this._clearManipulatorBar(); + this.off('select', this.boundFunction); + + var editObject = this._getEditObject(); + // create the toolbar contents this.manipulationDiv.innerHTML = "" + - "Back" + + "Cancel" + + "
    " + + "label: " + "
    " + - ""+message+""; + "color: " + + "
    " + + "" // bind the icon var backButton = document.getElementById("manipulate-back"); backButton.onclick = this._createManipulatorBar.bind(this); + var saveButton = document.getElementById("manipulator-obj-save"); + saveButton.onclick = this._saveNodeData.bind(this); - var self = this; - events.addListener(self, 'select', function(params) {alert(self.selectForConnect)}); - }, - - _continueConnect : function() { - if (this._clusterInSelection()) { - this._unselectAll(); - this._createConnectToolbar("Select the node you want to connect (Clusters are not allowed)."); - return true; - } - else if (!this._selectionIsEmpty()) { - this._connectNodes(); - return true; - } - else { - var manipulatorLabel = document.getElementById['manipolatorLabel']; - manipulatorLabel - return false; - } + // we use the boundFunction so we can reference it when we unbind it from the "select" event. + this.boundFunction = this._createManipulatorBar.bind(this); + this.on('select', this.boundFunction); }, /** - * Adds a node on the specified location + * save the changes in the node data * - * @param {Object} pointer + * @private */ - _addNode : function(pointer) { - console.log("HERE",this) - if (this._selectionIsEmpty()) { - var positionObject = this._pointerToPositionObject(pointer); - this.nodesData.add({id:util.randomUUID(),x:positionObject.left,y:positionObject.top,label:"new",fixed:false}); - this.moving = true; - this.start(); - } - }, + _saveNodeData : function() { + var editObjectId = this._getEditObject().id; + var label = document.getElementById('manipulator-obj-label').value; - _connectNodes : function() { - console.log(this.selectionObj) + var definedColor = document.getElementById('manipulator-obj-color').value; + var hsv = util.hexToHSV(definedColor); + + var lighterColorHSV = {h:hsv.h,s:hsv.s * 0.45,v:Math.min(1,hsv.v * 1.05)}; + var darkerColorHSV = {h:hsv.h,s:Math.min(1,hsv.v * 1.25),v:hsv.v*0.6}; + var darkerColorHex = util.HSVToHex(darkerColorHSV.h ,darkerColorHSV.h ,darkerColorHSV.v); + var lighterColorHex = util.HSVToHex(lighterColorHSV.h,lighterColorHSV.s,lighterColorHSV.v); + + var updatedSettings = {id:editObjectId, + label: label, + color: { + background:definedColor, + border:darkerColorHex, + highlight: { + background:lighterColorHex, + border:darkerColorHex + } + }}; + this.nodesData.update(updatedSettings); + this._createManipulatorBar(); }, /** - * delete everything in the selection + * creating the toolbar to edit edges. * * @private */ - _deleteSelected : function() { - if (!this._clusterInSelection()) { - var selectedNodes = this.getSelectedNodes(); - var selectedEdges = this.getSelectedEdges(); - this._removeEdges(selectedEdges); - this._removeNodes(selectedNodes); - this._redraw(); - } - else { - alert("Clusters cannot be deleted.") - } - } + _createEditEdgeToolbar : function() { + // clear the toolbar + this.blockConnectingEdgeSelection = false; + this._clearManipulatorBar(); + this.off('select', this.boundFunction); + // create the toolbar contents + this.manipulationDiv.innerHTML = "" + + "Back" + + "
    " + + "Currently only nodes can be edited."; + // bind the icon + var backButton = document.getElementById("manipulate-back"); + backButton.onclick = this._createManipulatorBar.bind(this); + + // we use the boundFunction so we can reference it when we unbind it from the "select" event. + this.boundFunction = this._createManipulatorBar.bind(this); + this.on('select', this.boundFunction); + }, -} -/** -======= ->>>>>>> origin/gh-pages - * Creation of the SectorMixin var. - * - * This contains all the functions the Graph object can use to employ the sector system. - * The sector system is always used by Graph, though the benefits only apply to the use of clustering. - * If clustering is not used, there is no overhead except for a duplicate object with references to nodes and edges. - * - * Alex de Mulder - * 21-01-2013 - */ -var SectorMixin = { /** - * This function is only called by the setData function of the Graph object. - * This loads the global references into the active sector. This initializes the sector. + * create the toolbar to connect nodes * * @private */ - _putDataInSector : function() { - this.sectors["active"][this._sector()].nodes = this.nodes; - this.sectors["active"][this._sector()].edges = this.edges; - this.sectors["active"][this._sector()].nodeIndices = this.nodeIndices; + _createConnectToolbar : function() { + // clear the toolbar + this._clearManipulatorBar(); + this.off('select', this.boundFunction); + + this._unselectAll(); + this.forceAppendSelection = false; + this.blockConnectingEdgeSelection = true; + + this.manipulationDiv.innerHTML = "" + + "Back" + + "
    " + + "Select the node you want to connect to other nodes."; + + // bind the icon + var backButton = document.getElementById("manipulate-back"); + backButton.onclick = this._createManipulatorBar.bind(this); + + // we use the boundFunction so we can reference it when we unbind it from the "select" event. + this.boundFunction = this._handleConnect.bind(this); + this.on('select', this.boundFunction); }, /** - * /** - * This function sets the global references to nodes, edges and nodeIndices back to - * those of the supplied (active) sector. If a type is defined, do the specific type + * create the toolbar for deleting selected objects. User has to be sure. * - * @param {String} sectorId - * @param {String} [sectorType] | "active" or "frozen" * @private */ - _switchToSector : function(sectorId, sectorType) { - if (sectorType === undefined || sectorType == "active") { - this._switchToActiveSector(sectorId); + _createDeletionToolbar : function() { + // clear the toolbar + this._clearManipulatorBar(); + this.off('select', this.boundFunction); + + if (this._selectionIsEmpty()) { + this.manipulationDiv.innerHTML = "" + + "Cannot delete an empty selection."; + var graph = this; + window.setTimeout (function() {graph._createManipulatorBar()},1500); } else { - this._switchToFrozenSector(sectorId); + this.manipulationDiv.innerHTML = "" + + "Back" + + "
    " + + "Are you sure? This cannot be undone." + + "
    " + + "Yes."; + + // bind the buttons + var backButton = document.getElementById("manipulate-back"); + backButton.onclick = this._createManipulatorBar.bind(this); + var acceptDeleteButton = document.getElementById("manipulate-acceptDelete"); + acceptDeleteButton.onclick = this._deleteSelected.bind(this); + + // we use the boundFunction so we can reference it when we unbind it from the "select" event. + this.boundFunction = this._createManipulatorBar.bind(this); + this.on('select', this.boundFunction); } }, /** - * This function sets the global references to nodes, edges and nodeIndices back to - * those of the supplied active sector. + * the function bound to the selection event. It checks if you want to connect a cluster and changes the description + * to walk the user through the process. * - * @param sectorId * @private */ - _switchToActiveSector : function(sectorId) { - this.nodeIndices = this.sectors["active"][sectorId]["nodeIndices"]; - this.nodes = this.sectors["active"][sectorId]["nodes"]; - this.edges = this.sectors["active"][sectorId]["edges"]; + _handleConnect : function() { + this.forceAppendSelection = false; + if (this._clusterInSelection()) { + this._unselectClusters(true); + if (!this._selectionIsEmpty()) { + this._setManipulationMessage("You cannot connect a node to a cluster."); + this.forceAppendSelection = true; + } + else { + this._setManipulationMessage("You cannot connect anything to a cluster."); + } + } + else if (!this._selectionIsEmpty()) { + if (this._getSelectedNodeCount() == 2) { + this._connectNodes(); + this._restoreSourceNode(); + this._setManipulationMessage("Click on another node you want to connect this node to or go back."); + } + else { + this._setManipulationMessage("Click on the node you want to connect this node."); + this._setSourceNode(); + this.forceAppendSelection = true; + } + } + else { + this._setManipulationMessage("Select the node you want to connect to other nodes."); + } }, /** - * This function sets the global references to nodes, edges and nodeIndices back to - * those of the supplied frozen sector. + * returns the object that is selected * - * @param sectorId + * @returns {*} * @private */ - _switchToFrozenSector : function(sectorId) { - this.nodeIndices = this.sectors["frozen"][sectorId]["nodeIndices"]; - this.nodes = this.sectors["frozen"][sectorId]["nodes"]; - this.edges = this.sectors["frozen"][sectorId]["edges"]; + _getEditObject : function() { + for(var objectId in this.selectionObj) { + if(this.selectionObj.hasOwnProperty(objectId)) { + return this.selectionObj[objectId]; + } + } + return null; }, /** - * This function sets the global references to nodes, edges and nodeIndices to - * those of the navigation controls sector. + * stores the first selected node for the connecting process as the source node. This allows us to remember the direction * * @private */ - _switchToNavigationSector : function() { - this.nodeIndices = this.sectors["navigation"]["nodeIndices"]; - this.nodes = this.sectors["navigation"]["nodes"]; - this.edges = this.sectors["navigation"]["edges"]; + _setSourceNode : function() { + for(var objectId in this.selectionObj) { + if(this.selectionObj.hasOwnProperty(objectId)) { + if (this.selectionObj[objectId] instanceof Node) { + this.manipulationSourceNode = this.selectionObj[objectId]; + } + } + } }, /** - * This function sets the global references to nodes, edges and nodeIndices back to + * gets the node the source connects to. + * + * @returns {*} + * @private + */ + _getTargetNode : function() { + for(var objectId in this.selectionObj) { + if(this.selectionObj.hasOwnProperty(objectId)) { + if (this.selectionObj[objectId] instanceof Node) { + if (this.manipulationSourceNode.id != this.selectionObj[objectId].id) { + return this.selectionObj[objectId]; + } + } + } + } + return null; + }, + + + /** + * restore the selection back to only the sourcenode + * + * @private + */ + _restoreSourceNode : function() { + this._unselectAll(true); + this._selectObject(this.manipulationSourceNode); + }, + + + /** + * change the description message on the toolbar + * + * @param message + * @private + */ + _setManipulationMessage : function(message) { + var messageSpan = document.getElementById('manipulatorLabel'); + messageSpan.innerHTML = message; + }, + + + /** + * Adds a node on the specified location + * + * @param {Object} pointer + */ + _addNode : function() { + if (this._selectionIsEmpty()) { + var positionObject = this._pointerToPositionObject(this.pointerPosition); + this.createNodeOnClick = true; + this.nodesData.add({id:util.randomUUID(),x:positionObject.left,y:positionObject.top,label:"new",fixed:false}); + this.createNodeOnClick = false; + this.moving = true; + this.start(); + } + }, + + + /** + * connect two nodes with a new edge. + * + * @private + */ + _connectNodes : function() { + var targetNode = this._getTargetNode(); + var sourceNode = this.manipulationSourceNode; + this.edgesData.add({from:sourceNode.id, to:targetNode.id}) + this.moving = true; + this.start(); + }, + + + /** + * delete everything in the selection + * + * @private + */ + _deleteSelected : function() { + if (!this._clusterInSelection()) { + var selectedNodes = this.getSelectedNodes(); + var selectedEdges = this.getSelectedEdges(); + this._removeEdges(selectedEdges); + this._removeNodes(selectedNodes); + this.moving = true; + this.start(); + } + else { + alert("Clusters cannot be deleted.") + } + } + + +} +/** + * Creation of the SectorMixin var. + * + * This contains all the functions the Graph object can use to employ the sector system. + * The sector system is always used by Graph, though the benefits only apply to the use of clustering. + * If clustering is not used, there is no overhead except for a duplicate object with references to nodes and edges. + * + * Alex de Mulder + * 21-01-2013 + */ +var SectorMixin = { + + /** + * This function is only called by the setData function of the Graph object. + * This loads the global references into the active sector. This initializes the sector. + * + * @private + */ + _putDataInSector : function() { + this.sectors["active"][this._sector()].nodes = this.nodes; + this.sectors["active"][this._sector()].edges = this.edges; + this.sectors["active"][this._sector()].nodeIndices = this.nodeIndices; + }, + + + /** + * /** + * This function sets the global references to nodes, edges and nodeIndices back to + * those of the supplied (active) sector. If a type is defined, do the specific type + * + * @param {String} sectorId + * @param {String} [sectorType] | "active" or "frozen" + * @private + */ + _switchToSector : function(sectorId, sectorType) { + if (sectorType === undefined || sectorType == "active") { + this._switchToActiveSector(sectorId); + } + else { + this._switchToFrozenSector(sectorId); + } + }, + + + /** + * This function sets the global references to nodes, edges and nodeIndices back to + * those of the supplied active sector. + * + * @param sectorId + * @private + */ + _switchToActiveSector : function(sectorId) { + this.nodeIndices = this.sectors["active"][sectorId]["nodeIndices"]; + this.nodes = this.sectors["active"][sectorId]["nodes"]; + this.edges = this.sectors["active"][sectorId]["edges"]; + }, + + + /** + * This function sets the global references to nodes, edges and nodeIndices back to + * those of the supplied frozen sector. + * + * @param sectorId + * @private + */ + _switchToFrozenSector : function(sectorId) { + this.nodeIndices = this.sectors["frozen"][sectorId]["nodeIndices"]; + this.nodes = this.sectors["frozen"][sectorId]["nodes"]; + this.edges = this.sectors["frozen"][sectorId]["edges"]; + }, + + + /** + * This function sets the global references to nodes, edges and nodeIndices to + * those of the navigation controls sector. + * + * @private + */ + _switchToNavigationSector : function() { + this.nodeIndices = this.sectors["navigation"]["nodeIndices"]; + this.nodes = this.sectors["navigation"]["nodes"]; + this.edges = this.sectors["navigation"]["edges"]; + }, + + + /** + * This function sets the global references to nodes, edges and nodeIndices back to * those of the currently active sector. * * @private @@ -11800,13 +12265,10 @@ var ClusterMixin = { // if child node has been added on smaller scale than current, kick out if (childNode.formationScale < this.scale || force == true) { -<<<<<<< HEAD // remove the selection, first remove the selection from the connected edges this._unselectConnectedEdges(parentNode); parentNode.unselect(); -======= ->>>>>>> origin/gh-pages // put the child node back in the global nodes object this.nodes[containedNodeId] = childNode; @@ -11855,12 +12317,9 @@ var ClusterMixin = { // recalculate the size of the node on the next time the node is rendered parentNode.clearSizeCache(); -<<<<<<< HEAD // this unselects the rest of the edges this._unselectConnectedEdges(parentNode); -======= ->>>>>>> origin/gh-pages } // check if a further expansion step is possible if recursivity is enabled @@ -12606,11 +13065,7 @@ var SelectionMixin = { _getNodeAt : function (pointer) { // we first check if this is an navigation controls element var positionObject = this._pointerToPositionObject(pointer); -<<<<<<< HEAD var overlappingNodes = this._getAllNodesOverlappingWith(positionObject); -======= - overlappingNodes = this._getAllNodesOverlappingWith(positionObject); ->>>>>>> origin/gh-pages // if there are overlapping nodes, select the last one, this is the // one which is drawn on top of the others @@ -12624,7 +13079,6 @@ var SelectionMixin = { /** -<<<<<<< HEAD * retrieve all edges overlapping with given object, selector is around center * @param {Object} object An object with parameters left, top, right, bottom * @return {Number[]} An array with id's of the overlapping nodes @@ -12655,8 +13109,6 @@ var SelectionMixin = { }, /** -======= ->>>>>>> origin/gh-pages * Place holder. To implement change the _getNodeAt to a _getObjectAt. Have the _getObjectAt call * _getNodeAt and _getEdgesAt, then priortize the selection to user preferences. * @@ -12665,7 +13117,6 @@ var SelectionMixin = { * @private */ _getEdgeAt : function(pointer) { -<<<<<<< HEAD var positionObject = this._pointerToPositionObject(pointer); var overlappingEdges = this._getAllEdgesOverlappingWith(positionObject); @@ -12675,27 +13126,16 @@ var SelectionMixin = { else { return null; } -======= - return null; ->>>>>>> origin/gh-pages }, /** -<<<<<<< HEAD * Add object to the selection array. -======= - * Add object to the selection array. The this.selection id array may not be needed. ->>>>>>> origin/gh-pages * * @param obj * @private */ _addToSelection : function(obj) { -<<<<<<< HEAD -======= - this.selection.push(obj.id); ->>>>>>> origin/gh-pages this.selectionObj[obj.id] = obj; }, @@ -12703,19 +13143,10 @@ var SelectionMixin = { /** * Remove a single option from selection. * - * @param obj + * @param {Object} obj * @private */ _removeFromSelection : function(obj) { -<<<<<<< HEAD -======= - for (var i = 0; i < this.selection.length; i++) { - if (obj.id == this.selection[i]) { - this.selection.splice(i,1); - break; - } - } ->>>>>>> origin/gh-pages delete this.selectionObj[obj.id]; }, @@ -12731,16 +13162,9 @@ var SelectionMixin = { doNotTrigger = false; } -<<<<<<< HEAD for (var objectId in this.selectionObj) { if (this.selectionObj.hasOwnProperty(objectId)) { this.selectionObj[objectId].unselect(); -======= - this.selection = []; - for (var objId in this.selectionObj) { - if (this.selectionObj.hasOwnProperty(objId)) { - this.selectionObj[objId].unselect(); ->>>>>>> origin/gh-pages } } this.selectionObj = {}; @@ -12752,6 +13176,89 @@ var SelectionMixin = { } }, + /** + * Unselect all clusters. The selectionObj is useful for this. + * + * @param {Boolean} [doNotTrigger] | ignore trigger + * @private + */ + _unselectClusters : function(doNotTrigger) { + if (doNotTrigger === undefined) { + doNotTrigger = false; + } + + for (var objectId in this.selectionObj) { + if (this.selectionObj.hasOwnProperty(objectId)) { + if (this.selectionObj[objectId] instanceof Node) { + if (this.selectionObj[objectId].clusterSize > 1) { + this.selectionObj[objectId].unselect(); + this._removeFromSelection(this.selectionObj[objectId]); + } + } + } + } + + if (doNotTrigger == false) { + this._trigger('select', { + nodes: this.getSelection() + }); + } + }, + + + /** + * return the number of selected nodes + * + * @returns {number} + * @private + */ + _getSelectedNodeCount : function() { + var count = 0; + for (var objectId in this.selectionObj) { + if (this.selectionObj.hasOwnProperty(objectId)) { + if (this.selectionObj[objectId] instanceof Node) { + count += 1; + } + } + } + return count; + }, + + + /** + * return the number of selected edges + * + * @returns {number} + * @private + */ + _getSelectedEdgeCount : function() { + var count = 0; + for (var objectId in this.selectionObj) { + if (this.selectionObj.hasOwnProperty(objectId)) { + if (this.selectionObj[objectId] instanceof Edge) { + count += 1; + } + } + } + return count; + }, + + + /** + * return the number of selected objects. + * + * @returns {number} + * @private + */ + _getSelectedObjectCount : function() { + var count = 0; + for (var objectId in this.selectionObj) { + if (this.selectionObj.hasOwnProperty(objectId)) { + count += 1; + } + } + return count; + }, /** * Check if anything is selected @@ -12760,7 +13267,6 @@ var SelectionMixin = { * @private */ _selectionIsEmpty : function() { -<<<<<<< HEAD for(var objectId in this.selectionObj) { if(this.selectionObj.hasOwnProperty(objectId)) { return false; @@ -12769,6 +13275,13 @@ var SelectionMixin = { return true; }, + + /** + * check if one of the selected nodes is a cluster. + * + * @returns {boolean} + * @private + */ _clusterInSelection : function() { for(var objectId in this.selectionObj) { if(this.selectionObj.hasOwnProperty(objectId)) { @@ -12808,68 +13321,39 @@ var SelectionMixin = { var edge = node.dynamicEdges[i]; edge.unselect(); this._removeFromSelection(edge); -======= - if (this.selection.length == 0) { - return true; - } - else { - return false; ->>>>>>> origin/gh-pages } }, -<<<<<<< HEAD -======= ->>>>>>> origin/gh-pages /** * This is called when someone clicks on a node. either select or deselect it. * If there is an existing selection and we don't want to append to it, clear the existing selection * -<<<<<<< HEAD * @param {Node || Edge} object -======= - * @param {Node} node ->>>>>>> origin/gh-pages * @param {Boolean} append * @param {Boolean} [doNotTrigger] | ignore trigger * @private */ -<<<<<<< HEAD _selectObject : function(object, append, doNotTrigger) { -======= - _selectNode : function(node, append, doNotTrigger) { ->>>>>>> origin/gh-pages if (doNotTrigger === undefined) { doNotTrigger = false; } - if (this._selectionIsEmpty() == false && append == false) { + if (this._selectionIsEmpty() == false && append == false && this.forceAppendSelection == false) { this._unselectAll(true); } -<<<<<<< HEAD if (object.selected == false) { object.select(); this._addToSelection(object); - if (object instanceof Node) { + if (object instanceof Node && this.blockConnectingEdgeSelection == false) { this._selectConnectedEdges(object); } } else { object.unselect(); this._removeFromSelection(object); -======= - - if (node.selected == false) { - node.select(); - this._addToSelection(node); - } - else { - node.unselect(); - this._removeFromSelection(node); ->>>>>>> origin/gh-pages } if (doNotTrigger == false) { this._trigger('select', { @@ -12889,6 +13373,7 @@ var SelectionMixin = { */ _handleTouch : function(pointer) { if (this.constants.navigation.enabled == true) { + this.pointerPosition = pointer; var node = this._getNavigationNodeAt(pointer); if (node != null) { if (this[node.triggerFunction] !== undefined) { @@ -12908,7 +13393,6 @@ var SelectionMixin = { _handleTap : function(pointer) { var node = this._getNodeAt(pointer); if (node != null) { -<<<<<<< HEAD this._selectObject(node,false); } else { @@ -12919,12 +13403,6 @@ var SelectionMixin = { else { this._unselectAll(); } -======= - this._selectNode(node,false); - } - else { - this._unselectAll(); ->>>>>>> origin/gh-pages } this._redraw(); }, @@ -12956,7 +13434,6 @@ var SelectionMixin = { _handleOnHold : function(pointer) { var node = this._getNodeAt(pointer); if (node != null) { -<<<<<<< HEAD this._selectObject(node,true); } else { @@ -12964,9 +13441,6 @@ var SelectionMixin = { if (edge != null) { this._selectObject(edge,true); } -======= - this._selectNode(node,true); ->>>>>>> origin/gh-pages } this._redraw(); }, @@ -12988,27 +13462,18 @@ var SelectionMixin = { /** * -<<<<<<< HEAD * retrieve the currently selected objects -======= - * retrieve the currently selected nodes ->>>>>>> origin/gh-pages * @return {Number[] | String[]} selection An array with the ids of the * selected nodes. */ getSelection : function() { -<<<<<<< HEAD var nodeIds = this.getSelectedNodes(); var edgeIds = this.getSelectedEdges(); return {nodes:nodeIds, edges:edgeIds}; -======= - return this.selection.concat([]); ->>>>>>> origin/gh-pages }, /** * -<<<<<<< HEAD * retrieve the currently selected nodes * @return {String} selection An array with the ids of the * selected nodes. @@ -13045,19 +13510,6 @@ var SelectionMixin = { /** -======= - * retrieve the currently selected nodes as objects - * @return {Objects} selection An array with the ids of the - * selected nodes. - */ - getSelectionObjects : function() { - return this.selectionObj; - }, - - /** - * // TODO: rework this function, it is from the old system - * ->>>>>>> origin/gh-pages * select zero or more nodes * @param {Number[] | String[]} selection An array with the ids of the * selected nodes. @@ -13078,28 +13530,17 @@ var SelectionMixin = { if (!node) { throw new RangeError('Node with id "' + id + '" not found'); } -<<<<<<< HEAD this._selectObject(node,true,true); -======= - this._selectNode(node,true,true); ->>>>>>> origin/gh-pages } - this.redraw(); }, /** -<<<<<<< HEAD -======= - * TODO: rework this function, it is from the old system - * ->>>>>>> origin/gh-pages * Validate the selection: remove ids of nodes which no longer exist * @private */ _updateSelection : function () { -<<<<<<< HEAD for(var objectId in this.selectionObj) { if(this.selectionObj.hasOwnProperty(objectId)) { if (this.selectionObj[objectId] instanceof Node) { @@ -13111,88 +13552,12 @@ var SelectionMixin = { if (!this.edges.hasOwnProperty(objectId)) { delete this.selectionObj[objectId]; } - changed = true; } - this.selection = []; - } - } -======= - var i = 0; - while (i < this.selection.length) { - var nodeId = this.selection[i]; - if (!this.nodes.hasOwnProperty(nodeId)) { - this.selection.splice(i, 1); - delete this.selectionObj[nodeId]; - } - else { - i++; } } } - - /** - * Unselect selected nodes. If no selection array is provided, all nodes - * are unselected - * @param {Object[]} selection Array with selection objects, each selection - * object has a parameter row. Optional - * @param {Boolean} triggerSelect If true (default), the select event - * is triggered when nodes are unselected - * @return {Boolean} changed True if the selection is changed - * @private - */ - /* _unselectNodes : function(selection, triggerSelect) { - var changed = false; - var i, iMax, id; - - if (selection) { - // remove provided selections - for (i = 0, iMax = selection.length; i < iMax; i++) { - id = selection[i]; - if (this.nodes.hasOwnProperty(id)) { - this.nodes[id].unselect(); - } - var j = 0; - while (j < this.selection.length) { - if (this.selection[j] == id) { - this.selection.splice(j, 1); - changed = true; - } - else { - j++; - } - } - } - } - else if (this.selection && this.selection.length) { - // remove all selections - for (i = 0, iMax = this.selection.length; i < iMax; i++) { - id = this.selection[i]; - if (this.nodes.hasOwnProperty(id)) { - this.nodes[id].unselect(); - } - changed = true; - } - this.selection = []; - } ->>>>>>> origin/gh-pages - - if (changed && (triggerSelect == true || triggerSelect == undefined)) { - // fire the select event - this._trigger('select', { - nodes: this.getSelection() - }); - } - - return changed; -<<<<<<< HEAD - } - } -======= - }, -*/ ->>>>>>> origin/gh-pages /** * select all nodes on given location x, y * @param {Array} selection an array with node ids @@ -13217,7 +13582,6 @@ var SelectionMixin = { if (selection[i] != this.selection[i]) { selectionAlreadyThere = false; break; -<<<<<<< HEAD >>>>>>> develop } } @@ -13227,47 +13591,14 @@ var SelectionMixin = { <<<<<<< HEAD ======= -======= - } - } - } - if (selectionAlreadyThere) { - return changed; - } - - if (append == undefined || append == false) { - // first deselect any selected node - var triggerSelect = false; - changed = this._unselectNodes(undefined, triggerSelect); - } - - for (i = 0, iMax = selection.length; i < iMax; i++) { - // add each of the new selections, but only when they are not duplicate - var id = selection[i]; - var isDuplicate = (this.selection.indexOf(id) != -1); - if (!isDuplicate) { - this.nodes[id].select(); - this.selection.push(id); - changed = true; - } - } - ->>>>>>> origin/gh-pages if (changed) { // fire the select event this._trigger('select', { nodes: this.getSelection() }); } -<<<<<<< HEAD >>>>>>> develop -======= - - return changed; - }, - */ ->>>>>>> origin/gh-pages }; @@ -13615,6 +13946,9 @@ function Graph (container, data, options) { enabled: false, speed: {x: 10, y: 10, zoom: 0.02} }, + dataManipulationToolbar: { + enabled: false + }, minVelocity: 2, // px/s maxIterations: 1000 // maximum number of iteration to stabilize }; @@ -13631,43 +13965,21 @@ function Graph (container, data, options) { this.yIncrement = 0; this.zoomIncrement = 0; -<<<<<<< HEAD - -======= ->>>>>>> origin/gh-pages // create a frame and canvas this._create(); // load the sector system. (mandatory, fully integrated with Graph) this._loadSectorSystem(); -<<<<<<< HEAD -======= - // apply options - this.setOptions(options); - ->>>>>>> origin/gh-pages // load the cluster system. (mandatory, even when not using the cluster system, there are function calls to it) this._loadClusterSystem(); // load the selection system. (mandatory, required by Graph) this._loadSelectionSystem(); -<<<<<<< HEAD - // load the data manipulation system - this._loadManipulationSystem(); - // apply options this.setOptions(options); - - - - - - -======= ->>>>>>> origin/gh-pages // other vars var graph = this; this.freezeSimulation = false;// freeze the simulation @@ -13678,6 +13990,7 @@ function Graph (container, data, options) { this.canvasTopLeft = {"x": 0,"y": 0}; // coordinates of the top left of the canvas. they will be set during _redraw. this.canvasBottomRight = {"x": 0,"y": 0}; // coordinates of the bottom right of the canvas. they will be set during _redraw + this.pointerPosition = {"x": 0,"y": 0}; // coordinates of the bottom right of the canvas. they will be set during _redraw this.areaCenter = {}; // object with x and y elements used for determining the center of the zoom action this.scale = 1; // defining the global scale variable in the constructor @@ -13960,6 +14273,17 @@ Graph.prototype.setOptions = function (options) { this.constants.keyboard.enabled = false; } + if (options.dataManipulationToolbar) { + this.constants.dataManipulationToolbar.enabled = true; + for (var prop in options.dataManipulationToolbar) { + if (options.dataManipulationToolbar.hasOwnProperty(prop)) { + this.constants.dataManipulationToolbar[prop] = options.dataManipulationToolbar[prop]; + } + } + } + else if (options.dataManipulationToolbar !== undefined) { + this.constants.dataManipulationToolbar.enabled = false; + } // TODO: work out these options and document them if (options.edges) { @@ -14021,16 +14345,18 @@ Graph.prototype.setOptions = function (options) { } } - this.setSize(this.width, this.height); - this._setTranslation(this.frame.clientWidth / 2, this.frame.clientHeight / 2); - this._setScale(1); - // load the navigation system. this._loadNavigationControls(); + // load the data manipulation system + this._loadManipulationSystem(); + // bind keys. If disabled, this will not do anything; this._createKeyBinds(); + this.setSize(this.width, this.height); + this._setTranslation(this.frame.clientWidth / 2, this.frame.clientHeight / 2); + this._setScale(1); this._redraw(); }; @@ -14089,10 +14415,7 @@ Graph.prototype._create = function () { this.frame.className = 'graph-frame'; this.frame.style.position = 'relative'; this.frame.style.overflow = 'hidden'; -<<<<<<< HEAD this.frame.style.zIndex = "1"; -======= ->>>>>>> origin/gh-pages // create the graph canvas (HTML canvas element) this.frame.canvas = document.createElement( 'canvas' ); @@ -14128,10 +14451,7 @@ Graph.prototype._create = function () { // add the frame to the container element this.containerElement.appendChild(this.frame); -<<<<<<< HEAD -======= ->>>>>>> origin/gh-pages }; @@ -14167,17 +14487,10 @@ Graph.prototype._createKeyBinds = function() { this.mousetrap.bind("pagedown",this._zoomOut.bind(me),"keydown"); this.mousetrap.bind("pagedown",this._stopZoom.bind(me), "keyup"); } -<<<<<<< HEAD -======= - /* - this.mousetrap.bind("=",this.decreaseClusterLevel.bind(me)); - this.mousetrap.bind("-",this.increaseClusterLevel.bind(me)); - this.mousetrap.bind("s",this.singleStep.bind(me)); - this.mousetrap.bind("h",this.updateClustersDefault.bind(me)); - this.mousetrap.bind("c",this._collapseSector.bind(me)); - this.mousetrap.bind("f",this.toggleFreeze.bind(me)); - */ ->>>>>>> origin/gh-pages + + if (this.constants.dataManipulationToolbar.enabled == true) { + this.mousetrap.bind("escape",this._createManipulatorBar.bind(me)); + } } /** @@ -14224,7 +14537,6 @@ Graph.prototype._onDragStart = function () { drag.nodeId = node.id; // select the clicked node if not yet selected if (!node.isSelected()) { -<<<<<<< HEAD this._selectObject(node,false); } @@ -14251,33 +14563,6 @@ Graph.prototype._onDragStart = function () { } } } -======= - this._selectNode(node,false); - } - - // create an array with the selected nodes and their original location and status - var me = this; - this.selection.forEach(function (id) { - var node = me.nodes[id]; - if (node) { - var s = { - id: id, - node: node, - - // store original x, y, xFixed and yFixed, make the node temporarily Fixed - x: node.x, - y: node.y, - xFixed: node.xFixed, - yFixed: node.yFixed - }; - - node.xFixed = true; - node.yFixed = true; - - drag.selection.push(s); - } - }); ->>>>>>> origin/gh-pages } }; @@ -14354,11 +14639,9 @@ Graph.prototype._onDragEnd = function () { */ Graph.prototype._onTap = function (event) { var pointer = this._getPointer(event.gesture.touches[0]); + this.pointerPosition = pointer; this._handleTap(pointer); -<<<<<<< HEAD -======= ->>>>>>> origin/gh-pages }; @@ -14379,6 +14662,7 @@ Graph.prototype._onDoubleTap = function (event) { */ Graph.prototype._onHold = function (event) { var pointer = this._getPointer(event.gesture.touches[0]); + this.pointerPosition = pointer; this._handleOnHold(pointer); }; @@ -14707,11 +14991,10 @@ Graph.prototype.setSize = function(width, height) { this.frame.canvas.width = this.frame.canvas.clientWidth; this.frame.canvas.height = this.frame.canvas.clientHeight; -<<<<<<< HEAD - this.manipulationDiv.style.width = this.frame.canvas.clientWidth; + if (this.manipulationDiv !== undefined) { + this.manipulationDiv.style.width = this.frame.canvas.clientWidth; + } -======= ->>>>>>> origin/gh-pages if (this.constants.navigation.enabled == true) { this._relocateNavigation(); } @@ -14776,11 +15059,7 @@ Graph.prototype._addNodes = function(ids) { var node = new Node(data, this.images, this.groups, this.constants); this.nodes[id] = node; // note: this may replace an existing node -<<<<<<< HEAD if (!node.isFixed() && this.createNodeOnClick != true) { -======= - if (!node.isFixed()) { ->>>>>>> origin/gh-pages // TODO: position new nodes in a smarter way! var radius = this.constants.edges.length * 2; var count = ids.length; @@ -14796,10 +15075,7 @@ Graph.prototype._addNodes = function(ids) { this._updateNodeIndexList(); this._reconnectEdges(); this._updateValueRange(this.nodes); -<<<<<<< HEAD this.updateLabels(); -======= ->>>>>>> origin/gh-pages }; /** @@ -15068,11 +15344,7 @@ Graph.prototype._redraw = function() { this._doInAllSectors("_drawAllSectorNodes",ctx); this._doInAllSectors("_drawEdges",ctx); -<<<<<<< HEAD this._doInAllSectors("_drawNodes",ctx,true); -======= - this._doInAllSectors("_drawNodes",ctx); ->>>>>>> origin/gh-pages // restore original scaling and translation ctx.restore(); @@ -15326,6 +15598,7 @@ Graph.prototype._calculateForces = function() { // we loop from i over all but the last entree in the array // j loops from i+1 to the last. This way we do not double count any of the indices, nor i == j + var a_base = (-2/3); var b = 4/3; for (i = 0; i < this.nodeIndices.length-1; i++) { node1 = nodes[this.nodeIndices[i]]; for (j = i+1; j < this.nodeIndices.length; j++) { @@ -15338,6 +15611,7 @@ Graph.prototype._calculateForces = function() { // clusters have a larger region of influence minimumDistance = (clusterSize == 0) ? this.constants.nodes.distance : (this.constants.nodes.distance * (1 + clusterSize * this.constants.clustering.distanceAmplification)); + var a = a_base / minimumDistance; if (distance < 2*minimumDistance) { // at 2.0 * the minimum distance, the force is 0.000045 angle = Math.atan2(dy, dx); @@ -15348,13 +15622,13 @@ Graph.prototype._calculateForces = function() { // TODO: correct factor for repulsing force //repulsingForce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force //repulsingForce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force - repulsingForce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)); // TODO: customize the repulsing force + //repulsingForce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)); // TODO: customize the repulsing force + repulsingForce = a * distance + b; // TODO: test the approximation of the function above } // amplify the repulsion for clusters. repulsingForce *= (clusterSize == 0) ? 1 : 1 + clusterSize * this.constants.clustering.forceAmplification; repulsingForce *= this.forceFactor; - fx = Math.cos(angle) * repulsingForce; fy = Math.sin(angle) * repulsingForce ; @@ -15567,15 +15841,9 @@ Graph.prototype.start = function() { } }; -<<<<<<< HEAD /** * Debug function, does one step of the graph */ -======= - - - ->>>>>>> origin/gh-pages Graph.prototype.singleStep = function() { if (this.moving) { this._initializeForceCalculation(); @@ -15654,10 +15922,6 @@ Graph.prototype._loadSectorSystem = function() { * @private */ Graph.prototype._loadSelectionSystem = function() { -<<<<<<< HEAD -======= - this.selection = []; ->>>>>>> origin/gh-pages this.selectionObj = {}; for (var mixinFunction in SelectionMixin) { @@ -15668,7 +15932,6 @@ Graph.prototype._loadSelectionSystem = function() { } -<<<<<<< HEAD /** * Mixin the navigationUI (User Interface) system and initialize the parameters required @@ -15676,25 +15939,30 @@ Graph.prototype._loadSelectionSystem = function() { * @private */ Graph.prototype._loadManipulationSystem = function() { - // load the manipulator HTML elements. All styling done in css. - this.manipulationDiv = document.createElement('div'); - this.manipulationDiv.className = 'graph-manipulationDiv'; - this.containerElement.insertBefore(this.manipulationDiv, this.frame); + // reset global variables -- these are used by the selection of nodes and edges. + this.blockConnectingEdgeSelection = false; + this.forceAppendSelection = false - // load the manipulation functions - for (var mixinFunction in manipulationMixin) { - if (manipulationMixin.hasOwnProperty(mixinFunction)) { - Graph.prototype[mixinFunction] = manipulationMixin[mixinFunction]; + if (this.constants.dataManipulationToolbar.enabled == true) { + // load the manipulator HTML elements. All styling done in css. + if (this.manipulationDiv === undefined) { + this.manipulationDiv = document.createElement('div'); + this.manipulationDiv.className = 'graph-manipulationDiv'; + this.containerElement.insertBefore(this.manipulationDiv, this.frame); + } + // load the manipulation functions + for (var mixinFunction in manipulationMixin) { + if (manipulationMixin.hasOwnProperty(mixinFunction)) { + Graph.prototype[mixinFunction] = manipulationMixin[mixinFunction]; + } } - } - - this._createManipulatorBar(); + // create the manipulator toolbar + this._createManipulatorBar(); + } } -======= ->>>>>>> origin/gh-pages /** * Mixin the navigation (User Interface) system and initialize the parameters required * diff --git a/dist/vis.min.js b/dist/vis.min.js index 06c28c96..3da5db1c 100644 --- a/dist/vis.min.js +++ b/dist/vis.min.js @@ -4,13 +4,8 @@ * * A dynamic, browser-based visualization library. * -<<<<<<< HEAD * @version 0.5.0-SNAPSHOT - * @date 2014-02-04 -======= - * @version 0.4.0 - * @date 2014-01-31 ->>>>>>> origin/gh-pages + * @date 2014-02-05 * * @license * Copyright (C) 2011-2014 Almende B.V, http://almende.com @@ -27,20 +22,10 @@ * License for the specific language governing permissions and limitations under * the License. */ -<<<<<<< HEAD -!function(t){if("object"==typeof exports)module.exports=t();else if("function"==typeof define&&define.amd)define(t);else{var e;"undefined"!=typeof window?e=window:"undefined"!=typeof global?e=global:"undefined"!=typeof self&&(e=self),e.vis=t()}}(function(){var t;return function e(t,i,n){function s(r,a){if(!i[r]){if(!t[r]){var h="function"==typeof require&&require;if(!a&&h)return h(r,!0);if(o)return o(r,!0);throw new Error("Cannot find module '"+r+"'")}var d=i[r]={exports:{}};t[r][0].call(d.exports,function(e){var i=t[r][1][e];return s(i?i:e)},d,d.exports,e,t,i,n)}return i[r].exports}for(var o="function"==typeof require&&require,r=0;ri;++i)t.call(e||this,this[i],i,this)}),Array.prototype.map||(Array.prototype.map=function(t,e){var i,n,s;if(null==this)throw new TypeError(" this is null or not defined");var o=Object(this),r=o.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(e&&(i=e),n=new Array(r),s=0;r>s;){var a,h;s in o&&(a=o[s],h=t.call(i,a,s,o),n[s]=h),s++}return n}),Array.prototype.filter||(Array.prototype.filter=function(t){"use strict";if(null==this)throw new TypeError;var e=Object(this),i=e.length>>>0;if("function"!=typeof t)throw new TypeError;for(var n=[],s=arguments[1],o=0;i>o;o++)if(o in e){var r=e[o];t.call(s,r,o,e)&&n.push(r)}return n}),Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,e=!{toString:null}.propertyIsEnumerable("toString"),i=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],n=i.length;return function(s){if("object"!=typeof s&&"function"!=typeof s||null===s)throw new TypeError("Object.keys called on non-object");var o=[];for(var r in s)t.call(s,r)&&o.push(r);if(e)for(var a=0;n>a;a++)t.call(s,i[a])&&o.push(i[a]);return o}}()),Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s}),Object.create||(Object.create=function(t){function e(){}if(arguments.length>1)throw new Error("Object.create implementation only accepts the first parameter.");return e.prototype=t,new e}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s});var z={};z.isNumber=function(t){return t instanceof Number||"number"==typeof t},z.isString=function(t){return t instanceof String||"string"==typeof t},z.isDate=function(t){if(t instanceof Date)return!0;if(z.isString(t)){var e=P.exec(t);if(e)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},z.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},z.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},z.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var n=arguments[e];for(var s in n)n.hasOwnProperty(s)&&void 0!==n[s]&&(t[s]=n[s])}return t},z.convert=function(t,e){var i;if(void 0===t)return void 0;if(null===t)return null;if(!e)return t;if("string"!=typeof e&&!(e instanceof String))throw new Error("Type must be a string");switch(e){case"boolean":case"Boolean":return Boolean(t);case"number":case"Number":return Number(t.valueOf());case"string":case"String":return String(t);case"Date":if(z.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(L.isMoment(t))return new Date(t.valueOf());if(z.isString(t))return i=P.exec(t),i?new Date(Number(i[1])):L(t).toDate();throw new Error("Cannot convert object of type "+z.getType(t)+" to type Date");case"Moment":if(z.isNumber(t))return L(t);if(t instanceof Date)return L(t.valueOf());if(L.isMoment(t))return L(t);if(z.isString(t))return i=P.exec(t),L(i?Number(i[1]):t);throw new Error("Cannot convert object of type "+z.getType(t)+" to type Date");case"ISODate":if(z.isNumber(t))return new Date(t);if(t instanceof Date)return t.toISOString();if(L.isMoment(t))return t.toDate().toISOString();if(z.isString(t))return i=P.exec(t),i?new Date(Number(i[1])).toISOString():new Date(t).toISOString();throw new Error("Cannot convert object of type "+z.getType(t)+" to type ISODate");case"ASPDate":if(z.isNumber(t))return"/Date("+t+")/";if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(z.isString(t)){i=P.exec(t);var n;return n=i?new Date(Number(i[1])).valueOf():new Date(t).valueOf(),"/Date("+n+")/"}throw new Error("Cannot convert object of type "+z.getType(t)+" to type ASPDate");default:throw new Error("Cannot convert object of type "+z.getType(t)+' to type "'+e+'"')}};var P=/^\/?Date\((\-?\d+)/i;z.getType=function(t){var e=typeof t;return"object"==e?null==t?"null":t instanceof Boolean?"Boolean":t instanceof Number?"Number":t instanceof String?"String":t instanceof Array?"Array":t instanceof Date?"Date":"Object":"number"==e?"Number":"boolean"==e?"Boolean":"string"==e?"String":e},z.getAbsoluteLeft=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetLeft,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetLeft,n-=s.scrollLeft,s=s.offsetParent;return n},z.getAbsoluteTop=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetTop,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetTop,n-=s.scrollTop,s=s.offsetParent;return n},z.getPageY=function(t){if("pageY"in t)return t.pageY;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientY:t.clientY;var i=document.documentElement,n=document.body;return e+(i&&i.scrollTop||n&&n.scrollTop||0)-(i&&i.clientTop||n&&n.clientTop||0)},z.getPageX=function(t){if("pageY"in t)return t.pageX;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientX:t.clientX;var i=document.documentElement,n=document.body;return e+(i&&i.scrollLeft||n&&n.scrollLeft||0)-(i&&i.clientLeft||n&&n.clientLeft||0)},z.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},z.removeClassName=function(t,e){var i=t.className.split(" "),n=i.indexOf(e);-1!=n&&(i.splice(n,1),t.className=i.join(" "))},z.forEach=function(t,e){var i,n;if(t instanceof Array)for(i=0,n=t.length;n>i;i++)e(t[i],i,t);else for(i in t)t.hasOwnProperty(i)&&e(t[i],i,t)},z.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},z.addEventListener=function(t,e,i,n){t.addEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.addEventListener(e,i,n)):t.attachEvent("on"+e,i)},z.removeEventListener=function(t,e,i,n){t.removeEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.removeEventListener(e,i,n)):t.detachEvent("on"+e,i)},z.getTarget=function(t){t||(t=window.event);var e;return t.target?e=t.target:t.srcElement&&(e=t.srcElement),void 0!=e.nodeType&&3==e.nodeType&&(e=e.parentNode),e},z.stopPropagation=function(t){t||(t=window.event),t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},z.fakeGesture=function(t,e){var i=null;return N.event.collectEventData(this,i,e)},z.preventDefault=function(t){t||(t=window.event),t.preventDefault?t.preventDefault():t.returnValue=!1},z.option={},z.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},z.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},z.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?String(t):e||null},z.option.asSize=function(t,e){return"function"==typeof t&&(t=t()),z.isString(t)?t:z.isNumber(t)?t+"px":e||null},z.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null};var F={listeners:[],indexOf:function(t){for(var e=this.listeners,i=0,n=this.listeners.length;n>i;i++){var s=e[i];if(s&&s.object==t)return i}return-1},addListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];s||(s={object:t,events:{}},this.listeners.push(s));var o=s.events[e];o||(o=[],s.events[e]=o),-1==o.indexOf(i)&&o.push(i)},removeListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];o&&(n=o.indexOf(i),-1!=n&&o.splice(n,1),0==o.length&&delete s.events[e]);var r=0,a=s.events;for(var h in a)a.hasOwnProperty(h)&&r++;0==r&&delete this.listeners[n]}},removeAllListeners:function(){this.listeners=[]},trigger:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];if(o)for(var r=0,a=o.length;a>r;r++)o[r](i)}}};s.prototype.on=function(t,e,i){var n=t instanceof RegExp?t:new RegExp(t.replace("*","\\w+")),s={id:z.randomUUID(),event:t,regexp:n,callback:"function"==typeof e?e:null,target:i};return this.subscriptions.push(s),s.id},s.prototype.off=function(t){for(var e=0;eo;o++)i=s._addItem(t[o]),n.push(i);else if(z.isDataTable(t))for(var a=this._getColumnNames(t),h=0,d=t.getNumberOfRows();d>h;h++){for(var c={},l=0,u=a.length;u>l;l++){var p=a[l];c[p]=t.getValue(h,l)}i=s._addItem(c),n.push(i)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");i=s._addItem(t),n.push(i)}return n.length&&this._trigger("add",{items:n},e),n},o.prototype.update=function(t,e){var i=[],n=[],s=this,o=s.fieldId,r=function(t){var e=t[o];s.data[e]?(e=s._updateItem(t),n.push(e)):(e=s._addItem(t),i.push(e))};if(t instanceof Array)for(var a=0,h=t.length;h>a;a++)r(t[a]);else if(z.isDataTable(t))for(var d=this._getColumnNames(t),c=0,l=t.getNumberOfRows();l>c;c++){for(var u={},p=0,f=d.length;f>p;p++){var g=d[p];u[g]=t.getValue(c,p)}r(u)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");r(t)}return i.length&&this._trigger("add",{items:i},e),n.length&&this._trigger("update",{items:n},e),i.concat(n)},o.prototype.get=function(){var t,e,i,n,s=this,o=this.showInternalIds,r=z.getType(arguments[0]);"String"==r||"Number"==r?(t=arguments[0],i=arguments[1],n=arguments[2]):"Array"==r?(e=arguments[0],i=arguments[1],n=arguments[2]):(i=arguments[0],n=arguments[1]);var a;if(i&&i.type){if(a="DataTable"==i.type?"DataTable":"Array",n&&a!=z.getType(n))throw new Error('Type of parameter "data" ('+z.getType(n)+") does not correspond with specified options.type ("+i.type+")");if("DataTable"==a&&!z.isDataTable(n))throw new Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else a=n?"DataTable"==z.getType(n)?"DataTable":"Array":"Array";void 0!=i&&void 0!=i.showInternalIds&&(this.showInternalIds=i.showInternalIds);var h,d,c,l,u=i&&i.convert||this.options.convert,p=i&&i.filter,f=[];if(void 0!=t)h=s._getItem(t,u),p&&!p(h)&&(h=null);else if(void 0!=e)for(c=0,l=e.length;l>c;c++)h=s._getItem(e[c],u),(!p||p(h))&&f.push(h);else for(d in this.data)this.data.hasOwnProperty(d)&&(h=s._getItem(d,u),(!p||p(h))&&f.push(h));if(this.showInternalIds=o,i&&i.order&&void 0==t&&this._sort(f,i.order),i&&i.fields){var g=i.fields;if(void 0!=t)h=this._filterFields(h,g);else for(c=0,l=f.length;l>c;c++)f[c]=this._filterFields(f[c],g)}if("DataTable"==a){var m=this._getColumnNames(n);if(void 0!=t)s._appendRow(n,m,h);else for(c=0,l=f.length;l>c;c++)s._appendRow(n,m,f[c]);return n}if(void 0!=t)return h;if(n){for(c=0,l=f.length;l>c;c++)n.push(f[c]);return n}return f},o.prototype.getIds=function(t){var e,i,n,s,o,r=this.data,a=t&&t.filter,h=t&&t.order,d=t&&t.convert||this.options.convert,c=[];if(a)if(h){o=[];for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,d),a(s)&&o.push(s));for(this._sort(o,h),e=0,i=o.length;i>e;e++)c[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,d),a(s)&&c.push(s[this.fieldId]));else if(h){o=[];for(n in r)r.hasOwnProperty(n)&&o.push(r[n]);for(this._sort(o,h),e=0,i=o.length;i>e;e++)c[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=r[n],c.push(s[this.fieldId]));return c},o.prototype.forEach=function(t,e){var i,n,s=e&&e.filter,o=e&&e.convert||this.options.convert,r=this.data;if(e&&e.order)for(var a=this.get(e),h=0,d=a.length;d>h;h++)i=a[h],n=i[this.fieldId],t(i,n);else for(n in r)r.hasOwnProperty(n)&&(i=this._getItem(n,o),(!s||s(i))&&t(i,n))},o.prototype.map=function(t,e){var i,n=e&&e.filter,s=e&&e.convert||this.options.convert,o=[],r=this.data;for(var a in r)r.hasOwnProperty(a)&&(i=this._getItem(a,s),(!n||n(i))&&o.push(t(i,a)));return e&&e.order&&this._sort(o,e.order),o},o.prototype._filterFields=function(t,e){var i={};for(var n in t)t.hasOwnProperty(n)&&-1!=e.indexOf(n)&&(i[n]=t[n]);return i},o.prototype._sort=function(t,e){if(z.isString(e)){var i=e;t.sort(function(t,e){var n=t[i],s=e[i];return n>s?1:s>n?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},o.prototype.remove=function(t,e){var i,n,s,o=[];if(t instanceof Array)for(i=0,n=t.length;n>i;i++)s=this._remove(t[i]),null!=s&&o.push(s);else s=this._remove(t),null!=s&&o.push(s);return o.length&&this._trigger("remove",{items:o},e),o},o.prototype._remove=function(t){if(z.isNumber(t)||z.isString(t)){if(this.data[t])return delete this.data[t],delete this.internalIds[t],t}else if(t instanceof Object){var e=t[this.fieldId];if(e&&this.data[e])return delete this.data[e],delete this.internalIds[e],e}return null},o.prototype.clear=function(t){var e=Object.keys(this.data);return this.data={},this.internalIds={},this._trigger("remove",{items:e},t),e},o.prototype.max=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||r>n)&&(i=o,n=r)}return i},o.prototype.min=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||n>r)&&(i=o,n=r)}return i},o.prototype.distinct=function(t){var e=this.data,i=[],n=this.options.convert[t],s=0;for(var o in e)if(e.hasOwnProperty(o)){for(var r=e[o],a=z.convert(r[t],n),h=!1,d=0;s>d;d++)if(i[d]==a){h=!0;break}h||(i[s]=a,s++)}return i},o.prototype._addItem=function(t){var e=t[this.fieldId];if(void 0!=e){if(this.data[e])throw new Error("Cannot add item: item with id "+e+" already exists")}else e=z.randomUUID(),t[this.fieldId]=e,this.internalIds[e]=t;var i={};for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=z.convert(t[n],s)}return this.data[e]=i,e},o.prototype._getItem=function(t,e){var i,n,s=this.data[t];if(!s)return null;var o={},r=this.fieldId,a=this.internalIds;if(e)for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a&&!this.showInternalIds||(o[i]=z.convert(n,e[i])));else for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a&&!this.showInternalIds||(o[i]=n));return o},o.prototype._updateItem=function(t){var e=t[this.fieldId];if(void 0==e)throw new Error("Cannot update item: item has no id (item: "+JSON.stringify(t)+")");var i=this.data[e];if(!i)throw new Error("Cannot update item: no item with id "+e+" found");for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=z.convert(t[n],s)}return e},o.prototype.isInternalId=function(t){return t in this.internalIds},o.prototype._getColumnNames=function(t){for(var e=[],i=0,n=t.getNumberOfColumns();n>i;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},o.prototype._appendRow=function(t,e,i){for(var n=t.addRow(),s=0,o=e.length;o>s;s++){var r=e[s];t.setValue(n,s,i[r])}},r.prototype.setData=function(t){var e,i,n;if(this.data){this.data.unsubscribe&&this.data.unsubscribe("*",this.listener),e=[];for(var s in this.ids)this.ids.hasOwnProperty(s)&&e.push(s);this.ids={},this._trigger("remove",{items:e})}if(this.data=t,this.data){for(this.fieldId=this.options.fieldId||this.data&&this.data.options&&this.data.options.fieldId||"id",e=this.data.getIds({filter:this.options&&this.options.filter}),i=0,n=e.length;n>i;i++)s=e[i],this.ids[s]=!0;this._trigger("add",{items:e}),this.data.subscribe&&this.data.subscribe("*",this.listener)}},r.prototype.get=function(){var t,e,i,n=this,s=z.getType(arguments[0]);"String"==s||"Number"==s||"Array"==s?(t=arguments[0],e=arguments[1],i=arguments[2]):(e=arguments[0],i=arguments[1]);var o=z.extend({},this.options,e);this.options.filter&&e&&e.filter&&(o.filter=function(t){return n.options.filter(t)&&e.filter(t)});var r=[];return void 0!=t&&r.push(t),r.push(o),r.push(i),this.data&&this.data.get.apply(this.data,r)},r.prototype.getIds=function(t){var e;if(this.data){var i,n=this.options.filter;i=t&&t.filter?n?function(e){return n(e)&&t.filter(e)}:t.filter:n,e=this.data.getIds({filter:i,order:t&&t.order})}else e=[];return e},r.prototype._onEvent=function(t,e,i){var n,s,o,r,a=e&&e.items,h=this.data,d=[],c=[],l=[];if(a&&h){switch(t){case"add":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r&&(this.ids[o]=!0,d.push(o));break;case"update":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r?this.ids[o]?c.push(o):(this.ids[o]=!0,d.push(o)):this.ids[o]&&(delete this.ids[o],l.push(o));break;case"remove":for(n=0,s=a.length;s>n;n++)o=a[n],this.ids[o]&&(delete this.ids[o],l.push(o))}d.length&&this._trigger("add",{items:d},i),c.length&&this._trigger("update",{items:c},i),l.length&&this._trigger("remove",{items:l},i)}},r.prototype.subscribe=o.prototype.subscribe,r.prototype.unsubscribe=o.prototype.unsubscribe,r.prototype._trigger=o.prototype._trigger,TimeStep=function(t,e,i){this.current=new Date,this._start=new Date,this._end=new Date,this.autoScale=!0,this.scale=TimeStep.SCALE.DAY,this.step=1,this.setRange(t,e,i)},TimeStep.SCALE={MILLISECOND:1,SECOND:2,MINUTE:3,HOUR:4,DAY:5,WEEKDAY:6,MONTH:7,YEAR:8},TimeStep.prototype.setRange=function(t,e,i){if(!(t instanceof Date&&e instanceof Date))throw"No legal start or end date in method setRange";this._start=void 0!=t?new Date(t.valueOf()):new Date,this._end=void 0!=e?new Date(e.valueOf()):new Date,this.autoScale&&this.setMinimumStep(i)},TimeStep.prototype.first=function(){this.current=new Date(this._start.valueOf()),this.roundToMinor()},TimeStep.prototype.roundToMinor=function(){switch(this.scale){case TimeStep.SCALE.YEAR:this.current.setFullYear(this.step*Math.floor(this.current.getFullYear()/this.step)),this.current.setMonth(0);case TimeStep.SCALE.MONTH:this.current.setDate(1);case TimeStep.SCALE.DAY:case TimeStep.SCALE.WEEKDAY:this.current.setHours(0);case TimeStep.SCALE.HOUR:this.current.setMinutes(0);case TimeStep.SCALE.MINUTE:this.current.setSeconds(0);case TimeStep.SCALE.SECOND:this.current.setMilliseconds(0)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.setMilliseconds(this.current.getMilliseconds()-this.current.getMilliseconds()%this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()-this.current.getSeconds()%this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()-this.current.getMinutes()%this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()-this.current.getHours()%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()-1-(this.current.getDate()-1)%this.step+1);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()-this.current.getMonth()%this.step); -break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()-this.current.getFullYear()%this.step)}},TimeStep.prototype.hasNext=function(){return this.current.valueOf()<=this._end.valueOf()},TimeStep.prototype.next=function(){var t=this.current.valueOf();if(this.current.getMonth()<6)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current=new Date(this.current.valueOf()+1e3*this.step);break;case TimeStep.SCALE.MINUTE:this.current=new Date(this.current.valueOf()+1e3*this.step*60);break;case TimeStep.SCALE.HOUR:this.current=new Date(this.current.valueOf()+1e3*this.step*60*60);var e=this.current.getHours();this.current.setHours(e-e%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}else switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()+this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()+this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()+this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.getMilliseconds()0&&(this.step=e),this.autoScale=!1},TimeStep.prototype.setAutoScale=function(t){this.autoScale=t},TimeStep.prototype.setMinimumStep=function(t){if(void 0!=t){var e=31104e6,i=2592e6,n=864e5,s=36e5,o=6e4,r=1e3,a=1;1e3*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1e3),500*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=500),100*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=100),50*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=50),10*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=10),5*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=5),e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1),3*i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=3),i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=1),5*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=5),2*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=2),n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=1),n/2>t&&(this.scale=TimeStep.SCALE.WEEKDAY,this.step=1),4*s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=4),s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=1),15*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=15),10*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=10),5*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=5),o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=1),15*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=15),10*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=10),5*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=5),r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=1),200*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=200),100*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=100),50*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=50),10*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=10),5*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=5),a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=1)}},TimeStep.prototype.snap=function(t){if(this.scale==TimeStep.SCALE.YEAR){var e=t.getFullYear()+Math.round(t.getMonth()/12);t.setFullYear(Math.round(e/this.step)*this.step),t.setMonth(0),t.setDate(0),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MONTH)t.getDate()>15?(t.setDate(1),t.setMonth(t.getMonth()+1)):t.setDate(1),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0);else if(this.scale==TimeStep.SCALE.DAY||this.scale==TimeStep.SCALE.WEEKDAY){switch(this.step){case 5:case 2:t.setHours(24*Math.round(t.getHours()/24));break;default:t.setHours(12*Math.round(t.getHours()/12))}t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.HOUR){switch(this.step){case 4:t.setMinutes(60*Math.round(t.getMinutes()/60));break;default:t.setMinutes(30*Math.round(t.getMinutes()/30))}t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MINUTE){switch(this.step){case 15:case 10:t.setMinutes(5*Math.round(t.getMinutes()/5)),t.setSeconds(0);break;case 5:t.setSeconds(60*Math.round(t.getSeconds()/60));break;default:t.setSeconds(30*Math.round(t.getSeconds()/30))}t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.SECOND)switch(this.step){case 15:case 10:t.setSeconds(5*Math.round(t.getSeconds()/5)),t.setMilliseconds(0);break;case 5:t.setMilliseconds(1e3*Math.round(t.getMilliseconds()/1e3));break;default:t.setMilliseconds(500*Math.round(t.getMilliseconds()/500))}else if(this.scale==TimeStep.SCALE.MILLISECOND){var i=this.step>5?this.step/2:1;t.setMilliseconds(Math.round(t.getMilliseconds()/i)*i)}},TimeStep.prototype.isMajor=function(){switch(this.scale){case TimeStep.SCALE.MILLISECOND:return 0==this.current.getMilliseconds();case TimeStep.SCALE.SECOND:return 0==this.current.getSeconds();case TimeStep.SCALE.MINUTE:return 0==this.current.getHours()&&0==this.current.getMinutes();case TimeStep.SCALE.HOUR:return 0==this.current.getHours();case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return 1==this.current.getDate();case TimeStep.SCALE.MONTH:return 0==this.current.getMonth();case TimeStep.SCALE.YEAR:return!1;default:return!1}},TimeStep.prototype.getLabelMinor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return L(t).format("SSS");case TimeStep.SCALE.SECOND:return L(t).format("s");case TimeStep.SCALE.MINUTE:return L(t).format("HH:mm");case TimeStep.SCALE.HOUR:return L(t).format("HH:mm");case TimeStep.SCALE.WEEKDAY:return L(t).format("ddd D");case TimeStep.SCALE.DAY:return L(t).format("D");case TimeStep.SCALE.MONTH:return L(t).format("MMM");case TimeStep.SCALE.YEAR:return L(t).format("YYYY");default:return""}},TimeStep.prototype.getLabelMajor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return L(t).format("HH:mm:ss");case TimeStep.SCALE.SECOND:return L(t).format("D MMMM HH:mm");case TimeStep.SCALE.MINUTE:case TimeStep.SCALE.HOUR:return L(t).format("ddd D MMMM");case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return L(t).format("MMMM YYYY");case TimeStep.SCALE.MONTH:return L(t).format("YYYY");case TimeStep.SCALE.YEAR:return"";default:return""}},a.prototype.setOptions=function(t){z.extend(this.options,t)},a.prototype.update=function(){this._order(),this._stack()},a.prototype._order=function(){var t=this.parent.items;if(!t)throw new Error("Cannot stack items: parent does not contain items");var e=[],i=0;z.forEach(t,function(t){t.visible&&(e[i]=t,i++)});var n=this.options.order||this.defaultOptions.order;if("function"!=typeof n)throw new Error("Option order must be a function");e.sort(n),this.ordered=e},a.prototype._stack=function(){var t,e,i,n=this.ordered,s=this.options,o=s.orientation||this.defaultOptions.orientation,r="top"==o;for(i=s.margin&&void 0!==s.margin.item?s.margin.item:this.defaultOptions.margin.item,t=0,e=n.length;e>t;t++){var a=n[t],h=null;do h=this.checkOverlap(n,t,0,t-1,i),null!=h&&(a.top=r?h.top+h.height+i:h.top-a.height-i);while(h)}},a.prototype.checkOverlap=function(t,e,i,n,s){for(var o=this.collision,r=t[e],a=n;a>=i;a--){var h=t[a];if(o(r,h,s)&&a!=e)return h}return null},a.prototype.collision=function(t,e,i){return t.left-ie.left&&t.top-ie.top},h.prototype.setOptions=function(t){z.extend(this.options,t),null!==this.start&&null!==this.end&&this.setRange(this.start,this.end)},h.prototype.subscribe=function(t,e,i){function n(e){s._onMouseWheel(e,t,i)}var s=this;if("move"==e)t.on("dragstart",function(e){s._onDragStart(e,t)}),t.on("drag",function(e){s._onDrag(e,t,i)}),t.on("dragend",function(e){s._onDragEnd(e,t)});else{if("zoom"!=e)throw new TypeError('Unknown event "'+e+'". Choose "move" or "zoom".');t.on("mousewheel",n),t.on("DOMMouseScroll",n),t.on("touch",function(){s._onTouch()}),t.on("pinch",function(e){s._onPinch(e,t,i)})}},h.prototype.on=function(t,e){var i=["rangechange","rangechanged"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());F.addListener(this,t,e)},h.prototype.off=function(t,e){F.removeListener(this,t,e)},h.prototype._trigger=function(t){F.trigger(this,t,{start:this.start,end:this.end})},h.prototype.setRange=function(t,e){var i=this._applyRange(t,e);i&&(this._trigger("rangechange"),this._trigger("rangechanged"))},h.prototype._applyRange=function(t,e){var i,n=null!=t?z.convert(t,"Date").valueOf():this.start,s=null!=e?z.convert(e,"Date").valueOf():this.end,o=null!=this.options.max?z.convert(this.options.max,"Date").valueOf():null,r=null!=this.options.min?z.convert(this.options.min,"Date").valueOf():null;if(isNaN(n)||null===n)throw new Error('Invalid start "'+t+'"');if(isNaN(s)||null===s)throw new Error('Invalid end "'+e+'"');if(n>s&&(s=n),null!==r&&r>n&&(i=r-n,n+=i,s+=i,null!=o&&s>o&&(s=o)),null!==o&&s>o&&(i=s-o,n-=i,s-=i,null!=r&&r>n&&(n=r)),null!==this.options.zoomMin){var a=parseFloat(this.options.zoomMin);0>a&&(a=0),a>s-n&&(this.end-this.start===a?(n=this.start,s=this.end):(i=a-(s-n),n-=i/2,s+=i/2))}if(null!==this.options.zoomMax){var h=parseFloat(this.options.zoomMax);0>h&&(h=0),s-n>h&&(this.end-this.start===h?(n=this.start,s=this.end):(i=s-n-h,n+=i/2,s-=i/2))}var d=this.start!=n||this.end!=s;return this.start=n,this.end=s,d},h.prototype.getRange=function(){return{start:this.start,end:this.end}},h.prototype.conversion=function(t){return h.conversion(this.start,this.end,t)},h.conversion=function(t,e,i){return 0!=i&&e-t!=0?{offset:t,scale:i/(e-t)}:{offset:0,scale:1}};var Y={};h.prototype._onDragStart=function(t,e){if(!Y.pinching){Y.start=this.start,Y.end=this.end;var i=e.frame;i&&(i.style.cursor="move")}},h.prototype._onDrag=function(t,e,i){if(d(i),!Y.pinching){var n="horizontal"==i?t.gesture.deltaX:t.gesture.deltaY,s=Y.end-Y.start,o="horizontal"==i?e.width:e.height,r=-n/o*s;this._applyRange(Y.start+r,Y.end+r),this._trigger("rangechange")}},h.prototype._onDragEnd=function(t,e){Y.pinching||(e.frame&&(e.frame.style.cursor="auto"),this._trigger("rangechanged"))},h.prototype._onMouseWheel=function(t,e,i){d(i);var n=0;if(t.wheelDelta?n=t.wheelDelta/120:t.detail&&(n=-t.detail/3),n){var s;s=0>n?1-n/5:1/(1+n/5);var o=z.fakeGesture(this,t),r=c(o.touches[0],e.frame),a=this._pointerToDate(e,i,r);this.zoom(s,a)}z.preventDefault(t)},h.prototype._onTouch=function(){Y.start=this.start,Y.end=this.end,Y.pinching=!1,Y.center=null},h.prototype._onPinch=function(t,e,i){if(Y.pinching=!0,t.gesture.touches.length>1){Y.center||(Y.center=c(t.gesture.center,e.frame));var n=1/t.gesture.scale,s=this._pointerToDate(e,i,Y.center),o=c(t.gesture.center,e.frame),r=(this._pointerToDate(e,i,o),parseInt(s+(Y.start-s)*n)),a=parseInt(s+(Y.end-s)*n);this.setRange(r,a)}},h.prototype._pointerToDate=function(t,e,i){var n;if("horizontal"==e){var s=t.width;return n=this.conversion(s),i.x/n.scale+n.offset}var o=t.height;return n=this.conversion(o),i.y/n.scale+n.offset},h.prototype.zoom=function(t,e){null==e&&(e=(this.start+this.end)/2);var i=e+(this.start-e)*t,n=e+(this.end-e)*t;this.setRange(i,n)},h.prototype.move=function(t){var e=this.end-this.start,i=this.start+e*t,n=this.end+e*t;this.start=i,this.end=n},h.prototype.moveTo=function(t){var e=(this.start+this.end)/2,i=e-t,n=this.start-i,s=this.end-i;this.setRange(n,s)},l.prototype.add=function(t){if(void 0==t.id)throw new Error("Component has no field id");if(!(t instanceof u||t instanceof l))throw new TypeError("Component must be an instance of prototype Component or Controller");t.controller=this,this.components[t.id]=t},l.prototype.remove=function(t){var e;for(e in this.components)if(this.components.hasOwnProperty(e)&&(e==t||this.components[e]==t))break;e&&delete this.components[e]},l.prototype.requestReflow=function(t){if(t)this.reflow();else if(!this.reflowTimer){var e=this;this.reflowTimer=setTimeout(function(){e.reflowTimer=void 0,e.reflow()},0)}},l.prototype.requestRepaint=function(t){if(t)this.repaint();else if(!this.repaintTimer){var e=this;this.repaintTimer=setTimeout(function(){e.repaintTimer=void 0,e.repaint()},0)}},l.prototype.repaint=function G(){function G(i,n){n in e||(i.depends&&i.depends.forEach(function(t){G(t,t.id)}),i.parent&&G(i.parent,i.parent.id),t=i.repaint()||t,e[n]=!0)}var t=!1;this.repaintTimer&&(clearTimeout(this.repaintTimer),this.repaintTimer=void 0);var e={};z.forEach(this.components,G),t&&this.reflow()},l.prototype.reflow=function B(){function B(i,n){n in e||(i.depends&&i.depends.forEach(function(t){B(t,t.id)}),i.parent&&B(i.parent,i.parent.id),t=i.reflow()||t,e[n]=!0)}var t=!1;this.reflowTimer&&(clearTimeout(this.reflowTimer),this.reflowTimer=void 0);var e={};z.forEach(this.components,B),t&&this.repaint()},u.prototype.setOptions=function(t){t&&(z.extend(this.options,t),this.controller&&(this.requestRepaint(),this.requestReflow()))},u.prototype.getOption=function(t){var e;return this.options&&(e=this.options[t]),void 0===e&&this.defaultOptions&&(e=this.defaultOptions[t]),e},u.prototype.getContainer=function(){return null},u.prototype.getFrame=function(){return this.frame},u.prototype.repaint=function(){return!1},u.prototype.reflow=function(){return!1},u.prototype.hide=function(){return this.frame&&this.frame.parentNode?(this.frame.parentNode.removeChild(this.frame),!0):!1},u.prototype.show=function(){return this.frame&&this.frame.parentNode?!1:this.repaint()},u.prototype.requestRepaint=function(){if(!this.controller)throw new Error("Cannot request a repaint: no controller configured");this.controller.requestRepaint()},u.prototype.requestReflow=function(){if(!this.controller)throw new Error("Cannot request a reflow: no controller configured");this.controller.requestReflow()},p.prototype=new u,p.prototype.setOptions=u.prototype.setOptions,p.prototype.getContainer=function(){return this.frame},p.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.frame;if(!s){s=document.createElement("div"),s.className="panel";var o=n.className;o&&("function"==typeof o?z.addClassName(s,String(o())):z.addClassName(s,String(o))),this.frame=s,t+=1}if(!s.parentNode){if(!this.parent)throw new Error("Cannot repaint panel: no parent attached");var r=this.parent.getContainer();if(!r)throw new Error("Cannot repaint panel: parent has no container element");r.appendChild(s),t+=1}return t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),t>0},p.prototype.reflow=function(){var t=0,e=z.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},f.prototype=new p,f.prototype.setOptions=u.prototype.setOptions,f.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.frame;if(s||(s=document.createElement("div"),this.frame=s,t+=1),!s.parentNode){if(!this.container)throw new Error("Cannot repaint root panel: no container attached");this.container.appendChild(s),t+=1}s.className="vis timeline rootpanel "+n.orientation;var o=n.className;return o&&z.addClassName(s,z.option.asString(o)),t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),this._updateEventEmitters(),this._updateWatch(),t>0},f.prototype.reflow=function(){var t=0,e=z.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},f.prototype._updateWatch=function(){var t=this.getOption("autoResize");t?this._watch():this._unwatch()},f.prototype._watch=function(){var t=this;this._unwatch();var e=function(){var e=t.getOption("autoResize");return e?void(t.frame&&(t.frame.clientWidth!=t.width||t.frame.clientHeight!=t.height)&&t.requestReflow()):void t._unwatch()};z.addEventListener(window,"resize",e),this.watchTimer=setInterval(e,1e3)},f.prototype._unwatch=function(){this.watchTimer&&(clearInterval(this.watchTimer),this.watchTimer=void 0)},f.prototype.on=function(t,e){var i=this.listeners[t];i||(i=[],this.listeners[t]=i),i.push(e),this._updateEventEmitters()},f.prototype._updateEventEmitters=function(){if(this.listeners){var t=this;z.forEach(this.listeners,function(e,i){if(t.emitters||(t.emitters={}),!(i in t.emitters)){var n=t.frame;if(n){var s=function(t){e.forEach(function(e){e(t)})};t.emitters[i]=s,t.hammer||(t.hammer=N(n,{prevent_default:!0})),t.hammer.on(i,s)}}})}},g.prototype=new u,g.prototype.setOptions=u.prototype.setOptions,g.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},g.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},g.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},g.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.props,r=this.step,a=this.frame;if(a||(a=document.createElement("div"),this.frame=a,t+=1),a.className="axis",!a.parentNode){if(!this.parent)throw new Error("Cannot repaint time axis: no parent attached");var h=this.parent.getContainer();if(!h)throw new Error("Cannot repaint time axis: parent has no container element");h.appendChild(a),t+=1}var d=a.parentNode;if(d){var c=a.nextSibling;d.removeChild(a);var l="bottom"==s&&this.props.parentHeight&&this.height?this.props.parentHeight-this.height+"px":"0px";if(t+=e(a.style,"top",i(n.top,l)),t+=e(a.style,"left",i(n.left,"0px")),t+=e(a.style,"width",i(n.width,"100%")),t+=e(a.style,"height",i(n.height,this.height+"px")),this._repaintMeasureChars(),this.step){this._repaintStart(),r.first();for(var u=void 0,p=0;r.hasNext()&&1e3>p;){p++;var f=r.getCurrent(),g=this.toScreen(f),m=r.isMajor();this.getOption("showMinorLabels")&&this._repaintMinorText(g,r.getLabelMinor()),m&&this.getOption("showMajorLabels")?(g>0&&(void 0==u&&(u=g),this._repaintMajorText(g,r.getLabelMajor())),this._repaintMajorLine(g)):this._repaintMinorLine(g),r.next()}if(this.getOption("showMajorLabels")){var v=this.toTime(0),y=r.getLabelMajor(v),_=y.length*(o.majorCharWidth||10)+10;(void 0==u||u>_)&&this._repaintMajorText(0,y)}this._repaintEnd()}this._repaintLine(),c?d.insertBefore(a,c):d.appendChild(a)}return t>0},g.prototype._repaintStart=function(){var t=this.dom,e=t.redundant;e.majorLines=t.majorLines,e.majorTexts=t.majorTexts,e.minorLines=t.minorLines,e.minorTexts=t.minorTexts,t.majorLines=[],t.majorTexts=[],t.minorLines=[],t.minorTexts=[]},g.prototype._repaintEnd=function(){z.forEach(this.dom.redundant,function(t){for(;t.length;){var e=t.pop();e&&e.parentNode&&e.parentNode.removeChild(e)}})},g.prototype._repaintMinorText=function(t,e){var i=this.dom.redundant.minorTexts.shift();if(!i){var n=document.createTextNode("");i=document.createElement("div"),i.appendChild(n),i.className="text minor",this.frame.appendChild(i)}this.dom.minorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.left=t+"px",i.style.top=this.props.minorLabelTop+"px"},g.prototype._repaintMajorText=function(t,e){var i=this.dom.redundant.majorTexts.shift();if(!i){var n=document.createTextNode(e);i=document.createElement("div"),i.className="text major",i.appendChild(n),this.frame.appendChild(i)}this.dom.majorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.top=this.props.majorLabelTop+"px",i.style.left=t+"px"},g.prototype._repaintMinorLine=function(t){var e=this.dom.redundant.minorLines.shift();e||(e=document.createElement("div"),e.className="grid vertical minor",this.frame.appendChild(e)),this.dom.minorLines.push(e);var i=this.props;e.style.top=i.minorLineTop+"px",e.style.height=i.minorLineHeight+"px",e.style.left=t-i.minorLineWidth/2+"px"},g.prototype._repaintMajorLine=function(t){var e=this.dom.redundant.majorLines.shift();e||(e=document.createElement("DIV"),e.className="grid vertical major",this.frame.appendChild(e)),this.dom.majorLines.push(e);var i=this.props;e.style.top=i.majorLineTop+"px",e.style.left=t-i.majorLineWidth/2+"px",e.style.height=i.majorLineHeight+"px"},g.prototype._repaintLine=function(){{var t=this.dom.line,e=this.frame;this.options}this.getOption("showMinorLabels")||this.getOption("showMajorLabels")?(t?(e.removeChild(t),e.appendChild(t)):(t=document.createElement("div"),t.className="grid horizontal major",e.appendChild(t),this.dom.line=t),t.style.top=this.props.lineTop+"px"):t&&t.parentElement&&(e.removeChild(t.line),delete this.dom.line)},g.prototype._repaintMeasureChars=function(){var t,e=this.dom;if(!e.measureCharMinor){t=document.createTextNode("0");var i=document.createElement("DIV");i.className="text minor measure",i.appendChild(t),this.frame.appendChild(i),e.measureCharMinor=i}if(!e.measureCharMajor){t=document.createTextNode("0");var n=document.createElement("DIV");n.className="text major measure",n.appendChild(t),this.frame.appendChild(n),e.measureCharMajor=n}},g.prototype.reflow=function(){var t=0,e=z.updateProperty,i=this.frame,n=this.range;if(!n)throw new Error("Cannot repaint time axis: no range configured");if(i){t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft);var s=this.props,o=this.getOption("showMinorLabels"),r=this.getOption("showMajorLabels"),a=this.dom.measureCharMinor,h=this.dom.measureCharMajor;a&&(s.minorCharHeight=a.clientHeight,s.minorCharWidth=a.clientWidth),h&&(s.majorCharHeight=h.clientHeight,s.majorCharWidth=h.clientWidth);var d=i.parentNode?i.parentNode.offsetHeight:0;switch(d!=s.parentHeight&&(s.parentHeight=d,t+=1),this.getOption("orientation")){case"bottom":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.minorLabelTop=0,s.majorLabelTop=s.minorLabelTop+s.minorLabelHeight,s.minorLineTop=-this.top,s.minorLineHeight=Math.max(this.top+s.majorLabelHeight,0),s.minorLineWidth=1,s.majorLineTop=-this.top,s.majorLineHeight=Math.max(this.top+s.minorLabelHeight+s.majorLabelHeight,0),s.majorLineWidth=1,s.lineTop=0;break;case"top":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.majorLabelTop=0,s.minorLabelTop=s.majorLabelTop+s.majorLabelHeight,s.minorLineTop=s.minorLabelTop,s.minorLineHeight=Math.max(d-s.majorLabelHeight-this.top),s.minorLineWidth=1,s.majorLineTop=0,s.majorLineHeight=Math.max(d-this.top),s.majorLineWidth=1,s.lineTop=s.majorLabelHeight+s.minorLabelHeight;break;default:throw new Error('Unkown orientation "'+this.getOption("orientation")+'"')}var c=s.minorLabelHeight+s.majorLabelHeight;t+=e(this,"width",i.offsetWidth),t+=e(this,"height",c),this._updateConversion();var l=z.convert(n.start,"Number"),u=z.convert(n.end,"Number"),p=this.toTime(5*(s.minorCharWidth||10)).valueOf()-this.toTime(0).valueOf();this.step=new TimeStep(new Date(l),new Date(u),p),t+=e(s.range,"start",l),t+=e(s.range,"end",u),t+=e(s.range,"minimumStep",p.valueOf())}return t>0},g.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},m.prototype=new u,m.prototype.setOptions=u.prototype.setOptions,m.prototype.getContainer=function(){return this.frame},m.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCurrentTime"))return void(t&&(i.removeChild(t),delete this.frame));t||(t=document.createElement("div"),t.className="currenttime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t),this.frame=t),e.conversion||e._updateConversion();var n=new Date,s=e.toScreen(n);t.style.left=s+"px",t.title="Current time: "+n,void 0!==this.currentTimeTimer&&(clearTimeout(this.currentTimeTimer),delete this.currentTimeTimer);var o=this,r=1/e.conversion.scale/2;return 30>r&&(r=30),this.currentTimeTimer=setTimeout(function(){o.repaint()},r),!1},v.prototype=new u,v.prototype.setOptions=u.prototype.setOptions,v.prototype.getContainer=function(){return this.frame},v.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCustomTime"))return void(t&&(i.removeChild(t),delete this.frame));if(!t){t=document.createElement("div"),t.className="customtime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t);var n=document.createElement("div");n.style.position="relative",n.style.top="0px",n.style.left="-10px",n.style.height="100%",n.style.width="20px",t.appendChild(n),this.frame=t,this.subscribe(this,"movetime")}e.conversion||e._updateConversion();var s=e.toScreen(this.customTime);return t.style.left=s+"px",t.title="Time: "+this.customTime,!1},v.prototype._setCustomTime=function(t){this.customTime=new Date(t.valueOf()),this.repaint()},v.prototype._getCustomTime=function(){return new Date(this.customTime.valueOf())},v.prototype.subscribe=function(t,e){var i=this,n={component:t,event:e,callback:function(t){i._onMouseDown(t,n)},params:{}};t.on("mousedown",n.callback),i.listeners.push(n)},v.prototype.on=function(t,e){var i=this.frame;if(!i)throw new Error("Cannot add event listener: no parent attached");F.addListener(this,t,e),z.addEventListener(i,t,e)},v.prototype._onMouseDown=function(t,e){t=t||window.event;var i=e.params,n=t.which?1==t.which:1==t.button;if(n){i.mouseX=z.getPageX(t),i.moved=!1,i.customTime=this.customTime;var s=this;i.onMouseMove||(i.onMouseMove=function(t){s._onMouseMove(t,e)},z.addEventListener(document,"mousemove",i.onMouseMove)),i.onMouseUp||(i.onMouseUp=function(t){s._onMouseUp(t,e)},z.addEventListener(document,"mouseup",i.onMouseUp)),z.stopPropagation(t),z.preventDefault(t)}},v.prototype._onMouseMove=function(t,e){t=t||window.event;var i=e.params,n=this.parent,s=z.getPageX(t);void 0===i.mouseX&&(i.mouseX=s);var o=s-i.mouseX;Math.abs(o)>=1&&(i.moved=!0);var r=n.toScreen(i.customTime),a=r+o,h=n.toTime(a);this._setCustomTime(h),F.trigger(this,"timechange",{customTime:this.customTime}),z.preventDefault(t)},v.prototype._onMouseUp=function(t,e){t=t||window.event;var i=e.params;i.onMouseMove&&(z.removeEventListener(document,"mousemove",i.onMouseMove),i.onMouseMove=null),i.onMouseUp&&(z.removeEventListener(document,"mouseup",i.onMouseUp),i.onMouseUp=null),i.moved&&F.trigger(this,"timechanged",{customTime:this.customTime})},y.prototype=new p,y.types={box:w,range:S,rangeoverflow:E,point:b},y.prototype.setOptions=u.prototype.setOptions,y.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},y.prototype.setSelection=function(t){var e,i,n,s,o;if(t){if(!Array.isArray(t))throw new TypeError("Array expected");for(e=0,i=this.selection.length;i>e;e++)n=this.selection[e],s=this.items[n],s&&s.unselect();for(this.selection=[],e=0,i=t.length;i>e;e++)n=t[e],s=this.items[n],s&&(this.selection.push(n),s.select());o=this.selection.concat([]),F.trigger(this,"select",{ids:o}),this.controller&&this.requestRepaint()}},y.prototype.getSelection=function(){return this.selection.concat([])},y.prototype._deselect=function(t){for(var e=this.selection,i=0,n=e.length;n>i;i++)if(e[i]==t){e.splice(i,1);break}},y.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.defaultOptions,r=this.frame;if(!r){r=document.createElement("div"),r.className="itemset";var a=n.className;a&&z.addClassName(r,z.option.asString(a));var h=document.createElement("div");h.className="background",r.appendChild(h),this.dom.background=h;var d=document.createElement("div");d.className="foreground",r.appendChild(d),this.dom.foreground=d;var c=document.createElement("div");c.className="itemset-axis",this.dom.axis=c,this.frame=r,t+=1}if(!this.parent)throw new Error("Cannot repaint itemset: no parent attached");var l=this.parent.getContainer();if(!l)throw new Error("Cannot repaint itemset: parent has no container element");r.parentNode||(l.appendChild(r),t+=1),this.dom.axis.parentNode||(l.appendChild(this.dom.axis),t+=1),t+=e(r.style,"left",i(n.left,"0px")),t+=e(r.style,"top",i(n.top,"0px")),t+=e(r.style,"width",i(n.width,"100%")),t+=e(r.style,"height",i(n.height,this.height+"px")),t+=e(this.dom.axis.style,"left",i(n.left,"0px")),t+=e(this.dom.axis.style,"width",i(n.width,"100%")),t+="bottom"==s?e(this.dom.axis.style,"top",this.height+this.top+"px"):e(this.dom.axis.style,"top",this.top+"px"),this._updateConversion();var u=this,p=this.queue,f=this.itemsData,g=this.items,m={};for(var v in p)if(p.hasOwnProperty(v)){var _=p[v],w=g[v],b=_.action;switch(b){case"add":case"update":var S=f&&f.get(v,m);if(S){var E=S.type||S.start&&S.end&&"range"||n.type||"box",T=y.types[E];if(w&&(T&&w instanceof T?(w.data=S,t++):(t+=w.hide(),w=null)),!w){if(!T)throw new TypeError('Unknown item type "'+E+'"');w=new T(u,S,n,o),w.id=_.id,t++}w.repaint(),g[v]=w}delete p[v];break;case"remove":w&&(w.selected&&u._deselect(v),t+=w.hide()),delete g[v],delete p[v];break;default:console.log('Error: unknown action "'+b+'"')}}return z.forEach(this.items,function(e){e.visible?(t+=e.show(),e.reposition()):t+=e.hide()}),t>0},y.prototype.getForeground=function(){return this.dom.foreground},y.prototype.getBackground=function(){return this.dom.background},y.prototype.getAxis=function(){return this.dom.axis},y.prototype.reflow=function(){var t=0,e=this.options,i=e.margin&&e.margin.axis||this.defaultOptions.margin.axis,n=e.margin&&e.margin.item||this.defaultOptions.margin.item,s=z.updateProperty,o=z.option.asNumber,r=z.option.asSize,a=this.frame;if(a){this._updateConversion(),z.forEach(this.items,function(e){t+=e.reflow()}),this.stack.update();var h,d=o(e.maxHeight),c=null!=r(e.height);if(c)h=a.offsetHeight;else{var l=this.stack.ordered;if(l.length){var u=l[0].top,p=l[0].top+l[0].height;z.forEach(l,function(t){u=Math.min(u,t.top),p=Math.max(p,t.top+t.height)}),h=p-u+i+n}else h=i+n}null!=d&&(h=Math.min(h,d)),t+=s(this,"height",h),t+=s(this,"top",a.offsetTop),t+=s(this,"left",a.offsetLeft),t+=s(this,"width",a.offsetWidth)}else t+=1;return t>0},y.prototype.hide=function(){var t=!1;return this.frame&&this.frame.parentNode&&(this.frame.parentNode.removeChild(this.frame),t=!0),this.dom.axis&&this.dom.axis.parentNode&&(this.dom.axis.parentNode.removeChild(this.dom.axis),t=!0),t -},y.prototype.setItems=function(t){var e,i=this,n=this.itemsData;if(t){if(!(t instanceof o||t instanceof r))throw new TypeError("Data must be an instance of DataSet");this.itemsData=t}else this.itemsData=null;if(n&&(z.forEach(this.listeners,function(t,e){n.unsubscribe(e,t)}),e=n.getIds(),this._onRemove(e)),this.itemsData){var s=this.id;z.forEach(this.listeners,function(t,e){i.itemsData.subscribe(e,t,s)}),e=this.itemsData.getIds(),this._onAdd(e)}},y.prototype.getItems=function(){return this.itemsData},y.prototype._onUpdate=function(t){this._toQueue("update",t)},y.prototype._onAdd=function(t){this._toQueue("add",t)},y.prototype._onRemove=function(t){this._toQueue("remove",t)},y.prototype._toQueue=function(t,e){var i=this.queue;e.forEach(function(e){i[e]={id:e,action:t}}),this.controller&&this.requestRepaint()},y.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},y.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},y.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},_.prototype.select=function(){this.selected=!0,this.visible&&this.repaint()},_.prototype.unselect=function(){this.selected=!1,this.visible&&this.repaint()},_.prototype.show=function(){return!1},_.prototype.hide=function(){return!1},_.prototype.repaint=function(){return!1},_.prototype.reflow=function(){return!1},_.prototype.getWidth=function(){return this.width},w.prototype=new _(null,null),w.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");if(!e.box.parentNode){var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");i.appendChild(e.box),t=!0}if(!e.line.parentNode){var n=this.parent.getBackground();if(!n)throw new Error("Cannot repaint time axis: parent has no background container element");n.appendChild(e.line),t=!0}if(!e.dot.parentNode){var s=this.parent.getAxis();if(!n)throw new Error("Cannot repaint time axis: parent has no axis container element");s.appendChild(e.dot),t=!0}if(this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var o=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=o&&(this.className=o,e.box.className="item box"+o,e.line.className="item line"+o,e.dot.className="item dot"+o,t=!0)}return t},w.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},w.prototype.hide=function(){var t=!1,e=this.dom;return e&&(e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),e.line.parentNode&&e.line.parentNode.removeChild(e.line),e.dot.parentNode&&e.dot.parentNode.removeChild(e.dot)),t},w.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,d,c,l,u=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(c=this.data,l=this.parent&&this.parent.range,c&&l){var p=l.end-l.start;this.visible=c.start>l.start-p&&c.start0},w.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("DIV"),t.content=document.createElement("DIV"),t.content.className="content",t.box.appendChild(t.content),t.line=document.createElement("DIV"),t.line.className="line",t.dot=document.createElement("DIV"),t.dot.className="dot",t.box["timeline-item"]=this)},w.prototype.reposition=function(){var t=this.dom,e=this.props,i=this.options.orientation||this.defaultOptions.orientation;if(t){var n=t.box,s=t.line,o=t.dot;n.style.left=this.left+"px",n.style.top=this.top+"px",s.style.left=e.line.left+"px","top"==i?(s.style.top="0px",s.style.height=this.top+"px"):(s.style.top=this.top+this.height+"px",s.style.height=Math.max(this.parent.height-this.top-this.height+this.props.dot.height/2,0)+"px"),o.style.left=e.dot.left+"px",o.style.top=e.dot.top+"px"}},b.prototype=new _(null,null),b.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.point.parentNode||(i.appendChild(e.point),i.appendChild(e.point),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.point.className="item point"+n,t=!0)}return t},b.prototype.show=function(){return this.dom&&this.dom.point.parentNode?!1:this.repaint()},b.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.point.parentNode&&(e.point.parentNode.removeChild(e.point),t=!0),t},b.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,d,c=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(h=this.data,d=this.parent&&this.parent.range,h&&d){var l=d.end-d.start;this.visible=h.start>d.start-l&&h.start0},b.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.point=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.point.appendChild(t.content),t.dot=document.createElement("div"),t.dot.className="dot",t.point.appendChild(t.dot),t.point["timeline-item"]=this)},b.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.point.style.top=this.top+"px",t.point.style.left=this.left+"px",t.content.style.marginLeft=e.content.marginLeft+"px",t.dot.style.top=e.dot.top+"px")},S.prototype=new _(null,null),S.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.box.className="item range"+n,t=!0)}return t},S.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},S.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),t},S.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,d,c,l,u,p,f,g,m=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(void 0==this.data.end)throw new Error('Property "end" missing in item '+this.data.id);return h=this.data,d=this.parent&&this.parent.range,this.visible=h&&d?h.startd.start:!1,this.visible&&(t=this.dom,t?(e=this.props,i=this.options,o=this.parent,r=o.toScreen(this.data.start),a=o.toScreen(this.data.end),c=z.updateProperty,l=t.box,u=o.width,f=i.orientation||this.defaultOptions.orientation,n=i.margin&&i.margin.axis||this.defaultOptions.margin.axis,s=i.padding||this.defaultOptions.padding,m+=c(e.content,"width",t.content.offsetWidth),m+=c(this,"height",l.offsetHeight),-u>r&&(r=-u),a>2*u&&(a=2*u),p=0>r?Math.min(-r,a-r-e.content.width-2*s):0,m+=c(e.content,"left",p),"top"==f?(g=n,m+=c(this,"top",g)):(g=o.height-this.height-n,m+=c(this,"top",g)),m+=c(this,"left",r),m+=c(this,"width",Math.max(a-r,1))):m+=1),m>0},S.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content),t.box["timeline-item"]=this)},S.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.box.style.top=this.top+"px",t.box.style.left=this.left+"px",t.box.style.width=this.width+"px",t.content.style.left=e.content.left+"px")},E.prototype=new S(null,null),E.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=this.data.className?" "+this.data.className:"";this.className!=n&&(this.className=n,e.box.className="item rangeoverflow"+n,t=!0)}return t},E.prototype.getWidth=function(){return void 0!==this.props.content&&this.width0},x.prototype=new p,x.prototype.setOptions=u.prototype.setOptions,x.prototype.setRange=function(){},x.prototype.setItems=function(t){this.itemsData=t;for(var e in this.groups)if(this.groups.hasOwnProperty(e)){var i=this.groups[e];i.setItems(t)}},x.prototype.getItems=function(){return this.itemsData},x.prototype.setRange=function(t){this.range=t},x.prototype.setGroups=function(t){var e,i=this;if(this.groupsData&&(z.forEach(this.listeners,function(t,e){i.groupsData.unsubscribe(e,t)}),e=this.groupsData.getIds(),this._onRemove(e)),t?t instanceof o?this.groupsData=t:(this.groupsData=new o({convert:{start:"Date",end:"Date"}}),this.groupsData.add(t)):this.groupsData=null,this.groupsData){var n=this.id;z.forEach(this.listeners,function(t,e){i.groupsData.subscribe(e,t,n)}),e=this.groupsData.getIds(),this._onAdd(e)}},x.prototype.getGroups=function(){return this.groupsData},x.prototype.setSelection=function(t){var e=[],i=this.groups;for(var n in i)if(i.hasOwnProperty(n)){var s=i[n];s.setSelection(t)}return e},x.prototype.getSelection=function(){var t=[],e=this.groups;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];t=t.concat(n.getSelection())}return t},x.prototype.repaint=function(){var t,e,i,n,s=0,o=z.updateProperty,r=z.option.asSize,a=z.option.asElement,h=this.options,d=this.dom.frame,c=this.dom.labels,l=this.dom.labelSet;if(!this.parent)throw new Error("Cannot repaint groupset: no parent attached");var u=this.parent.getContainer();if(!u)throw new Error("Cannot repaint groupset: parent has no container element");if(!d){d=document.createElement("div"),d.className="groupset",this.dom.frame=d;var p=h.className;p&&z.addClassName(d,z.option.asString(p)),s+=1}d.parentNode||(u.appendChild(d),s+=1);var f=a(h.labelContainer);if(!f)throw new Error('Cannot repaint groupset: option "labelContainer" not defined');c||(c=document.createElement("div"),c.className="labels",this.dom.labels=c),l||(l=document.createElement("div"),l.className="label-set",c.appendChild(l),this.dom.labelSet=l),c.parentNode&&c.parentNode==f||(c.parentNode&&c.parentNode.removeChild(c.parentNode),f.appendChild(c)),s+=o(d.style,"height",r(h.height,this.height+"px")),s+=o(d.style,"top",r(h.top,"0px")),s+=o(d.style,"left",r(h.left,"0px")),s+=o(d.style,"width",r(h.width,"100%")),s+=o(l.style,"top",r(h.top,"0px")),s+=o(l.style,"height",r(h.height,this.height+"px"));var g=this,m=this.queue,v=this.groups,y=this.groupsData,_=Object.keys(m);if(_.length){_.forEach(function(t){var e=m[t],i=v[t];switch(e){case"add":case"update":if(!i){var n=Object.create(g.options);z.extend(n,{height:null,maxHeight:null}),i=new T(g,t,n),i.setItems(g.itemsData),v[t]=i,g.controller.add(i)}i.data=y.get(t),delete m[t];break;case"remove":i&&(i.setItems(),delete v[t],g.controller.remove(i)),delete m[t];break;default:console.log('Error: unknown action "'+e+'"')}});var w=this.groupsData.getIds({order:this.options.groupOrder});for(t=0;t0},x.prototype._createLabel=function(t){var e=this.groups[t],i=document.createElement("div");i.className="label";var n=document.createElement("div");n.className="inner",i.appendChild(n);var s=e.data&&e.data.content;s instanceof Element?n.appendChild(s):void 0!=s&&(n.innerHTML=s);var o=e.data&&e.data.className;return o&&z.addClassName(i,o),e.label=i,i},x.prototype.getContainer=function(){return this.dom.frame},x.prototype.getLabelsWidth=function(){return this.props.labels.width},x.prototype.reflow=function(){var t,e,i=0,n=this.options,s=z.updateProperty,o=z.option.asNumber,r=z.option.asSize,a=this.dom.frame;if(a){var h,d=o(n.maxHeight),c=null!=r(n.height);if(c)h=a.offsetHeight;else{h=0;for(t in this.groups)this.groups.hasOwnProperty(t)&&(e=this.groups[t],h+=e.height)}null!=d&&(h=Math.min(h,d)),i+=s(this,"height",h),i+=s(this,"top",a.offsetTop),i+=s(this,"left",a.offsetLeft),i+=s(this,"width",a.offsetWidth)}var l=0;for(t in this.groups)if(this.groups.hasOwnProperty(t)){e=this.groups[t];var u=e.props&&e.props.label&&e.props.label.width||0;l=Math.max(l,u)}return i+=s(this.props.labels,"width",l),i>0},x.prototype.hide=function(){return this.dom.frame&&this.dom.frame.parentNode?(this.dom.frame.parentNode.removeChild(this.dom.frame),!0):!1},x.prototype.show=function(){return this.dom.frame&&this.dom.frame.parentNode?!1:this.repaint()},x.prototype._onUpdate=function(t){this._toQueue(t,"update")},x.prototype._onAdd=function(t){this._toQueue(t,"add")},x.prototype._onRemove=function(t){this._toQueue(t,"remove")},x.prototype._toQueue=function(t,e){var i=this.queue;t.forEach(function(t){i[t]=e}),this.controller&&this.requestRepaint()},C.prototype.setOptions=function(t){z.extend(this.options,t),this.range.setRange(t.start,t.end),this.controller.reflow(),this.controller.repaint()},C.prototype.setCustomTime=function(t){this.customtime._setCustomTime(t)},C.prototype.getCustomTime=function(){return new Date(this.customtime.customTime.valueOf())},C.prototype.setItems=function(t){var e,i=null==this.itemsData;if(t?t instanceof o&&(e=t):e=null,t instanceof o||(e=new o({convert:{start:"Date",end:"Date"}}),e.add(t)),this.itemsData=e,this.content.setItems(e),i&&(void 0==this.options.start||void 0==this.options.end)){var n=this.getItemRange(),s=n.min,r=n.max;if(null!=s&&null!=r){var a=r.valueOf()-s.valueOf();0>=a&&(a=864e5),s=new Date(s.valueOf()-.05*a),r=new Date(r.valueOf()+.05*a)}void 0!=this.options.start&&(s=z.convert(this.options.start,"Date")),void 0!=this.options.end&&(r=z.convert(this.options.end,"Date")),(null!=s||null!=r)&&this.range.setRange(s,r)}},C.prototype.setGroups=function(t){var e=this;this.groupsData=t;var i=this.groupsData?x:y;if(!(this.content instanceof i)){this.content&&(this.content.hide(),this.content.setItems&&this.content.setItems(),this.content.setGroups&&this.content.setGroups(),this.controller.remove(this.content));var n=Object.create(this.options);z.extend(n,{top:function(){return"top"==e.options.orientation?e.timeaxis.height:e.itemPanel.height-e.timeaxis.height-e.content.height},left:null,width:"100%",height:function(){return e.options.height?e.itemPanel.height-e.timeaxis.height:null},maxHeight:function(){if(e.options.maxHeight){if(!z.isNumber(e.options.maxHeight))throw new TypeError("Number expected for property maxHeight");return e.options.maxHeight-e.timeaxis.height}return null},labelContainer:function(){return e.labelPanel.getContainer()}}),this.content=new i(this.itemPanel,[this.timeaxis],n),this.content.setRange&&this.content.setRange(this.range),this.content.setItems&&this.content.setItems(this.itemsData),this.content.setGroups&&this.content.setGroups(this.groupsData),this.controller.add(this.content)}},C.prototype.getItemRange=function(){var t=this.itemsData,e=null,i=null;if(t){var n=t.min("start");e=n?n.start.valueOf():null;var s=t.max("start");s&&(i=s.start.valueOf());var o=t.max("end");o&&(i=null==i?o.end.valueOf():Math.max(i,o.end.valueOf()))}return{min:null!=e?new Date(e):null,max:null!=i?new Date(i):null}},C.prototype.setSelection=function(t){this.content&&this.content.setSelection(t)},C.prototype.getSelection=function(){return this.content?this.content.getSelection():[]},C.prototype.on=function(t,e){var i=["rangechange","rangechanged","select"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());F.addListener(this,t,e)},C.prototype.off=function(t,e){F.removeListener(this,t,e)},C.prototype._trigger=function(t,e){F.trigger(this,t,e||{})},C.prototype._onSelectItem=function(t){var e=this._itemFromTarget(t),i=e?[e.id]:[];this.setSelection(i),this._trigger("select",{items:this.getSelection()}),t.stopPropagation()},C.prototype._onMultiSelectItem=function(t){var e,i=this._itemFromTarget(t);if(i){e=this.getSelection();var n=e.indexOf(i.id);-1==n?e.push(i.id):e.splice(n,1),this.setSelection(e),this._trigger("select",{items:this.getSelection()}),t.stopPropagation()}},C.prototype._itemFromTarget=function(t){for(var e=t.target;e;){if(e.hasOwnProperty("timeline-item"))return e["timeline-item"];e=e.parentNode}return null},function(t){function e(t){return C=t,u()}function i(){M=0,D=C.charAt(0)}function n(){M++,D=C.charAt(M)}function s(){return C.charAt(M+1)}function o(t){return N.test(t)}function r(t,e){if(t||(t={}),e)for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function a(t,e,i){for(var n=e.split("."),s=t;n.length;){var o=n.shift();n.length?(s[o]||(s[o]={}),s=s[o]):s[o]=i}}function h(t,e){for(var i,n,s=null,o=[t],a=t;a.parent;)o.push(a.parent),a=a.parent;if(a.nodes)for(i=0,n=a.nodes.length;n>i;i++)if(e.id===a.nodes[i].id){s=a.nodes[i];break}for(s||(s={id:e.id},t.node&&(s.attr=r(s.attr,t.node))),i=o.length-1;i>=0;i--){var h=o[i];h.nodes||(h.nodes=[]),-1==h.nodes.indexOf(s)&&h.nodes.push(s)}e.attr&&(s.attr=r(s.attr,e.attr))}function d(t,e){if(t.edges||(t.edges=[]),t.edges.push(e),t.edge){var i=r({},t.edge);e.attr=r(i,e.attr)}}function c(t,e,i,n,s){var o={from:e,to:i,type:n};return t.edge&&(o.attr=r({},t.edge)),o.attr=r(o.attr||{},s),o}function l(){for(I=T.NULL,O="";" "==D||" "==D||"\n"==D||"\r"==D;)n();do{var t=!1;if("#"==D){for(var e=M-1;" "==C.charAt(e)||" "==C.charAt(e);)e--;if("\n"==C.charAt(e)||""==C.charAt(e)){for(;""!=D&&"\n"!=D;)n();t=!0}}if("/"==D&&"/"==s()){for(;""!=D&&"\n"!=D;)n();t=!0}if("/"==D&&"*"==s()){for(;""!=D;){if("*"==D&&"/"==s()){n(),n();break}n()}t=!0}for(;" "==D||" "==D||"\n"==D||"\r"==D;)n()}while(t);if(""==D)return void(I=T.DELIMITER);var i=D+s();if(x[i])return I=T.DELIMITER,O=i,n(),void n();if(x[D])return I=T.DELIMITER,O=D,void n();if(o(D)||"-"==D){for(O+=D,n();o(D);)O+=D,n();return"false"==O?O=!1:"true"==O?O=!0:isNaN(Number(O))||(O=Number(O)),void(I=T.IDENTIFIER)}if('"'==D){for(n();""!=D&&('"'!=D||'"'==D&&'"'==s());)O+=D,'"'==D&&n(),n();if('"'!=D)throw w('End of string " expected');return n(),void(I=T.IDENTIFIER)}for(I=T.UNKNOWN;""!=D;)O+=D,n();throw new SyntaxError('Syntax error in part "'+b(O,30)+'"')}function u(){var t={};if(i(),l(),"strict"==O&&(t.strict=!0,l()),("graph"==O||"digraph"==O)&&(t.type=O,l()),I==T.IDENTIFIER&&(t.id=O,l()),"{"!=O)throw w("Angle bracket { expected");if(l(),p(t),"}"!=O)throw w("Angle bracket } expected");if(l(),""!==O)throw w("End of file expected");return l(),delete t.node,delete t.edge,delete t.graph,t}function p(t){for(;""!==O&&"}"!=O;)f(t),";"==O&&l()}function f(t){var e=g(t);if(e)return void y(t,e);var i=m(t);if(!i){if(I!=T.IDENTIFIER)throw w("Identifier expected");var n=O;if(l(),"="==O){if(l(),I!=T.IDENTIFIER)throw w("Identifier expected");t[n]=O,l()}else v(t,n)}}function g(t){var e=null;if("subgraph"==O&&(e={},e.type="subgraph",l(),I==T.IDENTIFIER&&(e.id=O,l())),"{"==O){if(l(),e||(e={}),e.parent=t,e.node=t.node,e.edge=t.edge,e.graph=t.graph,p(e),"}"!=O)throw w("Angle bracket } expected");l(),delete e.node,delete e.edge,delete e.graph,delete e.parent,t.subgraphs||(t.subgraphs=[]),t.subgraphs.push(e)}return e}function m(t){return"node"==O?(l(),t.node=_(),"node"):"edge"==O?(l(),t.edge=_(),"edge"):"graph"==O?(l(),t.graph=_(),"graph"):null}function v(t,e){var i={id:e},n=_();n&&(i.attr=n),h(t,i),y(t,e)}function y(t,e){for(;"->"==O||"--"==O;){var i,n=O;l();var s=g(t);if(s)i=s;else{if(I!=T.IDENTIFIER)throw w("Identifier or subgraph expected");i=O,h(t,{id:i}),l()}var o=_(),r=c(t,e,i,n,o);d(t,r),e=i}}function _(){for(var t=null;"["==O;){for(l(),t={};""!==O&&"]"!=O;){if(I!=T.IDENTIFIER)throw w("Attribute name expected");var e=O;if(l(),"="!=O)throw w("Equal sign = expected");if(l(),I!=T.IDENTIFIER)throw w("Attribute value expected");var i=O;a(t,e,i),l(),","==O&&l()}if("]"!=O)throw w("Bracket ] expected");l()}return t}function w(t){return new SyntaxError(t+', got "'+b(O,30)+'" (char '+M+")")}function b(t,e){return t.length<=e?t:t.substr(0,27)+"..."}function S(t,e,i){t instanceof Array?t.forEach(function(t){e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}):e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}function E(t){function i(t){var e={from:t.from,to:t.to};return r(e,t.attr),e.style="->"==t.type?"arrow":"line",e}var n=e(t),s={nodes:[],edges:[],options:{}};return n.nodes&&n.nodes.forEach(function(t){var e={id:t.id,label:String(t.label||t.id)};r(e,t.attr),e.image&&(e.shape="image"),s.nodes.push(e)}),n.edges&&n.edges.forEach(function(t){var e,n;e=t.from instanceof Object?t.from.nodes:{id:t.from},n=t.to instanceof Object?t.to.nodes:{id:t.to},t.from instanceof Object&&t.from.edges&&t.from.edges.forEach(function(t){var e=i(t);s.edges.push(e)}),S(e,n,function(e,n){var o=c(s,e.id,n.id,t.type,t.attr),r=i(o);s.edges.push(r)}),t.to instanceof Object&&t.to.edges&&t.to.edges.forEach(function(t){var e=i(t);s.edges.push(e)})}),n.attr&&(s.options=n.attr),s}var T={NULL:0,DELIMITER:1,IDENTIFIER:2,UNKNOWN:3},x={"{":!0,"}":!0,"[":!0,"]":!0,";":!0,"=":!0,",":!0,"->":!0,"--":!0},C="",M=0,D="",O="",I=T.NULL,N=/[a-zA-Z_0-9.:#]/;t.parseDOT=e,t.DOTToGraph=E}("undefined"!=typeof z?z:n),"undefined"!=typeof CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.circle=function(t,e,i){this.beginPath(),this.arc(t,e,i,0,2*Math.PI,!1)},CanvasRenderingContext2D.prototype.square=function(t,e,i){this.beginPath(),this.rect(t-i,e-i,2*i,2*i)},CanvasRenderingContext2D.prototype.triangle=function(t,e,i){this.beginPath();var n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e-(r-o)),this.lineTo(t+s,e+o),this.lineTo(t-s,e+o),this.lineTo(t,e-(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.triangleDown=function(t,e,i){this.beginPath();var n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e+(r-o)),this.lineTo(t+s,e-o),this.lineTo(t-s,e-o),this.lineTo(t,e+(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.star=function(t,e,i){this.beginPath();for(var n=0;10>n;n++){var s=n%2===0?1.3*i:.5*i;this.lineTo(t+s*Math.sin(2*n*Math.PI/10),e-s*Math.cos(2*n*Math.PI/10))}this.closePath()},CanvasRenderingContext2D.prototype.roundRect=function(t,e,i,n,s){var o=Math.PI/180;0>i-2*s&&(s=i/2),0>n-2*s&&(s=n/2),this.beginPath(),this.moveTo(t+s,e),this.lineTo(t+i-s,e),this.arc(t+i-s,e+s,s,270*o,360*o,!1),this.lineTo(t+i,e+n-s),this.arc(t+i-s,e+n-s,s,0,90*o,!1),this.lineTo(t+s,e+n),this.arc(t+s,e+n-s,s,90*o,180*o,!1),this.lineTo(t,e+s),this.arc(t+s,e+s,s,180*o,270*o,!1)},CanvasRenderingContext2D.prototype.ellipse=function(t,e,i,n){var s=.5522848,o=i/2*s,r=n/2*s,a=t+i,h=e+n,d=t+i/2,c=e+n/2;this.beginPath(),this.moveTo(t,c),this.bezierCurveTo(t,c-r,d-o,e,d,e),this.bezierCurveTo(d+o,e,a,c-r,a,c),this.bezierCurveTo(a,c+r,d+o,h,d,h),this.bezierCurveTo(d-o,h,t,c+r,t,c)},CanvasRenderingContext2D.prototype.database=function(t,e,i,n){var s=1/3,o=i,r=n*s,a=.5522848,h=o/2*a,d=r/2*a,c=t+o,l=e+r,u=t+o/2,p=e+r/2,f=e+(n-r/2),g=e+n;this.beginPath(),this.moveTo(c,p),this.bezierCurveTo(c,p+d,u+h,l,u,l),this.bezierCurveTo(u-h,l,t,p+d,t,p),this.bezierCurveTo(t,p-d,u-h,e,u,e),this.bezierCurveTo(u+h,e,c,p-d,c,p),this.lineTo(c,f),this.bezierCurveTo(c,f+d,u+h,g,u,g),this.bezierCurveTo(u-h,g,t,f+d,t,f),this.lineTo(t,p)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,n){var s=t-n*Math.cos(i),o=e-n*Math.sin(i),r=t-.9*n*Math.cos(i),a=e-.9*n*Math.sin(i),h=s+n/3*Math.cos(i+.5*Math.PI),d=o+n/3*Math.sin(i+.5*Math.PI),c=s+n/3*Math.cos(i-.5*Math.PI),l=o+n/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,d),this.lineTo(r,a),this.lineTo(c,l),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,n,s){s||(s=[10,5]),0==u&&(u=.001);var o=s.length;this.moveTo(t,e);for(var r=i-t,a=n-e,h=a/r,d=Math.sqrt(r*r+a*a),c=0,l=!0;d>=.1;){var u=s[c++%o];u>d&&(u=d);var p=Math.sqrt(u*u/(1+h*h));0>r&&(p=-p),t+=p,e+=h*p,this[l?"lineTo":"moveTo"](t,e),d-=u,l=!l}}),M.prototype.resetCluster=function(){this.formationScale=void 0,this.clusterSize=1,this.containedNodes={},this.containedEdges={},this.clusterSessions=[]},M.prototype.attachEdge=function(t){-1==this.edges.indexOf(t)&&this.edges.push(t),-1==this.dynamicEdges.indexOf(t)&&this.dynamicEdges.push(t),this.dynamicEdgesLength=this.dynamicEdges.length,this._updateMass()},M.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&(this.edges.splice(e,1),this.dynamicEdges.splice(e,1)),this.dynamicEdgesLength=this.dynamicEdges.length,this._updateMass()},M.prototype._updateMass=function(){this.mass=1+.6*this.edges.length},M.prototype.setProperties=function(t,e){if(t){if(this.originalLabel=void 0,void 0!==t.id&&(this.id=t.id),void 0!==t.label&&(this.label=t.label,this.originalLabel=t.label),void 0!==t.title&&(this.title=t.title),void 0!==t.group&&(this.group=t.group),void 0!==t.x&&(this.x=t.x),void 0!==t.y&&(this.y=t.y),void 0!==t.value&&(this.value=t.value),void 0!==t.horizontalAlignLeft&&(this.horizontalAlignLeft=t.horizontalAlignLeft),void 0!==t.verticalAlignTop&&(this.verticalAlignTop=t.verticalAlignTop),void 0!==t.triggerFunction&&(this.triggerFunction=t.triggerFunction),void 0===this.id)throw"Node must have an id";if(this.group){var i=this.grouplist.get(this.group);for(var n in i)i.hasOwnProperty(n)&&(this[n]=i[n])}if(void 0!==t.shape&&(this.shape=t.shape),void 0!==t.image&&(this.image=t.image),void 0!==t.radius&&(this.radius=t.radius),void 0!==t.color&&(this.color=M.parseColor(t.color)),void 0!==t.fontColor&&(this.fontColor=t.fontColor),void 0!==t.fontSize&&(this.fontSize=t.fontSize),void 0!==t.fontFace&&(this.fontFace=t.fontFace),void 0!==this.image){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.image)}switch(this.xFixed=this.xFixed||void 0!==t.x&&t.fixed,this.yFixed=this.yFixed||void 0!==t.y&&t.fixed,this.radiusFixed=this.radiusFixed||void 0!==t.radius,"image"==this.shape&&(this.radiusMin=e.nodes.widthMin,this.radiusMax=e.nodes.widthMax),this.shape){case"database":this.draw=this._drawDatabase,this.resize=this._resizeDatabase;break;case"box":this.draw=this._drawBox,this.resize=this._resizeBox;break;case"circle":this.draw=this._drawCircle,this.resize=this._resizeCircle;break;case"ellipse":this.draw=this._drawEllipse,this.resize=this._resizeEllipse;break;case"image":this.draw=this._drawImage,this.resize=this._resizeImage;break;case"text":this.draw=this._drawText,this.resize=this._resizeText;break;case"dot":this.draw=this._drawDot,this.resize=this._resizeShape;break;case"square":this.draw=this._drawSquare,this.resize=this._resizeShape;break;case"triangle":this.draw=this._drawTriangle,this.resize=this._resizeShape;break;case"triangleDown":this.draw=this._drawTriangleDown,this.resize=this._resizeShape;break;case"star":this.draw=this._drawStar,this.resize=this._resizeShape;break;default:this.draw=this._drawEllipse,this.resize=this._resizeEllipse}this._reset()}},M.parseColor=function(t){var e;return z.isString(t)?e={border:t,background:t,highlight:{border:t,background:t}}:(e={},e.background=t.background||"white",e.border=t.border||e.background,z.isString(t.highlight)?e.highlight={border:t.highlight,background:t.highlight}:(e.highlight={},e.highlight.background=t.highlight&&t.highlight.background||e.background,e.highlight.border=t.highlight&&t.highlight.border||e.border)),e},M.prototype.select=function(){this.selected=!0,this._reset()},M.prototype.unselect=function(){this.selected=!1,this._reset()},M.prototype.clearSizeCache=function(){this._reset()},M.prototype._reset=function(){this.width=void 0,this.height=void 0},M.prototype.getTitle=function(){return this.title},M.prototype.distanceToBorder=function(t,e){var i=1;switch(this.width||this.resize(t),this.shape){case"circle":case"dot":return this.radius+i;case"ellipse":var n=this.width/2,s=this.height/2,o=Math.sin(e)*n,r=Math.cos(e)*s; -return n*s/Math.sqrt(o*o+r*r);case"box":case"image":case"text":default:return this.width?Math.min(Math.abs(this.width/2/Math.cos(e)),Math.abs(this.height/2/Math.sin(e)))+i:0}},M.prototype._setForce=function(t,e){this.fx=t,this.fy=e},M.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},M.prototype.discreteStep=function(t){if(!this.xFixed){var e=-this.damping*this.vx,i=(this.fx+e)/this.mass;this.vx+=i*t,this.x+=this.vx*t}if(!this.yFixed){var n=-this.damping*this.vy,s=(this.fy+n)/this.mass;this.vy+=s*t,this.y+=this.vy*t}},M.prototype.isFixed=function(){return this.xFixed&&this.yFixed},M.prototype.isMoving=function(t){return Math.abs(this.vx)>t||Math.abs(this.vy)>t?!0:(this.vx=0,this.vy=0,!1)},M.prototype.isSelected=function(){return this.selected},M.prototype.getValue=function(){return this.value},M.prototype.getDistance=function(t,e){var i=this.x-t,n=this.y-e;return Math.sqrt(i*i+n*n)},M.prototype.setValueRange=function(t,e){if(!this.radiusFixed&&void 0!==this.value)if(e==t)this.radius=(this.radiusMin+this.radiusMax)/2;else{var i=(this.radiusMax-this.radiusMin)/(e-t);this.radius=(this.value-t)*i+this.radiusMin}this.baseRadiusValue=this.radius},M.prototype.draw=function(){throw"Draw method not initialized for node"},M.prototype.resize=function(){throw"Resize method not initialized for node"},M.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},M.prototype._resizeImage=function(){if(!this.width||!this.height){var t,e;if(this.value){this.radius=this.baseRadiusValue;var i=this.imageObj.height/this.imageObj.width;void 0!==i?(t=this.radius||this.imageObj.width,e=this.radius*i||this.imageObj.height):(t=0,e=0)}else t=this.imageObj.width,e=this.imageObj.height;this.width=t,this.height=e,this.width>0&&this.height>0&&(this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor)}},M.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e;if(0!=this.imageObj.width){if(this.clusterSize>1){var i=this.clusterSize>1?10:0;i*=this.graphScaleInv,i=Math.min(.2*this.width,i),t.globalAlpha=.5,t.drawImage(this.imageObj,this.left-i,this.top-i,this.width+2*i,this.height+2*i)}t.globalAlpha=1,t.drawImage(this.imageObj,this.left,this.top,this.width,this.height),e=this.y+this.height/2}else e=this.y;this._label(t,this.label,this.x,e,void 0,"top")},M.prototype._resizeBox=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=.5*(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=.5*(this.clusterSize-1)*this.clusterSizeHeightFactor}},M.prototype._drawBox=function(t){this._resizeBox(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.roundRect(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth,this.radius),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.roundRect(this.left,this.top,this.width,this.height,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeDatabase=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=i.width+2*e;this.width=n,this.height=n,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawDatabase=function(t){this._resizeDatabase(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.database(this.x-this.width/2-2*t.lineWidth,this.y-.5*this.height-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.database(this.x-this.width/2,this.y-.5*this.height,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=Math.max(i.width,i.height)+2*e;this.radius=n/2,this.width=n,this.height=n,this.radius+=.5*(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawCircle=function(t){this._resizeCircle(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.circle(this.x,this.y,this.radius+2*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.circle(this.x,this.y,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeEllipse=function(t){if(!this.width){var e=this.getTextSize(t);this.width=1.5*e.width,this.height=2*e.height,this.width1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.ellipse(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.ellipse(this.left,this.top,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._drawDot=function(t){this._drawShape(t,"circle")},M.prototype._drawTriangle=function(t){this._drawShape(t,"triangle")},M.prototype._drawTriangleDown=function(t){this._drawShape(t,"triangleDown")},M.prototype._drawSquare=function(t){this._drawShape(t,"square")},M.prototype._drawStar=function(t){this._drawShape(t,"star")},M.prototype._resizeShape=function(){if(!this.width){this.radius=this.baseRadiusValue;var t=2*this.radius;this.width=t,this.height=t,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=.5*(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawShape=function(t,e){this._resizeShape(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var i=2.5,n=2,s=2;switch(e){case"dot":s=2;break;case"square":s=2;break;case"triangle":s=3;break;case"triangleDown":s=3;break;case"star":s=4}t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?n:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t[e](this.x,this.y,this.radius+s*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?n:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t[e](this.x,this.y,this.radius),t.fill(),t.stroke(),this.label&&this._label(t,this.label,this.x,this.y+this.height/2,void 0,"top")},M.prototype._resizeText=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawText=function(t){this._resizeText(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,this._label(t,this.label,this.x,this.y)},M.prototype._label=function(t,e,i,n,s,o){if(e){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle=this.fontColor||"black",t.textAlign=s||"center",t.textBaseline=o||"middle";for(var r=e.split("\n"),a=r.length,h=this.fontSize+4,d=n+(1-a)/2*h,c=0;a>c;c++)t.fillText(r[c],i,d),d+=h}},M.prototype.getTextSize=function(t){if(void 0!==this.label){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace;for(var e=this.label.split("\n"),i=(this.fontSize+4)*e.length,n=0,s=0,o=e.length;o>s;s++)n=Math.max(n,t.measureText(e[s]).width);return{width:n,height:i}}return{width:0,height:0}},M.prototype.inArea=function(){return void 0!==this.width?this.x+this.width*this.graphScaleInv>=this.canvasTopLeft.x&&this.x-this.width*this.graphScaleInv=this.canvasTopLeft.y&&this.y-this.height*this.graphScaleInv=this.canvasTopLeft.x&&this.x=this.canvasTopLeft.y&&this.yh},D.prototype._drawLine=function(t){t.strokeStyle=this.color,t.lineWidth=this._getLineWidth();var e;if(this.from!=this.to)this._line(t),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y));else{var i,n,s=this.length/4,o=this.from;o.width||o.resize(t),o.width>o.height?(i=o.x+o.width/2,n=o.y-s):(i=o.x+s,n=o.y-o.height/2),this._circle(t,i,n,s),e=this._pointOnCircle(i,n,s,.5),this._label(t,this.label,e.x,e.y)}},D.prototype._getLineWidth=function(){return 1==this.selected?Math.min(2*this.width,this.widthMax)*this.graphScaleInv:this.width*this.graphScaleInv},D.prototype._line=function(t){t.beginPath(),t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y),t.stroke()},D.prototype._circle=function(t,e,i,n){t.beginPath(),t.arc(e,i,n,0,2*Math.PI,!1),t.stroke()},D.prototype._label=function(t,e,i,n){if(e){t.font=(this.from.selected||this.to.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle="white";var s=t.measureText(e).width,o=this.fontSize,r=i-s/2,a=n-o/2;t.fillRect(r,a,s,o),t.fillStyle=this.fontColor||"black",t.textAlign="left",t.textBaseline="top",t.fillText(e,r,a)}},D.prototype._drawDashLine=function(t){if(t.strokeStyle=this.color,t.lineWidth=this._getLineWidth(),t.beginPath(),t.lineCap="round",void 0!==this.dash.altLength?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]):void 0!==this.dash.length&&void 0!==this.dash.gap?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap]):(t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y)),t.stroke(),this.label){var e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}},D.prototype._pointOnLine=function(t){return{x:(1-t)*this.from.x+t*this.to.x,y:(1-t)*this.from.y+t*this.to.y}},D.prototype._pointOnCircle=function(t,e,i,n){var s=2*(n-3/8)*Math.PI;return{x:t+i*Math.cos(s),y:e-i*Math.sin(s)}},D.prototype._drawArrowCenter=function(t){var e;if(t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth(),this.from!=this.to){this._line(t);var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),n=10+5*this.width;e=this._pointOnLine(.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y))}else{var s,o,r=this.length/4,a=this.from;a.width||a.resize(t),a.width>a.height?(s=a.x+a.width/2,o=a.y-r):(s=a.x+r,o=a.y-a.height/2),this._circle(t,s,o,r);var i=.2*Math.PI,n=10+5*this.width;e=this._pointOnCircle(s,o,r,.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(s,o,r,.5),this._label(t,this.label,e.x,e.y))}},D.prototype._drawArrow=function(t){t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth();var e,i;if(this.from!=this.to){e=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x);var n=this.to.x-this.from.x,s=this.to.y-this.from.y,o=Math.sqrt(n*n+s*s),r=this.from.distanceToBorder(t,e+Math.PI),a=(o-r)/o,h=a*this.from.x+(1-a)*this.to.x,d=a*this.from.y+(1-a)*this.to.y,c=this.to.distanceToBorder(t,e),l=(o-c)/o,u=(1-l)*this.from.x+l*this.to.x,p=(1-l)*this.from.y+l*this.to.y;if(t.beginPath(),t.moveTo(h,d),t.lineTo(u,p),t.stroke(),i=10+5*this.width,t.arrow(u,p,e,i),t.fill(),t.stroke(),this.label){var f=this._pointOnLine(.5);this._label(t,this.label,f.x,f.y)}}else{var g,m,v,y=this.from,_=this.length/4;y.width||y.resize(t),y.width>y.height?(g=y.x+y.width/2,m=y.y-_,v={x:g,y:y.y,angle:.9*Math.PI}):(g=y.x+_,m=y.y-y.height/2,v={x:y.x,y:m,angle:.6*Math.PI}),t.beginPath(),t.arc(g,m,_,0,2*Math.PI,!1),t.stroke(),i=10+5*this.width,t.arrow(v.x,v.y,v.angle,i),t.fill(),t.stroke(),this.label&&(f=this._pointOnCircle(g,m,_,.5),this._label(t,this.label,f.x,f.y))}},D._dist=function(t,e,i,n,s,o){var r=i-t,a=n-e,h=r*r+a*a,d=((s-t)*r+(o-e)*a)/h;d>1?d=1:0>d&&(d=0);var c=t+d*r,l=e+d*a,u=c-s,p=l-o;return Math.sqrt(u*u+p*p)},D.prototype.setScale=function(t){this.graphScaleInv=1/t},D.prototype.select=function(){this.selected=!0},D.prototype.unselect=function(){this.selected=!1},O.prototype.setPosition=function(t,e){this.x=parseInt(t),this.y=parseInt(e)},O.prototype.setText=function(t){this.frame.innerHTML=t},O.prototype.show=function(t){if(void 0===t&&(t=!0),t){var e=this.frame.clientHeight,i=this.frame.clientWidth,n=this.frame.parentNode.clientHeight,s=this.frame.parentNode.clientWidth,o=this.y-e;o+e+this.padding>n&&(o=n-e-this.padding),os&&(r=s-i-this.padding),rAdd Node
    Connect Node
    Delete selected";var t=document.getElementById("manipulate-addNode");t.onclick=this._createAddToolbar.bind(this);var e=document.getElementById("manipulate-connectNode");e.onclick=this._createConnectToolbar.bind(this);var i=document.getElementById("manipulate-delete");i.onclick=this._deleteSelected.bind(this)},_createAddToolbar:function(){for(;this.manipulationDiv.hasChildNodes();)this.manipulationDiv.removeChild(this.manipulationDiv.firstChild);this.manipulationDiv.innerHTML="Back
    Click in an empty space to place a new node";var t=document.getElementById("manipulate-back");t.onclick=this._createManipulatorBar.bind(this);var e=this;F.addListener(e,"select",e._addNode.bind(e))},_createConnectToolbar:function(){for(;this.manipulationDiv.hasChildNodes();)this.manipulationDiv.removeChild(this.manipulationDiv.firstChild);var t="hello";this._selectionIsEmpty()||(t="Select the node you want to connect to other nodes"),this.manipulationDiv.innerHTML="Back
    "+t+"";var e=document.getElementById("manipulate-back");e.onclick=this._createManipulatorBar.bind(this);var i=this;F.addListener(i,"select",function(){alert(i.selectForConnect)})},_continueConnect:function(){if(this._clusterInSelection())return this._unselectAll(),this._createConnectToolbar("Select the node you want to connect (Clusters are not allowed)."),!0;if(this._selectionIsEmpty()){{document.getElementById.manipolatorLabel}return!1}return this._connectNodes(),!0},_addNode:function(t){if(console.log("HERE",this),this._selectionIsEmpty()){var e=this._pointerToPositionObject(t);this.nodesData.add({id:z.randomUUID(),x:e.left,y:e.top,label:"new",fixed:!1}),this.moving=!0,this.start()}},_connectNodes:function(){console.log(this.selectionObj)},_deleteSelected:function(){if(this._clusterInSelection())alert("Clusters cannot be deleted.");else{var t=this.getSelectedNodes(),e=this.getSelectedEdges();this._removeEdges(e),this._removeNodes(t),this._redraw()}}},R={_putDataInSector:function(){this.sectors.active[this._sector()].nodes=this.nodes,this.sectors.active[this._sector()].edges=this.edges,this.sectors.active[this._sector()].nodeIndices=this.nodeIndices},_switchToSector:function(t,e){void 0===e||"active"==e?this._switchToActiveSector(t):this._switchToFrozenSector(t)},_switchToActiveSector:function(t){this.nodeIndices=this.sectors.active[t].nodeIndices,this.nodes=this.sectors.active[t].nodes,this.edges=this.sectors.active[t].edges},_switchToFrozenSector:function(t){this.nodeIndices=this.sectors.frozen[t].nodeIndices,this.nodes=this.sectors.frozen[t].nodes,this.edges=this.sectors.frozen[t].edges},_switchToNavigationSector:function(){this.nodeIndices=this.sectors.navigation.nodeIndices,this.nodes=this.sectors.navigation.nodes,this.edges=this.sectors.navigation.edges},_loadLatestSector:function(){this._switchToSector(this._sector())},_sector:function(){return this.activeSector[this.activeSector.length-1]},_previousSector:function(){if(this.activeSector.length>1)return this.activeSector[this.activeSector.length-2];throw new TypeError("there are not enough sectors in the this.activeSector array.")},_setActiveSector:function(t){this.activeSector.push(t)},_forgetLastSector:function(){this.activeSector.pop()},_createNewSector:function(t){this.sectors.active[t]={nodes:{},edges:{},nodeIndices:[],formationScale:this.scale,drawingNode:void 0},this.sectors.active[t].drawingNode=new M({id:t,color:{background:"#eaefef",border:"495c5e"}},{},{},this.constants),this.sectors.active[t].drawingNode.clusterSize=2},_deleteActiveSector:function(t){delete this.sectors.active[t]},_deleteFrozenSector:function(t){delete this.sectors.frozen[t]},_freezeSector:function(t){this.sectors.frozen[t]=this.sectors.active[t],this._deleteActiveSector(t)},_activateSector:function(t){this.sectors.active[t]=this.sectors.frozen[t],this._deleteFrozenSector(t)},_mergeThisWithFrozen:function(t){for(var e in this.nodes)this.nodes.hasOwnProperty(e)&&(this.sectors.frozen[t].nodes[e]=this.nodes[e]);for(var i in this.edges)this.edges.hasOwnProperty(i)&&(this.sectors.frozen[t].edges[i]=this.edges[i]);for(var n=0;n1?this[t](n[0],n[1]):this[t](e)}this._loadLatestSector()},_doInAllFrozenSectors:function(t,e){if(void 0===e)for(var i in this.sectors.frozen)this.sectors.frozen.hasOwnProperty(i)&&(this._switchToFrozenSector(i),this[t]());else for(var i in this.sectors.frozen)if(this.sectors.frozen.hasOwnProperty(i)){this._switchToFrozenSector(i);var n=Array.prototype.splice.call(arguments,1);n.length>1?this[t](n[0],n[1]):this[t](e)}this._loadLatestSector()},_doInNavigationSector:function(t,e){if(this._switchToNavigationSector(),void 0===e)this[t]();else{var i=Array.prototype.splice.call(arguments,1);i.length>1?this[t](i[0],i[1]):this[t](e)}this._loadLatestSector()},_doInAllSectors:function(t,e){var i=Array.prototype.splice.call(arguments,1);void 0===e?(this._doInAllActiveSectors(t),this._doInAllFrozenSectors(t)):i.length>1?(this._doInAllActiveSectors(t,i[0],i[1]),this._doInAllFrozenSectors(t,i[0],i[1])):(this._doInAllActiveSectors(t,e),this._doInAllFrozenSectors(t,e))},_clearNodeIndexList:function(){var t=this._sector();this.sectors.active[t].nodeIndices=[],this.nodeIndices=this.sectors.active[t].nodeIndices},_drawSectorNodes:function(t,e){var i,n=1e9,s=-1e9,o=1e9,r=-1e9;for(var a in this.sectors[e])if(this.sectors[e].hasOwnProperty(a)&&void 0!==this.sectors[e][a].drawingNode){this._switchToSector(a,e),n=1e9,s=-1e9,o=1e9,r=-1e9;for(var h in this.nodes)this.nodes.hasOwnProperty(h)&&(i=this.nodes[h],i.resize(t),o>i.x-.5*i.width&&(o=i.x-.5*i.width),ri.y-.5*i.height&&(n=i.y-.5*i.height),st&&n>s;)s%3==0?this.forceAggregateHubs():this.increaseClusterLevel(),i=this.nodeIndices.length,s+=1;s>1&&1==e&&this.repositionNodes()},openCluster:function(t){var e=this.moving;if(t.clusterSize>this.constants.clustering.sectorThreshold&&this._nodeInActiveArea(t)&&("default"!=this._sector()||1!=this.nodeIndices.length)){this._addSector(t);for(var i=0;this.nodeIndices.lengthi;)this.decreaseClusterLevel(),i+=1}else this._expandClusterNode(t,!1,!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels();this.moving!=e&&this.start()},updateClustersDefault:function(){1==this.constants.clustering.enabled&&this.updateClusters(0,!1,!1)},increaseClusterLevel:function(){this.updateClusters(-1,!1,!0)},decreaseClusterLevel:function(){this.updateClusters(1,!1,!0)},updateClusters:function(t,e,i){var n=this.moving,s=this.nodeIndices.length;this.previousScale>this.scale&&0==t&&this._collapseSector(),this.previousScale>this.scale||-1==t?this._formClusters(i):(this.previousScalethis.scale||-1==t)&&(this._aggregateHubs(i),this._updateNodeIndexList()),(this.previousScale>this.scale||-1==t)&&(this.handleChains(),this._updateNodeIndexList()),this.previousScale=this.scale,this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.lengththis.constants.clustering.chainThreshold&&this._reduceAmountOfChains(1-this.constants.clustering.chainThreshold/t)},_aggregateHubs:function(t){this._getHubSize(),this._formClustersByHub(t,!1)},forceAggregateHubs:function(){var t=this.moving,e=this.nodeIndices.length;this._aggregateHubs(!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.length!=e&&(this.clusterSession+=1),this.moving!=t&&this.start()},_openClustersBySize:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];1==e.inView()&&(e.width*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientWidth||e.height*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientHeight)&&this.openCluster(e)}},_openClusters:function(t,e){for(var i=0;i1&&(t.clusterSizei)){var r=o.from,a=o.to; -o.to.mass>o.from.mass&&(r=o.to,a=o.from),1==a.dynamicEdgesLength?this._addToCluster(r,a,!1):1==r.dynamicEdgesLength&&this._addToCluster(a,r,!1)}}},_forceClustersByZoom:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];if(1==e.dynamicEdgesLength&&0!=e.dynamicEdges.length){var i=e.dynamicEdges[0],n=i.toId==e.id?this.nodes[i.fromId]:this.nodes[i.toId];e.id!=n.id&&(n.mass>e.mass?this._addToCluster(n,e,!0):this._addToCluster(e,n,!0))}}},_formClustersByHub:function(t,e){for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&this._formClusterFromHub(this.nodes[i],t,e)},_formClusterFromHub:function(t,e,i,n){if(void 0===n&&(n=0),t.dynamicEdgesLength>=this.hubThreshold&&0==i||t.dynamicEdgesLength==this.hubThreshold&&1==i){for(var s,o,r,a=this.constants.clustering.clusterEdgeThreshold/this.scale,h=!1,d=[],c=t.dynamicEdges.length,l=0;c>l;l++)d.push(t.dynamicEdges[l].id);if(0==e)for(h=!1,l=0;c>l;l++){var u=this.edges[d[l]];if(void 0!==u&&u.connected&&u.toId!=u.fromId&&(s=u.to.x-u.from.x,o=u.to.y-u.from.y,r=Math.sqrt(s*s+o*o),a>r)){h=!0;break}}if(!e&&h||e)for(l=0;c>l;l++)if(u=this.edges[d[l]],void 0!==u){var p=this.nodes[u.fromId==t.id?u.toId:u.fromId];p.dynamicEdges.length<=this.hubThreshold+n&&p.id!=t.id&&this._addToCluster(t,p,e)}}},_addToCluster:function(t,e,i){t.containedNodes[e.id]=e;for(var n=0;n1)for(var n=0;n1&&(e.label="[".concat(String(e.clusterSize),"]"))}for(t in this.nodes)this.nodes.hasOwnProperty(t)&&(e=this.nodes[t],1==e.clusterSize&&(e.label=void 0!==e.originalLabel?e.originalLabel:String(e.id)))},_nodeInActiveArea:function(t){return Math.abs(t.x-this.areaCenter.x)<=this.constants.clustering.activeAreaBoxSize/this.scale&&Math.abs(t.y-this.areaCenter.y)<=this.constants.clustering.activeAreaBoxSize/this.scale},repositionNodes:function(){for(var t=0;tn&&(n=o.dynamicEdgesLength),t+=o.dynamicEdgesLength,e+=Math.pow(o.dynamicEdgesLength,2),i+=1}t/=i,e/=i;var r=e-Math.pow(t,2),a=Math.sqrt(r);this.hubThreshold=Math.floor(t+2*a),this.hubThreshold>n&&(this.hubThreshold=n)},_reduceAmountOfChains:function(t){this.hubThreshold=2;var e=Math.floor(this.nodeIndices.length*t);for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&e>0&&(this._formClusterFromHub(this.nodes[i],!0,!0,1),e-=1)},_getChainFraction:function(){var t=0,e=0;for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&(2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&(t+=1),e+=1);return t/e}},j={_getNodesOverlappingWith:function(t,e){var i=this.nodes;for(var n in i)i.hasOwnProperty(n)&&i[n].isOverlappingWith(t)&&e.push(n)},_getAllNodesOverlappingWith:function(t){var e=[];return this._doInAllActiveSectors("_getNodesOverlappingWith",t,e),e},_getAllNavigationNodesOverlappingWith:function(t){var e=[];return this._doInNavigationSector("_getNodesOverlappingWith",t,e),e},_pointerToPositionObject:function(t){var e=this._canvasToX(t.x),i=this._canvasToY(t.y);return{left:e,top:i,right:e,bottom:i}},_pointerToScreenPositionObject:function(t){var e=t.x,i=t.y;return{left:e,top:i,right:e,bottom:i}},_getNavigationNodeAt:function(t){var e=this._pointerToScreenPositionObject(t),i=this._getAllNavigationNodesOverlappingWith(e);return i.length>0?this.sectors.navigation.nodes[i[i.length-1]]:null},_getNodeAt:function(t){var e=this._pointerToPositionObject(t),i=this._getAllNodesOverlappingWith(e);return i.length>0?this.nodes[i[i.length-1]]:null},_getEdgesOverlappingWith:function(t,e){var i=this.edges;for(var n in i)i.hasOwnProperty(n)&&i[n].isOverlappingWith(t)&&e.push(n)},_getAllEdgesOverlappingWith:function(t){var e=[];return this._doInAllActiveSectors("_getEdgesOverlappingWith",t,e),e},_getEdgeAt:function(t){var e=this._pointerToPositionObject(t),i=this._getAllEdgesOverlappingWith(e);return i.length>0?this.edges[i[i.length-1]]:null},_addToSelection:function(t){this.selectionObj[t.id]=t},_removeFromSelection:function(t){delete this.selectionObj[t.id]},_unselectAll:function(t){void 0===t&&(t=!1);for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e].unselect();this.selectionObj={},0==t&&this._trigger("select",{nodes:this.getSelection()})},_selectionIsEmpty:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t))return!1;return!0},_clusterInSelection:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t)&&this.selectionObj[t]instanceof M&&this.selectionObj[t].clusterSize>1)return!0;return!1},_selectConnectedEdges:function(t){for(var e=0;ee;e++){n=t[e];var s=this.nodes[n];if(!s)throw new RangeError('Node with id "'+n+'" not found');this._selectObject(s,!0,!0)}this.redraw()},_updateSelection:function(){for(var t in this.selectionObj)this.selectionObj.hasOwnProperty(t)&&(this.selectionObj[t]instanceof M?this.nodes.hasOwnProperty(t)||delete this.selectionObj[t]:(this.edges.hasOwnProperty(t)||delete this.selectionObj[t],changed=!0),this.selection=[]);return!changed||1!=triggerSelect&&void 0!=triggerSelect||this._trigger("select",{nodes:this.getSelection()}),changed}},U={_relocateNavigation:function(){if(void 0!==this.sectors){var t=this.navigationClientWidth-this.frame.canvas.clientWidth,e=this.navigationClientHeight-this.frame.canvas.clientHeight;this.navigationClientWidth=this.frame.canvas.clientWidth,this.navigationClientHeight=this.frame.canvas.clientHeight;var i=null;for(var n in this.sectors.navigation.nodes)this.sectors.navigation.nodes.hasOwnProperty(n)&&(i=this.sectors.navigation.nodes[n],i.horizontalAlignLeft||(i.x-=t),i.verticalAlignTop||(i.y-=e))}},_loadNavigationElements:function(){var t=this.constants.navigation.iconPath;this.navigationClientWidth=this.frame.canvas.clientWidth,this.navigationClientHeight=this.frame.canvas.clientHeight,void 0===this.navigationClientWidth&&(this.navigationClientWidth=0,this.navigationClientHeight=0);for(var e=15,i=7,n=[{id:"navigation_up",shape:"image",image:t+"/uparrow.png",triggerFunction:"_moveUp",verticalAlignTop:!1,x:45+e+i,y:this.navigationClientHeight-45-e-i},{id:"navigation_down",shape:"image",image:t+"/downarrow.png",triggerFunction:"_moveDown",verticalAlignTop:!1,x:45+e+i,y:this.navigationClientHeight-15-e},{id:"navigation_left",shape:"image",image:t+"/leftarrow.png",triggerFunction:"_moveLeft",verticalAlignTop:!1,x:15+e,y:this.navigationClientHeight-15-e},{id:"navigation_right",shape:"image",image:t+"/rightarrow.png",triggerFunction:"_moveRight",verticalAlignTop:!1,x:75+e+2*i,y:this.navigationClientHeight-15-e},{id:"navigation_plus",shape:"image",image:t+"/plus.png",triggerFunction:"_zoomIn",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-45-e-i,y:this.navigationClientHeight-15-e},{id:"navigation_min",shape:"image",image:t+"/minus.png",triggerFunction:"_zoomOut",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-15-e,y:this.navigationClientHeight-15-e},{id:"navigation_zoomExtends",shape:"image",image:t+"/zoomExtends.png",triggerFunction:"zoomToFit",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-15-e,y:this.navigationClientHeight-45-e-i}],s=null,o=0;ot.x-t.width&&(n=t.x-t.width),st.y-t.height&&(e=t.y-t.height),i=this.constants.clustering.initialMaxNodes)var n=38.8467/(e-14.50184)+.0116;else var n=42.54117319/(e+39.31966387)+.1944405;else{var s=1.1*(Math.abs(i.minX)+Math.abs(i.maxX)),o=1.1*(Math.abs(i.minY)+Math.abs(i.maxY)),r=this.frame.canvas.clientWidth/s,a=this.frame.canvas.clientHeight/o;n=a>=r?r:a}n>1&&(n=1),this.pinch.mousewheelScale=n,this._setScale(n),this._centerGraph(i),this.start()},I.prototype._updateNodeIndexList=function(){this._clearNodeIndexList();for(var t in this.nodes)this.nodes.hasOwnProperty(t)&&this.nodeIndices.push(t)},I.prototype.setData=function(t,e){if(void 0===e&&(e=!1),t&&t.dot&&(t.nodes||t.edges))throw new SyntaxError('Data must contain either parameter "dot" or parameter pair "nodes" and "edges", but not both.');if(this.setOptions(t&&t.options),t&&t.dot){if(t&&t.dot){var i=V.util.DOTToGraph(t.dot);return void this.setData(i)}}else this._setNodes(t&&t.nodes),this._setEdges(t&&t.edges);this._putDataInSector(),e||(this.stabilize&&this._doStabilize(),this.moving=!0,this.start())},I.prototype.setOptions=function(t){if(t){if(void 0!==t.width&&(this.width=t.width),void 0!==t.height&&(this.height=t.height),void 0!==t.stabilize&&(this.stabilize=t.stabilize),void 0!==t.selectable&&(this.selectable=t.selectable),t.clustering){this.constants.clustering.enabled=!0;for(var e in t.clustering)t.clustering.hasOwnProperty(e)&&(this.constants.clustering[e]=t.clustering[e])}else void 0!==t.clustering&&(this.constants.clustering.enabled=!1);if(t.navigation){this.constants.navigation.enabled=!0;for(var e in t.navigation)t.navigation.hasOwnProperty(e)&&(this.constants.navigation[e]=t.navigation[e])}else void 0!==t.navigation&&(this.constants.navigation.enabled=!1);if(t.keyboard){this.constants.keyboard.enabled=!0;for(var e in t.keyboard)t.keyboard.hasOwnProperty(e)&&(this.constants.keyboard[e]=t.keyboard[e])}else void 0!==t.keyboard&&(this.constants.keyboard.enabled=!1);if(t.edges){for(e in t.edges)t.edges.hasOwnProperty(e)&&(this.constants.edges[e]=t.edges[e]);void 0!==t.edges.length&&t.nodes&&void 0===t.nodes.distance&&(this.constants.edges.length=t.edges.length,this.constants.nodes.distance=1.25*t.edges.length),t.edges.fontColor||(this.constants.edges.fontColor=t.edges.color),t.edges.dash&&(void 0!==t.edges.dash.length&&(this.constants.edges.dash.length=t.edges.dash.length),void 0!==t.edges.dash.gap&&(this.constants.edges.dash.gap=t.edges.dash.gap),void 0!==t.edges.dash.altLength&&(this.constants.edges.dash.altLength=t.edges.dash.altLength))}if(t.nodes){for(e in t.nodes)t.nodes.hasOwnProperty(e)&&(this.constants.nodes[e]=t.nodes[e]);t.nodes.color&&(this.constants.nodes.color=M.parseColor(t.nodes.color))}if(t.groups)for(var i in t.groups)if(t.groups.hasOwnProperty(i)){var n=t.groups[i];this.groups.add(i,n)}}this.setSize(this.width,this.height),this._setTranslation(this.frame.clientWidth/2,this.frame.clientHeight/2),this._setScale(1),this._loadNavigationControls(),this._createKeyBinds(),this._redraw()},I.prototype.on=function(t,e){var i=["select"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());F.addListener(this,t,e)},I.prototype.off=function(t,e){F.removeListener(this,t,e)},I.prototype._trigger=function(t,e){F.trigger(this,t,e)},I.prototype._create=function(){for(;this.containerElement.hasChildNodes();)this.containerElement.removeChild(this.containerElement.firstChild);if(this.frame=document.createElement("div"),this.frame.className="graph-frame",this.frame.style.position="relative",this.frame.style.overflow="hidden",this.frame.style.zIndex="1",this.frame.canvas=document.createElement("canvas"),this.frame.canvas.style.position="relative",this.frame.appendChild(this.frame.canvas),!this.frame.canvas.getContext){var t=document.createElement("DIV");t.style.color="red",t.style.fontWeight="bold",t.style.padding="10px",t.innerHTML="Error: your browser does not support HTML canvas",this.frame.canvas.appendChild(t)}var e=this;this.drag={},this.pinch={},this.hammer=N(this.frame.canvas,{prevent_default:!0}),this.hammer.on("tap",e._onTap.bind(e)),this.hammer.on("doubletap",e._onDoubleTap.bind(e)),this.hammer.on("hold",e._onHold.bind(e)),this.hammer.on("pinch",e._onPinch.bind(e)),this.hammer.on("touch",e._onTouch.bind(e)),this.hammer.on("dragstart",e._onDragStart.bind(e)),this.hammer.on("drag",e._onDrag.bind(e)),this.hammer.on("dragend",e._onDragEnd.bind(e)),this.hammer.on("release",e._onRelease.bind(e)),this.hammer.on("mousewheel",e._onMouseWheel.bind(e)),this.hammer.on("DOMMouseScroll",e._onMouseWheel.bind(e)),this.hammer.on("mousemove",e._onMouseMoveTitle.bind(e)),this.containerElement.appendChild(this.frame)},I.prototype._createKeyBinds=function(){var t=this;this.mousetrap=k,this.mousetrap.reset(),1==this.constants.keyboard.enabled&&(this.mousetrap.bind("up",this._moveUp.bind(t),"keydown"),this.mousetrap.bind("up",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("down",this._moveDown.bind(t),"keydown"),this.mousetrap.bind("down",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("left",this._moveLeft.bind(t),"keydown"),this.mousetrap.bind("left",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("right",this._moveRight.bind(t),"keydown"),this.mousetrap.bind("right",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("=",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("=",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("-",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("-",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("[",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("[",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("]",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("]",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pageup",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("pageup",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pagedown",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("pagedown",this._stopZoom.bind(t),"keyup"))},I.prototype._getPointer=function(t){return{x:t.pageX-V.util.getAbsoluteLeft(this.frame.canvas),y:t.pageY-V.util.getAbsoluteTop(this.frame.canvas)}},I.prototype._onTouch=function(t){this.drag.pointer=this._getPointer(t.gesture.touches[0]),this.drag.pinched=!1,this.pinch.scale=this._getScale(),this._handleTouch(this.drag.pointer)},I.prototype._onDragStart=function(){var t=this.drag,e=this._getNodeAt(t.pointer);if(t.dragging=!0,t.selection=[],t.translation=this._getTranslation(),t.nodeId=null,null!=e){t.nodeId=e.id,e.isSelected()||this._selectObject(e,!1);for(var i in this.selectionObj)if(this.selectionObj.hasOwnProperty(i)){var n=this.selectionObj[i];if(n instanceof M){var s={id:n.id,node:n,x:n.x,y:n.y,xFixed:n.xFixed,yFixed:n.yFixed};n.xFixed=!0,n.yFixed=!0,t.selection.push(s)}}}},I.prototype._onDrag=function(t){if(!this.drag.pinched){var e=this._getPointer(t.gesture.touches[0]),i=this,n=this.drag,s=n.selection;if(s&&s.length){var o=e.x-n.pointer.x,r=e.y-n.pointer.y;s.forEach(function(t){var e=t.node;t.xFixed||(e.x=i._canvasToX(i._xToCanvas(t.x)+o)),t.yFixed||(e.y=i._canvasToY(i._yToCanvas(t.y)+r))}),this.moving||(this.moving=!0,this.start())}else{var a=e.x-this.drag.pointer.x,h=e.y-this.drag.pointer.y;this._setTranslation(this.drag.translation.x+a,this.drag.translation.y+h),this._redraw(),this.moved=!0}}},I.prototype._onDragEnd=function(){this.drag.dragging=!1;var t=this.drag.selection;t&&t.forEach(function(t){t.node.xFixed=t.xFixed,t.node.yFixed=t.yFixed})},I.prototype._onTap=function(t){var e=this._getPointer(t.gesture.touches[0]);this._handleTap(e)},I.prototype._onDoubleTap=function(t){var e=this._getPointer(t.gesture.touches[0]);this._handleDoubleTap(e)},I.prototype._onHold=function(t){var e=this._getPointer(t.gesture.touches[0]);this._handleOnHold(e)},I.prototype._onRelease=function(){this._handleOnRelease()},I.prototype._onPinch=function(t){var e=this._getPointer(t.gesture.center);this.drag.pinched=!0,"scale"in this.pinch||(this.pinch.scale=1);var i=this.pinch.scale*t.gesture.scale;this._zoom(i,e)},I.prototype._zoom=function(t,e){var i=this._getScale();1e-5>t&&(t=1e-5),t>10&&(t=10);var n=this._getTranslation(),s=t/i,o=(1-s)*e.x+n.x*s,r=(1-s)*e.y+n.y*s;return this.areaCenter={x:this._canvasToX(e.x),y:this._canvasToY(e.y)},this.pinch.mousewheelScale=t,this._setScale(t),this._setTranslation(o,r),this.updateClustersDefault(),this._redraw(),t},I.prototype._onMouseWheel=function(t){var e=0;if(t.wheelDelta?e=t.wheelDelta/120:t.detail&&(e=-t.detail/3),e){"mousewheelScale"in this.pinch||(this.pinch.mousewheelScale=1);var i=this.pinch.mousewheelScale,n=e/10;0>e&&(n/=1-n),i*=1+n;var s=z.fakeGesture(this,t),o=this._getPointer(s.center);i=this._zoom(i,o)}t.preventDefault()},I.prototype._onMouseMoveTitle=function(t){var e=z.fakeGesture(this,t),i=this._getPointer(e.center);this.popupNode&&this._checkHidePopup(i);var n=this,s=function(){n._checkShowPopup(i)};this.popupTimer&&clearInterval(this.popupTimer),this.drag.dragging||(this.popupTimer=setTimeout(s,300))},I.prototype._checkShowPopup=function(t){var e,i={left:this._canvasToX(t.x),top:this._canvasToY(t.y),right:this._canvasToX(t.x),bottom:this._canvasToY(t.y)},n=this.popupNode;if(void 0==this.popupNode){var s=this.nodes;for(e in s)if(s.hasOwnProperty(e)){var o=s[e];if(void 0!==o.getTitle()&&o.isOverlappingWith(i)){this.popupNode=o;break}}}if(void 0===this.popupNode){var r=this.edges;for(e in r)if(r.hasOwnProperty(e)){var a=r[e];if(a.connected&&void 0!==a.getTitle()&&a.isOverlappingWith(i)){this.popupNode=a;break}}}if(this.popupNode){if(this.popupNode!=n){var h=this;h.popup||(h.popup=new O(h.frame)),h.popup.setPosition(t.x-3,t.y-3),h.popup.setText(h.popupNode.getTitle()),h.popup.show()}}else this.popup&&this.popup.hide()},I.prototype._checkHidePopup=function(t){this.popupNode&&this._getNodeAt(t)||(this.popupNode=void 0,this.popup&&this.popup.hide())},I.prototype._getConnectionCount=function(t){function e(t){for(var e=[],i=0,n=t.length;n>i;i++)for(var s=t[i],o=s.edges,r=0,a=o.length;a>r;r++){var h=o[r],d=null;h.from==s?d=h.to:h.to==s&&(d=h.from);var c,l;if(d)for(c=0,l=t.length;l>c;c++)if(t[c]==d){d=null;break}if(d)for(c=0,l=e.length;l>c;c++)if(e[c]==d){d=null;break}d&&e.push(d)}return e}void 0==t&&(t=1);var i=[],n=this.nodes;for(var s in n)if(n.hasOwnProperty(s)){for(var o=[n[s]],r=0;t>r;r++)o=o.concat(e(o));i.push(o)}for(var a=[],h=0,d=i.length;d>h;h++)a.push(i[h].length);return a},I.prototype.setSize=function(t,e){this.frame.style.width=t,this.frame.style.height=e,this.frame.canvas.style.width="100%",this.frame.canvas.style.height="100%",this.frame.canvas.width=this.frame.canvas.clientWidth,this.frame.canvas.height=this.frame.canvas.clientHeight,this.manipulationDiv.style.width=this.frame.canvas.clientWidth,1==this.constants.navigation.enabled&&this._relocateNavigation()},I.prototype._setNodes=function(t){var e=this.nodesData;if(t instanceof o||t instanceof r)this.nodesData=t;else if(t instanceof Array)this.nodesData=new o,this.nodesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.nodesData=new o}if(e&&z.forEach(this.nodesListeners,function(t,i){e.unsubscribe(i,t)}),this.nodes={},this.nodesData){var i=this;z.forEach(this.nodesListeners,function(t,e){i.nodesData.subscribe(e,t)});var n=this.nodesData.getIds();this._addNodes(n)}this._updateSelection()},I.prototype._addNodes=function(t){for(var e,i=0,n=t.length;n>i;i++){e=t[i];var s=this.nodesData.get(e),o=new M(s,this.images,this.groups,this.constants);if(this.nodes[e]=o,!o.isFixed()&&1!=this.createNodeOnClick){var r=2*this.constants.edges.length,a=t.length,h=2*Math.PI*(i/a);o.x=r*Math.cos(h),o.y=r*Math.sin(h),this.moving=!0}}this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(this.nodes),this.updateLabels()},I.prototype._updateNodes=function(t){for(var e=this.nodes,i=this.nodesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o],a=i.get(o);r?r.setProperties(a,this.constants):(r=new M(properties,this.images,this.groups,this.constants),e[o]=r,r.isFixed()||(this.moving=!0))}this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(e)},I.prototype._removeNodes=function(t){for(var e=this.nodes,i=0,n=t.length;n>i;i++){var s=t[i];delete e[s]}this._updateNodeIndexList(),this._reconnectEdges(),this._updateSelection(),this._updateValueRange(e)},I.prototype._setEdges=function(t){var e=this.edgesData;if(t instanceof o||t instanceof r)this.edgesData=t;else if(t instanceof Array)this.edgesData=new o,this.edgesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.edgesData=new o}if(e&&z.forEach(this.edgesListeners,function(t,i){e.unsubscribe(i,t)}),this.edges={},this.edgesData){var i=this;z.forEach(this.edgesListeners,function(t,e){i.edgesData.subscribe(e,t)});var n=this.edgesData.getIds();this._addEdges(n)}this._reconnectEdges()},I.prototype._addEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o];r&&r.disconnect();var a=i.get(o,{showInternalIds:!0});e[o]=new D(a,this,this.constants)}this.moving=!0,this._updateValueRange(e)},I.prototype._updateEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=i.get(o),a=e[o];a?(a.disconnect(),a.setProperties(r,this.constants),a.connect()):(a=new D(r,this,this.constants),this.edges[o]=a)}this.moving=!0,this._updateValueRange(e)},I.prototype._removeEdges=function(t){for(var e=this.edges,i=0,n=t.length;n>i;i++){var s=t[i],o=e[s];o&&(o.disconnect(),delete e[s])}this.moving=!0,this._updateValueRange(e)},I.prototype._reconnectEdges=function(){var t,e=this.nodes,i=this.edges;for(t in e)e.hasOwnProperty(t)&&(e[t].edges=[]);for(t in i)if(i.hasOwnProperty(t)){var n=i[t];n.from=null,n.to=null,n.connect()}},I.prototype._updateValueRange=function(t){var e,i=void 0,n=void 0;for(e in t)if(t.hasOwnProperty(e)){var s=t[e].getValue();void 0!==s&&(i=void 0===i?s:Math.min(s,i),n=void 0===n?s:Math.max(s,n))}if(void 0!==i&&void 0!==n)for(e in t)t.hasOwnProperty(e)&&t[e].setValueRange(i,n)},I.prototype.redraw=function(){this.setSize(this.width,this.height),this._redraw()},I.prototype._redraw=function(){var t=this.frame.canvas.getContext("2d"),e=this.frame.canvas.width,i=this.frame.canvas.height;t.clearRect(0,0,e,i),t.save(),t.translate(this.translation.x,this.translation.y),t.scale(this.scale,this.scale),this.canvasTopLeft={x:this._canvasToX(0),y:this._canvasToY(0)},this.canvasBottomRight={x:this._canvasToX(this.frame.canvas.clientWidth),y:this._canvasToY(this.frame.canvas.clientHeight)},this._doInAllSectors("_drawAllSectorNodes",t),this._doInAllSectors("_drawEdges",t),this._doInAllSectors("_drawNodes",t,!0),t.restore(),1==this.constants.navigation.enabled&&this._doInNavigationSector("_drawNodes",t,!0)},I.prototype._setTranslation=function(t,e){void 0===this.translation&&(this.translation={x:0,y:0}),void 0!==t&&(this.translation.x=t),void 0!==e&&(this.translation.y=e)},I.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},I.prototype._setScale=function(t){this.scale=t},I.prototype._getScale=function(){return this.scale},I.prototype._canvasToX=function(t){return(t-this.translation.x)/this.scale},I.prototype._xToCanvas=function(t){return t*this.scale+this.translation.x},I.prototype._canvasToY=function(t){return(t-this.translation.y)/this.scale},I.prototype._yToCanvas=function(t){return t*this.scale+this.translation.y},I.prototype._drawNodes=function(t,e){void 0===e&&(e=!1);var i=this.nodes,n=[];for(var s in i)i.hasOwnProperty(s)&&(i[s].setScaleAndPos(this.scale,this.canvasTopLeft,this.canvasBottomRight),i[s].isSelected()?n.push(s):(i[s].inArea()||e)&&i[s].draw(t));for(var o=0,r=n.length;r>o;o++)(i[n[o]].inArea()||e)&&i[n[o]].draw(t)},I.prototype._drawEdges=function(t){var e=this.edges;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];n.setScale(this.scale),n.connected&&e[i].draw(t)}},I.prototype._doStabilize=function(){for(var t=0,e=this.constants.minVelocity,i=!1;!i&&tthis.constants.clustering.clusterThreshold&&1==this.constants.clustering.enabled&&this.clusterToFit(this.constants.clustering.reduceToNodes,!1),this._calculateForces())},I.prototype._calculateForces=function(){var t,e,i,n,s,o,r,a,h,d,c,l,u,p,f,g,m,v,y=this.nodes,_=this.edges,w=.08*this.forceFactor;for(g=0;gn&&(i=Math.atan2(e,t),r=.5*b>n?1:1/(1+Math.exp((n/b-1)*S)),r*=0==v?1:1+v*this.constants.clustering.forceAmplification,r*=this.forceFactor,s=Math.cos(i)*r,o=Math.sin(i)*r,l._addForce(-s,-o),u._addForce(s,o));for(f in _)_.hasOwnProperty(f)&&(p=_[f],p.connected&&this.nodes.hasOwnProperty(p.toId)&&this.nodes.hasOwnProperty(p.fromId)&&(v=p.to.clusterSize+p.from.clusterSize-2,t=p.to.x-p.from.x,e=p.to.y-p.from.y,d=p.length,d+=v*this.constants.clustering.edgeGrowth,h=Math.sqrt(t*t+e*e),i=Math.atan2(e,t),a=p.stiffness*(d-h)*this.forceFactor,s=Math.cos(i)*a,o=Math.sin(i)*a,p.from._addForce(-s,-o),p.to._addForce(s,o)))},I.prototype._isMoving=function(t){var e=t/this.scale,i=this.nodes;for(var n in i)if(i.hasOwnProperty(n)&&i[n].isMoving(e))return!0;return!1},I.prototype._discreteStepNodes=function(){var t=.01,e=this.nodes;for(var i in e)e.hasOwnProperty(i)&&e[i].discreteStep(t);var n=this.constants.minVelocity;this.moving=this._isMoving(n)},I.prototype.start=function(){if(!this.freezeSimulation)if(this.moving&&(this._doInAllActiveSectors("_initializeForceCalculation"),this._doInAllActiveSectors("_discreteStepNodes"),this._findCenter(this._getRange())),this.moving||0!=this.xIncrement||0!=this.yIncrement||0!=this.zoomIncrement){if(!this.timer){var t=this;this.timer=window.setTimeout(function(){if(t.timer=void 0,0!=t.xIncrement||0!=t.yIncrement){var e=t._getTranslation();t._setTranslation(e.x+t.xIncrement,e.y+t.yIncrement)}if(0!=t.zoomIncrement){var i={x:t.frame.canvas.clientWidth/2,y:t.frame.canvas.clientHeight/2};t._zoom(t.scale*(1+t.zoomIncrement),i)}t.start(),t._redraw()},this.renderTimestep)}}else this._redraw()},I.prototype.singleStep=function(){if(this.moving){this._initializeForceCalculation(),this._discreteStepNodes();var t=this.constants.minVelocity;this.moving=this._isMoving(t),this._redraw()}},I.prototype.toggleFreeze=function(){0==this.freezeSimulation?this.freezeSimulation=!0:(this.freezeSimulation=!1,this.start())},I.prototype._loadClusterSystem=function(){this.clusterSession=0,this.hubThreshold=5;for(var t in W)W.hasOwnProperty(t)&&(I.prototype[t]=W[t])},I.prototype._loadSectorSystem=function(){this.sectors={},this.activeSector=["default"],this.sectors.active={},this.sectors.active["default"]={nodes:{},edges:{},nodeIndices:[],formationScale:1,drawingNode:void 0},this.sectors.frozen={},this.sectors.navigation={nodes:{},edges:{},nodeIndices:[],formationScale:1,drawingNode:void 0},this.nodeIndices=this.sectors.active["default"].nodeIndices;for(var t in R)R.hasOwnProperty(t)&&(I.prototype[t]=R[t])},I.prototype._loadSelectionSystem=function(){this.selectionObj={};for(var t in j)j.hasOwnProperty(t)&&(I.prototype[t]=j[t])},I.prototype._loadManipulationSystem=function(){this.manipulationDiv=document.createElement("div"),this.manipulationDiv.className="graph-manipulationDiv",this.containerElement.insertBefore(this.manipulationDiv,this.frame);for(var t in H)H.hasOwnProperty(t)&&(I.prototype[t]=H[t]);this._createManipulatorBar()},I.prototype._loadNavigationControls=function(){for(var t in U)U.hasOwnProperty(t)&&(I.prototype[t]=U[t]);1==this.constants.navigation.enabled&&this._loadNavigationElements()},I.prototype._relocateNavigation=function(){},I.prototype._unHighlightAll=function(){};var V={util:z,events:F,Controller:l,DataSet:o,DataView:r,Range:h,Stack:a,TimeStep:TimeStep,EventBus:s,components:{items:{Item:_,ItemBox:w,ItemPoint:b,ItemRange:S},Component:u,Panel:p,RootPanel:f,ItemSet:y,TimeAxis:g},graph:{Node:M,Edge:D,Popup:O,Groups:Groups,Images:Images},Timeline:C,Graph:I};"undefined"!=typeof n&&(n=V),"undefined"!=typeof i&&"undefined"!=typeof i.exports&&(i.exports=V),"function"==typeof t&&t(function(){return V}),"undefined"!=typeof window&&(window.vis=V)},{hammerjs:2,moment:3,mousetrap:4}],2:[function(t,e){!function(t,i){"use strict";function n(){if(!s.READY){s.event.determineEventTypes();for(var t in s.gestures)s.gestures.hasOwnProperty(t)&&s.detection.register(s.gestures[t]);s.event.onTouch(s.DOCUMENT,s.EVENT_MOVE,s.detection.detect),s.event.onTouch(s.DOCUMENT,s.EVENT_END,s.detection.detect),s.READY=!0}}var s=function(t,e){return new s.Instance(t,e||{})};s.defaults={stop_browser_behavior:{userSelect:"none",touchAction:"none",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}},s.HAS_POINTEREVENTS=navigator.pointerEnabled||navigator.msPointerEnabled,s.HAS_TOUCHEVENTS="ontouchstart"in t,s.MOBILE_REGEX=/mobile|tablet|ip(ad|hone|od)|android/i,s.NO_MOUSEEVENTS=s.HAS_TOUCHEVENTS&&navigator.userAgent.match(s.MOBILE_REGEX),s.EVENT_TYPES={},s.DIRECTION_DOWN="down",s.DIRECTION_LEFT="left",s.DIRECTION_UP="up",s.DIRECTION_RIGHT="right",s.POINTER_MOUSE="mouse",s.POINTER_TOUCH="touch",s.POINTER_PEN="pen",s.EVENT_START="start",s.EVENT_MOVE="move",s.EVENT_END="end",s.DOCUMENT=document,s.plugins={},s.READY=!1,s.Instance=function(t,e){var i=this;return n(),this.element=t,this.enabled=!0,this.options=s.utils.extend(s.utils.extend({},s.defaults),e||{}),this.options.stop_browser_behavior&&s.utils.stopDefaultBrowserBehavior(this.element,this.options.stop_browser_behavior),s.event.onTouch(t,s.EVENT_START,function(t){i.enabled&&s.detection.startDetect(i,t)}),this},s.Instance.prototype={on:function(t,e){for(var i=t.split(" "),n=0;n0&&e==s.EVENT_END?e=s.EVENT_MOVE:c||(e=s.EVENT_END),c||null===o?o=h:h=o,i.call(s.detection,n.collectEventData(t,e,h)),s.HAS_POINTEREVENTS&&e==s.EVENT_END&&(c=s.PointerEvent.updatePointer(e,h))),c||(o=null,r=!1,a=!1,s.PointerEvent.reset())}})},determineEventTypes:function(){var t;t=s.HAS_POINTEREVENTS?s.PointerEvent.getEvents():s.NO_MOUSEEVENTS?["touchstart","touchmove","touchend touchcancel"]:["touchstart mousedown","touchmove mousemove","touchend touchcancel mouseup"],s.EVENT_TYPES[s.EVENT_START]=t[0],s.EVENT_TYPES[s.EVENT_MOVE]=t[1],s.EVENT_TYPES[s.EVENT_END]=t[2]},getTouchList:function(t){return s.HAS_POINTEREVENTS?s.PointerEvent.getTouchList():t.touches?t.touches:[{identifier:1,pageX:t.pageX,pageY:t.pageY,target:t.target}]},collectEventData:function(t,e,i){var n=this.getTouchList(i,e),o=s.POINTER_TOUCH;return(i.type.match(/mouse/)||s.PointerEvent.matchType(s.POINTER_MOUSE,i))&&(o=s.POINTER_MOUSE),{center:s.utils.getCenter(n),timeStamp:(new Date).getTime(),target:i.target,touches:n,eventType:e,pointerType:o,srcEvent:i,preventDefault:function(){this.srcEvent.preventManipulation&&this.srcEvent.preventManipulation(),this.srcEvent.preventDefault&&this.srcEvent.preventDefault()},stopPropagation:function(){this.srcEvent.stopPropagation()},stopDetect:function(){return s.detection.stopDetect()}}}},s.PointerEvent={pointers:{},getTouchList:function(){var t=this,e=[];return Object.keys(t.pointers).sort().forEach(function(i){e.push(t.pointers[i])}),e},updatePointer:function(t,e){return t==s.EVENT_END?this.pointers={}:(e.identifier=e.pointerId,this.pointers[e.pointerId]=e),Object.keys(this.pointers).length},matchType:function(t,e){if(!e.pointerType)return!1;var i={};return i[s.POINTER_MOUSE]=e.pointerType==e.MSPOINTER_TYPE_MOUSE||e.pointerType==s.POINTER_MOUSE,i[s.POINTER_TOUCH]=e.pointerType==e.MSPOINTER_TYPE_TOUCH||e.pointerType==s.POINTER_TOUCH,i[s.POINTER_PEN]=e.pointerType==e.MSPOINTER_TYPE_PEN||e.pointerType==s.POINTER_PEN,i[t]},getEvents:function(){return["pointerdown MSPointerDown","pointermove MSPointerMove","pointerup pointercancel MSPointerUp MSPointerCancel"]},reset:function(){this.pointers={}}},s.utils={extend:function(t,e,n){for(var s in e)t[s]!==i&&n||(t[s]=e[s]);return t},hasParent:function(t,e){for(;t;){if(t==e)return!0;t=t.parentNode}return!1},getCenter:function(t){for(var e=[],i=[],n=0,s=t.length;s>n;n++)e.push(t[n].pageX),i.push(t[n].pageY);return{pageX:(Math.min.apply(Math,e)+Math.max.apply(Math,e))/2,pageY:(Math.min.apply(Math,i)+Math.max.apply(Math,i))/2}},getVelocity:function(t,e,i){return{x:Math.abs(e/t)||0,y:Math.abs(i/t)||0}},getAngle:function(t,e){var i=e.pageY-t.pageY,n=e.pageX-t.pageX;return 180*Math.atan2(i,n)/Math.PI},getDirection:function(t,e){var i=Math.abs(t.pageX-e.pageX),n=Math.abs(t.pageY-e.pageY);return i>=n?t.pageX-e.pageX>0?s.DIRECTION_LEFT:s.DIRECTION_RIGHT:t.pageY-e.pageY>0?s.DIRECTION_UP:s.DIRECTION_DOWN},getDistance:function(t,e){var i=e.pageX-t.pageX,n=e.pageY-t.pageY;return Math.sqrt(i*i+n*n)},getScale:function(t,e){return t.length>=2&&e.length>=2?this.getDistance(e[0],e[1])/this.getDistance(t[0],t[1]):1},getRotation:function(t,e){return t.length>=2&&e.length>=2?this.getAngle(e[1],e[0])-this.getAngle(t[1],t[0]):0},isVertical:function(t){return t==s.DIRECTION_UP||t==s.DIRECTION_DOWN},stopDefaultBrowserBehavior:function(t,e){var i,n=["webkit","khtml","moz","ms","o",""];if(e&&t.style){for(var s=0;si;i++){var o=this.gestures[i];if(!this.stopped&&e[o.name]!==!1&&o.handler.call(o,t,this.current.inst)===!1){this.stopDetect();break}}return this.current&&(this.current.lastEvent=t),t.eventType==s.EVENT_END&&!t.touches.length-1&&this.stopDetect(),t}},stopDetect:function(){this.previous=s.utils.extend({},this.current),this.current=null,this.stopped=!0},extendEventData:function(t){var e=this.current.startEvent;if(e&&(t.touches.length!=e.touches.length||t.touches===e.touches)){e.touches=[];for(var i=0,n=t.touches.length;n>i;i++)e.touches.push(s.utils.extend({},t.touches[i]))}var o=t.timeStamp-e.timeStamp,r=t.center.pageX-e.center.pageX,a=t.center.pageY-e.center.pageY,h=s.utils.getVelocity(o,r,a);return s.utils.extend(t,{deltaTime:o,deltaX:r,deltaY:a,velocityX:h.x,velocityY:h.y,distance:s.utils.getDistance(e.center,t.center),angle:s.utils.getAngle(e.center,t.center),direction:s.utils.getDirection(e.center,t.center),scale:s.utils.getScale(e.touches,t.touches),rotation:s.utils.getRotation(e.touches,t.touches),startEvent:e}),t},register:function(t){var e=t.defaults||{};return e[t.name]===i&&(e[t.name]=!0),s.utils.extend(s.defaults,e,!0),t.index=t.index||1e3,this.gestures.push(t),this.gestures.sort(function(t,e){return t.indexe.index?1:0}),this.gestures}},s.gestures=s.gestures||{},s.gestures.Hold={name:"hold",index:10,defaults:{hold_timeout:500,hold_threshold:1},timer:null,handler:function(t,e){switch(t.eventType){case s.EVENT_START:clearTimeout(this.timer),s.detection.current.name=this.name,this.timer=setTimeout(function(){"hold"==s.detection.current.name&&e.trigger("hold",t)},e.options.hold_timeout);break;case s.EVENT_MOVE:t.distance>e.options.hold_threshold&&clearTimeout(this.timer);break;case s.EVENT_END:clearTimeout(this.timer)}}},s.gestures.Tap={name:"tap",index:100,defaults:{tap_max_touchtime:250,tap_max_distance:10,tap_always:!0,doubletap_distance:20,doubletap_interval:300},handler:function(t,e){if(t.eventType==s.EVENT_END){var i=s.detection.previous,n=!1;if(t.deltaTime>e.options.tap_max_touchtime||t.distance>e.options.tap_max_distance)return;i&&"tap"==i.name&&t.timeStamp-i.lastEvent.timeStamp0&&t.touches.length>e.options.swipe_max_touches)return;(t.velocityX>e.options.swipe_velocity||t.velocityY>e.options.swipe_velocity)&&(e.trigger(this.name,t),e.trigger(this.name+t.direction,t))}}},s.gestures.Drag={name:"drag",index:50,defaults:{drag_min_distance:10,drag_max_touches:1,drag_block_horizontal:!1,drag_block_vertical:!1,drag_lock_to_axis:!1,drag_lock_min_distance:25},triggered:!1,handler:function(t,e){if(s.detection.current.name!=this.name&&this.triggered)return e.trigger(this.name+"end",t),void(this.triggered=!1);if(!(e.options.drag_max_touches>0&&t.touches.length>e.options.drag_max_touches))switch(t.eventType){case s.EVENT_START:this.triggered=!1;break;case s.EVENT_MOVE:if(t.distancee.options.transform_min_rotation&&e.trigger("rotate",t),i>e.options.transform_min_scale&&(e.trigger("pinch",t),e.trigger("pinch"+(t.scale<1?"in":"out"),t));break;case s.EVENT_END:this.triggered&&e.trigger(this.name+"end",t),this.triggered=!1}}},s.gestures.Touch={name:"touch",index:-1/0,defaults:{prevent_default:!1,prevent_mouseevents:!1},handler:function(t,e){return e.options.prevent_mouseevents&&t.pointerType==s.POINTER_MOUSE?void t.stopDetect():(e.options.prevent_default&&t.preventDefault(),void(t.eventType==s.EVENT_START&&e.trigger(this.name,t)))}},s.gestures.Release={name:"release",index:1/0,handler:function(t,e){t.eventType==s.EVENT_END&&e.trigger(this.name,t)}},"object"==typeof e&&"object"==typeof e.exports?e.exports=s:(t.Hammer=s,"function"==typeof t.define&&t.define.amd&&t.define("hammer",[],function(){return s}))}(this)},{}],3:[function(e,i){(function(n){function s(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function o(t,e){return function(i){return p(t.call(this,i),e)}}function r(t,e){return function(i){return this.lang().ordinal(t.call(this,i),e)}}function a(){}function h(t){x(t),c(this,t)}function d(t){var e=_(t),i=e.year||0,n=e.month||0,s=e.week||0,o=e.day||0,r=e.hour||0,a=e.minute||0,h=e.second||0,d=e.millisecond||0;this._milliseconds=+d+1e3*h+6e4*a+36e5*r,this._days=+o+7*s,this._months=+n+12*i,this._data={},this._bubble()}function c(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return e.hasOwnProperty("toString")&&(t.toString=e.toString),e.hasOwnProperty("valueOf")&&(t.valueOf=e.valueOf),t}function l(t){var e,i={};for(e in t)t.hasOwnProperty(e)&&_e.hasOwnProperty(e)&&(i[e]=t[e]);return i}function u(t){return 0>t?Math.ceil(t):Math.floor(t)}function p(t,e,i){for(var n=""+Math.abs(t),s=t>=0;n.lengthn;n++)(i&&t[n]!==e[n]||!i&&b(t[n])!==b(e[n]))&&r++;return r+o}function y(t){if(t){var e=t.toLowerCase().replace(/(.)s$/,"$1");t=Xe[t]||Ze[e]||e}return t}function _(t){var e,i,n={};for(i in t)t.hasOwnProperty(i)&&(e=y(i),e&&(n[e]=t[i]));return n}function w(t){var e,i;if(0===t.indexOf("week"))e=7,i="day";else{if(0!==t.indexOf("month"))return;e=12,i="month"}re[t]=function(s,o){var r,a,h=re.fn._lang[t],d=[];if("number"==typeof s&&(o=s,s=n),a=function(t){var e=re().utc().set(i,t);return h.call(re.fn._lang,e,s||"")},null!=o)return a(o);for(r=0;e>r;r++)d.push(a(r));return d}}function b(t){var e=+t,i=0;return 0!==e&&isFinite(e)&&(i=e>=0?Math.floor(e):Math.ceil(e)),i}function S(t,e){return new Date(Date.UTC(t,e+1,0)).getUTCDate()}function E(t){return T(t)?366:365}function T(t){return t%4===0&&t%100!==0||t%400===0}function x(t){var e;t._a&&-2===t._pf.overflow&&(e=t._a[ue]<0||t._a[ue]>11?ue:t._a[pe]<1||t._a[pe]>S(t._a[le],t._a[ue])?pe:t._a[fe]<0||t._a[fe]>23?fe:t._a[ge]<0||t._a[ge]>59?ge:t._a[me]<0||t._a[me]>59?me:t._a[ve]<0||t._a[ve]>999?ve:-1,t._pf._overflowDayOfYear&&(le>e||e>pe)&&(e=pe),t._pf.overflow=e)}function C(t){return null==t._isValid&&(t._isValid=!isNaN(t._d.getTime())&&t._pf.overflow<0&&!t._pf.empty&&!t._pf.invalidMonth&&!t._pf.nullInput&&!t._pf.invalidFormat&&!t._pf.userInvalidated,t._strict&&(t._isValid=t._isValid&&0===t._pf.charsLeftOver&&0===t._pf.unusedTokens.length)),t._isValid}function M(t){return t?t.toLowerCase().replace("_","-"):t}function D(t,e){return e._isUTC?re(t).zone(e._offset||0):re(t).local()}function O(t,e){return e.abbr=t,ye[t]||(ye[t]=new a),ye[t].set(e),ye[t]}function I(t){delete ye[t]}function N(t){var i,n,s,o,r=0,a=function(t){if(!ye[t]&&we)try{e("./lang/"+t)}catch(i){}return ye[t]};if(!t)return re.fn._lang;if(!g(t)){if(n=a(t))return n;t=[t]}for(;r0;){if(n=a(o.slice(0,i).join("-")))return n;if(s&&s.length>=i&&v(o,s,!0)>=i-1)break;i--}r++}return re.fn._lang}function L(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function k(t){var e,i,n=t.match(Te);for(e=0,i=n.length;i>e;e++)n[e]=Je[n[e]]?Je[n[e]]:L(n[e]);return function(s){var o="";for(e=0;i>e;e++)o+=n[e]instanceof Function?n[e].call(s,t):n[e];return o}}function A(t,e){return t.isValid()?(e=z(e,t.lang()),Ke[e]||(Ke[e]=k(e)),Ke[e](t)):t.lang().invalidDate()}function z(t,e){function i(t){return e.longDateFormat(t)||t}var n=5;for(xe.lastIndex=0;n>=0&&xe.test(t);)t=t.replace(xe,i),xe.lastIndex=0,n-=1;return t}function P(t,e){var i,n=e._strict;switch(t){case"DDDD":return Fe;case"YYYY":case"GGGG":case"gggg":return n?Ye:De;case"Y":case"G":case"g":return Re;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return n?He:Oe;case"S":if(n)return ze;case"SS":if(n)return Pe;case"SSS":if(n)return Fe;case"DDD":return Me;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Ne;case"a":case"A":return N(e._l)._meridiemParse;case"X":return Ae;case"Z":case"ZZ":return Le;case"T":return ke;case"SSSS":return Ie;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return n?Pe:Ce;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return Ce;default:return i=new RegExp(V(U(t.replace("\\","")),"i"))}}function F(t){t=t||"";var e=t.match(Le)||[],i=e[e.length-1]||[],n=(i+"").match(Ge)||["-",0,0],s=+(60*n[1])+b(n[2]);return"+"===n[0]?-s:s}function Y(t,e,i){var n,s=i._a;switch(t){case"M":case"MM":null!=e&&(s[ue]=b(e)-1);break;case"MMM":case"MMMM":n=N(i._l).monthsParse(e),null!=n?s[ue]=n:i._pf.invalidMonth=e;break;case"D":case"DD":null!=e&&(s[pe]=b(e));break;case"DDD":case"DDDD":null!=e&&(i._dayOfYear=b(e));break;case"YY":s[le]=b(e)+(b(e)>68?1900:2e3);break;case"YYYY":case"YYYYY":case"YYYYYY":s[le]=b(e);break;case"a":case"A":i._isPm=N(i._l).isPM(e);break;case"H":case"HH":case"h":case"hh":s[fe]=b(e);break;case"m":case"mm":s[ge]=b(e);break;case"s":case"ss":s[me]=b(e);break;case"S":case"SS":case"SSS":case"SSSS":s[ve]=b(1e3*("0."+e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,i._tzm=F(e);break;case"w":case"ww":case"W":case"WW":case"d":case"dd":case"ddd":case"dddd":case"e":case"E":t=t.substr(0,1);case"gg":case"gggg":case"GG":case"GGGG":case"GGGGG":t=t.substr(0,2),e&&(i._w=i._w||{},i._w[t]=e)}}function H(t){var e,i,n,s,o,r,a,h,d,c,l=[];if(!t._d){for(n=W(t),t._w&&null==t._a[pe]&&null==t._a[ue]&&(o=function(e){var i=parseInt(e,10);return e?e.length<3?i>68?1900+i:2e3+i:i:null==t._a[le]?re().weekYear():t._a[le]},r=t._w,null!=r.GG||null!=r.W||null!=r.E?a=te(o(r.GG),r.W||1,r.E,4,1):(h=N(t._l),d=null!=r.d?K(r.d,h):null!=r.e?parseInt(r.e,10)+h._week.dow:0,c=parseInt(r.w,10)||1,null!=r.d&&dE(s)&&(t._pf._overflowDayOfYear=!0),i=Z(s,0,t._dayOfYear),t._a[ue]=i.getUTCMonth(),t._a[pe]=i.getUTCDate()),e=0;3>e&&null==t._a[e];++e)t._a[e]=l[e]=n[e];for(;7>e;e++)t._a[e]=l[e]=null==t._a[e]?2===e?1:0:t._a[e];l[fe]+=b((t._tzm||0)/60),l[ge]+=b((t._tzm||0)%60),t._d=(t._useUTC?Z:X).apply(null,l)}}function R(t){var e;t._d||(e=_(t._i),t._a=[e.year,e.month,e.day,e.hour,e.minute,e.second,e.millisecond],H(t))}function W(t){var e=new Date;return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function j(t){t._a=[],t._pf.empty=!0;var e,i,n,s,o,r=N(t._l),a=""+t._i,h=a.length,d=0;for(n=z(t._f,r).match(Te)||[],e=0;e0&&t._pf.unusedInput.push(o),a=a.slice(a.indexOf(i)+i.length),d+=i.length),Je[s]?(i?t._pf.empty=!1:t._pf.unusedTokens.push(s),Y(s,i,t)):t._strict&&!i&&t._pf.unusedTokens.push(s);t._pf.charsLeftOver=h-d,a.length>0&&t._pf.unusedInput.push(a),t._isPm&&t._a[fe]<12&&(t._a[fe]+=12),t._isPm===!1&&12===t._a[fe]&&(t._a[fe]=0),H(t),x(t)}function U(t){return t.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,i,n,s){return e||i||n||s})}function V(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function G(t){var e,i,n,o,r;if(0===t._f.length)return t._pf.invalidFormat=!0,void(t._d=new Date(0/0));for(o=0;or)&&(n=r,i=e));c(t,i||e)}function B(t){var e,i,n=t._i,s=We.exec(n);if(s){for(t._pf.iso=!0,e=0,i=Ue.length;i>e;e++)if(Ue[e][1].exec(n)){t._f=Ue[e][0]+(s[6]||" ");break}for(e=0,i=Ve.length;i>e;e++)if(Ve[e][1].exec(n)){t._f+=Ve[e][0];break}n.match(Le)&&(t._f+="Z"),j(t)}else t._d=new Date(n)}function q(t){var e=t._i,i=be.exec(e);e===n?t._d=new Date:i?t._d=new Date(+i[1]):"string"==typeof e?B(t):g(e)?(t._a=e.slice(0),H(t)):m(e)?t._d=new Date(+e):"object"==typeof e?R(t):t._d=new Date(e)}function X(t,e,i,n,s,o,r){var a=new Date(t,e,i,n,s,o,r);return 1970>t&&a.setFullYear(t),a}function Z(t){var e=new Date(Date.UTC.apply(null,arguments));return 1970>t&&e.setUTCFullYear(t),e}function K(t,e){if("string"==typeof t)if(isNaN(t)){if(t=e.weekdaysParse(t),"number"!=typeof t)return null}else t=parseInt(t,10);return t}function $(t,e,i,n,s){return s.relativeTime(e||1,!!i,t,n)}function Q(t,e,i){var n=ce(Math.abs(t)/1e3),s=ce(n/60),o=ce(s/60),r=ce(o/24),a=ce(r/365),h=45>n&&["s",n]||1===s&&["m"]||45>s&&["mm",s]||1===o&&["h"]||22>o&&["hh",o]||1===r&&["d"]||25>=r&&["dd",r]||45>=r&&["M"]||345>r&&["MM",ce(r/30)]||1===a&&["y"]||["yy",a];return h[2]=e,h[3]=t>0,h[4]=i,$.apply({},h)}function J(t,e,i){var n,s=i-e,o=i-t.day();return o>s&&(o-=7),s-7>o&&(o+=7),n=re(t).add("d",o),{week:Math.ceil(n.dayOfYear()/7),year:n.year()}}function te(t,e,i,n,s){var o,r,a=Z(t,0,1).getUTCDay();return i=null!=i?i:s,o=s-a+(a>n?7:0)-(s>a?7:0),r=7*(e-1)+(i-s)+o+1,{year:r>0?t:t-1,dayOfYear:r>0?r:E(t-1)+r}}function ee(t){var e=t._i,i=t._f;return null===e?re.invalid({nullInput:!0}):("string"==typeof e&&(t._i=e=N().preparse(e)),re.isMoment(e)?(t=l(e),t._d=new Date(+e._d)):i?g(i)?G(t):j(t):q(t),new h(t))}function ie(t,e){re.fn[t]=re.fn[t+"s"]=function(t){var i=this._isUTC?"UTC":"";return null!=t?(this._d["set"+i+e](t),re.updateOffset(this),this):this._d["get"+i+e]()}}function ne(t){re.duration.fn[t]=function(){return this._data[t]}}function se(t,e){re.duration.fn["as"+t]=function(){return+this/e}}function oe(t){var e=!1,i=re;"undefined"==typeof ender&&(t?(de.moment=function(){return!e&&console&&console.warn&&(e=!0,console.warn("Accessing Moment through the global scope is deprecated, and will be removed in an upcoming release.")),i.apply(null,arguments)},c(de.moment,i)):de.moment=re)}for(var re,ae,he="2.5.1",de=this,ce=Math.round,le=0,ue=1,pe=2,fe=3,ge=4,me=5,ve=6,ye={},_e={_isAMomentObject:null,_i:null,_f:null,_l:null,_strict:null,_isUTC:null,_offset:null,_pf:null,_lang:null},we="undefined"!=typeof i&&i.exports&&"undefined"!=typeof e,be=/^\/?Date\((\-?\d+)/i,Se=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,Ee=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,Te=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g,xe=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,Ce=/\d\d?/,Me=/\d{1,3}/,De=/\d{1,4}/,Oe=/[+\-]?\d{1,6}/,Ie=/\d+/,Ne=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Le=/Z|[\+\-]\d\d:?\d\d/gi,ke=/T/i,Ae=/[\+\-]?\d+(\.\d{1,3})?/,ze=/\d/,Pe=/\d\d/,Fe=/\d{3}/,Ye=/\d{4}/,He=/[+-]?\d{6}/,Re=/[+-]?\d+/,We=/^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,je="YYYY-MM-DDTHH:mm:ssZ",Ue=[["YYYYYY-MM-DD",/[+-]\d{6}-\d{2}-\d{2}/],["YYYY-MM-DD",/\d{4}-\d{2}-\d{2}/],["GGGG-[W]WW-E",/\d{4}-W\d{2}-\d/],["GGGG-[W]WW",/\d{4}-W\d{2}/],["YYYY-DDD",/\d{4}-\d{3}/]],Ve=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d{1,3}/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],Ge=/([\+\-]|\d\d)/gi,Be="Date|Hours|Minutes|Seconds|Milliseconds".split("|"),qe={Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6},Xe={ms:"millisecond",s:"second",m:"minute",h:"hour",d:"day",D:"date",w:"week",W:"isoWeek",M:"month",y:"year",DDD:"dayOfYear",e:"weekday",E:"isoWeekday",gg:"weekYear",GG:"isoWeekYear"},Ze={dayofyear:"dayOfYear",isoweekday:"isoWeekday",isoweek:"isoWeek",weekyear:"weekYear",isoweekyear:"isoWeekYear"},Ke={},$e="DDD w W M D d".split(" "),Qe="M D H h m s w W".split(" "),Je={M:function(){return this.month()+1},MMM:function(t){return this.lang().monthsShort(this,t)},MMMM:function(t){return this.lang().months(this,t)},D:function(){return this.date()},DDD:function(){return this.dayOfYear()},d:function(){return this.day()},dd:function(t){return this.lang().weekdaysMin(this,t)},ddd:function(t){return this.lang().weekdaysShort(this,t)},dddd:function(t){return this.lang().weekdays(this,t)},w:function(){return this.week()},W:function(){return this.isoWeek()},YY:function(){return p(this.year()%100,2)},YYYY:function(){return p(this.year(),4)},YYYYY:function(){return p(this.year(),5)},YYYYYY:function(){var t=this.year(),e=t>=0?"+":"-";return e+p(Math.abs(t),6)},gg:function(){return p(this.weekYear()%100,2)},gggg:function(){return p(this.weekYear(),4)},ggggg:function(){return p(this.weekYear(),5)},GG:function(){return p(this.isoWeekYear()%100,2)},GGGG:function(){return p(this.isoWeekYear(),4)},GGGGG:function(){return p(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.lang().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.lang().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return b(this.milliseconds()/100)},SS:function(){return p(b(this.milliseconds()/10),2)},SSS:function(){return p(this.milliseconds(),3)},SSSS:function(){return p(this.milliseconds(),3)},Z:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(b(t/60),2)+":"+p(b(t)%60,2)},ZZ:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(b(t/60),2)+p(b(t)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},X:function(){return this.unix()},Q:function(){return this.quarter()}},ti=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"];$e.length;)ae=$e.pop(),Je[ae+"o"]=r(Je[ae],ae);for(;Qe.length;)ae=Qe.pop(),Je[ae+ae]=o(Je[ae],2);for(Je.DDDD=o(Je.DDD,3),c(a.prototype,{set:function(t){var e,i;for(i in t)e=t[i],"function"==typeof e?this[i]=e:this["_"+i]=e},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(t){return this._months[t.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(t){return this._monthsShort[t.month()]},monthsParse:function(t){var e,i,n;for(this._monthsParse||(this._monthsParse=[]),e=0;12>e;e++)if(this._monthsParse[e]||(i=re.utc([2e3,e]),n="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[e]=new RegExp(n.replace(".",""),"i")),this._monthsParse[e].test(t))return e},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(t){return this._weekdays[t.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(t){return this._weekdaysShort[t.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(t){return this._weekdaysMin[t.day()]},weekdaysParse:function(t){var e,i,n;for(this._weekdaysParse||(this._weekdaysParse=[]),e=0;7>e;e++)if(this._weekdaysParse[e]||(i=re([2e3,1]).day(e),n="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[e]=new RegExp(n.replace(".",""),"i")),this._weekdaysParse[e].test(t))return e},_longDateFormat:{LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D YYYY",LLL:"MMMM D YYYY LT",LLLL:"dddd, MMMM D YYYY LT"},longDateFormat:function(t){var e=this._longDateFormat[t];return!e&&this._longDateFormat[t.toUpperCase()]&&(e=this._longDateFormat[t.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1) -}),this._longDateFormat[t]=e),e},isPM:function(t){return"p"===(t+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(t,e,i){return t>11?i?"pm":"PM":i?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(t,e){var i=this._calendar[t];return"function"==typeof i?i.apply(e):i},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(t,e,i,n){var s=this._relativeTime[i];return"function"==typeof s?s(t,e,i,n):s.replace(/%d/i,t)},pastFuture:function(t,e){var i=this._relativeTime[t>0?"future":"past"];return"function"==typeof i?i(e):i.replace(/%s/i,e)},ordinal:function(t){return this._ordinal.replace("%d",t)},_ordinal:"%d",preparse:function(t){return t},postformat:function(t){return t},week:function(t){return J(t,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),re=function(t,e,i,o){var r;return"boolean"==typeof i&&(o=i,i=n),r={},r._isAMomentObject=!0,r._i=t,r._f=e,r._l=i,r._strict=o,r._isUTC=!1,r._pf=s(),ee(r)},re.utc=function(t,e,i,o){var r;return"boolean"==typeof i&&(o=i,i=n),r={},r._isAMomentObject=!0,r._useUTC=!0,r._isUTC=!0,r._l=i,r._i=t,r._f=e,r._strict=o,r._pf=s(),ee(r).utc()},re.unix=function(t){return re(1e3*t)},re.duration=function(t,e){var i,n,s,o=t,r=null;return re.isDuration(t)?o={ms:t._milliseconds,d:t._days,M:t._months}:"number"==typeof t?(o={},e?o[e]=t:o.milliseconds=t):(r=Se.exec(t))?(i="-"===r[1]?-1:1,o={y:0,d:b(r[pe])*i,h:b(r[fe])*i,m:b(r[ge])*i,s:b(r[me])*i,ms:b(r[ve])*i}):(r=Ee.exec(t))&&(i="-"===r[1]?-1:1,s=function(t){var e=t&&parseFloat(t.replace(",","."));return(isNaN(e)?0:e)*i},o={y:s(r[2]),M:s(r[3]),d:s(r[4]),h:s(r[5]),m:s(r[6]),s:s(r[7]),w:s(r[8])}),n=new d(o),re.isDuration(t)&&t.hasOwnProperty("_lang")&&(n._lang=t._lang),n},re.version=he,re.defaultFormat=je,re.updateOffset=function(){},re.lang=function(t,e){var i;return t?(e?O(M(t),e):null===e?(I(t),t="en"):ye[t]||N(t),i=re.duration.fn._lang=re.fn._lang=N(t),i._abbr):re.fn._lang._abbr},re.langData=function(t){return t&&t._lang&&t._lang._abbr&&(t=t._lang._abbr),N(t)},re.isMoment=function(t){return t instanceof h||null!=t&&t.hasOwnProperty("_isAMomentObject")},re.isDuration=function(t){return t instanceof d},ae=ti.length-1;ae>=0;--ae)w(ti[ae]);for(re.normalizeUnits=function(t){return y(t)},re.invalid=function(t){var e=re.utc(0/0);return null!=t?c(e._pf,t):e._pf.userInvalidated=!0,e},re.parseZone=function(t){return re(t).parseZone()},c(re.fn=h.prototype,{clone:function(){return re(this)},valueOf:function(){return+this._d+6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().lang("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){var t=re(this).utc();return 00:!1},parsingFlags:function(){return c({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(){return this.zone(0)},local:function(){return this.zone(0),this._isUTC=!1,this},format:function(t){var e=A(this,t||re.defaultFormat);return this.lang().postformat(e)},add:function(t,e){var i;return i="string"==typeof t?re.duration(+e,t):re.duration(t,e),f(this,i,1),this},subtract:function(t,e){var i;return i="string"==typeof t?re.duration(+e,t):re.duration(t,e),f(this,i,-1),this},diff:function(t,e,i){var n,s,o=D(t,this),r=6e4*(this.zone()-o.zone());return e=y(e),"year"===e||"month"===e?(n=432e5*(this.daysInMonth()+o.daysInMonth()),s=12*(this.year()-o.year())+(this.month()-o.month()),s+=(this-re(this).startOf("month")-(o-re(o).startOf("month")))/n,s-=6e4*(this.zone()-re(this).startOf("month").zone()-(o.zone()-re(o).startOf("month").zone()))/n,"year"===e&&(s/=12)):(n=this-o,s="second"===e?n/1e3:"minute"===e?n/6e4:"hour"===e?n/36e5:"day"===e?(n-r)/864e5:"week"===e?(n-r)/6048e5:n),i?s:u(s)},from:function(t,e){return re.duration(this.diff(t)).lang(this.lang()._abbr).humanize(!e)},fromNow:function(t){return this.from(re(),t)},calendar:function(){var t=D(re(),this).startOf("day"),e=this.diff(t,"days",!0),i=-6>e?"sameElse":-1>e?"lastWeek":0>e?"lastDay":1>e?"sameDay":2>e?"nextDay":7>e?"nextWeek":"sameElse";return this.format(this.lang().calendar(i,this))},isLeapYear:function(){return T(this.year())},isDST:function(){return this.zone()+re(t).startOf(e)},isBefore:function(t,e){return e="undefined"!=typeof e?e:"millisecond",+this.clone().startOf(e)<+re(t).startOf(e)},isSame:function(t,e){return e=e||"ms",+this.clone().startOf(e)===+D(t,this).startOf(e)},min:function(t){return t=re.apply(null,arguments),this>t?this:t},max:function(t){return t=re.apply(null,arguments),t>this?this:t},zone:function(t){var e=this._offset||0;return null==t?this._isUTC?e:this._d.getTimezoneOffset():("string"==typeof t&&(t=F(t)),Math.abs(t)<16&&(t=60*t),this._offset=t,this._isUTC=!0,e!==t&&f(this,re.duration(e-t,"m"),1,!0),this)},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.zone(this._tzm):"string"==typeof this._i&&this.zone(this._i),this},hasAlignedHourOffset:function(t){return t=t?re(t).zone():0,(this.zone()-t)%60===0},daysInMonth:function(){return S(this.year(),this.month())},dayOfYear:function(t){var e=ce((re(this).startOf("day")-re(this).startOf("year"))/864e5)+1;return null==t?e:this.add("d",t-e)},quarter:function(){return Math.ceil((this.month()+1)/3)},weekYear:function(t){var e=J(this,this.lang()._week.dow,this.lang()._week.doy).year;return null==t?e:this.add("y",t-e)},isoWeekYear:function(t){var e=J(this,1,4).year;return null==t?e:this.add("y",t-e)},week:function(t){var e=this.lang().week(this);return null==t?e:this.add("d",7*(t-e))},isoWeek:function(t){var e=J(this,1,4).week;return null==t?e:this.add("d",7*(t-e))},weekday:function(t){var e=(this.day()+7-this.lang()._week.dow)%7;return null==t?e:this.add("d",t-e)},isoWeekday:function(t){return null==t?this.day()||7:this.day(this.day()%7?t:t-7)},get:function(t){return t=y(t),this[t]()},set:function(t,e){return t=y(t),"function"==typeof this[t]&&this[t](e),this},lang:function(t){return t===n?this._lang:(this._lang=N(t),this)}}),ae=0;ae-1?!1:"INPUT"==i||"SELECT"==i||"TEXTAREA"==i||e.contentEditable&&"true"==e.contentEditable}function o(t,e){return t.sort().join(",")===e.sort().join(",")}function r(t){t=t||{};var e,i=!1;for(e in M)t[e]?i=!0:M[e]=0;i||(O=!1)}function a(t,e,i,n,s){var r,a,h=[];if(!x[t])return[];for("keyup"==i&&u(t)&&(e=[t]),r=0;r95&&112>t||b.hasOwnProperty(t)&&(_[b[t]]=t)}return _}function g(t,e,i){return i||(i=f()[t]?"keydown":"keypress"),"keypress"==i&&e.length&&(i="keydown"),i}function m(t,e,i,s){M[t]=0,s||(s=g(e[0],[]));var o,a=function(){O=s,++M[t],p()},h=function(t){d(i,t),"keyup"!==s&&(D=n(t)),setTimeout(r,10)};for(o=0;o1)return m(t,d,e,i);for(h="+"===t?["+"]:t.split("+"),o=0;o":".","?":"/","|":"\\"},T={option:"alt",command:"meta","return":"enter",escape:"esc"},x={},C={},M={},D=!1,O=!1,I=1;20>I;++I)b[111+I]="f"+I;for(I=0;9>=I;++I)b[I+96]=I;i(document,"keypress",l),i(document,"keydown",l),i(document,"keyup",l);var N={bind:function(t,e,i){return y(t instanceof Array?t:[t],e,i),C[t+":"+i]=e,this},unbind:function(t,e){return C[t+":"+e]&&(delete C[t+":"+e],this.bind(t,function(){},e)),this},trigger:function(t,e){return C[t+":"+e](),this},reset:function(){return x={},C={},this}};e.exports=N},{}]},{},[1])(1)}); -======= -!function(t){if("object"==typeof exports)module.exports=t();else if("function"==typeof define&&define.amd)define(t);else{var e;"undefined"!=typeof window?e=window:"undefined"!=typeof global?e=global:"undefined"!=typeof self&&(e=self),e.vis=t()}}(function(){var t;return function e(t,i,n){function s(r,a){if(!i[r]){if(!t[r]){var h="function"==typeof require&&require;if(!a&&h)return h(r,!0);if(o)return o(r,!0);throw new Error("Cannot find module '"+r+"'")}var d=i[r]={exports:{}};t[r][0].call(d.exports,function(e){var i=t[r][1][e];return s(i?i:e)},d,d.exports,e,t,i,n)}return i[r].exports}for(var o="function"==typeof require&&require,r=0;ri;++i)t.call(e||this,this[i],i,this)}),Array.prototype.map||(Array.prototype.map=function(t,e){var i,n,s;if(null==this)throw new TypeError(" this is null or not defined");var o=Object(this),r=o.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(e&&(i=e),n=new Array(r),s=0;r>s;){var a,h;s in o&&(a=o[s],h=t.call(i,a,s,o),n[s]=h),s++}return n}),Array.prototype.filter||(Array.prototype.filter=function(t){"use strict";if(null==this)throw new TypeError;var e=Object(this),i=e.length>>>0;if("function"!=typeof t)throw new TypeError;for(var n=[],s=arguments[1],o=0;i>o;o++)if(o in e){var r=e[o];t.call(s,r,o,e)&&n.push(r)}return n}),Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,e=!{toString:null}.propertyIsEnumerable("toString"),i=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],n=i.length;return function(s){if("object"!=typeof s&&"function"!=typeof s||null===s)throw new TypeError("Object.keys called on non-object");var o=[];for(var r in s)t.call(s,r)&&o.push(r);if(e)for(var a=0;n>a;a++)t.call(s,i[a])&&o.push(i[a]);return o}}()),Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s}),Object.create||(Object.create=function(t){function e(){}if(arguments.length>1)throw new Error("Object.create implementation only accepts the first parameter.");return e.prototype=t,new e}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s});var z={};z.isNumber=function(t){return t instanceof Number||"number"==typeof t},z.isString=function(t){return t instanceof String||"string"==typeof t},z.isDate=function(t){if(t instanceof Date)return!0;if(z.isString(t)){var e=P.exec(t);if(e)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},z.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},z.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},z.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var n=arguments[e];for(var s in n)n.hasOwnProperty(s)&&void 0!==n[s]&&(t[s]=n[s])}return t},z.convert=function(t,e){var i;if(void 0===t)return void 0;if(null===t)return null;if(!e)return t;if("string"!=typeof e&&!(e instanceof String))throw new Error("Type must be a string");switch(e){case"boolean":case"Boolean":return Boolean(t);case"number":case"Number":return Number(t.valueOf());case"string":case"String":return String(t);case"Date":if(z.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(L.isMoment(t))return new Date(t.valueOf());if(z.isString(t))return i=P.exec(t),i?new Date(Number(i[1])):L(t).toDate();throw new Error("Cannot convert object of type "+z.getType(t)+" to type Date");case"Moment":if(z.isNumber(t))return L(t);if(t instanceof Date)return L(t.valueOf());if(L.isMoment(t))return L(t);if(z.isString(t))return i=P.exec(t),L(i?Number(i[1]):t);throw new Error("Cannot convert object of type "+z.getType(t)+" to type Date");case"ISODate":if(z.isNumber(t))return new Date(t);if(t instanceof Date)return t.toISOString();if(L.isMoment(t))return t.toDate().toISOString();if(z.isString(t))return i=P.exec(t),i?new Date(Number(i[1])).toISOString():new Date(t).toISOString();throw new Error("Cannot convert object of type "+z.getType(t)+" to type ISODate");case"ASPDate":if(z.isNumber(t))return"/Date("+t+")/";if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(z.isString(t)){i=P.exec(t);var n;return n=i?new Date(Number(i[1])).valueOf():new Date(t).valueOf(),"/Date("+n+")/"}throw new Error("Cannot convert object of type "+z.getType(t)+" to type ASPDate");default:throw new Error("Cannot convert object of type "+z.getType(t)+' to type "'+e+'"')}};var P=/^\/?Date\((\-?\d+)/i;z.getType=function(t){var e=typeof t;return"object"==e?null==t?"null":t instanceof Boolean?"Boolean":t instanceof Number?"Number":t instanceof String?"String":t instanceof Array?"Array":t instanceof Date?"Date":"Object":"number"==e?"Number":"boolean"==e?"Boolean":"string"==e?"String":e},z.getAbsoluteLeft=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetLeft,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetLeft,n-=s.scrollLeft,s=s.offsetParent;return n},z.getAbsoluteTop=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetTop,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetTop,n-=s.scrollTop,s=s.offsetParent;return n},z.getPageY=function(t){if("pageY"in t)return t.pageY;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientY:t.clientY;var i=document.documentElement,n=document.body;return e+(i&&i.scrollTop||n&&n.scrollTop||0)-(i&&i.clientTop||n&&n.clientTop||0)},z.getPageX=function(t){if("pageY"in t)return t.pageX;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientX:t.clientX;var i=document.documentElement,n=document.body;return e+(i&&i.scrollLeft||n&&n.scrollLeft||0)-(i&&i.clientLeft||n&&n.clientLeft||0)},z.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},z.removeClassName=function(t,e){var i=t.className.split(" "),n=i.indexOf(e);-1!=n&&(i.splice(n,1),t.className=i.join(" "))},z.forEach=function(t,e){var i,n;if(t instanceof Array)for(i=0,n=t.length;n>i;i++)e(t[i],i,t);else for(i in t)t.hasOwnProperty(i)&&e(t[i],i,t)},z.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},z.addEventListener=function(t,e,i,n){t.addEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.addEventListener(e,i,n)):t.attachEvent("on"+e,i)},z.removeEventListener=function(t,e,i,n){t.removeEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.removeEventListener(e,i,n)):t.detachEvent("on"+e,i)},z.getTarget=function(t){t||(t=window.event);var e;return t.target?e=t.target:t.srcElement&&(e=t.srcElement),void 0!=e.nodeType&&3==e.nodeType&&(e=e.parentNode),e},z.stopPropagation=function(t){t||(t=window.event),t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},z.fakeGesture=function(t,e){var i=null;return N.event.collectEventData(this,i,e)},z.preventDefault=function(t){t||(t=window.event),t.preventDefault?t.preventDefault():t.returnValue=!1},z.option={},z.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},z.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},z.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?String(t):e||null},z.option.asSize=function(t,e){return"function"==typeof t&&(t=t()),z.isString(t)?t:z.isNumber(t)?t+"px":e||null},z.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null};var F={listeners:[],indexOf:function(t){for(var e=this.listeners,i=0,n=this.listeners.length;n>i;i++){var s=e[i];if(s&&s.object==t)return i}return-1},addListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];s||(s={object:t,events:{}},this.listeners.push(s));var o=s.events[e];o||(o=[],s.events[e]=o),-1==o.indexOf(i)&&o.push(i)},removeListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];o&&(n=o.indexOf(i),-1!=n&&o.splice(n,1),0==o.length&&delete s.events[e]);var r=0,a=s.events;for(var h in a)a.hasOwnProperty(h)&&r++;0==r&&delete this.listeners[n]}},removeAllListeners:function(){this.listeners=[]},trigger:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];if(o)for(var r=0,a=o.length;a>r;r++)o[r](i)}}};s.prototype.on=function(t,e,i){var n=t instanceof RegExp?t:new RegExp(t.replace("*","\\w+")),s={id:z.randomUUID(),event:t,regexp:n,callback:"function"==typeof e?e:null,target:i};return this.subscriptions.push(s),s.id},s.prototype.off=function(t){for(var e=0;eo;o++)i=s._addItem(t[o]),n.push(i);else if(z.isDataTable(t))for(var a=this._getColumnNames(t),h=0,d=t.getNumberOfRows();d>h;h++){for(var c={},l=0,u=a.length;u>l;l++){var p=a[l];c[p]=t.getValue(h,l)}i=s._addItem(c),n.push(i)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");i=s._addItem(t),n.push(i)}return n.length&&this._trigger("add",{items:n},e),n},o.prototype.update=function(t,e){var i=[],n=[],s=this,o=s.fieldId,r=function(t){var e=t[o];s.data[e]?(e=s._updateItem(t),n.push(e)):(e=s._addItem(t),i.push(e))};if(t instanceof Array)for(var a=0,h=t.length;h>a;a++)r(t[a]);else if(z.isDataTable(t))for(var d=this._getColumnNames(t),c=0,l=t.getNumberOfRows();l>c;c++){for(var u={},p=0,f=d.length;f>p;p++){var g=d[p];u[g]=t.getValue(c,p)}r(u)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");r(t)}return i.length&&this._trigger("add",{items:i},e),n.length&&this._trigger("update",{items:n},e),i.concat(n)},o.prototype.get=function(){var t,e,i,n,s=this,o=this.showInternalIds,r=z.getType(arguments[0]);"String"==r||"Number"==r?(t=arguments[0],i=arguments[1],n=arguments[2]):"Array"==r?(e=arguments[0],i=arguments[1],n=arguments[2]):(i=arguments[0],n=arguments[1]);var a;if(i&&i.type){if(a="DataTable"==i.type?"DataTable":"Array",n&&a!=z.getType(n))throw new Error('Type of parameter "data" ('+z.getType(n)+") does not correspond with specified options.type ("+i.type+")");if("DataTable"==a&&!z.isDataTable(n))throw new Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else a=n?"DataTable"==z.getType(n)?"DataTable":"Array":"Array";void 0!=i&&void 0!=i.showInternalIds&&(this.showInternalIds=i.showInternalIds);var h,d,c,l,u=i&&i.convert||this.options.convert,p=i&&i.filter,f=[];if(void 0!=t)h=s._getItem(t,u),p&&!p(h)&&(h=null);else if(void 0!=e)for(c=0,l=e.length;l>c;c++)h=s._getItem(e[c],u),(!p||p(h))&&f.push(h);else for(d in this.data)this.data.hasOwnProperty(d)&&(h=s._getItem(d,u),(!p||p(h))&&f.push(h));if(this.showInternalIds=o,i&&i.order&&void 0==t&&this._sort(f,i.order),i&&i.fields){var g=i.fields;if(void 0!=t)h=this._filterFields(h,g);else for(c=0,l=f.length;l>c;c++)f[c]=this._filterFields(f[c],g)}if("DataTable"==a){var m=this._getColumnNames(n);if(void 0!=t)s._appendRow(n,m,h);else for(c=0,l=f.length;l>c;c++)s._appendRow(n,m,f[c]);return n}if(void 0!=t)return h;if(n){for(c=0,l=f.length;l>c;c++)n.push(f[c]);return n}return f},o.prototype.getIds=function(t){var e,i,n,s,o,r=this.data,a=t&&t.filter,h=t&&t.order,d=t&&t.convert||this.options.convert,c=[];if(a)if(h){o=[];for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,d),a(s)&&o.push(s));for(this._sort(o,h),e=0,i=o.length;i>e;e++)c[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,d),a(s)&&c.push(s[this.fieldId]));else if(h){o=[];for(n in r)r.hasOwnProperty(n)&&o.push(r[n]);for(this._sort(o,h),e=0,i=o.length;i>e;e++)c[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=r[n],c.push(s[this.fieldId]));return c},o.prototype.forEach=function(t,e){var i,n,s=e&&e.filter,o=e&&e.convert||this.options.convert,r=this.data;if(e&&e.order)for(var a=this.get(e),h=0,d=a.length;d>h;h++)i=a[h],n=i[this.fieldId],t(i,n);else for(n in r)r.hasOwnProperty(n)&&(i=this._getItem(n,o),(!s||s(i))&&t(i,n))},o.prototype.map=function(t,e){var i,n=e&&e.filter,s=e&&e.convert||this.options.convert,o=[],r=this.data;for(var a in r)r.hasOwnProperty(a)&&(i=this._getItem(a,s),(!n||n(i))&&o.push(t(i,a)));return e&&e.order&&this._sort(o,e.order),o},o.prototype._filterFields=function(t,e){var i={};for(var n in t)t.hasOwnProperty(n)&&-1!=e.indexOf(n)&&(i[n]=t[n]);return i},o.prototype._sort=function(t,e){if(z.isString(e)){var i=e;t.sort(function(t,e){var n=t[i],s=e[i];return n>s?1:s>n?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},o.prototype.remove=function(t,e){var i,n,s,o=[];if(t instanceof Array)for(i=0,n=t.length;n>i;i++)s=this._remove(t[i]),null!=s&&o.push(s);else s=this._remove(t),null!=s&&o.push(s);return o.length&&this._trigger("remove",{items:o},e),o},o.prototype._remove=function(t){if(z.isNumber(t)||z.isString(t)){if(this.data[t])return delete this.data[t],delete this.internalIds[t],t}else if(t instanceof Object){var e=t[this.fieldId];if(e&&this.data[e])return delete this.data[e],delete this.internalIds[e],e}return null},o.prototype.clear=function(t){var e=Object.keys(this.data);return this.data={},this.internalIds={},this._trigger("remove",{items:e},t),e},o.prototype.max=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||r>n)&&(i=o,n=r)}return i},o.prototype.min=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||n>r)&&(i=o,n=r)}return i},o.prototype.distinct=function(t){var e=this.data,i=[],n=this.options.convert[t],s=0;for(var o in e)if(e.hasOwnProperty(o)){for(var r=e[o],a=z.convert(r[t],n),h=!1,d=0;s>d;d++)if(i[d]==a){h=!0;break}h||(i[s]=a,s++)}return i},o.prototype._addItem=function(t){var e=t[this.fieldId];if(void 0!=e){if(this.data[e])throw new Error("Cannot add item: item with id "+e+" already exists")}else e=z.randomUUID(),t[this.fieldId]=e,this.internalIds[e]=t;var i={};for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=z.convert(t[n],s)}return this.data[e]=i,e},o.prototype._getItem=function(t,e){var i,n,s=this.data[t];if(!s)return null;var o={},r=this.fieldId,a=this.internalIds;if(e)for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a&&!this.showInternalIds||(o[i]=z.convert(n,e[i])));else for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a&&!this.showInternalIds||(o[i]=n));return o},o.prototype._updateItem=function(t){var e=t[this.fieldId];if(void 0==e)throw new Error("Cannot update item: item has no id (item: "+JSON.stringify(t)+")");var i=this.data[e];if(!i)throw new Error("Cannot update item: no item with id "+e+" found");for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=z.convert(t[n],s)}return e},o.prototype.isInternalId=function(t){return t in this.internalIds},o.prototype._getColumnNames=function(t){for(var e=[],i=0,n=t.getNumberOfColumns();n>i;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},o.prototype._appendRow=function(t,e,i){for(var n=t.addRow(),s=0,o=e.length;o>s;s++){var r=e[s];t.setValue(n,s,i[r])}},r.prototype.setData=function(t){var e,i,n;if(this.data){this.data.unsubscribe&&this.data.unsubscribe("*",this.listener),e=[];for(var s in this.ids)this.ids.hasOwnProperty(s)&&e.push(s);this.ids={},this._trigger("remove",{items:e})}if(this.data=t,this.data){for(this.fieldId=this.options.fieldId||this.data&&this.data.options&&this.data.options.fieldId||"id",e=this.data.getIds({filter:this.options&&this.options.filter}),i=0,n=e.length;n>i;i++)s=e[i],this.ids[s]=!0;this._trigger("add",{items:e}),this.data.subscribe&&this.data.subscribe("*",this.listener)}},r.prototype.get=function(){var t,e,i,n=this,s=z.getType(arguments[0]);"String"==s||"Number"==s||"Array"==s?(t=arguments[0],e=arguments[1],i=arguments[2]):(e=arguments[0],i=arguments[1]);var o=z.extend({},this.options,e);this.options.filter&&e&&e.filter&&(o.filter=function(t){return n.options.filter(t)&&e.filter(t)});var r=[];return void 0!=t&&r.push(t),r.push(o),r.push(i),this.data&&this.data.get.apply(this.data,r)},r.prototype.getIds=function(t){var e;if(this.data){var i,n=this.options.filter;i=t&&t.filter?n?function(e){return n(e)&&t.filter(e)}:t.filter:n,e=this.data.getIds({filter:i,order:t&&t.order})}else e=[];return e},r.prototype._onEvent=function(t,e,i){var n,s,o,r,a=e&&e.items,h=this.data,d=[],c=[],l=[];if(a&&h){switch(t){case"add":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r&&(this.ids[o]=!0,d.push(o));break;case"update":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r?this.ids[o]?c.push(o):(this.ids[o]=!0,d.push(o)):this.ids[o]&&(delete this.ids[o],l.push(o));break;case"remove":for(n=0,s=a.length;s>n;n++)o=a[n],this.ids[o]&&(delete this.ids[o],l.push(o))}d.length&&this._trigger("add",{items:d},i),c.length&&this._trigger("update",{items:c},i),l.length&&this._trigger("remove",{items:l},i)}},r.prototype.subscribe=o.prototype.subscribe,r.prototype.unsubscribe=o.prototype.unsubscribe,r.prototype._trigger=o.prototype._trigger,TimeStep=function(t,e,i){this.current=new Date,this._start=new Date,this._end=new Date,this.autoScale=!0,this.scale=TimeStep.SCALE.DAY,this.step=1,this.setRange(t,e,i)},TimeStep.SCALE={MILLISECOND:1,SECOND:2,MINUTE:3,HOUR:4,DAY:5,WEEKDAY:6,MONTH:7,YEAR:8},TimeStep.prototype.setRange=function(t,e,i){if(!(t instanceof Date&&e instanceof Date))throw"No legal start or end date in method setRange";this._start=void 0!=t?new Date(t.valueOf()):new Date,this._end=void 0!=e?new Date(e.valueOf()):new Date,this.autoScale&&this.setMinimumStep(i)},TimeStep.prototype.first=function(){this.current=new Date(this._start.valueOf()),this.roundToMinor()},TimeStep.prototype.roundToMinor=function(){switch(this.scale){case TimeStep.SCALE.YEAR:this.current.setFullYear(this.step*Math.floor(this.current.getFullYear()/this.step)),this.current.setMonth(0);case TimeStep.SCALE.MONTH:this.current.setDate(1);case TimeStep.SCALE.DAY:case TimeStep.SCALE.WEEKDAY:this.current.setHours(0);case TimeStep.SCALE.HOUR:this.current.setMinutes(0);case TimeStep.SCALE.MINUTE:this.current.setSeconds(0);case TimeStep.SCALE.SECOND:this.current.setMilliseconds(0)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.setMilliseconds(this.current.getMilliseconds()-this.current.getMilliseconds()%this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()-this.current.getSeconds()%this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()-this.current.getMinutes()%this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()-this.current.getHours()%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()-1-(this.current.getDate()-1)%this.step+1);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()-this.current.getMonth()%this.step); -break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()-this.current.getFullYear()%this.step)}},TimeStep.prototype.hasNext=function(){return this.current.valueOf()<=this._end.valueOf()},TimeStep.prototype.next=function(){var t=this.current.valueOf();if(this.current.getMonth()<6)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current=new Date(this.current.valueOf()+1e3*this.step);break;case TimeStep.SCALE.MINUTE:this.current=new Date(this.current.valueOf()+1e3*this.step*60);break;case TimeStep.SCALE.HOUR:this.current=new Date(this.current.valueOf()+1e3*this.step*60*60);var e=this.current.getHours();this.current.setHours(e-e%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}else switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()+this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()+this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()+this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.getMilliseconds()0&&(this.step=e),this.autoScale=!1},TimeStep.prototype.setAutoScale=function(t){this.autoScale=t},TimeStep.prototype.setMinimumStep=function(t){if(void 0!=t){var e=31104e6,i=2592e6,n=864e5,s=36e5,o=6e4,r=1e3,a=1;1e3*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1e3),500*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=500),100*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=100),50*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=50),10*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=10),5*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=5),e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1),3*i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=3),i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=1),5*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=5),2*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=2),n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=1),n/2>t&&(this.scale=TimeStep.SCALE.WEEKDAY,this.step=1),4*s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=4),s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=1),15*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=15),10*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=10),5*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=5),o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=1),15*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=15),10*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=10),5*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=5),r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=1),200*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=200),100*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=100),50*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=50),10*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=10),5*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=5),a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=1)}},TimeStep.prototype.snap=function(t){if(this.scale==TimeStep.SCALE.YEAR){var e=t.getFullYear()+Math.round(t.getMonth()/12);t.setFullYear(Math.round(e/this.step)*this.step),t.setMonth(0),t.setDate(0),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MONTH)t.getDate()>15?(t.setDate(1),t.setMonth(t.getMonth()+1)):t.setDate(1),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0);else if(this.scale==TimeStep.SCALE.DAY||this.scale==TimeStep.SCALE.WEEKDAY){switch(this.step){case 5:case 2:t.setHours(24*Math.round(t.getHours()/24));break;default:t.setHours(12*Math.round(t.getHours()/12))}t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.HOUR){switch(this.step){case 4:t.setMinutes(60*Math.round(t.getMinutes()/60));break;default:t.setMinutes(30*Math.round(t.getMinutes()/30))}t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MINUTE){switch(this.step){case 15:case 10:t.setMinutes(5*Math.round(t.getMinutes()/5)),t.setSeconds(0);break;case 5:t.setSeconds(60*Math.round(t.getSeconds()/60));break;default:t.setSeconds(30*Math.round(t.getSeconds()/30))}t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.SECOND)switch(this.step){case 15:case 10:t.setSeconds(5*Math.round(t.getSeconds()/5)),t.setMilliseconds(0);break;case 5:t.setMilliseconds(1e3*Math.round(t.getMilliseconds()/1e3));break;default:t.setMilliseconds(500*Math.round(t.getMilliseconds()/500))}else if(this.scale==TimeStep.SCALE.MILLISECOND){var i=this.step>5?this.step/2:1;t.setMilliseconds(Math.round(t.getMilliseconds()/i)*i)}},TimeStep.prototype.isMajor=function(){switch(this.scale){case TimeStep.SCALE.MILLISECOND:return 0==this.current.getMilliseconds();case TimeStep.SCALE.SECOND:return 0==this.current.getSeconds();case TimeStep.SCALE.MINUTE:return 0==this.current.getHours()&&0==this.current.getMinutes();case TimeStep.SCALE.HOUR:return 0==this.current.getHours();case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return 1==this.current.getDate();case TimeStep.SCALE.MONTH:return 0==this.current.getMonth();case TimeStep.SCALE.YEAR:return!1;default:return!1}},TimeStep.prototype.getLabelMinor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return L(t).format("SSS");case TimeStep.SCALE.SECOND:return L(t).format("s");case TimeStep.SCALE.MINUTE:return L(t).format("HH:mm");case TimeStep.SCALE.HOUR:return L(t).format("HH:mm");case TimeStep.SCALE.WEEKDAY:return L(t).format("ddd D");case TimeStep.SCALE.DAY:return L(t).format("D");case TimeStep.SCALE.MONTH:return L(t).format("MMM");case TimeStep.SCALE.YEAR:return L(t).format("YYYY");default:return""}},TimeStep.prototype.getLabelMajor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return L(t).format("HH:mm:ss");case TimeStep.SCALE.SECOND:return L(t).format("D MMMM HH:mm");case TimeStep.SCALE.MINUTE:case TimeStep.SCALE.HOUR:return L(t).format("ddd D MMMM");case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return L(t).format("MMMM YYYY");case TimeStep.SCALE.MONTH:return L(t).format("YYYY");case TimeStep.SCALE.YEAR:return"";default:return""}},a.prototype.setOptions=function(t){z.extend(this.options,t)},a.prototype.update=function(){this._order(),this._stack()},a.prototype._order=function(){var t=this.parent.items;if(!t)throw new Error("Cannot stack items: parent does not contain items");var e=[],i=0;z.forEach(t,function(t){t.visible&&(e[i]=t,i++)});var n=this.options.order||this.defaultOptions.order;if("function"!=typeof n)throw new Error("Option order must be a function");e.sort(n),this.ordered=e},a.prototype._stack=function(){var t,e,i,n=this.ordered,s=this.options,o=s.orientation||this.defaultOptions.orientation,r="top"==o;for(i=s.margin&&void 0!==s.margin.item?s.margin.item:this.defaultOptions.margin.item,t=0,e=n.length;e>t;t++){var a=n[t],h=null;do h=this.checkOverlap(n,t,0,t-1,i),null!=h&&(a.top=r?h.top+h.height+i:h.top-a.height-i);while(h)}},a.prototype.checkOverlap=function(t,e,i,n,s){for(var o=this.collision,r=t[e],a=n;a>=i;a--){var h=t[a];if(o(r,h,s)&&a!=e)return h}return null},a.prototype.collision=function(t,e,i){return t.left-ie.left&&t.top-ie.top},h.prototype.setOptions=function(t){z.extend(this.options,t),null!==this.start&&null!==this.end&&this.setRange(this.start,this.end)},h.prototype.subscribe=function(t,e,i){function n(e){s._onMouseWheel(e,t,i)}var s=this;if("move"==e)t.on("dragstart",function(e){s._onDragStart(e,t)}),t.on("drag",function(e){s._onDrag(e,t,i)}),t.on("dragend",function(e){s._onDragEnd(e,t)});else{if("zoom"!=e)throw new TypeError('Unknown event "'+e+'". Choose "move" or "zoom".');t.on("mousewheel",n),t.on("DOMMouseScroll",n),t.on("touch",function(){s._onTouch()}),t.on("pinch",function(e){s._onPinch(e,t,i)})}},h.prototype.on=function(t,e){var i=["rangechange","rangechanged"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());F.addListener(this,t,e)},h.prototype.off=function(t,e){F.removeListener(this,t,e)},h.prototype._trigger=function(t){F.trigger(this,t,{start:this.start,end:this.end})},h.prototype.setRange=function(t,e){var i=this._applyRange(t,e);i&&(this._trigger("rangechange"),this._trigger("rangechanged"))},h.prototype._applyRange=function(t,e){var i,n=null!=t?z.convert(t,"Date").valueOf():this.start,s=null!=e?z.convert(e,"Date").valueOf():this.end,o=null!=this.options.max?z.convert(this.options.max,"Date").valueOf():null,r=null!=this.options.min?z.convert(this.options.min,"Date").valueOf():null;if(isNaN(n)||null===n)throw new Error('Invalid start "'+t+'"');if(isNaN(s)||null===s)throw new Error('Invalid end "'+e+'"');if(n>s&&(s=n),null!==r&&r>n&&(i=r-n,n+=i,s+=i,null!=o&&s>o&&(s=o)),null!==o&&s>o&&(i=s-o,n-=i,s-=i,null!=r&&r>n&&(n=r)),null!==this.options.zoomMin){var a=parseFloat(this.options.zoomMin);0>a&&(a=0),a>s-n&&(this.end-this.start===a?(n=this.start,s=this.end):(i=a-(s-n),n-=i/2,s+=i/2))}if(null!==this.options.zoomMax){var h=parseFloat(this.options.zoomMax);0>h&&(h=0),s-n>h&&(this.end-this.start===h?(n=this.start,s=this.end):(i=s-n-h,n+=i/2,s-=i/2))}var d=this.start!=n||this.end!=s;return this.start=n,this.end=s,d},h.prototype.getRange=function(){return{start:this.start,end:this.end}},h.prototype.conversion=function(t){return h.conversion(this.start,this.end,t)},h.conversion=function(t,e,i){return 0!=i&&e-t!=0?{offset:t,scale:i/(e-t)}:{offset:0,scale:1}};var Y={};h.prototype._onDragStart=function(t,e){if(!Y.pinching){Y.start=this.start,Y.end=this.end;var i=e.frame;i&&(i.style.cursor="move")}},h.prototype._onDrag=function(t,e,i){if(d(i),!Y.pinching){var n="horizontal"==i?t.gesture.deltaX:t.gesture.deltaY,s=Y.end-Y.start,o="horizontal"==i?e.width:e.height,r=-n/o*s;this._applyRange(Y.start+r,Y.end+r),this._trigger("rangechange")}},h.prototype._onDragEnd=function(t,e){Y.pinching||(e.frame&&(e.frame.style.cursor="auto"),this._trigger("rangechanged"))},h.prototype._onMouseWheel=function(t,e,i){d(i);var n=0;if(t.wheelDelta?n=t.wheelDelta/120:t.detail&&(n=-t.detail/3),n){var s;s=0>n?1-n/5:1/(1+n/5);var o=z.fakeGesture(this,t),r=c(o.touches[0],e.frame),a=this._pointerToDate(e,i,r);this.zoom(s,a)}z.preventDefault(t)},h.prototype._onTouch=function(){Y.start=this.start,Y.end=this.end,Y.pinching=!1,Y.center=null},h.prototype._onPinch=function(t,e,i){if(Y.pinching=!0,t.gesture.touches.length>1){Y.center||(Y.center=c(t.gesture.center,e.frame));var n=1/t.gesture.scale,s=this._pointerToDate(e,i,Y.center),o=c(t.gesture.center,e.frame),r=(this._pointerToDate(e,i,o),parseInt(s+(Y.start-s)*n)),a=parseInt(s+(Y.end-s)*n);this.setRange(r,a)}},h.prototype._pointerToDate=function(t,e,i){var n;if("horizontal"==e){var s=t.width;return n=this.conversion(s),i.x/n.scale+n.offset}var o=t.height;return n=this.conversion(o),i.y/n.scale+n.offset},h.prototype.zoom=function(t,e){null==e&&(e=(this.start+this.end)/2);var i=e+(this.start-e)*t,n=e+(this.end-e)*t;this.setRange(i,n)},h.prototype.move=function(t){var e=this.end-this.start,i=this.start+e*t,n=this.end+e*t;this.start=i,this.end=n},h.prototype.moveTo=function(t){var e=(this.start+this.end)/2,i=e-t,n=this.start-i,s=this.end-i;this.setRange(n,s)},l.prototype.add=function(t){if(void 0==t.id)throw new Error("Component has no field id");if(!(t instanceof u||t instanceof l))throw new TypeError("Component must be an instance of prototype Component or Controller");t.controller=this,this.components[t.id]=t},l.prototype.remove=function(t){var e;for(e in this.components)if(this.components.hasOwnProperty(e)&&(e==t||this.components[e]==t))break;e&&delete this.components[e]},l.prototype.requestReflow=function(t){if(t)this.reflow();else if(!this.reflowTimer){var e=this;this.reflowTimer=setTimeout(function(){e.reflowTimer=void 0,e.reflow()},0)}},l.prototype.requestRepaint=function(t){if(t)this.repaint();else if(!this.repaintTimer){var e=this;this.repaintTimer=setTimeout(function(){e.repaintTimer=void 0,e.repaint()},0)}},l.prototype.repaint=function V(){function V(i,n){n in e||(i.depends&&i.depends.forEach(function(t){V(t,t.id)}),i.parent&&V(i.parent,i.parent.id),t=i.repaint()||t,e[n]=!0)}var t=!1;this.repaintTimer&&(clearTimeout(this.repaintTimer),this.repaintTimer=void 0);var e={};z.forEach(this.components,V),t&&this.reflow()},l.prototype.reflow=function G(){function G(i,n){n in e||(i.depends&&i.depends.forEach(function(t){G(t,t.id)}),i.parent&&G(i.parent,i.parent.id),t=i.reflow()||t,e[n]=!0)}var t=!1;this.reflowTimer&&(clearTimeout(this.reflowTimer),this.reflowTimer=void 0);var e={};z.forEach(this.components,G),t&&this.repaint()},u.prototype.setOptions=function(t){t&&(z.extend(this.options,t),this.controller&&(this.requestRepaint(),this.requestReflow()))},u.prototype.getOption=function(t){var e;return this.options&&(e=this.options[t]),void 0===e&&this.defaultOptions&&(e=this.defaultOptions[t]),e},u.prototype.getContainer=function(){return null},u.prototype.getFrame=function(){return this.frame},u.prototype.repaint=function(){return!1},u.prototype.reflow=function(){return!1},u.prototype.hide=function(){return this.frame&&this.frame.parentNode?(this.frame.parentNode.removeChild(this.frame),!0):!1},u.prototype.show=function(){return this.frame&&this.frame.parentNode?!1:this.repaint()},u.prototype.requestRepaint=function(){if(!this.controller)throw new Error("Cannot request a repaint: no controller configured");this.controller.requestRepaint()},u.prototype.requestReflow=function(){if(!this.controller)throw new Error("Cannot request a reflow: no controller configured");this.controller.requestReflow()},p.prototype=new u,p.prototype.setOptions=u.prototype.setOptions,p.prototype.getContainer=function(){return this.frame},p.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.frame;if(!s){s=document.createElement("div"),s.className="panel";var o=n.className;o&&("function"==typeof o?z.addClassName(s,String(o())):z.addClassName(s,String(o))),this.frame=s,t+=1}if(!s.parentNode){if(!this.parent)throw new Error("Cannot repaint panel: no parent attached");var r=this.parent.getContainer();if(!r)throw new Error("Cannot repaint panel: parent has no container element");r.appendChild(s),t+=1}return t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),t>0},p.prototype.reflow=function(){var t=0,e=z.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},f.prototype=new p,f.prototype.setOptions=u.prototype.setOptions,f.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.frame;if(s||(s=document.createElement("div"),this.frame=s,t+=1),!s.parentNode){if(!this.container)throw new Error("Cannot repaint root panel: no container attached");this.container.appendChild(s),t+=1}s.className="vis timeline rootpanel "+n.orientation;var o=n.className;return o&&z.addClassName(s,z.option.asString(o)),t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),this._updateEventEmitters(),this._updateWatch(),t>0},f.prototype.reflow=function(){var t=0,e=z.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},f.prototype._updateWatch=function(){var t=this.getOption("autoResize");t?this._watch():this._unwatch()},f.prototype._watch=function(){var t=this;this._unwatch();var e=function(){var e=t.getOption("autoResize");return e?void(t.frame&&(t.frame.clientWidth!=t.width||t.frame.clientHeight!=t.height)&&t.requestReflow()):void t._unwatch()};z.addEventListener(window,"resize",e),this.watchTimer=setInterval(e,1e3)},f.prototype._unwatch=function(){this.watchTimer&&(clearInterval(this.watchTimer),this.watchTimer=void 0)},f.prototype.on=function(t,e){var i=this.listeners[t];i||(i=[],this.listeners[t]=i),i.push(e),this._updateEventEmitters()},f.prototype._updateEventEmitters=function(){if(this.listeners){var t=this;z.forEach(this.listeners,function(e,i){if(t.emitters||(t.emitters={}),!(i in t.emitters)){var n=t.frame;if(n){var s=function(t){e.forEach(function(e){e(t)})};t.emitters[i]=s,t.hammer||(t.hammer=N(n,{prevent_default:!0})),t.hammer.on(i,s)}}})}},g.prototype=new u,g.prototype.setOptions=u.prototype.setOptions,g.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},g.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},g.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},g.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.props,r=this.step,a=this.frame;if(a||(a=document.createElement("div"),this.frame=a,t+=1),a.className="axis",!a.parentNode){if(!this.parent)throw new Error("Cannot repaint time axis: no parent attached");var h=this.parent.getContainer();if(!h)throw new Error("Cannot repaint time axis: parent has no container element");h.appendChild(a),t+=1}var d=a.parentNode;if(d){var c=a.nextSibling;d.removeChild(a);var l="bottom"==s&&this.props.parentHeight&&this.height?this.props.parentHeight-this.height+"px":"0px";if(t+=e(a.style,"top",i(n.top,l)),t+=e(a.style,"left",i(n.left,"0px")),t+=e(a.style,"width",i(n.width,"100%")),t+=e(a.style,"height",i(n.height,this.height+"px")),this._repaintMeasureChars(),this.step){this._repaintStart(),r.first();for(var u=void 0,p=0;r.hasNext()&&1e3>p;){p++;var f=r.getCurrent(),g=this.toScreen(f),m=r.isMajor();this.getOption("showMinorLabels")&&this._repaintMinorText(g,r.getLabelMinor()),m&&this.getOption("showMajorLabels")?(g>0&&(void 0==u&&(u=g),this._repaintMajorText(g,r.getLabelMajor())),this._repaintMajorLine(g)):this._repaintMinorLine(g),r.next()}if(this.getOption("showMajorLabels")){var v=this.toTime(0),y=r.getLabelMajor(v),_=y.length*(o.majorCharWidth||10)+10;(void 0==u||u>_)&&this._repaintMajorText(0,y)}this._repaintEnd()}this._repaintLine(),c?d.insertBefore(a,c):d.appendChild(a)}return t>0},g.prototype._repaintStart=function(){var t=this.dom,e=t.redundant;e.majorLines=t.majorLines,e.majorTexts=t.majorTexts,e.minorLines=t.minorLines,e.minorTexts=t.minorTexts,t.majorLines=[],t.majorTexts=[],t.minorLines=[],t.minorTexts=[]},g.prototype._repaintEnd=function(){z.forEach(this.dom.redundant,function(t){for(;t.length;){var e=t.pop();e&&e.parentNode&&e.parentNode.removeChild(e)}})},g.prototype._repaintMinorText=function(t,e){var i=this.dom.redundant.minorTexts.shift();if(!i){var n=document.createTextNode("");i=document.createElement("div"),i.appendChild(n),i.className="text minor",this.frame.appendChild(i)}this.dom.minorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.left=t+"px",i.style.top=this.props.minorLabelTop+"px"},g.prototype._repaintMajorText=function(t,e){var i=this.dom.redundant.majorTexts.shift();if(!i){var n=document.createTextNode(e);i=document.createElement("div"),i.className="text major",i.appendChild(n),this.frame.appendChild(i)}this.dom.majorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.top=this.props.majorLabelTop+"px",i.style.left=t+"px"},g.prototype._repaintMinorLine=function(t){var e=this.dom.redundant.minorLines.shift();e||(e=document.createElement("div"),e.className="grid vertical minor",this.frame.appendChild(e)),this.dom.minorLines.push(e);var i=this.props;e.style.top=i.minorLineTop+"px",e.style.height=i.minorLineHeight+"px",e.style.left=t-i.minorLineWidth/2+"px"},g.prototype._repaintMajorLine=function(t){var e=this.dom.redundant.majorLines.shift();e||(e=document.createElement("DIV"),e.className="grid vertical major",this.frame.appendChild(e)),this.dom.majorLines.push(e);var i=this.props;e.style.top=i.majorLineTop+"px",e.style.left=t-i.majorLineWidth/2+"px",e.style.height=i.majorLineHeight+"px"},g.prototype._repaintLine=function(){{var t=this.dom.line,e=this.frame;this.options}this.getOption("showMinorLabels")||this.getOption("showMajorLabels")?(t?(e.removeChild(t),e.appendChild(t)):(t=document.createElement("div"),t.className="grid horizontal major",e.appendChild(t),this.dom.line=t),t.style.top=this.props.lineTop+"px"):t&&t.parentElement&&(e.removeChild(t.line),delete this.dom.line)},g.prototype._repaintMeasureChars=function(){var t,e=this.dom;if(!e.measureCharMinor){t=document.createTextNode("0");var i=document.createElement("DIV");i.className="text minor measure",i.appendChild(t),this.frame.appendChild(i),e.measureCharMinor=i}if(!e.measureCharMajor){t=document.createTextNode("0");var n=document.createElement("DIV");n.className="text major measure",n.appendChild(t),this.frame.appendChild(n),e.measureCharMajor=n}},g.prototype.reflow=function(){var t=0,e=z.updateProperty,i=this.frame,n=this.range;if(!n)throw new Error("Cannot repaint time axis: no range configured");if(i){t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft);var s=this.props,o=this.getOption("showMinorLabels"),r=this.getOption("showMajorLabels"),a=this.dom.measureCharMinor,h=this.dom.measureCharMajor;a&&(s.minorCharHeight=a.clientHeight,s.minorCharWidth=a.clientWidth),h&&(s.majorCharHeight=h.clientHeight,s.majorCharWidth=h.clientWidth);var d=i.parentNode?i.parentNode.offsetHeight:0;switch(d!=s.parentHeight&&(s.parentHeight=d,t+=1),this.getOption("orientation")){case"bottom":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.minorLabelTop=0,s.majorLabelTop=s.minorLabelTop+s.minorLabelHeight,s.minorLineTop=-this.top,s.minorLineHeight=Math.max(this.top+s.majorLabelHeight,0),s.minorLineWidth=1,s.majorLineTop=-this.top,s.majorLineHeight=Math.max(this.top+s.minorLabelHeight+s.majorLabelHeight,0),s.majorLineWidth=1,s.lineTop=0;break;case"top":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.majorLabelTop=0,s.minorLabelTop=s.majorLabelTop+s.majorLabelHeight,s.minorLineTop=s.minorLabelTop,s.minorLineHeight=Math.max(d-s.majorLabelHeight-this.top),s.minorLineWidth=1,s.majorLineTop=0,s.majorLineHeight=Math.max(d-this.top),s.majorLineWidth=1,s.lineTop=s.majorLabelHeight+s.minorLabelHeight;break;default:throw new Error('Unkown orientation "'+this.getOption("orientation")+'"')}var c=s.minorLabelHeight+s.majorLabelHeight;t+=e(this,"width",i.offsetWidth),t+=e(this,"height",c),this._updateConversion();var l=z.convert(n.start,"Number"),u=z.convert(n.end,"Number"),p=this.toTime(5*(s.minorCharWidth||10)).valueOf()-this.toTime(0).valueOf();this.step=new TimeStep(new Date(l),new Date(u),p),t+=e(s.range,"start",l),t+=e(s.range,"end",u),t+=e(s.range,"minimumStep",p.valueOf())}return t>0},g.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},m.prototype=new u,m.prototype.setOptions=u.prototype.setOptions,m.prototype.getContainer=function(){return this.frame},m.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCurrentTime"))return void(t&&(i.removeChild(t),delete this.frame));t||(t=document.createElement("div"),t.className="currenttime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t),this.frame=t),e.conversion||e._updateConversion();var n=new Date,s=e.toScreen(n);t.style.left=s+"px",t.title="Current time: "+n,void 0!==this.currentTimeTimer&&(clearTimeout(this.currentTimeTimer),delete this.currentTimeTimer);var o=this,r=1/e.conversion.scale/2;return 30>r&&(r=30),this.currentTimeTimer=setTimeout(function(){o.repaint()},r),!1},v.prototype=new u,v.prototype.setOptions=u.prototype.setOptions,v.prototype.getContainer=function(){return this.frame},v.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCustomTime"))return void(t&&(i.removeChild(t),delete this.frame));if(!t){t=document.createElement("div"),t.className="customtime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t);var n=document.createElement("div");n.style.position="relative",n.style.top="0px",n.style.left="-10px",n.style.height="100%",n.style.width="20px",t.appendChild(n),this.frame=t,this.subscribe(this,"movetime")}e.conversion||e._updateConversion();var s=e.toScreen(this.customTime);return t.style.left=s+"px",t.title="Time: "+this.customTime,!1},v.prototype._setCustomTime=function(t){this.customTime=new Date(t.valueOf()),this.repaint()},v.prototype._getCustomTime=function(){return new Date(this.customTime.valueOf())},v.prototype.subscribe=function(t,e){var i=this,n={component:t,event:e,callback:function(t){i._onMouseDown(t,n)},params:{}};t.on("mousedown",n.callback),i.listeners.push(n)},v.prototype.on=function(t,e){var i=this.frame;if(!i)throw new Error("Cannot add event listener: no parent attached");F.addListener(this,t,e),z.addEventListener(i,t,e)},v.prototype._onMouseDown=function(t,e){t=t||window.event;var i=e.params,n=t.which?1==t.which:1==t.button;if(n){i.mouseX=z.getPageX(t),i.moved=!1,i.customTime=this.customTime;var s=this;i.onMouseMove||(i.onMouseMove=function(t){s._onMouseMove(t,e)},z.addEventListener(document,"mousemove",i.onMouseMove)),i.onMouseUp||(i.onMouseUp=function(t){s._onMouseUp(t,e)},z.addEventListener(document,"mouseup",i.onMouseUp)),z.stopPropagation(t),z.preventDefault(t)}},v.prototype._onMouseMove=function(t,e){t=t||window.event;var i=e.params,n=this.parent,s=z.getPageX(t);void 0===i.mouseX&&(i.mouseX=s);var o=s-i.mouseX;Math.abs(o)>=1&&(i.moved=!0);var r=n.toScreen(i.customTime),a=r+o,h=n.toTime(a);this._setCustomTime(h),F.trigger(this,"timechange",{customTime:this.customTime}),z.preventDefault(t)},v.prototype._onMouseUp=function(t,e){t=t||window.event;var i=e.params;i.onMouseMove&&(z.removeEventListener(document,"mousemove",i.onMouseMove),i.onMouseMove=null),i.onMouseUp&&(z.removeEventListener(document,"mouseup",i.onMouseUp),i.onMouseUp=null),i.moved&&F.trigger(this,"timechanged",{customTime:this.customTime})},y.prototype=new p,y.types={box:w,range:S,rangeoverflow:E,point:b},y.prototype.setOptions=u.prototype.setOptions,y.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},y.prototype.setSelection=function(t){var e,i,n,s,o;if(t){if(!Array.isArray(t))throw new TypeError("Array expected");for(e=0,i=this.selection.length;i>e;e++)n=this.selection[e],s=this.items[n],s&&s.unselect();for(this.selection=[],e=0,i=t.length;i>e;e++)n=t[e],s=this.items[n],s&&(this.selection.push(n),s.select());o=this.selection.concat([]),F.trigger(this,"select",{ids:o}),this.controller&&this.requestRepaint()}},y.prototype.getSelection=function(){return this.selection.concat([])},y.prototype._deselect=function(t){for(var e=this.selection,i=0,n=e.length;n>i;i++)if(e[i]==t){e.splice(i,1);break}},y.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.defaultOptions,r=this.frame;if(!r){r=document.createElement("div"),r.className="itemset";var a=n.className;a&&z.addClassName(r,z.option.asString(a));var h=document.createElement("div");h.className="background",r.appendChild(h),this.dom.background=h;var d=document.createElement("div");d.className="foreground",r.appendChild(d),this.dom.foreground=d;var c=document.createElement("div");c.className="itemset-axis",this.dom.axis=c,this.frame=r,t+=1}if(!this.parent)throw new Error("Cannot repaint itemset: no parent attached");var l=this.parent.getContainer();if(!l)throw new Error("Cannot repaint itemset: parent has no container element");r.parentNode||(l.appendChild(r),t+=1),this.dom.axis.parentNode||(l.appendChild(this.dom.axis),t+=1),t+=e(r.style,"left",i(n.left,"0px")),t+=e(r.style,"top",i(n.top,"0px")),t+=e(r.style,"width",i(n.width,"100%")),t+=e(r.style,"height",i(n.height,this.height+"px")),t+=e(this.dom.axis.style,"left",i(n.left,"0px")),t+=e(this.dom.axis.style,"width",i(n.width,"100%")),t+="bottom"==s?e(this.dom.axis.style,"top",this.height+this.top+"px"):e(this.dom.axis.style,"top",this.top+"px"),this._updateConversion();var u=this,p=this.queue,f=this.itemsData,g=this.items,m={};for(var v in p)if(p.hasOwnProperty(v)){var _=p[v],w=g[v],b=_.action;switch(b){case"add":case"update":var S=f&&f.get(v,m);if(S){var E=S.type||S.start&&S.end&&"range"||n.type||"box",T=y.types[E];if(w&&(T&&w instanceof T?(w.data=S,t++):(t+=w.hide(),w=null)),!w){if(!T)throw new TypeError('Unknown item type "'+E+'"');w=new T(u,S,n,o),w.id=_.id,t++}w.repaint(),g[v]=w}delete p[v];break;case"remove":w&&(w.selected&&u._deselect(v),t+=w.hide()),delete g[v],delete p[v];break;default:console.log('Error: unknown action "'+b+'"')}}return z.forEach(this.items,function(e){e.visible?(t+=e.show(),e.reposition()):t+=e.hide()}),t>0},y.prototype.getForeground=function(){return this.dom.foreground},y.prototype.getBackground=function(){return this.dom.background},y.prototype.getAxis=function(){return this.dom.axis},y.prototype.reflow=function(){var t=0,e=this.options,i=e.margin&&e.margin.axis||this.defaultOptions.margin.axis,n=e.margin&&e.margin.item||this.defaultOptions.margin.item,s=z.updateProperty,o=z.option.asNumber,r=z.option.asSize,a=this.frame;if(a){this._updateConversion(),z.forEach(this.items,function(e){t+=e.reflow()}),this.stack.update();var h,d=o(e.maxHeight),c=null!=r(e.height);if(c)h=a.offsetHeight;else{var l=this.stack.ordered;if(l.length){var u=l[0].top,p=l[0].top+l[0].height;z.forEach(l,function(t){u=Math.min(u,t.top),p=Math.max(p,t.top+t.height)}),h=p-u+i+n}else h=i+n}null!=d&&(h=Math.min(h,d)),t+=s(this,"height",h),t+=s(this,"top",a.offsetTop),t+=s(this,"left",a.offsetLeft),t+=s(this,"width",a.offsetWidth)}else t+=1;return t>0},y.prototype.hide=function(){var t=!1;return this.frame&&this.frame.parentNode&&(this.frame.parentNode.removeChild(this.frame),t=!0),this.dom.axis&&this.dom.axis.parentNode&&(this.dom.axis.parentNode.removeChild(this.dom.axis),t=!0),t -},y.prototype.setItems=function(t){var e,i=this,n=this.itemsData;if(t){if(!(t instanceof o||t instanceof r))throw new TypeError("Data must be an instance of DataSet");this.itemsData=t}else this.itemsData=null;if(n&&(z.forEach(this.listeners,function(t,e){n.unsubscribe(e,t)}),e=n.getIds(),this._onRemove(e)),this.itemsData){var s=this.id;z.forEach(this.listeners,function(t,e){i.itemsData.subscribe(e,t,s)}),e=this.itemsData.getIds(),this._onAdd(e)}},y.prototype.getItems=function(){return this.itemsData},y.prototype._onUpdate=function(t){this._toQueue("update",t)},y.prototype._onAdd=function(t){this._toQueue("add",t)},y.prototype._onRemove=function(t){this._toQueue("remove",t)},y.prototype._toQueue=function(t,e){var i=this.queue;e.forEach(function(e){i[e]={id:e,action:t}}),this.controller&&this.requestRepaint()},y.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},y.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},y.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},_.prototype.select=function(){this.selected=!0,this.visible&&this.repaint()},_.prototype.unselect=function(){this.selected=!1,this.visible&&this.repaint()},_.prototype.show=function(){return!1},_.prototype.hide=function(){return!1},_.prototype.repaint=function(){return!1},_.prototype.reflow=function(){return!1},_.prototype.getWidth=function(){return this.width},w.prototype=new _(null,null),w.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");if(!e.box.parentNode){var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");i.appendChild(e.box),t=!0}if(!e.line.parentNode){var n=this.parent.getBackground();if(!n)throw new Error("Cannot repaint time axis: parent has no background container element");n.appendChild(e.line),t=!0}if(!e.dot.parentNode){var s=this.parent.getAxis();if(!n)throw new Error("Cannot repaint time axis: parent has no axis container element");s.appendChild(e.dot),t=!0}if(this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var o=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=o&&(this.className=o,e.box.className="item box"+o,e.line.className="item line"+o,e.dot.className="item dot"+o,t=!0)}return t},w.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},w.prototype.hide=function(){var t=!1,e=this.dom;return e&&(e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),e.line.parentNode&&e.line.parentNode.removeChild(e.line),e.dot.parentNode&&e.dot.parentNode.removeChild(e.dot)),t},w.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,d,c,l,u=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(c=this.data,l=this.parent&&this.parent.range,c&&l){var p=l.end-l.start;this.visible=c.start>l.start-p&&c.start0},w.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("DIV"),t.content=document.createElement("DIV"),t.content.className="content",t.box.appendChild(t.content),t.line=document.createElement("DIV"),t.line.className="line",t.dot=document.createElement("DIV"),t.dot.className="dot",t.box["timeline-item"]=this)},w.prototype.reposition=function(){var t=this.dom,e=this.props,i=this.options.orientation||this.defaultOptions.orientation;if(t){var n=t.box,s=t.line,o=t.dot;n.style.left=this.left+"px",n.style.top=this.top+"px",s.style.left=e.line.left+"px","top"==i?(s.style.top="0px",s.style.height=this.top+"px"):(s.style.top=this.top+this.height+"px",s.style.height=Math.max(this.parent.height-this.top-this.height+this.props.dot.height/2,0)+"px"),o.style.left=e.dot.left+"px",o.style.top=e.dot.top+"px"}},b.prototype=new _(null,null),b.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.point.parentNode||(i.appendChild(e.point),i.appendChild(e.point),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.point.className="item point"+n,t=!0)}return t},b.prototype.show=function(){return this.dom&&this.dom.point.parentNode?!1:this.repaint()},b.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.point.parentNode&&(e.point.parentNode.removeChild(e.point),t=!0),t},b.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,d,c=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(h=this.data,d=this.parent&&this.parent.range,h&&d){var l=d.end-d.start;this.visible=h.start>d.start-l&&h.start0},b.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.point=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.point.appendChild(t.content),t.dot=document.createElement("div"),t.dot.className="dot",t.point.appendChild(t.dot),t.point["timeline-item"]=this)},b.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.point.style.top=this.top+"px",t.point.style.left=this.left+"px",t.content.style.marginLeft=e.content.marginLeft+"px",t.dot.style.top=e.dot.top+"px")},S.prototype=new _(null,null),S.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.box.className="item range"+n,t=!0)}return t},S.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},S.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),t},S.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,d,c,l,u,p,f,g,m=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(void 0==this.data.end)throw new Error('Property "end" missing in item '+this.data.id);return h=this.data,d=this.parent&&this.parent.range,this.visible=h&&d?h.startd.start:!1,this.visible&&(t=this.dom,t?(e=this.props,i=this.options,o=this.parent,r=o.toScreen(this.data.start),a=o.toScreen(this.data.end),c=z.updateProperty,l=t.box,u=o.width,f=i.orientation||this.defaultOptions.orientation,n=i.margin&&i.margin.axis||this.defaultOptions.margin.axis,s=i.padding||this.defaultOptions.padding,m+=c(e.content,"width",t.content.offsetWidth),m+=c(this,"height",l.offsetHeight),-u>r&&(r=-u),a>2*u&&(a=2*u),p=0>r?Math.min(-r,a-r-e.content.width-2*s):0,m+=c(e.content,"left",p),"top"==f?(g=n,m+=c(this,"top",g)):(g=o.height-this.height-n,m+=c(this,"top",g)),m+=c(this,"left",r),m+=c(this,"width",Math.max(a-r,1))):m+=1),m>0},S.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content),t.box["timeline-item"]=this)},S.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.box.style.top=this.top+"px",t.box.style.left=this.left+"px",t.box.style.width=this.width+"px",t.content.style.left=e.content.left+"px")},E.prototype=new S(null,null),E.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=this.data.className?" "+this.data.className:"";this.className!=n&&(this.className=n,e.box.className="item rangeoverflow"+n,t=!0)}return t},E.prototype.getWidth=function(){return void 0!==this.props.content&&this.width0},x.prototype=new p,x.prototype.setOptions=u.prototype.setOptions,x.prototype.setRange=function(){},x.prototype.setItems=function(t){this.itemsData=t;for(var e in this.groups)if(this.groups.hasOwnProperty(e)){var i=this.groups[e];i.setItems(t)}},x.prototype.getItems=function(){return this.itemsData},x.prototype.setRange=function(t){this.range=t},x.prototype.setGroups=function(t){var e,i=this;if(this.groupsData&&(z.forEach(this.listeners,function(t,e){i.groupsData.unsubscribe(e,t)}),e=this.groupsData.getIds(),this._onRemove(e)),t?t instanceof o?this.groupsData=t:(this.groupsData=new o({convert:{start:"Date",end:"Date"}}),this.groupsData.add(t)):this.groupsData=null,this.groupsData){var n=this.id;z.forEach(this.listeners,function(t,e){i.groupsData.subscribe(e,t,n)}),e=this.groupsData.getIds(),this._onAdd(e)}},x.prototype.getGroups=function(){return this.groupsData},x.prototype.setSelection=function(t){var e=[],i=this.groups;for(var n in i)if(i.hasOwnProperty(n)){var s=i[n];s.setSelection(t)}return e},x.prototype.getSelection=function(){var t=[],e=this.groups;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];t=t.concat(n.getSelection())}return t},x.prototype.repaint=function(){var t,e,i,n,s=0,o=z.updateProperty,r=z.option.asSize,a=z.option.asElement,h=this.options,d=this.dom.frame,c=this.dom.labels,l=this.dom.labelSet;if(!this.parent)throw new Error("Cannot repaint groupset: no parent attached");var u=this.parent.getContainer();if(!u)throw new Error("Cannot repaint groupset: parent has no container element");if(!d){d=document.createElement("div"),d.className="groupset",this.dom.frame=d;var p=h.className;p&&z.addClassName(d,z.option.asString(p)),s+=1}d.parentNode||(u.appendChild(d),s+=1);var f=a(h.labelContainer);if(!f)throw new Error('Cannot repaint groupset: option "labelContainer" not defined');c||(c=document.createElement("div"),c.className="labels",this.dom.labels=c),l||(l=document.createElement("div"),l.className="label-set",c.appendChild(l),this.dom.labelSet=l),c.parentNode&&c.parentNode==f||(c.parentNode&&c.parentNode.removeChild(c.parentNode),f.appendChild(c)),s+=o(d.style,"height",r(h.height,this.height+"px")),s+=o(d.style,"top",r(h.top,"0px")),s+=o(d.style,"left",r(h.left,"0px")),s+=o(d.style,"width",r(h.width,"100%")),s+=o(l.style,"top",r(h.top,"0px")),s+=o(l.style,"height",r(h.height,this.height+"px"));var g=this,m=this.queue,v=this.groups,y=this.groupsData,_=Object.keys(m);if(_.length){_.forEach(function(t){var e=m[t],i=v[t];switch(e){case"add":case"update":if(!i){var n=Object.create(g.options);z.extend(n,{height:null,maxHeight:null}),i=new T(g,t,n),i.setItems(g.itemsData),v[t]=i,g.controller.add(i)}i.data=y.get(t),delete m[t];break;case"remove":i&&(i.setItems(),delete v[t],g.controller.remove(i)),delete m[t];break;default:console.log('Error: unknown action "'+e+'"')}});var w=this.groupsData.getIds({order:this.options.groupOrder});for(t=0;t0},x.prototype._createLabel=function(t){var e=this.groups[t],i=document.createElement("div");i.className="label";var n=document.createElement("div");n.className="inner",i.appendChild(n);var s=e.data&&e.data.content;s instanceof Element?n.appendChild(s):void 0!=s&&(n.innerHTML=s);var o=e.data&&e.data.className;return o&&z.addClassName(i,o),e.label=i,i},x.prototype.getContainer=function(){return this.dom.frame},x.prototype.getLabelsWidth=function(){return this.props.labels.width},x.prototype.reflow=function(){var t,e,i=0,n=this.options,s=z.updateProperty,o=z.option.asNumber,r=z.option.asSize,a=this.dom.frame;if(a){var h,d=o(n.maxHeight),c=null!=r(n.height);if(c)h=a.offsetHeight;else{h=0;for(t in this.groups)this.groups.hasOwnProperty(t)&&(e=this.groups[t],h+=e.height)}null!=d&&(h=Math.min(h,d)),i+=s(this,"height",h),i+=s(this,"top",a.offsetTop),i+=s(this,"left",a.offsetLeft),i+=s(this,"width",a.offsetWidth)}var l=0;for(t in this.groups)if(this.groups.hasOwnProperty(t)){e=this.groups[t];var u=e.props&&e.props.label&&e.props.label.width||0;l=Math.max(l,u)}return i+=s(this.props.labels,"width",l),i>0},x.prototype.hide=function(){return this.dom.frame&&this.dom.frame.parentNode?(this.dom.frame.parentNode.removeChild(this.dom.frame),!0):!1},x.prototype.show=function(){return this.dom.frame&&this.dom.frame.parentNode?!1:this.repaint()},x.prototype._onUpdate=function(t){this._toQueue(t,"update")},x.prototype._onAdd=function(t){this._toQueue(t,"add")},x.prototype._onRemove=function(t){this._toQueue(t,"remove")},x.prototype._toQueue=function(t,e){var i=this.queue;t.forEach(function(t){i[t]=e}),this.controller&&this.requestRepaint()},C.prototype.setOptions=function(t){z.extend(this.options,t),this.range.setRange(t.start,t.end),this.controller.reflow(),this.controller.repaint()},C.prototype.setCustomTime=function(t){this.customtime._setCustomTime(t)},C.prototype.getCustomTime=function(){return new Date(this.customtime.customTime.valueOf())},C.prototype.setItems=function(t){var e,i=null==this.itemsData;if(t?t instanceof o&&(e=t):e=null,t instanceof o||(e=new o({convert:{start:"Date",end:"Date"}}),e.add(t)),this.itemsData=e,this.content.setItems(e),i&&(void 0==this.options.start||void 0==this.options.end)){var n=this.getItemRange(),s=n.min,r=n.max;if(null!=s&&null!=r){var a=r.valueOf()-s.valueOf();0>=a&&(a=864e5),s=new Date(s.valueOf()-.05*a),r=new Date(r.valueOf()+.05*a)}void 0!=this.options.start&&(s=z.convert(this.options.start,"Date")),void 0!=this.options.end&&(r=z.convert(this.options.end,"Date")),(null!=s||null!=r)&&this.range.setRange(s,r)}},C.prototype.setGroups=function(t){var e=this;this.groupsData=t;var i=this.groupsData?x:y;if(!(this.content instanceof i)){this.content&&(this.content.hide(),this.content.setItems&&this.content.setItems(),this.content.setGroups&&this.content.setGroups(),this.controller.remove(this.content));var n=Object.create(this.options);z.extend(n,{top:function(){return"top"==e.options.orientation?e.timeaxis.height:e.itemPanel.height-e.timeaxis.height-e.content.height},left:null,width:"100%",height:function(){return e.options.height?e.itemPanel.height-e.timeaxis.height:null},maxHeight:function(){if(e.options.maxHeight){if(!z.isNumber(e.options.maxHeight))throw new TypeError("Number expected for property maxHeight");return e.options.maxHeight-e.timeaxis.height}return null},labelContainer:function(){return e.labelPanel.getContainer()}}),this.content=new i(this.itemPanel,[this.timeaxis],n),this.content.setRange&&this.content.setRange(this.range),this.content.setItems&&this.content.setItems(this.itemsData),this.content.setGroups&&this.content.setGroups(this.groupsData),this.controller.add(this.content)}},C.prototype.getItemRange=function(){var t=this.itemsData,e=null,i=null;if(t){var n=t.min("start");e=n?n.start.valueOf():null;var s=t.max("start");s&&(i=s.start.valueOf());var o=t.max("end");o&&(i=null==i?o.end.valueOf():Math.max(i,o.end.valueOf()))}return{min:null!=e?new Date(e):null,max:null!=i?new Date(i):null}},C.prototype.setSelection=function(t){this.content&&this.content.setSelection(t)},C.prototype.getSelection=function(){return this.content?this.content.getSelection():[]},C.prototype.on=function(t,e){var i=["rangechange","rangechanged","select"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());F.addListener(this,t,e)},C.prototype.off=function(t,e){F.removeListener(this,t,e)},C.prototype._trigger=function(t,e){F.trigger(this,t,e||{})},C.prototype._onSelectItem=function(t){var e=this._itemFromTarget(t),i=e?[e.id]:[];this.setSelection(i),this._trigger("select",{items:this.getSelection()}),t.stopPropagation()},C.prototype._onMultiSelectItem=function(t){var e,i=this._itemFromTarget(t);if(i){e=this.getSelection();var n=e.indexOf(i.id);-1==n?e.push(i.id):e.splice(n,1),this.setSelection(e),this._trigger("select",{items:this.getSelection()}),t.stopPropagation()}},C.prototype._itemFromTarget=function(t){for(var e=t.target;e;){if(e.hasOwnProperty("timeline-item"))return e["timeline-item"];e=e.parentNode}return null},function(t){function e(t){return C=t,u()}function i(){M=0,D=C.charAt(0)}function n(){M++,D=C.charAt(M)}function s(){return C.charAt(M+1)}function o(t){return N.test(t)}function r(t,e){if(t||(t={}),e)for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function a(t,e,i){for(var n=e.split("."),s=t;n.length;){var o=n.shift();n.length?(s[o]||(s[o]={}),s=s[o]):s[o]=i}}function h(t,e){for(var i,n,s=null,o=[t],a=t;a.parent;)o.push(a.parent),a=a.parent;if(a.nodes)for(i=0,n=a.nodes.length;n>i;i++)if(e.id===a.nodes[i].id){s=a.nodes[i];break}for(s||(s={id:e.id},t.node&&(s.attr=r(s.attr,t.node))),i=o.length-1;i>=0;i--){var h=o[i];h.nodes||(h.nodes=[]),-1==h.nodes.indexOf(s)&&h.nodes.push(s)}e.attr&&(s.attr=r(s.attr,e.attr))}function d(t,e){if(t.edges||(t.edges=[]),t.edges.push(e),t.edge){var i=r({},t.edge);e.attr=r(i,e.attr)}}function c(t,e,i,n,s){var o={from:e,to:i,type:n};return t.edge&&(o.attr=r({},t.edge)),o.attr=r(o.attr||{},s),o}function l(){for(O=T.NULL,I="";" "==D||" "==D||"\n"==D||"\r"==D;)n();do{var t=!1;if("#"==D){for(var e=M-1;" "==C.charAt(e)||" "==C.charAt(e);)e--;if("\n"==C.charAt(e)||""==C.charAt(e)){for(;""!=D&&"\n"!=D;)n();t=!0}}if("/"==D&&"/"==s()){for(;""!=D&&"\n"!=D;)n();t=!0}if("/"==D&&"*"==s()){for(;""!=D;){if("*"==D&&"/"==s()){n(),n();break}n()}t=!0}for(;" "==D||" "==D||"\n"==D||"\r"==D;)n()}while(t);if(""==D)return void(O=T.DELIMITER);var i=D+s();if(x[i])return O=T.DELIMITER,I=i,n(),void n();if(x[D])return O=T.DELIMITER,I=D,void n();if(o(D)||"-"==D){for(I+=D,n();o(D);)I+=D,n();return"false"==I?I=!1:"true"==I?I=!0:isNaN(Number(I))||(I=Number(I)),void(O=T.IDENTIFIER)}if('"'==D){for(n();""!=D&&('"'!=D||'"'==D&&'"'==s());)I+=D,'"'==D&&n(),n();if('"'!=D)throw w('End of string " expected');return n(),void(O=T.IDENTIFIER)}for(O=T.UNKNOWN;""!=D;)I+=D,n();throw new SyntaxError('Syntax error in part "'+b(I,30)+'"')}function u(){var t={};if(i(),l(),"strict"==I&&(t.strict=!0,l()),("graph"==I||"digraph"==I)&&(t.type=I,l()),O==T.IDENTIFIER&&(t.id=I,l()),"{"!=I)throw w("Angle bracket { expected");if(l(),p(t),"}"!=I)throw w("Angle bracket } expected");if(l(),""!==I)throw w("End of file expected");return l(),delete t.node,delete t.edge,delete t.graph,t}function p(t){for(;""!==I&&"}"!=I;)f(t),";"==I&&l()}function f(t){var e=g(t);if(e)return void y(t,e);var i=m(t);if(!i){if(O!=T.IDENTIFIER)throw w("Identifier expected");var n=I;if(l(),"="==I){if(l(),O!=T.IDENTIFIER)throw w("Identifier expected");t[n]=I,l()}else v(t,n)}}function g(t){var e=null;if("subgraph"==I&&(e={},e.type="subgraph",l(),O==T.IDENTIFIER&&(e.id=I,l())),"{"==I){if(l(),e||(e={}),e.parent=t,e.node=t.node,e.edge=t.edge,e.graph=t.graph,p(e),"}"!=I)throw w("Angle bracket } expected");l(),delete e.node,delete e.edge,delete e.graph,delete e.parent,t.subgraphs||(t.subgraphs=[]),t.subgraphs.push(e)}return e}function m(t){return"node"==I?(l(),t.node=_(),"node"):"edge"==I?(l(),t.edge=_(),"edge"):"graph"==I?(l(),t.graph=_(),"graph"):null}function v(t,e){var i={id:e},n=_();n&&(i.attr=n),h(t,i),y(t,e)}function y(t,e){for(;"->"==I||"--"==I;){var i,n=I;l();var s=g(t);if(s)i=s;else{if(O!=T.IDENTIFIER)throw w("Identifier or subgraph expected");i=I,h(t,{id:i}),l()}var o=_(),r=c(t,e,i,n,o);d(t,r),e=i}}function _(){for(var t=null;"["==I;){for(l(),t={};""!==I&&"]"!=I;){if(O!=T.IDENTIFIER)throw w("Attribute name expected");var e=I;if(l(),"="!=I)throw w("Equal sign = expected");if(l(),O!=T.IDENTIFIER)throw w("Attribute value expected");var i=I;a(t,e,i),l(),","==I&&l()}if("]"!=I)throw w("Bracket ] expected");l()}return t}function w(t){return new SyntaxError(t+', got "'+b(I,30)+'" (char '+M+")")}function b(t,e){return t.length<=e?t:t.substr(0,27)+"..."}function S(t,e,i){t instanceof Array?t.forEach(function(t){e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}):e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}function E(t){function i(t){var e={from:t.from,to:t.to};return r(e,t.attr),e.style="->"==t.type?"arrow":"line",e}var n=e(t),s={nodes:[],edges:[],options:{}};return n.nodes&&n.nodes.forEach(function(t){var e={id:t.id,label:String(t.label||t.id)};r(e,t.attr),e.image&&(e.shape="image"),s.nodes.push(e)}),n.edges&&n.edges.forEach(function(t){var e,n;e=t.from instanceof Object?t.from.nodes:{id:t.from},n=t.to instanceof Object?t.to.nodes:{id:t.to},t.from instanceof Object&&t.from.edges&&t.from.edges.forEach(function(t){var e=i(t);s.edges.push(e)}),S(e,n,function(e,n){var o=c(s,e.id,n.id,t.type,t.attr),r=i(o);s.edges.push(r)}),t.to instanceof Object&&t.to.edges&&t.to.edges.forEach(function(t){var e=i(t);s.edges.push(e)})}),n.attr&&(s.options=n.attr),s}var T={NULL:0,DELIMITER:1,IDENTIFIER:2,UNKNOWN:3},x={"{":!0,"}":!0,"[":!0,"]":!0,";":!0,"=":!0,",":!0,"->":!0,"--":!0},C="",M=0,D="",I="",O=T.NULL,N=/[a-zA-Z_0-9.:#]/;t.parseDOT=e,t.DOTToGraph=E}("undefined"!=typeof z?z:n),"undefined"!=typeof CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.circle=function(t,e,i){this.beginPath(),this.arc(t,e,i,0,2*Math.PI,!1)},CanvasRenderingContext2D.prototype.square=function(t,e,i){this.beginPath(),this.rect(t-i,e-i,2*i,2*i)},CanvasRenderingContext2D.prototype.triangle=function(t,e,i){this.beginPath();var n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e-(r-o)),this.lineTo(t+s,e+o),this.lineTo(t-s,e+o),this.lineTo(t,e-(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.triangleDown=function(t,e,i){this.beginPath();var n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e+(r-o)),this.lineTo(t+s,e-o),this.lineTo(t-s,e-o),this.lineTo(t,e+(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.star=function(t,e,i){this.beginPath();for(var n=0;10>n;n++){var s=n%2===0?1.3*i:.5*i;this.lineTo(t+s*Math.sin(2*n*Math.PI/10),e-s*Math.cos(2*n*Math.PI/10))}this.closePath()},CanvasRenderingContext2D.prototype.roundRect=function(t,e,i,n,s){var o=Math.PI/180;0>i-2*s&&(s=i/2),0>n-2*s&&(s=n/2),this.beginPath(),this.moveTo(t+s,e),this.lineTo(t+i-s,e),this.arc(t+i-s,e+s,s,270*o,360*o,!1),this.lineTo(t+i,e+n-s),this.arc(t+i-s,e+n-s,s,0,90*o,!1),this.lineTo(t+s,e+n),this.arc(t+s,e+n-s,s,90*o,180*o,!1),this.lineTo(t,e+s),this.arc(t+s,e+s,s,180*o,270*o,!1)},CanvasRenderingContext2D.prototype.ellipse=function(t,e,i,n){var s=.5522848,o=i/2*s,r=n/2*s,a=t+i,h=e+n,d=t+i/2,c=e+n/2;this.beginPath(),this.moveTo(t,c),this.bezierCurveTo(t,c-r,d-o,e,d,e),this.bezierCurveTo(d+o,e,a,c-r,a,c),this.bezierCurveTo(a,c+r,d+o,h,d,h),this.bezierCurveTo(d-o,h,t,c+r,t,c)},CanvasRenderingContext2D.prototype.database=function(t,e,i,n){var s=1/3,o=i,r=n*s,a=.5522848,h=o/2*a,d=r/2*a,c=t+o,l=e+r,u=t+o/2,p=e+r/2,f=e+(n-r/2),g=e+n;this.beginPath(),this.moveTo(c,p),this.bezierCurveTo(c,p+d,u+h,l,u,l),this.bezierCurveTo(u-h,l,t,p+d,t,p),this.bezierCurveTo(t,p-d,u-h,e,u,e),this.bezierCurveTo(u+h,e,c,p-d,c,p),this.lineTo(c,f),this.bezierCurveTo(c,f+d,u+h,g,u,g),this.bezierCurveTo(u-h,g,t,f+d,t,f),this.lineTo(t,p)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,n){var s=t-n*Math.cos(i),o=e-n*Math.sin(i),r=t-.9*n*Math.cos(i),a=e-.9*n*Math.sin(i),h=s+n/3*Math.cos(i+.5*Math.PI),d=o+n/3*Math.sin(i+.5*Math.PI),c=s+n/3*Math.cos(i-.5*Math.PI),l=o+n/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,d),this.lineTo(r,a),this.lineTo(c,l),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,n,s){s||(s=[10,5]),0==u&&(u=.001);var o=s.length;this.moveTo(t,e);for(var r=i-t,a=n-e,h=a/r,d=Math.sqrt(r*r+a*a),c=0,l=!0;d>=.1;){var u=s[c++%o];u>d&&(u=d);var p=Math.sqrt(u*u/(1+h*h));0>r&&(p=-p),t+=p,e+=h*p,this[l?"lineTo":"moveTo"](t,e),d-=u,l=!l}}),M.prototype.resetCluster=function(){this.formationScale=void 0,this.clusterSize=1,this.containedNodes={},this.containedEdges={},this.clusterSessions=[]},M.prototype.attachEdge=function(t){-1==this.edges.indexOf(t)&&this.edges.push(t),-1==this.dynamicEdges.indexOf(t)&&this.dynamicEdges.push(t),this.dynamicEdgesLength=this.dynamicEdges.length,this._updateMass()},M.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&(this.edges.splice(e,1),this.dynamicEdges.splice(e,1)),this.dynamicEdgesLength=this.dynamicEdges.length,this._updateMass()},M.prototype._updateMass=function(){this.mass=1+.6*this.edges.length},M.prototype.setProperties=function(t,e){if(t){if(this.originalLabel=void 0,void 0!==t.id&&(this.id=t.id),void 0!==t.label&&(this.label=t.label,this.originalLabel=t.label),void 0!==t.title&&(this.title=t.title),void 0!==t.group&&(this.group=t.group),void 0!==t.x&&(this.x=t.x),void 0!==t.y&&(this.y=t.y),void 0!==t.value&&(this.value=t.value),void 0!==t.horizontalAlignLeft&&(this.horizontalAlignLeft=t.horizontalAlignLeft),void 0!==t.verticalAlignTop&&(this.verticalAlignTop=t.verticalAlignTop),void 0!==t.triggerFunction&&(this.triggerFunction=t.triggerFunction),void 0===this.id)throw"Node must have an id";if(this.group){var i=this.grouplist.get(this.group);for(var n in i)i.hasOwnProperty(n)&&(this[n]=i[n])}if(void 0!==t.shape&&(this.shape=t.shape),void 0!==t.image&&(this.image=t.image),void 0!==t.radius&&(this.radius=t.radius),void 0!==t.color&&(this.color=M.parseColor(t.color)),void 0!==t.fontColor&&(this.fontColor=t.fontColor),void 0!==t.fontSize&&(this.fontSize=t.fontSize),void 0!==t.fontFace&&(this.fontFace=t.fontFace),void 0!==this.image){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.image)}switch(this.xFixed=this.xFixed||void 0!==t.x,this.yFixed=this.yFixed||void 0!==t.y,this.radiusFixed=this.radiusFixed||void 0!==t.radius,"image"==this.shape&&(this.radiusMin=e.nodes.widthMin,this.radiusMax=e.nodes.widthMax),this.shape){case"database":this.draw=this._drawDatabase,this.resize=this._resizeDatabase;break;case"box":this.draw=this._drawBox,this.resize=this._resizeBox;break;case"circle":this.draw=this._drawCircle,this.resize=this._resizeCircle;break;case"ellipse":this.draw=this._drawEllipse,this.resize=this._resizeEllipse;break;case"image":this.draw=this._drawImage,this.resize=this._resizeImage;break;case"text":this.draw=this._drawText,this.resize=this._resizeText;break;case"dot":this.draw=this._drawDot,this.resize=this._resizeShape;break;case"square":this.draw=this._drawSquare,this.resize=this._resizeShape;break;case"triangle":this.draw=this._drawTriangle,this.resize=this._resizeShape;break;case"triangleDown":this.draw=this._drawTriangleDown,this.resize=this._resizeShape;break;case"star":this.draw=this._drawStar,this.resize=this._resizeShape;break;default:this.draw=this._drawEllipse,this.resize=this._resizeEllipse}this._reset()}},M.parseColor=function(t){var e;return z.isString(t)?e={border:t,background:t,highlight:{border:t,background:t}}:(e={},e.background=t.background||"white",e.border=t.border||e.background,z.isString(t.highlight)?e.highlight={border:t.highlight,background:t.highlight}:(e.highlight={},e.highlight.background=t.highlight&&t.highlight.background||e.background,e.highlight.border=t.highlight&&t.highlight.border||e.border)),e},M.prototype.select=function(){this.selected=!0,this._reset()},M.prototype.unselect=function(){this.selected=!1,this._reset()},M.prototype.clearSizeCache=function(){this._reset()},M.prototype._reset=function(){this.width=void 0,this.height=void 0},M.prototype.getTitle=function(){return this.title},M.prototype.distanceToBorder=function(t,e){var i=1;switch(this.width||this.resize(t),this.shape){case"circle":case"dot":return this.radius+i;case"ellipse":var n=this.width/2,s=this.height/2,o=Math.sin(e)*n,r=Math.cos(e)*s; -return n*s/Math.sqrt(o*o+r*r);case"box":case"image":case"text":default:return this.width?Math.min(Math.abs(this.width/2/Math.cos(e)),Math.abs(this.height/2/Math.sin(e)))+i:0}},M.prototype._setForce=function(t,e){this.fx=t,this.fy=e},M.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},M.prototype.discreteStep=function(t){if(!this.xFixed){var e=-this.damping*this.vx,i=(this.fx+e)/this.mass;this.vx+=i*t,this.x+=this.vx*t}if(!this.yFixed){var n=-this.damping*this.vy,s=(this.fy+n)/this.mass;this.vy+=s*t,this.y+=this.vy*t}},M.prototype.isFixed=function(){return this.xFixed&&this.yFixed},M.prototype.isMoving=function(t){return Math.abs(this.vx)>t||Math.abs(this.vy)>t?!0:(this.vx=0,this.vy=0,!1)},M.prototype.isSelected=function(){return this.selected},M.prototype.getValue=function(){return this.value},M.prototype.getDistance=function(t,e){var i=this.x-t,n=this.y-e;return Math.sqrt(i*i+n*n)},M.prototype.setValueRange=function(t,e){if(!this.radiusFixed&&void 0!==this.value)if(e==t)this.radius=(this.radiusMin+this.radiusMax)/2;else{var i=(this.radiusMax-this.radiusMin)/(e-t);this.radius=(this.value-t)*i+this.radiusMin}this.baseRadiusValue=this.radius},M.prototype.draw=function(){throw"Draw method not initialized for node"},M.prototype.resize=function(){throw"Resize method not initialized for node"},M.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},M.prototype._resizeImage=function(){if(!this.width||!this.height){var t,e;if(this.value){this.radius=this.baseRadiusValue;var i=this.imageObj.height/this.imageObj.width;void 0!==i?(t=this.radius||this.imageObj.width,e=this.radius*i||this.imageObj.height):(t=0,e=0)}else t=this.imageObj.width,e=this.imageObj.height;this.width=t,this.height=e,this.width>0&&this.height>0&&(this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor)}},M.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e;if(0!=this.imageObj.width){if(this.clusterSize>1){var i=this.clusterSize>1?10:0;i*=this.graphScaleInv,i=Math.min(.2*this.width,i),t.globalAlpha=.5,t.drawImage(this.imageObj,this.left-i,this.top-i,this.width+2*i,this.height+2*i)}t.globalAlpha=1,t.drawImage(this.imageObj,this.left,this.top,this.width,this.height),e=this.y+this.height/2}else e=this.y;this._label(t,this.label,this.x,e,void 0,"top")},M.prototype._resizeBox=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=.5*(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=.5*(this.clusterSize-1)*this.clusterSizeHeightFactor}},M.prototype._drawBox=function(t){this._resizeBox(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.roundRect(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth,this.radius),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.roundRect(this.left,this.top,this.width,this.height,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeDatabase=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=i.width+2*e;this.width=n,this.height=n,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawDatabase=function(t){this._resizeDatabase(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.database(this.x-this.width/2-2*t.lineWidth,this.y-.5*this.height-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.database(this.x-this.width/2,this.y-.5*this.height,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=Math.max(i.width,i.height)+2*e;this.radius=n/2,this.width=n,this.height=n,this.radius+=.5*(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawCircle=function(t){this._resizeCircle(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.circle(this.x,this.y,this.radius+2*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.circle(this.x,this.y,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeEllipse=function(t){if(!this.width){var e=this.getTextSize(t);this.width=1.5*e.width,this.height=2*e.height,this.width1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.ellipse(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.ellipse(this.left,this.top,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._drawDot=function(t){this._drawShape(t,"circle")},M.prototype._drawTriangle=function(t){this._drawShape(t,"triangle")},M.prototype._drawTriangleDown=function(t){this._drawShape(t,"triangleDown")},M.prototype._drawSquare=function(t){this._drawShape(t,"square")},M.prototype._drawStar=function(t){this._drawShape(t,"star")},M.prototype._resizeShape=function(){if(!this.width){this.radius=this.baseRadiusValue;var t=2*this.radius;this.width=t,this.height=t,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=.5*(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawShape=function(t,e){this._resizeShape(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var i=2.5,n=2,s=2;switch(e){case"dot":s=2;break;case"square":s=2;break;case"triangle":s=3;break;case"triangleDown":s=3;break;case"star":s=4}t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?n:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t[e](this.x,this.y,this.radius+s*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?n:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t[e](this.x,this.y,this.radius),t.fill(),t.stroke(),this.label&&this._label(t,this.label,this.x,this.y+this.height/2,void 0,"top")},M.prototype._resizeText=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawText=function(t){this._resizeText(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,this._label(t,this.label,this.x,this.y)},M.prototype._label=function(t,e,i,n,s,o){if(e){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle=this.fontColor||"black",t.textAlign=s||"center",t.textBaseline=o||"middle";for(var r=e.split("\n"),a=r.length,h=this.fontSize+4,d=n+(1-a)/2*h,c=0;a>c;c++)t.fillText(r[c],i,d),d+=h}},M.prototype.getTextSize=function(t){if(void 0!==this.label){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace;for(var e=this.label.split("\n"),i=(this.fontSize+4)*e.length,n=0,s=0,o=e.length;o>s;s++)n=Math.max(n,t.measureText(e[s]).width);return{width:n,height:i}}return{width:0,height:0}},M.prototype.inArea=function(){return void 0!==this.width?this.x+this.width*this.graphScaleInv>=this.canvasTopLeft.x&&this.x-this.width*this.graphScaleInv=this.canvasTopLeft.y&&this.y-this.height*this.graphScaleInv=this.canvasTopLeft.x&&this.x=this.canvasTopLeft.y&&this.yh},D.prototype._drawLine=function(t){t.strokeStyle=this.color,t.lineWidth=this._getLineWidth();var e;if(this.from!=this.to)this._line(t),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y));else{var i,n,s=this.length/4,o=this.from;o.width||o.resize(t),o.width>o.height?(i=o.x+o.width/2,n=o.y-s):(i=o.x+s,n=o.y-o.height/2),this._circle(t,i,n,s),e=this._pointOnCircle(i,n,s,.5),this._label(t,this.label,e.x,e.y)}},D.prototype._getLineWidth=function(){return this.from.selected||this.to.selected?Math.min(2*this.width,this.widthMax)*this.graphScaleInv:this.width*this.graphScaleInv},D.prototype._line=function(t){t.beginPath(),t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y),t.stroke()},D.prototype._circle=function(t,e,i,n){t.beginPath(),t.arc(e,i,n,0,2*Math.PI,!1),t.stroke()},D.prototype._label=function(t,e,i,n){if(e){t.font=(this.from.selected||this.to.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle="white";var s=t.measureText(e).width,o=this.fontSize,r=i-s/2,a=n-o/2;t.fillRect(r,a,s,o),t.fillStyle=this.fontColor||"black",t.textAlign="left",t.textBaseline="top",t.fillText(e,r,a)}},D.prototype._drawDashLine=function(t){if(t.strokeStyle=this.color,t.lineWidth=this._getLineWidth(),t.beginPath(),t.lineCap="round",void 0!==this.dash.altLength?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]):void 0!==this.dash.length&&void 0!==this.dash.gap?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap]):(t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y)),t.stroke(),this.label){var e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}},D.prototype._pointOnLine=function(t){return{x:(1-t)*this.from.x+t*this.to.x,y:(1-t)*this.from.y+t*this.to.y}},D.prototype._pointOnCircle=function(t,e,i,n){var s=2*(n-3/8)*Math.PI;return{x:t+i*Math.cos(s),y:e-i*Math.sin(s)}},D.prototype._drawArrowCenter=function(t){var e;if(t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth(),this.from!=this.to){this._line(t);var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),n=10+5*this.width;e=this._pointOnLine(.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y))}else{var s,o,r=this.length/4,a=this.from;a.width||a.resize(t),a.width>a.height?(s=a.x+a.width/2,o=a.y-r):(s=a.x+r,o=a.y-a.height/2),this._circle(t,s,o,r);var i=.2*Math.PI,n=10+5*this.width;e=this._pointOnCircle(s,o,r,.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(s,o,r,.5),this._label(t,this.label,e.x,e.y))}},D.prototype._drawArrow=function(t){t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth();var e,i;if(this.from!=this.to){e=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x);var n=this.to.x-this.from.x,s=this.to.y-this.from.y,o=Math.sqrt(n*n+s*s),r=this.from.distanceToBorder(t,e+Math.PI),a=(o-r)/o,h=a*this.from.x+(1-a)*this.to.x,d=a*this.from.y+(1-a)*this.to.y,c=this.to.distanceToBorder(t,e),l=(o-c)/o,u=(1-l)*this.from.x+l*this.to.x,p=(1-l)*this.from.y+l*this.to.y;if(t.beginPath(),t.moveTo(h,d),t.lineTo(u,p),t.stroke(),i=10+5*this.width,t.arrow(u,p,e,i),t.fill(),t.stroke(),this.label){var f=this._pointOnLine(.5);this._label(t,this.label,f.x,f.y)}}else{var g,m,v,y=this.from,_=this.length/4;y.width||y.resize(t),y.width>y.height?(g=y.x+y.width/2,m=y.y-_,v={x:g,y:y.y,angle:.9*Math.PI}):(g=y.x+_,m=y.y-y.height/2,v={x:y.x,y:m,angle:.6*Math.PI}),t.beginPath(),t.arc(g,m,_,0,2*Math.PI,!1),t.stroke(),i=10+5*this.width,t.arrow(v.x,v.y,v.angle,i),t.fill(),t.stroke(),this.label&&(f=this._pointOnCircle(g,m,_,.5),this._label(t,this.label,f.x,f.y))}},D._dist=function(t,e,i,n,s,o){var r=i-t,a=n-e,h=r*r+a*a,d=((s-t)*r+(o-e)*a)/h;d>1?d=1:0>d&&(d=0);var c=t+d*r,l=e+d*a,u=c-s,p=l-o;return Math.sqrt(u*u+p*p)},D.prototype.setScale=function(t){this.graphScaleInv=1/t},I.prototype.setPosition=function(t,e){this.x=parseInt(t),this.y=parseInt(e)},I.prototype.setText=function(t){this.frame.innerHTML=t},I.prototype.show=function(t){if(void 0===t&&(t=!0),t){var e=this.frame.clientHeight,i=this.frame.clientWidth,n=this.frame.parentNode.clientHeight,s=this.frame.parentNode.clientWidth,o=this.y-e;o+e+this.padding>n&&(o=n-e-this.padding),os&&(r=s-i-this.padding),r1)return this.activeSector[this.activeSector.length-2];throw new TypeError("there are not enough sectors in the this.activeSector array.")},_setActiveSector:function(t){this.activeSector.push(t)},_forgetLastSector:function(){this.activeSector.pop()},_createNewSector:function(t){this.sectors.active[t]={nodes:{},edges:{},nodeIndices:[],formationScale:this.scale,drawingNode:void 0},this.sectors.active[t].drawingNode=new M({id:t,color:{background:"#eaefef",border:"495c5e"}},{},{},this.constants),this.sectors.active[t].drawingNode.clusterSize=2},_deleteActiveSector:function(t){delete this.sectors.active[t]},_deleteFrozenSector:function(t){delete this.sectors.frozen[t]},_freezeSector:function(t){this.sectors.frozen[t]=this.sectors.active[t],this._deleteActiveSector(t)},_activateSector:function(t){this.sectors.active[t]=this.sectors.frozen[t],this._deleteFrozenSector(t)},_mergeThisWithFrozen:function(t){for(var e in this.nodes)this.nodes.hasOwnProperty(e)&&(this.sectors.frozen[t].nodes[e]=this.nodes[e]);for(var i in this.edges)this.edges.hasOwnProperty(i)&&(this.sectors.frozen[t].edges[i]=this.edges[i]);for(var n=0;n1?this[t](n[0],n[1]):this[t](e)}this._loadLatestSector()},_doInAllFrozenSectors:function(t,e){if(void 0===e)for(var i in this.sectors.frozen)this.sectors.frozen.hasOwnProperty(i)&&(this._switchToFrozenSector(i),this[t]());else for(var i in this.sectors.frozen)if(this.sectors.frozen.hasOwnProperty(i)){this._switchToFrozenSector(i);var n=Array.prototype.splice.call(arguments,1);n.length>1?this[t](n[0],n[1]):this[t](e)}this._loadLatestSector()},_doInNavigationSector:function(t,e){if(this._switchToNavigationSector(),void 0===e)this[t]();else{var i=Array.prototype.splice.call(arguments,1);i.length>1?this[t](i[0],i[1]):this[t](e)}this._loadLatestSector()},_doInAllSectors:function(t,e){var i=Array.prototype.splice.call(arguments,1);void 0===e?(this._doInAllActiveSectors(t),this._doInAllFrozenSectors(t)):i.length>1?(this._doInAllActiveSectors(t,i[0],i[1]),this._doInAllFrozenSectors(t,i[0],i[1])):(this._doInAllActiveSectors(t,e),this._doInAllFrozenSectors(t,e))},_clearNodeIndexList:function(){var t=this._sector();this.sectors.active[t].nodeIndices=[],this.nodeIndices=this.sectors.active[t].nodeIndices},_drawSectorNodes:function(t,e){var i,n=1e9,s=-1e9,o=1e9,r=-1e9;for(var a in this.sectors[e])if(this.sectors[e].hasOwnProperty(a)&&void 0!==this.sectors[e][a].drawingNode){this._switchToSector(a,e),n=1e9,s=-1e9,o=1e9,r=-1e9;for(var h in this.nodes)this.nodes.hasOwnProperty(h)&&(i=this.nodes[h],i.resize(t),o>i.x-.5*i.width&&(o=i.x-.5*i.width),ri.y-.5*i.height&&(n=i.y-.5*i.height),st&&n>s;)s%3==0?this.forceAggregateHubs():this.increaseClusterLevel(),i=this.nodeIndices.length,s+=1;s>1&&1==e&&this.repositionNodes()},openCluster:function(t){var e=this.moving;if(t.clusterSize>this.constants.clustering.sectorThreshold&&this._nodeInActiveArea(t)&&("default"!=this._sector()||1!=this.nodeIndices.length)){this._addSector(t);for(var i=0;this.nodeIndices.lengthi;)this.decreaseClusterLevel(),i+=1}else this._expandClusterNode(t,!1,!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels();this.moving!=e&&this.start()},updateClustersDefault:function(){1==this.constants.clustering.enabled&&this.updateClusters(0,!1,!1)},increaseClusterLevel:function(){this.updateClusters(-1,!1,!0)},decreaseClusterLevel:function(){this.updateClusters(1,!1,!0)},updateClusters:function(t,e,i){var n=this.moving,s=this.nodeIndices.length;this.previousScale>this.scale&&0==t&&this._collapseSector(),this.previousScale>this.scale||-1==t?this._formClusters(i):(this.previousScalethis.scale||-1==t)&&(this._aggregateHubs(i),this._updateNodeIndexList()),(this.previousScale>this.scale||-1==t)&&(this.handleChains(),this._updateNodeIndexList()),this.previousScale=this.scale,this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.lengththis.constants.clustering.chainThreshold&&this._reduceAmountOfChains(1-this.constants.clustering.chainThreshold/t)},_aggregateHubs:function(t){this._getHubSize(),this._formClustersByHub(t,!1)},forceAggregateHubs:function(){var t=this.moving,e=this.nodeIndices.length;this._aggregateHubs(!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.length!=e&&(this.clusterSession+=1),this.moving!=t&&this.start()},_openClustersBySize:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];1==e.inView()&&(e.width*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientWidth||e.height*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientHeight)&&this.openCluster(e)}},_openClusters:function(t,e){for(var i=0;i1&&(t.clusterSizei)){var r=o.from,a=o.to;o.to.mass>o.from.mass&&(r=o.to,a=o.from),1==a.dynamicEdgesLength?this._addToCluster(r,a,!1):1==r.dynamicEdgesLength&&this._addToCluster(a,r,!1)}}},_forceClustersByZoom:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];if(1==e.dynamicEdgesLength&&0!=e.dynamicEdges.length){var i=e.dynamicEdges[0],n=i.toId==e.id?this.nodes[i.fromId]:this.nodes[i.toId];e.id!=n.id&&(n.mass>e.mass?this._addToCluster(n,e,!0):this._addToCluster(e,n,!0))}}},_formClustersByHub:function(t,e){for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&this._formClusterFromHub(this.nodes[i],t,e)},_formClusterFromHub:function(t,e,i,n){if(void 0===n&&(n=0),t.dynamicEdgesLength>=this.hubThreshold&&0==i||t.dynamicEdgesLength==this.hubThreshold&&1==i){for(var s,o,r,a=this.constants.clustering.clusterEdgeThreshold/this.scale,h=!1,d=[],c=t.dynamicEdges.length,l=0;c>l;l++)d.push(t.dynamicEdges[l].id);if(0==e)for(h=!1,l=0;c>l;l++){var u=this.edges[d[l]];if(void 0!==u&&u.connected&&u.toId!=u.fromId&&(s=u.to.x-u.from.x,o=u.to.y-u.from.y,r=Math.sqrt(s*s+o*o),a>r)){h=!0;break}}if(!e&&h||e)for(l=0;c>l;l++)if(u=this.edges[d[l]],void 0!==u){var p=this.nodes[u.fromId==t.id?u.toId:u.fromId];p.dynamicEdges.length<=this.hubThreshold+n&&p.id!=t.id&&this._addToCluster(t,p,e)}}},_addToCluster:function(t,e,i){t.containedNodes[e.id]=e;for(var n=0;n1)for(var n=0;n1&&(e.label="[".concat(String(e.clusterSize),"]"))}for(t in this.nodes)this.nodes.hasOwnProperty(t)&&(e=this.nodes[t],1==e.clusterSize&&(e.label=void 0!==e.originalLabel?e.originalLabel:String(e.id)))},_nodeInActiveArea:function(t){return Math.abs(t.x-this.areaCenter.x)<=this.constants.clustering.activeAreaBoxSize/this.scale&&Math.abs(t.y-this.areaCenter.y)<=this.constants.clustering.activeAreaBoxSize/this.scale},repositionNodes:function(){for(var t=0;tn&&(n=o.dynamicEdgesLength),t+=o.dynamicEdgesLength,e+=Math.pow(o.dynamicEdgesLength,2),i+=1}t/=i,e/=i;var r=e-Math.pow(t,2),a=Math.sqrt(r);this.hubThreshold=Math.floor(t+2*a),this.hubThreshold>n&&(this.hubThreshold=n)},_reduceAmountOfChains:function(t){this.hubThreshold=2;var e=Math.floor(this.nodeIndices.length*t);for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&e>0&&(this._formClusterFromHub(this.nodes[i],!0,!0,1),e-=1)},_getChainFraction:function(){var t=0,e=0;for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&(2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&(t+=1),e+=1);return t/e}},W={_getNodesOverlappingWith:function(t,e){var i=this.nodes;for(var n in i)i.hasOwnProperty(n)&&i[n].isOverlappingWith(t)&&e.push(n)},_getAllNodesOverlappingWith:function(t){var e=[];return this._doInAllActiveSectors("_getNodesOverlappingWith",t,e),e},_getAllNavigationNodesOverlappingWith:function(t){var e=[];return this._doInNavigationSector("_getNodesOverlappingWith",t,e),e},_pointerToPositionObject:function(t){var e=this._canvasToX(t.x),i=this._canvasToY(t.y);return{left:e,top:i,right:e,bottom:i}},_pointerToScreenPositionObject:function(t){var e=t.x,i=t.y;return{left:e,top:i,right:e,bottom:i}},_getNavigationNodeAt:function(t){var e=this._pointerToScreenPositionObject(t),i=this._getAllNavigationNodesOverlappingWith(e);return i.length>0?this.sectors.navigation.nodes[i[i.length-1]]:null},_getNodeAt:function(t){var e=this._pointerToPositionObject(t);return overlappingNodes=this._getAllNodesOverlappingWith(e),overlappingNodes.length>0?this.nodes[overlappingNodes[overlappingNodes.length-1]]:null},_getEdgeAt:function(){return null},_addToSelection:function(t){this.selection.push(t.id),this.selectionObj[t.id]=t},_removeFromSelection:function(t){for(var e=0;ee;e++){n=t[e];var s=this.nodes[n];if(!s)throw new RangeError('Node with id "'+n+'" not found');this._selectNode(s,!0,!0)}this.redraw()},_updateSelection:function(){for(var t=0;tt.x-t.width&&(n=t.x-t.width),st.y-t.height&&(e=t.y-t.height),i=this.constants.clustering.initialMaxNodes)var n=38.8467/(e-14.50184)+.0116;else var n=42.54117319/(e+39.31966387)+.1944405;else{var s=1.1*(Math.abs(i.minX)+Math.abs(i.maxX)),o=1.1*(Math.abs(i.minY)+Math.abs(i.maxY)),r=this.frame.canvas.clientWidth/s,a=this.frame.canvas.clientHeight/o;n=a>=r?r:a}n>1&&(n=1),this.pinch.mousewheelScale=n,this._setScale(n),this._centerGraph(i),this.start()},O.prototype._updateNodeIndexList=function(){this._clearNodeIndexList();for(var t in this.nodes)this.nodes.hasOwnProperty(t)&&this.nodeIndices.push(t)},O.prototype.setData=function(t,e){if(void 0===e&&(e=!1),t&&t.dot&&(t.nodes||t.edges))throw new SyntaxError('Data must contain either parameter "dot" or parameter pair "nodes" and "edges", but not both.');if(this.setOptions(t&&t.options),t&&t.dot){if(t&&t.dot){var i=U.util.DOTToGraph(t.dot);return void this.setData(i)}}else this._setNodes(t&&t.nodes),this._setEdges(t&&t.edges);this._putDataInSector(),e||(this.stabilize&&this._doStabilize(),this.moving=!0,this.start())},O.prototype.setOptions=function(t){if(t){if(void 0!==t.width&&(this.width=t.width),void 0!==t.height&&(this.height=t.height),void 0!==t.stabilize&&(this.stabilize=t.stabilize),void 0!==t.selectable&&(this.selectable=t.selectable),t.clustering){this.constants.clustering.enabled=!0;for(var e in t.clustering)t.clustering.hasOwnProperty(e)&&(this.constants.clustering[e]=t.clustering[e])}else void 0!==t.clustering&&(this.constants.clustering.enabled=!1);if(t.navigation){this.constants.navigation.enabled=!0;for(var e in t.navigation)t.navigation.hasOwnProperty(e)&&(this.constants.navigation[e]=t.navigation[e])}else void 0!==t.navigation&&(this.constants.navigation.enabled=!1);if(t.keyboard){this.constants.keyboard.enabled=!0;for(var e in t.keyboard)t.keyboard.hasOwnProperty(e)&&(this.constants.keyboard[e]=t.keyboard[e])}else void 0!==t.keyboard&&(this.constants.keyboard.enabled=!1);if(t.edges){for(e in t.edges)t.edges.hasOwnProperty(e)&&(this.constants.edges[e]=t.edges[e]);void 0!==t.edges.length&&t.nodes&&void 0===t.nodes.distance&&(this.constants.edges.length=t.edges.length,this.constants.nodes.distance=1.25*t.edges.length),t.edges.fontColor||(this.constants.edges.fontColor=t.edges.color),t.edges.dash&&(void 0!==t.edges.dash.length&&(this.constants.edges.dash.length=t.edges.dash.length),void 0!==t.edges.dash.gap&&(this.constants.edges.dash.gap=t.edges.dash.gap),void 0!==t.edges.dash.altLength&&(this.constants.edges.dash.altLength=t.edges.dash.altLength))}if(t.nodes){for(e in t.nodes)t.nodes.hasOwnProperty(e)&&(this.constants.nodes[e]=t.nodes[e]);t.nodes.color&&(this.constants.nodes.color=M.parseColor(t.nodes.color))}if(t.groups)for(var i in t.groups)if(t.groups.hasOwnProperty(i)){var n=t.groups[i];this.groups.add(i,n)}}this.setSize(this.width,this.height),this._setTranslation(this.frame.clientWidth/2,this.frame.clientHeight/2),this._setScale(1),this._loadNavigationControls(),this._createKeyBinds(),this._redraw()},O.prototype.on=function(t,e){var i=["select"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());F.addListener(this,t,e)},O.prototype.off=function(t,e){F.removeListener(this,t,e)},O.prototype._trigger=function(t,e){F.trigger(this,t,e)},O.prototype._create=function(){for(;this.containerElement.hasChildNodes();)this.containerElement.removeChild(this.containerElement.firstChild);if(this.frame=document.createElement("div"),this.frame.className="graph-frame",this.frame.style.position="relative",this.frame.style.overflow="hidden",this.frame.canvas=document.createElement("canvas"),this.frame.canvas.style.position="relative",this.frame.appendChild(this.frame.canvas),!this.frame.canvas.getContext){var t=document.createElement("DIV");t.style.color="red",t.style.fontWeight="bold",t.style.padding="10px",t.innerHTML="Error: your browser does not support HTML canvas",this.frame.canvas.appendChild(t)}var e=this;this.drag={},this.pinch={},this.hammer=N(this.frame.canvas,{prevent_default:!0}),this.hammer.on("tap",e._onTap.bind(e)),this.hammer.on("doubletap",e._onDoubleTap.bind(e)),this.hammer.on("hold",e._onHold.bind(e)),this.hammer.on("pinch",e._onPinch.bind(e)),this.hammer.on("touch",e._onTouch.bind(e)),this.hammer.on("dragstart",e._onDragStart.bind(e)),this.hammer.on("drag",e._onDrag.bind(e)),this.hammer.on("dragend",e._onDragEnd.bind(e)),this.hammer.on("release",e._onRelease.bind(e)),this.hammer.on("mousewheel",e._onMouseWheel.bind(e)),this.hammer.on("DOMMouseScroll",e._onMouseWheel.bind(e)),this.hammer.on("mousemove",e._onMouseMoveTitle.bind(e)),this.containerElement.appendChild(this.frame)},O.prototype._createKeyBinds=function(){var t=this;this.mousetrap=A,this.mousetrap.reset(),1==this.constants.keyboard.enabled&&(this.mousetrap.bind("up",this._moveUp.bind(t),"keydown"),this.mousetrap.bind("up",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("down",this._moveDown.bind(t),"keydown"),this.mousetrap.bind("down",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("left",this._moveLeft.bind(t),"keydown"),this.mousetrap.bind("left",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("right",this._moveRight.bind(t),"keydown"),this.mousetrap.bind("right",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("=",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("=",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("-",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("-",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("[",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("[",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("]",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("]",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pageup",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("pageup",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pagedown",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("pagedown",this._stopZoom.bind(t),"keyup"))},O.prototype._getPointer=function(t){return{x:t.pageX-U.util.getAbsoluteLeft(this.frame.canvas),y:t.pageY-U.util.getAbsoluteTop(this.frame.canvas)}},O.prototype._onTouch=function(t){this.drag.pointer=this._getPointer(t.gesture.touches[0]),this.drag.pinched=!1,this.pinch.scale=this._getScale(),this._handleTouch(this.drag.pointer)},O.prototype._onDragStart=function(){var t=this.drag,e=this._getNodeAt(t.pointer);if(t.dragging=!0,t.selection=[],t.translation=this._getTranslation(),t.nodeId=null,null!=e){t.nodeId=e.id,e.isSelected()||this._selectNode(e,!1);var i=this;this.selection.forEach(function(e){var n=i.nodes[e];if(n){var s={id:e,node:n,x:n.x,y:n.y,xFixed:n.xFixed,yFixed:n.yFixed};n.xFixed=!0,n.yFixed=!0,t.selection.push(s)}})}},O.prototype._onDrag=function(t){if(!this.drag.pinched){var e=this._getPointer(t.gesture.touches[0]),i=this,n=this.drag,s=n.selection;if(s&&s.length){var o=e.x-n.pointer.x,r=e.y-n.pointer.y;s.forEach(function(t){var e=t.node;t.xFixed||(e.x=i._canvasToX(i._xToCanvas(t.x)+o)),t.yFixed||(e.y=i._canvasToY(i._yToCanvas(t.y)+r))}),this.moving||(this.moving=!0,this.start())}else{var a=e.x-this.drag.pointer.x,h=e.y-this.drag.pointer.y;this._setTranslation(this.drag.translation.x+a,this.drag.translation.y+h),this._redraw(),this.moved=!0}}},O.prototype._onDragEnd=function(){this.drag.dragging=!1;var t=this.drag.selection;t&&t.forEach(function(t){t.node.xFixed=t.xFixed,t.node.yFixed=t.yFixed})},O.prototype._onTap=function(t){var e=this._getPointer(t.gesture.touches[0]);this._handleTap(e)},O.prototype._onDoubleTap=function(t){var e=this._getPointer(t.gesture.touches[0]);this._handleDoubleTap(e)},O.prototype._onHold=function(t){var e=this._getPointer(t.gesture.touches[0]);this._handleOnHold(e)},O.prototype._onRelease=function(){this._handleOnRelease()},O.prototype._onPinch=function(t){var e=this._getPointer(t.gesture.center);this.drag.pinched=!0,"scale"in this.pinch||(this.pinch.scale=1);var i=this.pinch.scale*t.gesture.scale;this._zoom(i,e)},O.prototype._zoom=function(t,e){var i=this._getScale();1e-5>t&&(t=1e-5),t>10&&(t=10);var n=this._getTranslation(),s=t/i,o=(1-s)*e.x+n.x*s,r=(1-s)*e.y+n.y*s;return this.areaCenter={x:this._canvasToX(e.x),y:this._canvasToY(e.y)},this.pinch.mousewheelScale=t,this._setScale(t),this._setTranslation(o,r),this.updateClustersDefault(),this._redraw(),t},O.prototype._onMouseWheel=function(t){var e=0;if(t.wheelDelta?e=t.wheelDelta/120:t.detail&&(e=-t.detail/3),e){"mousewheelScale"in this.pinch||(this.pinch.mousewheelScale=1);var i=this.pinch.mousewheelScale,n=e/10;0>e&&(n/=1-n),i*=1+n;var s=z.fakeGesture(this,t),o=this._getPointer(s.center);i=this._zoom(i,o)}t.preventDefault()},O.prototype._onMouseMoveTitle=function(t){var e=z.fakeGesture(this,t),i=this._getPointer(e.center);this.popupNode&&this._checkHidePopup(i);var n=this,s=function(){n._checkShowPopup(i)};this.popupTimer&&clearInterval(this.popupTimer),this.drag.dragging||(this.popupTimer=setTimeout(s,300))},O.prototype._checkShowPopup=function(t){var e,i={left:this._canvasToX(t.x),top:this._canvasToY(t.y),right:this._canvasToX(t.x),bottom:this._canvasToY(t.y)},n=this.popupNode;if(void 0==this.popupNode){var s=this.nodes;for(e in s)if(s.hasOwnProperty(e)){var o=s[e];if(void 0!==o.getTitle()&&o.isOverlappingWith(i)){this.popupNode=o;break}}}if(void 0===this.popupNode){var r=this.edges;for(e in r)if(r.hasOwnProperty(e)){var a=r[e];if(a.connected&&void 0!==a.getTitle()&&a.isOverlappingWith(i)){this.popupNode=a;break}}}if(this.popupNode){if(this.popupNode!=n){var h=this;h.popup||(h.popup=new I(h.frame)),h.popup.setPosition(t.x-3,t.y-3),h.popup.setText(h.popupNode.getTitle()),h.popup.show()}}else this.popup&&this.popup.hide()},O.prototype._checkHidePopup=function(t){this.popupNode&&this._getNodeAt(t)||(this.popupNode=void 0,this.popup&&this.popup.hide())},O.prototype._getConnectionCount=function(t){function e(t){for(var e=[],i=0,n=t.length;n>i;i++)for(var s=t[i],o=s.edges,r=0,a=o.length;a>r;r++){var h=o[r],d=null;h.from==s?d=h.to:h.to==s&&(d=h.from);var c,l;if(d)for(c=0,l=t.length;l>c;c++)if(t[c]==d){d=null;break}if(d)for(c=0,l=e.length;l>c;c++)if(e[c]==d){d=null;break}d&&e.push(d)}return e}void 0==t&&(t=1);var i=[],n=this.nodes;for(var s in n)if(n.hasOwnProperty(s)){for(var o=[n[s]],r=0;t>r;r++)o=o.concat(e(o));i.push(o)}for(var a=[],h=0,d=i.length;d>h;h++)a.push(i[h].length);return a},O.prototype.setSize=function(t,e){this.frame.style.width=t,this.frame.style.height=e,this.frame.canvas.style.width="100%",this.frame.canvas.style.height="100%",this.frame.canvas.width=this.frame.canvas.clientWidth,this.frame.canvas.height=this.frame.canvas.clientHeight,1==this.constants.navigation.enabled&&this._relocateNavigation()},O.prototype._setNodes=function(t){var e=this.nodesData;if(t instanceof o||t instanceof r)this.nodesData=t;else if(t instanceof Array)this.nodesData=new o,this.nodesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.nodesData=new o}if(e&&z.forEach(this.nodesListeners,function(t,i){e.unsubscribe(i,t)}),this.nodes={},this.nodesData){var i=this;z.forEach(this.nodesListeners,function(t,e){i.nodesData.subscribe(e,t)});var n=this.nodesData.getIds();this._addNodes(n)}this._updateSelection()},O.prototype._addNodes=function(t){for(var e,i=0,n=t.length;n>i;i++){e=t[i];var s=this.nodesData.get(e),o=new M(s,this.images,this.groups,this.constants);if(this.nodes[e]=o,!o.isFixed()){var r=2*this.constants.edges.length,a=t.length,h=2*Math.PI*(i/a);o.x=r*Math.cos(h),o.y=r*Math.sin(h),this.moving=!0}}this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(this.nodes)},O.prototype._updateNodes=function(t){for(var e=this.nodes,i=this.nodesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o],a=i.get(o);r?r.setProperties(a,this.constants):(r=new M(properties,this.images,this.groups,this.constants),e[o]=r,r.isFixed()||(this.moving=!0))}this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(e)},O.prototype._removeNodes=function(t){for(var e=this.nodes,i=0,n=t.length;n>i;i++){var s=t[i];delete e[s]}this._updateNodeIndexList(),this._reconnectEdges(),this._updateSelection(),this._updateValueRange(e)},O.prototype._setEdges=function(t){var e=this.edgesData;if(t instanceof o||t instanceof r)this.edgesData=t;else if(t instanceof Array)this.edgesData=new o,this.edgesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.edgesData=new o}if(e&&z.forEach(this.edgesListeners,function(t,i){e.unsubscribe(i,t)}),this.edges={},this.edgesData){var i=this;z.forEach(this.edgesListeners,function(t,e){i.edgesData.subscribe(e,t)});var n=this.edgesData.getIds();this._addEdges(n)}this._reconnectEdges()},O.prototype._addEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o];r&&r.disconnect();var a=i.get(o,{showInternalIds:!0});e[o]=new D(a,this,this.constants)}this.moving=!0,this._updateValueRange(e)},O.prototype._updateEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=i.get(o),a=e[o];a?(a.disconnect(),a.setProperties(r,this.constants),a.connect()):(a=new D(r,this,this.constants),this.edges[o]=a)}this.moving=!0,this._updateValueRange(e)},O.prototype._removeEdges=function(t){for(var e=this.edges,i=0,n=t.length;n>i;i++){var s=t[i],o=e[s];o&&(o.disconnect(),delete e[s])}this.moving=!0,this._updateValueRange(e)},O.prototype._reconnectEdges=function(){var t,e=this.nodes,i=this.edges;for(t in e)e.hasOwnProperty(t)&&(e[t].edges=[]);for(t in i)if(i.hasOwnProperty(t)){var n=i[t];n.from=null,n.to=null,n.connect()}},O.prototype._updateValueRange=function(t){var e,i=void 0,n=void 0;for(e in t)if(t.hasOwnProperty(e)){var s=t[e].getValue();void 0!==s&&(i=void 0===i?s:Math.min(s,i),n=void 0===n?s:Math.max(s,n))}if(void 0!==i&&void 0!==n)for(e in t)t.hasOwnProperty(e)&&t[e].setValueRange(i,n)},O.prototype.redraw=function(){this.setSize(this.width,this.height),this._redraw()},O.prototype._redraw=function(){var t=this.frame.canvas.getContext("2d"),e=this.frame.canvas.width,i=this.frame.canvas.height;t.clearRect(0,0,e,i),t.save(),t.translate(this.translation.x,this.translation.y),t.scale(this.scale,this.scale),this.canvasTopLeft={x:this._canvasToX(0),y:this._canvasToY(0)},this.canvasBottomRight={x:this._canvasToX(this.frame.canvas.clientWidth),y:this._canvasToY(this.frame.canvas.clientHeight)},this._doInAllSectors("_drawAllSectorNodes",t),this._doInAllSectors("_drawEdges",t),this._doInAllSectors("_drawNodes",t),t.restore(),1==this.constants.navigation.enabled&&this._doInNavigationSector("_drawNodes",t,!0)},O.prototype._setTranslation=function(t,e){void 0===this.translation&&(this.translation={x:0,y:0}),void 0!==t&&(this.translation.x=t),void 0!==e&&(this.translation.y=e)},O.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},O.prototype._setScale=function(t){this.scale=t},O.prototype._getScale=function(){return this.scale},O.prototype._canvasToX=function(t){return(t-this.translation.x)/this.scale},O.prototype._xToCanvas=function(t){return t*this.scale+this.translation.x},O.prototype._canvasToY=function(t){return(t-this.translation.y)/this.scale},O.prototype._yToCanvas=function(t){return t*this.scale+this.translation.y},O.prototype._drawNodes=function(t,e){void 0===e&&(e=!1);var i=this.nodes,n=[];for(var s in i)i.hasOwnProperty(s)&&(i[s].setScaleAndPos(this.scale,this.canvasTopLeft,this.canvasBottomRight),i[s].isSelected()?n.push(s):(i[s].inArea()||e)&&i[s].draw(t));for(var o=0,r=n.length;r>o;o++)(i[n[o]].inArea()||e)&&i[n[o]].draw(t)},O.prototype._drawEdges=function(t){var e=this.edges;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];n.setScale(this.scale),n.connected&&e[i].draw(t)}},O.prototype._doStabilize=function(){for(var t=0,e=this.constants.minVelocity,i=!1;!i&&tthis.constants.clustering.clusterThreshold&&1==this.constants.clustering.enabled&&this.clusterToFit(this.constants.clustering.reduceToNodes,!1),this._calculateForces())},O.prototype._calculateForces=function(){var t,e,i,n,s,o,r,a,h,d,c,l,u,p,f,g,m,v,y=this.nodes,_=this.edges,w=.08*this.forceFactor;for(g=0;gn&&(i=Math.atan2(e,t),r=.5*b>n?1:1/(1+Math.exp((n/b-1)*S)),r*=0==v?1:1+v*this.constants.clustering.forceAmplification,r*=this.forceFactor,s=Math.cos(i)*r,o=Math.sin(i)*r,l._addForce(-s,-o),u._addForce(s,o));for(f in _)_.hasOwnProperty(f)&&(p=_[f],p.connected&&this.nodes.hasOwnProperty(p.toId)&&this.nodes.hasOwnProperty(p.fromId)&&(v=p.to.clusterSize+p.from.clusterSize-2,t=p.to.x-p.from.x,e=p.to.y-p.from.y,d=p.length,d+=v*this.constants.clustering.edgeGrowth,h=Math.sqrt(t*t+e*e),i=Math.atan2(e,t),a=p.stiffness*(d-h)*this.forceFactor,s=Math.cos(i)*a,o=Math.sin(i)*a,p.from._addForce(-s,-o),p.to._addForce(s,o)))},O.prototype._isMoving=function(t){var e=t/this.scale,i=this.nodes;for(var n in i)if(i.hasOwnProperty(n)&&i[n].isMoving(e))return!0;return!1},O.prototype._discreteStepNodes=function(){var t=.01,e=this.nodes;for(var i in e)e.hasOwnProperty(i)&&e[i].discreteStep(t);var n=this.constants.minVelocity;this.moving=this._isMoving(n)},O.prototype.start=function(){if(!this.freezeSimulation)if(this.moving&&(this._doInAllActiveSectors("_initializeForceCalculation"),this._doInAllActiveSectors("_discreteStepNodes"),this._findCenter(this._getRange())),this.moving||0!=this.xIncrement||0!=this.yIncrement||0!=this.zoomIncrement){if(!this.timer){var t=this;this.timer=window.setTimeout(function(){if(t.timer=void 0,0!=t.xIncrement||0!=t.yIncrement){var e=t._getTranslation();t._setTranslation(e.x+t.xIncrement,e.y+t.yIncrement)}if(0!=t.zoomIncrement){var i={x:t.frame.canvas.clientWidth/2,y:t.frame.canvas.clientHeight/2};t._zoom(t.scale*(1+t.zoomIncrement),i)}t.start(),t._redraw()},this.renderTimestep)}}else this._redraw()},O.prototype.singleStep=function(){if(this.moving){this._initializeForceCalculation(),this._discreteStepNodes();var t=this.constants.minVelocity;this.moving=this._isMoving(t),this._redraw()}},O.prototype.toggleFreeze=function(){0==this.freezeSimulation?this.freezeSimulation=!0:(this.freezeSimulation=!1,this.start())},O.prototype._loadClusterSystem=function(){this.clusterSession=0,this.hubThreshold=5;for(var t in H)H.hasOwnProperty(t)&&(O.prototype[t]=H[t])},O.prototype._loadSectorSystem=function(){this.sectors={},this.activeSector=["default"],this.sectors.active={},this.sectors.active["default"]={nodes:{},edges:{},nodeIndices:[],formationScale:1,drawingNode:void 0},this.sectors.frozen={},this.sectors.navigation={nodes:{},edges:{},nodeIndices:[],formationScale:1,drawingNode:void 0},this.nodeIndices=this.sectors.active["default"].nodeIndices;for(var t in R)R.hasOwnProperty(t)&&(O.prototype[t]=R[t])},O.prototype._loadSelectionSystem=function(){this.selection=[],this.selectionObj={};for(var t in W)W.hasOwnProperty(t)&&(O.prototype[t]=W[t])},O.prototype._loadNavigationControls=function(){for(var t in j)j.hasOwnProperty(t)&&(O.prototype[t]=j[t]);1==this.constants.navigation.enabled&&this._loadNavigationElements()},O.prototype._relocateNavigation=function(){},O.prototype._unHighlightAll=function(){};var U={util:z,events:F,Controller:l,DataSet:o,DataView:r,Range:h,Stack:a,TimeStep:TimeStep,EventBus:s,components:{items:{Item:_,ItemBox:w,ItemPoint:b,ItemRange:S},Component:u,Panel:p,RootPanel:f,ItemSet:y,TimeAxis:g},graph:{Node:M,Edge:D,Popup:I,Groups:Groups,Images:Images},Timeline:C,Graph:O};"undefined"!=typeof n&&(n=U),"undefined"!=typeof i&&"undefined"!=typeof i.exports&&(i.exports=U),"function"==typeof t&&t(function(){return U}),"undefined"!=typeof window&&(window.vis=U)},{hammerjs:2,moment:3,mousetrap:4}],2:[function(t,e){!function(t,i){"use strict";function n(){if(!s.READY){s.event.determineEventTypes();for(var t in s.gestures)s.gestures.hasOwnProperty(t)&&s.detection.register(s.gestures[t]);s.event.onTouch(s.DOCUMENT,s.EVENT_MOVE,s.detection.detect),s.event.onTouch(s.DOCUMENT,s.EVENT_END,s.detection.detect),s.READY=!0}}var s=function(t,e){return new s.Instance(t,e||{})};s.defaults={stop_browser_behavior:{userSelect:"none",touchAction:"none",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}},s.HAS_POINTEREVENTS=navigator.pointerEnabled||navigator.msPointerEnabled,s.HAS_TOUCHEVENTS="ontouchstart"in t,s.MOBILE_REGEX=/mobile|tablet|ip(ad|hone|od)|android/i,s.NO_MOUSEEVENTS=s.HAS_TOUCHEVENTS&&navigator.userAgent.match(s.MOBILE_REGEX),s.EVENT_TYPES={},s.DIRECTION_DOWN="down",s.DIRECTION_LEFT="left",s.DIRECTION_UP="up",s.DIRECTION_RIGHT="right",s.POINTER_MOUSE="mouse",s.POINTER_TOUCH="touch",s.POINTER_PEN="pen",s.EVENT_START="start",s.EVENT_MOVE="move",s.EVENT_END="end",s.DOCUMENT=document,s.plugins={},s.READY=!1,s.Instance=function(t,e){var i=this; -return n(),this.element=t,this.enabled=!0,this.options=s.utils.extend(s.utils.extend({},s.defaults),e||{}),this.options.stop_browser_behavior&&s.utils.stopDefaultBrowserBehavior(this.element,this.options.stop_browser_behavior),s.event.onTouch(t,s.EVENT_START,function(t){i.enabled&&s.detection.startDetect(i,t)}),this},s.Instance.prototype={on:function(t,e){for(var i=t.split(" "),n=0;n0&&e==s.EVENT_END?e=s.EVENT_MOVE:c||(e=s.EVENT_END),c||null===o?o=h:h=o,i.call(s.detection,n.collectEventData(t,e,h)),s.HAS_POINTEREVENTS&&e==s.EVENT_END&&(c=s.PointerEvent.updatePointer(e,h))),c||(o=null,r=!1,a=!1,s.PointerEvent.reset())}})},determineEventTypes:function(){var t;t=s.HAS_POINTEREVENTS?s.PointerEvent.getEvents():s.NO_MOUSEEVENTS?["touchstart","touchmove","touchend touchcancel"]:["touchstart mousedown","touchmove mousemove","touchend touchcancel mouseup"],s.EVENT_TYPES[s.EVENT_START]=t[0],s.EVENT_TYPES[s.EVENT_MOVE]=t[1],s.EVENT_TYPES[s.EVENT_END]=t[2]},getTouchList:function(t){return s.HAS_POINTEREVENTS?s.PointerEvent.getTouchList():t.touches?t.touches:[{identifier:1,pageX:t.pageX,pageY:t.pageY,target:t.target}]},collectEventData:function(t,e,i){var n=this.getTouchList(i,e),o=s.POINTER_TOUCH;return(i.type.match(/mouse/)||s.PointerEvent.matchType(s.POINTER_MOUSE,i))&&(o=s.POINTER_MOUSE),{center:s.utils.getCenter(n),timeStamp:(new Date).getTime(),target:i.target,touches:n,eventType:e,pointerType:o,srcEvent:i,preventDefault:function(){this.srcEvent.preventManipulation&&this.srcEvent.preventManipulation(),this.srcEvent.preventDefault&&this.srcEvent.preventDefault()},stopPropagation:function(){this.srcEvent.stopPropagation()},stopDetect:function(){return s.detection.stopDetect()}}}},s.PointerEvent={pointers:{},getTouchList:function(){var t=this,e=[];return Object.keys(t.pointers).sort().forEach(function(i){e.push(t.pointers[i])}),e},updatePointer:function(t,e){return t==s.EVENT_END?this.pointers={}:(e.identifier=e.pointerId,this.pointers[e.pointerId]=e),Object.keys(this.pointers).length},matchType:function(t,e){if(!e.pointerType)return!1;var i={};return i[s.POINTER_MOUSE]=e.pointerType==e.MSPOINTER_TYPE_MOUSE||e.pointerType==s.POINTER_MOUSE,i[s.POINTER_TOUCH]=e.pointerType==e.MSPOINTER_TYPE_TOUCH||e.pointerType==s.POINTER_TOUCH,i[s.POINTER_PEN]=e.pointerType==e.MSPOINTER_TYPE_PEN||e.pointerType==s.POINTER_PEN,i[t]},getEvents:function(){return["pointerdown MSPointerDown","pointermove MSPointerMove","pointerup pointercancel MSPointerUp MSPointerCancel"]},reset:function(){this.pointers={}}},s.utils={extend:function(t,e,n){for(var s in e)t[s]!==i&&n||(t[s]=e[s]);return t},hasParent:function(t,e){for(;t;){if(t==e)return!0;t=t.parentNode}return!1},getCenter:function(t){for(var e=[],i=[],n=0,s=t.length;s>n;n++)e.push(t[n].pageX),i.push(t[n].pageY);return{pageX:(Math.min.apply(Math,e)+Math.max.apply(Math,e))/2,pageY:(Math.min.apply(Math,i)+Math.max.apply(Math,i))/2}},getVelocity:function(t,e,i){return{x:Math.abs(e/t)||0,y:Math.abs(i/t)||0}},getAngle:function(t,e){var i=e.pageY-t.pageY,n=e.pageX-t.pageX;return 180*Math.atan2(i,n)/Math.PI},getDirection:function(t,e){var i=Math.abs(t.pageX-e.pageX),n=Math.abs(t.pageY-e.pageY);return i>=n?t.pageX-e.pageX>0?s.DIRECTION_LEFT:s.DIRECTION_RIGHT:t.pageY-e.pageY>0?s.DIRECTION_UP:s.DIRECTION_DOWN},getDistance:function(t,e){var i=e.pageX-t.pageX,n=e.pageY-t.pageY;return Math.sqrt(i*i+n*n)},getScale:function(t,e){return t.length>=2&&e.length>=2?this.getDistance(e[0],e[1])/this.getDistance(t[0],t[1]):1},getRotation:function(t,e){return t.length>=2&&e.length>=2?this.getAngle(e[1],e[0])-this.getAngle(t[1],t[0]):0},isVertical:function(t){return t==s.DIRECTION_UP||t==s.DIRECTION_DOWN},stopDefaultBrowserBehavior:function(t,e){var i,n=["webkit","khtml","moz","ms","o",""];if(e&&t.style){for(var s=0;si;i++){var o=this.gestures[i];if(!this.stopped&&e[o.name]!==!1&&o.handler.call(o,t,this.current.inst)===!1){this.stopDetect();break}}return this.current&&(this.current.lastEvent=t),t.eventType==s.EVENT_END&&!t.touches.length-1&&this.stopDetect(),t}},stopDetect:function(){this.previous=s.utils.extend({},this.current),this.current=null,this.stopped=!0},extendEventData:function(t){var e=this.current.startEvent;if(e&&(t.touches.length!=e.touches.length||t.touches===e.touches)){e.touches=[];for(var i=0,n=t.touches.length;n>i;i++)e.touches.push(s.utils.extend({},t.touches[i]))}var o=t.timeStamp-e.timeStamp,r=t.center.pageX-e.center.pageX,a=t.center.pageY-e.center.pageY,h=s.utils.getVelocity(o,r,a);return s.utils.extend(t,{deltaTime:o,deltaX:r,deltaY:a,velocityX:h.x,velocityY:h.y,distance:s.utils.getDistance(e.center,t.center),angle:s.utils.getAngle(e.center,t.center),direction:s.utils.getDirection(e.center,t.center),scale:s.utils.getScale(e.touches,t.touches),rotation:s.utils.getRotation(e.touches,t.touches),startEvent:e}),t},register:function(t){var e=t.defaults||{};return e[t.name]===i&&(e[t.name]=!0),s.utils.extend(s.defaults,e,!0),t.index=t.index||1e3,this.gestures.push(t),this.gestures.sort(function(t,e){return t.indexe.index?1:0}),this.gestures}},s.gestures=s.gestures||{},s.gestures.Hold={name:"hold",index:10,defaults:{hold_timeout:500,hold_threshold:1},timer:null,handler:function(t,e){switch(t.eventType){case s.EVENT_START:clearTimeout(this.timer),s.detection.current.name=this.name,this.timer=setTimeout(function(){"hold"==s.detection.current.name&&e.trigger("hold",t)},e.options.hold_timeout);break;case s.EVENT_MOVE:t.distance>e.options.hold_threshold&&clearTimeout(this.timer);break;case s.EVENT_END:clearTimeout(this.timer)}}},s.gestures.Tap={name:"tap",index:100,defaults:{tap_max_touchtime:250,tap_max_distance:10,tap_always:!0,doubletap_distance:20,doubletap_interval:300},handler:function(t,e){if(t.eventType==s.EVENT_END){var i=s.detection.previous,n=!1;if(t.deltaTime>e.options.tap_max_touchtime||t.distance>e.options.tap_max_distance)return;i&&"tap"==i.name&&t.timeStamp-i.lastEvent.timeStamp0&&t.touches.length>e.options.swipe_max_touches)return;(t.velocityX>e.options.swipe_velocity||t.velocityY>e.options.swipe_velocity)&&(e.trigger(this.name,t),e.trigger(this.name+t.direction,t))}}},s.gestures.Drag={name:"drag",index:50,defaults:{drag_min_distance:10,drag_max_touches:1,drag_block_horizontal:!1,drag_block_vertical:!1,drag_lock_to_axis:!1,drag_lock_min_distance:25},triggered:!1,handler:function(t,e){if(s.detection.current.name!=this.name&&this.triggered)return e.trigger(this.name+"end",t),void(this.triggered=!1);if(!(e.options.drag_max_touches>0&&t.touches.length>e.options.drag_max_touches))switch(t.eventType){case s.EVENT_START:this.triggered=!1;break;case s.EVENT_MOVE:if(t.distancee.options.transform_min_rotation&&e.trigger("rotate",t),i>e.options.transform_min_scale&&(e.trigger("pinch",t),e.trigger("pinch"+(t.scale<1?"in":"out"),t));break;case s.EVENT_END:this.triggered&&e.trigger(this.name+"end",t),this.triggered=!1}}},s.gestures.Touch={name:"touch",index:-1/0,defaults:{prevent_default:!1,prevent_mouseevents:!1},handler:function(t,e){return e.options.prevent_mouseevents&&t.pointerType==s.POINTER_MOUSE?void t.stopDetect():(e.options.prevent_default&&t.preventDefault(),void(t.eventType==s.EVENT_START&&e.trigger(this.name,t)))}},s.gestures.Release={name:"release",index:1/0,handler:function(t,e){t.eventType==s.EVENT_END&&e.trigger(this.name,t)}},"object"==typeof e&&"object"==typeof e.exports?e.exports=s:(t.Hammer=s,"function"==typeof t.define&&t.define.amd&&t.define("hammer",[],function(){return s}))}(this)},{}],3:[function(e,i){(function(n){function s(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function o(t,e){return function(i){return p(t.call(this,i),e)}}function r(t,e){return function(i){return this.lang().ordinal(t.call(this,i),e)}}function a(){}function h(t){x(t),c(this,t)}function d(t){var e=_(t),i=e.year||0,n=e.month||0,s=e.week||0,o=e.day||0,r=e.hour||0,a=e.minute||0,h=e.second||0,d=e.millisecond||0;this._milliseconds=+d+1e3*h+6e4*a+36e5*r,this._days=+o+7*s,this._months=+n+12*i,this._data={},this._bubble()}function c(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return e.hasOwnProperty("toString")&&(t.toString=e.toString),e.hasOwnProperty("valueOf")&&(t.valueOf=e.valueOf),t}function l(t){var e,i={};for(e in t)t.hasOwnProperty(e)&&_e.hasOwnProperty(e)&&(i[e]=t[e]);return i}function u(t){return 0>t?Math.ceil(t):Math.floor(t)}function p(t,e,i){for(var n=""+Math.abs(t),s=t>=0;n.lengthn;n++)(i&&t[n]!==e[n]||!i&&b(t[n])!==b(e[n]))&&r++;return r+o}function y(t){if(t){var e=t.toLowerCase().replace(/(.)s$/,"$1");t=Xe[t]||Ze[e]||e}return t}function _(t){var e,i,n={};for(i in t)t.hasOwnProperty(i)&&(e=y(i),e&&(n[e]=t[i]));return n}function w(t){var e,i;if(0===t.indexOf("week"))e=7,i="day";else{if(0!==t.indexOf("month"))return;e=12,i="month"}re[t]=function(s,o){var r,a,h=re.fn._lang[t],d=[];if("number"==typeof s&&(o=s,s=n),a=function(t){var e=re().utc().set(i,t);return h.call(re.fn._lang,e,s||"")},null!=o)return a(o);for(r=0;e>r;r++)d.push(a(r));return d}}function b(t){var e=+t,i=0;return 0!==e&&isFinite(e)&&(i=e>=0?Math.floor(e):Math.ceil(e)),i}function S(t,e){return new Date(Date.UTC(t,e+1,0)).getUTCDate()}function E(t){return T(t)?366:365}function T(t){return t%4===0&&t%100!==0||t%400===0}function x(t){var e;t._a&&-2===t._pf.overflow&&(e=t._a[ue]<0||t._a[ue]>11?ue:t._a[pe]<1||t._a[pe]>S(t._a[le],t._a[ue])?pe:t._a[fe]<0||t._a[fe]>23?fe:t._a[ge]<0||t._a[ge]>59?ge:t._a[me]<0||t._a[me]>59?me:t._a[ve]<0||t._a[ve]>999?ve:-1,t._pf._overflowDayOfYear&&(le>e||e>pe)&&(e=pe),t._pf.overflow=e)}function C(t){return null==t._isValid&&(t._isValid=!isNaN(t._d.getTime())&&t._pf.overflow<0&&!t._pf.empty&&!t._pf.invalidMonth&&!t._pf.nullInput&&!t._pf.invalidFormat&&!t._pf.userInvalidated,t._strict&&(t._isValid=t._isValid&&0===t._pf.charsLeftOver&&0===t._pf.unusedTokens.length)),t._isValid}function M(t){return t?t.toLowerCase().replace("_","-"):t}function D(t,e){return e._isUTC?re(t).zone(e._offset||0):re(t).local()}function I(t,e){return e.abbr=t,ye[t]||(ye[t]=new a),ye[t].set(e),ye[t]}function O(t){delete ye[t]}function N(t){var i,n,s,o,r=0,a=function(t){if(!ye[t]&&we)try{e("./lang/"+t)}catch(i){}return ye[t]};if(!t)return re.fn._lang;if(!g(t)){if(n=a(t))return n;t=[t]}for(;r0;){if(n=a(o.slice(0,i).join("-")))return n;if(s&&s.length>=i&&v(o,s,!0)>=i-1)break;i--}r++}return re.fn._lang}function L(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function A(t){var e,i,n=t.match(Te);for(e=0,i=n.length;i>e;e++)n[e]=Je[n[e]]?Je[n[e]]:L(n[e]);return function(s){var o="";for(e=0;i>e;e++)o+=n[e]instanceof Function?n[e].call(s,t):n[e];return o}}function k(t,e){return t.isValid()?(e=z(e,t.lang()),Ke[e]||(Ke[e]=A(e)),Ke[e](t)):t.lang().invalidDate()}function z(t,e){function i(t){return e.longDateFormat(t)||t}var n=5;for(xe.lastIndex=0;n>=0&&xe.test(t);)t=t.replace(xe,i),xe.lastIndex=0,n-=1;return t}function P(t,e){var i,n=e._strict;switch(t){case"DDDD":return Fe;case"YYYY":case"GGGG":case"gggg":return n?Ye:De;case"Y":case"G":case"g":return He;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return n?Re:Ie;case"S":if(n)return ze;case"SS":if(n)return Pe;case"SSS":if(n)return Fe;case"DDD":return Me;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Ne;case"a":case"A":return N(e._l)._meridiemParse;case"X":return ke;case"Z":case"ZZ":return Le;case"T":return Ae;case"SSSS":return Oe;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return n?Pe:Ce;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return Ce;default:return i=new RegExp(V(U(t.replace("\\","")),"i"))}}function F(t){t=t||"";var e=t.match(Le)||[],i=e[e.length-1]||[],n=(i+"").match(Ge)||["-",0,0],s=+(60*n[1])+b(n[2]);return"+"===n[0]?-s:s}function Y(t,e,i){var n,s=i._a;switch(t){case"M":case"MM":null!=e&&(s[ue]=b(e)-1);break;case"MMM":case"MMMM":n=N(i._l).monthsParse(e),null!=n?s[ue]=n:i._pf.invalidMonth=e;break;case"D":case"DD":null!=e&&(s[pe]=b(e));break;case"DDD":case"DDDD":null!=e&&(i._dayOfYear=b(e));break;case"YY":s[le]=b(e)+(b(e)>68?1900:2e3);break;case"YYYY":case"YYYYY":case"YYYYYY":s[le]=b(e);break;case"a":case"A":i._isPm=N(i._l).isPM(e);break;case"H":case"HH":case"h":case"hh":s[fe]=b(e);break;case"m":case"mm":s[ge]=b(e);break;case"s":case"ss":s[me]=b(e);break;case"S":case"SS":case"SSS":case"SSSS":s[ve]=b(1e3*("0."+e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,i._tzm=F(e);break;case"w":case"ww":case"W":case"WW":case"d":case"dd":case"ddd":case"dddd":case"e":case"E":t=t.substr(0,1);case"gg":case"gggg":case"GG":case"GGGG":case"GGGGG":t=t.substr(0,2),e&&(i._w=i._w||{},i._w[t]=e)}}function R(t){var e,i,n,s,o,r,a,h,d,c,l=[];if(!t._d){for(n=W(t),t._w&&null==t._a[pe]&&null==t._a[ue]&&(o=function(e){var i=parseInt(e,10);return e?e.length<3?i>68?1900+i:2e3+i:i:null==t._a[le]?re().weekYear():t._a[le]},r=t._w,null!=r.GG||null!=r.W||null!=r.E?a=te(o(r.GG),r.W||1,r.E,4,1):(h=N(t._l),d=null!=r.d?K(r.d,h):null!=r.e?parseInt(r.e,10)+h._week.dow:0,c=parseInt(r.w,10)||1,null!=r.d&&dE(s)&&(t._pf._overflowDayOfYear=!0),i=Z(s,0,t._dayOfYear),t._a[ue]=i.getUTCMonth(),t._a[pe]=i.getUTCDate()),e=0;3>e&&null==t._a[e];++e)t._a[e]=l[e]=n[e];for(;7>e;e++)t._a[e]=l[e]=null==t._a[e]?2===e?1:0:t._a[e];l[fe]+=b((t._tzm||0)/60),l[ge]+=b((t._tzm||0)%60),t._d=(t._useUTC?Z:X).apply(null,l)}}function H(t){var e;t._d||(e=_(t._i),t._a=[e.year,e.month,e.day,e.hour,e.minute,e.second,e.millisecond],R(t))}function W(t){var e=new Date;return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function j(t){t._a=[],t._pf.empty=!0;var e,i,n,s,o,r=N(t._l),a=""+t._i,h=a.length,d=0;for(n=z(t._f,r).match(Te)||[],e=0;e0&&t._pf.unusedInput.push(o),a=a.slice(a.indexOf(i)+i.length),d+=i.length),Je[s]?(i?t._pf.empty=!1:t._pf.unusedTokens.push(s),Y(s,i,t)):t._strict&&!i&&t._pf.unusedTokens.push(s);t._pf.charsLeftOver=h-d,a.length>0&&t._pf.unusedInput.push(a),t._isPm&&t._a[fe]<12&&(t._a[fe]+=12),t._isPm===!1&&12===t._a[fe]&&(t._a[fe]=0),R(t),x(t)}function U(t){return t.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,i,n,s){return e||i||n||s})}function V(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function G(t){var e,i,n,o,r;if(0===t._f.length)return t._pf.invalidFormat=!0,void(t._d=new Date(0/0));for(o=0;or)&&(n=r,i=e));c(t,i||e)}function B(t){var e,i,n=t._i,s=We.exec(n);if(s){for(t._pf.iso=!0,e=0,i=Ue.length;i>e;e++)if(Ue[e][1].exec(n)){t._f=Ue[e][0]+(s[6]||" ");break}for(e=0,i=Ve.length;i>e;e++)if(Ve[e][1].exec(n)){t._f+=Ve[e][0];break}n.match(Le)&&(t._f+="Z"),j(t)}else t._d=new Date(n)}function q(t){var e=t._i,i=be.exec(e);e===n?t._d=new Date:i?t._d=new Date(+i[1]):"string"==typeof e?B(t):g(e)?(t._a=e.slice(0),R(t)):m(e)?t._d=new Date(+e):"object"==typeof e?H(t):t._d=new Date(e)}function X(t,e,i,n,s,o,r){var a=new Date(t,e,i,n,s,o,r);return 1970>t&&a.setFullYear(t),a}function Z(t){var e=new Date(Date.UTC.apply(null,arguments));return 1970>t&&e.setUTCFullYear(t),e}function K(t,e){if("string"==typeof t)if(isNaN(t)){if(t=e.weekdaysParse(t),"number"!=typeof t)return null}else t=parseInt(t,10);return t}function $(t,e,i,n,s){return s.relativeTime(e||1,!!i,t,n)}function Q(t,e,i){var n=ce(Math.abs(t)/1e3),s=ce(n/60),o=ce(s/60),r=ce(o/24),a=ce(r/365),h=45>n&&["s",n]||1===s&&["m"]||45>s&&["mm",s]||1===o&&["h"]||22>o&&["hh",o]||1===r&&["d"]||25>=r&&["dd",r]||45>=r&&["M"]||345>r&&["MM",ce(r/30)]||1===a&&["y"]||["yy",a];return h[2]=e,h[3]=t>0,h[4]=i,$.apply({},h)}function J(t,e,i){var n,s=i-e,o=i-t.day();return o>s&&(o-=7),s-7>o&&(o+=7),n=re(t).add("d",o),{week:Math.ceil(n.dayOfYear()/7),year:n.year()}}function te(t,e,i,n,s){var o,r,a=Z(t,0,1).getUTCDay();return i=null!=i?i:s,o=s-a+(a>n?7:0)-(s>a?7:0),r=7*(e-1)+(i-s)+o+1,{year:r>0?t:t-1,dayOfYear:r>0?r:E(t-1)+r}}function ee(t){var e=t._i,i=t._f;return null===e?re.invalid({nullInput:!0}):("string"==typeof e&&(t._i=e=N().preparse(e)),re.isMoment(e)?(t=l(e),t._d=new Date(+e._d)):i?g(i)?G(t):j(t):q(t),new h(t))}function ie(t,e){re.fn[t]=re.fn[t+"s"]=function(t){var i=this._isUTC?"UTC":"";return null!=t?(this._d["set"+i+e](t),re.updateOffset(this),this):this._d["get"+i+e]()}}function ne(t){re.duration.fn[t]=function(){return this._data[t]}}function se(t,e){re.duration.fn["as"+t]=function(){return+this/e}}function oe(t){var e=!1,i=re;"undefined"==typeof ender&&(t?(de.moment=function(){return!e&&console&&console.warn&&(e=!0,console.warn("Accessing Moment through the global scope is deprecated, and will be removed in an upcoming release.")),i.apply(null,arguments)},c(de.moment,i)):de.moment=re)}for(var re,ae,he="2.5.1",de=this,ce=Math.round,le=0,ue=1,pe=2,fe=3,ge=4,me=5,ve=6,ye={},_e={_isAMomentObject:null,_i:null,_f:null,_l:null,_strict:null,_isUTC:null,_offset:null,_pf:null,_lang:null},we="undefined"!=typeof i&&i.exports&&"undefined"!=typeof e,be=/^\/?Date\((\-?\d+)/i,Se=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,Ee=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,Te=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g,xe=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,Ce=/\d\d?/,Me=/\d{1,3}/,De=/\d{1,4}/,Ie=/[+\-]?\d{1,6}/,Oe=/\d+/,Ne=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Le=/Z|[\+\-]\d\d:?\d\d/gi,Ae=/T/i,ke=/[\+\-]?\d+(\.\d{1,3})?/,ze=/\d/,Pe=/\d\d/,Fe=/\d{3}/,Ye=/\d{4}/,Re=/[+-]?\d{6}/,He=/[+-]?\d+/,We=/^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,je="YYYY-MM-DDTHH:mm:ssZ",Ue=[["YYYYYY-MM-DD",/[+-]\d{6}-\d{2}-\d{2}/],["YYYY-MM-DD",/\d{4}-\d{2}-\d{2}/],["GGGG-[W]WW-E",/\d{4}-W\d{2}-\d/],["GGGG-[W]WW",/\d{4}-W\d{2}/],["YYYY-DDD",/\d{4}-\d{3}/]],Ve=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d{1,3}/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],Ge=/([\+\-]|\d\d)/gi,Be="Date|Hours|Minutes|Seconds|Milliseconds".split("|"),qe={Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6},Xe={ms:"millisecond",s:"second",m:"minute",h:"hour",d:"day",D:"date",w:"week",W:"isoWeek",M:"month",y:"year",DDD:"dayOfYear",e:"weekday",E:"isoWeekday",gg:"weekYear",GG:"isoWeekYear"},Ze={dayofyear:"dayOfYear",isoweekday:"isoWeekday",isoweek:"isoWeek",weekyear:"weekYear",isoweekyear:"isoWeekYear"},Ke={},$e="DDD w W M D d".split(" "),Qe="M D H h m s w W".split(" "),Je={M:function(){return this.month()+1},MMM:function(t){return this.lang().monthsShort(this,t)},MMMM:function(t){return this.lang().months(this,t)},D:function(){return this.date()},DDD:function(){return this.dayOfYear()},d:function(){return this.day()},dd:function(t){return this.lang().weekdaysMin(this,t)},ddd:function(t){return this.lang().weekdaysShort(this,t)},dddd:function(t){return this.lang().weekdays(this,t)},w:function(){return this.week()},W:function(){return this.isoWeek()},YY:function(){return p(this.year()%100,2)},YYYY:function(){return p(this.year(),4)},YYYYY:function(){return p(this.year(),5)},YYYYYY:function(){var t=this.year(),e=t>=0?"+":"-";return e+p(Math.abs(t),6)},gg:function(){return p(this.weekYear()%100,2)},gggg:function(){return p(this.weekYear(),4)},ggggg:function(){return p(this.weekYear(),5)},GG:function(){return p(this.isoWeekYear()%100,2)},GGGG:function(){return p(this.isoWeekYear(),4)},GGGGG:function(){return p(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.lang().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.lang().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return b(this.milliseconds()/100)},SS:function(){return p(b(this.milliseconds()/10),2)},SSS:function(){return p(this.milliseconds(),3)},SSSS:function(){return p(this.milliseconds(),3)},Z:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(b(t/60),2)+":"+p(b(t)%60,2)},ZZ:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(b(t/60),2)+p(b(t)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},X:function(){return this.unix()},Q:function(){return this.quarter()}},ti=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"];$e.length;)ae=$e.pop(),Je[ae+"o"]=r(Je[ae],ae);for(;Qe.length;)ae=Qe.pop(),Je[ae+ae]=o(Je[ae],2);for(Je.DDDD=o(Je.DDD,3),c(a.prototype,{set:function(t){var e,i;for(i in t)e=t[i],"function"==typeof e?this[i]=e:this["_"+i]=e},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(t){return this._months[t.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(t){return this._monthsShort[t.month()]},monthsParse:function(t){var e,i,n;for(this._monthsParse||(this._monthsParse=[]),e=0;12>e;e++)if(this._monthsParse[e]||(i=re.utc([2e3,e]),n="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[e]=new RegExp(n.replace(".",""),"i")),this._monthsParse[e].test(t))return e},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(t){return this._weekdays[t.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(t){return this._weekdaysShort[t.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(t){return this._weekdaysMin[t.day()]},weekdaysParse:function(t){var e,i,n;for(this._weekdaysParse||(this._weekdaysParse=[]),e=0;7>e;e++)if(this._weekdaysParse[e]||(i=re([2e3,1]).day(e),n="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[e]=new RegExp(n.replace(".",""),"i")),this._weekdaysParse[e].test(t))return e},_longDateFormat:{LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D YYYY",LLL:"MMMM D YYYY LT",LLLL:"dddd, MMMM D YYYY LT"},longDateFormat:function(t){var e=this._longDateFormat[t];return!e&&this._longDateFormat[t.toUpperCase()]&&(e=this._longDateFormat[t.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t]=e),e},isPM:function(t){return"p"===(t+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(t,e,i){return t>11?i?"pm":"PM":i?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(t,e){var i=this._calendar[t];return"function"==typeof i?i.apply(e):i},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(t,e,i,n){var s=this._relativeTime[i];return"function"==typeof s?s(t,e,i,n):s.replace(/%d/i,t)},pastFuture:function(t,e){var i=this._relativeTime[t>0?"future":"past"];return"function"==typeof i?i(e):i.replace(/%s/i,e)},ordinal:function(t){return this._ordinal.replace("%d",t)},_ordinal:"%d",preparse:function(t){return t},postformat:function(t){return t},week:function(t){return J(t,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),re=function(t,e,i,o){var r;return"boolean"==typeof i&&(o=i,i=n),r={},r._isAMomentObject=!0,r._i=t,r._f=e,r._l=i,r._strict=o,r._isUTC=!1,r._pf=s(),ee(r)},re.utc=function(t,e,i,o){var r;return"boolean"==typeof i&&(o=i,i=n),r={},r._isAMomentObject=!0,r._useUTC=!0,r._isUTC=!0,r._l=i,r._i=t,r._f=e,r._strict=o,r._pf=s(),ee(r).utc()},re.unix=function(t){return re(1e3*t)},re.duration=function(t,e){var i,n,s,o=t,r=null;return re.isDuration(t)?o={ms:t._milliseconds,d:t._days,M:t._months}:"number"==typeof t?(o={},e?o[e]=t:o.milliseconds=t):(r=Se.exec(t))?(i="-"===r[1]?-1:1,o={y:0,d:b(r[pe])*i,h:b(r[fe])*i,m:b(r[ge])*i,s:b(r[me])*i,ms:b(r[ve])*i}):(r=Ee.exec(t))&&(i="-"===r[1]?-1:1,s=function(t){var e=t&&parseFloat(t.replace(",","."));return(isNaN(e)?0:e)*i},o={y:s(r[2]),M:s(r[3]),d:s(r[4]),h:s(r[5]),m:s(r[6]),s:s(r[7]),w:s(r[8])}),n=new d(o),re.isDuration(t)&&t.hasOwnProperty("_lang")&&(n._lang=t._lang),n},re.version=he,re.defaultFormat=je,re.updateOffset=function(){},re.lang=function(t,e){var i;return t?(e?I(M(t),e):null===e?(O(t),t="en"):ye[t]||N(t),i=re.duration.fn._lang=re.fn._lang=N(t),i._abbr):re.fn._lang._abbr},re.langData=function(t){return t&&t._lang&&t._lang._abbr&&(t=t._lang._abbr),N(t)},re.isMoment=function(t){return t instanceof h||null!=t&&t.hasOwnProperty("_isAMomentObject")},re.isDuration=function(t){return t instanceof d},ae=ti.length-1;ae>=0;--ae)w(ti[ae]);for(re.normalizeUnits=function(t){return y(t)},re.invalid=function(t){var e=re.utc(0/0);return null!=t?c(e._pf,t):e._pf.userInvalidated=!0,e},re.parseZone=function(t){return re(t).parseZone()},c(re.fn=h.prototype,{clone:function(){return re(this)},valueOf:function(){return+this._d+6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().lang("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){var t=re(this).utc();return 00:!1},parsingFlags:function(){return c({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(){return this.zone(0)},local:function(){return this.zone(0),this._isUTC=!1,this},format:function(t){var e=k(this,t||re.defaultFormat);return this.lang().postformat(e)},add:function(t,e){var i;return i="string"==typeof t?re.duration(+e,t):re.duration(t,e),f(this,i,1),this},subtract:function(t,e){var i;return i="string"==typeof t?re.duration(+e,t):re.duration(t,e),f(this,i,-1),this},diff:function(t,e,i){var n,s,o=D(t,this),r=6e4*(this.zone()-o.zone());return e=y(e),"year"===e||"month"===e?(n=432e5*(this.daysInMonth()+o.daysInMonth()),s=12*(this.year()-o.year())+(this.month()-o.month()),s+=(this-re(this).startOf("month")-(o-re(o).startOf("month")))/n,s-=6e4*(this.zone()-re(this).startOf("month").zone()-(o.zone()-re(o).startOf("month").zone()))/n,"year"===e&&(s/=12)):(n=this-o,s="second"===e?n/1e3:"minute"===e?n/6e4:"hour"===e?n/36e5:"day"===e?(n-r)/864e5:"week"===e?(n-r)/6048e5:n),i?s:u(s)},from:function(t,e){return re.duration(this.diff(t)).lang(this.lang()._abbr).humanize(!e)},fromNow:function(t){return this.from(re(),t)},calendar:function(){var t=D(re(),this).startOf("day"),e=this.diff(t,"days",!0),i=-6>e?"sameElse":-1>e?"lastWeek":0>e?"lastDay":1>e?"sameDay":2>e?"nextDay":7>e?"nextWeek":"sameElse";return this.format(this.lang().calendar(i,this))},isLeapYear:function(){return T(this.year())},isDST:function(){return this.zone()+re(t).startOf(e)},isBefore:function(t,e){return e="undefined"!=typeof e?e:"millisecond",+this.clone().startOf(e)<+re(t).startOf(e)},isSame:function(t,e){return e=e||"ms",+this.clone().startOf(e)===+D(t,this).startOf(e)},min:function(t){return t=re.apply(null,arguments),this>t?this:t},max:function(t){return t=re.apply(null,arguments),t>this?this:t},zone:function(t){var e=this._offset||0;return null==t?this._isUTC?e:this._d.getTimezoneOffset():("string"==typeof t&&(t=F(t)),Math.abs(t)<16&&(t=60*t),this._offset=t,this._isUTC=!0,e!==t&&f(this,re.duration(e-t,"m"),1,!0),this)},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.zone(this._tzm):"string"==typeof this._i&&this.zone(this._i),this},hasAlignedHourOffset:function(t){return t=t?re(t).zone():0,(this.zone()-t)%60===0},daysInMonth:function(){return S(this.year(),this.month())},dayOfYear:function(t){var e=ce((re(this).startOf("day")-re(this).startOf("year"))/864e5)+1;return null==t?e:this.add("d",t-e)},quarter:function(){return Math.ceil((this.month()+1)/3)},weekYear:function(t){var e=J(this,this.lang()._week.dow,this.lang()._week.doy).year;return null==t?e:this.add("y",t-e)},isoWeekYear:function(t){var e=J(this,1,4).year;return null==t?e:this.add("y",t-e)},week:function(t){var e=this.lang().week(this);return null==t?e:this.add("d",7*(t-e))},isoWeek:function(t){var e=J(this,1,4).week;return null==t?e:this.add("d",7*(t-e))},weekday:function(t){var e=(this.day()+7-this.lang()._week.dow)%7;return null==t?e:this.add("d",t-e)},isoWeekday:function(t){return null==t?this.day()||7:this.day(this.day()%7?t:t-7)},get:function(t){return t=y(t),this[t]()},set:function(t,e){return t=y(t),"function"==typeof this[t]&&this[t](e),this},lang:function(t){return t===n?this._lang:(this._lang=N(t),this)}}),ae=0;ae-1?!1:"INPUT"==i||"SELECT"==i||"TEXTAREA"==i||e.contentEditable&&"true"==e.contentEditable}function o(t,e){return t.sort().join(",")===e.sort().join(",")}function r(t){t=t||{};var e,i=!1;for(e in M)t[e]?i=!0:M[e]=0;i||(I=!1)}function a(t,e,i,n,s){var r,a,h=[];if(!x[t])return[];for("keyup"==i&&u(t)&&(e=[t]),r=0;r95&&112>t||b.hasOwnProperty(t)&&(_[b[t]]=t)}return _}function g(t,e,i){return i||(i=f()[t]?"keydown":"keypress"),"keypress"==i&&e.length&&(i="keydown"),i}function m(t,e,i,s){M[t]=0,s||(s=g(e[0],[]));var o,a=function(){I=s,++M[t],p()},h=function(t){d(i,t),"keyup"!==s&&(D=n(t)),setTimeout(r,10)};for(o=0;o1)return m(t,d,e,i);for(h="+"===t?["+"]:t.split("+"),o=0;o":".","?":"/","|":"\\"},T={option:"alt",command:"meta","return":"enter",escape:"esc"},x={},C={},M={},D=!1,I=!1,O=1;20>O;++O)b[111+O]="f"+O;for(O=0;9>=O;++O)b[O+96]=O;i(document,"keypress",l),i(document,"keydown",l),i(document,"keyup",l);var N={bind:function(t,e,i){return y(t instanceof Array?t:[t],e,i),C[t+":"+i]=e,this},unbind:function(t,e){return C[t+":"+e]&&(delete C[t+":"+e],this.bind(t,function(){},e)),this},trigger:function(t,e){return C[t+":"+e](),this},reset:function(){return x={},C={},this}};e.exports=N},{}]},{},[1])(1)}); ->>>>>>> origin/gh-pages +!function(t){if("object"==typeof exports)module.exports=t();else if("function"==typeof define&&define.amd)define(t);else{var e;"undefined"!=typeof window?e=window:"undefined"!=typeof global?e=global:"undefined"!=typeof self&&(e=self),e.vis=t()}}(function(){var t;return function e(t,i,n){function s(r,a){if(!i[r]){if(!t[r]){var h="function"==typeof require&&require;if(!a&&h)return h(r,!0);if(o)return o(r,!0);throw new Error("Cannot find module '"+r+"'")}var c=i[r]={exports:{}};t[r][0].call(c.exports,function(e){var i=t[r][1][e];return s(i?i:e)},c,c.exports,e,t,i,n)}return i[r].exports}for(var o="function"==typeof require&&require,r=0;ri;++i)t.call(e||this,this[i],i,this)}),Array.prototype.map||(Array.prototype.map=function(t,e){var i,n,s;if(null==this)throw new TypeError(" this is null or not defined");var o=Object(this),r=o.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(e&&(i=e),n=new Array(r),s=0;r>s;){var a,h;s in o&&(a=o[s],h=t.call(i,a,s,o),n[s]=h),s++}return n}),Array.prototype.filter||(Array.prototype.filter=function(t){"use strict";if(null==this)throw new TypeError;var e=Object(this),i=e.length>>>0;if("function"!=typeof t)throw new TypeError;for(var n=[],s=arguments[1],o=0;i>o;o++)if(o in e){var r=e[o];t.call(s,r,o,e)&&n.push(r)}return n}),Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,e=!{toString:null}.propertyIsEnumerable("toString"),i=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],n=i.length;return function(s){if("object"!=typeof s&&"function"!=typeof s||null===s)throw new TypeError("Object.keys called on non-object");var o=[];for(var r in s)t.call(s,r)&&o.push(r);if(e)for(var a=0;n>a;a++)t.call(s,i[a])&&o.push(i[a]);return o}}()),Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s}),Object.create||(Object.create=function(t){function e(){}if(arguments.length>1)throw new Error("Object.create implementation only accepts the first parameter.");return e.prototype=t,new e}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s});var z={};z.isNumber=function(t){return t instanceof Number||"number"==typeof t},z.isString=function(t){return t instanceof String||"string"==typeof t},z.isDate=function(t){if(t instanceof Date)return!0;if(z.isString(t)){var e=P.exec(t);if(e)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},z.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},z.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},z.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var n=arguments[e];for(var s in n)n.hasOwnProperty(s)&&void 0!==n[s]&&(t[s]=n[s])}return t},z.convert=function(t,e){var i;if(void 0===t)return void 0;if(null===t)return null;if(!e)return t;if("string"!=typeof e&&!(e instanceof String))throw new Error("Type must be a string");switch(e){case"boolean":case"Boolean":return Boolean(t);case"number":case"Number":return Number(t.valueOf());case"string":case"String":return String(t);case"Date":if(z.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(L.isMoment(t))return new Date(t.valueOf());if(z.isString(t))return i=P.exec(t),i?new Date(Number(i[1])):L(t).toDate();throw new Error("Cannot convert object of type "+z.getType(t)+" to type Date");case"Moment":if(z.isNumber(t))return L(t);if(t instanceof Date)return L(t.valueOf());if(L.isMoment(t))return L(t);if(z.isString(t))return i=P.exec(t),L(i?Number(i[1]):t);throw new Error("Cannot convert object of type "+z.getType(t)+" to type Date");case"ISODate":if(z.isNumber(t))return new Date(t);if(t instanceof Date)return t.toISOString();if(L.isMoment(t))return t.toDate().toISOString();if(z.isString(t))return i=P.exec(t),i?new Date(Number(i[1])).toISOString():new Date(t).toISOString();throw new Error("Cannot convert object of type "+z.getType(t)+" to type ISODate");case"ASPDate":if(z.isNumber(t))return"/Date("+t+")/";if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(z.isString(t)){i=P.exec(t);var n;return n=i?new Date(Number(i[1])).valueOf():new Date(t).valueOf(),"/Date("+n+")/"}throw new Error("Cannot convert object of type "+z.getType(t)+" to type ASPDate");default:throw new Error("Cannot convert object of type "+z.getType(t)+' to type "'+e+'"')}};var P=/^\/?Date\((\-?\d+)/i;z.getType=function(t){var e=typeof t;return"object"==e?null==t?"null":t instanceof Boolean?"Boolean":t instanceof Number?"Number":t instanceof String?"String":t instanceof Array?"Array":t instanceof Date?"Date":"Object":"number"==e?"Number":"boolean"==e?"Boolean":"string"==e?"String":e},z.getAbsoluteLeft=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetLeft,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetLeft,n-=s.scrollLeft,s=s.offsetParent;return n},z.getAbsoluteTop=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetTop,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetTop,n-=s.scrollTop,s=s.offsetParent;return n},z.getPageY=function(t){if("pageY"in t)return t.pageY;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientY:t.clientY;var i=document.documentElement,n=document.body;return e+(i&&i.scrollTop||n&&n.scrollTop||0)-(i&&i.clientTop||n&&n.clientTop||0)},z.getPageX=function(t){if("pageY"in t)return t.pageX;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientX:t.clientX;var i=document.documentElement,n=document.body;return e+(i&&i.scrollLeft||n&&n.scrollLeft||0)-(i&&i.clientLeft||n&&n.clientLeft||0)},z.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},z.removeClassName=function(t,e){var i=t.className.split(" "),n=i.indexOf(e);-1!=n&&(i.splice(n,1),t.className=i.join(" "))},z.forEach=function(t,e){var i,n;if(t instanceof Array)for(i=0,n=t.length;n>i;i++)e(t[i],i,t);else for(i in t)t.hasOwnProperty(i)&&e(t[i],i,t)},z.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},z.addEventListener=function(t,e,i,n){t.addEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.addEventListener(e,i,n)):t.attachEvent("on"+e,i)},z.removeEventListener=function(t,e,i,n){t.removeEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.removeEventListener(e,i,n)):t.detachEvent("on"+e,i)},z.getTarget=function(t){t||(t=window.event);var e;return t.target?e=t.target:t.srcElement&&(e=t.srcElement),void 0!=e.nodeType&&3==e.nodeType&&(e=e.parentNode),e},z.stopPropagation=function(t){t||(t=window.event),t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},z.fakeGesture=function(t,e){var i=null;return N.event.collectEventData(this,i,e)},z.preventDefault=function(t){t||(t=window.event),t.preventDefault?t.preventDefault():t.returnValue=!1},z.option={},z.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},z.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},z.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?String(t):e||null},z.option.asSize=function(t,e){return"function"==typeof t&&(t=t()),z.isString(t)?t:z.isNumber(t)?t+"px":e||null},z.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null},utli.hexToRGB=function(t){var e=GiveDec(t.substring(0,1)),i=GiveDec(t.substring(1,2)),n=GiveDec(t.substring(2,3)),s=GiveDec(t.substring(3,4)),o=GiveDec(t.substring(4,5)),r=GiveDec(t.substring(5,6)),a=16*e+i,h=16*n+s,i=16*o+r;return{r:a,g:h,b:i}},utli.RGBToHex=function(t,e,i){var n=GiveHex(Math.floor(t/16)),s=GiveHex(t%16),o=GiveHex(Math.floor(e/16)),r=GiveHex(e%16),a=GiveHex(Math.floor(i/16)),h=GiveHex(i%16),c=n+s+o+r+a+h;return c},utli.RGBToHSV=function(t,e,i){t/=255,e/=255,i/=255;var n=Math.min(t,Math.min(e,i)),s=Math.max(t,Math.max(e,i));if(n==s)return{h:0,s:0,v:n};var o=t==n?e-i:i==n?t-e:i-t,r=t==n?3:i==n?1:5,a=60*(r-o/(s-n)),h=(s-n)/s,c=s;return{h:a,s:h,v:c}},z.HSVToRGB=function(t,e,i){var n,s,o,r,a,h,c,d;switch(t&&void 0===e&&void 0===i&&(e=t.s,i=t.v,t=t.h),r=Math.floor(6*t),a=6*t-r,h=i*(1-e),c=i*(1-a*e),d=i*(1-(1-a)*e),r%6){case 0:n=i,s=d,o=h;break;case 1:n=c,s=i,o=h;break;case 2:n=h,s=i,o=d;break;case 3:n=h,s=c,o=i;break;case 4:n=d,s=h,o=i;break;case 5:n=i,s=h,o=c}return{r:Math.floor(255*n),g:Math.floor(255*s),b:Math.floor(255*o)}};var F={listeners:[],indexOf:function(t){for(var e=this.listeners,i=0,n=this.listeners.length;n>i;i++){var s=e[i];if(s&&s.object==t)return i}return-1},addListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];s||(s={object:t,events:{}},this.listeners.push(s));var o=s.events[e];o||(o=[],s.events[e]=o),-1==o.indexOf(i)&&o.push(i)},removeListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];o&&(n=o.indexOf(i),-1!=n&&o.splice(n,1),0==o.length&&delete s.events[e]);var r=0,a=s.events;for(var h in a)a.hasOwnProperty(h)&&r++;0==r&&delete this.listeners[n]}},removeAllListeners:function(){this.listeners=[]},trigger:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];if(o)for(var r=0,a=o.length;a>r;r++)o[r](i)}}};s.prototype.on=function(t,e,i){var n=t instanceof RegExp?t:new RegExp(t.replace("*","\\w+")),s={id:z.randomUUID(),event:t,regexp:n,callback:"function"==typeof e?e:null,target:i};return this.subscriptions.push(s),s.id},s.prototype.off=function(t){for(var e=0;eo;o++)i=s._addItem(t[o]),n.push(i);else if(z.isDataTable(t))for(var a=this._getColumnNames(t),h=0,c=t.getNumberOfRows();c>h;h++){for(var d={},l=0,u=a.length;u>l;l++){var p=a[l];d[p]=t.getValue(h,l)}i=s._addItem(d),n.push(i)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");i=s._addItem(t),n.push(i)}return n.length&&this._trigger("add",{items:n},e),n},o.prototype.update=function(t,e){var i=[],n=[],s=this,o=s.fieldId,r=function(t){var e=t[o];s.data[e]?(e=s._updateItem(t),n.push(e)):(e=s._addItem(t),i.push(e))};if(t instanceof Array)for(var a=0,h=t.length;h>a;a++)r(t[a]);else if(z.isDataTable(t))for(var c=this._getColumnNames(t),d=0,l=t.getNumberOfRows();l>d;d++){for(var u={},p=0,f=c.length;f>p;p++){var g=c[p];u[g]=t.getValue(d,p)}r(u)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");r(t)}return i.length&&this._trigger("add",{items:i},e),n.length&&this._trigger("update",{items:n},e),i.concat(n)},o.prototype.get=function(){var t,e,i,n,s=this,o=this.showInternalIds,r=z.getType(arguments[0]);"String"==r||"Number"==r?(t=arguments[0],i=arguments[1],n=arguments[2]):"Array"==r?(e=arguments[0],i=arguments[1],n=arguments[2]):(i=arguments[0],n=arguments[1]);var a;if(i&&i.type){if(a="DataTable"==i.type?"DataTable":"Array",n&&a!=z.getType(n))throw new Error('Type of parameter "data" ('+z.getType(n)+") does not correspond with specified options.type ("+i.type+")");if("DataTable"==a&&!z.isDataTable(n))throw new Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else a=n?"DataTable"==z.getType(n)?"DataTable":"Array":"Array";void 0!=i&&void 0!=i.showInternalIds&&(this.showInternalIds=i.showInternalIds);var h,c,d,l,u=i&&i.convert||this.options.convert,p=i&&i.filter,f=[];if(void 0!=t)h=s._getItem(t,u),p&&!p(h)&&(h=null);else if(void 0!=e)for(d=0,l=e.length;l>d;d++)h=s._getItem(e[d],u),(!p||p(h))&&f.push(h);else for(c in this.data)this.data.hasOwnProperty(c)&&(h=s._getItem(c,u),(!p||p(h))&&f.push(h));if(this.showInternalIds=o,i&&i.order&&void 0==t&&this._sort(f,i.order),i&&i.fields){var g=i.fields;if(void 0!=t)h=this._filterFields(h,g);else for(d=0,l=f.length;l>d;d++)f[d]=this._filterFields(f[d],g)}if("DataTable"==a){var m=this._getColumnNames(n);if(void 0!=t)s._appendRow(n,m,h);else for(d=0,l=f.length;l>d;d++)s._appendRow(n,m,f[d]);return n}if(void 0!=t)return h;if(n){for(d=0,l=f.length;l>d;d++)n.push(f[d]);return n}return f},o.prototype.getIds=function(t){var e,i,n,s,o,r=this.data,a=t&&t.filter,h=t&&t.order,c=t&&t.convert||this.options.convert,d=[];if(a)if(h){o=[];for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,c),a(s)&&o.push(s));for(this._sort(o,h),e=0,i=o.length;i>e;e++)d[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,c),a(s)&&d.push(s[this.fieldId]));else if(h){o=[];for(n in r)r.hasOwnProperty(n)&&o.push(r[n]);for(this._sort(o,h),e=0,i=o.length;i>e;e++)d[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=r[n],d.push(s[this.fieldId]));return d},o.prototype.forEach=function(t,e){var i,n,s=e&&e.filter,o=e&&e.convert||this.options.convert,r=this.data;if(e&&e.order)for(var a=this.get(e),h=0,c=a.length;c>h;h++)i=a[h],n=i[this.fieldId],t(i,n);else for(n in r)r.hasOwnProperty(n)&&(i=this._getItem(n,o),(!s||s(i))&&t(i,n))},o.prototype.map=function(t,e){var i,n=e&&e.filter,s=e&&e.convert||this.options.convert,o=[],r=this.data;for(var a in r)r.hasOwnProperty(a)&&(i=this._getItem(a,s),(!n||n(i))&&o.push(t(i,a)));return e&&e.order&&this._sort(o,e.order),o},o.prototype._filterFields=function(t,e){var i={};for(var n in t)t.hasOwnProperty(n)&&-1!=e.indexOf(n)&&(i[n]=t[n]);return i},o.prototype._sort=function(t,e){if(z.isString(e)){var i=e;t.sort(function(t,e){var n=t[i],s=e[i];return n>s?1:s>n?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},o.prototype.remove=function(t,e){var i,n,s,o=[];if(t instanceof Array)for(i=0,n=t.length;n>i;i++)s=this._remove(t[i]),null!=s&&o.push(s);else s=this._remove(t),null!=s&&o.push(s);return o.length&&this._trigger("remove",{items:o},e),o},o.prototype._remove=function(t){if(z.isNumber(t)||z.isString(t)){if(this.data[t])return delete this.data[t],delete this.internalIds[t],t}else if(t instanceof Object){var e=t[this.fieldId];if(e&&this.data[e])return delete this.data[e],delete this.internalIds[e],e}return null},o.prototype.clear=function(t){var e=Object.keys(this.data);return this.data={},this.internalIds={},this._trigger("remove",{items:e},t),e},o.prototype.max=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||r>n)&&(i=o,n=r)}return i},o.prototype.min=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||n>r)&&(i=o,n=r)}return i},o.prototype.distinct=function(t){var e=this.data,i=[],n=this.options.convert[t],s=0;for(var o in e)if(e.hasOwnProperty(o)){for(var r=e[o],a=z.convert(r[t],n),h=!1,c=0;s>c;c++)if(i[c]==a){h=!0;break}h||(i[s]=a,s++)}return i},o.prototype._addItem=function(t){var e=t[this.fieldId];if(void 0!=e){if(this.data[e])throw new Error("Cannot add item: item with id "+e+" already exists")}else e=z.randomUUID(),t[this.fieldId]=e,this.internalIds[e]=t;var i={};for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=z.convert(t[n],s)}return this.data[e]=i,e},o.prototype._getItem=function(t,e){var i,n,s=this.data[t];if(!s)return null;var o={},r=this.fieldId,a=this.internalIds;if(e)for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a&&!this.showInternalIds||(o[i]=z.convert(n,e[i])));else for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a&&!this.showInternalIds||(o[i]=n));return o},o.prototype._updateItem=function(t){var e=t[this.fieldId];if(void 0==e)throw new Error("Cannot update item: item has no id (item: "+JSON.stringify(t)+")");var i=this.data[e];if(!i)throw new Error("Cannot update item: no item with id "+e+" found");for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=z.convert(t[n],s)}return e},o.prototype.isInternalId=function(t){return t in this.internalIds},o.prototype._getColumnNames=function(t){for(var e=[],i=0,n=t.getNumberOfColumns();n>i;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},o.prototype._appendRow=function(t,e,i){for(var n=t.addRow(),s=0,o=e.length;o>s;s++){var r=e[s];t.setValue(n,s,i[r])}},r.prototype.setData=function(t){var e,i,n;if(this.data){this.data.unsubscribe&&this.data.unsubscribe("*",this.listener),e=[];for(var s in this.ids)this.ids.hasOwnProperty(s)&&e.push(s);this.ids={},this._trigger("remove",{items:e})}if(this.data=t,this.data){for(this.fieldId=this.options.fieldId||this.data&&this.data.options&&this.data.options.fieldId||"id",e=this.data.getIds({filter:this.options&&this.options.filter}),i=0,n=e.length;n>i;i++)s=e[i],this.ids[s]=!0;this._trigger("add",{items:e}),this.data.subscribe&&this.data.subscribe("*",this.listener)}},r.prototype.get=function(){var t,e,i,n=this,s=z.getType(arguments[0]);"String"==s||"Number"==s||"Array"==s?(t=arguments[0],e=arguments[1],i=arguments[2]):(e=arguments[0],i=arguments[1]);var o=z.extend({},this.options,e);this.options.filter&&e&&e.filter&&(o.filter=function(t){return n.options.filter(t)&&e.filter(t)});var r=[];return void 0!=t&&r.push(t),r.push(o),r.push(i),this.data&&this.data.get.apply(this.data,r)},r.prototype.getIds=function(t){var e;if(this.data){var i,n=this.options.filter;i=t&&t.filter?n?function(e){return n(e)&&t.filter(e)}:t.filter:n,e=this.data.getIds({filter:i,order:t&&t.order})}else e=[];return e},r.prototype._onEvent=function(t,e,i){var n,s,o,r,a=e&&e.items,h=this.data,c=[],d=[],l=[];if(a&&h){switch(t){case"add":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r&&(this.ids[o]=!0,c.push(o));break;case"update":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r?this.ids[o]?d.push(o):(this.ids[o]=!0,c.push(o)):this.ids[o]&&(delete this.ids[o],l.push(o));break;case"remove":for(n=0,s=a.length;s>n;n++)o=a[n],this.ids[o]&&(delete this.ids[o],l.push(o))}c.length&&this._trigger("add",{items:c},i),d.length&&this._trigger("update",{items:d},i),l.length&&this._trigger("remove",{items:l},i)}},r.prototype.subscribe=o.prototype.subscribe,r.prototype.unsubscribe=o.prototype.unsubscribe,r.prototype._trigger=o.prototype._trigger,TimeStep=function(t,e,i){this.current=new Date,this._start=new Date,this._end=new Date,this.autoScale=!0,this.scale=TimeStep.SCALE.DAY,this.step=1,this.setRange(t,e,i)},TimeStep.SCALE={MILLISECOND:1,SECOND:2,MINUTE:3,HOUR:4,DAY:5,WEEKDAY:6,MONTH:7,YEAR:8},TimeStep.prototype.setRange=function(t,e,i){if(!(t instanceof Date&&e instanceof Date))throw"No legal start or end date in method setRange";this._start=void 0!=t?new Date(t.valueOf()):new Date,this._end=void 0!=e?new Date(e.valueOf()):new Date,this.autoScale&&this.setMinimumStep(i)},TimeStep.prototype.first=function(){this.current=new Date(this._start.valueOf()),this.roundToMinor()},TimeStep.prototype.roundToMinor=function(){switch(this.scale){case TimeStep.SCALE.YEAR:this.current.setFullYear(this.step*Math.floor(this.current.getFullYear()/this.step)),this.current.setMonth(0); +case TimeStep.SCALE.MONTH:this.current.setDate(1);case TimeStep.SCALE.DAY:case TimeStep.SCALE.WEEKDAY:this.current.setHours(0);case TimeStep.SCALE.HOUR:this.current.setMinutes(0);case TimeStep.SCALE.MINUTE:this.current.setSeconds(0);case TimeStep.SCALE.SECOND:this.current.setMilliseconds(0)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.setMilliseconds(this.current.getMilliseconds()-this.current.getMilliseconds()%this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()-this.current.getSeconds()%this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()-this.current.getMinutes()%this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()-this.current.getHours()%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()-1-(this.current.getDate()-1)%this.step+1);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()-this.current.getMonth()%this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()-this.current.getFullYear()%this.step)}},TimeStep.prototype.hasNext=function(){return this.current.valueOf()<=this._end.valueOf()},TimeStep.prototype.next=function(){var t=this.current.valueOf();if(this.current.getMonth()<6)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current=new Date(this.current.valueOf()+1e3*this.step);break;case TimeStep.SCALE.MINUTE:this.current=new Date(this.current.valueOf()+1e3*this.step*60);break;case TimeStep.SCALE.HOUR:this.current=new Date(this.current.valueOf()+1e3*this.step*60*60);var e=this.current.getHours();this.current.setHours(e-e%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}else switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()+this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()+this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()+this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.getMilliseconds()0&&(this.step=e),this.autoScale=!1},TimeStep.prototype.setAutoScale=function(t){this.autoScale=t},TimeStep.prototype.setMinimumStep=function(t){if(void 0!=t){var e=31104e6,i=2592e6,n=864e5,s=36e5,o=6e4,r=1e3,a=1;1e3*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1e3),500*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=500),100*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=100),50*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=50),10*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=10),5*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=5),e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1),3*i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=3),i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=1),5*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=5),2*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=2),n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=1),n/2>t&&(this.scale=TimeStep.SCALE.WEEKDAY,this.step=1),4*s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=4),s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=1),15*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=15),10*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=10),5*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=5),o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=1),15*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=15),10*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=10),5*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=5),r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=1),200*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=200),100*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=100),50*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=50),10*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=10),5*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=5),a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=1)}},TimeStep.prototype.snap=function(t){if(this.scale==TimeStep.SCALE.YEAR){var e=t.getFullYear()+Math.round(t.getMonth()/12);t.setFullYear(Math.round(e/this.step)*this.step),t.setMonth(0),t.setDate(0),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MONTH)t.getDate()>15?(t.setDate(1),t.setMonth(t.getMonth()+1)):t.setDate(1),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0);else if(this.scale==TimeStep.SCALE.DAY||this.scale==TimeStep.SCALE.WEEKDAY){switch(this.step){case 5:case 2:t.setHours(24*Math.round(t.getHours()/24));break;default:t.setHours(12*Math.round(t.getHours()/12))}t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.HOUR){switch(this.step){case 4:t.setMinutes(60*Math.round(t.getMinutes()/60));break;default:t.setMinutes(30*Math.round(t.getMinutes()/30))}t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MINUTE){switch(this.step){case 15:case 10:t.setMinutes(5*Math.round(t.getMinutes()/5)),t.setSeconds(0);break;case 5:t.setSeconds(60*Math.round(t.getSeconds()/60));break;default:t.setSeconds(30*Math.round(t.getSeconds()/30))}t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.SECOND)switch(this.step){case 15:case 10:t.setSeconds(5*Math.round(t.getSeconds()/5)),t.setMilliseconds(0);break;case 5:t.setMilliseconds(1e3*Math.round(t.getMilliseconds()/1e3));break;default:t.setMilliseconds(500*Math.round(t.getMilliseconds()/500))}else if(this.scale==TimeStep.SCALE.MILLISECOND){var i=this.step>5?this.step/2:1;t.setMilliseconds(Math.round(t.getMilliseconds()/i)*i)}},TimeStep.prototype.isMajor=function(){switch(this.scale){case TimeStep.SCALE.MILLISECOND:return 0==this.current.getMilliseconds();case TimeStep.SCALE.SECOND:return 0==this.current.getSeconds();case TimeStep.SCALE.MINUTE:return 0==this.current.getHours()&&0==this.current.getMinutes();case TimeStep.SCALE.HOUR:return 0==this.current.getHours();case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return 1==this.current.getDate();case TimeStep.SCALE.MONTH:return 0==this.current.getMonth();case TimeStep.SCALE.YEAR:return!1;default:return!1}},TimeStep.prototype.getLabelMinor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return L(t).format("SSS");case TimeStep.SCALE.SECOND:return L(t).format("s");case TimeStep.SCALE.MINUTE:return L(t).format("HH:mm");case TimeStep.SCALE.HOUR:return L(t).format("HH:mm");case TimeStep.SCALE.WEEKDAY:return L(t).format("ddd D");case TimeStep.SCALE.DAY:return L(t).format("D");case TimeStep.SCALE.MONTH:return L(t).format("MMM");case TimeStep.SCALE.YEAR:return L(t).format("YYYY");default:return""}},TimeStep.prototype.getLabelMajor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return L(t).format("HH:mm:ss");case TimeStep.SCALE.SECOND:return L(t).format("D MMMM HH:mm");case TimeStep.SCALE.MINUTE:case TimeStep.SCALE.HOUR:return L(t).format("ddd D MMMM");case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return L(t).format("MMMM YYYY");case TimeStep.SCALE.MONTH:return L(t).format("YYYY");case TimeStep.SCALE.YEAR:return"";default:return""}},a.prototype.setOptions=function(t){z.extend(this.options,t)},a.prototype.update=function(){this._order(),this._stack()},a.prototype._order=function(){var t=this.parent.items;if(!t)throw new Error("Cannot stack items: parent does not contain items");var e=[],i=0;z.forEach(t,function(t){t.visible&&(e[i]=t,i++)});var n=this.options.order||this.defaultOptions.order;if("function"!=typeof n)throw new Error("Option order must be a function");e.sort(n),this.ordered=e},a.prototype._stack=function(){var t,e,i,n=this.ordered,s=this.options,o=s.orientation||this.defaultOptions.orientation,r="top"==o;for(i=s.margin&&void 0!==s.margin.item?s.margin.item:this.defaultOptions.margin.item,t=0,e=n.length;e>t;t++){var a=n[t],h=null;do h=this.checkOverlap(n,t,0,t-1,i),null!=h&&(a.top=r?h.top+h.height+i:h.top-a.height-i);while(h)}},a.prototype.checkOverlap=function(t,e,i,n,s){for(var o=this.collision,r=t[e],a=n;a>=i;a--){var h=t[a];if(o(r,h,s)&&a!=e)return h}return null},a.prototype.collision=function(t,e,i){return t.left-ie.left&&t.top-ie.top},h.prototype.setOptions=function(t){z.extend(this.options,t),null!==this.start&&null!==this.end&&this.setRange(this.start,this.end)},h.prototype.subscribe=function(t,e,i){function n(e){s._onMouseWheel(e,t,i)}var s=this;if("move"==e)t.on("dragstart",function(e){s._onDragStart(e,t)}),t.on("drag",function(e){s._onDrag(e,t,i)}),t.on("dragend",function(e){s._onDragEnd(e,t)});else{if("zoom"!=e)throw new TypeError('Unknown event "'+e+'". Choose "move" or "zoom".');t.on("mousewheel",n),t.on("DOMMouseScroll",n),t.on("touch",function(){s._onTouch()}),t.on("pinch",function(e){s._onPinch(e,t,i)})}},h.prototype.on=function(t,e){var i=["rangechange","rangechanged"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());F.addListener(this,t,e)},h.prototype.off=function(t,e){F.removeListener(this,t,e)},h.prototype._trigger=function(t){F.trigger(this,t,{start:this.start,end:this.end})},h.prototype.setRange=function(t,e){var i=this._applyRange(t,e);i&&(this._trigger("rangechange"),this._trigger("rangechanged"))},h.prototype._applyRange=function(t,e){var i,n=null!=t?z.convert(t,"Date").valueOf():this.start,s=null!=e?z.convert(e,"Date").valueOf():this.end,o=null!=this.options.max?z.convert(this.options.max,"Date").valueOf():null,r=null!=this.options.min?z.convert(this.options.min,"Date").valueOf():null;if(isNaN(n)||null===n)throw new Error('Invalid start "'+t+'"');if(isNaN(s)||null===s)throw new Error('Invalid end "'+e+'"');if(n>s&&(s=n),null!==r&&r>n&&(i=r-n,n+=i,s+=i,null!=o&&s>o&&(s=o)),null!==o&&s>o&&(i=s-o,n-=i,s-=i,null!=r&&r>n&&(n=r)),null!==this.options.zoomMin){var a=parseFloat(this.options.zoomMin);0>a&&(a=0),a>s-n&&(this.end-this.start===a?(n=this.start,s=this.end):(i=a-(s-n),n-=i/2,s+=i/2))}if(null!==this.options.zoomMax){var h=parseFloat(this.options.zoomMax);0>h&&(h=0),s-n>h&&(this.end-this.start===h?(n=this.start,s=this.end):(i=s-n-h,n+=i/2,s-=i/2))}var c=this.start!=n||this.end!=s;return this.start=n,this.end=s,c},h.prototype.getRange=function(){return{start:this.start,end:this.end}},h.prototype.conversion=function(t){return h.conversion(this.start,this.end,t)},h.conversion=function(t,e,i){return 0!=i&&e-t!=0?{offset:t,scale:i/(e-t)}:{offset:0,scale:1}};var Y={};h.prototype._onDragStart=function(t,e){if(!Y.pinching){Y.start=this.start,Y.end=this.end;var i=e.frame;i&&(i.style.cursor="move")}},h.prototype._onDrag=function(t,e,i){if(c(i),!Y.pinching){var n="horizontal"==i?t.gesture.deltaX:t.gesture.deltaY,s=Y.end-Y.start,o="horizontal"==i?e.width:e.height,r=-n/o*s;this._applyRange(Y.start+r,Y.end+r),this._trigger("rangechange")}},h.prototype._onDragEnd=function(t,e){Y.pinching||(e.frame&&(e.frame.style.cursor="auto"),this._trigger("rangechanged"))},h.prototype._onMouseWheel=function(t,e,i){c(i);var n=0;if(t.wheelDelta?n=t.wheelDelta/120:t.detail&&(n=-t.detail/3),n){var s;s=0>n?1-n/5:1/(1+n/5);var o=z.fakeGesture(this,t),r=d(o.touches[0],e.frame),a=this._pointerToDate(e,i,r);this.zoom(s,a)}z.preventDefault(t)},h.prototype._onTouch=function(){Y.start=this.start,Y.end=this.end,Y.pinching=!1,Y.center=null},h.prototype._onPinch=function(t,e,i){if(Y.pinching=!0,t.gesture.touches.length>1){Y.center||(Y.center=d(t.gesture.center,e.frame));var n=1/t.gesture.scale,s=this._pointerToDate(e,i,Y.center),o=d(t.gesture.center,e.frame),r=(this._pointerToDate(e,i,o),parseInt(s+(Y.start-s)*n)),a=parseInt(s+(Y.end-s)*n);this.setRange(r,a)}},h.prototype._pointerToDate=function(t,e,i){var n;if("horizontal"==e){var s=t.width;return n=this.conversion(s),i.x/n.scale+n.offset}var o=t.height;return n=this.conversion(o),i.y/n.scale+n.offset},h.prototype.zoom=function(t,e){null==e&&(e=(this.start+this.end)/2);var i=e+(this.start-e)*t,n=e+(this.end-e)*t;this.setRange(i,n)},h.prototype.move=function(t){var e=this.end-this.start,i=this.start+e*t,n=this.end+e*t;this.start=i,this.end=n},h.prototype.moveTo=function(t){var e=(this.start+this.end)/2,i=e-t,n=this.start-i,s=this.end-i;this.setRange(n,s)},l.prototype.add=function(t){if(void 0==t.id)throw new Error("Component has no field id");if(!(t instanceof u||t instanceof l))throw new TypeError("Component must be an instance of prototype Component or Controller");t.controller=this,this.components[t.id]=t},l.prototype.remove=function(t){var e;for(e in this.components)if(this.components.hasOwnProperty(e)&&(e==t||this.components[e]==t))break;e&&delete this.components[e]},l.prototype.requestReflow=function(t){if(t)this.reflow();else if(!this.reflowTimer){var e=this;this.reflowTimer=setTimeout(function(){e.reflowTimer=void 0,e.reflow()},0)}},l.prototype.requestRepaint=function(t){if(t)this.repaint();else if(!this.repaintTimer){var e=this;this.repaintTimer=setTimeout(function(){e.repaintTimer=void 0,e.repaint()},0)}},l.prototype.repaint=function V(){function V(i,n){n in e||(i.depends&&i.depends.forEach(function(t){V(t,t.id)}),i.parent&&V(i.parent,i.parent.id),t=i.repaint()||t,e[n]=!0)}var t=!1;this.repaintTimer&&(clearTimeout(this.repaintTimer),this.repaintTimer=void 0);var e={};z.forEach(this.components,V),t&&this.reflow()},l.prototype.reflow=function G(){function G(i,n){n in e||(i.depends&&i.depends.forEach(function(t){G(t,t.id)}),i.parent&&G(i.parent,i.parent.id),t=i.reflow()||t,e[n]=!0)}var t=!1;this.reflowTimer&&(clearTimeout(this.reflowTimer),this.reflowTimer=void 0);var e={};z.forEach(this.components,G),t&&this.repaint()},u.prototype.setOptions=function(t){t&&(z.extend(this.options,t),this.controller&&(this.requestRepaint(),this.requestReflow()))},u.prototype.getOption=function(t){var e;return this.options&&(e=this.options[t]),void 0===e&&this.defaultOptions&&(e=this.defaultOptions[t]),e},u.prototype.getContainer=function(){return null},u.prototype.getFrame=function(){return this.frame},u.prototype.repaint=function(){return!1},u.prototype.reflow=function(){return!1},u.prototype.hide=function(){return this.frame&&this.frame.parentNode?(this.frame.parentNode.removeChild(this.frame),!0):!1},u.prototype.show=function(){return this.frame&&this.frame.parentNode?!1:this.repaint()},u.prototype.requestRepaint=function(){if(!this.controller)throw new Error("Cannot request a repaint: no controller configured");this.controller.requestRepaint()},u.prototype.requestReflow=function(){if(!this.controller)throw new Error("Cannot request a reflow: no controller configured");this.controller.requestReflow()},p.prototype=new u,p.prototype.setOptions=u.prototype.setOptions,p.prototype.getContainer=function(){return this.frame},p.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.frame;if(!s){s=document.createElement("div"),s.className="panel";var o=n.className;o&&("function"==typeof o?z.addClassName(s,String(o())):z.addClassName(s,String(o))),this.frame=s,t+=1}if(!s.parentNode){if(!this.parent)throw new Error("Cannot repaint panel: no parent attached");var r=this.parent.getContainer();if(!r)throw new Error("Cannot repaint panel: parent has no container element");r.appendChild(s),t+=1}return t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),t>0},p.prototype.reflow=function(){var t=0,e=z.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},f.prototype=new p,f.prototype.setOptions=u.prototype.setOptions,f.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.frame;if(s||(s=document.createElement("div"),this.frame=s,t+=1),!s.parentNode){if(!this.container)throw new Error("Cannot repaint root panel: no container attached");this.container.appendChild(s),t+=1}s.className="vis timeline rootpanel "+n.orientation;var o=n.className;return o&&z.addClassName(s,z.option.asString(o)),t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),this._updateEventEmitters(),this._updateWatch(),t>0},f.prototype.reflow=function(){var t=0,e=z.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},f.prototype._updateWatch=function(){var t=this.getOption("autoResize");t?this._watch():this._unwatch()},f.prototype._watch=function(){var t=this;this._unwatch();var e=function(){var e=t.getOption("autoResize");return e?void(t.frame&&(t.frame.clientWidth!=t.width||t.frame.clientHeight!=t.height)&&t.requestReflow()):void t._unwatch()};z.addEventListener(window,"resize",e),this.watchTimer=setInterval(e,1e3)},f.prototype._unwatch=function(){this.watchTimer&&(clearInterval(this.watchTimer),this.watchTimer=void 0)},f.prototype.on=function(t,e){var i=this.listeners[t];i||(i=[],this.listeners[t]=i),i.push(e),this._updateEventEmitters()},f.prototype._updateEventEmitters=function(){if(this.listeners){var t=this;z.forEach(this.listeners,function(e,i){if(t.emitters||(t.emitters={}),!(i in t.emitters)){var n=t.frame;if(n){var s=function(t){e.forEach(function(e){e(t)})};t.emitters[i]=s,t.hammer||(t.hammer=N(n,{prevent_default:!0})),t.hammer.on(i,s)}}})}},g.prototype=new u,g.prototype.setOptions=u.prototype.setOptions,g.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},g.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},g.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},g.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.props,r=this.step,a=this.frame;if(a||(a=document.createElement("div"),this.frame=a,t+=1),a.className="axis",!a.parentNode){if(!this.parent)throw new Error("Cannot repaint time axis: no parent attached");var h=this.parent.getContainer();if(!h)throw new Error("Cannot repaint time axis: parent has no container element");h.appendChild(a),t+=1}var c=a.parentNode;if(c){var d=a.nextSibling;c.removeChild(a);var l="bottom"==s&&this.props.parentHeight&&this.height?this.props.parentHeight-this.height+"px":"0px";if(t+=e(a.style,"top",i(n.top,l)),t+=e(a.style,"left",i(n.left,"0px")),t+=e(a.style,"width",i(n.width,"100%")),t+=e(a.style,"height",i(n.height,this.height+"px")),this._repaintMeasureChars(),this.step){this._repaintStart(),r.first();for(var u=void 0,p=0;r.hasNext()&&1e3>p;){p++;var f=r.getCurrent(),g=this.toScreen(f),m=r.isMajor();this.getOption("showMinorLabels")&&this._repaintMinorText(g,r.getLabelMinor()),m&&this.getOption("showMajorLabels")?(g>0&&(void 0==u&&(u=g),this._repaintMajorText(g,r.getLabelMajor())),this._repaintMajorLine(g)):this._repaintMinorLine(g),r.next()}if(this.getOption("showMajorLabels")){var v=this.toTime(0),y=r.getLabelMajor(v),_=y.length*(o.majorCharWidth||10)+10;(void 0==u||u>_)&&this._repaintMajorText(0,y)}this._repaintEnd()}this._repaintLine(),d?c.insertBefore(a,d):c.appendChild(a)}return t>0},g.prototype._repaintStart=function(){var t=this.dom,e=t.redundant;e.majorLines=t.majorLines,e.majorTexts=t.majorTexts,e.minorLines=t.minorLines,e.minorTexts=t.minorTexts,t.majorLines=[],t.majorTexts=[],t.minorLines=[],t.minorTexts=[]},g.prototype._repaintEnd=function(){z.forEach(this.dom.redundant,function(t){for(;t.length;){var e=t.pop();e&&e.parentNode&&e.parentNode.removeChild(e)}})},g.prototype._repaintMinorText=function(t,e){var i=this.dom.redundant.minorTexts.shift();if(!i){var n=document.createTextNode("");i=document.createElement("div"),i.appendChild(n),i.className="text minor",this.frame.appendChild(i)}this.dom.minorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.left=t+"px",i.style.top=this.props.minorLabelTop+"px"},g.prototype._repaintMajorText=function(t,e){var i=this.dom.redundant.majorTexts.shift();if(!i){var n=document.createTextNode(e);i=document.createElement("div"),i.className="text major",i.appendChild(n),this.frame.appendChild(i)}this.dom.majorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.top=this.props.majorLabelTop+"px",i.style.left=t+"px"},g.prototype._repaintMinorLine=function(t){var e=this.dom.redundant.minorLines.shift();e||(e=document.createElement("div"),e.className="grid vertical minor",this.frame.appendChild(e)),this.dom.minorLines.push(e);var i=this.props;e.style.top=i.minorLineTop+"px",e.style.height=i.minorLineHeight+"px",e.style.left=t-i.minorLineWidth/2+"px"},g.prototype._repaintMajorLine=function(t){var e=this.dom.redundant.majorLines.shift();e||(e=document.createElement("DIV"),e.className="grid vertical major",this.frame.appendChild(e)),this.dom.majorLines.push(e);var i=this.props;e.style.top=i.majorLineTop+"px",e.style.left=t-i.majorLineWidth/2+"px",e.style.height=i.majorLineHeight+"px"},g.prototype._repaintLine=function(){{var t=this.dom.line,e=this.frame;this.options}this.getOption("showMinorLabels")||this.getOption("showMajorLabels")?(t?(e.removeChild(t),e.appendChild(t)):(t=document.createElement("div"),t.className="grid horizontal major",e.appendChild(t),this.dom.line=t),t.style.top=this.props.lineTop+"px"):t&&t.parentElement&&(e.removeChild(t.line),delete this.dom.line)},g.prototype._repaintMeasureChars=function(){var t,e=this.dom;if(!e.measureCharMinor){t=document.createTextNode("0");var i=document.createElement("DIV");i.className="text minor measure",i.appendChild(t),this.frame.appendChild(i),e.measureCharMinor=i}if(!e.measureCharMajor){t=document.createTextNode("0");var n=document.createElement("DIV");n.className="text major measure",n.appendChild(t),this.frame.appendChild(n),e.measureCharMajor=n}},g.prototype.reflow=function(){var t=0,e=z.updateProperty,i=this.frame,n=this.range;if(!n)throw new Error("Cannot repaint time axis: no range configured");if(i){t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft);var s=this.props,o=this.getOption("showMinorLabels"),r=this.getOption("showMajorLabels"),a=this.dom.measureCharMinor,h=this.dom.measureCharMajor;a&&(s.minorCharHeight=a.clientHeight,s.minorCharWidth=a.clientWidth),h&&(s.majorCharHeight=h.clientHeight,s.majorCharWidth=h.clientWidth);var c=i.parentNode?i.parentNode.offsetHeight:0;switch(c!=s.parentHeight&&(s.parentHeight=c,t+=1),this.getOption("orientation")){case"bottom":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.minorLabelTop=0,s.majorLabelTop=s.minorLabelTop+s.minorLabelHeight,s.minorLineTop=-this.top,s.minorLineHeight=Math.max(this.top+s.majorLabelHeight,0),s.minorLineWidth=1,s.majorLineTop=-this.top,s.majorLineHeight=Math.max(this.top+s.minorLabelHeight+s.majorLabelHeight,0),s.majorLineWidth=1,s.lineTop=0;break;case"top":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.majorLabelTop=0,s.minorLabelTop=s.majorLabelTop+s.majorLabelHeight,s.minorLineTop=s.minorLabelTop,s.minorLineHeight=Math.max(c-s.majorLabelHeight-this.top),s.minorLineWidth=1,s.majorLineTop=0,s.majorLineHeight=Math.max(c-this.top),s.majorLineWidth=1,s.lineTop=s.majorLabelHeight+s.minorLabelHeight;break;default:throw new Error('Unkown orientation "'+this.getOption("orientation")+'"')}var d=s.minorLabelHeight+s.majorLabelHeight;t+=e(this,"width",i.offsetWidth),t+=e(this,"height",d),this._updateConversion();var l=z.convert(n.start,"Number"),u=z.convert(n.end,"Number"),p=this.toTime(5*(s.minorCharWidth||10)).valueOf()-this.toTime(0).valueOf();this.step=new TimeStep(new Date(l),new Date(u),p),t+=e(s.range,"start",l),t+=e(s.range,"end",u),t+=e(s.range,"minimumStep",p.valueOf())}return t>0},g.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},m.prototype=new u,m.prototype.setOptions=u.prototype.setOptions,m.prototype.getContainer=function(){return this.frame},m.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCurrentTime"))return void(t&&(i.removeChild(t),delete this.frame));t||(t=document.createElement("div"),t.className="currenttime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t),this.frame=t),e.conversion||e._updateConversion();var n=new Date,s=e.toScreen(n);t.style.left=s+"px",t.title="Current time: "+n,void 0!==this.currentTimeTimer&&(clearTimeout(this.currentTimeTimer),delete this.currentTimeTimer);var o=this,r=1/e.conversion.scale/2;return 30>r&&(r=30),this.currentTimeTimer=setTimeout(function(){o.repaint()},r),!1},v.prototype=new u,v.prototype.setOptions=u.prototype.setOptions,v.prototype.getContainer=function(){return this.frame},v.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCustomTime"))return void(t&&(i.removeChild(t),delete this.frame));if(!t){t=document.createElement("div"),t.className="customtime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t);var n=document.createElement("div");n.style.position="relative",n.style.top="0px",n.style.left="-10px",n.style.height="100%",n.style.width="20px",t.appendChild(n),this.frame=t,this.subscribe(this,"movetime")}e.conversion||e._updateConversion();var s=e.toScreen(this.customTime);return t.style.left=s+"px",t.title="Time: "+this.customTime,!1},v.prototype._setCustomTime=function(t){this.customTime=new Date(t.valueOf()),this.repaint()},v.prototype._getCustomTime=function(){return new Date(this.customTime.valueOf())},v.prototype.subscribe=function(t,e){var i=this,n={component:t,event:e,callback:function(t){i._onMouseDown(t,n)},params:{}};t.on("mousedown",n.callback),i.listeners.push(n)},v.prototype.on=function(t,e){var i=this.frame;if(!i)throw new Error("Cannot add event listener: no parent attached");F.addListener(this,t,e),z.addEventListener(i,t,e)},v.prototype._onMouseDown=function(t,e){t=t||window.event;var i=e.params,n=t.which?1==t.which:1==t.button;if(n){i.mouseX=z.getPageX(t),i.moved=!1,i.customTime=this.customTime;var s=this;i.onMouseMove||(i.onMouseMove=function(t){s._onMouseMove(t,e)},z.addEventListener(document,"mousemove",i.onMouseMove)),i.onMouseUp||(i.onMouseUp=function(t){s._onMouseUp(t,e)},z.addEventListener(document,"mouseup",i.onMouseUp)),z.stopPropagation(t),z.preventDefault(t)}},v.prototype._onMouseMove=function(t,e){t=t||window.event;var i=e.params,n=this.parent,s=z.getPageX(t);void 0===i.mouseX&&(i.mouseX=s);var o=s-i.mouseX;Math.abs(o)>=1&&(i.moved=!0);var r=n.toScreen(i.customTime),a=r+o,h=n.toTime(a);this._setCustomTime(h),F.trigger(this,"timechange",{customTime:this.customTime}),z.preventDefault(t)},v.prototype._onMouseUp=function(t,e){t=t||window.event;var i=e.params;i.onMouseMove&&(z.removeEventListener(document,"mousemove",i.onMouseMove),i.onMouseMove=null),i.onMouseUp&&(z.removeEventListener(document,"mouseup",i.onMouseUp),i.onMouseUp=null),i.moved&&F.trigger(this,"timechanged",{customTime:this.customTime})},y.prototype=new p,y.types={box:w,range:S,rangeoverflow:E,point:b},y.prototype.setOptions=u.prototype.setOptions,y.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},y.prototype.setSelection=function(t){var e,i,n,s,o;if(t){if(!Array.isArray(t))throw new TypeError("Array expected");for(e=0,i=this.selection.length;i>e;e++)n=this.selection[e],s=this.items[n],s&&s.unselect();for(this.selection=[],e=0,i=t.length;i>e;e++)n=t[e],s=this.items[n],s&&(this.selection.push(n),s.select());o=this.selection.concat([]),F.trigger(this,"select",{ids:o}),this.controller&&this.requestRepaint()}},y.prototype.getSelection=function(){return this.selection.concat([])},y.prototype._deselect=function(t){for(var e=this.selection,i=0,n=e.length;n>i;i++)if(e[i]==t){e.splice(i,1);break}},y.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.defaultOptions,r=this.frame;if(!r){r=document.createElement("div"),r.className="itemset";var a=n.className;a&&z.addClassName(r,z.option.asString(a));var h=document.createElement("div");h.className="background",r.appendChild(h),this.dom.background=h;var c=document.createElement("div");c.className="foreground",r.appendChild(c),this.dom.foreground=c;var d=document.createElement("div");d.className="itemset-axis",this.dom.axis=d,this.frame=r,t+=1}if(!this.parent)throw new Error("Cannot repaint itemset: no parent attached");var l=this.parent.getContainer();if(!l)throw new Error("Cannot repaint itemset: parent has no container element");r.parentNode||(l.appendChild(r),t+=1),this.dom.axis.parentNode||(l.appendChild(this.dom.axis),t+=1),t+=e(r.style,"left",i(n.left,"0px")),t+=e(r.style,"top",i(n.top,"0px")),t+=e(r.style,"width",i(n.width,"100%")),t+=e(r.style,"height",i(n.height,this.height+"px")),t+=e(this.dom.axis.style,"left",i(n.left,"0px")),t+=e(this.dom.axis.style,"width",i(n.width,"100%")),t+="bottom"==s?e(this.dom.axis.style,"top",this.height+this.top+"px"):e(this.dom.axis.style,"top",this.top+"px"),this._updateConversion();var u=this,p=this.queue,f=this.itemsData,g=this.items,m={};for(var v in p)if(p.hasOwnProperty(v)){var _=p[v],w=g[v],b=_.action;switch(b){case"add":case"update":var S=f&&f.get(v,m);if(S){var E=S.type||S.start&&S.end&&"range"||n.type||"box",T=y.types[E];if(w&&(T&&w instanceof T?(w.data=S,t++):(t+=w.hide(),w=null)),!w){if(!T)throw new TypeError('Unknown item type "'+E+'"');w=new T(u,S,n,o),w.id=_.id,t++}w.repaint(),g[v]=w}delete p[v];break;case"remove":w&&(w.selected&&u._deselect(v),t+=w.hide()),delete g[v],delete p[v];break;default:console.log('Error: unknown action "'+b+'"')}}return z.forEach(this.items,function(e){e.visible?(t+=e.show(),e.reposition()):t+=e.hide()}),t>0},y.prototype.getForeground=function(){return this.dom.foreground +},y.prototype.getBackground=function(){return this.dom.background},y.prototype.getAxis=function(){return this.dom.axis},y.prototype.reflow=function(){var t=0,e=this.options,i=e.margin&&e.margin.axis||this.defaultOptions.margin.axis,n=e.margin&&e.margin.item||this.defaultOptions.margin.item,s=z.updateProperty,o=z.option.asNumber,r=z.option.asSize,a=this.frame;if(a){this._updateConversion(),z.forEach(this.items,function(e){t+=e.reflow()}),this.stack.update();var h,c=o(e.maxHeight),d=null!=r(e.height);if(d)h=a.offsetHeight;else{var l=this.stack.ordered;if(l.length){var u=l[0].top,p=l[0].top+l[0].height;z.forEach(l,function(t){u=Math.min(u,t.top),p=Math.max(p,t.top+t.height)}),h=p-u+i+n}else h=i+n}null!=c&&(h=Math.min(h,c)),t+=s(this,"height",h),t+=s(this,"top",a.offsetTop),t+=s(this,"left",a.offsetLeft),t+=s(this,"width",a.offsetWidth)}else t+=1;return t>0},y.prototype.hide=function(){var t=!1;return this.frame&&this.frame.parentNode&&(this.frame.parentNode.removeChild(this.frame),t=!0),this.dom.axis&&this.dom.axis.parentNode&&(this.dom.axis.parentNode.removeChild(this.dom.axis),t=!0),t},y.prototype.setItems=function(t){var e,i=this,n=this.itemsData;if(t){if(!(t instanceof o||t instanceof r))throw new TypeError("Data must be an instance of DataSet");this.itemsData=t}else this.itemsData=null;if(n&&(z.forEach(this.listeners,function(t,e){n.unsubscribe(e,t)}),e=n.getIds(),this._onRemove(e)),this.itemsData){var s=this.id;z.forEach(this.listeners,function(t,e){i.itemsData.subscribe(e,t,s)}),e=this.itemsData.getIds(),this._onAdd(e)}},y.prototype.getItems=function(){return this.itemsData},y.prototype._onUpdate=function(t){this._toQueue("update",t)},y.prototype._onAdd=function(t){this._toQueue("add",t)},y.prototype._onRemove=function(t){this._toQueue("remove",t)},y.prototype._toQueue=function(t,e){var i=this.queue;e.forEach(function(e){i[e]={id:e,action:t}}),this.controller&&this.requestRepaint()},y.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},y.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},y.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},_.prototype.select=function(){this.selected=!0,this.visible&&this.repaint()},_.prototype.unselect=function(){this.selected=!1,this.visible&&this.repaint()},_.prototype.show=function(){return!1},_.prototype.hide=function(){return!1},_.prototype.repaint=function(){return!1},_.prototype.reflow=function(){return!1},_.prototype.getWidth=function(){return this.width},w.prototype=new _(null,null),w.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");if(!e.box.parentNode){var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");i.appendChild(e.box),t=!0}if(!e.line.parentNode){var n=this.parent.getBackground();if(!n)throw new Error("Cannot repaint time axis: parent has no background container element");n.appendChild(e.line),t=!0}if(!e.dot.parentNode){var s=this.parent.getAxis();if(!n)throw new Error("Cannot repaint time axis: parent has no axis container element");s.appendChild(e.dot),t=!0}if(this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var o=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=o&&(this.className=o,e.box.className="item box"+o,e.line.className="item line"+o,e.dot.className="item dot"+o,t=!0)}return t},w.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},w.prototype.hide=function(){var t=!1,e=this.dom;return e&&(e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),e.line.parentNode&&e.line.parentNode.removeChild(e.line),e.dot.parentNode&&e.dot.parentNode.removeChild(e.dot)),t},w.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,c,d,l,u=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(d=this.data,l=this.parent&&this.parent.range,d&&l){var p=l.end-l.start;this.visible=d.start>l.start-p&&d.start0},w.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("DIV"),t.content=document.createElement("DIV"),t.content.className="content",t.box.appendChild(t.content),t.line=document.createElement("DIV"),t.line.className="line",t.dot=document.createElement("DIV"),t.dot.className="dot",t.box["timeline-item"]=this)},w.prototype.reposition=function(){var t=this.dom,e=this.props,i=this.options.orientation||this.defaultOptions.orientation;if(t){var n=t.box,s=t.line,o=t.dot;n.style.left=this.left+"px",n.style.top=this.top+"px",s.style.left=e.line.left+"px","top"==i?(s.style.top="0px",s.style.height=this.top+"px"):(s.style.top=this.top+this.height+"px",s.style.height=Math.max(this.parent.height-this.top-this.height+this.props.dot.height/2,0)+"px"),o.style.left=e.dot.left+"px",o.style.top=e.dot.top+"px"}},b.prototype=new _(null,null),b.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.point.parentNode||(i.appendChild(e.point),i.appendChild(e.point),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.point.className="item point"+n,t=!0)}return t},b.prototype.show=function(){return this.dom&&this.dom.point.parentNode?!1:this.repaint()},b.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.point.parentNode&&(e.point.parentNode.removeChild(e.point),t=!0),t},b.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,c,d=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(h=this.data,c=this.parent&&this.parent.range,h&&c){var l=c.end-c.start;this.visible=h.start>c.start-l&&h.start0},b.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.point=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.point.appendChild(t.content),t.dot=document.createElement("div"),t.dot.className="dot",t.point.appendChild(t.dot),t.point["timeline-item"]=this)},b.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.point.style.top=this.top+"px",t.point.style.left=this.left+"px",t.content.style.marginLeft=e.content.marginLeft+"px",t.dot.style.top=e.dot.top+"px")},S.prototype=new _(null,null),S.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.box.className="item range"+n,t=!0)}return t},S.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},S.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),t},S.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,c,d,l,u,p,f,g,m=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(void 0==this.data.end)throw new Error('Property "end" missing in item '+this.data.id);return h=this.data,c=this.parent&&this.parent.range,this.visible=h&&c?h.startc.start:!1,this.visible&&(t=this.dom,t?(e=this.props,i=this.options,o=this.parent,r=o.toScreen(this.data.start),a=o.toScreen(this.data.end),d=z.updateProperty,l=t.box,u=o.width,f=i.orientation||this.defaultOptions.orientation,n=i.margin&&i.margin.axis||this.defaultOptions.margin.axis,s=i.padding||this.defaultOptions.padding,m+=d(e.content,"width",t.content.offsetWidth),m+=d(this,"height",l.offsetHeight),-u>r&&(r=-u),a>2*u&&(a=2*u),p=0>r?Math.min(-r,a-r-e.content.width-2*s):0,m+=d(e.content,"left",p),"top"==f?(g=n,m+=d(this,"top",g)):(g=o.height-this.height-n,m+=d(this,"top",g)),m+=d(this,"left",r),m+=d(this,"width",Math.max(a-r,1))):m+=1),m>0},S.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content),t.box["timeline-item"]=this)},S.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.box.style.top=this.top+"px",t.box.style.left=this.left+"px",t.box.style.width=this.width+"px",t.content.style.left=e.content.left+"px")},E.prototype=new S(null,null),E.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=this.data.className?" "+this.data.className:"";this.className!=n&&(this.className=n,e.box.className="item rangeoverflow"+n,t=!0)}return t},E.prototype.getWidth=function(){return void 0!==this.props.content&&this.width0},x.prototype=new p,x.prototype.setOptions=u.prototype.setOptions,x.prototype.setRange=function(){},x.prototype.setItems=function(t){this.itemsData=t;for(var e in this.groups)if(this.groups.hasOwnProperty(e)){var i=this.groups[e];i.setItems(t)}},x.prototype.getItems=function(){return this.itemsData},x.prototype.setRange=function(t){this.range=t},x.prototype.setGroups=function(t){var e,i=this;if(this.groupsData&&(z.forEach(this.listeners,function(t,e){i.groupsData.unsubscribe(e,t)}),e=this.groupsData.getIds(),this._onRemove(e)),t?t instanceof o?this.groupsData=t:(this.groupsData=new o({convert:{start:"Date",end:"Date"}}),this.groupsData.add(t)):this.groupsData=null,this.groupsData){var n=this.id;z.forEach(this.listeners,function(t,e){i.groupsData.subscribe(e,t,n)}),e=this.groupsData.getIds(),this._onAdd(e)}},x.prototype.getGroups=function(){return this.groupsData},x.prototype.setSelection=function(t){var e=[],i=this.groups;for(var n in i)if(i.hasOwnProperty(n)){var s=i[n];s.setSelection(t)}return e},x.prototype.getSelection=function(){var t=[],e=this.groups;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];t=t.concat(n.getSelection())}return t},x.prototype.repaint=function(){var t,e,i,n,s=0,o=z.updateProperty,r=z.option.asSize,a=z.option.asElement,h=this.options,c=this.dom.frame,d=this.dom.labels,l=this.dom.labelSet;if(!this.parent)throw new Error("Cannot repaint groupset: no parent attached");var u=this.parent.getContainer();if(!u)throw new Error("Cannot repaint groupset: parent has no container element");if(!c){c=document.createElement("div"),c.className="groupset",this.dom.frame=c;var p=h.className;p&&z.addClassName(c,z.option.asString(p)),s+=1}c.parentNode||(u.appendChild(c),s+=1);var f=a(h.labelContainer);if(!f)throw new Error('Cannot repaint groupset: option "labelContainer" not defined');d||(d=document.createElement("div"),d.className="labels",this.dom.labels=d),l||(l=document.createElement("div"),l.className="label-set",d.appendChild(l),this.dom.labelSet=l),d.parentNode&&d.parentNode==f||(d.parentNode&&d.parentNode.removeChild(d.parentNode),f.appendChild(d)),s+=o(c.style,"height",r(h.height,this.height+"px")),s+=o(c.style,"top",r(h.top,"0px")),s+=o(c.style,"left",r(h.left,"0px")),s+=o(c.style,"width",r(h.width,"100%")),s+=o(l.style,"top",r(h.top,"0px")),s+=o(l.style,"height",r(h.height,this.height+"px"));var g=this,m=this.queue,v=this.groups,y=this.groupsData,_=Object.keys(m);if(_.length){_.forEach(function(t){var e=m[t],i=v[t];switch(e){case"add":case"update":if(!i){var n=Object.create(g.options);z.extend(n,{height:null,maxHeight:null}),i=new T(g,t,n),i.setItems(g.itemsData),v[t]=i,g.controller.add(i)}i.data=y.get(t),delete m[t];break;case"remove":i&&(i.setItems(),delete v[t],g.controller.remove(i)),delete m[t];break;default:console.log('Error: unknown action "'+e+'"')}});var w=this.groupsData.getIds({order:this.options.groupOrder});for(t=0;t0},x.prototype._createLabel=function(t){var e=this.groups[t],i=document.createElement("div");i.className="label";var n=document.createElement("div");n.className="inner",i.appendChild(n);var s=e.data&&e.data.content;s instanceof Element?n.appendChild(s):void 0!=s&&(n.innerHTML=s);var o=e.data&&e.data.className;return o&&z.addClassName(i,o),e.label=i,i},x.prototype.getContainer=function(){return this.dom.frame},x.prototype.getLabelsWidth=function(){return this.props.labels.width},x.prototype.reflow=function(){var t,e,i=0,n=this.options,s=z.updateProperty,o=z.option.asNumber,r=z.option.asSize,a=this.dom.frame;if(a){var h,c=o(n.maxHeight),d=null!=r(n.height);if(d)h=a.offsetHeight;else{h=0;for(t in this.groups)this.groups.hasOwnProperty(t)&&(e=this.groups[t],h+=e.height)}null!=c&&(h=Math.min(h,c)),i+=s(this,"height",h),i+=s(this,"top",a.offsetTop),i+=s(this,"left",a.offsetLeft),i+=s(this,"width",a.offsetWidth)}var l=0;for(t in this.groups)if(this.groups.hasOwnProperty(t)){e=this.groups[t];var u=e.props&&e.props.label&&e.props.label.width||0;l=Math.max(l,u)}return i+=s(this.props.labels,"width",l),i>0},x.prototype.hide=function(){return this.dom.frame&&this.dom.frame.parentNode?(this.dom.frame.parentNode.removeChild(this.dom.frame),!0):!1},x.prototype.show=function(){return this.dom.frame&&this.dom.frame.parentNode?!1:this.repaint()},x.prototype._onUpdate=function(t){this._toQueue(t,"update")},x.prototype._onAdd=function(t){this._toQueue(t,"add")},x.prototype._onRemove=function(t){this._toQueue(t,"remove")},x.prototype._toQueue=function(t,e){var i=this.queue;t.forEach(function(t){i[t]=e}),this.controller&&this.requestRepaint()},C.prototype.setOptions=function(t){z.extend(this.options,t),this.range.setRange(t.start,t.end),this.controller.reflow(),this.controller.repaint()},C.prototype.setCustomTime=function(t){this.customtime._setCustomTime(t)},C.prototype.getCustomTime=function(){return new Date(this.customtime.customTime.valueOf())},C.prototype.setItems=function(t){var e,i=null==this.itemsData;if(t?t instanceof o&&(e=t):e=null,t instanceof o||(e=new o({convert:{start:"Date",end:"Date"}}),e.add(t)),this.itemsData=e,this.content.setItems(e),i&&(void 0==this.options.start||void 0==this.options.end)){var n=this.getItemRange(),s=n.min,r=n.max;if(null!=s&&null!=r){var a=r.valueOf()-s.valueOf();0>=a&&(a=864e5),s=new Date(s.valueOf()-.05*a),r=new Date(r.valueOf()+.05*a)}void 0!=this.options.start&&(s=z.convert(this.options.start,"Date")),void 0!=this.options.end&&(r=z.convert(this.options.end,"Date")),(null!=s||null!=r)&&this.range.setRange(s,r)}},C.prototype.setGroups=function(t){var e=this;this.groupsData=t;var i=this.groupsData?x:y;if(!(this.content instanceof i)){this.content&&(this.content.hide(),this.content.setItems&&this.content.setItems(),this.content.setGroups&&this.content.setGroups(),this.controller.remove(this.content));var n=Object.create(this.options);z.extend(n,{top:function(){return"top"==e.options.orientation?e.timeaxis.height:e.itemPanel.height-e.timeaxis.height-e.content.height},left:null,width:"100%",height:function(){return e.options.height?e.itemPanel.height-e.timeaxis.height:null},maxHeight:function(){if(e.options.maxHeight){if(!z.isNumber(e.options.maxHeight))throw new TypeError("Number expected for property maxHeight");return e.options.maxHeight-e.timeaxis.height}return null},labelContainer:function(){return e.labelPanel.getContainer()}}),this.content=new i(this.itemPanel,[this.timeaxis],n),this.content.setRange&&this.content.setRange(this.range),this.content.setItems&&this.content.setItems(this.itemsData),this.content.setGroups&&this.content.setGroups(this.groupsData),this.controller.add(this.content)}},C.prototype.getItemRange=function(){var t=this.itemsData,e=null,i=null;if(t){var n=t.min("start");e=n?n.start.valueOf():null;var s=t.max("start");s&&(i=s.start.valueOf());var o=t.max("end");o&&(i=null==i?o.end.valueOf():Math.max(i,o.end.valueOf()))}return{min:null!=e?new Date(e):null,max:null!=i?new Date(i):null}},C.prototype.setSelection=function(t){this.content&&this.content.setSelection(t)},C.prototype.getSelection=function(){return this.content?this.content.getSelection():[]},C.prototype.on=function(t,e){var i=["rangechange","rangechanged","select"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());F.addListener(this,t,e)},C.prototype.off=function(t,e){F.removeListener(this,t,e)},C.prototype._trigger=function(t,e){F.trigger(this,t,e||{})},C.prototype._onSelectItem=function(t){var e=this._itemFromTarget(t),i=e?[e.id]:[];this.setSelection(i),this._trigger("select",{items:this.getSelection()}),t.stopPropagation()},C.prototype._onMultiSelectItem=function(t){var e,i=this._itemFromTarget(t);if(i){e=this.getSelection();var n=e.indexOf(i.id);-1==n?e.push(i.id):e.splice(n,1),this.setSelection(e),this._trigger("select",{items:this.getSelection()}),t.stopPropagation()}},C.prototype._itemFromTarget=function(t){for(var e=t.target;e;){if(e.hasOwnProperty("timeline-item"))return e["timeline-item"];e=e.parentNode}return null},function(t){function e(t){return C=t,u()}function i(){M=0,D=C.charAt(0)}function n(){M++,D=C.charAt(M)}function s(){return C.charAt(M+1)}function o(t){return N.test(t)}function r(t,e){if(t||(t={}),e)for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function a(t,e,i){for(var n=e.split("."),s=t;n.length;){var o=n.shift();n.length?(s[o]||(s[o]={}),s=s[o]):s[o]=i}}function h(t,e){for(var i,n,s=null,o=[t],a=t;a.parent;)o.push(a.parent),a=a.parent;if(a.nodes)for(i=0,n=a.nodes.length;n>i;i++)if(e.id===a.nodes[i].id){s=a.nodes[i];break}for(s||(s={id:e.id},t.node&&(s.attr=r(s.attr,t.node))),i=o.length-1;i>=0;i--){var h=o[i];h.nodes||(h.nodes=[]),-1==h.nodes.indexOf(s)&&h.nodes.push(s)}e.attr&&(s.attr=r(s.attr,e.attr))}function c(t,e){if(t.edges||(t.edges=[]),t.edges.push(e),t.edge){var i=r({},t.edge);e.attr=r(i,e.attr)}}function d(t,e,i,n,s){var o={from:e,to:i,type:n};return t.edge&&(o.attr=r({},t.edge)),o.attr=r(o.attr||{},s),o}function l(){for(I=T.NULL,O="";" "==D||" "==D||"\n"==D||"\r"==D;)n();do{var t=!1;if("#"==D){for(var e=M-1;" "==C.charAt(e)||" "==C.charAt(e);)e--;if("\n"==C.charAt(e)||""==C.charAt(e)){for(;""!=D&&"\n"!=D;)n();t=!0}}if("/"==D&&"/"==s()){for(;""!=D&&"\n"!=D;)n();t=!0}if("/"==D&&"*"==s()){for(;""!=D;){if("*"==D&&"/"==s()){n(),n();break}n()}t=!0}for(;" "==D||" "==D||"\n"==D||"\r"==D;)n()}while(t);if(""==D)return void(I=T.DELIMITER);var i=D+s();if(x[i])return I=T.DELIMITER,O=i,n(),void n();if(x[D])return I=T.DELIMITER,O=D,void n();if(o(D)||"-"==D){for(O+=D,n();o(D);)O+=D,n();return"false"==O?O=!1:"true"==O?O=!0:isNaN(Number(O))||(O=Number(O)),void(I=T.IDENTIFIER)}if('"'==D){for(n();""!=D&&('"'!=D||'"'==D&&'"'==s());)O+=D,'"'==D&&n(),n();if('"'!=D)throw w('End of string " expected');return n(),void(I=T.IDENTIFIER)}for(I=T.UNKNOWN;""!=D;)O+=D,n();throw new SyntaxError('Syntax error in part "'+b(O,30)+'"')}function u(){var t={};if(i(),l(),"strict"==O&&(t.strict=!0,l()),("graph"==O||"digraph"==O)&&(t.type=O,l()),I==T.IDENTIFIER&&(t.id=O,l()),"{"!=O)throw w("Angle bracket { expected");if(l(),p(t),"}"!=O)throw w("Angle bracket } expected");if(l(),""!==O)throw w("End of file expected");return l(),delete t.node,delete t.edge,delete t.graph,t}function p(t){for(;""!==O&&"}"!=O;)f(t),";"==O&&l()}function f(t){var e=g(t);if(e)return void y(t,e);var i=m(t);if(!i){if(I!=T.IDENTIFIER)throw w("Identifier expected");var n=O;if(l(),"="==O){if(l(),I!=T.IDENTIFIER)throw w("Identifier expected");t[n]=O,l()}else v(t,n)}}function g(t){var e=null;if("subgraph"==O&&(e={},e.type="subgraph",l(),I==T.IDENTIFIER&&(e.id=O,l())),"{"==O){if(l(),e||(e={}),e.parent=t,e.node=t.node,e.edge=t.edge,e.graph=t.graph,p(e),"}"!=O)throw w("Angle bracket } expected");l(),delete e.node,delete e.edge,delete e.graph,delete e.parent,t.subgraphs||(t.subgraphs=[]),t.subgraphs.push(e)}return e}function m(t){return"node"==O?(l(),t.node=_(),"node"):"edge"==O?(l(),t.edge=_(),"edge"):"graph"==O?(l(),t.graph=_(),"graph"):null}function v(t,e){var i={id:e},n=_();n&&(i.attr=n),h(t,i),y(t,e)}function y(t,e){for(;"->"==O||"--"==O;){var i,n=O;l();var s=g(t);if(s)i=s;else{if(I!=T.IDENTIFIER)throw w("Identifier or subgraph expected");i=O,h(t,{id:i}),l()}var o=_(),r=d(t,e,i,n,o);c(t,r),e=i}}function _(){for(var t=null;"["==O;){for(l(),t={};""!==O&&"]"!=O;){if(I!=T.IDENTIFIER)throw w("Attribute name expected");var e=O;if(l(),"="!=O)throw w("Equal sign = expected");if(l(),I!=T.IDENTIFIER)throw w("Attribute value expected");var i=O;a(t,e,i),l(),","==O&&l()}if("]"!=O)throw w("Bracket ] expected");l()}return t}function w(t){return new SyntaxError(t+', got "'+b(O,30)+'" (char '+M+")")}function b(t,e){return t.length<=e?t:t.substr(0,27)+"..."}function S(t,e,i){t instanceof Array?t.forEach(function(t){e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}):e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}function E(t){function i(t){var e={from:t.from,to:t.to};return r(e,t.attr),e.style="->"==t.type?"arrow":"line",e}var n=e(t),s={nodes:[],edges:[],options:{}};return n.nodes&&n.nodes.forEach(function(t){var e={id:t.id,label:String(t.label||t.id)};r(e,t.attr),e.image&&(e.shape="image"),s.nodes.push(e)}),n.edges&&n.edges.forEach(function(t){var e,n;e=t.from instanceof Object?t.from.nodes:{id:t.from},n=t.to instanceof Object?t.to.nodes:{id:t.to},t.from instanceof Object&&t.from.edges&&t.from.edges.forEach(function(t){var e=i(t);s.edges.push(e)}),S(e,n,function(e,n){var o=d(s,e.id,n.id,t.type,t.attr),r=i(o);s.edges.push(r)}),t.to instanceof Object&&t.to.edges&&t.to.edges.forEach(function(t){var e=i(t);s.edges.push(e)})}),n.attr&&(s.options=n.attr),s}var T={NULL:0,DELIMITER:1,IDENTIFIER:2,UNKNOWN:3},x={"{":!0,"}":!0,"[":!0,"]":!0,";":!0,"=":!0,",":!0,"->":!0,"--":!0},C="",M=0,D="",O="",I=T.NULL,N=/[a-zA-Z_0-9.:#]/;t.parseDOT=e,t.DOTToGraph=E}("undefined"!=typeof z?z:n),"undefined"!=typeof CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.circle=function(t,e,i){this.beginPath(),this.arc(t,e,i,0,2*Math.PI,!1)},CanvasRenderingContext2D.prototype.square=function(t,e,i){this.beginPath(),this.rect(t-i,e-i,2*i,2*i)},CanvasRenderingContext2D.prototype.triangle=function(t,e,i){this.beginPath();var n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e-(r-o)),this.lineTo(t+s,e+o),this.lineTo(t-s,e+o),this.lineTo(t,e-(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.triangleDown=function(t,e,i){this.beginPath();var n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e+(r-o)),this.lineTo(t+s,e-o),this.lineTo(t-s,e-o),this.lineTo(t,e+(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.star=function(t,e,i){this.beginPath();for(var n=0;10>n;n++){var s=n%2===0?1.3*i:.5*i;this.lineTo(t+s*Math.sin(2*n*Math.PI/10),e-s*Math.cos(2*n*Math.PI/10))}this.closePath()},CanvasRenderingContext2D.prototype.roundRect=function(t,e,i,n,s){var o=Math.PI/180;0>i-2*s&&(s=i/2),0>n-2*s&&(s=n/2),this.beginPath(),this.moveTo(t+s,e),this.lineTo(t+i-s,e),this.arc(t+i-s,e+s,s,270*o,360*o,!1),this.lineTo(t+i,e+n-s),this.arc(t+i-s,e+n-s,s,0,90*o,!1),this.lineTo(t+s,e+n),this.arc(t+s,e+n-s,s,90*o,180*o,!1),this.lineTo(t,e+s),this.arc(t+s,e+s,s,180*o,270*o,!1)},CanvasRenderingContext2D.prototype.ellipse=function(t,e,i,n){var s=.5522848,o=i/2*s,r=n/2*s,a=t+i,h=e+n,c=t+i/2,d=e+n/2;this.beginPath(),this.moveTo(t,d),this.bezierCurveTo(t,d-r,c-o,e,c,e),this.bezierCurveTo(c+o,e,a,d-r,a,d),this.bezierCurveTo(a,d+r,c+o,h,c,h),this.bezierCurveTo(c-o,h,t,d+r,t,d)},CanvasRenderingContext2D.prototype.database=function(t,e,i,n){var s=1/3,o=i,r=n*s,a=.5522848,h=o/2*a,c=r/2*a,d=t+o,l=e+r,u=t+o/2,p=e+r/2,f=e+(n-r/2),g=e+n;this.beginPath(),this.moveTo(d,p),this.bezierCurveTo(d,p+c,u+h,l,u,l),this.bezierCurveTo(u-h,l,t,p+c,t,p),this.bezierCurveTo(t,p-c,u-h,e,u,e),this.bezierCurveTo(u+h,e,d,p-c,d,p),this.lineTo(d,f),this.bezierCurveTo(d,f+c,u+h,g,u,g),this.bezierCurveTo(u-h,g,t,f+c,t,f),this.lineTo(t,p)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,n){var s=t-n*Math.cos(i),o=e-n*Math.sin(i),r=t-.9*n*Math.cos(i),a=e-.9*n*Math.sin(i),h=s+n/3*Math.cos(i+.5*Math.PI),c=o+n/3*Math.sin(i+.5*Math.PI),d=s+n/3*Math.cos(i-.5*Math.PI),l=o+n/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,c),this.lineTo(r,a),this.lineTo(d,l),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,n,s){s||(s=[10,5]),0==u&&(u=.001);var o=s.length;this.moveTo(t,e);for(var r=i-t,a=n-e,h=a/r,c=Math.sqrt(r*r+a*a),d=0,l=!0;c>=.1;){var u=s[d++%o];u>c&&(u=c);var p=Math.sqrt(u*u/(1+h*h));0>r&&(p=-p),t+=p,e+=h*p,this[l?"lineTo":"moveTo"](t,e),c-=u,l=!l}}),M.prototype.resetCluster=function(){this.formationScale=void 0,this.clusterSize=1,this.containedNodes={},this.containedEdges={},this.clusterSessions=[]},M.prototype.attachEdge=function(t){-1==this.edges.indexOf(t)&&this.edges.push(t),-1==this.dynamicEdges.indexOf(t)&&this.dynamicEdges.push(t),this.dynamicEdgesLength=this.dynamicEdges.length,this._updateMass()},M.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&(this.edges.splice(e,1),this.dynamicEdges.splice(e,1)),this.dynamicEdgesLength=this.dynamicEdges.length,this._updateMass()},M.prototype._updateMass=function(){this.mass=1+.6*this.edges.length},M.prototype.setProperties=function(t,e){if(t){if(this.originalLabel=void 0,void 0!==t.id&&(this.id=t.id),void 0!==t.label&&(this.label=t.label,this.originalLabel=t.label),void 0!==t.title&&(this.title=t.title),void 0!==t.group&&(this.group=t.group),void 0!==t.x&&(this.x=t.x),void 0!==t.y&&(this.y=t.y),void 0!==t.value&&(this.value=t.value),void 0!==t.horizontalAlignLeft&&(this.horizontalAlignLeft=t.horizontalAlignLeft),void 0!==t.verticalAlignTop&&(this.verticalAlignTop=t.verticalAlignTop),void 0!==t.triggerFunction&&(this.triggerFunction=t.triggerFunction),void 0===this.id)throw"Node must have an id";if(this.group){var i=this.grouplist.get(this.group);for(var n in i)i.hasOwnProperty(n)&&(this[n]=i[n])}if(void 0!==t.shape&&(this.shape=t.shape),void 0!==t.image&&(this.image=t.image),void 0!==t.radius&&(this.radius=t.radius),void 0!==t.color&&(this.color=M.parseColor(t.color)),void 0!==t.fontColor&&(this.fontColor=t.fontColor),void 0!==t.fontSize&&(this.fontSize=t.fontSize),void 0!==t.fontFace&&(this.fontFace=t.fontFace),void 0!==this.image){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.image)}switch(this.xFixed=this.xFixed||void 0!==t.x&&t.fixed,this.yFixed=this.yFixed||void 0!==t.y&&t.fixed,this.radiusFixed=this.radiusFixed||void 0!==t.radius,"image"==this.shape&&(this.radiusMin=e.nodes.widthMin,this.radiusMax=e.nodes.widthMax),this.shape){case"database":this.draw=this._drawDatabase,this.resize=this._resizeDatabase;break;case"box":this.draw=this._drawBox,this.resize=this._resizeBox;break;case"circle":this.draw=this._drawCircle,this.resize=this._resizeCircle;break;case"ellipse":this.draw=this._drawEllipse,this.resize=this._resizeEllipse;break;case"image":this.draw=this._drawImage,this.resize=this._resizeImage;break;case"text":this.draw=this._drawText,this.resize=this._resizeText;break;case"dot":this.draw=this._drawDot,this.resize=this._resizeShape;break;case"square":this.draw=this._drawSquare,this.resize=this._resizeShape;break;case"triangle":this.draw=this._drawTriangle,this.resize=this._resizeShape;break;case"triangleDown":this.draw=this._drawTriangleDown,this.resize=this._resizeShape; +break;case"star":this.draw=this._drawStar,this.resize=this._resizeShape;break;default:this.draw=this._drawEllipse,this.resize=this._resizeEllipse}this._reset()}},M.parseColor=function(t){var e;return z.isString(t)?e={border:t,background:t,highlight:{border:t,background:t}}:(e={},e.background=t.background||"white",e.border=t.border||e.background,z.isString(t.highlight)?e.highlight={border:t.highlight,background:t.highlight}:(e.highlight={},e.highlight.background=t.highlight&&t.highlight.background||e.background,e.highlight.border=t.highlight&&t.highlight.border||e.border)),e},M.prototype.select=function(){this.selected=!0,this._reset()},M.prototype.unselect=function(){this.selected=!1,this._reset()},M.prototype.clearSizeCache=function(){this._reset()},M.prototype._reset=function(){this.width=void 0,this.height=void 0},M.prototype.getTitle=function(){return this.title},M.prototype.distanceToBorder=function(t,e){var i=1;switch(this.width||this.resize(t),this.shape){case"circle":case"dot":return this.radius+i;case"ellipse":var n=this.width/2,s=this.height/2,o=Math.sin(e)*n,r=Math.cos(e)*s;return n*s/Math.sqrt(o*o+r*r);case"box":case"image":case"text":default:return this.width?Math.min(Math.abs(this.width/2/Math.cos(e)),Math.abs(this.height/2/Math.sin(e)))+i:0}},M.prototype._setForce=function(t,e){this.fx=t,this.fy=e},M.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},M.prototype.discreteStep=function(t){if(!this.xFixed){var e=-this.damping*this.vx,i=(this.fx+e)/this.mass;this.vx+=i*t,this.x+=this.vx*t}if(!this.yFixed){var n=-this.damping*this.vy,s=(this.fy+n)/this.mass;this.vy+=s*t,this.y+=this.vy*t}},M.prototype.isFixed=function(){return this.xFixed&&this.yFixed},M.prototype.isMoving=function(t){return Math.abs(this.vx)>t||Math.abs(this.vy)>t?!0:(this.vx=0,this.vy=0,!1)},M.prototype.isSelected=function(){return this.selected},M.prototype.getValue=function(){return this.value},M.prototype.getDistance=function(t,e){var i=this.x-t,n=this.y-e;return Math.sqrt(i*i+n*n)},M.prototype.setValueRange=function(t,e){if(!this.radiusFixed&&void 0!==this.value)if(e==t)this.radius=(this.radiusMin+this.radiusMax)/2;else{var i=(this.radiusMax-this.radiusMin)/(e-t);this.radius=(this.value-t)*i+this.radiusMin}this.baseRadiusValue=this.radius},M.prototype.draw=function(){throw"Draw method not initialized for node"},M.prototype.resize=function(){throw"Resize method not initialized for node"},M.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},M.prototype._resizeImage=function(){if(!this.width||!this.height){var t,e;if(this.value){this.radius=this.baseRadiusValue;var i=this.imageObj.height/this.imageObj.width;void 0!==i?(t=this.radius||this.imageObj.width,e=this.radius*i||this.imageObj.height):(t=0,e=0)}else t=this.imageObj.width,e=this.imageObj.height;this.width=t,this.height=e,this.width>0&&this.height>0&&(this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor)}},M.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e;if(0!=this.imageObj.width){if(this.clusterSize>1){var i=this.clusterSize>1?10:0;i*=this.graphScaleInv,i=Math.min(.2*this.width,i),t.globalAlpha=.5,t.drawImage(this.imageObj,this.left-i,this.top-i,this.width+2*i,this.height+2*i)}t.globalAlpha=1,t.drawImage(this.imageObj,this.left,this.top,this.width,this.height),e=this.y+this.height/2}else e=this.y;this._label(t,this.label,this.x,e,void 0,"top")},M.prototype._resizeBox=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=.5*(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=.5*(this.clusterSize-1)*this.clusterSizeHeightFactor}},M.prototype._drawBox=function(t){this._resizeBox(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.roundRect(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth,this.radius),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.roundRect(this.left,this.top,this.width,this.height,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeDatabase=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=i.width+2*e;this.width=n,this.height=n,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawDatabase=function(t){this._resizeDatabase(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.database(this.x-this.width/2-2*t.lineWidth,this.y-.5*this.height-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.database(this.x-this.width/2,this.y-.5*this.height,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=Math.max(i.width,i.height)+2*e;this.radius=n/2,this.width=n,this.height=n,this.radius+=.5*(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawCircle=function(t){this._resizeCircle(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.circle(this.x,this.y,this.radius+2*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.circle(this.x,this.y,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeEllipse=function(t){if(!this.width){var e=this.getTextSize(t);this.width=1.5*e.width,this.height=2*e.height,this.width1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.ellipse(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.ellipse(this.left,this.top,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._drawDot=function(t){this._drawShape(t,"circle")},M.prototype._drawTriangle=function(t){this._drawShape(t,"triangle")},M.prototype._drawTriangleDown=function(t){this._drawShape(t,"triangleDown")},M.prototype._drawSquare=function(t){this._drawShape(t,"square")},M.prototype._drawStar=function(t){this._drawShape(t,"star")},M.prototype._resizeShape=function(){if(!this.width){this.radius=this.baseRadiusValue;var t=2*this.radius;this.width=t,this.height=t,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=.5*(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawShape=function(t,e){this._resizeShape(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var i=2.5,n=2,s=2;switch(e){case"dot":s=2;break;case"square":s=2;break;case"triangle":s=3;break;case"triangleDown":s=3;break;case"star":s=4}t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?n:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t[e](this.x,this.y,this.radius+s*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?n:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t[e](this.x,this.y,this.radius),t.fill(),t.stroke(),this.label&&this._label(t,this.label,this.x,this.y+this.height/2,void 0,"top")},M.prototype._resizeText=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawText=function(t){this._resizeText(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,this._label(t,this.label,this.x,this.y)},M.prototype._label=function(t,e,i,n,s,o){if(e){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle=this.fontColor||"black",t.textAlign=s||"center",t.textBaseline=o||"middle";for(var r=e.split("\n"),a=r.length,h=this.fontSize+4,c=n+(1-a)/2*h,d=0;a>d;d++)t.fillText(r[d],i,c),c+=h}},M.prototype.getTextSize=function(t){if(void 0!==this.label){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace;for(var e=this.label.split("\n"),i=(this.fontSize+4)*e.length,n=0,s=0,o=e.length;o>s;s++)n=Math.max(n,t.measureText(e[s]).width);return{width:n,height:i}}return{width:0,height:0}},M.prototype.inArea=function(){return void 0!==this.width?this.x+this.width*this.graphScaleInv>=this.canvasTopLeft.x&&this.x-this.width*this.graphScaleInv=this.canvasTopLeft.y&&this.y-this.height*this.graphScaleInv=this.canvasTopLeft.x&&this.x=this.canvasTopLeft.y&&this.yh},D.prototype._drawLine=function(t){t.strokeStyle=this.color,t.lineWidth=this._getLineWidth();var e;if(this.from!=this.to)this._line(t),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y));else{var i,n,s=this.length/4,o=this.from;o.width||o.resize(t),o.width>o.height?(i=o.x+o.width/2,n=o.y-s):(i=o.x+s,n=o.y-o.height/2),this._circle(t,i,n,s),e=this._pointOnCircle(i,n,s,.5),this._label(t,this.label,e.x,e.y)}},D.prototype._getLineWidth=function(){return 1==this.selected?Math.min(2*this.width,this.widthMax)*this.graphScaleInv:this.width*this.graphScaleInv},D.prototype._line=function(t){t.beginPath(),t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y),t.stroke()},D.prototype._circle=function(t,e,i,n){t.beginPath(),t.arc(e,i,n,0,2*Math.PI,!1),t.stroke()},D.prototype._label=function(t,e,i,n){if(e){t.font=(this.from.selected||this.to.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle="white";var s=t.measureText(e).width,o=this.fontSize,r=i-s/2,a=n-o/2;t.fillRect(r,a,s,o),t.fillStyle=this.fontColor||"black",t.textAlign="left",t.textBaseline="top",t.fillText(e,r,a)}},D.prototype._drawDashLine=function(t){if(t.strokeStyle=this.color,t.lineWidth=this._getLineWidth(),t.beginPath(),t.lineCap="round",void 0!==this.dash.altLength?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]):void 0!==this.dash.length&&void 0!==this.dash.gap?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap]):(t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y)),t.stroke(),this.label){var e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}},D.prototype._pointOnLine=function(t){return{x:(1-t)*this.from.x+t*this.to.x,y:(1-t)*this.from.y+t*this.to.y}},D.prototype._pointOnCircle=function(t,e,i,n){var s=2*(n-3/8)*Math.PI;return{x:t+i*Math.cos(s),y:e-i*Math.sin(s)}},D.prototype._drawArrowCenter=function(t){var e;if(t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth(),this.from!=this.to){this._line(t);var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),n=10+5*this.width;e=this._pointOnLine(.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y))}else{var s,o,r=this.length/4,a=this.from;a.width||a.resize(t),a.width>a.height?(s=a.x+a.width/2,o=a.y-r):(s=a.x+r,o=a.y-a.height/2),this._circle(t,s,o,r);var i=.2*Math.PI,n=10+5*this.width;e=this._pointOnCircle(s,o,r,.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(s,o,r,.5),this._label(t,this.label,e.x,e.y))}},D.prototype._drawArrow=function(t){t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth();var e,i;if(this.from!=this.to){e=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x);var n=this.to.x-this.from.x,s=this.to.y-this.from.y,o=Math.sqrt(n*n+s*s),r=this.from.distanceToBorder(t,e+Math.PI),a=(o-r)/o,h=a*this.from.x+(1-a)*this.to.x,c=a*this.from.y+(1-a)*this.to.y,d=this.to.distanceToBorder(t,e),l=(o-d)/o,u=(1-l)*this.from.x+l*this.to.x,p=(1-l)*this.from.y+l*this.to.y;if(t.beginPath(),t.moveTo(h,c),t.lineTo(u,p),t.stroke(),i=10+5*this.width,t.arrow(u,p,e,i),t.fill(),t.stroke(),this.label){var f=this._pointOnLine(.5);this._label(t,this.label,f.x,f.y)}}else{var g,m,v,y=this.from,_=this.length/4;y.width||y.resize(t),y.width>y.height?(g=y.x+y.width/2,m=y.y-_,v={x:g,y:y.y,angle:.9*Math.PI}):(g=y.x+_,m=y.y-y.height/2,v={x:y.x,y:m,angle:.6*Math.PI}),t.beginPath(),t.arc(g,m,_,0,2*Math.PI,!1),t.stroke(),i=10+5*this.width,t.arrow(v.x,v.y,v.angle,i),t.fill(),t.stroke(),this.label&&(f=this._pointOnCircle(g,m,_,.5),this._label(t,this.label,f.x,f.y))}},D._dist=function(t,e,i,n,s,o){var r=i-t,a=n-e,h=r*r+a*a,c=((s-t)*r+(o-e)*a)/h;c>1?c=1:0>c&&(c=0);var d=t+c*r,l=e+c*a,u=d-s,p=l-o;return Math.sqrt(u*u+p*p)},D.prototype.setScale=function(t){this.graphScaleInv=1/t},D.prototype.select=function(){this.selected=!0},D.prototype.unselect=function(){this.selected=!1},O.prototype.setPosition=function(t,e){this.x=parseInt(t),this.y=parseInt(e)},O.prototype.setText=function(t){this.frame.innerHTML=t},O.prototype.show=function(t){if(void 0===t&&(t=!0),t){var e=this.frame.clientHeight,i=this.frame.clientWidth,n=this.frame.parentNode.clientHeight,s=this.frame.parentNode.clientWidth,o=this.y-e;o+e+this.padding>n&&(o=n-e-this.padding),os&&(r=s-i-this.padding),rAdd Node
    Edit Selected
    Connect Node
    Delete selected";var t=document.getElementById("manipulate-addNode");t.onclick=this._createAddToolbar.bind(this);var e=document.getElementById("manipulate-editNode");e.onclick=this._createEditToolbar.bind(this);var i=document.getElementById("manipulate-connectNode");i.onclick=this._createConnectToolbar.bind(this);var n=document.getElementById("manipulate-delete");n.onclick=this._deleteSelected.bind(this)},_createAddToolbar:function(){this._clearManipulatorBar(),this.off("select",this.boundFunction),this.manipulationDiv.innerHTML="Back
    Click in an empty space to place a new node";var t=document.getElementById("manipulate-back");t.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._addNode.bind(this),this.on("select",this.boundFunction)},_createEditToolbar:function(){this.selectForEdit=!1,this._clearManipulatorBar(),this.off("select",this.boundFunction);var t="";if(this._selectionIsEmpty()?t="Select a node or edge to edit.":this._getSelectedObjectCount()>1?(t="Select a single node or edge to edit.",this._unselectAll()):this._getSelectedNodeCount()>0?this._createEditNodeToolbar():this._createEditEdgeToolbar(),""!=t){this.selectForEdit=!0,this.manipulationDiv.innerHTML="Back
    "+t+"";var e=document.getElementById("manipulate-back");e.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._createEditToolbar.bind(this),this.on("select",this.boundFunction)}},_createEditNodeToolbar:function(){console.log("here)"),this.selectForEdit=!1,this._clearManipulatorBar(),this.off("select",this.boundFunction);var t=this._getEditObject();this.manipulationDiv.innerHTML="Back
    label:
    color:
    ";var e=document.getElementById("manipulate-back");e.onclick=this._createManipulatorBar.bind(this);var i=document.getElementById("manipulator-obj-save");i.onclick=this._saveNodeData.bind(this),this.boundFunction=this._createManipulatorBar.bind(this),this.on("select",this.boundFunction)},_saveNodeData:function(){var t=this._getEditObject();t.label=document.getElementById("manipulator-obj-label").innerHTML;document.getElementById("manipulator-obj-label").innerHTML;t.color.background=document.getElementById("manipulator-obj-label").innerHTML},_createEditEdgeToolbar:function(){},_createConnectToolbar:function(){this._clearManipulatorBar(),this.off("select",this.boundFunction),this._unselectAll(),this.selectingForConnection=!1,this.manipulationDiv.innerHTML="Back
    Select the node you want to connect to other nodes.";var t=document.getElementById("manipulate-back");t.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._handleConnect.bind(this),this.on("select",this.boundFunction)},_handleConnect:function(){this.selectingForConnection=!1,this._clusterInSelection()?(this._unselectClusters(!0),this._setManipulationMessage(this._selectionIsEmpty()?"Select the node you want to connect to other nodes (Clusters are not allowed).":"Click on the node you want to connect this node to (Clusters are not allowed).")):this._selectionIsEmpty()?this._setManipulationMessage("Select the node you want to connect to other nodes."):2==this._getSelectedNodeCount()?(this._connectNodes(),this._restoreSourceNode(),this._setManipulationMessage("Click on another node you want to connect this node to or go back.")):(this._setManipulationMessage("Click on the node you want to connect this node."),this._setSourceNode(),this.selectingForConnection=!0)},_getEditObject:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t))return this.selectionObj[t];return null},_setSourceNode:function(){for(var t in this.selectionObj)this.selectionObj.hasOwnProperty(t)&&this.selectionObj[t]instanceof M&&(this.manipulationSourceNode=this.selectionObj[t])},_getTargetNode:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t)&&this.selectionObj[t]instanceof M&&this.manipulationSourceNode.id!=this.selectionObj[t].id)return this.selectionObj[t];return null},_restoreSourceNode:function(){this._unselectAll(!0),this._selectObject(this.manipulationSourceNode)},_setManipulationMessage:function(t){var e=document.getElementById("manipulatorLabel");e.innerHTML=t},_addNode:function(){if(this._selectionIsEmpty()){var t=this._pointerToPositionObject(this.pointerPosition);this.createNodeOnClick=!0,this.nodesData.add({id:z.randomUUID(),x:t.left,y:t.top,label:"new",fixed:!1}),this.createNodeOnClick=!1,this.moving=!0,this.start()}},_connectNodes:function(){var t=this._getTargetNode(),e=this.manipulationSourceNode;this.edgesData.add({from:e.id,to:t.id}),this.moving=!0,this.start()},_deleteSelected:function(){if(this._clusterInSelection())alert("Clusters cannot be deleted.");else{var t=this.getSelectedNodes(),e=this.getSelectedEdges();this._removeEdges(e),this._removeNodes(t),this._redraw()}}},R={_putDataInSector:function(){this.sectors.active[this._sector()].nodes=this.nodes,this.sectors.active[this._sector()].edges=this.edges,this.sectors.active[this._sector()].nodeIndices=this.nodeIndices},_switchToSector:function(t,e){void 0===e||"active"==e?this._switchToActiveSector(t):this._switchToFrozenSector(t)},_switchToActiveSector:function(t){this.nodeIndices=this.sectors.active[t].nodeIndices,this.nodes=this.sectors.active[t].nodes,this.edges=this.sectors.active[t].edges},_switchToFrozenSector:function(t){this.nodeIndices=this.sectors.frozen[t].nodeIndices,this.nodes=this.sectors.frozen[t].nodes,this.edges=this.sectors.frozen[t].edges},_switchToNavigationSector:function(){this.nodeIndices=this.sectors.navigation.nodeIndices,this.nodes=this.sectors.navigation.nodes,this.edges=this.sectors.navigation.edges},_loadLatestSector:function(){this._switchToSector(this._sector())},_sector:function(){return this.activeSector[this.activeSector.length-1]},_previousSector:function(){if(this.activeSector.length>1)return this.activeSector[this.activeSector.length-2];throw new TypeError("there are not enough sectors in the this.activeSector array.")},_setActiveSector:function(t){this.activeSector.push(t)},_forgetLastSector:function(){this.activeSector.pop()},_createNewSector:function(t){this.sectors.active[t]={nodes:{},edges:{},nodeIndices:[],formationScale:this.scale,drawingNode:void 0},this.sectors.active[t].drawingNode=new M({id:t,color:{background:"#eaefef",border:"495c5e"}},{},{},this.constants),this.sectors.active[t].drawingNode.clusterSize=2},_deleteActiveSector:function(t){delete this.sectors.active[t]},_deleteFrozenSector:function(t){delete this.sectors.frozen[t]},_freezeSector:function(t){this.sectors.frozen[t]=this.sectors.active[t],this._deleteActiveSector(t)},_activateSector:function(t){this.sectors.active[t]=this.sectors.frozen[t],this._deleteFrozenSector(t)},_mergeThisWithFrozen:function(t){for(var e in this.nodes)this.nodes.hasOwnProperty(e)&&(this.sectors.frozen[t].nodes[e]=this.nodes[e]);for(var i in this.edges)this.edges.hasOwnProperty(i)&&(this.sectors.frozen[t].edges[i]=this.edges[i]);for(var n=0;n1?this[t](n[0],n[1]):this[t](e)}this._loadLatestSector()},_doInAllFrozenSectors:function(t,e){if(void 0===e)for(var i in this.sectors.frozen)this.sectors.frozen.hasOwnProperty(i)&&(this._switchToFrozenSector(i),this[t]());else for(var i in this.sectors.frozen)if(this.sectors.frozen.hasOwnProperty(i)){this._switchToFrozenSector(i);var n=Array.prototype.splice.call(arguments,1);n.length>1?this[t](n[0],n[1]):this[t](e)}this._loadLatestSector()},_doInNavigationSector:function(t,e){if(this._switchToNavigationSector(),void 0===e)this[t]();else{var i=Array.prototype.splice.call(arguments,1);i.length>1?this[t](i[0],i[1]):this[t](e)}this._loadLatestSector()},_doInAllSectors:function(t,e){var i=Array.prototype.splice.call(arguments,1);void 0===e?(this._doInAllActiveSectors(t),this._doInAllFrozenSectors(t)):i.length>1?(this._doInAllActiveSectors(t,i[0],i[1]),this._doInAllFrozenSectors(t,i[0],i[1])):(this._doInAllActiveSectors(t,e),this._doInAllFrozenSectors(t,e))},_clearNodeIndexList:function(){var t=this._sector();this.sectors.active[t].nodeIndices=[],this.nodeIndices=this.sectors.active[t].nodeIndices},_drawSectorNodes:function(t,e){var i,n=1e9,s=-1e9,o=1e9,r=-1e9; +for(var a in this.sectors[e])if(this.sectors[e].hasOwnProperty(a)&&void 0!==this.sectors[e][a].drawingNode){this._switchToSector(a,e),n=1e9,s=-1e9,o=1e9,r=-1e9;for(var h in this.nodes)this.nodes.hasOwnProperty(h)&&(i=this.nodes[h],i.resize(t),o>i.x-.5*i.width&&(o=i.x-.5*i.width),ri.y-.5*i.height&&(n=i.y-.5*i.height),st&&n>s;)s%3==0?this.forceAggregateHubs():this.increaseClusterLevel(),i=this.nodeIndices.length,s+=1;s>1&&1==e&&this.repositionNodes()},openCluster:function(t){var e=this.moving;if(t.clusterSize>this.constants.clustering.sectorThreshold&&this._nodeInActiveArea(t)&&("default"!=this._sector()||1!=this.nodeIndices.length)){this._addSector(t);for(var i=0;this.nodeIndices.lengthi;)this.decreaseClusterLevel(),i+=1}else this._expandClusterNode(t,!1,!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels();this.moving!=e&&this.start()},updateClustersDefault:function(){1==this.constants.clustering.enabled&&this.updateClusters(0,!1,!1)},increaseClusterLevel:function(){this.updateClusters(-1,!1,!0)},decreaseClusterLevel:function(){this.updateClusters(1,!1,!0)},updateClusters:function(t,e,i){var n=this.moving,s=this.nodeIndices.length;this.previousScale>this.scale&&0==t&&this._collapseSector(),this.previousScale>this.scale||-1==t?this._formClusters(i):(this.previousScalethis.scale||-1==t)&&(this._aggregateHubs(i),this._updateNodeIndexList()),(this.previousScale>this.scale||-1==t)&&(this.handleChains(),this._updateNodeIndexList()),this.previousScale=this.scale,this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.lengththis.constants.clustering.chainThreshold&&this._reduceAmountOfChains(1-this.constants.clustering.chainThreshold/t)},_aggregateHubs:function(t){this._getHubSize(),this._formClustersByHub(t,!1)},forceAggregateHubs:function(){var t=this.moving,e=this.nodeIndices.length;this._aggregateHubs(!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.length!=e&&(this.clusterSession+=1),this.moving!=t&&this.start()},_openClustersBySize:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];1==e.inView()&&(e.width*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientWidth||e.height*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientHeight)&&this.openCluster(e)}},_openClusters:function(t,e){for(var i=0;i1&&(t.clusterSizei)){var r=o.from,a=o.to;o.to.mass>o.from.mass&&(r=o.to,a=o.from),1==a.dynamicEdgesLength?this._addToCluster(r,a,!1):1==r.dynamicEdgesLength&&this._addToCluster(a,r,!1)}}},_forceClustersByZoom:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];if(1==e.dynamicEdgesLength&&0!=e.dynamicEdges.length){var i=e.dynamicEdges[0],n=i.toId==e.id?this.nodes[i.fromId]:this.nodes[i.toId];e.id!=n.id&&(n.mass>e.mass?this._addToCluster(n,e,!0):this._addToCluster(e,n,!0))}}},_formClustersByHub:function(t,e){for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&this._formClusterFromHub(this.nodes[i],t,e)},_formClusterFromHub:function(t,e,i,n){if(void 0===n&&(n=0),t.dynamicEdgesLength>=this.hubThreshold&&0==i||t.dynamicEdgesLength==this.hubThreshold&&1==i){for(var s,o,r,a=this.constants.clustering.clusterEdgeThreshold/this.scale,h=!1,c=[],d=t.dynamicEdges.length,l=0;d>l;l++)c.push(t.dynamicEdges[l].id);if(0==e)for(h=!1,l=0;d>l;l++){var u=this.edges[c[l]];if(void 0!==u&&u.connected&&u.toId!=u.fromId&&(s=u.to.x-u.from.x,o=u.to.y-u.from.y,r=Math.sqrt(s*s+o*o),a>r)){h=!0;break}}if(!e&&h||e)for(l=0;d>l;l++)if(u=this.edges[c[l]],void 0!==u){var p=this.nodes[u.fromId==t.id?u.toId:u.fromId];p.dynamicEdges.length<=this.hubThreshold+n&&p.id!=t.id&&this._addToCluster(t,p,e)}}},_addToCluster:function(t,e,i){t.containedNodes[e.id]=e;for(var n=0;n1)for(var n=0;n1&&(e.label="[".concat(String(e.clusterSize),"]"))}for(t in this.nodes)this.nodes.hasOwnProperty(t)&&(e=this.nodes[t],1==e.clusterSize&&(e.label=void 0!==e.originalLabel?e.originalLabel:String(e.id)))},_nodeInActiveArea:function(t){return Math.abs(t.x-this.areaCenter.x)<=this.constants.clustering.activeAreaBoxSize/this.scale&&Math.abs(t.y-this.areaCenter.y)<=this.constants.clustering.activeAreaBoxSize/this.scale},repositionNodes:function(){for(var t=0;tn&&(n=o.dynamicEdgesLength),t+=o.dynamicEdgesLength,e+=Math.pow(o.dynamicEdgesLength,2),i+=1}t/=i,e/=i;var r=e-Math.pow(t,2),a=Math.sqrt(r);this.hubThreshold=Math.floor(t+2*a),this.hubThreshold>n&&(this.hubThreshold=n)},_reduceAmountOfChains:function(t){this.hubThreshold=2;var e=Math.floor(this.nodeIndices.length*t);for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&e>0&&(this._formClusterFromHub(this.nodes[i],!0,!0,1),e-=1)},_getChainFraction:function(){var t=0,e=0;for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&(2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&(t+=1),e+=1);return t/e}},j={_getNodesOverlappingWith:function(t,e){var i=this.nodes;for(var n in i)i.hasOwnProperty(n)&&i[n].isOverlappingWith(t)&&e.push(n)},_getAllNodesOverlappingWith:function(t){var e=[];return this._doInAllActiveSectors("_getNodesOverlappingWith",t,e),e},_getAllNavigationNodesOverlappingWith:function(t){var e=[];return this._doInNavigationSector("_getNodesOverlappingWith",t,e),e},_pointerToPositionObject:function(t){var e=this._canvasToX(t.x),i=this._canvasToY(t.y);return{left:e,top:i,right:e,bottom:i}},_pointerToScreenPositionObject:function(t){var e=t.x,i=t.y;return{left:e,top:i,right:e,bottom:i}},_getNavigationNodeAt:function(t){var e=this._pointerToScreenPositionObject(t),i=this._getAllNavigationNodesOverlappingWith(e);return i.length>0?this.sectors.navigation.nodes[i[i.length-1]]:null},_getNodeAt:function(t){var e=this._pointerToPositionObject(t),i=this._getAllNodesOverlappingWith(e);return i.length>0?this.nodes[i[i.length-1]]:null},_getEdgesOverlappingWith:function(t,e){var i=this.edges;for(var n in i)i.hasOwnProperty(n)&&i[n].isOverlappingWith(t)&&e.push(n)},_getAllEdgesOverlappingWith:function(t){var e=[];return this._doInAllActiveSectors("_getEdgesOverlappingWith",t,e),e},_getEdgeAt:function(t){var e=this._pointerToPositionObject(t),i=this._getAllEdgesOverlappingWith(e);return i.length>0?this.edges[i[i.length-1]]:null},_addToSelection:function(t){this.selectionObj[t.id]=t},_removeFromSelection:function(t){delete this.selectionObj[t.id]},_unselectAll:function(t){void 0===t&&(t=!1);for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e].unselect();this.selectionObj={},0==t&&this._trigger("select",{nodes:this.getSelection()})},_unselectClusters:function(t){void 0===t&&(t=!1);for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e]instanceof M&&this.selectionObj[e].clusterSize>1&&this.selectionObj[e].unselect();0==t&&this._trigger("select",{nodes:this.getSelection()})},_getSelectedNodeCount:function(){var t=0;for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e]instanceof M&&(t+=1);return t},_getSelectedEdgeCount:function(){var t=0;for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e]instanceof D&&(t+=1);return t},_getSelectedObjectCount:function(){var t=0;for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&(t+=1);return t},_selectionIsEmpty:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t))return!1;return!0},_clusterInSelection:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t)&&this.selectionObj[t]instanceof M&&this.selectionObj[t].clusterSize>1)return!0;return!1},_selectConnectedEdges:function(t){for(var e=0;ee;e++){n=t[e];var s=this.nodes[n];if(!s)throw new RangeError('Node with id "'+n+'" not found');this._selectObject(s,!0,!0)}this.redraw()},_updateSelection:function(){for(var t in this.selectionObj)this.selectionObj.hasOwnProperty(t)&&(this.selectionObj[t]instanceof M?this.nodes.hasOwnProperty(t)||delete this.selectionObj[t]:this.edges.hasOwnProperty(t)||delete this.selectionObj[t])}},U={_relocateNavigation:function(){if(void 0!==this.sectors){var t=this.navigationClientWidth-this.frame.canvas.clientWidth,e=this.navigationClientHeight-this.frame.canvas.clientHeight;this.navigationClientWidth=this.frame.canvas.clientWidth,this.navigationClientHeight=this.frame.canvas.clientHeight;var i=null;for(var n in this.sectors.navigation.nodes)this.sectors.navigation.nodes.hasOwnProperty(n)&&(i=this.sectors.navigation.nodes[n],i.horizontalAlignLeft||(i.x-=t),i.verticalAlignTop||(i.y-=e))}},_loadNavigationElements:function(){var t=this.constants.navigation.iconPath;this.navigationClientWidth=this.frame.canvas.clientWidth,this.navigationClientHeight=this.frame.canvas.clientHeight,void 0===this.navigationClientWidth&&(this.navigationClientWidth=0,this.navigationClientHeight=0);for(var e=15,i=7,n=[{id:"navigation_up",shape:"image",image:t+"/uparrow.png",triggerFunction:"_moveUp",verticalAlignTop:!1,x:45+e+i,y:this.navigationClientHeight-45-e-i},{id:"navigation_down",shape:"image",image:t+"/downarrow.png",triggerFunction:"_moveDown",verticalAlignTop:!1,x:45+e+i,y:this.navigationClientHeight-15-e},{id:"navigation_left",shape:"image",image:t+"/leftarrow.png",triggerFunction:"_moveLeft",verticalAlignTop:!1,x:15+e,y:this.navigationClientHeight-15-e},{id:"navigation_right",shape:"image",image:t+"/rightarrow.png",triggerFunction:"_moveRight",verticalAlignTop:!1,x:75+e+2*i,y:this.navigationClientHeight-15-e},{id:"navigation_plus",shape:"image",image:t+"/plus.png",triggerFunction:"_zoomIn",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-45-e-i,y:this.navigationClientHeight-15-e},{id:"navigation_min",shape:"image",image:t+"/minus.png",triggerFunction:"_zoomOut",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-15-e,y:this.navigationClientHeight-15-e},{id:"navigation_zoomExtends",shape:"image",image:t+"/zoomExtends.png",triggerFunction:"zoomToFit",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-15-e,y:this.navigationClientHeight-45-e-i}],s=null,o=0;ot.x-t.width&&(n=t.x-t.width),st.y-t.height&&(e=t.y-t.height),i=this.constants.clustering.initialMaxNodes)var n=38.8467/(e-14.50184)+.0116;else var n=42.54117319/(e+39.31966387)+.1944405;else{var s=1.1*(Math.abs(i.minX)+Math.abs(i.maxX)),o=1.1*(Math.abs(i.minY)+Math.abs(i.maxY)),r=this.frame.canvas.clientWidth/s,a=this.frame.canvas.clientHeight/o;n=a>=r?r:a}n>1&&(n=1),this.pinch.mousewheelScale=n,this._setScale(n),this._centerGraph(i),this.start()},I.prototype._updateNodeIndexList=function(){this._clearNodeIndexList();for(var t in this.nodes)this.nodes.hasOwnProperty(t)&&this.nodeIndices.push(t)},I.prototype.setData=function(t,e){if(void 0===e&&(e=!1),t&&t.dot&&(t.nodes||t.edges))throw new SyntaxError('Data must contain either parameter "dot" or parameter pair "nodes" and "edges", but not both.');if(this.setOptions(t&&t.options),t&&t.dot){if(t&&t.dot){var i=B.util.DOTToGraph(t.dot);return void this.setData(i)}}else this._setNodes(t&&t.nodes),this._setEdges(t&&t.edges);this._putDataInSector(),e||(this.stabilize&&this._doStabilize(),this.moving=!0,this.start())},I.prototype.setOptions=function(t){if(t){if(void 0!==t.width&&(this.width=t.width),void 0!==t.height&&(this.height=t.height),void 0!==t.stabilize&&(this.stabilize=t.stabilize),void 0!==t.selectable&&(this.selectable=t.selectable),t.clustering){this.constants.clustering.enabled=!0;for(var e in t.clustering)t.clustering.hasOwnProperty(e)&&(this.constants.clustering[e]=t.clustering[e])}else void 0!==t.clustering&&(this.constants.clustering.enabled=!1);if(t.navigation){this.constants.navigation.enabled=!0;for(var e in t.navigation)t.navigation.hasOwnProperty(e)&&(this.constants.navigation[e]=t.navigation[e])}else void 0!==t.navigation&&(this.constants.navigation.enabled=!1);if(t.keyboard){this.constants.keyboard.enabled=!0;for(var e in t.keyboard)t.keyboard.hasOwnProperty(e)&&(this.constants.keyboard[e]=t.keyboard[e])}else void 0!==t.keyboard&&(this.constants.keyboard.enabled=!1);if(t.edges){for(e in t.edges)t.edges.hasOwnProperty(e)&&(this.constants.edges[e]=t.edges[e]);void 0!==t.edges.length&&t.nodes&&void 0===t.nodes.distance&&(this.constants.edges.length=t.edges.length,this.constants.nodes.distance=1.25*t.edges.length),t.edges.fontColor||(this.constants.edges.fontColor=t.edges.color),t.edges.dash&&(void 0!==t.edges.dash.length&&(this.constants.edges.dash.length=t.edges.dash.length),void 0!==t.edges.dash.gap&&(this.constants.edges.dash.gap=t.edges.dash.gap),void 0!==t.edges.dash.altLength&&(this.constants.edges.dash.altLength=t.edges.dash.altLength))}if(t.nodes){for(e in t.nodes)t.nodes.hasOwnProperty(e)&&(this.constants.nodes[e]=t.nodes[e]);t.nodes.color&&(this.constants.nodes.color=M.parseColor(t.nodes.color))}if(t.groups)for(var i in t.groups)if(t.groups.hasOwnProperty(i)){var n=t.groups[i];this.groups.add(i,n)}}this.setSize(this.width,this.height),this._setTranslation(this.frame.clientWidth/2,this.frame.clientHeight/2),this._setScale(1),this._loadNavigationControls(),this._createKeyBinds(),this._redraw()},I.prototype.on=function(t,e){var i=["select"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());F.addListener(this,t,e)},I.prototype.off=function(t,e){F.removeListener(this,t,e)},I.prototype._trigger=function(t,e){F.trigger(this,t,e)},I.prototype._create=function(){for(;this.containerElement.hasChildNodes();)this.containerElement.removeChild(this.containerElement.firstChild);if(this.frame=document.createElement("div"),this.frame.className="graph-frame",this.frame.style.position="relative",this.frame.style.overflow="hidden",this.frame.style.zIndex="1",this.frame.canvas=document.createElement("canvas"),this.frame.canvas.style.position="relative",this.frame.appendChild(this.frame.canvas),!this.frame.canvas.getContext){var t=document.createElement("DIV");t.style.color="red",t.style.fontWeight="bold",t.style.padding="10px",t.innerHTML="Error: your browser does not support HTML canvas",this.frame.canvas.appendChild(t)}var e=this;this.drag={},this.pinch={},this.hammer=N(this.frame.canvas,{prevent_default:!0}),this.hammer.on("tap",e._onTap.bind(e)),this.hammer.on("doubletap",e._onDoubleTap.bind(e)),this.hammer.on("hold",e._onHold.bind(e)),this.hammer.on("pinch",e._onPinch.bind(e)),this.hammer.on("touch",e._onTouch.bind(e)),this.hammer.on("dragstart",e._onDragStart.bind(e)),this.hammer.on("drag",e._onDrag.bind(e)),this.hammer.on("dragend",e._onDragEnd.bind(e)),this.hammer.on("release",e._onRelease.bind(e)),this.hammer.on("mousewheel",e._onMouseWheel.bind(e)),this.hammer.on("DOMMouseScroll",e._onMouseWheel.bind(e)),this.hammer.on("mousemove",e._onMouseMoveTitle.bind(e)),this.containerElement.appendChild(this.frame)},I.prototype._createKeyBinds=function(){var t=this;this.mousetrap=k,this.mousetrap.reset(),1==this.constants.keyboard.enabled&&(this.mousetrap.bind("up",this._moveUp.bind(t),"keydown"),this.mousetrap.bind("up",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("down",this._moveDown.bind(t),"keydown"),this.mousetrap.bind("down",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("left",this._moveLeft.bind(t),"keydown"),this.mousetrap.bind("left",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("right",this._moveRight.bind(t),"keydown"),this.mousetrap.bind("right",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("=",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("=",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("-",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("-",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("[",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("[",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("]",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("]",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pageup",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("pageup",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pagedown",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("pagedown",this._stopZoom.bind(t),"keyup"))},I.prototype._getPointer=function(t){return{x:t.pageX-B.util.getAbsoluteLeft(this.frame.canvas),y:t.pageY-B.util.getAbsoluteTop(this.frame.canvas)}},I.prototype._onTouch=function(t){this.drag.pointer=this._getPointer(t.gesture.touches[0]),this.drag.pinched=!1,this.pinch.scale=this._getScale(),this._handleTouch(this.drag.pointer)},I.prototype._onDragStart=function(){var t=this.drag,e=this._getNodeAt(t.pointer);if(t.dragging=!0,t.selection=[],t.translation=this._getTranslation(),t.nodeId=null,null!=e){t.nodeId=e.id,e.isSelected()||this._selectObject(e,!1);for(var i in this.selectionObj)if(this.selectionObj.hasOwnProperty(i)){var n=this.selectionObj[i];if(n instanceof M){var s={id:n.id,node:n,x:n.x,y:n.y,xFixed:n.xFixed,yFixed:n.yFixed};n.xFixed=!0,n.yFixed=!0,t.selection.push(s)}}}},I.prototype._onDrag=function(t){if(!this.drag.pinched){var e=this._getPointer(t.gesture.touches[0]),i=this,n=this.drag,s=n.selection;if(s&&s.length){var o=e.x-n.pointer.x,r=e.y-n.pointer.y;s.forEach(function(t){var e=t.node;t.xFixed||(e.x=i._canvasToX(i._xToCanvas(t.x)+o)),t.yFixed||(e.y=i._canvasToY(i._yToCanvas(t.y)+r))}),this.moving||(this.moving=!0,this.start())}else{var a=e.x-this.drag.pointer.x,h=e.y-this.drag.pointer.y;this._setTranslation(this.drag.translation.x+a,this.drag.translation.y+h),this._redraw(),this.moved=!0}}},I.prototype._onDragEnd=function(){this.drag.dragging=!1;var t=this.drag.selection;t&&t.forEach(function(t){t.node.xFixed=t.xFixed,t.node.yFixed=t.yFixed})},I.prototype._onTap=function(t){var e=this._getPointer(t.gesture.touches[0]);this.pointerPosition=e,this._handleTap(e)},I.prototype._onDoubleTap=function(t){var e=this._getPointer(t.gesture.touches[0]);this._handleDoubleTap(e)},I.prototype._onHold=function(t){var e=this._getPointer(t.gesture.touches[0]);this.pointerPosition=e,this._handleOnHold(e)},I.prototype._onRelease=function(){this._handleOnRelease()},I.prototype._onPinch=function(t){var e=this._getPointer(t.gesture.center);this.drag.pinched=!0,"scale"in this.pinch||(this.pinch.scale=1);var i=this.pinch.scale*t.gesture.scale;this._zoom(i,e)},I.prototype._zoom=function(t,e){var i=this._getScale();1e-5>t&&(t=1e-5),t>10&&(t=10);var n=this._getTranslation(),s=t/i,o=(1-s)*e.x+n.x*s,r=(1-s)*e.y+n.y*s;return this.areaCenter={x:this._canvasToX(e.x),y:this._canvasToY(e.y)},this.pinch.mousewheelScale=t,this._setScale(t),this._setTranslation(o,r),this.updateClustersDefault(),this._redraw(),t},I.prototype._onMouseWheel=function(t){var e=0;if(t.wheelDelta?e=t.wheelDelta/120:t.detail&&(e=-t.detail/3),e){"mousewheelScale"in this.pinch||(this.pinch.mousewheelScale=1);var i=this.pinch.mousewheelScale,n=e/10;0>e&&(n/=1-n),i*=1+n;var s=z.fakeGesture(this,t),o=this._getPointer(s.center);i=this._zoom(i,o)}t.preventDefault()},I.prototype._onMouseMoveTitle=function(t){var e=z.fakeGesture(this,t),i=this._getPointer(e.center);this.popupNode&&this._checkHidePopup(i);var n=this,s=function(){n._checkShowPopup(i)};this.popupTimer&&clearInterval(this.popupTimer),this.drag.dragging||(this.popupTimer=setTimeout(s,300))},I.prototype._checkShowPopup=function(t){var e,i={left:this._canvasToX(t.x),top:this._canvasToY(t.y),right:this._canvasToX(t.x),bottom:this._canvasToY(t.y)},n=this.popupNode;if(void 0==this.popupNode){var s=this.nodes;for(e in s)if(s.hasOwnProperty(e)){var o=s[e];if(void 0!==o.getTitle()&&o.isOverlappingWith(i)){this.popupNode=o;break}}}if(void 0===this.popupNode){var r=this.edges;for(e in r)if(r.hasOwnProperty(e)){var a=r[e];if(a.connected&&void 0!==a.getTitle()&&a.isOverlappingWith(i)){this.popupNode=a;break}}}if(this.popupNode){if(this.popupNode!=n){var h=this;h.popup||(h.popup=new O(h.frame)),h.popup.setPosition(t.x-3,t.y-3),h.popup.setText(h.popupNode.getTitle()),h.popup.show()}}else this.popup&&this.popup.hide()},I.prototype._checkHidePopup=function(t){this.popupNode&&this._getNodeAt(t)||(this.popupNode=void 0,this.popup&&this.popup.hide())},I.prototype._getConnectionCount=function(t){function e(t){for(var e=[],i=0,n=t.length;n>i;i++)for(var s=t[i],o=s.edges,r=0,a=o.length;a>r;r++){var h=o[r],c=null;h.from==s?c=h.to:h.to==s&&(c=h.from);var d,l;if(c)for(d=0,l=t.length;l>d;d++)if(t[d]==c){c=null;break}if(c)for(d=0,l=e.length;l>d;d++)if(e[d]==c){c=null;break}c&&e.push(c)}return e}void 0==t&&(t=1);var i=[],n=this.nodes;for(var s in n)if(n.hasOwnProperty(s)){for(var o=[n[s]],r=0;t>r;r++)o=o.concat(e(o));i.push(o)}for(var a=[],h=0,c=i.length;c>h;h++)a.push(i[h].length);return a},I.prototype.setSize=function(t,e){this.frame.style.width=t,this.frame.style.height=e,this.frame.canvas.style.width="100%",this.frame.canvas.style.height="100%",this.frame.canvas.width=this.frame.canvas.clientWidth,this.frame.canvas.height=this.frame.canvas.clientHeight,void 0!==this.manipulationDiv&&(this.manipulationDiv.style.width=this.frame.canvas.clientWidth),1==this.constants.navigation.enabled&&this._relocateNavigation() +},I.prototype._setNodes=function(t){var e=this.nodesData;if(t instanceof o||t instanceof r)this.nodesData=t;else if(t instanceof Array)this.nodesData=new o,this.nodesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.nodesData=new o}if(e&&z.forEach(this.nodesListeners,function(t,i){e.unsubscribe(i,t)}),this.nodes={},this.nodesData){var i=this;z.forEach(this.nodesListeners,function(t,e){i.nodesData.subscribe(e,t)});var n=this.nodesData.getIds();this._addNodes(n)}this._updateSelection()},I.prototype._addNodes=function(t){for(var e,i=0,n=t.length;n>i;i++){e=t[i];var s=this.nodesData.get(e),o=new M(s,this.images,this.groups,this.constants);if(this.nodes[e]=o,!o.isFixed()&&1!=this.createNodeOnClick){var r=2*this.constants.edges.length,a=t.length,h=2*Math.PI*(i/a);o.x=r*Math.cos(h),o.y=r*Math.sin(h),this.moving=!0}}this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(this.nodes),this.updateLabels()},I.prototype._updateNodes=function(t){for(var e=this.nodes,i=this.nodesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o],a=i.get(o);r?r.setProperties(a,this.constants):(r=new M(properties,this.images,this.groups,this.constants),e[o]=r,r.isFixed()||(this.moving=!0))}this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(e)},I.prototype._removeNodes=function(t){for(var e=this.nodes,i=0,n=t.length;n>i;i++){var s=t[i];delete e[s]}this._updateNodeIndexList(),this._reconnectEdges(),this._updateSelection(),this._updateValueRange(e)},I.prototype._setEdges=function(t){var e=this.edgesData;if(t instanceof o||t instanceof r)this.edgesData=t;else if(t instanceof Array)this.edgesData=new o,this.edgesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.edgesData=new o}if(e&&z.forEach(this.edgesListeners,function(t,i){e.unsubscribe(i,t)}),this.edges={},this.edgesData){var i=this;z.forEach(this.edgesListeners,function(t,e){i.edgesData.subscribe(e,t)});var n=this.edgesData.getIds();this._addEdges(n)}this._reconnectEdges()},I.prototype._addEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o];r&&r.disconnect();var a=i.get(o,{showInternalIds:!0});e[o]=new D(a,this,this.constants)}this.moving=!0,this._updateValueRange(e)},I.prototype._updateEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=i.get(o),a=e[o];a?(a.disconnect(),a.setProperties(r,this.constants),a.connect()):(a=new D(r,this,this.constants),this.edges[o]=a)}this.moving=!0,this._updateValueRange(e)},I.prototype._removeEdges=function(t){for(var e=this.edges,i=0,n=t.length;n>i;i++){var s=t[i],o=e[s];o&&(o.disconnect(),delete e[s])}this.moving=!0,this._updateValueRange(e)},I.prototype._reconnectEdges=function(){var t,e=this.nodes,i=this.edges;for(t in e)e.hasOwnProperty(t)&&(e[t].edges=[]);for(t in i)if(i.hasOwnProperty(t)){var n=i[t];n.from=null,n.to=null,n.connect()}},I.prototype._updateValueRange=function(t){var e,i=void 0,n=void 0;for(e in t)if(t.hasOwnProperty(e)){var s=t[e].getValue();void 0!==s&&(i=void 0===i?s:Math.min(s,i),n=void 0===n?s:Math.max(s,n))}if(void 0!==i&&void 0!==n)for(e in t)t.hasOwnProperty(e)&&t[e].setValueRange(i,n)},I.prototype.redraw=function(){this.setSize(this.width,this.height),this._redraw()},I.prototype._redraw=function(){var t=this.frame.canvas.getContext("2d"),e=this.frame.canvas.width,i=this.frame.canvas.height;t.clearRect(0,0,e,i),t.save(),t.translate(this.translation.x,this.translation.y),t.scale(this.scale,this.scale),this.canvasTopLeft={x:this._canvasToX(0),y:this._canvasToY(0)},this.canvasBottomRight={x:this._canvasToX(this.frame.canvas.clientWidth),y:this._canvasToY(this.frame.canvas.clientHeight)},this._doInAllSectors("_drawAllSectorNodes",t),this._doInAllSectors("_drawEdges",t),this._doInAllSectors("_drawNodes",t,!0),t.restore(),1==this.constants.navigation.enabled&&this._doInNavigationSector("_drawNodes",t,!0)},I.prototype._setTranslation=function(t,e){void 0===this.translation&&(this.translation={x:0,y:0}),void 0!==t&&(this.translation.x=t),void 0!==e&&(this.translation.y=e)},I.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},I.prototype._setScale=function(t){this.scale=t},I.prototype._getScale=function(){return this.scale},I.prototype._canvasToX=function(t){return(t-this.translation.x)/this.scale},I.prototype._xToCanvas=function(t){return t*this.scale+this.translation.x},I.prototype._canvasToY=function(t){return(t-this.translation.y)/this.scale},I.prototype._yToCanvas=function(t){return t*this.scale+this.translation.y},I.prototype._drawNodes=function(t,e){void 0===e&&(e=!1);var i=this.nodes,n=[];for(var s in i)i.hasOwnProperty(s)&&(i[s].setScaleAndPos(this.scale,this.canvasTopLeft,this.canvasBottomRight),i[s].isSelected()?n.push(s):(i[s].inArea()||e)&&i[s].draw(t));for(var o=0,r=n.length;r>o;o++)(i[n[o]].inArea()||e)&&i[n[o]].draw(t)},I.prototype._drawEdges=function(t){var e=this.edges;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];n.setScale(this.scale),n.connected&&e[i].draw(t)}},I.prototype._doStabilize=function(){for(var t=0,e=this.constants.minVelocity,i=!1;!i&&tthis.constants.clustering.clusterThreshold&&1==this.constants.clustering.enabled&&this.clusterToFit(this.constants.clustering.reduceToNodes,!1),this._calculateForces())},I.prototype._calculateForces=function(){var t,e,i,n,s,o,r,a,h,c,d,l,u,p,f,g,m,v,y=this.nodes,_=this.edges,w=.08*this.forceFactor;for(g=0;gn&&(i=Math.atan2(e,t),r=.5*b>n?1:T*n+E,r*=0==v?1:1+v*this.constants.clustering.forceAmplification,r*=this.forceFactor,s=Math.cos(i)*r,o=Math.sin(i)*r,l._addForce(-s,-o),u._addForce(s,o))}for(f in _)_.hasOwnProperty(f)&&(p=_[f],p.connected&&this.nodes.hasOwnProperty(p.toId)&&this.nodes.hasOwnProperty(p.fromId)&&(v=p.to.clusterSize+p.from.clusterSize-2,t=p.to.x-p.from.x,e=p.to.y-p.from.y,c=p.length,c+=v*this.constants.clustering.edgeGrowth,h=Math.sqrt(t*t+e*e),i=Math.atan2(e,t),a=p.stiffness*(c-h)*this.forceFactor,s=Math.cos(i)*a,o=Math.sin(i)*a,p.from._addForce(-s,-o),p.to._addForce(s,o)))},I.prototype._isMoving=function(t){var e=t/this.scale,i=this.nodes;for(var n in i)if(i.hasOwnProperty(n)&&i[n].isMoving(e))return!0;return!1},I.prototype._discreteStepNodes=function(){var t=.01,e=this.nodes;for(var i in e)e.hasOwnProperty(i)&&e[i].discreteStep(t);var n=this.constants.minVelocity;this.moving=this._isMoving(n)},I.prototype.start=function(){if(!this.freezeSimulation)if(this.moving&&(this._doInAllActiveSectors("_initializeForceCalculation"),this._doInAllActiveSectors("_discreteStepNodes"),this._findCenter(this._getRange())),this.moving||0!=this.xIncrement||0!=this.yIncrement||0!=this.zoomIncrement){if(!this.timer){var t=this;this.timer=window.setTimeout(function(){if(t.timer=void 0,0!=t.xIncrement||0!=t.yIncrement){var e=t._getTranslation();t._setTranslation(e.x+t.xIncrement,e.y+t.yIncrement)}if(0!=t.zoomIncrement){var i={x:t.frame.canvas.clientWidth/2,y:t.frame.canvas.clientHeight/2};t._zoom(t.scale*(1+t.zoomIncrement),i)}t.start(),t._redraw()},this.renderTimestep)}}else this._redraw()},I.prototype.singleStep=function(){if(this.moving){this._initializeForceCalculation(),this._discreteStepNodes();var t=this.constants.minVelocity;this.moving=this._isMoving(t),this._redraw()}},I.prototype.toggleFreeze=function(){0==this.freezeSimulation?this.freezeSimulation=!0:(this.freezeSimulation=!1,this.start())},I.prototype._loadClusterSystem=function(){this.clusterSession=0,this.hubThreshold=5;for(var t in W)W.hasOwnProperty(t)&&(I.prototype[t]=W[t])},I.prototype._loadSectorSystem=function(){this.sectors={},this.activeSector=["default"],this.sectors.active={},this.sectors.active["default"]={nodes:{},edges:{},nodeIndices:[],formationScale:1,drawingNode:void 0},this.sectors.frozen={},this.sectors.navigation={nodes:{},edges:{},nodeIndices:[],formationScale:1,drawingNode:void 0},this.nodeIndices=this.sectors.active["default"].nodeIndices;for(var t in R)R.hasOwnProperty(t)&&(I.prototype[t]=R[t])},I.prototype._loadSelectionSystem=function(){this.selectionObj={};for(var t in j)j.hasOwnProperty(t)&&(I.prototype[t]=j[t])},I.prototype._loadManipulationSystem=function(){this.manipulationDiv=document.createElement("div"),this.manipulationDiv.className="graph-manipulationDiv",this.containerElement.insertBefore(this.manipulationDiv,this.frame);for(var t in H)H.hasOwnProperty(t)&&(I.prototype[t]=H[t]);this._createManipulatorBar()},I.prototype._loadNavigationControls=function(){for(var t in U)U.hasOwnProperty(t)&&(I.prototype[t]=U[t]);1==this.constants.navigation.enabled&&this._loadNavigationElements()},I.prototype._relocateNavigation=function(){},I.prototype._unHighlightAll=function(){};var B={util:z,events:F,Controller:l,DataSet:o,DataView:r,Range:h,Stack:a,TimeStep:TimeStep,EventBus:s,components:{items:{Item:_,ItemBox:w,ItemPoint:b,ItemRange:S},Component:u,Panel:p,RootPanel:f,ItemSet:y,TimeAxis:g},graph:{Node:M,Edge:D,Popup:O,Groups:Groups,Images:Images},Timeline:C,Graph:I};"undefined"!=typeof n&&(n=B),"undefined"!=typeof i&&"undefined"!=typeof i.exports&&(i.exports=B),"function"==typeof t&&t(function(){return B}),"undefined"!=typeof window&&(window.vis=B)},{hammerjs:2,moment:3,mousetrap:4}],2:[function(t,e){!function(t,i){"use strict";function n(){if(!s.READY){s.event.determineEventTypes();for(var t in s.gestures)s.gestures.hasOwnProperty(t)&&s.detection.register(s.gestures[t]);s.event.onTouch(s.DOCUMENT,s.EVENT_MOVE,s.detection.detect),s.event.onTouch(s.DOCUMENT,s.EVENT_END,s.detection.detect),s.READY=!0}}var s=function(t,e){return new s.Instance(t,e||{})};s.defaults={stop_browser_behavior:{userSelect:"none",touchAction:"none",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}},s.HAS_POINTEREVENTS=navigator.pointerEnabled||navigator.msPointerEnabled,s.HAS_TOUCHEVENTS="ontouchstart"in t,s.MOBILE_REGEX=/mobile|tablet|ip(ad|hone|od)|android/i,s.NO_MOUSEEVENTS=s.HAS_TOUCHEVENTS&&navigator.userAgent.match(s.MOBILE_REGEX),s.EVENT_TYPES={},s.DIRECTION_DOWN="down",s.DIRECTION_LEFT="left",s.DIRECTION_UP="up",s.DIRECTION_RIGHT="right",s.POINTER_MOUSE="mouse",s.POINTER_TOUCH="touch",s.POINTER_PEN="pen",s.EVENT_START="start",s.EVENT_MOVE="move",s.EVENT_END="end",s.DOCUMENT=document,s.plugins={},s.READY=!1,s.Instance=function(t,e){var i=this;return n(),this.element=t,this.enabled=!0,this.options=s.utils.extend(s.utils.extend({},s.defaults),e||{}),this.options.stop_browser_behavior&&s.utils.stopDefaultBrowserBehavior(this.element,this.options.stop_browser_behavior),s.event.onTouch(t,s.EVENT_START,function(t){i.enabled&&s.detection.startDetect(i,t)}),this},s.Instance.prototype={on:function(t,e){for(var i=t.split(" "),n=0;n0&&e==s.EVENT_END?e=s.EVENT_MOVE:d||(e=s.EVENT_END),d||null===o?o=h:h=o,i.call(s.detection,n.collectEventData(t,e,h)),s.HAS_POINTEREVENTS&&e==s.EVENT_END&&(d=s.PointerEvent.updatePointer(e,h))),d||(o=null,r=!1,a=!1,s.PointerEvent.reset())}})},determineEventTypes:function(){var t;t=s.HAS_POINTEREVENTS?s.PointerEvent.getEvents():s.NO_MOUSEEVENTS?["touchstart","touchmove","touchend touchcancel"]:["touchstart mousedown","touchmove mousemove","touchend touchcancel mouseup"],s.EVENT_TYPES[s.EVENT_START]=t[0],s.EVENT_TYPES[s.EVENT_MOVE]=t[1],s.EVENT_TYPES[s.EVENT_END]=t[2]},getTouchList:function(t){return s.HAS_POINTEREVENTS?s.PointerEvent.getTouchList():t.touches?t.touches:[{identifier:1,pageX:t.pageX,pageY:t.pageY,target:t.target}]},collectEventData:function(t,e,i){var n=this.getTouchList(i,e),o=s.POINTER_TOUCH;return(i.type.match(/mouse/)||s.PointerEvent.matchType(s.POINTER_MOUSE,i))&&(o=s.POINTER_MOUSE),{center:s.utils.getCenter(n),timeStamp:(new Date).getTime(),target:i.target,touches:n,eventType:e,pointerType:o,srcEvent:i,preventDefault:function(){this.srcEvent.preventManipulation&&this.srcEvent.preventManipulation(),this.srcEvent.preventDefault&&this.srcEvent.preventDefault()},stopPropagation:function(){this.srcEvent.stopPropagation()},stopDetect:function(){return s.detection.stopDetect()}}}},s.PointerEvent={pointers:{},getTouchList:function(){var t=this,e=[];return Object.keys(t.pointers).sort().forEach(function(i){e.push(t.pointers[i])}),e},updatePointer:function(t,e){return t==s.EVENT_END?this.pointers={}:(e.identifier=e.pointerId,this.pointers[e.pointerId]=e),Object.keys(this.pointers).length},matchType:function(t,e){if(!e.pointerType)return!1;var i={};return i[s.POINTER_MOUSE]=e.pointerType==e.MSPOINTER_TYPE_MOUSE||e.pointerType==s.POINTER_MOUSE,i[s.POINTER_TOUCH]=e.pointerType==e.MSPOINTER_TYPE_TOUCH||e.pointerType==s.POINTER_TOUCH,i[s.POINTER_PEN]=e.pointerType==e.MSPOINTER_TYPE_PEN||e.pointerType==s.POINTER_PEN,i[t]},getEvents:function(){return["pointerdown MSPointerDown","pointermove MSPointerMove","pointerup pointercancel MSPointerUp MSPointerCancel"]},reset:function(){this.pointers={}}},s.utils={extend:function(t,e,n){for(var s in e)t[s]!==i&&n||(t[s]=e[s]);return t},hasParent:function(t,e){for(;t;){if(t==e)return!0;t=t.parentNode}return!1},getCenter:function(t){for(var e=[],i=[],n=0,s=t.length;s>n;n++)e.push(t[n].pageX),i.push(t[n].pageY);return{pageX:(Math.min.apply(Math,e)+Math.max.apply(Math,e))/2,pageY:(Math.min.apply(Math,i)+Math.max.apply(Math,i))/2}},getVelocity:function(t,e,i){return{x:Math.abs(e/t)||0,y:Math.abs(i/t)||0}},getAngle:function(t,e){var i=e.pageY-t.pageY,n=e.pageX-t.pageX;return 180*Math.atan2(i,n)/Math.PI},getDirection:function(t,e){var i=Math.abs(t.pageX-e.pageX),n=Math.abs(t.pageY-e.pageY);return i>=n?t.pageX-e.pageX>0?s.DIRECTION_LEFT:s.DIRECTION_RIGHT:t.pageY-e.pageY>0?s.DIRECTION_UP:s.DIRECTION_DOWN},getDistance:function(t,e){var i=e.pageX-t.pageX,n=e.pageY-t.pageY;return Math.sqrt(i*i+n*n)},getScale:function(t,e){return t.length>=2&&e.length>=2?this.getDistance(e[0],e[1])/this.getDistance(t[0],t[1]):1},getRotation:function(t,e){return t.length>=2&&e.length>=2?this.getAngle(e[1],e[0])-this.getAngle(t[1],t[0]):0},isVertical:function(t){return t==s.DIRECTION_UP||t==s.DIRECTION_DOWN},stopDefaultBrowserBehavior:function(t,e){var i,n=["webkit","khtml","moz","ms","o",""];if(e&&t.style){for(var s=0;si;i++){var o=this.gestures[i];if(!this.stopped&&e[o.name]!==!1&&o.handler.call(o,t,this.current.inst)===!1){this.stopDetect();break}}return this.current&&(this.current.lastEvent=t),t.eventType==s.EVENT_END&&!t.touches.length-1&&this.stopDetect(),t}},stopDetect:function(){this.previous=s.utils.extend({},this.current),this.current=null,this.stopped=!0},extendEventData:function(t){var e=this.current.startEvent;if(e&&(t.touches.length!=e.touches.length||t.touches===e.touches)){e.touches=[];for(var i=0,n=t.touches.length;n>i;i++)e.touches.push(s.utils.extend({},t.touches[i]))}var o=t.timeStamp-e.timeStamp,r=t.center.pageX-e.center.pageX,a=t.center.pageY-e.center.pageY,h=s.utils.getVelocity(o,r,a);return s.utils.extend(t,{deltaTime:o,deltaX:r,deltaY:a,velocityX:h.x,velocityY:h.y,distance:s.utils.getDistance(e.center,t.center),angle:s.utils.getAngle(e.center,t.center),direction:s.utils.getDirection(e.center,t.center),scale:s.utils.getScale(e.touches,t.touches),rotation:s.utils.getRotation(e.touches,t.touches),startEvent:e}),t},register:function(t){var e=t.defaults||{};return e[t.name]===i&&(e[t.name]=!0),s.utils.extend(s.defaults,e,!0),t.index=t.index||1e3,this.gestures.push(t),this.gestures.sort(function(t,e){return t.indexe.index?1:0}),this.gestures}},s.gestures=s.gestures||{},s.gestures.Hold={name:"hold",index:10,defaults:{hold_timeout:500,hold_threshold:1},timer:null,handler:function(t,e){switch(t.eventType){case s.EVENT_START:clearTimeout(this.timer),s.detection.current.name=this.name,this.timer=setTimeout(function(){"hold"==s.detection.current.name&&e.trigger("hold",t)},e.options.hold_timeout);break;case s.EVENT_MOVE:t.distance>e.options.hold_threshold&&clearTimeout(this.timer);break;case s.EVENT_END:clearTimeout(this.timer)}}},s.gestures.Tap={name:"tap",index:100,defaults:{tap_max_touchtime:250,tap_max_distance:10,tap_always:!0,doubletap_distance:20,doubletap_interval:300},handler:function(t,e){if(t.eventType==s.EVENT_END){var i=s.detection.previous,n=!1;if(t.deltaTime>e.options.tap_max_touchtime||t.distance>e.options.tap_max_distance)return;i&&"tap"==i.name&&t.timeStamp-i.lastEvent.timeStamp0&&t.touches.length>e.options.swipe_max_touches)return;(t.velocityX>e.options.swipe_velocity||t.velocityY>e.options.swipe_velocity)&&(e.trigger(this.name,t),e.trigger(this.name+t.direction,t))}}},s.gestures.Drag={name:"drag",index:50,defaults:{drag_min_distance:10,drag_max_touches:1,drag_block_horizontal:!1,drag_block_vertical:!1,drag_lock_to_axis:!1,drag_lock_min_distance:25},triggered:!1,handler:function(t,e){if(s.detection.current.name!=this.name&&this.triggered)return e.trigger(this.name+"end",t),void(this.triggered=!1);if(!(e.options.drag_max_touches>0&&t.touches.length>e.options.drag_max_touches))switch(t.eventType){case s.EVENT_START:this.triggered=!1;break;case s.EVENT_MOVE:if(t.distancee.options.transform_min_rotation&&e.trigger("rotate",t),i>e.options.transform_min_scale&&(e.trigger("pinch",t),e.trigger("pinch"+(t.scale<1?"in":"out"),t));break;case s.EVENT_END:this.triggered&&e.trigger(this.name+"end",t),this.triggered=!1}}},s.gestures.Touch={name:"touch",index:-1/0,defaults:{prevent_default:!1,prevent_mouseevents:!1},handler:function(t,e){return e.options.prevent_mouseevents&&t.pointerType==s.POINTER_MOUSE?void t.stopDetect():(e.options.prevent_default&&t.preventDefault(),void(t.eventType==s.EVENT_START&&e.trigger(this.name,t)))}},s.gestures.Release={name:"release",index:1/0,handler:function(t,e){t.eventType==s.EVENT_END&&e.trigger(this.name,t)}},"object"==typeof e&&"object"==typeof e.exports?e.exports=s:(t.Hammer=s,"function"==typeof t.define&&t.define.amd&&t.define("hammer",[],function(){return s}))}(this)},{}],3:[function(e,i){(function(n){function s(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function o(t,e){return function(i){return p(t.call(this,i),e)}}function r(t,e){return function(i){return this.lang().ordinal(t.call(this,i),e)}}function a(){}function h(t){x(t),d(this,t)}function c(t){var e=_(t),i=e.year||0,n=e.month||0,s=e.week||0,o=e.day||0,r=e.hour||0,a=e.minute||0,h=e.second||0,c=e.millisecond||0;this._milliseconds=+c+1e3*h+6e4*a+36e5*r,this._days=+o+7*s,this._months=+n+12*i,this._data={},this._bubble()}function d(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return e.hasOwnProperty("toString")&&(t.toString=e.toString),e.hasOwnProperty("valueOf")&&(t.valueOf=e.valueOf),t}function l(t){var e,i={};for(e in t)t.hasOwnProperty(e)&&_e.hasOwnProperty(e)&&(i[e]=t[e]);return i}function u(t){return 0>t?Math.ceil(t):Math.floor(t)}function p(t,e,i){for(var n=""+Math.abs(t),s=t>=0;n.lengthn;n++)(i&&t[n]!==e[n]||!i&&b(t[n])!==b(e[n]))&&r++;return r+o}function y(t){if(t){var e=t.toLowerCase().replace(/(.)s$/,"$1");t=Xe[t]||Ze[e]||e}return t}function _(t){var e,i,n={};for(i in t)t.hasOwnProperty(i)&&(e=y(i),e&&(n[e]=t[i]));return n}function w(t){var e,i;if(0===t.indexOf("week"))e=7,i="day";else{if(0!==t.indexOf("month"))return;e=12,i="month"}re[t]=function(s,o){var r,a,h=re.fn._lang[t],c=[];if("number"==typeof s&&(o=s,s=n),a=function(t){var e=re().utc().set(i,t);return h.call(re.fn._lang,e,s||"")},null!=o)return a(o);for(r=0;e>r;r++)c.push(a(r));return c}}function b(t){var e=+t,i=0;return 0!==e&&isFinite(e)&&(i=e>=0?Math.floor(e):Math.ceil(e)),i}function S(t,e){return new Date(Date.UTC(t,e+1,0)).getUTCDate()}function E(t){return T(t)?366:365}function T(t){return t%4===0&&t%100!==0||t%400===0}function x(t){var e;t._a&&-2===t._pf.overflow&&(e=t._a[ue]<0||t._a[ue]>11?ue:t._a[pe]<1||t._a[pe]>S(t._a[le],t._a[ue])?pe:t._a[fe]<0||t._a[fe]>23?fe:t._a[ge]<0||t._a[ge]>59?ge:t._a[me]<0||t._a[me]>59?me:t._a[ve]<0||t._a[ve]>999?ve:-1,t._pf._overflowDayOfYear&&(le>e||e>pe)&&(e=pe),t._pf.overflow=e)}function C(t){return null==t._isValid&&(t._isValid=!isNaN(t._d.getTime())&&t._pf.overflow<0&&!t._pf.empty&&!t._pf.invalidMonth&&!t._pf.nullInput&&!t._pf.invalidFormat&&!t._pf.userInvalidated,t._strict&&(t._isValid=t._isValid&&0===t._pf.charsLeftOver&&0===t._pf.unusedTokens.length)),t._isValid}function M(t){return t?t.toLowerCase().replace("_","-"):t}function D(t,e){return e._isUTC?re(t).zone(e._offset||0):re(t).local()}function O(t,e){return e.abbr=t,ye[t]||(ye[t]=new a),ye[t].set(e),ye[t]}function I(t){delete ye[t]}function N(t){var i,n,s,o,r=0,a=function(t){if(!ye[t]&&we)try{e("./lang/"+t)}catch(i){}return ye[t]};if(!t)return re.fn._lang;if(!g(t)){if(n=a(t))return n;t=[t]}for(;r0;){if(n=a(o.slice(0,i).join("-")))return n;if(s&&s.length>=i&&v(o,s,!0)>=i-1)break;i--}r++}return re.fn._lang}function L(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function k(t){var e,i,n=t.match(Te);for(e=0,i=n.length;i>e;e++)n[e]=Je[n[e]]?Je[n[e]]:L(n[e]);return function(s){var o="";for(e=0;i>e;e++)o+=n[e]instanceof Function?n[e].call(s,t):n[e];return o}}function A(t,e){return t.isValid()?(e=z(e,t.lang()),Ke[e]||(Ke[e]=k(e)),Ke[e](t)):t.lang().invalidDate()}function z(t,e){function i(t){return e.longDateFormat(t)||t}var n=5;for(xe.lastIndex=0;n>=0&&xe.test(t);)t=t.replace(xe,i),xe.lastIndex=0,n-=1;return t}function P(t,e){var i,n=e._strict;switch(t){case"DDDD":return Fe;case"YYYY":case"GGGG":case"gggg":return n?Ye:De;case"Y":case"G":case"g":return Re;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return n?He:Oe;case"S":if(n)return ze;case"SS":if(n)return Pe;case"SSS":if(n)return Fe;case"DDD":return Me;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Ne;case"a":case"A":return N(e._l)._meridiemParse;case"X":return Ae;case"Z":case"ZZ":return Le;case"T":return ke;case"SSSS":return Ie;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return n?Pe:Ce;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return Ce;default:return i=new RegExp(B(U(t.replace("\\","")),"i"))}}function F(t){t=t||"";var e=t.match(Le)||[],i=e[e.length-1]||[],n=(i+"").match(Ve)||["-",0,0],s=+(60*n[1])+b(n[2]);return"+"===n[0]?-s:s}function Y(t,e,i){var n,s=i._a;switch(t){case"M":case"MM":null!=e&&(s[ue]=b(e)-1);break;case"MMM":case"MMMM":n=N(i._l).monthsParse(e),null!=n?s[ue]=n:i._pf.invalidMonth=e;break;case"D":case"DD":null!=e&&(s[pe]=b(e));break;case"DDD":case"DDDD":null!=e&&(i._dayOfYear=b(e));break;case"YY":s[le]=b(e)+(b(e)>68?1900:2e3);break;case"YYYY":case"YYYYY":case"YYYYYY":s[le]=b(e);break;case"a":case"A":i._isPm=N(i._l).isPM(e);break;case"H":case"HH":case"h":case"hh":s[fe]=b(e);break;case"m":case"mm":s[ge]=b(e);break;case"s":case"ss":s[me]=b(e);break;case"S":case"SS":case"SSS":case"SSSS":s[ve]=b(1e3*("0."+e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,i._tzm=F(e);break;case"w":case"ww":case"W":case"WW":case"d":case"dd":case"ddd":case"dddd":case"e":case"E":t=t.substr(0,1);case"gg":case"gggg":case"GG":case"GGGG":case"GGGGG":t=t.substr(0,2),e&&(i._w=i._w||{},i._w[t]=e)}}function H(t){var e,i,n,s,o,r,a,h,c,d,l=[];if(!t._d){for(n=W(t),t._w&&null==t._a[pe]&&null==t._a[ue]&&(o=function(e){var i=parseInt(e,10);return e?e.length<3?i>68?1900+i:2e3+i:i:null==t._a[le]?re().weekYear():t._a[le]},r=t._w,null!=r.GG||null!=r.W||null!=r.E?a=te(o(r.GG),r.W||1,r.E,4,1):(h=N(t._l),c=null!=r.d?K(r.d,h):null!=r.e?parseInt(r.e,10)+h._week.dow:0,d=parseInt(r.w,10)||1,null!=r.d&&cE(s)&&(t._pf._overflowDayOfYear=!0),i=Z(s,0,t._dayOfYear),t._a[ue]=i.getUTCMonth(),t._a[pe]=i.getUTCDate()),e=0;3>e&&null==t._a[e];++e)t._a[e]=l[e]=n[e];for(;7>e;e++)t._a[e]=l[e]=null==t._a[e]?2===e?1:0:t._a[e];l[fe]+=b((t._tzm||0)/60),l[ge]+=b((t._tzm||0)%60),t._d=(t._useUTC?Z:X).apply(null,l)}}function R(t){var e;t._d||(e=_(t._i),t._a=[e.year,e.month,e.day,e.hour,e.minute,e.second,e.millisecond],H(t))}function W(t){var e=new Date;return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function j(t){t._a=[],t._pf.empty=!0;var e,i,n,s,o,r=N(t._l),a=""+t._i,h=a.length,c=0;for(n=z(t._f,r).match(Te)||[],e=0;e0&&t._pf.unusedInput.push(o),a=a.slice(a.indexOf(i)+i.length),c+=i.length),Je[s]?(i?t._pf.empty=!1:t._pf.unusedTokens.push(s),Y(s,i,t)):t._strict&&!i&&t._pf.unusedTokens.push(s);t._pf.charsLeftOver=h-c,a.length>0&&t._pf.unusedInput.push(a),t._isPm&&t._a[fe]<12&&(t._a[fe]+=12),t._isPm===!1&&12===t._a[fe]&&(t._a[fe]=0),H(t),x(t)}function U(t){return t.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,i,n,s){return e||i||n||s})}function B(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function V(t){var e,i,n,o,r;if(0===t._f.length)return t._pf.invalidFormat=!0,void(t._d=new Date(0/0));for(o=0;or)&&(n=r,i=e));d(t,i||e)}function G(t){var e,i,n=t._i,s=We.exec(n);if(s){for(t._pf.iso=!0,e=0,i=Ue.length;i>e;e++)if(Ue[e][1].exec(n)){t._f=Ue[e][0]+(s[6]||" ");break}for(e=0,i=Be.length;i>e;e++)if(Be[e][1].exec(n)){t._f+=Be[e][0];break}n.match(Le)&&(t._f+="Z"),j(t)}else t._d=new Date(n)}function q(t){var e=t._i,i=be.exec(e);e===n?t._d=new Date:i?t._d=new Date(+i[1]):"string"==typeof e?G(t):g(e)?(t._a=e.slice(0),H(t)):m(e)?t._d=new Date(+e):"object"==typeof e?R(t):t._d=new Date(e)}function X(t,e,i,n,s,o,r){var a=new Date(t,e,i,n,s,o,r);return 1970>t&&a.setFullYear(t),a}function Z(t){var e=new Date(Date.UTC.apply(null,arguments));return 1970>t&&e.setUTCFullYear(t),e}function K(t,e){if("string"==typeof t)if(isNaN(t)){if(t=e.weekdaysParse(t),"number"!=typeof t)return null}else t=parseInt(t,10);return t}function $(t,e,i,n,s){return s.relativeTime(e||1,!!i,t,n)}function Q(t,e,i){var n=de(Math.abs(t)/1e3),s=de(n/60),o=de(s/60),r=de(o/24),a=de(r/365),h=45>n&&["s",n]||1===s&&["m"]||45>s&&["mm",s]||1===o&&["h"]||22>o&&["hh",o]||1===r&&["d"]||25>=r&&["dd",r]||45>=r&&["M"]||345>r&&["MM",de(r/30)]||1===a&&["y"]||["yy",a];return h[2]=e,h[3]=t>0,h[4]=i,$.apply({},h)}function J(t,e,i){var n,s=i-e,o=i-t.day();return o>s&&(o-=7),s-7>o&&(o+=7),n=re(t).add("d",o),{week:Math.ceil(n.dayOfYear()/7),year:n.year()}}function te(t,e,i,n,s){var o,r,a=Z(t,0,1).getUTCDay();return i=null!=i?i:s,o=s-a+(a>n?7:0)-(s>a?7:0),r=7*(e-1)+(i-s)+o+1,{year:r>0?t:t-1,dayOfYear:r>0?r:E(t-1)+r}}function ee(t){var e=t._i,i=t._f;return null===e?re.invalid({nullInput:!0}):("string"==typeof e&&(t._i=e=N().preparse(e)),re.isMoment(e)?(t=l(e),t._d=new Date(+e._d)):i?g(i)?V(t):j(t):q(t),new h(t))}function ie(t,e){re.fn[t]=re.fn[t+"s"]=function(t){var i=this._isUTC?"UTC":"";return null!=t?(this._d["set"+i+e](t),re.updateOffset(this),this):this._d["get"+i+e]()}}function ne(t){re.duration.fn[t]=function(){return this._data[t]}}function se(t,e){re.duration.fn["as"+t]=function(){return+this/e}}function oe(t){var e=!1,i=re; +"undefined"==typeof ender&&(t?(ce.moment=function(){return!e&&console&&console.warn&&(e=!0,console.warn("Accessing Moment through the global scope is deprecated, and will be removed in an upcoming release.")),i.apply(null,arguments)},d(ce.moment,i)):ce.moment=re)}for(var re,ae,he="2.5.1",ce=this,de=Math.round,le=0,ue=1,pe=2,fe=3,ge=4,me=5,ve=6,ye={},_e={_isAMomentObject:null,_i:null,_f:null,_l:null,_strict:null,_isUTC:null,_offset:null,_pf:null,_lang:null},we="undefined"!=typeof i&&i.exports&&"undefined"!=typeof e,be=/^\/?Date\((\-?\d+)/i,Se=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,Ee=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,Te=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g,xe=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,Ce=/\d\d?/,Me=/\d{1,3}/,De=/\d{1,4}/,Oe=/[+\-]?\d{1,6}/,Ie=/\d+/,Ne=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Le=/Z|[\+\-]\d\d:?\d\d/gi,ke=/T/i,Ae=/[\+\-]?\d+(\.\d{1,3})?/,ze=/\d/,Pe=/\d\d/,Fe=/\d{3}/,Ye=/\d{4}/,He=/[+-]?\d{6}/,Re=/[+-]?\d+/,We=/^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,je="YYYY-MM-DDTHH:mm:ssZ",Ue=[["YYYYYY-MM-DD",/[+-]\d{6}-\d{2}-\d{2}/],["YYYY-MM-DD",/\d{4}-\d{2}-\d{2}/],["GGGG-[W]WW-E",/\d{4}-W\d{2}-\d/],["GGGG-[W]WW",/\d{4}-W\d{2}/],["YYYY-DDD",/\d{4}-\d{3}/]],Be=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d{1,3}/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],Ve=/([\+\-]|\d\d)/gi,Ge="Date|Hours|Minutes|Seconds|Milliseconds".split("|"),qe={Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6},Xe={ms:"millisecond",s:"second",m:"minute",h:"hour",d:"day",D:"date",w:"week",W:"isoWeek",M:"month",y:"year",DDD:"dayOfYear",e:"weekday",E:"isoWeekday",gg:"weekYear",GG:"isoWeekYear"},Ze={dayofyear:"dayOfYear",isoweekday:"isoWeekday",isoweek:"isoWeek",weekyear:"weekYear",isoweekyear:"isoWeekYear"},Ke={},$e="DDD w W M D d".split(" "),Qe="M D H h m s w W".split(" "),Je={M:function(){return this.month()+1},MMM:function(t){return this.lang().monthsShort(this,t)},MMMM:function(t){return this.lang().months(this,t)},D:function(){return this.date()},DDD:function(){return this.dayOfYear()},d:function(){return this.day()},dd:function(t){return this.lang().weekdaysMin(this,t)},ddd:function(t){return this.lang().weekdaysShort(this,t)},dddd:function(t){return this.lang().weekdays(this,t)},w:function(){return this.week()},W:function(){return this.isoWeek()},YY:function(){return p(this.year()%100,2)},YYYY:function(){return p(this.year(),4)},YYYYY:function(){return p(this.year(),5)},YYYYYY:function(){var t=this.year(),e=t>=0?"+":"-";return e+p(Math.abs(t),6)},gg:function(){return p(this.weekYear()%100,2)},gggg:function(){return p(this.weekYear(),4)},ggggg:function(){return p(this.weekYear(),5)},GG:function(){return p(this.isoWeekYear()%100,2)},GGGG:function(){return p(this.isoWeekYear(),4)},GGGGG:function(){return p(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.lang().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.lang().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return b(this.milliseconds()/100)},SS:function(){return p(b(this.milliseconds()/10),2)},SSS:function(){return p(this.milliseconds(),3)},SSSS:function(){return p(this.milliseconds(),3)},Z:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(b(t/60),2)+":"+p(b(t)%60,2)},ZZ:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(b(t/60),2)+p(b(t)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},X:function(){return this.unix()},Q:function(){return this.quarter()}},ti=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"];$e.length;)ae=$e.pop(),Je[ae+"o"]=r(Je[ae],ae);for(;Qe.length;)ae=Qe.pop(),Je[ae+ae]=o(Je[ae],2);for(Je.DDDD=o(Je.DDD,3),d(a.prototype,{set:function(t){var e,i;for(i in t)e=t[i],"function"==typeof e?this[i]=e:this["_"+i]=e},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(t){return this._months[t.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(t){return this._monthsShort[t.month()]},monthsParse:function(t){var e,i,n;for(this._monthsParse||(this._monthsParse=[]),e=0;12>e;e++)if(this._monthsParse[e]||(i=re.utc([2e3,e]),n="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[e]=new RegExp(n.replace(".",""),"i")),this._monthsParse[e].test(t))return e},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(t){return this._weekdays[t.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(t){return this._weekdaysShort[t.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(t){return this._weekdaysMin[t.day()]},weekdaysParse:function(t){var e,i,n;for(this._weekdaysParse||(this._weekdaysParse=[]),e=0;7>e;e++)if(this._weekdaysParse[e]||(i=re([2e3,1]).day(e),n="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[e]=new RegExp(n.replace(".",""),"i")),this._weekdaysParse[e].test(t))return e},_longDateFormat:{LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D YYYY",LLL:"MMMM D YYYY LT",LLLL:"dddd, MMMM D YYYY LT"},longDateFormat:function(t){var e=this._longDateFormat[t];return!e&&this._longDateFormat[t.toUpperCase()]&&(e=this._longDateFormat[t.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t]=e),e},isPM:function(t){return"p"===(t+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(t,e,i){return t>11?i?"pm":"PM":i?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(t,e){var i=this._calendar[t];return"function"==typeof i?i.apply(e):i},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(t,e,i,n){var s=this._relativeTime[i];return"function"==typeof s?s(t,e,i,n):s.replace(/%d/i,t)},pastFuture:function(t,e){var i=this._relativeTime[t>0?"future":"past"];return"function"==typeof i?i(e):i.replace(/%s/i,e)},ordinal:function(t){return this._ordinal.replace("%d",t)},_ordinal:"%d",preparse:function(t){return t},postformat:function(t){return t},week:function(t){return J(t,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),re=function(t,e,i,o){var r;return"boolean"==typeof i&&(o=i,i=n),r={},r._isAMomentObject=!0,r._i=t,r._f=e,r._l=i,r._strict=o,r._isUTC=!1,r._pf=s(),ee(r)},re.utc=function(t,e,i,o){var r;return"boolean"==typeof i&&(o=i,i=n),r={},r._isAMomentObject=!0,r._useUTC=!0,r._isUTC=!0,r._l=i,r._i=t,r._f=e,r._strict=o,r._pf=s(),ee(r).utc()},re.unix=function(t){return re(1e3*t)},re.duration=function(t,e){var i,n,s,o=t,r=null;return re.isDuration(t)?o={ms:t._milliseconds,d:t._days,M:t._months}:"number"==typeof t?(o={},e?o[e]=t:o.milliseconds=t):(r=Se.exec(t))?(i="-"===r[1]?-1:1,o={y:0,d:b(r[pe])*i,h:b(r[fe])*i,m:b(r[ge])*i,s:b(r[me])*i,ms:b(r[ve])*i}):(r=Ee.exec(t))&&(i="-"===r[1]?-1:1,s=function(t){var e=t&&parseFloat(t.replace(",","."));return(isNaN(e)?0:e)*i},o={y:s(r[2]),M:s(r[3]),d:s(r[4]),h:s(r[5]),m:s(r[6]),s:s(r[7]),w:s(r[8])}),n=new c(o),re.isDuration(t)&&t.hasOwnProperty("_lang")&&(n._lang=t._lang),n},re.version=he,re.defaultFormat=je,re.updateOffset=function(){},re.lang=function(t,e){var i;return t?(e?O(M(t),e):null===e?(I(t),t="en"):ye[t]||N(t),i=re.duration.fn._lang=re.fn._lang=N(t),i._abbr):re.fn._lang._abbr},re.langData=function(t){return t&&t._lang&&t._lang._abbr&&(t=t._lang._abbr),N(t)},re.isMoment=function(t){return t instanceof h||null!=t&&t.hasOwnProperty("_isAMomentObject")},re.isDuration=function(t){return t instanceof c},ae=ti.length-1;ae>=0;--ae)w(ti[ae]);for(re.normalizeUnits=function(t){return y(t)},re.invalid=function(t){var e=re.utc(0/0);return null!=t?d(e._pf,t):e._pf.userInvalidated=!0,e},re.parseZone=function(t){return re(t).parseZone()},d(re.fn=h.prototype,{clone:function(){return re(this)},valueOf:function(){return+this._d+6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().lang("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){var t=re(this).utc();return 00:!1},parsingFlags:function(){return d({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(){return this.zone(0)},local:function(){return this.zone(0),this._isUTC=!1,this},format:function(t){var e=A(this,t||re.defaultFormat);return this.lang().postformat(e)},add:function(t,e){var i;return i="string"==typeof t?re.duration(+e,t):re.duration(t,e),f(this,i,1),this},subtract:function(t,e){var i;return i="string"==typeof t?re.duration(+e,t):re.duration(t,e),f(this,i,-1),this},diff:function(t,e,i){var n,s,o=D(t,this),r=6e4*(this.zone()-o.zone());return e=y(e),"year"===e||"month"===e?(n=432e5*(this.daysInMonth()+o.daysInMonth()),s=12*(this.year()-o.year())+(this.month()-o.month()),s+=(this-re(this).startOf("month")-(o-re(o).startOf("month")))/n,s-=6e4*(this.zone()-re(this).startOf("month").zone()-(o.zone()-re(o).startOf("month").zone()))/n,"year"===e&&(s/=12)):(n=this-o,s="second"===e?n/1e3:"minute"===e?n/6e4:"hour"===e?n/36e5:"day"===e?(n-r)/864e5:"week"===e?(n-r)/6048e5:n),i?s:u(s)},from:function(t,e){return re.duration(this.diff(t)).lang(this.lang()._abbr).humanize(!e)},fromNow:function(t){return this.from(re(),t)},calendar:function(){var t=D(re(),this).startOf("day"),e=this.diff(t,"days",!0),i=-6>e?"sameElse":-1>e?"lastWeek":0>e?"lastDay":1>e?"sameDay":2>e?"nextDay":7>e?"nextWeek":"sameElse";return this.format(this.lang().calendar(i,this))},isLeapYear:function(){return T(this.year())},isDST:function(){return this.zone()+re(t).startOf(e)},isBefore:function(t,e){return e="undefined"!=typeof e?e:"millisecond",+this.clone().startOf(e)<+re(t).startOf(e)},isSame:function(t,e){return e=e||"ms",+this.clone().startOf(e)===+D(t,this).startOf(e)},min:function(t){return t=re.apply(null,arguments),this>t?this:t},max:function(t){return t=re.apply(null,arguments),t>this?this:t},zone:function(t){var e=this._offset||0;return null==t?this._isUTC?e:this._d.getTimezoneOffset():("string"==typeof t&&(t=F(t)),Math.abs(t)<16&&(t=60*t),this._offset=t,this._isUTC=!0,e!==t&&f(this,re.duration(e-t,"m"),1,!0),this)},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.zone(this._tzm):"string"==typeof this._i&&this.zone(this._i),this},hasAlignedHourOffset:function(t){return t=t?re(t).zone():0,(this.zone()-t)%60===0},daysInMonth:function(){return S(this.year(),this.month())},dayOfYear:function(t){var e=de((re(this).startOf("day")-re(this).startOf("year"))/864e5)+1;return null==t?e:this.add("d",t-e)},quarter:function(){return Math.ceil((this.month()+1)/3)},weekYear:function(t){var e=J(this,this.lang()._week.dow,this.lang()._week.doy).year;return null==t?e:this.add("y",t-e)},isoWeekYear:function(t){var e=J(this,1,4).year;return null==t?e:this.add("y",t-e)},week:function(t){var e=this.lang().week(this);return null==t?e:this.add("d",7*(t-e))},isoWeek:function(t){var e=J(this,1,4).week;return null==t?e:this.add("d",7*(t-e))},weekday:function(t){var e=(this.day()+7-this.lang()._week.dow)%7;return null==t?e:this.add("d",t-e)},isoWeekday:function(t){return null==t?this.day()||7:this.day(this.day()%7?t:t-7)},get:function(t){return t=y(t),this[t]()},set:function(t,e){return t=y(t),"function"==typeof this[t]&&this[t](e),this},lang:function(t){return t===n?this._lang:(this._lang=N(t),this)}}),ae=0;ae-1?!1:"INPUT"==i||"SELECT"==i||"TEXTAREA"==i||e.contentEditable&&"true"==e.contentEditable}function o(t,e){return t.sort().join(",")===e.sort().join(",")}function r(t){t=t||{};var e,i=!1;for(e in M)t[e]?i=!0:M[e]=0;i||(O=!1)}function a(t,e,i,n,s){var r,a,h=[];if(!x[t])return[];for("keyup"==i&&u(t)&&(e=[t]),r=0;r95&&112>t||b.hasOwnProperty(t)&&(_[b[t]]=t)}return _}function g(t,e,i){return i||(i=f()[t]?"keydown":"keypress"),"keypress"==i&&e.length&&(i="keydown"),i}function m(t,e,i,s){M[t]=0,s||(s=g(e[0],[]));var o,a=function(){O=s,++M[t],p()},h=function(t){c(i,t),"keyup"!==s&&(D=n(t)),setTimeout(r,10)};for(o=0;o1)return m(t,c,e,i);for(h="+"===t?["+"]:t.split("+"),o=0;o":".","?":"/","|":"\\"},T={option:"alt",command:"meta","return":"enter",escape:"esc"},x={},C={},M={},D=!1,O=!1,I=1;20>I;++I)b[111+I]="f"+I;for(I=0;9>=I;++I)b[I+96]=I;i(document,"keypress",l),i(document,"keydown",l),i(document,"keyup",l);var N={bind:function(t,e,i){return y(t instanceof Array?t:[t],e,i),C[t+":"+i]=e,this},unbind:function(t,e){return C[t+":"+e]&&(delete C[t+":"+e],this.bind(t,function(){},e)),this},trigger:function(t,e){return C[t+":"+e](),this},reset:function(){return x={},C={},this}};e.exports=N},{}]},{},[1])(1)}); \ No newline at end of file diff --git a/examples/graph/02_random_nodes.html b/examples/graph/02_random_nodes.html index 3b88450b..f5a05364 100755 --- a/examples/graph/02_random_nodes.html +++ b/examples/graph/02_random_nodes.html @@ -94,19 +94,8 @@ graph = new vis.Graph(container, data, options); // add event listeners -<<<<<<< HEAD -<<<<<<< HEAD - vis.events.addListener(graph, 'select', function(params) { - document.getElementById('selection').innerHTML = - 'Selection: ' + JSON.stringify(graph.getSelection()); -======= graph.on('select', function(params) { document.getElementById('selection').innerHTML = 'Selection: ' + params.nodes; ->>>>>>> develop -======= - graph.on('select', function(params) { - document.getElementById('selection').innerHTML = 'Selection: ' + params.nodes; ->>>>>>> origin/gh-pages }); } diff --git a/examples/graph/18_fully_random_nodes_clustering.html b/examples/graph/18_fully_random_nodes_clustering.html index 4aa91c91..b2440b76 100644 --- a/examples/graph/18_fully_random_nodes_clustering.html +++ b/examples/graph/18_fully_random_nodes_clustering.html @@ -64,19 +64,8 @@ graph = new vis.Graph(container, data, options); // add event listeners -<<<<<<< HEAD -<<<<<<< HEAD - vis.events.addListener(graph, 'select', function(params) { - document.getElementById('selection').innerHTML = - 'Selection: ' + JSON.stringify(graph.getSelection()); -======= graph.on('select', function(params) { document.getElementById('selection').innerHTML = 'Selection: ' + params.nodes; ->>>>>>> develop -======= - graph.on('select', function(params) { - document.getElementById('selection').innerHTML = 'Selection: ' + params.nodes; ->>>>>>> origin/gh-pages }); } diff --git a/examples/graph/19_scale_free_graph_clustering.html b/examples/graph/19_scale_free_graph_clustering.html index 9c9c0aa9..cced805b 100644 --- a/examples/graph/19_scale_free_graph_clustering.html +++ b/examples/graph/19_scale_free_graph_clustering.html @@ -100,19 +100,8 @@ graph = new vis.Graph(container, data, options); // add event listeners -<<<<<<< HEAD -<<<<<<< HEAD - vis.events.addListener(graph, 'select', function(params) { - document.getElementById('selection').innerHTML = - 'Selection: ' + JSON.stringify(graph.getSelection()); -======= graph.on('select', function(params) { document.getElementById('selection').innerHTML = 'Selection: ' + params.nodes; ->>>>>>> develop -======= - graph.on('select', function(params) { - document.getElementById('selection').innerHTML = 'Selection: ' + params.nodes; ->>>>>>> origin/gh-pages }); } diff --git a/examples/graph/20_navigation.html b/examples/graph/20_navigation.html index cc9ed615..5bfaff77 100644 --- a/examples/graph/20_navigation.html +++ b/examples/graph/20_navigation.html @@ -31,7 +31,6 @@ div.table_description { width:100px; } - diff --git a/examples/graph/20_UI_example.html b/examples/graph/21_data_manipulation.html similarity index 58% rename from examples/graph/20_UI_example.html rename to examples/graph/21_data_manipulation.html index ee8f8394..d2c3ba7b 100644 --- a/examples/graph/20_UI_example.html +++ b/examples/graph/21_data_manipulation.html @@ -1,7 +1,7 @@ - Graph | Random nodes + Graph | Navigation @@ -177,78 +204,76 @@ nodes: nodes, edges: edges }; - /* + /* + var options = { + nodes: { + shape: 'circle' + }, + edges: { + length: 50 + }, + stabilize: false + }; + */ var options = { - nodes: { - shape: 'circle' - }, edges: { length: 50 }, - stabilize: false + stabilize: false, + clustering:true, + navigation: true, + keyboard: true, + dataManipulationToolbar: true }; - */ - var options = { - edges: { - length: 50 - }, - stabilize: false, - navigationUI: { - enabled: true - }, - keyboardNavigation: { - enabled: true - } - }; graph = new vis.Graph(container, data, options); // add event listeners - vis.events.addListener(graph, 'select', function(params) { - document.getElementById('selection').innerHTML = - 'Selection: ' + JSON.stringify(graph.getSelection()); + graph.on('select', function(params) { + document.getElementById('selection').innerHTML = 'Selection: ' + params.nodes; }); } -

    UI - User Interface and Keyboad Navigation

    +

    Navigation controls and keyboad navigation

    - This example is the same as example 2, except for the UI that has been activated. The UI icons are described below.

    -
    Icons:
    Keyboard shortcuts:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Icons:
    Keyboard shortcuts:
    Up arrow
    Down arrow
    Left arrow
    Right arrow
    =
    [
    Page up
    -
    ]
    Page down
    None
    Description:
    Move up
    Move down
    Move left
    Move right
    Zoom in
    Zoom out
    Zoom extends
    -
    - Apart from clicking the icons, you can also navigate using the keyboard. The buttons are in table above. - Zoom Extends changes the zoom and position of the camera to encompass all visible nodes. + This example is the same as example 2, except for the navigation controls that has been activated. The navigation controls are described below.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Icons:
    Keyboard shortcuts:
    Up arrow
    Down arrow
    Left arrow
    Right arrow
    =
    [
    Page up
    -
    ]
    Page down
    None
    Description:
    Move up
    Move down
    Move left
    Move right
    Zoom in
    Zoom out
    Zoom extends
    +
    + Apart from clicking the icons, you can also navigate using the keyboard. The buttons are in table above. + Zoom Extends changes the zoom and position of the camera to encompass all visible nodes. diff --git a/examples/graph/index.html b/examples/graph/index.html index d48f7c87..53720b5b 100644 --- a/examples/graph/index.html +++ b/examples/graph/index.html @@ -32,6 +32,7 @@

    18_fully_random_nodes_clustering.html

    19_scale_free_graph_clustering.html

    20_navigation.html

    +

    21_data_manipulation.html

    graphviz_gallery.html

    diff --git a/src/graph/Graph.js b/src/graph/Graph.js index f39a7dbb..408ab33c 100644 --- a/src/graph/Graph.js +++ b/src/graph/Graph.js @@ -94,6 +94,9 @@ function Graph (container, data, options) { enabled: false, speed: {x: 10, y: 10, zoom: 0.02} }, + dataManipulationToolbar: { + enabled: false + }, minVelocity: 2, // px/s maxIterations: 1000 // maximum number of iteration to stabilize }; @@ -110,7 +113,6 @@ function Graph (container, data, options) { this.yIncrement = 0; this.zoomIncrement = 0; - // create a frame and canvas this._create(); @@ -123,18 +125,9 @@ function Graph (container, data, options) { // load the selection system. (mandatory, required by Graph) this._loadSelectionSystem(); - // load the data manipulation system - this._loadManipulationSystem(); - // apply options this.setOptions(options); - - - - - - // other vars var graph = this; this.freezeSimulation = false;// freeze the simulation @@ -145,6 +138,7 @@ function Graph (container, data, options) { this.canvasTopLeft = {"x": 0,"y": 0}; // coordinates of the top left of the canvas. they will be set during _redraw. this.canvasBottomRight = {"x": 0,"y": 0}; // coordinates of the bottom right of the canvas. they will be set during _redraw + this.pointerPosition = {"x": 0,"y": 0}; // coordinates of the bottom right of the canvas. they will be set during _redraw this.areaCenter = {}; // object with x and y elements used for determining the center of the zoom action this.scale = 1; // defining the global scale variable in the constructor @@ -427,6 +421,17 @@ Graph.prototype.setOptions = function (options) { this.constants.keyboard.enabled = false; } + if (options.dataManipulationToolbar) { + this.constants.dataManipulationToolbar.enabled = true; + for (var prop in options.dataManipulationToolbar) { + if (options.dataManipulationToolbar.hasOwnProperty(prop)) { + this.constants.dataManipulationToolbar[prop] = options.dataManipulationToolbar[prop]; + } + } + } + else if (options.dataManipulationToolbar !== undefined) { + this.constants.dataManipulationToolbar.enabled = false; + } // TODO: work out these options and document them if (options.edges) { @@ -488,16 +493,18 @@ Graph.prototype.setOptions = function (options) { } } - this.setSize(this.width, this.height); - this._setTranslation(this.frame.clientWidth / 2, this.frame.clientHeight / 2); - this._setScale(1); - // load the navigation system. this._loadNavigationControls(); + // load the data manipulation system + this._loadManipulationSystem(); + // bind keys. If disabled, this will not do anything; this._createKeyBinds(); + this.setSize(this.width, this.height); + this._setTranslation(this.frame.clientWidth / 2, this.frame.clientHeight / 2); + this._setScale(1); this._redraw(); }; @@ -628,6 +635,10 @@ Graph.prototype._createKeyBinds = function() { this.mousetrap.bind("pagedown",this._zoomOut.bind(me),"keydown"); this.mousetrap.bind("pagedown",this._stopZoom.bind(me), "keyup"); } + + if (this.constants.dataManipulationToolbar.enabled == true) { + this.mousetrap.bind("escape",this._createManipulatorBar.bind(me)); + } } /** @@ -776,6 +787,7 @@ Graph.prototype._onDragEnd = function () { */ Graph.prototype._onTap = function (event) { var pointer = this._getPointer(event.gesture.touches[0]); + this.pointerPosition = pointer; this._handleTap(pointer); }; @@ -798,6 +810,7 @@ Graph.prototype._onDoubleTap = function (event) { */ Graph.prototype._onHold = function (event) { var pointer = this._getPointer(event.gesture.touches[0]); + this.pointerPosition = pointer; this._handleOnHold(pointer); }; @@ -1126,7 +1139,9 @@ Graph.prototype.setSize = function(width, height) { this.frame.canvas.width = this.frame.canvas.clientWidth; this.frame.canvas.height = this.frame.canvas.clientHeight; - this.manipulationDiv.style.width = this.frame.canvas.clientWidth; + if (this.manipulationDiv !== undefined) { + this.manipulationDiv.style.width = this.frame.canvas.clientWidth; + } if (this.constants.navigation.enabled == true) { this._relocateNavigation(); @@ -1731,6 +1746,7 @@ Graph.prototype._calculateForces = function() { // we loop from i over all but the last entree in the array // j loops from i+1 to the last. This way we do not double count any of the indices, nor i == j + var a_base = (-2/3); var b = 4/3; for (i = 0; i < this.nodeIndices.length-1; i++) { node1 = nodes[this.nodeIndices[i]]; for (j = i+1; j < this.nodeIndices.length; j++) { @@ -1743,6 +1759,7 @@ Graph.prototype._calculateForces = function() { // clusters have a larger region of influence minimumDistance = (clusterSize == 0) ? this.constants.nodes.distance : (this.constants.nodes.distance * (1 + clusterSize * this.constants.clustering.distanceAmplification)); + var a = a_base / minimumDistance; if (distance < 2*minimumDistance) { // at 2.0 * the minimum distance, the force is 0.000045 angle = Math.atan2(dy, dx); @@ -1753,13 +1770,13 @@ Graph.prototype._calculateForces = function() { // TODO: correct factor for repulsing force //repulsingForce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force //repulsingForce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force - repulsingForce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)); // TODO: customize the repulsing force + //repulsingForce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)); // TODO: customize the repulsing force + repulsingForce = a * distance + b; // TODO: test the approximation of the function above } // amplify the repulsion for clusters. repulsingForce *= (clusterSize == 0) ? 1 : 1 + clusterSize * this.constants.clustering.forceAmplification; repulsingForce *= this.forceFactor; - fx = Math.cos(angle) * repulsingForce; fy = Math.sin(angle) * repulsingForce ; @@ -2070,21 +2087,28 @@ Graph.prototype._loadSelectionSystem = function() { * @private */ Graph.prototype._loadManipulationSystem = function() { - // load the manipulator HTML elements. All styling done in css. - this.manipulationDiv = document.createElement('div'); - this.manipulationDiv.className = 'graph-manipulationDiv'; - this.containerElement.insertBefore(this.manipulationDiv, this.frame); + // reset global variables -- these are used by the selection of nodes and edges. + this.blockConnectingEdgeSelection = false; + this.forceAppendSelection = false - // load the manipulation functions - for (var mixinFunction in manipulationMixin) { - if (manipulationMixin.hasOwnProperty(mixinFunction)) { - Graph.prototype[mixinFunction] = manipulationMixin[mixinFunction]; + if (this.constants.dataManipulationToolbar.enabled == true) { + // load the manipulator HTML elements. All styling done in css. + if (this.manipulationDiv === undefined) { + this.manipulationDiv = document.createElement('div'); + this.manipulationDiv.className = 'graph-manipulationDiv'; + this.containerElement.insertBefore(this.manipulationDiv, this.frame); + } + // load the manipulation functions + for (var mixinFunction in manipulationMixin) { + if (manipulationMixin.hasOwnProperty(mixinFunction)) { + Graph.prototype[mixinFunction] = manipulationMixin[mixinFunction]; + } } - } - - this._createManipulatorBar(); + // create the manipulator toolbar + this._createManipulatorBar(); + } } /** diff --git a/src/graph/SelectionMixin.js b/src/graph/SelectionMixin.js index 9d24703b..7252ac15 100644 --- a/src/graph/SelectionMixin.js +++ b/src/graph/SelectionMixin.js @@ -186,7 +186,7 @@ var SelectionMixin = { /** * Remove a single option from selection. * - * @param obj + * @param {Object} obj * @private */ _removeFromSelection : function(obj) { @@ -219,6 +219,89 @@ var SelectionMixin = { } }, + /** + * Unselect all clusters. The selectionObj is useful for this. + * + * @param {Boolean} [doNotTrigger] | ignore trigger + * @private + */ + _unselectClusters : function(doNotTrigger) { + if (doNotTrigger === undefined) { + doNotTrigger = false; + } + + for (var objectId in this.selectionObj) { + if (this.selectionObj.hasOwnProperty(objectId)) { + if (this.selectionObj[objectId] instanceof Node) { + if (this.selectionObj[objectId].clusterSize > 1) { + this.selectionObj[objectId].unselect(); + this._removeFromSelection(this.selectionObj[objectId]); + } + } + } + } + + if (doNotTrigger == false) { + this._trigger('select', { + nodes: this.getSelection() + }); + } + }, + + + /** + * return the number of selected nodes + * + * @returns {number} + * @private + */ + _getSelectedNodeCount : function() { + var count = 0; + for (var objectId in this.selectionObj) { + if (this.selectionObj.hasOwnProperty(objectId)) { + if (this.selectionObj[objectId] instanceof Node) { + count += 1; + } + } + } + return count; + }, + + + /** + * return the number of selected edges + * + * @returns {number} + * @private + */ + _getSelectedEdgeCount : function() { + var count = 0; + for (var objectId in this.selectionObj) { + if (this.selectionObj.hasOwnProperty(objectId)) { + if (this.selectionObj[objectId] instanceof Edge) { + count += 1; + } + } + } + return count; + }, + + + /** + * return the number of selected objects. + * + * @returns {number} + * @private + */ + _getSelectedObjectCount : function() { + var count = 0; + for (var objectId in this.selectionObj) { + if (this.selectionObj.hasOwnProperty(objectId)) { + count += 1; + } + } + return count; + }, /** * Check if anything is selected @@ -235,6 +318,13 @@ var SelectionMixin = { return true; }, + + /** + * check if one of the selected nodes is a cluster. + * + * @returns {boolean} + * @private + */ _clusterInSelection : function() { for(var objectId in this.selectionObj) { if(this.selectionObj.hasOwnProperty(objectId)) { @@ -293,14 +383,14 @@ var SelectionMixin = { doNotTrigger = false; } - if (this._selectionIsEmpty() == false && append == false) { + if (this._selectionIsEmpty() == false && append == false && this.forceAppendSelection == false) { this._unselectAll(true); } if (object.selected == false) { object.select(); this._addToSelection(object); - if (object instanceof Node) { + if (object instanceof Node && this.blockConnectingEdgeSelection == false) { this._selectConnectedEdges(object); } } @@ -326,6 +416,7 @@ var SelectionMixin = { */ _handleTouch : function(pointer) { if (this.constants.navigation.enabled == true) { + this.pointerPosition = pointer; var node = this._getNavigationNodeAt(pointer); if (node != null) { if (this[node.triggerFunction] !== undefined) { @@ -484,7 +575,6 @@ var SelectionMixin = { } this._selectObject(node,true,true); } - this.redraw(); }, @@ -505,20 +595,9 @@ var SelectionMixin = { if (!this.edges.hasOwnProperty(objectId)) { delete this.selectionObj[objectId]; } - changed = true; } - this.selection = []; } } - - if (changed && (triggerSelect == true || triggerSelect == undefined)) { - // fire the select event - this._trigger('select', { - nodes: this.getSelection() - }); - } - - return changed; } } diff --git a/src/graph/img/acceptDeleteIcon.png b/src/graph/img/acceptDeleteIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..02a062852c2a8ea7610b64f5d6f79ce4953c3b42 GIT binary patch literal 20675 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

    |#V-x46+1BId1SnF`o)!|KGJUGs&sOwUB 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 REZGm4F~`{$=NWC^^ItUJ)cF7a literal 0 HcmV?d00001 diff --git a/src/graph/img/deleteIcon.png b/src/graph/img/deleteIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..540256479106ed2f9263ec5df22fd7f0c75231e4 GIT binary patch literal 20981 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 literal 0 HcmV?d00001 diff --git a/src/graph/img/editIcon.png b/src/graph/img/editIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..494d0f00c0717e7a970848fc0cb518e9e620077a GIT binary patch literal 21016 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 literal 0 HcmV?d00001 diff --git a/src/graph/manipulationMixin.js b/src/graph/manipulationMixin.js index 9ba8f20f..9f1d6ad0 100644 --- a/src/graph/manipulationMixin.js +++ b/src/graph/manipulationMixin.js @@ -4,7 +4,31 @@ var manipulationMixin = { + /** + * clears the toolbar div element of children + * + * @private + */ + _clearManipulatorBar : function() { + while (this.manipulationDiv.hasChildNodes()) { + this.manipulationDiv.removeChild(this.manipulationDiv.firstChild); + } + }, + + + /** + * main function, creates the main toolbar. Removes functions bound to the select event. Binds all the buttons of the toolbar. + * + * @private + */ _createManipulatorBar : function() { + // remove bound functions + this.off('select', this.boundFunction); + + // reset global variables + this.blockConnectingEdgeSelection = false; + this.forceAppendSelection = false + while (this.manipulationDiv.hasChildNodes()) { this.manipulationDiv.removeChild(this.manipulationDiv.firstChild); } @@ -12,6 +36,8 @@ var manipulationMixin = { this.manipulationDiv.innerHTML = "" + "Add Node" + "

    " + + "Edit Selected" + + "
    " + "Connect Node" + "
    " + "Delete selected"; @@ -19,17 +45,26 @@ var manipulationMixin = { // bind the icons var addButton = document.getElementById("manipulate-addNode"); addButton.onclick = this._createAddToolbar.bind(this); + var editButton = document.getElementById("manipulate-editNode"); + editButton.onclick = this._createEditToolbar.bind(this); var connectButton = document.getElementById("manipulate-connectNode"); connectButton.onclick = this._createConnectToolbar.bind(this); var deleteButton = document.getElementById("manipulate-delete"); - deleteButton.onclick = this._deleteSelected.bind(this); + deleteButton.onclick = this._createDeletionToolbar.bind(this); }, + + /** + * Create the toolbar for adding Nodes + * + * @private + */ _createAddToolbar : function() { - while (this.manipulationDiv.hasChildNodes()) { - this.manipulationDiv.removeChild(this.manipulationDiv.firstChild); - } + // clear the toolbar + this._clearManipulatorBar(); + this.off('select', this.boundFunction); + // create the toolbar contents this.manipulationDiv.innerHTML = "" + "Back" + "
    " + @@ -39,69 +74,369 @@ var manipulationMixin = { var backButton = document.getElementById("manipulate-back"); backButton.onclick = this._createManipulatorBar.bind(this); - - var me = this; - events.addListener(me, 'select', me._addNode.bind(me)); + // we use the boundFunction so we can reference it when we unbind it from the "select" event. + this.boundFunction = this._addNode.bind(this); + this.on('select', this.boundFunction); }, - _createConnectToolbar : function() { - while (this.manipulationDiv.hasChildNodes()) { - this.manipulationDiv.removeChild(this.manipulationDiv.firstChild); + /** + * Create the toolbar to edit nodes or edges. + * TODO: edges not implemented yet, unsure what to edit. + * + * @private + */ + _createEditToolbar : function() { + // clear the toolbar + this.blockConnectingEdgeSelection = false; + this._clearManipulatorBar(); + this.off('select', this.boundFunction); + + + var message = ""; + if (this._selectionIsEmpty()) { + message = "Select a node or edge to edit."; } - var message = "hello"; - if (!this._selectionIsEmpty()) { - message = "Select the node you want to connect to other nodes"; + else { + if (this._getSelectedObjectCount() > 1) { + message = "Select a single node or edge to edit." + this._unselectAll(true); + } + else { + if (this._clusterInSelection()) { + message = "You cannot edit a cluster." + this._unselectAll(true); + } + else { + if (this._getSelectedNodeCount() > 0) { // the selected item is a node + this._createEditNodeToolbar(); + } + else { // the selected item is an edge + this._createEditEdgeToolbar(); + } + } + } + } + + if (message != "") { + this.blockConnectingEdgeSelection = true; + // create the toolbar contents + this.manipulationDiv.innerHTML = "" + + "Back" + + "
    " + + ""+message+""; + + // bind the icon + var backButton = document.getElementById("manipulate-back"); + backButton.onclick = this._createManipulatorBar.bind(this); + + // we use the boundFunction so we can reference it when we unbind it from the "select" event. + this.boundFunction = this._createEditToolbar.bind(this); + this.on('select', this.boundFunction); } + }, + + + /** + * Create the toolbar to edit the selected node. The label and the color can be changed. Other colors are derived from the chosen color. + * TODO: change shape or group? + * + * @private + */ + _createEditNodeToolbar : function() { + // clear the toolbar + this.blockConnectingEdgeSelection = false; + this._clearManipulatorBar(); + this.off('select', this.boundFunction); + + var editObject = this._getEditObject(); + + // create the toolbar contents + this.manipulationDiv.innerHTML = "" + + "Cancel" + + "
    " + + "label: " + + "
    " + + "color: " + + "
    " + + "" + + // bind the icon + var backButton = document.getElementById("manipulate-back"); + backButton.onclick = this._createManipulatorBar.bind(this); + var saveButton = document.getElementById("manipulator-obj-save"); + saveButton.onclick = this._saveNodeData.bind(this); + + // we use the boundFunction so we can reference it when we unbind it from the "select" event. + this.boundFunction = this._createManipulatorBar.bind(this); + this.on('select', this.boundFunction); + }, + + + /** + * save the changes in the node data + * + * @private + */ + _saveNodeData : function() { + var editObjectId = this._getEditObject().id; + var label = document.getElementById('manipulator-obj-label').value; + + var definedColor = document.getElementById('manipulator-obj-color').value; + var hsv = util.hexToHSV(definedColor); + + var lighterColorHSV = {h:hsv.h,s:hsv.s * 0.45,v:Math.min(1,hsv.v * 1.05)}; + var darkerColorHSV = {h:hsv.h,s:Math.min(1,hsv.v * 1.25),v:hsv.v*0.6}; + var darkerColorHex = util.HSVToHex(darkerColorHSV.h ,darkerColorHSV.h ,darkerColorHSV.v); + var lighterColorHex = util.HSVToHex(lighterColorHSV.h,lighterColorHSV.s,lighterColorHSV.v); + + var updatedSettings = {id:editObjectId, + label: label, + color: { + background:definedColor, + border:darkerColorHex, + highlight: { + background:lighterColorHex, + border:darkerColorHex + } + }}; + this.nodesData.update(updatedSettings); + this._createManipulatorBar(); + }, + + + /** + * creating the toolbar to edit edges. + * + * @private + */ + _createEditEdgeToolbar : function() { + // clear the toolbar + this.blockConnectingEdgeSelection = false; + this._clearManipulatorBar(); + this.off('select', this.boundFunction); + + // create the toolbar contents + this.manipulationDiv.innerHTML = "" + + "Back" + + "
    " + + "Currently only nodes can be edited."; + + // bind the icon + var backButton = document.getElementById("manipulate-back"); + backButton.onclick = this._createManipulatorBar.bind(this); + + // we use the boundFunction so we can reference it when we unbind it from the "select" event. + this.boundFunction = this._createManipulatorBar.bind(this); + this.on('select', this.boundFunction); + }, + + + /** + * create the toolbar to connect nodes + * + * @private + */ + _createConnectToolbar : function() { + // clear the toolbar + this._clearManipulatorBar(); + this.off('select', this.boundFunction); + + this._unselectAll(); + this.forceAppendSelection = false; + this.blockConnectingEdgeSelection = true; this.manipulationDiv.innerHTML = "" + "Back" + "
    " + - ""+message+""; + "Select the node you want to connect to other nodes."; // bind the icon var backButton = document.getElementById("manipulate-back"); backButton.onclick = this._createManipulatorBar.bind(this); - var self = this; - events.addListener(self, 'select', function(params) {alert(self.selectForConnect)}); + // we use the boundFunction so we can reference it when we unbind it from the "select" event. + this.boundFunction = this._handleConnect.bind(this); + this.on('select', this.boundFunction); + }, + + + /** + * create the toolbar for deleting selected objects. User has to be sure. + * + * @private + */ + _createDeletionToolbar : function() { + // clear the toolbar + this._clearManipulatorBar(); + this.off('select', this.boundFunction); + + if (this._selectionIsEmpty()) { + this.manipulationDiv.innerHTML = "" + + "Cannot delete an empty selection."; + var graph = this; + window.setTimeout (function() {graph._createManipulatorBar()},1500); + } + else { + this.manipulationDiv.innerHTML = "" + + "Back" + + "
    " + + "Are you sure? This cannot be undone." + + "
    " + + "Yes."; + + // bind the buttons + var backButton = document.getElementById("manipulate-back"); + backButton.onclick = this._createManipulatorBar.bind(this); + var acceptDeleteButton = document.getElementById("manipulate-acceptDelete"); + acceptDeleteButton.onclick = this._deleteSelected.bind(this); + + // we use the boundFunction so we can reference it when we unbind it from the "select" event. + this.boundFunction = this._createManipulatorBar.bind(this); + this.on('select', this.boundFunction); + } }, - _continueConnect : function() { + + /** + * the function bound to the selection event. It checks if you want to connect a cluster and changes the description + * to walk the user through the process. + * + * @private + */ + _handleConnect : function() { + this.forceAppendSelection = false; if (this._clusterInSelection()) { - this._unselectAll(); - this._createConnectToolbar("Select the node you want to connect (Clusters are not allowed)."); - return true; + this._unselectClusters(true); + if (!this._selectionIsEmpty()) { + this._setManipulationMessage("You cannot connect a node to a cluster."); + this.forceAppendSelection = true; + } + else { + this._setManipulationMessage("You cannot connect anything to a cluster."); + } } else if (!this._selectionIsEmpty()) { - this._connectNodes(); - return true; + if (this._getSelectedNodeCount() == 2) { + this._connectNodes(); + this._restoreSourceNode(); + this._setManipulationMessage("Click on another node you want to connect this node to or go back."); + } + else { + this._setManipulationMessage("Click on the node you want to connect this node."); + this._setSourceNode(); + this.forceAppendSelection = true; + } } else { - var manipulatorLabel = document.getElementById['manipolatorLabel']; - manipulatorLabel - return false; + this._setManipulationMessage("Select the node you want to connect to other nodes."); } }, + /** + * returns the object that is selected + * + * @returns {*} + * @private + */ + _getEditObject : function() { + for(var objectId in this.selectionObj) { + if(this.selectionObj.hasOwnProperty(objectId)) { + return this.selectionObj[objectId]; + } + } + return null; + }, + + + /** + * stores the first selected node for the connecting process as the source node. This allows us to remember the direction + * + * @private + */ + _setSourceNode : function() { + for(var objectId in this.selectionObj) { + if(this.selectionObj.hasOwnProperty(objectId)) { + if (this.selectionObj[objectId] instanceof Node) { + this.manipulationSourceNode = this.selectionObj[objectId]; + } + } + } + }, + + + /** + * gets the node the source connects to. + * + * @returns {*} + * @private + */ + _getTargetNode : function() { + for(var objectId in this.selectionObj) { + if(this.selectionObj.hasOwnProperty(objectId)) { + if (this.selectionObj[objectId] instanceof Node) { + if (this.manipulationSourceNode.id != this.selectionObj[objectId].id) { + return this.selectionObj[objectId]; + } + } + } + } + return null; + }, + + + /** + * restore the selection back to only the sourcenode + * + * @private + */ + _restoreSourceNode : function() { + this._unselectAll(true); + this._selectObject(this.manipulationSourceNode); + }, + + + /** + * change the description message on the toolbar + * + * @param message + * @private + */ + _setManipulationMessage : function(message) { + var messageSpan = document.getElementById('manipulatorLabel'); + messageSpan.innerHTML = message; + }, + + /** * Adds a node on the specified location * * @param {Object} pointer */ - _addNode : function(pointer) { - console.log("HERE",this) + _addNode : function() { if (this._selectionIsEmpty()) { - var positionObject = this._pointerToPositionObject(pointer); + var positionObject = this._pointerToPositionObject(this.pointerPosition); + this.createNodeOnClick = true; this.nodesData.add({id:util.randomUUID(),x:positionObject.left,y:positionObject.top,label:"new",fixed:false}); + this.createNodeOnClick = false; this.moving = true; this.start(); } }, + + /** + * connect two nodes with a new edge. + * + * @private + */ _connectNodes : function() { - console.log(this.selectionObj) + var targetNode = this._getTargetNode(); + var sourceNode = this.manipulationSourceNode; + this.edgesData.add({from:sourceNode.id, to:targetNode.id}) + this.moving = true; + this.start(); }, @@ -116,7 +451,8 @@ var manipulationMixin = { var selectedEdges = this.getSelectedEdges(); this._removeEdges(selectedEdges); this._removeNodes(selectedNodes); - this._redraw(); + this.moving = true; + this.start(); } else { alert("Clusters cannot be deleted.") @@ -124,5 +460,4 @@ var manipulationMixin = { } - } \ No newline at end of file diff --git a/src/util.js b/src/util.js index 9036691e..8495d68c 100644 --- a/src/util.js +++ b/src/util.js @@ -671,3 +671,157 @@ util.option.asElement = function (value, defaultValue) { return value || defaultValue || null; }; + + + +util.GiveDec = function GiveDec(Hex) +{ + if(Hex == "A") + Value = 10; + else + if(Hex == "B") + Value = 11; + else + if(Hex == "C") + Value = 12; + else + if(Hex == "D") + Value = 13; + else + if(Hex == "E") + Value = 14; + else + if(Hex == "F") + Value = 15; + else + Value = eval(Hex) + return Value; +} + +util.GiveHex = function GiveHex(Dec) +{ + if(Dec == 10) + Value = "A"; + else + if(Dec == 11) + Value = "B"; + else + if(Dec == 12) + Value = "C"; + else + if(Dec == 13) + Value = "D"; + else + if(Dec == 14) + Value = "E"; + else + if(Dec == 15) + Value = "F"; + else + Value = "" + Dec; + return Value; +} + +/** + * http://www.yellowpipe.com/yis/tools/hex-to-rgb/color-converter.php + * + * @param {String} hex + * @returns {{r: *, g: *, b: *}} + */ +util.hexToRGB = function hexToRGB(hex) { + hex = hex.replace("#","").toUpperCase(); + + var a = util.GiveDec(hex.substring(0, 1)); + var b = util.GiveDec(hex.substring(1, 2)); + var c = util.GiveDec(hex.substring(2, 3)); + var d = util.GiveDec(hex.substring(3, 4)); + var e = util.GiveDec(hex.substring(4, 5)); + var f = util.GiveDec(hex.substring(5, 6)); + + var r = (a * 16) + b; + var g = (c * 16) + d; + var b = (e * 16) + f; + + return {r:r,g:g,b:b}; +}; + +util.RGBToHex = function RGBToHex(red,green,blue) { + var a = util.GiveHex(Math.floor(red / 16)); + var b = util.GiveHex(red % 16); + var c = util.GiveHex(Math.floor(green / 16)); + var d = util.GiveHex(green % 16); + var e = util.GiveHex(Math.floor(blue / 16)); + var f = util.GiveHex(blue % 16); + + var hex = a + b + c + d + e + f; + return "#" + hex; +}; + + +/** + * http://www.javascripter.net/faq/rgb2hsv.htm + * + * @param red + * @param green + * @param blue + * @returns {*} + * @constructor + */ +util.RGBToHSV = function RGBToHSV (red,green,blue) { + red=red/255; green=green/255; blue=blue/255; + var minRGB = Math.min(red,Math.min(green,blue)); + var maxRGB = Math.max(red,Math.max(green,blue)); + + // Black-gray-white + if (minRGB == maxRGB) { + return {h:0,s:0,v:minRGB}; + } + + // Colors other than black-gray-white: + var d = (red==minRGB) ? green-blue : ((blue==minRGB) ? red-green : blue-red); + var h = (red==minRGB) ? 3 : ((blue==minRGB) ? 1 : 5); + var hue = 60*(h - d/(maxRGB - minRGB))/360; + var saturation = (maxRGB - minRGB)/maxRGB; + var value = maxRGB; + return {h:hue,s:saturation,v:value}; +}; + + +/** + * https://gist.github.com/mjijackson/5311256 + * @param hue + * @param saturation + * @param value + * @returns {{r: number, g: number, b: number}} + * @constructor + */ +util.HSVToRGB = function HSVToRGB(h, s, v) { + var r, g, b; + + var i = Math.floor(h * 6); + var f = h * 6 - i; + var p = v * (1 - s); + var q = v * (1 - f * s); + var t = v * (1 - (1 - f) * s); + + switch (i % 6) { + case 0: r = v, g = t, b = p; break; + case 1: r = q, g = v, b = p; break; + case 2: r = p, g = v, b = t; break; + case 3: r = p, g = q, b = v; break; + case 4: r = t, g = p, b = v; break; + case 5: r = v, g = p, b = q; break; + } + + return {r:Math.floor(r * 255), g:Math.floor(g * 255), b:Math.floor(b * 255) }; +}; + +util.HSVToHex = function HSVToHex(h,s,v) { + var rgb = util.HSVToRGB(h,s,v); + return util.RGBToHex(rgb.r,rgb.g,rgb.b); +} + +util.hexToHSV = function hexToHSV(hex) { + var rgb = util.hexToRGB(hex); + return util.RGBToHSV(rgb.r,rgb.g,rgb.b); +} \ No newline at end of file From ac3ea3c11f9c76d7ad079d8c4c7d2ed6fedb0c47 Mon Sep 17 00:00:00 2001 From: josdejong Date: Thu, 6 Feb 2014 15:41:46 +0100 Subject: [PATCH 31/52] Integrated an emitter-component as Emitter mixin --- dist/vis.js | 322 +++++++++++++++++++++++++++++++-------- package.json | 1 + src/module/imports.js | 3 +- src/timeline/Timeline.js | 73 +++------ 4 files changed, 285 insertions(+), 114 deletions(-) diff --git a/dist/vis.js b/dist/vis.js index e96a323e..4a3db05e 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -5,7 +5,7 @@ * A dynamic, browser-based visualization library. * * @version 0.5.0-SNAPSHOT - * @date 2014-02-05 + * @date 2014-02-06 * * @license * Copyright (C) 2011-2014 Almende B.V, http://almende.com @@ -31,6 +31,7 @@ // If not available there, load via require. var moment = (typeof window !== 'undefined') && window['moment'] || require('moment'); +var Emitter = require('emitter-component'); var Hammer; if (typeof window !== 'undefined') { @@ -55,8 +56,6 @@ else { } - - // Internet Explorer 8 and older does not support Array.indexOf, so we define // it here in that case. // http://soledadpenades.com/2007/05/17/arrayindexof-in-internet-explorer/ @@ -5352,6 +5351,15 @@ function ItemSet(parent, depends, options) { this.stack = new Stack(this, Object.create(this.options)); this.conversion = null; + + // event listeners for items + // TODO: implement event listeners + // TODO: event listeners must be removed when the ItemSet is deleted + //this.on('dragstart', this._onDragStart.bind(this)); + //this.on('drag', this._onDrag.bind(this)); + //this.on('dragend', this._onDragEnd.bind(this)); + + // TODO: ItemSet should also attach event listeners for rangechange and rangechanged, like timeaxis } @@ -5904,6 +5912,65 @@ ItemSet.prototype.toScreen = function toScreen(time) { return (time.valueOf() - conversion.offset) * conversion.scale; }; +// global (private) object to store drag params +var touchParams = {}; + +/** + * Start dragging the selected events + * @param {Event} event + * @private + */ +// TODO: move this function to ItemSet +ItemSet.prototype._onDragStart = function (event) { + var item = this._itemFromTarget(event); + + if (item && item.selected) { + touchParams.items = [item]; + //touchParams.items = this.getSelection(); // TODO: use the current selection + touchParams.itemsLeft = touchParams.items.map(function (item) { + return item.left; + }); + console.log('_onDragStart', touchParams) + event.stopPropagation(); + } +}; + +/** + * Drag selected items + * @param {Event} event + * @private + */ +// TODO: move this function to ItemSet +ItemSet.prototype._onDrag = function (event) { + if (touchParams.items) { + var deltaX = event.gesture.deltaX; + + touchParams.items.forEach(function (item, i) { + item.left = touchParams.itemsLeft[i] + deltaX; + item.reposition(); + }); + + event.stopPropagation(); + } +}; + +/** + * End of dragging selected items + * @param {Event} event + * @private + */ +// TODO: move this function to ItemSet +ItemSet.prototype._onDragEnd = function (event) { + if (touchParams.items) { + // actually apply the new locations + + touchParams.items = null; + + event.stopPropagation(); + } +}; + + /** * @constructor Item * @param {ItemSet} parent @@ -5980,11 +6047,11 @@ Item.prototype.reflow = function reflow() { /** * Return the items width - * @return {Integer} width + * @return {Number} width */ Item.prototype.getWidth = function getWidth() { return this.width; -} +}; /** * @constructor ItemBox @@ -7551,7 +7618,7 @@ GroupSet.prototype._toQueue = function _toQueue(ids, action) { /** * Create a timeline visualization * @param {HTMLElement} container - * @param {vis.DataSet | Array | DataTable} [items] + * @param {vis.DataSet | Array | google.visualization.DataTable} [items] * @param {Object} [options] See Timeline.setOptions for the available options. * @constructor */ @@ -7595,6 +7662,13 @@ function Timeline (container, items, options) { this.rootPanel = new RootPanel(container, rootOptions); this.controller.add(this.rootPanel); + // single select (or unselect) when tapping an item + // TODO: implement ctrl+click + this.rootPanel.on('tap', this._onSelectItem.bind(this)); + + // multi select when holding mouse/touch, or on ctrl+click + this.rootPanel.on('hold', this._onMultiSelectItem.bind(this)); + // item panel var itemOptions = Object.create(this.options); itemOptions.left = function () { @@ -7634,26 +7708,20 @@ function Timeline (container, items, options) { // TODO: reckon with options moveable and zoomable // TODO: put the listeners in setOptions, be able to dynamically change with options moveable and zoomable + // TODO: enable moving again this.range.subscribe(this.rootPanel, 'move', 'horizontal'); this.range.subscribe(this.rootPanel, 'zoom', 'horizontal'); this.range.on('rangechange', function (properties) { var force = true; me.controller.requestReflow(force); - me._trigger('rangechange', properties); + me.emit('rangechange', properties); }); this.range.on('rangechanged', function (properties) { var force = true; me.controller.requestReflow(force); - me._trigger('rangechanged', properties); + me.emit('rangechanged', properties); }); - // single select (or unselect) when tapping an item - // TODO: implement ctrl+click - this.rootPanel.on('tap', this._onSelectItem.bind(this)); - - // multi select when holding mouse/touch, or on ctrl+click - this.rootPanel.on('hold', this._onMultiSelectItem.bind(this)); - // time axis var timeaxisOptions = Object.create(rootOptions); timeaxisOptions.range = this.range; @@ -7690,6 +7758,9 @@ function Timeline (container, items, options) { } } +// extend Timeline with the Emitter mixin +Emitter(Timeline.prototype); + /** * Set options * @param {Object} options TODO: describe the available options @@ -7723,7 +7794,7 @@ Timeline.prototype.getCustomTime = function() { /** * Set items - * @param {vis.DataSet | Array | DataTable | null} items + * @param {vis.DataSet | Array | google.visualization.DataTable | null} items */ Timeline.prototype.setItems = function(items) { var initialLoad = (this.itemsData == null); @@ -7784,7 +7855,7 @@ Timeline.prototype.setItems = function(items) { /** * Set groups - * @param {vis.DataSet | Array | DataTable} groups + * @param {vis.DataSet | Array | google.visualization.DataTable} groups */ Timeline.prototype.setGroups = function(groups) { var me = this; @@ -7917,56 +7988,19 @@ Timeline.prototype.getSelection = function getSelection() { return this.content ? this.content.getSelection() : []; }; -/** - * Add event listener - * @param {String} event Event name. Available events: - * 'rangechange', 'rangechanged', 'select' - * @param {function} callback Callback function, invoked as callback(properties) - * where properties is an optional object containing - * event specific properties. - */ -Timeline.prototype.on = function on (event, callback) { - var available = ['rangechange', 'rangechanged', 'select']; - - if (available.indexOf(event) == -1) { - throw new Error('Unknown event "' + event + '". Choose from ' + available.join()); - } - - events.addListener(this, event, callback); -}; - -/** - * Remove an event listener - * @param {String} event Event name - * @param {function} callback Callback function - */ -Timeline.prototype.off = function off (event, callback) { - events.removeListener(this, event, callback); -}; - -/** - * Trigger an event - * @param {String} event Event name, available events: 'rangechange', - * 'rangechanged', 'select' - * @param {Object} [properties] Event specific properties - * @private - */ -Timeline.prototype._trigger = function _trigger(event, properties) { - events.trigger(this, event, properties || {}); -}; - /** * Handle selecting/deselecting an item when tapping it * @param {Event} event * @private */ +// TODO: move this function to ItemSet Timeline.prototype._onSelectItem = function (event) { var item = this._itemFromTarget(event); var selection = item ? [item.id] : []; this.setSelection(selection); - this._trigger('select', { + this.emit('select', { items: this.getSelection() }); @@ -7978,6 +8012,7 @@ Timeline.prototype._onSelectItem = function (event) { * @param {Event} event * @private */ +// TODO: move this function to ItemSet Timeline.prototype._onMultiSelectItem = function (event) { var selection, item = this._itemFromTarget(event); @@ -7999,7 +8034,7 @@ Timeline.prototype._onMultiSelectItem = function (event) { } this.setSelection(selection); - this._trigger('select', { + this.emit('select', { items: this.getSelection() }); @@ -8013,6 +8048,7 @@ Timeline.prototype._onMultiSelectItem = function (event) { * @return {Item | null| item * @private */ +// TODO: move this function to ItemSet Timeline.prototype._itemFromTarget = function _itemFromTarget (event) { var target = event.target; while (target) { @@ -16088,7 +16124,173 @@ if (typeof window !== 'undefined') { } -},{"hammerjs":2,"moment":3,"mousetrap":4}],2:[function(require,module,exports){ +},{"emitter-component":2,"hammerjs":3,"moment":4,"mousetrap":5}],2:[function(require,module,exports){ + +/** + * Expose `Emitter`. + */ + +module.exports = Emitter; + +/** + * Initialize a new `Emitter`. + * + * @api public + */ + +function Emitter(obj) { + if (obj) return mixin(obj); +}; + +/** + * Mixin the emitter properties. + * + * @param {Object} obj + * @return {Object} + * @api private + */ + +function mixin(obj) { + for (var key in Emitter.prototype) { + obj[key] = Emitter.prototype[key]; + } + return obj; +} + +/** + * Listen on the given `event` with `fn`. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public + */ + +Emitter.prototype.on = +Emitter.prototype.addEventListener = function(event, fn){ + this._callbacks = this._callbacks || {}; + (this._callbacks[event] = this._callbacks[event] || []) + .push(fn); + return this; +}; + +/** + * Adds an `event` listener that will be invoked a single + * time then automatically removed. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public + */ + +Emitter.prototype.once = function(event, fn){ + var self = this; + this._callbacks = this._callbacks || {}; + + function on() { + self.off(event, on); + fn.apply(this, arguments); + } + + on.fn = fn; + this.on(event, on); + return this; +}; + +/** + * Remove the given callback for `event` or all + * registered callbacks. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public + */ + +Emitter.prototype.off = +Emitter.prototype.removeListener = +Emitter.prototype.removeAllListeners = +Emitter.prototype.removeEventListener = function(event, fn){ + this._callbacks = this._callbacks || {}; + + // all + if (0 == arguments.length) { + this._callbacks = {}; + return this; + } + + // specific event + var callbacks = this._callbacks[event]; + if (!callbacks) return this; + + // remove all handlers + if (1 == arguments.length) { + delete this._callbacks[event]; + return this; + } + + // remove specific handler + var cb; + for (var i = 0; i < callbacks.length; i++) { + cb = callbacks[i]; + if (cb === fn || cb.fn === fn) { + callbacks.splice(i, 1); + break; + } + } + return this; +}; + +/** + * Emit `event` with the given args. + * + * @param {String} event + * @param {Mixed} ... + * @return {Emitter} + */ + +Emitter.prototype.emit = function(event){ + this._callbacks = this._callbacks || {}; + var args = [].slice.call(arguments, 1) + , callbacks = this._callbacks[event]; + + if (callbacks) { + callbacks = callbacks.slice(0); + for (var i = 0, len = callbacks.length; i < len; ++i) { + callbacks[i].apply(this, args); + } + } + + return this; +}; + +/** + * Return array of callbacks for `event`. + * + * @param {String} event + * @return {Array} + * @api public + */ + +Emitter.prototype.listeners = function(event){ + this._callbacks = this._callbacks || {}; + return this._callbacks[event] || []; +}; + +/** + * Check if this emitter has `event` handlers. + * + * @param {String} event + * @return {Boolean} + * @api public + */ + +Emitter.prototype.hasListeners = function(event){ + return !! this.listeners(event).length; +}; + +},{}],3:[function(require,module,exports){ /*! Hammer.JS - v1.0.5 - 2013-04-07 * http://eightmedia.github.com/hammer.js * @@ -17510,7 +17712,7 @@ else { } } })(this); -},{}],3:[function(require,module,exports){ +},{}],4:[function(require,module,exports){ //! moment.js //! version : 2.5.1 //! authors : Tim Wood, Iskren Chernev, Moment.js contributors @@ -19912,7 +20114,7 @@ else { } }).call(this); -},{}],4:[function(require,module,exports){ +},{}],5:[function(require,module,exports){ /** * Copyright 2012 Craig Campbell * diff --git a/package.json b/package.json index 73365fad..943db31a 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "moment": "latest", "hammerjs": "1.0.5", "mousetrap": "latest", + "emitter-component": "latest", "node-watch": "latest" } } diff --git a/src/module/imports.js b/src/module/imports.js index ea8d8c92..bda6f792 100644 --- a/src/module/imports.js +++ b/src/module/imports.js @@ -6,6 +6,7 @@ // If not available there, load via require. var moment = (typeof window !== 'undefined') && window['moment'] || require('moment'); +var Emitter = require('emitter-component'); var Hammer; if (typeof window !== 'undefined') { @@ -28,5 +29,3 @@ else { throw Error('mouseTrap is only available in a browser, not in node.js.'); } } - - diff --git a/src/timeline/Timeline.js b/src/timeline/Timeline.js index 38c19fae..3d2ff97c 100644 --- a/src/timeline/Timeline.js +++ b/src/timeline/Timeline.js @@ -1,7 +1,7 @@ /** * Create a timeline visualization * @param {HTMLElement} container - * @param {vis.DataSet | Array | DataTable} [items] + * @param {vis.DataSet | Array | google.visualization.DataTable} [items] * @param {Object} [options] See Timeline.setOptions for the available options. * @constructor */ @@ -45,6 +45,13 @@ function Timeline (container, items, options) { this.rootPanel = new RootPanel(container, rootOptions); this.controller.add(this.rootPanel); + // single select (or unselect) when tapping an item + // TODO: implement ctrl+click + this.rootPanel.on('tap', this._onSelectItem.bind(this)); + + // multi select when holding mouse/touch, or on ctrl+click + this.rootPanel.on('hold', this._onMultiSelectItem.bind(this)); + // item panel var itemOptions = Object.create(this.options); itemOptions.left = function () { @@ -84,26 +91,20 @@ function Timeline (container, items, options) { // TODO: reckon with options moveable and zoomable // TODO: put the listeners in setOptions, be able to dynamically change with options moveable and zoomable + // TODO: enable moving again this.range.subscribe(this.rootPanel, 'move', 'horizontal'); this.range.subscribe(this.rootPanel, 'zoom', 'horizontal'); this.range.on('rangechange', function (properties) { var force = true; me.controller.requestReflow(force); - me._trigger('rangechange', properties); + me.emit('rangechange', properties); }); this.range.on('rangechanged', function (properties) { var force = true; me.controller.requestReflow(force); - me._trigger('rangechanged', properties); + me.emit('rangechanged', properties); }); - // single select (or unselect) when tapping an item - // TODO: implement ctrl+click - this.rootPanel.on('tap', this._onSelectItem.bind(this)); - - // multi select when holding mouse/touch, or on ctrl+click - this.rootPanel.on('hold', this._onMultiSelectItem.bind(this)); - // time axis var timeaxisOptions = Object.create(rootOptions); timeaxisOptions.range = this.range; @@ -140,6 +141,9 @@ function Timeline (container, items, options) { } } +// extend Timeline with the Emitter mixin +Emitter(Timeline.prototype); + /** * Set options * @param {Object} options TODO: describe the available options @@ -173,7 +177,7 @@ Timeline.prototype.getCustomTime = function() { /** * Set items - * @param {vis.DataSet | Array | DataTable | null} items + * @param {vis.DataSet | Array | google.visualization.DataTable | null} items */ Timeline.prototype.setItems = function(items) { var initialLoad = (this.itemsData == null); @@ -234,7 +238,7 @@ Timeline.prototype.setItems = function(items) { /** * Set groups - * @param {vis.DataSet | Array | DataTable} groups + * @param {vis.DataSet | Array | google.visualization.DataTable} groups */ Timeline.prototype.setGroups = function(groups) { var me = this; @@ -367,56 +371,19 @@ Timeline.prototype.getSelection = function getSelection() { return this.content ? this.content.getSelection() : []; }; -/** - * Add event listener - * @param {String} event Event name. Available events: - * 'rangechange', 'rangechanged', 'select' - * @param {function} callback Callback function, invoked as callback(properties) - * where properties is an optional object containing - * event specific properties. - */ -Timeline.prototype.on = function on (event, callback) { - var available = ['rangechange', 'rangechanged', 'select']; - - if (available.indexOf(event) == -1) { - throw new Error('Unknown event "' + event + '". Choose from ' + available.join()); - } - - events.addListener(this, event, callback); -}; - -/** - * Remove an event listener - * @param {String} event Event name - * @param {function} callback Callback function - */ -Timeline.prototype.off = function off (event, callback) { - events.removeListener(this, event, callback); -}; - -/** - * Trigger an event - * @param {String} event Event name, available events: 'rangechange', - * 'rangechanged', 'select' - * @param {Object} [properties] Event specific properties - * @private - */ -Timeline.prototype._trigger = function _trigger(event, properties) { - events.trigger(this, event, properties || {}); -}; - /** * Handle selecting/deselecting an item when tapping it * @param {Event} event * @private */ +// TODO: move this function to ItemSet Timeline.prototype._onSelectItem = function (event) { var item = this._itemFromTarget(event); var selection = item ? [item.id] : []; this.setSelection(selection); - this._trigger('select', { + this.emit('select', { items: this.getSelection() }); @@ -428,6 +395,7 @@ Timeline.prototype._onSelectItem = function (event) { * @param {Event} event * @private */ +// TODO: move this function to ItemSet Timeline.prototype._onMultiSelectItem = function (event) { var selection, item = this._itemFromTarget(event); @@ -449,7 +417,7 @@ Timeline.prototype._onMultiSelectItem = function (event) { } this.setSelection(selection); - this._trigger('select', { + this.emit('select', { items: this.getSelection() }); @@ -463,6 +431,7 @@ Timeline.prototype._onMultiSelectItem = function (event) { * @return {Item | null| item * @private */ +// TODO: move this function to ItemSet Timeline.prototype._itemFromTarget = function _itemFromTarget (event) { var target = event.target; while (target) { From 9e68b81d319c356af7052da6745569983f152411 Mon Sep 17 00:00:00 2001 From: josdejong Date: Thu, 6 Feb 2014 17:28:43 +0100 Subject: [PATCH 32/52] Start with implementing an event bus to propagate events between the components of the Timeline --- dist/vis.js | 242 ++++++++++++++++++++-------- src/timeline/Controller.js | 11 +- src/timeline/Range.js | 19 +-- src/timeline/Timeline.js | 8 +- src/timeline/component/Component.js | 17 ++ src/timeline/component/ItemSet.js | 133 +++++++++++++++ src/timeline/component/RootPanel.js | 103 ++++++------ src/timeline/component/item/Item.js | 4 +- 8 files changed, 403 insertions(+), 134 deletions(-) diff --git a/dist/vis.js b/dist/vis.js index 4a3db05e..462af842 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -3254,26 +3254,27 @@ function validateDirection (direction) { /** * Add listeners for mouse and touch events to the component - * @param {Component} component + * @param {Controller} controller + * @param {Component} component Should be a rootpanel * @param {String} event Available events: 'move', 'zoom' * @param {String} direction Available directions: 'horizontal', 'vertical' */ -Range.prototype.subscribe = function (component, event, direction) { +Range.prototype.subscribe = function (controller, component, event, direction) { var me = this; if (event == 'move') { // drag start listener - component.on('dragstart', function (event) { + controller.on('dragstart', function (event) { me._onDragStart(event, component); }); // drag listener - component.on('drag', function (event) { + controller.on('drag', function (event) { me._onDrag(event, component, direction); }); // drag end listener - component.on('dragend', function (event) { + controller.on('dragend', function (event) { me._onDragEnd(event, component); }); } @@ -3282,14 +3283,14 @@ Range.prototype.subscribe = function (component, event, direction) { function mousewheel (event) { me._onMouseWheel(event, component, direction); } - component.on('mousewheel', mousewheel); - component.on('DOMMouseScroll', mousewheel); // For FF + controller.on('mousewheel', mousewheel); + controller.on('DOMMouseScroll', mousewheel); // For FF // pinch - component.on('touch', function (event) { + controller.on('touch', function (event) { me._onTouch(); }); - component.on('pinch', function (event) { + controller.on('pinch', function (event) { me._onPinch(event, component, direction); }); } @@ -3771,6 +3772,9 @@ function Controller () { this.reflowTimer = undefined; } +// Extend controller with Emitter mixin +Emitter(Controller.prototype); + /** * Add a component to the controller * @param {Component} component @@ -3786,7 +3790,7 @@ Controller.prototype.add = function add(component) { } // add the component - component.controller = this; + component.setController(this); this.components[component.id] = component; }; @@ -3798,13 +3802,17 @@ Controller.prototype.remove = function remove(component) { var id; for (id in this.components) { if (this.components.hasOwnProperty(id)) { - if (id == component || this.components[id] == component) { + if (id == component || this.components[id] === component) { break; } } } if (id) { + // unregister the controller (gives the component the ability to unregister + // event listeners and clean up other stuff) + this.components[id].setController(null); + delete this.components[id]; } }; @@ -3988,6 +3996,23 @@ Component.prototype.getOption = function getOption(name) { return value; }; +/** + * Set controller for this component, or remove current controller by passing + * null as parameter value. + * @param {Controller | null} controller + */ +Component.prototype.setController = function setController (controller) { + this.controller = controller || null; +}; + +/** + * Get controller of this component + * @return {Controller} controller + */ +Component.prototype.getController = function getController () { + return this.controller; +}; + /** * Get the container element of the component, which can be used by a child to * add its own widgets. Not all components do have a container for childs, in @@ -4205,12 +4230,29 @@ function RootPanel(container, options) { this.id = util.randomUUID(); this.container = container; + // create functions to be used as DOM event listeners + var me = this; + this.hammer = null; + + // create listeners for all interesting events, these events will be emitted + // via the controller + var events = [ + 'touch', 'pinch', 'tap', 'hold', + 'dragstart', 'drag', 'dragend', + 'mousewheel', 'DOMMouseScroll' // DOMMouseScroll is for Firefox + ]; + this.listeners = {}; + events.forEach(function (event) { + me.listeners[event] = function () { + var args = [event].concat(Array.prototype.slice.call(arguments, 0)); + me.controller.emit.apply(me.controller, args); + }; + }); + this.options = options || {}; this.defaultOptions = { autoResize: true }; - - this.listeners = {}; // event listeners } RootPanel.prototype = new Panel(); @@ -4243,6 +4285,8 @@ RootPanel.prototype.repaint = function () { this.frame = frame; + this._registerListeners(); + changed += 1; } if (!frame.parentNode) { @@ -4264,7 +4308,6 @@ RootPanel.prototype.repaint = function () { changed += update(frame.style, 'width', asSize(options.width, '100%')); changed += update(frame.style, 'height', asSize(options.height, '100%')); - this._updateEventEmitters(); this._updateWatch(); return (changed > 0); @@ -4353,59 +4396,52 @@ RootPanel.prototype._unwatch = function () { }; /** - * Event handler - * @param {String} event name of the event, for example 'click', 'mousemove' - * @param {function} callback callback handler, invoked with the raw HTML Event - * as parameter. + * Set controller for this component, or remove current controller by passing + * null as parameter value. + * @param {Controller | null} controller */ -RootPanel.prototype.on = function (event, callback) { - // register the listener at this component - var arr = this.listeners[event]; - if (!arr) { - arr = []; - this.listeners[event] = arr; - } - arr.push(callback); +RootPanel.prototype.setController = function setController (controller) { + this.controller = controller || null; - this._updateEventEmitters(); + if (this.controller) { + this._registerListeners(); + } + else { + this._unregisterListeners(); + } }; /** - * Update the event listeners for all event emitters + * Register event emitters emitted by the rootpanel * @private */ -RootPanel.prototype._updateEventEmitters = function () { - if (this.listeners) { - var me = this; - util.forEach(this.listeners, function (listeners, event) { - if (!me.emitters) { - me.emitters = {}; - } - if (!(event in me.emitters)) { - // create event - var frame = me.frame; - if (frame) { - //console.log('Created a listener for event ' + event + ' on component ' + me.id); // TODO: cleanup logging - var callback = function(event) { - listeners.forEach(function (listener) { - // TODO: filter on event target! - listener(event); - }); - }; - me.emitters[event] = callback; +RootPanel.prototype._registerListeners = function () { + if (this.frame && this.controller && !this.hammer) { + this.hammer = Hammer(this.frame, { + prevent_default: true + }); - if (!me.hammer) { - me.hammer = Hammer(frame, { - prevent_default: true - }); - } - me.hammer.on(event, callback); - } + for (var event in this.listeners) { + if (this.listeners.hasOwnProperty(event)) { + this.hammer.on(event, this.listeners[event]); } - }); + } + } +}; - // TODO: be able to delete event listeners - // TODO: be able to move event listeners to a parent when available +/** + * Unregister event emitters from the rootpanel + * @private + */ +RootPanel.prototype._unregisterListeners = function () { + if (this.hammer) { + for (var event in this.listeners) { + if (this.listeners.hasOwnProperty(event)) { + this.hammer.off(event, this.listeners[event]); + } + } + + this.hammer = null; } }; @@ -5308,6 +5344,13 @@ function ItemSet(parent, depends, options) { this.parent = parent; this.depends = depends; + // event listeners + this.listeners = { + dragstart: this._onDragStart.bind(this), + drag: this._onDrag.bind(this), + dragend: this._onDragEnd.bind(this) + }; + // one options object is shared by this itemset and all its items this.options = options || {}; this.defaultOptions = { @@ -5351,15 +5394,6 @@ function ItemSet(parent, depends, options) { this.stack = new Stack(this, Object.create(this.options)); this.conversion = null; - - // event listeners for items - // TODO: implement event listeners - // TODO: event listeners must be removed when the ItemSet is deleted - //this.on('dragstart', this._onDragStart.bind(this)); - //this.on('drag', this._onDrag.bind(this)); - //this.on('dragend', this._onDragEnd.bind(this)); - - // TODO: ItemSet should also attach event listeners for rangechange and rangechanged, like timeaxis } @@ -5400,6 +5434,55 @@ ItemSet.types = { */ ItemSet.prototype.setOptions = Component.prototype.setOptions; + + +/** + * Set controller for this component + * @param {Controller | null} controller + */ +ItemSet.prototype.setController = function setController (controller) { + var event; + + // unregister old event listeners + if (this.controller) { + for (event in this.listeners) { + if (this.listeners.hasOwnProperty(event)) { + this.controller.off(event, this.listeners[event]); + } + } + } + + this.controller = controller || null; + + // register new event listeners + if (this.controller) { + for (event in this.listeners) { + if (this.listeners.hasOwnProperty(event)) { + this.controller.on(event, this.listeners[event]); + } + } + } +}; + +// attach event listeners for dragging items to the controller +(function (me) { + var _controller = null; + var _onDragStart = null; + var _onDrag = null; + var _onDragEnd = null; + + Object.defineProperty(me, 'controller', { + get: function () { + return _controller; + }, + + set: function (controller) { + + } + }); +}) (this); + + /** * Set range (start and end). * @param {Range | Object} range A Range or an object containing start and end. @@ -5923,7 +6006,7 @@ var touchParams = {}; // TODO: move this function to ItemSet ItemSet.prototype._onDragStart = function (event) { var item = this._itemFromTarget(event); - +console.log('_onDragStart', event) if (item && item.selected) { touchParams.items = [item]; //touchParams.items = this.getSelection(); // TODO: use the current selection @@ -5970,7 +6053,24 @@ ItemSet.prototype._onDragEnd = function (event) { } }; +/** + * Find an item from an event target: + * searches for the attribute 'timeline-item' in the event target's element tree + * @param {Event} event + * @return {Item | null| item + * @private + */ +ItemSet.prototype._itemFromTarget = function _itemFromTarget (event) { + var target = event.target; + while (target) { + if (target.hasOwnProperty('timeline-item')) { + return target['timeline-item']; + } + target = target.parentNode; + } + return null; +}; /** * @constructor Item * @param {ItemSet} parent @@ -7664,10 +7764,10 @@ function Timeline (container, items, options) { // single select (or unselect) when tapping an item // TODO: implement ctrl+click - this.rootPanel.on('tap', this._onSelectItem.bind(this)); + this.controller.on('tap', this._onSelectItem.bind(this)); // multi select when holding mouse/touch, or on ctrl+click - this.rootPanel.on('hold', this._onMultiSelectItem.bind(this)); + this.controller.on('hold', this._onMultiSelectItem.bind(this)); // item panel var itemOptions = Object.create(this.options); @@ -7709,8 +7809,8 @@ function Timeline (container, items, options) { // TODO: reckon with options moveable and zoomable // TODO: put the listeners in setOptions, be able to dynamically change with options moveable and zoomable // TODO: enable moving again - this.range.subscribe(this.rootPanel, 'move', 'horizontal'); - this.range.subscribe(this.rootPanel, 'zoom', 'horizontal'); + this.range.subscribe(this.controller, this.rootPanel, 'move', 'horizontal'); + this.range.subscribe(this.controller, this.rootPanel, 'zoom', 'horizontal'); this.range.on('rangechange', function (properties) { var force = true; me.controller.requestReflow(force); diff --git a/src/timeline/Controller.js b/src/timeline/Controller.js index 185d341b..8ba7e563 100644 --- a/src/timeline/Controller.js +++ b/src/timeline/Controller.js @@ -11,6 +11,9 @@ function Controller () { this.reflowTimer = undefined; } +// Extend controller with Emitter mixin +Emitter(Controller.prototype); + /** * Add a component to the controller * @param {Component} component @@ -26,7 +29,7 @@ Controller.prototype.add = function add(component) { } // add the component - component.controller = this; + component.setController(this); this.components[component.id] = component; }; @@ -38,13 +41,17 @@ Controller.prototype.remove = function remove(component) { var id; for (id in this.components) { if (this.components.hasOwnProperty(id)) { - if (id == component || this.components[id] == component) { + if (id == component || this.components[id] === component) { break; } } } if (id) { + // unregister the controller (gives the component the ability to unregister + // event listeners and clean up other stuff) + this.components[id].setController(null); + delete this.components[id]; } }; diff --git a/src/timeline/Range.js b/src/timeline/Range.js index 70c9083d..f3e04390 100644 --- a/src/timeline/Range.js +++ b/src/timeline/Range.js @@ -48,26 +48,27 @@ function validateDirection (direction) { /** * Add listeners for mouse and touch events to the component - * @param {Component} component + * @param {Controller} controller + * @param {Component} component Should be a rootpanel * @param {String} event Available events: 'move', 'zoom' * @param {String} direction Available directions: 'horizontal', 'vertical' */ -Range.prototype.subscribe = function (component, event, direction) { +Range.prototype.subscribe = function (controller, component, event, direction) { var me = this; if (event == 'move') { // drag start listener - component.on('dragstart', function (event) { + controller.on('dragstart', function (event) { me._onDragStart(event, component); }); // drag listener - component.on('drag', function (event) { + controller.on('drag', function (event) { me._onDrag(event, component, direction); }); // drag end listener - component.on('dragend', function (event) { + controller.on('dragend', function (event) { me._onDragEnd(event, component); }); } @@ -76,14 +77,14 @@ Range.prototype.subscribe = function (component, event, direction) { function mousewheel (event) { me._onMouseWheel(event, component, direction); } - component.on('mousewheel', mousewheel); - component.on('DOMMouseScroll', mousewheel); // For FF + controller.on('mousewheel', mousewheel); + controller.on('DOMMouseScroll', mousewheel); // For FF // pinch - component.on('touch', function (event) { + controller.on('touch', function (event) { me._onTouch(); }); - component.on('pinch', function (event) { + controller.on('pinch', function (event) { me._onPinch(event, component, direction); }); } diff --git a/src/timeline/Timeline.js b/src/timeline/Timeline.js index 3d2ff97c..3b9efc4a 100644 --- a/src/timeline/Timeline.js +++ b/src/timeline/Timeline.js @@ -47,10 +47,10 @@ function Timeline (container, items, options) { // single select (or unselect) when tapping an item // TODO: implement ctrl+click - this.rootPanel.on('tap', this._onSelectItem.bind(this)); + this.controller.on('tap', this._onSelectItem.bind(this)); // multi select when holding mouse/touch, or on ctrl+click - this.rootPanel.on('hold', this._onMultiSelectItem.bind(this)); + this.controller.on('hold', this._onMultiSelectItem.bind(this)); // item panel var itemOptions = Object.create(this.options); @@ -92,8 +92,8 @@ function Timeline (container, items, options) { // TODO: reckon with options moveable and zoomable // TODO: put the listeners in setOptions, be able to dynamically change with options moveable and zoomable // TODO: enable moving again - this.range.subscribe(this.rootPanel, 'move', 'horizontal'); - this.range.subscribe(this.rootPanel, 'zoom', 'horizontal'); + this.range.subscribe(this.controller, this.rootPanel, 'move', 'horizontal'); + this.range.subscribe(this.controller, this.rootPanel, 'zoom', 'horizontal'); this.range.on('rangechange', function (properties) { var force = true; me.controller.requestReflow(force); diff --git a/src/timeline/component/Component.js b/src/timeline/component/Component.js index 8d15e0c6..c7c8cd3c 100644 --- a/src/timeline/component/Component.js +++ b/src/timeline/component/Component.js @@ -55,6 +55,23 @@ Component.prototype.getOption = function getOption(name) { return value; }; +/** + * Set controller for this component, or remove current controller by passing + * null as parameter value. + * @param {Controller | null} controller + */ +Component.prototype.setController = function setController (controller) { + this.controller = controller || null; +}; + +/** + * Get controller of this component + * @return {Controller} controller + */ +Component.prototype.getController = function getController () { + return this.controller; +}; + /** * Get the container element of the component, which can be used by a child to * add its own widgets. Not all components do have a container for childs, in diff --git a/src/timeline/component/ItemSet.js b/src/timeline/component/ItemSet.js index 20d7259b..35aab3ab 100644 --- a/src/timeline/component/ItemSet.js +++ b/src/timeline/component/ItemSet.js @@ -16,6 +16,13 @@ function ItemSet(parent, depends, options) { this.parent = parent; this.depends = depends; + // event listeners + this.listeners = { + dragstart: this._onDragStart.bind(this), + drag: this._onDrag.bind(this), + dragend: this._onDragEnd.bind(this) + }; + // one options object is shared by this itemset and all its items this.options = options || {}; this.defaultOptions = { @@ -99,6 +106,55 @@ ItemSet.types = { */ ItemSet.prototype.setOptions = Component.prototype.setOptions; + + +/** + * Set controller for this component + * @param {Controller | null} controller + */ +ItemSet.prototype.setController = function setController (controller) { + var event; + + // unregister old event listeners + if (this.controller) { + for (event in this.listeners) { + if (this.listeners.hasOwnProperty(event)) { + this.controller.off(event, this.listeners[event]); + } + } + } + + this.controller = controller || null; + + // register new event listeners + if (this.controller) { + for (event in this.listeners) { + if (this.listeners.hasOwnProperty(event)) { + this.controller.on(event, this.listeners[event]); + } + } + } +}; + +// attach event listeners for dragging items to the controller +(function (me) { + var _controller = null; + var _onDragStart = null; + var _onDrag = null; + var _onDragEnd = null; + + Object.defineProperty(me, 'controller', { + get: function () { + return _controller; + }, + + set: function (controller) { + + } + }); +}) (this); + + /** * Set range (start and end). * @param {Range | Object} range A Range or an object containing start and end. @@ -610,3 +666,80 @@ ItemSet.prototype.toScreen = function toScreen(time) { var conversion = this.conversion; return (time.valueOf() - conversion.offset) * conversion.scale; }; + +// global (private) object to store drag params +var touchParams = {}; + +/** + * Start dragging the selected events + * @param {Event} event + * @private + */ +// TODO: move this function to ItemSet +ItemSet.prototype._onDragStart = function (event) { + var item = this._itemFromTarget(event); +console.log('_onDragStart', event) + if (item && item.selected) { + touchParams.items = [item]; + //touchParams.items = this.getSelection(); // TODO: use the current selection + touchParams.itemsLeft = touchParams.items.map(function (item) { + return item.left; + }); + console.log('_onDragStart', touchParams) + event.stopPropagation(); + } +}; + +/** + * Drag selected items + * @param {Event} event + * @private + */ +// TODO: move this function to ItemSet +ItemSet.prototype._onDrag = function (event) { + if (touchParams.items) { + var deltaX = event.gesture.deltaX; + + touchParams.items.forEach(function (item, i) { + item.left = touchParams.itemsLeft[i] + deltaX; + item.reposition(); + }); + + event.stopPropagation(); + } +}; + +/** + * End of dragging selected items + * @param {Event} event + * @private + */ +// TODO: move this function to ItemSet +ItemSet.prototype._onDragEnd = function (event) { + if (touchParams.items) { + // actually apply the new locations + + touchParams.items = null; + + event.stopPropagation(); + } +}; + +/** + * Find an item from an event target: + * searches for the attribute 'timeline-item' in the event target's element tree + * @param {Event} event + * @return {Item | null| item + * @private + */ +ItemSet.prototype._itemFromTarget = function _itemFromTarget (event) { + var target = event.target; + while (target) { + if (target.hasOwnProperty('timeline-item')) { + return target['timeline-item']; + } + target = target.parentNode; + } + + return null; +}; \ No newline at end of file diff --git a/src/timeline/component/RootPanel.js b/src/timeline/component/RootPanel.js index 6bfd2db2..e4c6166d 100644 --- a/src/timeline/component/RootPanel.js +++ b/src/timeline/component/RootPanel.js @@ -10,12 +10,29 @@ function RootPanel(container, options) { this.id = util.randomUUID(); this.container = container; + // create functions to be used as DOM event listeners + var me = this; + this.hammer = null; + + // create listeners for all interesting events, these events will be emitted + // via the controller + var events = [ + 'touch', 'pinch', 'tap', 'hold', + 'dragstart', 'drag', 'dragend', + 'mousewheel', 'DOMMouseScroll' // DOMMouseScroll is for Firefox + ]; + this.listeners = {}; + events.forEach(function (event) { + me.listeners[event] = function () { + var args = [event].concat(Array.prototype.slice.call(arguments, 0)); + me.controller.emit.apply(me.controller, args); + }; + }); + this.options = options || {}; this.defaultOptions = { autoResize: true }; - - this.listeners = {}; // event listeners } RootPanel.prototype = new Panel(); @@ -48,6 +65,8 @@ RootPanel.prototype.repaint = function () { this.frame = frame; + this._registerListeners(); + changed += 1; } if (!frame.parentNode) { @@ -69,7 +88,6 @@ RootPanel.prototype.repaint = function () { changed += update(frame.style, 'width', asSize(options.width, '100%')); changed += update(frame.style, 'height', asSize(options.height, '100%')); - this._updateEventEmitters(); this._updateWatch(); return (changed > 0); @@ -158,58 +176,51 @@ RootPanel.prototype._unwatch = function () { }; /** - * Event handler - * @param {String} event name of the event, for example 'click', 'mousemove' - * @param {function} callback callback handler, invoked with the raw HTML Event - * as parameter. + * Set controller for this component, or remove current controller by passing + * null as parameter value. + * @param {Controller | null} controller */ -RootPanel.prototype.on = function (event, callback) { - // register the listener at this component - var arr = this.listeners[event]; - if (!arr) { - arr = []; - this.listeners[event] = arr; - } - arr.push(callback); +RootPanel.prototype.setController = function setController (controller) { + this.controller = controller || null; - this._updateEventEmitters(); + if (this.controller) { + this._registerListeners(); + } + else { + this._unregisterListeners(); + } }; /** - * Update the event listeners for all event emitters + * Register event emitters emitted by the rootpanel * @private */ -RootPanel.prototype._updateEventEmitters = function () { - if (this.listeners) { - var me = this; - util.forEach(this.listeners, function (listeners, event) { - if (!me.emitters) { - me.emitters = {}; +RootPanel.prototype._registerListeners = function () { + if (this.frame && this.controller && !this.hammer) { + this.hammer = Hammer(this.frame, { + prevent_default: true + }); + + for (var event in this.listeners) { + if (this.listeners.hasOwnProperty(event)) { + this.hammer.on(event, this.listeners[event]); } - if (!(event in me.emitters)) { - // create event - var frame = me.frame; - if (frame) { - //console.log('Created a listener for event ' + event + ' on component ' + me.id); // TODO: cleanup logging - var callback = function(event) { - listeners.forEach(function (listener) { - // TODO: filter on event target! - listener(event); - }); - }; - me.emitters[event] = callback; - - if (!me.hammer) { - me.hammer = Hammer(frame, { - prevent_default: true - }); - } - me.hammer.on(event, callback); - } + } + } +}; + +/** + * Unregister event emitters from the rootpanel + * @private + */ +RootPanel.prototype._unregisterListeners = function () { + if (this.hammer) { + for (var event in this.listeners) { + if (this.listeners.hasOwnProperty(event)) { + this.hammer.off(event, this.listeners[event]); } - }); + } - // TODO: be able to delete event listeners - // TODO: be able to move event listeners to a parent when available + this.hammer = null; } }; diff --git a/src/timeline/component/item/Item.js b/src/timeline/component/item/Item.js index 590ee551..a0d68354 100644 --- a/src/timeline/component/item/Item.js +++ b/src/timeline/component/item/Item.js @@ -74,8 +74,8 @@ Item.prototype.reflow = function reflow() { /** * Return the items width - * @return {Integer} width + * @return {Number} width */ Item.prototype.getWidth = function getWidth() { return this.width; -} +}; From 5801a0e7706c53ba4f16fa5c53cb4defff93e7df Mon Sep 17 00:00:00 2001 From: josdejong Date: Fri, 7 Feb 2014 11:12:49 +0100 Subject: [PATCH 33/52] Implemented dragging items --- src/timeline/Controller.js | 2 + src/timeline/Range.js | 36 ++++++-- src/timeline/Stack.js | 14 +-- src/timeline/Timeline.js | 24 +---- src/timeline/component/ItemSet.js | 110 ++++++++++++++++------- src/timeline/component/item/Item.js | 9 ++ src/timeline/component/item/ItemBox.js | 2 +- src/timeline/component/item/ItemPoint.js | 2 +- src/timeline/component/item/ItemRange.js | 4 +- 9 files changed, 131 insertions(+), 72 deletions(-) diff --git a/src/timeline/Controller.js b/src/timeline/Controller.js index 8ba7e563..ebb3e494 100644 --- a/src/timeline/Controller.js +++ b/src/timeline/Controller.js @@ -61,6 +61,7 @@ Controller.prototype.remove = function remove(component) { * @param {Boolean} [force] If true, an immediate reflow is forced. Default * is false. */ +// TODO: change requestReflow into an event Controller.prototype.requestReflow = function requestReflow(force) { if (force) { this.reflow(); @@ -81,6 +82,7 @@ Controller.prototype.requestReflow = function requestReflow(force) { * @param {Boolean} [force] If true, an immediate repaint is forced. Default * is false. */ +// TODO: change requestReflow into an event Controller.prototype.requestRepaint = function requestRepaint(force) { if (force) { this.repaint(); diff --git a/src/timeline/Range.js b/src/timeline/Range.js index f3e04390..0bea4d63 100644 --- a/src/timeline/Range.js +++ b/src/timeline/Range.js @@ -71,6 +71,11 @@ Range.prototype.subscribe = function (controller, component, event, direction) { controller.on('dragend', function (event) { me._onDragEnd(event, component); }); + + // ignore dragging when holding + controller.on('hold', function (event) { + me._onHold(); + }); } else if (event == 'zoom') { // mouse wheel @@ -82,7 +87,7 @@ Range.prototype.subscribe = function (controller, component, event, direction) { // pinch controller.on('touch', function (event) { - me._onTouch(); + me._onTouch(event); }); controller.on('pinch', function (event) { me._onPinch(event, component, direction); @@ -312,7 +317,7 @@ var touchParams = {}; Range.prototype._onDragStart = function(event, component) { // refuse to drag when we where pinching to prevent the timeline make a jump // when releasing the fingers in opposite order from the touch screen - if (touchParams.pinching) return; + if (touchParams.ignore) return; touchParams.start = this.start; touchParams.end = this.end; @@ -335,7 +340,7 @@ Range.prototype._onDrag = function (event, component, direction) { // refuse to drag when we where pinching to prevent the timeline make a jump // when releasing the fingers in opposite order from the touch screen - if (touchParams.pinching) return; + if (touchParams.ignore) return; var delta = (direction == 'horizontal') ? event.gesture.deltaX : event.gesture.deltaY, interval = (touchParams.end - touchParams.start), @@ -357,7 +362,7 @@ Range.prototype._onDrag = function (event, component, direction) { Range.prototype._onDragEnd = function (event, component) { // refuse to drag when we where pinching to prevent the timeline make a jump // when releasing the fingers in opposite order from the touch screen - if (touchParams.pinching) return; + if (touchParams.ignore) return; if (component.frame) { component.frame.style.cursor = 'auto'; @@ -418,14 +423,29 @@ Range.prototype._onMouseWheel = function(event, component, direction) { }; /** - * On start of a touch gesture, initialize scale to 1 + * Start of a touch gesture * @private */ -Range.prototype._onTouch = function () { +Range.prototype._onTouch = function (event) { touchParams.start = this.start; touchParams.end = this.end; - touchParams.pinching = false; + touchParams.ignore = false; touchParams.center = null; + + // don't move the range when dragging a selected event + // TODO: it's not so neat to have to know about the state of the ItemSet + var item = ItemSet.itemFromTarget(event); + if (item && item.selected) { + touchParams.ignore = true; + } +}; + +/** + * On start of a hold gesture + * @private + */ +Range.prototype._onHold = function () { + touchParams.ignore = true; }; /** @@ -436,7 +456,7 @@ Range.prototype._onTouch = function () { * @private */ Range.prototype._onPinch = function (event, component, direction) { - touchParams.pinching = true; + touchParams.ignore = true; if (event.gesture.touches.length > 1) { if (!touchParams.center) { diff --git a/src/timeline/Stack.js b/src/timeline/Stack.js index 017c98ce..16ac34b7 100644 --- a/src/timeline/Stack.js +++ b/src/timeline/Stack.js @@ -1,11 +1,11 @@ /** * @constructor Stack * Stacks items on top of each other. - * @param {ItemSet} parent + * @param {ItemSet} itemset * @param {Object} [options] */ -function Stack (parent, options) { - this.parent = parent; +function Stack (itemset, options) { + this.itemset = itemset; this.options = options || {}; this.defaultOptions = { @@ -43,14 +43,14 @@ function Stack (parent, options) { /** * Set options for the stack * @param {Object} options Available options: - * {ItemSet} parent + * {ItemSet} itemset * {Number} margin * {function} order Stacking order */ Stack.prototype.setOptions = function setOptions (options) { util.extend(this.options, options); - // TODO: register on data changes at the connected parent itemset, and update the changed part only and immediately + // TODO: register on data changes at the connected itemset, and update the changed part only and immediately }; /** @@ -70,9 +70,9 @@ Stack.prototype.update = function update() { * @private */ Stack.prototype._order = function _order () { - var items = this.parent.items; + var items = this.itemset.items; if (!items) { - throw new Error('Cannot stack items: parent does not contain items'); + throw new Error('Cannot stack items: ItemSet does not contain items'); } // TODO: store the sorted items, to have less work later on diff --git a/src/timeline/Timeline.js b/src/timeline/Timeline.js index 3b9efc4a..664bc20c 100644 --- a/src/timeline/Timeline.js +++ b/src/timeline/Timeline.js @@ -378,7 +378,7 @@ Timeline.prototype.getSelection = function getSelection() { */ // TODO: move this function to ItemSet Timeline.prototype._onSelectItem = function (event) { - var item = this._itemFromTarget(event); + var item = ItemSet.itemFromTarget(event); var selection = item ? [item.id] : []; this.setSelection(selection); @@ -398,7 +398,7 @@ Timeline.prototype._onSelectItem = function (event) { // TODO: move this function to ItemSet Timeline.prototype._onMultiSelectItem = function (event) { var selection, - item = this._itemFromTarget(event); + item = ItemSet.itemFromTarget(event); if (!item) { // do nothing... @@ -423,23 +423,3 @@ Timeline.prototype._onMultiSelectItem = function (event) { event.stopPropagation(); }; - -/** - * Find an item from an event target: - * searches for the attribute 'timeline-item' in the event target's element tree - * @param {Event} event - * @return {Item | null| item - * @private - */ -// TODO: move this function to ItemSet -Timeline.prototype._itemFromTarget = function _itemFromTarget (event) { - var target = event.target; - while (target) { - if (target.hasOwnProperty('timeline-item')) { - return target['timeline-item']; - } - target = target.parentNode; - } - - return null; -}; \ No newline at end of file diff --git a/src/timeline/component/ItemSet.js b/src/timeline/component/ItemSet.js index 35aab3ab..e44d4c87 100644 --- a/src/timeline/component/ItemSet.js +++ b/src/timeline/component/ItemSet.js @@ -17,7 +17,7 @@ function ItemSet(parent, depends, options) { this.depends = depends; // event listeners - this.listeners = { + this.eventListeners = { dragstart: this._onDragStart.bind(this), drag: this._onDrag.bind(this), dragend: this._onDragEnd.bind(this) @@ -42,6 +42,7 @@ function ItemSet(parent, depends, options) { this.itemsData = null; // DataSet this.range = null; // Range or Object {start: number, end: number} + // data change listeners this.listeners = { 'add': function (event, params, senderId) { if (senderId != me.id) { @@ -66,6 +67,8 @@ function ItemSet(parent, depends, options) { this.stack = new Stack(this, Object.create(this.options)); this.conversion = null; + this.touchParams = {}; // stores properties while dragging + // TODO: ItemSet should also attach event listeners for rangechange and rangechanged, like timeaxis } @@ -117,9 +120,9 @@ ItemSet.prototype.setController = function setController (controller) { // unregister old event listeners if (this.controller) { - for (event in this.listeners) { - if (this.listeners.hasOwnProperty(event)) { - this.controller.off(event, this.listeners[event]); + for (event in this.eventListeners) { + if (this.eventListeners.hasOwnProperty(event)) { + this.controller.off(event, this.eventListeners[event]); } } } @@ -128,9 +131,9 @@ ItemSet.prototype.setController = function setController (controller) { // register new event listeners if (this.controller) { - for (event in this.listeners) { - if (this.listeners.hasOwnProperty(event)) { - this.controller.on(event, this.listeners[event]); + for (event in this.eventListeners) { + if (this.eventListeners.hasOwnProperty(event)) { + this.controller.on(event, this.eventListeners[event]); } } } @@ -251,6 +254,7 @@ ItemSet.prototype.repaint = function repaint() { if (!frame) { frame = document.createElement('div'); frame.className = 'itemset'; + frame['timeline-itemset'] = this; var className = options.className; if (className) { @@ -667,25 +671,21 @@ ItemSet.prototype.toScreen = function toScreen(time) { return (time.valueOf() - conversion.offset) * conversion.scale; }; -// global (private) object to store drag params -var touchParams = {}; - /** * Start dragging the selected events * @param {Event} event * @private */ -// TODO: move this function to ItemSet ItemSet.prototype._onDragStart = function (event) { - var item = this._itemFromTarget(event); -console.log('_onDragStart', event) + var itemSet = ItemSet.itemSetFromTarget(event), + item = ItemSet.itemFromTarget(event), + me = this; + if (item && item.selected) { - touchParams.items = [item]; - //touchParams.items = this.getSelection(); // TODO: use the current selection - touchParams.itemsLeft = touchParams.items.map(function (item) { - return item.left; + this.touchParams.items = this.getSelection().map(function (id) { + return me.items[id]; }); - console.log('_onDragStart', touchParams) + event.stopPropagation(); } }; @@ -695,16 +695,21 @@ console.log('_onDragStart', event) * @param {Event} event * @private */ -// TODO: move this function to ItemSet ItemSet.prototype._onDrag = function (event) { - if (touchParams.items) { + if (this.touchParams.items) { var deltaX = event.gesture.deltaX; - touchParams.items.forEach(function (item, i) { - item.left = touchParams.itemsLeft[i] + deltaX; - item.reposition(); + // adjust the offset of the items being dragged + this.touchParams.items.forEach(function (item) { + item.setOffset(deltaX); }); + // TODO: implement snapping to nice dates + + // TODO: implement dragging from one group to another + + this.requestReflow(); + event.stopPropagation(); } }; @@ -714,12 +719,38 @@ ItemSet.prototype._onDrag = function (event) { * @param {Event} event * @private */ -// TODO: move this function to ItemSet ItemSet.prototype._onDragEnd = function (event) { - if (touchParams.items) { - // actually apply the new locations + if (this.touchParams.items) { + var deltaX = event.gesture.deltaX, + scale = this.conversion.scale; - touchParams.items = null; + // prepare a changeset for the changed items + var changes = this.touchParams.items.map(function (item) { + item.setOffset(0); + + var change = { + id: item.id + }; + + if ('start' in item.data) { + change.start = new Date(item.data.start.valueOf() + deltaX / scale); + } + if ('end' in item.data) { + change.end = new Date(item.data.end.valueOf() + deltaX / scale); + } + + return change; + }); + this.touchParams.items = null; + + // find the root DataSet from our DataSet/DataView + var data = this.itemsData; + while (data instanceof DataView) { + data = data.data; + } + + // apply the changes to the data + data.update(changes); event.stopPropagation(); } @@ -729,10 +760,9 @@ ItemSet.prototype._onDragEnd = function (event) { * Find an item from an event target: * searches for the attribute 'timeline-item' in the event target's element tree * @param {Event} event - * @return {Item | null| item - * @private + * @return {Item | null} item */ -ItemSet.prototype._itemFromTarget = function _itemFromTarget (event) { +ItemSet.itemFromTarget = function itemFromTarget (event) { var target = event.target; while (target) { if (target.hasOwnProperty('timeline-item')) { @@ -742,4 +772,22 @@ ItemSet.prototype._itemFromTarget = function _itemFromTarget (event) { } return null; -}; \ No newline at end of file +}; + +/** + * Find the ItemSet from an event target: + * searches for the attribute 'timeline-itemset' in the event target's element tree + * @param {Event} event + * @return {ItemSet | null} item + */ +ItemSet.itemSetFromTarget = function itemSetFromTarget (event) { + var target = event.target; + while (target) { + if (target.hasOwnProperty('timeline-itemset')) { + return target['timeline-itemset']; + } + target = target.parentNode; + } + + return null; +}; diff --git a/src/timeline/component/item/Item.js b/src/timeline/component/item/Item.js index a0d68354..cdb69c76 100644 --- a/src/timeline/component/item/Item.js +++ b/src/timeline/component/item/Item.js @@ -20,6 +20,7 @@ function Item (parent, data, options, defaultOptions) { this.left = 0; this.width = 0; this.height = 0; + this.offset = 0; } /** @@ -72,6 +73,14 @@ Item.prototype.reflow = function reflow() { return false; }; +/** + * Give the item a display offset in pixels + * @param {Number} offset Offset on screen in pixels + */ +Item.prototype.setOffset = function setOffset(offset) { + this.offset = offset; +}; + /** * Return the items width * @return {Number} width diff --git a/src/timeline/component/item/ItemBox.js b/src/timeline/component/item/ItemBox.js index cde86f5a..8ea236c9 100644 --- a/src/timeline/component/item/ItemBox.js +++ b/src/timeline/component/item/ItemBox.js @@ -187,7 +187,7 @@ ItemBox.prototype.reflow = function reflow() { update = util.updateProperty; props = this.props; options = this.options; - start = this.parent.toScreen(this.data.start); + start = this.parent.toScreen(this.data.start) + this.offset; align = options.align || this.defaultOptions.align; margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; orientation = options.orientation || this.defaultOptions.orientation; diff --git a/src/timeline/component/item/ItemPoint.js b/src/timeline/component/item/ItemPoint.js index 1a78a92b..2d5124e1 100644 --- a/src/timeline/component/item/ItemPoint.js +++ b/src/timeline/component/item/ItemPoint.js @@ -157,7 +157,7 @@ ItemPoint.prototype.reflow = function reflow() { options = this.options; orientation = options.orientation || this.defaultOptions.orientation; margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; - start = this.parent.toScreen(this.data.start); + start = this.parent.toScreen(this.data.start) + this.offset; changed += update(this, 'width', dom.point.offsetWidth); changed += update(this, 'height', dom.point.offsetHeight); diff --git a/src/timeline/component/item/ItemRange.js b/src/timeline/component/item/ItemRange.js index a2feec99..bb7b8386 100644 --- a/src/timeline/component/item/ItemRange.js +++ b/src/timeline/component/item/ItemRange.js @@ -157,8 +157,8 @@ ItemRange.prototype.reflow = function reflow() { props = this.props; options = this.options; parent = this.parent; - start = parent.toScreen(this.data.start); - end = parent.toScreen(this.data.end); + start = parent.toScreen(this.data.start) + this.offset; + end = parent.toScreen(this.data.end) + this.offset; update = util.updateProperty; box = dom.box; parentWidth = parent.width; From 984f2efafb45732b61c1e9721706c91133962679 Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Sat, 8 Feb 2014 01:35:30 +0100 Subject: [PATCH 34/52] Added Barnes-Hut force model. Main slowdown is in the drawing now.. --- Jakefile.js | 3 +- dist/vis.js | 875 ++++++++++++++++------- dist/vis.min.js | 16 +- examples/graph/02_random_nodes.html | 1 + examples/graph/21_data_manipulation.html | 2 +- examples/graph/22_les_miserables.html | 373 ++++++++++ src/graph/ClusterMixin.js | 2 +- src/graph/Edge.js | 8 +- src/graph/Graph.js | 276 ++----- src/graph/Node.js | 32 +- src/graph/SelectionMixin.js | 12 +- src/graph/manipulationMixin.js | 4 +- src/graph/physicsMixin.js | 539 ++++++++++++++ 13 files changed, 1622 insertions(+), 521 deletions(-) create mode 100644 examples/graph/22_les_miserables.html create mode 100644 src/graph/physicsMixin.js diff --git a/Jakefile.js b/Jakefile.js index bb43714b..511dbd21 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -82,7 +82,8 @@ task('build', {async: true}, function () { './src/graph/Popup.js', './src/graph/Groups.js', './src/graph/Images.js', - './src/graph/manipulationMixin.js', + './src/graph/PhysicsMixin.js', + './src/graph/ManipulationMixin.js', './src/graph/SectorsMixin.js', './src/graph/ClusterMixin.js', './src/graph/SelectionMixin.js', diff --git a/dist/vis.js b/dist/vis.js index e96a323e..daedfde5 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -5,7 +5,7 @@ * A dynamic, browser-based visualization library. * * @version 0.5.0-SNAPSHOT - * @date 2014-02-05 + * @date 2014-02-08 * * @license * Copyright (C) 2011-2014 Almende B.V, http://almende.com @@ -9103,6 +9103,7 @@ if (typeof CanvasRenderingContext2D !== 'undefined') { * retrieving group properties * @param {Object} constants An object with default values for * example for the color + * */ function Node(properties, imagelist, grouplist, constants) { this.selected = false; @@ -9155,8 +9156,7 @@ function Node(properties, imagelist, grouplist, constants) { this.vx = 0.0; // velocity x this.vy = 0.0; // velocity y this.minForce = constants.minForce; - this.damping = 0.9; - this.dampingFactor = 75; + this.damping = 0.9; // this is manipulated in the updateDaming function this.graphScaleInv = 1; this.canvasTopLeft = {"x": -300, "y": -300}; @@ -9210,7 +9210,7 @@ Node.prototype.detachEdge = function(edge) { * @private */ Node.prototype._updateMass = function() { - this.mass = 1 + 0.6 * this.edges.length; // kg + this.mass = 1;// + 0.6 * this.edges.length; // kg }; /** @@ -9472,6 +9472,29 @@ Node.prototype.discreteStep = function(interval) { }; + +/** + * Perform one discrete step for the node + * @param {number} interval Time interval in seconds + */ +Node.prototype.discreteStepLimited = function(interval, maxVelocity) { + if (!this.xFixed) { + var dx = -this.damping * this.vx; // damping force + var ax = (this.fx + dx) / this.mass; // acceleration + this.vx += ax * interval; // velocity + this.vx = (Math.abs(this.vx) > maxVelocity) ? ((this.vx > 0) ? maxVelocity : -maxVelocity) : this.vx; + this.x += this.vx * interval; // position + } + + if (!this.yFixed) { + var dy = -this.damping * this.vy; // damping force + var ay = (this.fy + dy) / this.mass; // acceleration + this.vy += ay * interval; // velocity + this.vy = (Math.abs(this.vy) > maxVelocity) ? ((this.vy > 0) ? maxVelocity : -maxVelocity) : this.vy; + this.y += this.vy * interval; // position + } +}; + /** * Check if this node has a fixed x and y position * @return {boolean} true if fixed, false if not @@ -10032,8 +10055,7 @@ Node.prototype.setScale = function(scale) { * @param {Number} numberOfNodes */ Node.prototype.updateDamping = function(numberOfNodes) { - this.damping = (0.8 + 0.1*this.clusterSize * (1 + Math.pow(numberOfNodes,-2))); - this.damping *= this.dampingFactor; + this.damping = (1 + 0.1*this.clusterSize * (1 + Math.pow(numberOfNodes,-2))); }; @@ -10143,10 +10165,10 @@ Edge.prototype.setProperties = function(properties, constants) { if (properties.fontSize !== undefined) {this.fontSize = properties.fontSize;} if (properties.fontFace !== undefined) {this.fontFace = properties.fontFace;} } - if (properties.title !== undefined) {this.title = properties.title;} - if (properties.width !== undefined) {this.width = properties.width;} - if (properties.value !== undefined) {this.value = properties.value;} - if (properties.length !== undefined) {this.length = properties.length;} + if (properties.title !== undefined) {this.title = properties.title;} + if (properties.width !== undefined) {this.width = properties.width;} + if (properties.value !== undefined) {this.value = properties.value;} + if (properties.length !== undefined) {this.length = properties.length;} // Added to support dashed lines // David Jordan @@ -10918,6 +10940,545 @@ Images.prototype.load = function(url) { return img; }; +/** + * Created by Alex on 2/6/14. + */ + + +var physicsMixin = { + + /** + * Before calculating the forces, we check if we need to cluster to keep up performance and we check + * if there is more than one node. If it is just one node, we dont calculate anything. + * + * @private + */ + _initializeForceCalculation : function() { + // stop calculation if there is only one node + if (this.nodeIndices.length == 1) { + this.nodes[this.nodeIndices[0]]._setForce(0,0); + } + else { + // if there are too many nodes on screen, we cluster without repositioning + if (this.nodeIndices.length > this.constants.clustering.clusterThreshold && this.constants.clustering.enabled == true) { + this.clusterToFit(this.constants.clustering.reduceToNodes, false); + } + + // we now start the force calculation + this._calculateForcesBarnesHut(); +// this._calculateForcesOriginal(); + } + }, + + + /** + * Calculate the external forces acting on the nodes + * Forces are caused by: edges, repulsing forces between nodes, gravity + * @private + */ + _calculateForcesOriginal : function() { + // Gravity is required to keep separated groups from floating off + // the forces are reset to zero in this loop by using _setForce instead + // of _addForce + +// var startTimeAll = Date.now(); + + this._calculateGravitationalForces(1); + +// var startTimeRepulsion = Date.now(); + // All nodes repel eachother. + this._calculateRepulsionForces(); + +// var endTimeRepulsion = Date.now(); + + // the edges are strings + this._calculateSpringForces(1); + +// var endTimeAll = Date.now(); + +// echo("Time repulsion part:", endTimeRepulsion - startTimeRepulsion); +// echo("Time total force calc:", endTimeAll - startTimeAll); + }, + + /** + * Calculate the external forces acting on the nodes + * Forces are caused by: edges, repulsing forces between nodes, gravity + * @private + */ + _calculateForcesBarnesHut : function() { + // Gravity is required to keep separated groups from floating off + // the forces are reset to zero in this loop by using _setForce instead + // of _addForce + +// var startTimeAll = Date.now(); + + this._clearForces(); + +// var startTimeRepulsion = Date.now(); + // All nodes repel eachother. + this._calculateBarnesHutForces(); + +// var endTimeRepulsion = Date.now(); + + // the edges are strings + this._calculateSpringForces(1); + +// var endTimeAll = Date.now(); + +// echo("Time repulsion part:", endTimeRepulsion - startTimeRepulsion); +// echo("Time total force calc:", endTimeAll - startTimeAll); + }, + + + _clearForces : function() { + var node; + var nodes = this.nodes; + + for (var i = 0; i < this.nodeIndices.length; i++) { + node = nodes[this.nodeIndices[i]]; + node._setForce(0, 0); + node.updateDamping(this.nodeIndices.length); + } + }, + + _calculateGravitationalForces : function(boost) { + var dx, dy, angle, fx, fy, node, i; + var nodes = this.nodes; + var gravity = 0.08 * boost; + + for (i = 0; i < this.nodeIndices.length; i++) { + node = nodes[this.nodeIndices[i]]; + // gravity does not apply when we are in a pocket sector + if (this._sector() == "default") { + dx = -node.x;// + screenCenterPos.x; + dy = -node.y;// + screenCenterPos.y; + + angle = Math.atan2(dy, dx); + fx = Math.cos(angle) * gravity; + fy = Math.sin(angle) * gravity; + } + else { + fx = 0; + fy = 0; + } + node._setForce(fx, fy); + node.updateDamping(this.nodeIndices.length); + } + }, + + _calculateRepulsionForces : function() { + var dx, dy, angle, distance, fx, fy, clusterSize, + repulsingForce, node1, node2, i, j; + var nodes = this.nodes; + + // approximation constants + var a_base = (-2/3); + var b = 4/3; + + // repulsing forces between nodes + var minimumDistance = this.constants.nodes.distance; + //var steepness = 10; + + // we loop from i over all but the last entree in the array + // j loops from i+1 to the last. This way we do not double count any of the indices, nor i == j + for (i = 0; i < this.nodeIndices.length-1; i++) { + node1 = nodes[this.nodeIndices[i]]; + for (j = i+1; j < this.nodeIndices.length; j++) { + node2 = nodes[this.nodeIndices[j]]; + clusterSize = (node1.clusterSize + node2.clusterSize - 2); + dx = node2.x - node1.x; + dy = node2.y - node1.y; + distance = Math.sqrt(dx * dx + dy * dy); + + + // clusters have a larger region of influence + minimumDistance = (clusterSize == 0) ? this.constants.nodes.distance : (this.constants.nodes.distance * (1 + clusterSize * this.constants.clustering.distanceAmplification)); + var a = a_base / minimumDistance; + if (distance < 2*minimumDistance) { // at 2.0 * the minimum distance, the force is 0.000045 + angle = Math.atan2(dy, dx); + + if (distance < 0.5*minimumDistance) { // at 0.5 * the minimum distance, the force is 0.993307 + repulsingForce = 1.0; + } + else { + repulsingForce = a * distance + b; // linear approx of 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)) + } + // amplify the repulsion for clusters. + repulsingForce *= (clusterSize == 0) ? 1 : 1 + clusterSize * this.constants.clustering.forceAmplification; + + fx = Math.cos(angle) * repulsingForce; + fy = Math.sin(angle) * repulsingForce ; + + node1._addForce(-fx, -fy); + node2._addForce(fx, fy); + } + } + } + }, + + _calculateSpringForces : function(boost) { + var dx, dy, angle, fx, fy, springForce, length, edgeLength, edge, edgeId, clusterSize; + var edges = this.edges; + + // forces caused by the edges, modelled as springs + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.connected) { + // only calculate forces if nodes are in the same sector + if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { + clusterSize = (edge.to.clusterSize + edge.from.clusterSize - 2); + dx = (edge.to.x - edge.from.x); + dy = (edge.to.y - edge.from.y); + + edgeLength = edge.length; + + // this implies that the edges between big clusters are longer + edgeLength += clusterSize * this.constants.clustering.edgeGrowth; + length = Math.sqrt(dx * dx + dy * dy); + angle = Math.atan2(dy, dx); + + springForce = 0.02 * (edgeLength - length) * boost; + + fx = Math.cos(angle) * springForce; + fy = Math.sin(angle) * springForce; + + edge.from._addForce(-fx, -fy); + edge.to._addForce(fx, fy); + } + } + } + } + }, + + _calculateBarnesHutForces : function() { + this._formBarnesHutTree(); + + var nodes = this.nodes; + var nodeIndices = this.nodeIndices; + var node; + var nodeCount = nodeIndices.length; + + var barnesHutTree = this.barnesHutTree; + + this.theta = 0.2; + this.graviationalConstant = -10000; + + + // place the nodes one by one recursively + for (var i = 0; i < nodeCount; i++) { + node = nodes[nodeIndices[i]]; + // starting with root is irrelevant, it never passes the BarnesHut condition + this._getForceContribution(barnesHutTree.root.children.NW,node); + this._getForceContribution(barnesHutTree.root.children.NE,node); + this._getForceContribution(barnesHutTree.root.children.SW,node); + this._getForceContribution(barnesHutTree.root.children.SE,node); + } + }, + + _getForceContribution : function(parentBranch,node) { + // we get no force contribution from an empty region + if (parentBranch.childrenCount > 0) { + var dx,dy,distance; + + // get the distance from the center of mass to the node. + dx = parentBranch.CenterOfMass.x - node.x; + dy = parentBranch.CenterOfMass.y - node.y; + distance = Math.sqrt(dx * dx + dy * dy); + + if (distance > 0) { // distance is 0 if it looks to apply a force on itself. + // we invert it here because we need the inverted distance for the force calculation too. + var distanceInv = 1/distance; + // BarnesHut condition + if (parentBranch.size * distanceInv > this.theta) { + // Did not pass the condition, go into children if available + if (parentBranch.childrenCount == 4) { + this._getForceContribution(parentBranch.children.NW,node); + this._getForceContribution(parentBranch.children.NE,node); + this._getForceContribution(parentBranch.children.SW,node); + this._getForceContribution(parentBranch.children.SE,node); + } + else { // parentBranch must have only one node, if it was empty we wouldnt be here + this._getForceOnNode(parentBranch, node, dx ,dy, distanceInv); + } + } + else { + this._getForceOnNode(parentBranch, node, dx ,dy, distanceInv); + } + } + } + }, + + _getForceOnNode : function(parentBranch, node, dx ,dy, distanceInv) { + // even if the parentBranch only has one node, its Center of Mass is at the right place (the node in this case). + var gravityForce = this.graviationalConstant * parentBranch.mass * node.mass * distanceInv * distanceInv; + var angle = Math.atan2(dy, dx); + var fx = Math.cos(angle) * gravityForce; + var fy = Math.sin(angle) * gravityForce; + node._addForce(fx, fy); + }, + + + _formBarnesHutTree : function() { + var nodes = this.nodes; + var nodeIndices = this.nodeIndices; + var node; + var nodeCount = nodeIndices.length; + + var minX = Number.MAX_VALUE, + minY = Number.MAX_VALUE, + maxX =-Number.MAX_VALUE, + maxY =-Number.MAX_VALUE; + + // get the range of the nodes + for (var i = 0; i < nodeCount; i++) { + var x = nodes[nodeIndices[i]].x; + var y = nodes[nodeIndices[i]].y; + if (x < minX) { minX = x; } + if (x > maxX) { maxX = x; } + if (y < minY) { minY = y; } + if (y > maxY) { maxY = y; } + } + // make the range a square + var sizeDiff = Math.abs(maxX - minX) - Math.abs(maxY - minY); // difference between X and Y + if (sizeDiff > 0) {minY -= 0.5 * sizeDiff; maxY += 0.5 * sizeDiff;} // xSize > ySize + else {minX += 0.5 * sizeDiff; maxY -= 0.5 * sizeDiff;} // xSize < ySize + + + // construct the barnesHutTree + var barnesHutTree = {root:{ + CenterOfMass:{x:0,y:0}, // Center of Mass + mass:0, + range:{minX:minX,maxX:maxX,minY:minY,maxY:maxY}, + size: Math.abs(maxX - minX), + children: {data:null}, + childrenCount: 4 + }}; + this._splitBranch(barnesHutTree.root); + + // place the nodes one by one recursively + for (i = 0; i < nodeCount; i++) { + node = nodes[nodeIndices[i]]; + this._placeInTree(barnesHutTree.root,node); + } + + // make global + this.barnesHutTree = barnesHutTree + }, + + + _updateBranchMass : function(parentBranch, node) { + var totalMass = parentBranch.mass + node.mass; + var totalMassInv = 1/totalMass; + + parentBranch.CenterOfMass.x = parentBranch.CenterOfMass.x * parentBranch.mass + node.x * node.mass; + parentBranch.CenterOfMass.x *= totalMassInv; + + parentBranch.CenterOfMass.y = parentBranch.CenterOfMass.y * parentBranch.mass + node.y * node.mass; + parentBranch.CenterOfMass.y *= totalMassInv; + + parentBranch.mass = totalMass; + }, + + _placeInTree : function(parentBranch,node) { + // update the mass of the branch. + this._updateBranchMass(parentBranch,node); + + if (parentBranch.children.NW.range.maxX > node.x) { // in NW or SW + if (parentBranch.children.NW.range.maxY > node.y) { // in NW + this._placeInRegion(parentBranch,node,"NW"); + } + else { // in SW + this._placeInRegion(parentBranch,node,"SW"); + } + } + else { // in NE or SE + if (parentBranch.children.NE.range.maxY > node.y) { // in NE + this._placeInRegion(parentBranch,node,"NE"); + } + else { // in SE + this._placeInRegion(parentBranch,node,"SE"); + } + } + }, + + _placeInRegion : function(parentBranch,node,region) { + switch (parentBranch.children[region].childrenCount) { + case 0: // place node here + parentBranch.children[region].children.data = node; + parentBranch.children[region].childrenCount = 1; + this._updateBranchMass(parentBranch.children[region],node); + break; + case 1: // convert into children + this._splitBranch(parentBranch.children[region]); + this._placeInTree(parentBranch.children[region],node); + break; + case 4: // place in branch + this._placeInTree(parentBranch.children[region],node); + break; + } + }, + + _splitBranch : function(parentBranch) { + // if the branch is filled with a node, replace the node in the new subset. + var containedNode = null; + if (parentBranch.childrenCount == 1) { + containedNode = parentBranch.children.data; + parentBranch.mass = 0; parentBranch.CenterOfMass.x = 0; parentBranch.CenterOfMass.y = 0; + } + parentBranch.childrenCount = 4; + parentBranch.children.data = null; + this._insertRegion(parentBranch,"NW"); + this._insertRegion(parentBranch,"NE"); + this._insertRegion(parentBranch,"SW"); + this._insertRegion(parentBranch,"SE"); + + if (containedNode != null) { + this._placeInTree(parentBranch,containedNode); + } + }, + + + /** + * This function subdivides the region into four new segments. + * Specifically, this inserts a single new segment. + * It fills the children section of the parentBranch + * + * @param parentBranch + * @param region + * @param parentRange + * @private + */ + _insertRegion : function(parentBranch, region) { + var minX,maxX,minY,maxY; + switch (region) { + case "NW": + minX = parentBranch.range.minX; + maxX = parentBranch.range.minX + parentBranch.size; + minY = parentBranch.range.minY; + maxY = parentBranch.range.minY + parentBranch.size; + break; + case "NE": + minX = parentBranch.range.minX + parentBranch.size; + maxX = parentBranch.range.maxX; + minY = parentBranch.range.minY; + maxY = parentBranch.range.minY + parentBranch.size; + break; + case "SW": + minX = parentBranch.range.minX; + maxX = parentBranch.range.minX + parentBranch.size; + minY = parentBranch.range.minY + parentBranch.size; + maxY = parentBranch.range.maxY; + break; + case "SE": + minX = parentBranch.range.minX + parentBranch.size; + maxX = parentBranch.range.maxX; + minY = parentBranch.range.minY + parentBranch.size; + maxY = parentBranch.range.maxY; + break; + } + + parentBranch.children[region] = { + CenterOfMass:{x:0,y:0}, + mass:0, + range:{minX:minX,maxX:maxX,minY:minY,maxY:maxY}, + size: 0.5 * parentBranch.size, + children: {data:null}, + childrenCount: 0 + }; + }, + + + _drawTree : function(ctx,color) { + if (this.barnesHutTree !== undefined) { + + ctx.lineWidth = 2; + + this._drawBranch(this.barnesHutTree.root,ctx,color); + } + }, + + _drawBranch : function(branch,ctx,color) { + if (color === undefined) { + color = "#FF0000"; + } + + if (branch.childrenCount == 4) { + this._drawBranch(branch.children.NW,ctx); + this._drawBranch(branch.children.NE,ctx); + this._drawBranch(branch.children.SE,ctx); + this._drawBranch(branch.children.SW,ctx); + } + ctx.strokeStyle = color; + ctx.beginPath(); + ctx.moveTo(branch.range.minX,branch.range.minY); + ctx.lineTo(branch.range.maxX,branch.range.minY); + ctx.stroke(); + + ctx.beginPath(); + ctx.moveTo(branch.range.maxX,branch.range.minY); + ctx.lineTo(branch.range.maxX,branch.range.maxY); + ctx.stroke(); + + ctx.beginPath(); + ctx.moveTo(branch.range.maxX,branch.range.maxY); + ctx.lineTo(branch.range.minX,branch.range.maxY); + ctx.stroke(); + + ctx.beginPath(); + ctx.moveTo(branch.range.minX,branch.range.maxY); + ctx.lineTo(branch.range.minX,branch.range.minY); + ctx.stroke(); + + /* + if (branch.mass > 0) { + ctx.circle(branch.CenterOfMass.x, branch.CenterOfMass.y, 3*branch.mass); + ctx.stroke(); + } + */ + } + + + + + + + + + + + + + + + + + + +}; + +function echo() { + switch (arguments.length) { + case 1: + echoN1(arguments[0]); break; + case 2: + echoN2(arguments[0],arguments[1]); break; + case 3: + echoN3(arguments[0],arguments[1],arguments[2]); break; + } +} + +function echoN1(message) { + console.log(message); +} + +function echoN2(message1,message2) { + console.log(message1,message2); +} + +function echoN3(message1,message2,message3) { + console.log(message1,message2,message3); +} /** * Created by Alex on 2/4/14. */ @@ -11362,6 +11923,8 @@ var manipulationMixin = { /** * delete everything in the selection + * TODO : place the alert in the gui. + * * * @private */ @@ -11380,7 +11943,7 @@ var manipulationMixin = { } -} +}; /** * Creation of the SectorMixin var. * @@ -12584,7 +13147,7 @@ var ClusterMixin = { /** * This function will apply the changes made to the remainingEdges during the formation of the clusters. - * This is a seperate function to allow for level-wise collapsing of the node tree. + * This is a seperate function to allow for level-wise collapsing of the node barnesHutTree. * It has to be called if a level is collapsed. It is called by _formClusters(). * @private */ @@ -13170,9 +13733,7 @@ var SelectionMixin = { this.selectionObj = {}; if (doNotTrigger == false) { - this._trigger('select', { - nodes: this.getSelection() - }); + this._trigger('select', this.getSelection()); } }, @@ -13199,9 +13760,7 @@ var SelectionMixin = { } if (doNotTrigger == false) { - this._trigger('select', { - nodes: this.getSelection() - }); + this._trigger('select', this.getSelection()); } }, @@ -13356,9 +13915,7 @@ var SelectionMixin = { this._removeFromSelection(object); } if (doNotTrigger == false) { - this._trigger('select', { - nodes: this.getSelection() - }); + this._trigger('select', this.getSelection()); } }, @@ -13872,15 +14429,13 @@ function Graph (container, data, options) { this.stabilize = true; // stabilize before displaying the graph this.selectable = true; - this.forceFactor = 50000; - // set constant values this.constants = { nodes: { radiusMin: 5, radiusMax: 20, radius: 5, - distance: 100, // px + distance: 100, // px shape: 'ellipse', image: undefined, widthMin: 16, // px @@ -13949,7 +14504,7 @@ function Graph (container, data, options) { dataManipulationToolbar: { enabled: false }, - minVelocity: 2, // px/s + minVelocity: 0.2, // px/s maxIterations: 1000 // maximum number of iteration to stabilize }; @@ -13965,6 +14520,9 @@ function Graph (container, data, options) { this.yIncrement = 0; this.zoomIncrement = 0; + // load the force calculation functions, grouped under the physics system. + this._loadPhysicsSystem(); + // create a frame and canvas this._create(); @@ -14487,6 +15045,7 @@ Graph.prototype._createKeyBinds = function() { this.mousetrap.bind("pagedown",this._zoomOut.bind(me),"keydown"); this.mousetrap.bind("pagedown",this._stopZoom.bind(me), "keyup"); } + this.mousetrap.bind("b",this._formBarnesHutTree.bind(me)); if (this.constants.dataManipulationToolbar.enabled == true) { this.mousetrap.bind("escape",this._createManipulatorBar.bind(me)); @@ -15061,7 +15620,7 @@ Graph.prototype._addNodes = function(ids) { if (!node.isFixed() && this.createNodeOnClick != true) { // TODO: position new nodes in a smarter way! - var radius = this.constants.edges.length * 2; + var radius = this.constants.edges.length; var count = ids.length; var angle = 2 * Math.PI * (i / count); node.x = radius * Math.cos(angle); @@ -15346,6 +15905,8 @@ Graph.prototype._redraw = function() { this._doInAllSectors("_drawEdges",ctx); this._doInAllSectors("_drawNodes",ctx,true); + //this._drawTree(ctx,"#F00F0F"); + // restore original scaling and translation ctx.restore(); @@ -15521,233 +16082,9 @@ Graph.prototype._doStabilize = function() { count++; } this.zoomToFit(); - - // var end = new Date(); - - // console.log('Stabilized in ' + (end-start) + ' ms, ' + count + ' iterations' ); // TODO: cleanup -}; - - -/** - * Before calculating the forces, we check if we need to cluster to keep up performance and we check - * if there is more than one node. If it is just one node, we dont calculate anything. - * - * @private - */ -Graph.prototype._initializeForceCalculation = function() { - // stop calculation if there is only one node - if (this.nodeIndices.length == 1) { - this.nodes[this.nodeIndices[0]]._setForce(0,0); - } - else { - // if there are too many nodes on screen, we cluster without repositioning - if (this.nodeIndices.length > this.constants.clustering.clusterThreshold && this.constants.clustering.enabled == true) { - this.clusterToFit(this.constants.clustering.reduceToNodes, false); - } - - // we now start the force calculation - this._calculateForces(); - } }; -/** - * Calculate the external forces acting on the nodes - * Forces are caused by: edges, repulsing forces between nodes, gravity - * @private - */ -Graph.prototype._calculateForces = function() { -// var screenCenterPos = {"x":(0.5*(this.canvasTopLeft.x + this.canvasBottomRight.x)), -// "y":(0.5*(this.canvasTopLeft.y + this.canvasBottomRight.y))} - // create a local edge to the nodes and edges, that is faster - var dx, dy, angle, distance, fx, fy, - repulsingForce, springForce, length, edgeLength, - node, node1, node2, edge, edgeId, i, j, nodeId, xCenter, yCenter; - var clusterSize; - var nodes = this.nodes; - var edges = this.edges; - - // Gravity is required to keep separated groups from floating off - // the forces are reset to zero in this loop by using _setForce instead - // of _addForce - var gravity = 0.08 * this.forceFactor; - for (i = 0; i < this.nodeIndices.length; i++) { - node = nodes[this.nodeIndices[i]]; - // gravity does not apply when we are in a pocket sector - if (this._sector() == "default") { - dx = -node.x;// + screenCenterPos.x; - dy = -node.y;// + screenCenterPos.y; - - angle = Math.atan2(dy, dx); - fx = Math.cos(angle) * gravity; - fy = Math.sin(angle) * gravity; - } - else { - fx = 0; - fy = 0; - } - node._setForce(fx, fy); - - node.updateDamping(this.nodeIndices.length); - } - - // repulsing forces between nodes - var minimumDistance = this.constants.nodes.distance, - steepness = 10; // higher value gives steeper slope of the force around the given minimumDistance - - - // we loop from i over all but the last entree in the array - // j loops from i+1 to the last. This way we do not double count any of the indices, nor i == j - var a_base = (-2/3); var b = 4/3; - for (i = 0; i < this.nodeIndices.length-1; i++) { - node1 = nodes[this.nodeIndices[i]]; - for (j = i+1; j < this.nodeIndices.length; j++) { - node2 = nodes[this.nodeIndices[j]]; - clusterSize = (node1.clusterSize + node2.clusterSize - 2); - dx = node2.x - node1.x; - dy = node2.y - node1.y; - distance = Math.sqrt(dx * dx + dy * dy); - - - // clusters have a larger region of influence - minimumDistance = (clusterSize == 0) ? this.constants.nodes.distance : (this.constants.nodes.distance * (1 + clusterSize * this.constants.clustering.distanceAmplification)); - var a = a_base / minimumDistance; - if (distance < 2*minimumDistance) { // at 2.0 * the minimum distance, the force is 0.000045 - angle = Math.atan2(dy, dx); - - if (distance < 0.5*minimumDistance) { // at 0.5 * the minimum distance, the force is 0.993307 - repulsingForce = 1.0; - } - else { - // TODO: correct factor for repulsing force - //repulsingForce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force - //repulsingForce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force - //repulsingForce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)); // TODO: customize the repulsing force - repulsingForce = a * distance + b; // TODO: test the approximation of the function above - } - // amplify the repulsion for clusters. - repulsingForce *= (clusterSize == 0) ? 1 : 1 + clusterSize * this.constants.clustering.forceAmplification; - repulsingForce *= this.forceFactor; - - fx = Math.cos(angle) * repulsingForce; - fy = Math.sin(angle) * repulsingForce ; - - node1._addForce(-fx, -fy); - node2._addForce(fx, fy); - } - } - } - -/* - // repulsion of the edges on the nodes and - for (var nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - node = nodes[nodeId]; - for(var edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - - // get the center of the edge - xCenter = edge.from.x+(edge.to.x - edge.from.x)/2; - yCenter = edge.from.y+(edge.to.y - edge.from.y)/2; - - // calculate normally distributed force - dx = node.x - xCenter; - dy = node.y - yCenter; - distance = Math.sqrt(dx * dx + dy * dy); - if (distance < 2*minimumDistance) { // at 2.0 * the minimum distance, the force is 0.000045 - angle = Math.atan2(dy, dx); - - if (distance < 0.5*minimumDistance) { // at 0.5 * the minimum distance, the force is 0.993307 - repulsingForce = 1.0; - } - else { - // TODO: correct factor for repulsing force - //var repulsingforce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force - //repulsingforce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ), // TODO: customize the repulsing force - repulsingForce = 1 / (1 + Math.exp((distance / (minimumDistance / 2) - 1) * steepness)); // TODO: customize the repulsing force - } - fx = Math.cos(angle) * repulsingForce; - fy = Math.sin(angle) * repulsingForce; - node._addForce(fx, fy); - edge.from._addForce(-fx/2,-fy/2); - edge.to._addForce(-fx/2,-fy/2); - } - } - } - } - } -*/ - - // forces caused by the edges, modelled as springs - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.connected) { - // only calculate forces if nodes are in the same sector - if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { - clusterSize = (edge.to.clusterSize + edge.from.clusterSize - 2); - dx = (edge.to.x - edge.from.x); - dy = (edge.to.y - edge.from.y); - //edgeLength = (edge.from.width + edge.from.height + edge.to.width + edge.to.height)/2 || edge.length; // TODO: dmin - //edgeLength = (edge.from.width + edge.to.width)/2 || edge.length; // TODO: dmin - //edgeLength = 20 + ((edge.from.width + edge.to.width) || 0) / 2; - edgeLength = edge.length; - // this implies that the edges between big clusters are longer - edgeLength += clusterSize * this.constants.clustering.edgeGrowth; - length = Math.sqrt(dx * dx + dy * dy); - angle = Math.atan2(dy, dx); - - springForce = edge.stiffness * (edgeLength - length) * this.forceFactor; - - fx = Math.cos(angle) * springForce; - fy = Math.sin(angle) * springForce; - - edge.from._addForce(-fx, -fy); - edge.to._addForce(fx, fy); - } - } - } - } -/* - // TODO: re-implement repulsion of edges - - // repulsing forces between edges - var minimumDistance = this.constants.edges.distance, - steepness = 10; // higher value gives steeper slope of the force around the given minimumDistance - for (var l = 0; l < edges.length; l++) { - //Keep distance from other edge centers - for (var l2 = l + 1; l2 < this.edges.length; l2++) { - //var dmin = (nodes[n].width + nodes[n].height + nodes[n2].width + nodes[n2].height) / 1 || minimumDistance, // TODO: dmin - //var dmin = (nodes[n].width + nodes[n2].width)/2 || minimumDistance, // TODO: dmin - //dmin = 40 + ((nodes[n].width/2 + nodes[n2].width/2) || 0), - var lx = edges[l].from.x+(edges[l].to.x - edges[l].from.x)/2, - ly = edges[l].from.y+(edges[l].to.y - edges[l].from.y)/2, - l2x = edges[l2].from.x+(edges[l2].to.x - edges[l2].from.x)/2, - l2y = edges[l2].from.y+(edges[l2].to.y - edges[l2].from.y)/2, - - // calculate normally distributed force - dx = l2x - lx, - dy = l2y - ly, - distance = Math.sqrt(dx * dx + dy * dy), - angle = Math.atan2(dy, dx), - - - // TODO: correct factor for repulsing force - //var repulsingforce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force - //repulsingforce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ), // TODO: customize the repulsing force - repulsingforce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)), // TODO: customize the repulsing force - fx = Math.cos(angle) * repulsingforce, - fy = Math.sin(angle) * repulsingforce; - - edges[l].from._addForce(-fx, -fy); - edges[l].to._addForce(-fx, -fy); - edges[l2].from._addForce(fx, fy); - edges[l2].to._addForce(fx, fy); - } - } -*/ -}; /** @@ -15776,14 +16113,25 @@ Graph.prototype._isMoving = function(vmin) { * @private */ Graph.prototype._discreteStepNodes = function() { - var interval = 0.01; + var interval = 1.0; var nodes = this.nodes; - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - nodes[id].discreteStep(interval); + + this.constants.maxVelocity = 30; + + if (this.constants.maxVelocity > 0) { + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + nodes[id].discreteStepLimited(interval, this.constants.maxVelocity); + } + } + } + else { + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + nodes[id].discreteStep(interval); + } } } - var vmin = this.constants.minVelocity; this.moving = this._isMoving(vmin); }; @@ -15831,7 +16179,6 @@ Graph.prototype.start = function() { //this.time = this.end - this.startTime; //console.log('refresh time: ' + this.time); //this.startTime = window.performance.now(); - }, this.renderTimestep); } } @@ -15870,6 +16217,22 @@ Graph.prototype.toggleFreeze = function() { } }; + + +/** + * Mixin the physics system and initialize the parameters required. + * + * @private + */ +Graph.prototype._loadPhysicsSystem = function() { + for (var mixinFunction in physicsMixin) { + if (physicsMixin.hasOwnProperty(mixinFunction)) { + Graph.prototype[mixinFunction] = physicsMixin[mixinFunction]; + } + } +}; + + /** * Mixin the cluster system and initialize the parameters required. * diff --git a/dist/vis.min.js b/dist/vis.min.js index 3da5db1c..d32451d9 100644 --- a/dist/vis.min.js +++ b/dist/vis.min.js @@ -5,7 +5,7 @@ * A dynamic, browser-based visualization library. * * @version 0.5.0-SNAPSHOT - * @date 2014-02-05 + * @date 2014-02-07 * * @license * Copyright (C) 2011-2014 Almende B.V, http://almende.com @@ -22,10 +22,10 @@ * License for the specific language governing permissions and limitations under * the License. */ -!function(t){if("object"==typeof exports)module.exports=t();else if("function"==typeof define&&define.amd)define(t);else{var e;"undefined"!=typeof window?e=window:"undefined"!=typeof global?e=global:"undefined"!=typeof self&&(e=self),e.vis=t()}}(function(){var t;return function e(t,i,n){function s(r,a){if(!i[r]){if(!t[r]){var h="function"==typeof require&&require;if(!a&&h)return h(r,!0);if(o)return o(r,!0);throw new Error("Cannot find module '"+r+"'")}var c=i[r]={exports:{}};t[r][0].call(c.exports,function(e){var i=t[r][1][e];return s(i?i:e)},c,c.exports,e,t,i,n)}return i[r].exports}for(var o="function"==typeof require&&require,r=0;ri;++i)t.call(e||this,this[i],i,this)}),Array.prototype.map||(Array.prototype.map=function(t,e){var i,n,s;if(null==this)throw new TypeError(" this is null or not defined");var o=Object(this),r=o.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(e&&(i=e),n=new Array(r),s=0;r>s;){var a,h;s in o&&(a=o[s],h=t.call(i,a,s,o),n[s]=h),s++}return n}),Array.prototype.filter||(Array.prototype.filter=function(t){"use strict";if(null==this)throw new TypeError;var e=Object(this),i=e.length>>>0;if("function"!=typeof t)throw new TypeError;for(var n=[],s=arguments[1],o=0;i>o;o++)if(o in e){var r=e[o];t.call(s,r,o,e)&&n.push(r)}return n}),Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,e=!{toString:null}.propertyIsEnumerable("toString"),i=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],n=i.length;return function(s){if("object"!=typeof s&&"function"!=typeof s||null===s)throw new TypeError("Object.keys called on non-object");var o=[];for(var r in s)t.call(s,r)&&o.push(r);if(e)for(var a=0;n>a;a++)t.call(s,i[a])&&o.push(i[a]);return o}}()),Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s}),Object.create||(Object.create=function(t){function e(){}if(arguments.length>1)throw new Error("Object.create implementation only accepts the first parameter.");return e.prototype=t,new e}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s});var z={};z.isNumber=function(t){return t instanceof Number||"number"==typeof t},z.isString=function(t){return t instanceof String||"string"==typeof t},z.isDate=function(t){if(t instanceof Date)return!0;if(z.isString(t)){var e=P.exec(t);if(e)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},z.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},z.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},z.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var n=arguments[e];for(var s in n)n.hasOwnProperty(s)&&void 0!==n[s]&&(t[s]=n[s])}return t},z.convert=function(t,e){var i;if(void 0===t)return void 0;if(null===t)return null;if(!e)return t;if("string"!=typeof e&&!(e instanceof String))throw new Error("Type must be a string");switch(e){case"boolean":case"Boolean":return Boolean(t);case"number":case"Number":return Number(t.valueOf());case"string":case"String":return String(t);case"Date":if(z.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(L.isMoment(t))return new Date(t.valueOf());if(z.isString(t))return i=P.exec(t),i?new Date(Number(i[1])):L(t).toDate();throw new Error("Cannot convert object of type "+z.getType(t)+" to type Date");case"Moment":if(z.isNumber(t))return L(t);if(t instanceof Date)return L(t.valueOf());if(L.isMoment(t))return L(t);if(z.isString(t))return i=P.exec(t),L(i?Number(i[1]):t);throw new Error("Cannot convert object of type "+z.getType(t)+" to type Date");case"ISODate":if(z.isNumber(t))return new Date(t);if(t instanceof Date)return t.toISOString();if(L.isMoment(t))return t.toDate().toISOString();if(z.isString(t))return i=P.exec(t),i?new Date(Number(i[1])).toISOString():new Date(t).toISOString();throw new Error("Cannot convert object of type "+z.getType(t)+" to type ISODate");case"ASPDate":if(z.isNumber(t))return"/Date("+t+")/";if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(z.isString(t)){i=P.exec(t);var n;return n=i?new Date(Number(i[1])).valueOf():new Date(t).valueOf(),"/Date("+n+")/"}throw new Error("Cannot convert object of type "+z.getType(t)+" to type ASPDate");default:throw new Error("Cannot convert object of type "+z.getType(t)+' to type "'+e+'"')}};var P=/^\/?Date\((\-?\d+)/i;z.getType=function(t){var e=typeof t;return"object"==e?null==t?"null":t instanceof Boolean?"Boolean":t instanceof Number?"Number":t instanceof String?"String":t instanceof Array?"Array":t instanceof Date?"Date":"Object":"number"==e?"Number":"boolean"==e?"Boolean":"string"==e?"String":e},z.getAbsoluteLeft=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetLeft,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetLeft,n-=s.scrollLeft,s=s.offsetParent;return n},z.getAbsoluteTop=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetTop,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetTop,n-=s.scrollTop,s=s.offsetParent;return n},z.getPageY=function(t){if("pageY"in t)return t.pageY;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientY:t.clientY;var i=document.documentElement,n=document.body;return e+(i&&i.scrollTop||n&&n.scrollTop||0)-(i&&i.clientTop||n&&n.clientTop||0)},z.getPageX=function(t){if("pageY"in t)return t.pageX;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientX:t.clientX;var i=document.documentElement,n=document.body;return e+(i&&i.scrollLeft||n&&n.scrollLeft||0)-(i&&i.clientLeft||n&&n.clientLeft||0)},z.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},z.removeClassName=function(t,e){var i=t.className.split(" "),n=i.indexOf(e);-1!=n&&(i.splice(n,1),t.className=i.join(" "))},z.forEach=function(t,e){var i,n;if(t instanceof Array)for(i=0,n=t.length;n>i;i++)e(t[i],i,t);else for(i in t)t.hasOwnProperty(i)&&e(t[i],i,t)},z.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},z.addEventListener=function(t,e,i,n){t.addEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.addEventListener(e,i,n)):t.attachEvent("on"+e,i)},z.removeEventListener=function(t,e,i,n){t.removeEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.removeEventListener(e,i,n)):t.detachEvent("on"+e,i)},z.getTarget=function(t){t||(t=window.event);var e;return t.target?e=t.target:t.srcElement&&(e=t.srcElement),void 0!=e.nodeType&&3==e.nodeType&&(e=e.parentNode),e},z.stopPropagation=function(t){t||(t=window.event),t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},z.fakeGesture=function(t,e){var i=null;return N.event.collectEventData(this,i,e)},z.preventDefault=function(t){t||(t=window.event),t.preventDefault?t.preventDefault():t.returnValue=!1},z.option={},z.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},z.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},z.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?String(t):e||null},z.option.asSize=function(t,e){return"function"==typeof t&&(t=t()),z.isString(t)?t:z.isNumber(t)?t+"px":e||null},z.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null},utli.hexToRGB=function(t){var e=GiveDec(t.substring(0,1)),i=GiveDec(t.substring(1,2)),n=GiveDec(t.substring(2,3)),s=GiveDec(t.substring(3,4)),o=GiveDec(t.substring(4,5)),r=GiveDec(t.substring(5,6)),a=16*e+i,h=16*n+s,i=16*o+r;return{r:a,g:h,b:i}},utli.RGBToHex=function(t,e,i){var n=GiveHex(Math.floor(t/16)),s=GiveHex(t%16),o=GiveHex(Math.floor(e/16)),r=GiveHex(e%16),a=GiveHex(Math.floor(i/16)),h=GiveHex(i%16),c=n+s+o+r+a+h;return c},utli.RGBToHSV=function(t,e,i){t/=255,e/=255,i/=255;var n=Math.min(t,Math.min(e,i)),s=Math.max(t,Math.max(e,i));if(n==s)return{h:0,s:0,v:n};var o=t==n?e-i:i==n?t-e:i-t,r=t==n?3:i==n?1:5,a=60*(r-o/(s-n)),h=(s-n)/s,c=s;return{h:a,s:h,v:c}},z.HSVToRGB=function(t,e,i){var n,s,o,r,a,h,c,d;switch(t&&void 0===e&&void 0===i&&(e=t.s,i=t.v,t=t.h),r=Math.floor(6*t),a=6*t-r,h=i*(1-e),c=i*(1-a*e),d=i*(1-(1-a)*e),r%6){case 0:n=i,s=d,o=h;break;case 1:n=c,s=i,o=h;break;case 2:n=h,s=i,o=d;break;case 3:n=h,s=c,o=i;break;case 4:n=d,s=h,o=i;break;case 5:n=i,s=h,o=c}return{r:Math.floor(255*n),g:Math.floor(255*s),b:Math.floor(255*o)}};var F={listeners:[],indexOf:function(t){for(var e=this.listeners,i=0,n=this.listeners.length;n>i;i++){var s=e[i];if(s&&s.object==t)return i}return-1},addListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];s||(s={object:t,events:{}},this.listeners.push(s));var o=s.events[e];o||(o=[],s.events[e]=o),-1==o.indexOf(i)&&o.push(i)},removeListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];o&&(n=o.indexOf(i),-1!=n&&o.splice(n,1),0==o.length&&delete s.events[e]);var r=0,a=s.events;for(var h in a)a.hasOwnProperty(h)&&r++;0==r&&delete this.listeners[n]}},removeAllListeners:function(){this.listeners=[]},trigger:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];if(o)for(var r=0,a=o.length;a>r;r++)o[r](i)}}};s.prototype.on=function(t,e,i){var n=t instanceof RegExp?t:new RegExp(t.replace("*","\\w+")),s={id:z.randomUUID(),event:t,regexp:n,callback:"function"==typeof e?e:null,target:i};return this.subscriptions.push(s),s.id},s.prototype.off=function(t){for(var e=0;eo;o++)i=s._addItem(t[o]),n.push(i);else if(z.isDataTable(t))for(var a=this._getColumnNames(t),h=0,c=t.getNumberOfRows();c>h;h++){for(var d={},l=0,u=a.length;u>l;l++){var p=a[l];d[p]=t.getValue(h,l)}i=s._addItem(d),n.push(i)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");i=s._addItem(t),n.push(i)}return n.length&&this._trigger("add",{items:n},e),n},o.prototype.update=function(t,e){var i=[],n=[],s=this,o=s.fieldId,r=function(t){var e=t[o];s.data[e]?(e=s._updateItem(t),n.push(e)):(e=s._addItem(t),i.push(e))};if(t instanceof Array)for(var a=0,h=t.length;h>a;a++)r(t[a]);else if(z.isDataTable(t))for(var c=this._getColumnNames(t),d=0,l=t.getNumberOfRows();l>d;d++){for(var u={},p=0,f=c.length;f>p;p++){var g=c[p];u[g]=t.getValue(d,p)}r(u)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");r(t)}return i.length&&this._trigger("add",{items:i},e),n.length&&this._trigger("update",{items:n},e),i.concat(n)},o.prototype.get=function(){var t,e,i,n,s=this,o=this.showInternalIds,r=z.getType(arguments[0]);"String"==r||"Number"==r?(t=arguments[0],i=arguments[1],n=arguments[2]):"Array"==r?(e=arguments[0],i=arguments[1],n=arguments[2]):(i=arguments[0],n=arguments[1]);var a;if(i&&i.type){if(a="DataTable"==i.type?"DataTable":"Array",n&&a!=z.getType(n))throw new Error('Type of parameter "data" ('+z.getType(n)+") does not correspond with specified options.type ("+i.type+")");if("DataTable"==a&&!z.isDataTable(n))throw new Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else a=n?"DataTable"==z.getType(n)?"DataTable":"Array":"Array";void 0!=i&&void 0!=i.showInternalIds&&(this.showInternalIds=i.showInternalIds);var h,c,d,l,u=i&&i.convert||this.options.convert,p=i&&i.filter,f=[];if(void 0!=t)h=s._getItem(t,u),p&&!p(h)&&(h=null);else if(void 0!=e)for(d=0,l=e.length;l>d;d++)h=s._getItem(e[d],u),(!p||p(h))&&f.push(h);else for(c in this.data)this.data.hasOwnProperty(c)&&(h=s._getItem(c,u),(!p||p(h))&&f.push(h));if(this.showInternalIds=o,i&&i.order&&void 0==t&&this._sort(f,i.order),i&&i.fields){var g=i.fields;if(void 0!=t)h=this._filterFields(h,g);else for(d=0,l=f.length;l>d;d++)f[d]=this._filterFields(f[d],g)}if("DataTable"==a){var m=this._getColumnNames(n);if(void 0!=t)s._appendRow(n,m,h);else for(d=0,l=f.length;l>d;d++)s._appendRow(n,m,f[d]);return n}if(void 0!=t)return h;if(n){for(d=0,l=f.length;l>d;d++)n.push(f[d]);return n}return f},o.prototype.getIds=function(t){var e,i,n,s,o,r=this.data,a=t&&t.filter,h=t&&t.order,c=t&&t.convert||this.options.convert,d=[];if(a)if(h){o=[];for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,c),a(s)&&o.push(s));for(this._sort(o,h),e=0,i=o.length;i>e;e++)d[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,c),a(s)&&d.push(s[this.fieldId]));else if(h){o=[];for(n in r)r.hasOwnProperty(n)&&o.push(r[n]);for(this._sort(o,h),e=0,i=o.length;i>e;e++)d[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=r[n],d.push(s[this.fieldId]));return d},o.prototype.forEach=function(t,e){var i,n,s=e&&e.filter,o=e&&e.convert||this.options.convert,r=this.data;if(e&&e.order)for(var a=this.get(e),h=0,c=a.length;c>h;h++)i=a[h],n=i[this.fieldId],t(i,n);else for(n in r)r.hasOwnProperty(n)&&(i=this._getItem(n,o),(!s||s(i))&&t(i,n))},o.prototype.map=function(t,e){var i,n=e&&e.filter,s=e&&e.convert||this.options.convert,o=[],r=this.data;for(var a in r)r.hasOwnProperty(a)&&(i=this._getItem(a,s),(!n||n(i))&&o.push(t(i,a)));return e&&e.order&&this._sort(o,e.order),o},o.prototype._filterFields=function(t,e){var i={};for(var n in t)t.hasOwnProperty(n)&&-1!=e.indexOf(n)&&(i[n]=t[n]);return i},o.prototype._sort=function(t,e){if(z.isString(e)){var i=e;t.sort(function(t,e){var n=t[i],s=e[i];return n>s?1:s>n?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},o.prototype.remove=function(t,e){var i,n,s,o=[];if(t instanceof Array)for(i=0,n=t.length;n>i;i++)s=this._remove(t[i]),null!=s&&o.push(s);else s=this._remove(t),null!=s&&o.push(s);return o.length&&this._trigger("remove",{items:o},e),o},o.prototype._remove=function(t){if(z.isNumber(t)||z.isString(t)){if(this.data[t])return delete this.data[t],delete this.internalIds[t],t}else if(t instanceof Object){var e=t[this.fieldId];if(e&&this.data[e])return delete this.data[e],delete this.internalIds[e],e}return null},o.prototype.clear=function(t){var e=Object.keys(this.data);return this.data={},this.internalIds={},this._trigger("remove",{items:e},t),e},o.prototype.max=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||r>n)&&(i=o,n=r)}return i},o.prototype.min=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||n>r)&&(i=o,n=r)}return i},o.prototype.distinct=function(t){var e=this.data,i=[],n=this.options.convert[t],s=0;for(var o in e)if(e.hasOwnProperty(o)){for(var r=e[o],a=z.convert(r[t],n),h=!1,c=0;s>c;c++)if(i[c]==a){h=!0;break}h||(i[s]=a,s++)}return i},o.prototype._addItem=function(t){var e=t[this.fieldId];if(void 0!=e){if(this.data[e])throw new Error("Cannot add item: item with id "+e+" already exists")}else e=z.randomUUID(),t[this.fieldId]=e,this.internalIds[e]=t;var i={};for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=z.convert(t[n],s)}return this.data[e]=i,e},o.prototype._getItem=function(t,e){var i,n,s=this.data[t];if(!s)return null;var o={},r=this.fieldId,a=this.internalIds;if(e)for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a&&!this.showInternalIds||(o[i]=z.convert(n,e[i])));else for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a&&!this.showInternalIds||(o[i]=n));return o},o.prototype._updateItem=function(t){var e=t[this.fieldId];if(void 0==e)throw new Error("Cannot update item: item has no id (item: "+JSON.stringify(t)+")");var i=this.data[e];if(!i)throw new Error("Cannot update item: no item with id "+e+" found");for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=z.convert(t[n],s)}return e},o.prototype.isInternalId=function(t){return t in this.internalIds},o.prototype._getColumnNames=function(t){for(var e=[],i=0,n=t.getNumberOfColumns();n>i;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},o.prototype._appendRow=function(t,e,i){for(var n=t.addRow(),s=0,o=e.length;o>s;s++){var r=e[s];t.setValue(n,s,i[r])}},r.prototype.setData=function(t){var e,i,n;if(this.data){this.data.unsubscribe&&this.data.unsubscribe("*",this.listener),e=[];for(var s in this.ids)this.ids.hasOwnProperty(s)&&e.push(s);this.ids={},this._trigger("remove",{items:e})}if(this.data=t,this.data){for(this.fieldId=this.options.fieldId||this.data&&this.data.options&&this.data.options.fieldId||"id",e=this.data.getIds({filter:this.options&&this.options.filter}),i=0,n=e.length;n>i;i++)s=e[i],this.ids[s]=!0;this._trigger("add",{items:e}),this.data.subscribe&&this.data.subscribe("*",this.listener)}},r.prototype.get=function(){var t,e,i,n=this,s=z.getType(arguments[0]);"String"==s||"Number"==s||"Array"==s?(t=arguments[0],e=arguments[1],i=arguments[2]):(e=arguments[0],i=arguments[1]);var o=z.extend({},this.options,e);this.options.filter&&e&&e.filter&&(o.filter=function(t){return n.options.filter(t)&&e.filter(t)});var r=[];return void 0!=t&&r.push(t),r.push(o),r.push(i),this.data&&this.data.get.apply(this.data,r)},r.prototype.getIds=function(t){var e;if(this.data){var i,n=this.options.filter;i=t&&t.filter?n?function(e){return n(e)&&t.filter(e)}:t.filter:n,e=this.data.getIds({filter:i,order:t&&t.order})}else e=[];return e},r.prototype._onEvent=function(t,e,i){var n,s,o,r,a=e&&e.items,h=this.data,c=[],d=[],l=[];if(a&&h){switch(t){case"add":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r&&(this.ids[o]=!0,c.push(o));break;case"update":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r?this.ids[o]?d.push(o):(this.ids[o]=!0,c.push(o)):this.ids[o]&&(delete this.ids[o],l.push(o));break;case"remove":for(n=0,s=a.length;s>n;n++)o=a[n],this.ids[o]&&(delete this.ids[o],l.push(o))}c.length&&this._trigger("add",{items:c},i),d.length&&this._trigger("update",{items:d},i),l.length&&this._trigger("remove",{items:l},i)}},r.prototype.subscribe=o.prototype.subscribe,r.prototype.unsubscribe=o.prototype.unsubscribe,r.prototype._trigger=o.prototype._trigger,TimeStep=function(t,e,i){this.current=new Date,this._start=new Date,this._end=new Date,this.autoScale=!0,this.scale=TimeStep.SCALE.DAY,this.step=1,this.setRange(t,e,i)},TimeStep.SCALE={MILLISECOND:1,SECOND:2,MINUTE:3,HOUR:4,DAY:5,WEEKDAY:6,MONTH:7,YEAR:8},TimeStep.prototype.setRange=function(t,e,i){if(!(t instanceof Date&&e instanceof Date))throw"No legal start or end date in method setRange";this._start=void 0!=t?new Date(t.valueOf()):new Date,this._end=void 0!=e?new Date(e.valueOf()):new Date,this.autoScale&&this.setMinimumStep(i)},TimeStep.prototype.first=function(){this.current=new Date(this._start.valueOf()),this.roundToMinor()},TimeStep.prototype.roundToMinor=function(){switch(this.scale){case TimeStep.SCALE.YEAR:this.current.setFullYear(this.step*Math.floor(this.current.getFullYear()/this.step)),this.current.setMonth(0); -case TimeStep.SCALE.MONTH:this.current.setDate(1);case TimeStep.SCALE.DAY:case TimeStep.SCALE.WEEKDAY:this.current.setHours(0);case TimeStep.SCALE.HOUR:this.current.setMinutes(0);case TimeStep.SCALE.MINUTE:this.current.setSeconds(0);case TimeStep.SCALE.SECOND:this.current.setMilliseconds(0)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.setMilliseconds(this.current.getMilliseconds()-this.current.getMilliseconds()%this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()-this.current.getSeconds()%this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()-this.current.getMinutes()%this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()-this.current.getHours()%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()-1-(this.current.getDate()-1)%this.step+1);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()-this.current.getMonth()%this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()-this.current.getFullYear()%this.step)}},TimeStep.prototype.hasNext=function(){return this.current.valueOf()<=this._end.valueOf()},TimeStep.prototype.next=function(){var t=this.current.valueOf();if(this.current.getMonth()<6)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current=new Date(this.current.valueOf()+1e3*this.step);break;case TimeStep.SCALE.MINUTE:this.current=new Date(this.current.valueOf()+1e3*this.step*60);break;case TimeStep.SCALE.HOUR:this.current=new Date(this.current.valueOf()+1e3*this.step*60*60);var e=this.current.getHours();this.current.setHours(e-e%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}else switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()+this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()+this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()+this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.getMilliseconds()0&&(this.step=e),this.autoScale=!1},TimeStep.prototype.setAutoScale=function(t){this.autoScale=t},TimeStep.prototype.setMinimumStep=function(t){if(void 0!=t){var e=31104e6,i=2592e6,n=864e5,s=36e5,o=6e4,r=1e3,a=1;1e3*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1e3),500*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=500),100*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=100),50*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=50),10*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=10),5*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=5),e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1),3*i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=3),i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=1),5*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=5),2*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=2),n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=1),n/2>t&&(this.scale=TimeStep.SCALE.WEEKDAY,this.step=1),4*s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=4),s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=1),15*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=15),10*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=10),5*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=5),o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=1),15*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=15),10*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=10),5*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=5),r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=1),200*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=200),100*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=100),50*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=50),10*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=10),5*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=5),a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=1)}},TimeStep.prototype.snap=function(t){if(this.scale==TimeStep.SCALE.YEAR){var e=t.getFullYear()+Math.round(t.getMonth()/12);t.setFullYear(Math.round(e/this.step)*this.step),t.setMonth(0),t.setDate(0),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MONTH)t.getDate()>15?(t.setDate(1),t.setMonth(t.getMonth()+1)):t.setDate(1),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0);else if(this.scale==TimeStep.SCALE.DAY||this.scale==TimeStep.SCALE.WEEKDAY){switch(this.step){case 5:case 2:t.setHours(24*Math.round(t.getHours()/24));break;default:t.setHours(12*Math.round(t.getHours()/12))}t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.HOUR){switch(this.step){case 4:t.setMinutes(60*Math.round(t.getMinutes()/60));break;default:t.setMinutes(30*Math.round(t.getMinutes()/30))}t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MINUTE){switch(this.step){case 15:case 10:t.setMinutes(5*Math.round(t.getMinutes()/5)),t.setSeconds(0);break;case 5:t.setSeconds(60*Math.round(t.getSeconds()/60));break;default:t.setSeconds(30*Math.round(t.getSeconds()/30))}t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.SECOND)switch(this.step){case 15:case 10:t.setSeconds(5*Math.round(t.getSeconds()/5)),t.setMilliseconds(0);break;case 5:t.setMilliseconds(1e3*Math.round(t.getMilliseconds()/1e3));break;default:t.setMilliseconds(500*Math.round(t.getMilliseconds()/500))}else if(this.scale==TimeStep.SCALE.MILLISECOND){var i=this.step>5?this.step/2:1;t.setMilliseconds(Math.round(t.getMilliseconds()/i)*i)}},TimeStep.prototype.isMajor=function(){switch(this.scale){case TimeStep.SCALE.MILLISECOND:return 0==this.current.getMilliseconds();case TimeStep.SCALE.SECOND:return 0==this.current.getSeconds();case TimeStep.SCALE.MINUTE:return 0==this.current.getHours()&&0==this.current.getMinutes();case TimeStep.SCALE.HOUR:return 0==this.current.getHours();case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return 1==this.current.getDate();case TimeStep.SCALE.MONTH:return 0==this.current.getMonth();case TimeStep.SCALE.YEAR:return!1;default:return!1}},TimeStep.prototype.getLabelMinor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return L(t).format("SSS");case TimeStep.SCALE.SECOND:return L(t).format("s");case TimeStep.SCALE.MINUTE:return L(t).format("HH:mm");case TimeStep.SCALE.HOUR:return L(t).format("HH:mm");case TimeStep.SCALE.WEEKDAY:return L(t).format("ddd D");case TimeStep.SCALE.DAY:return L(t).format("D");case TimeStep.SCALE.MONTH:return L(t).format("MMM");case TimeStep.SCALE.YEAR:return L(t).format("YYYY");default:return""}},TimeStep.prototype.getLabelMajor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return L(t).format("HH:mm:ss");case TimeStep.SCALE.SECOND:return L(t).format("D MMMM HH:mm");case TimeStep.SCALE.MINUTE:case TimeStep.SCALE.HOUR:return L(t).format("ddd D MMMM");case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return L(t).format("MMMM YYYY");case TimeStep.SCALE.MONTH:return L(t).format("YYYY");case TimeStep.SCALE.YEAR:return"";default:return""}},a.prototype.setOptions=function(t){z.extend(this.options,t)},a.prototype.update=function(){this._order(),this._stack()},a.prototype._order=function(){var t=this.parent.items;if(!t)throw new Error("Cannot stack items: parent does not contain items");var e=[],i=0;z.forEach(t,function(t){t.visible&&(e[i]=t,i++)});var n=this.options.order||this.defaultOptions.order;if("function"!=typeof n)throw new Error("Option order must be a function");e.sort(n),this.ordered=e},a.prototype._stack=function(){var t,e,i,n=this.ordered,s=this.options,o=s.orientation||this.defaultOptions.orientation,r="top"==o;for(i=s.margin&&void 0!==s.margin.item?s.margin.item:this.defaultOptions.margin.item,t=0,e=n.length;e>t;t++){var a=n[t],h=null;do h=this.checkOverlap(n,t,0,t-1,i),null!=h&&(a.top=r?h.top+h.height+i:h.top-a.height-i);while(h)}},a.prototype.checkOverlap=function(t,e,i,n,s){for(var o=this.collision,r=t[e],a=n;a>=i;a--){var h=t[a];if(o(r,h,s)&&a!=e)return h}return null},a.prototype.collision=function(t,e,i){return t.left-ie.left&&t.top-ie.top},h.prototype.setOptions=function(t){z.extend(this.options,t),null!==this.start&&null!==this.end&&this.setRange(this.start,this.end)},h.prototype.subscribe=function(t,e,i){function n(e){s._onMouseWheel(e,t,i)}var s=this;if("move"==e)t.on("dragstart",function(e){s._onDragStart(e,t)}),t.on("drag",function(e){s._onDrag(e,t,i)}),t.on("dragend",function(e){s._onDragEnd(e,t)});else{if("zoom"!=e)throw new TypeError('Unknown event "'+e+'". Choose "move" or "zoom".');t.on("mousewheel",n),t.on("DOMMouseScroll",n),t.on("touch",function(){s._onTouch()}),t.on("pinch",function(e){s._onPinch(e,t,i)})}},h.prototype.on=function(t,e){var i=["rangechange","rangechanged"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());F.addListener(this,t,e)},h.prototype.off=function(t,e){F.removeListener(this,t,e)},h.prototype._trigger=function(t){F.trigger(this,t,{start:this.start,end:this.end})},h.prototype.setRange=function(t,e){var i=this._applyRange(t,e);i&&(this._trigger("rangechange"),this._trigger("rangechanged"))},h.prototype._applyRange=function(t,e){var i,n=null!=t?z.convert(t,"Date").valueOf():this.start,s=null!=e?z.convert(e,"Date").valueOf():this.end,o=null!=this.options.max?z.convert(this.options.max,"Date").valueOf():null,r=null!=this.options.min?z.convert(this.options.min,"Date").valueOf():null;if(isNaN(n)||null===n)throw new Error('Invalid start "'+t+'"');if(isNaN(s)||null===s)throw new Error('Invalid end "'+e+'"');if(n>s&&(s=n),null!==r&&r>n&&(i=r-n,n+=i,s+=i,null!=o&&s>o&&(s=o)),null!==o&&s>o&&(i=s-o,n-=i,s-=i,null!=r&&r>n&&(n=r)),null!==this.options.zoomMin){var a=parseFloat(this.options.zoomMin);0>a&&(a=0),a>s-n&&(this.end-this.start===a?(n=this.start,s=this.end):(i=a-(s-n),n-=i/2,s+=i/2))}if(null!==this.options.zoomMax){var h=parseFloat(this.options.zoomMax);0>h&&(h=0),s-n>h&&(this.end-this.start===h?(n=this.start,s=this.end):(i=s-n-h,n+=i/2,s-=i/2))}var c=this.start!=n||this.end!=s;return this.start=n,this.end=s,c},h.prototype.getRange=function(){return{start:this.start,end:this.end}},h.prototype.conversion=function(t){return h.conversion(this.start,this.end,t)},h.conversion=function(t,e,i){return 0!=i&&e-t!=0?{offset:t,scale:i/(e-t)}:{offset:0,scale:1}};var Y={};h.prototype._onDragStart=function(t,e){if(!Y.pinching){Y.start=this.start,Y.end=this.end;var i=e.frame;i&&(i.style.cursor="move")}},h.prototype._onDrag=function(t,e,i){if(c(i),!Y.pinching){var n="horizontal"==i?t.gesture.deltaX:t.gesture.deltaY,s=Y.end-Y.start,o="horizontal"==i?e.width:e.height,r=-n/o*s;this._applyRange(Y.start+r,Y.end+r),this._trigger("rangechange")}},h.prototype._onDragEnd=function(t,e){Y.pinching||(e.frame&&(e.frame.style.cursor="auto"),this._trigger("rangechanged"))},h.prototype._onMouseWheel=function(t,e,i){c(i);var n=0;if(t.wheelDelta?n=t.wheelDelta/120:t.detail&&(n=-t.detail/3),n){var s;s=0>n?1-n/5:1/(1+n/5);var o=z.fakeGesture(this,t),r=d(o.touches[0],e.frame),a=this._pointerToDate(e,i,r);this.zoom(s,a)}z.preventDefault(t)},h.prototype._onTouch=function(){Y.start=this.start,Y.end=this.end,Y.pinching=!1,Y.center=null},h.prototype._onPinch=function(t,e,i){if(Y.pinching=!0,t.gesture.touches.length>1){Y.center||(Y.center=d(t.gesture.center,e.frame));var n=1/t.gesture.scale,s=this._pointerToDate(e,i,Y.center),o=d(t.gesture.center,e.frame),r=(this._pointerToDate(e,i,o),parseInt(s+(Y.start-s)*n)),a=parseInt(s+(Y.end-s)*n);this.setRange(r,a)}},h.prototype._pointerToDate=function(t,e,i){var n;if("horizontal"==e){var s=t.width;return n=this.conversion(s),i.x/n.scale+n.offset}var o=t.height;return n=this.conversion(o),i.y/n.scale+n.offset},h.prototype.zoom=function(t,e){null==e&&(e=(this.start+this.end)/2);var i=e+(this.start-e)*t,n=e+(this.end-e)*t;this.setRange(i,n)},h.prototype.move=function(t){var e=this.end-this.start,i=this.start+e*t,n=this.end+e*t;this.start=i,this.end=n},h.prototype.moveTo=function(t){var e=(this.start+this.end)/2,i=e-t,n=this.start-i,s=this.end-i;this.setRange(n,s)},l.prototype.add=function(t){if(void 0==t.id)throw new Error("Component has no field id");if(!(t instanceof u||t instanceof l))throw new TypeError("Component must be an instance of prototype Component or Controller");t.controller=this,this.components[t.id]=t},l.prototype.remove=function(t){var e;for(e in this.components)if(this.components.hasOwnProperty(e)&&(e==t||this.components[e]==t))break;e&&delete this.components[e]},l.prototype.requestReflow=function(t){if(t)this.reflow();else if(!this.reflowTimer){var e=this;this.reflowTimer=setTimeout(function(){e.reflowTimer=void 0,e.reflow()},0)}},l.prototype.requestRepaint=function(t){if(t)this.repaint();else if(!this.repaintTimer){var e=this;this.repaintTimer=setTimeout(function(){e.repaintTimer=void 0,e.repaint()},0)}},l.prototype.repaint=function V(){function V(i,n){n in e||(i.depends&&i.depends.forEach(function(t){V(t,t.id)}),i.parent&&V(i.parent,i.parent.id),t=i.repaint()||t,e[n]=!0)}var t=!1;this.repaintTimer&&(clearTimeout(this.repaintTimer),this.repaintTimer=void 0);var e={};z.forEach(this.components,V),t&&this.reflow()},l.prototype.reflow=function G(){function G(i,n){n in e||(i.depends&&i.depends.forEach(function(t){G(t,t.id)}),i.parent&&G(i.parent,i.parent.id),t=i.reflow()||t,e[n]=!0)}var t=!1;this.reflowTimer&&(clearTimeout(this.reflowTimer),this.reflowTimer=void 0);var e={};z.forEach(this.components,G),t&&this.repaint()},u.prototype.setOptions=function(t){t&&(z.extend(this.options,t),this.controller&&(this.requestRepaint(),this.requestReflow()))},u.prototype.getOption=function(t){var e;return this.options&&(e=this.options[t]),void 0===e&&this.defaultOptions&&(e=this.defaultOptions[t]),e},u.prototype.getContainer=function(){return null},u.prototype.getFrame=function(){return this.frame},u.prototype.repaint=function(){return!1},u.prototype.reflow=function(){return!1},u.prototype.hide=function(){return this.frame&&this.frame.parentNode?(this.frame.parentNode.removeChild(this.frame),!0):!1},u.prototype.show=function(){return this.frame&&this.frame.parentNode?!1:this.repaint()},u.prototype.requestRepaint=function(){if(!this.controller)throw new Error("Cannot request a repaint: no controller configured");this.controller.requestRepaint()},u.prototype.requestReflow=function(){if(!this.controller)throw new Error("Cannot request a reflow: no controller configured");this.controller.requestReflow()},p.prototype=new u,p.prototype.setOptions=u.prototype.setOptions,p.prototype.getContainer=function(){return this.frame},p.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.frame;if(!s){s=document.createElement("div"),s.className="panel";var o=n.className;o&&("function"==typeof o?z.addClassName(s,String(o())):z.addClassName(s,String(o))),this.frame=s,t+=1}if(!s.parentNode){if(!this.parent)throw new Error("Cannot repaint panel: no parent attached");var r=this.parent.getContainer();if(!r)throw new Error("Cannot repaint panel: parent has no container element");r.appendChild(s),t+=1}return t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),t>0},p.prototype.reflow=function(){var t=0,e=z.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},f.prototype=new p,f.prototype.setOptions=u.prototype.setOptions,f.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.frame;if(s||(s=document.createElement("div"),this.frame=s,t+=1),!s.parentNode){if(!this.container)throw new Error("Cannot repaint root panel: no container attached");this.container.appendChild(s),t+=1}s.className="vis timeline rootpanel "+n.orientation;var o=n.className;return o&&z.addClassName(s,z.option.asString(o)),t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),this._updateEventEmitters(),this._updateWatch(),t>0},f.prototype.reflow=function(){var t=0,e=z.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},f.prototype._updateWatch=function(){var t=this.getOption("autoResize");t?this._watch():this._unwatch()},f.prototype._watch=function(){var t=this;this._unwatch();var e=function(){var e=t.getOption("autoResize");return e?void(t.frame&&(t.frame.clientWidth!=t.width||t.frame.clientHeight!=t.height)&&t.requestReflow()):void t._unwatch()};z.addEventListener(window,"resize",e),this.watchTimer=setInterval(e,1e3)},f.prototype._unwatch=function(){this.watchTimer&&(clearInterval(this.watchTimer),this.watchTimer=void 0)},f.prototype.on=function(t,e){var i=this.listeners[t];i||(i=[],this.listeners[t]=i),i.push(e),this._updateEventEmitters()},f.prototype._updateEventEmitters=function(){if(this.listeners){var t=this;z.forEach(this.listeners,function(e,i){if(t.emitters||(t.emitters={}),!(i in t.emitters)){var n=t.frame;if(n){var s=function(t){e.forEach(function(e){e(t)})};t.emitters[i]=s,t.hammer||(t.hammer=N(n,{prevent_default:!0})),t.hammer.on(i,s)}}})}},g.prototype=new u,g.prototype.setOptions=u.prototype.setOptions,g.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},g.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},g.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},g.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.props,r=this.step,a=this.frame;if(a||(a=document.createElement("div"),this.frame=a,t+=1),a.className="axis",!a.parentNode){if(!this.parent)throw new Error("Cannot repaint time axis: no parent attached");var h=this.parent.getContainer();if(!h)throw new Error("Cannot repaint time axis: parent has no container element");h.appendChild(a),t+=1}var c=a.parentNode;if(c){var d=a.nextSibling;c.removeChild(a);var l="bottom"==s&&this.props.parentHeight&&this.height?this.props.parentHeight-this.height+"px":"0px";if(t+=e(a.style,"top",i(n.top,l)),t+=e(a.style,"left",i(n.left,"0px")),t+=e(a.style,"width",i(n.width,"100%")),t+=e(a.style,"height",i(n.height,this.height+"px")),this._repaintMeasureChars(),this.step){this._repaintStart(),r.first();for(var u=void 0,p=0;r.hasNext()&&1e3>p;){p++;var f=r.getCurrent(),g=this.toScreen(f),m=r.isMajor();this.getOption("showMinorLabels")&&this._repaintMinorText(g,r.getLabelMinor()),m&&this.getOption("showMajorLabels")?(g>0&&(void 0==u&&(u=g),this._repaintMajorText(g,r.getLabelMajor())),this._repaintMajorLine(g)):this._repaintMinorLine(g),r.next()}if(this.getOption("showMajorLabels")){var v=this.toTime(0),y=r.getLabelMajor(v),_=y.length*(o.majorCharWidth||10)+10;(void 0==u||u>_)&&this._repaintMajorText(0,y)}this._repaintEnd()}this._repaintLine(),d?c.insertBefore(a,d):c.appendChild(a)}return t>0},g.prototype._repaintStart=function(){var t=this.dom,e=t.redundant;e.majorLines=t.majorLines,e.majorTexts=t.majorTexts,e.minorLines=t.minorLines,e.minorTexts=t.minorTexts,t.majorLines=[],t.majorTexts=[],t.minorLines=[],t.minorTexts=[]},g.prototype._repaintEnd=function(){z.forEach(this.dom.redundant,function(t){for(;t.length;){var e=t.pop();e&&e.parentNode&&e.parentNode.removeChild(e)}})},g.prototype._repaintMinorText=function(t,e){var i=this.dom.redundant.minorTexts.shift();if(!i){var n=document.createTextNode("");i=document.createElement("div"),i.appendChild(n),i.className="text minor",this.frame.appendChild(i)}this.dom.minorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.left=t+"px",i.style.top=this.props.minorLabelTop+"px"},g.prototype._repaintMajorText=function(t,e){var i=this.dom.redundant.majorTexts.shift();if(!i){var n=document.createTextNode(e);i=document.createElement("div"),i.className="text major",i.appendChild(n),this.frame.appendChild(i)}this.dom.majorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.top=this.props.majorLabelTop+"px",i.style.left=t+"px"},g.prototype._repaintMinorLine=function(t){var e=this.dom.redundant.minorLines.shift();e||(e=document.createElement("div"),e.className="grid vertical minor",this.frame.appendChild(e)),this.dom.minorLines.push(e);var i=this.props;e.style.top=i.minorLineTop+"px",e.style.height=i.minorLineHeight+"px",e.style.left=t-i.minorLineWidth/2+"px"},g.prototype._repaintMajorLine=function(t){var e=this.dom.redundant.majorLines.shift();e||(e=document.createElement("DIV"),e.className="grid vertical major",this.frame.appendChild(e)),this.dom.majorLines.push(e);var i=this.props;e.style.top=i.majorLineTop+"px",e.style.left=t-i.majorLineWidth/2+"px",e.style.height=i.majorLineHeight+"px"},g.prototype._repaintLine=function(){{var t=this.dom.line,e=this.frame;this.options}this.getOption("showMinorLabels")||this.getOption("showMajorLabels")?(t?(e.removeChild(t),e.appendChild(t)):(t=document.createElement("div"),t.className="grid horizontal major",e.appendChild(t),this.dom.line=t),t.style.top=this.props.lineTop+"px"):t&&t.parentElement&&(e.removeChild(t.line),delete this.dom.line)},g.prototype._repaintMeasureChars=function(){var t,e=this.dom;if(!e.measureCharMinor){t=document.createTextNode("0");var i=document.createElement("DIV");i.className="text minor measure",i.appendChild(t),this.frame.appendChild(i),e.measureCharMinor=i}if(!e.measureCharMajor){t=document.createTextNode("0");var n=document.createElement("DIV");n.className="text major measure",n.appendChild(t),this.frame.appendChild(n),e.measureCharMajor=n}},g.prototype.reflow=function(){var t=0,e=z.updateProperty,i=this.frame,n=this.range;if(!n)throw new Error("Cannot repaint time axis: no range configured");if(i){t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft);var s=this.props,o=this.getOption("showMinorLabels"),r=this.getOption("showMajorLabels"),a=this.dom.measureCharMinor,h=this.dom.measureCharMajor;a&&(s.minorCharHeight=a.clientHeight,s.minorCharWidth=a.clientWidth),h&&(s.majorCharHeight=h.clientHeight,s.majorCharWidth=h.clientWidth);var c=i.parentNode?i.parentNode.offsetHeight:0;switch(c!=s.parentHeight&&(s.parentHeight=c,t+=1),this.getOption("orientation")){case"bottom":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.minorLabelTop=0,s.majorLabelTop=s.minorLabelTop+s.minorLabelHeight,s.minorLineTop=-this.top,s.minorLineHeight=Math.max(this.top+s.majorLabelHeight,0),s.minorLineWidth=1,s.majorLineTop=-this.top,s.majorLineHeight=Math.max(this.top+s.minorLabelHeight+s.majorLabelHeight,0),s.majorLineWidth=1,s.lineTop=0;break;case"top":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.majorLabelTop=0,s.minorLabelTop=s.majorLabelTop+s.majorLabelHeight,s.minorLineTop=s.minorLabelTop,s.minorLineHeight=Math.max(c-s.majorLabelHeight-this.top),s.minorLineWidth=1,s.majorLineTop=0,s.majorLineHeight=Math.max(c-this.top),s.majorLineWidth=1,s.lineTop=s.majorLabelHeight+s.minorLabelHeight;break;default:throw new Error('Unkown orientation "'+this.getOption("orientation")+'"')}var d=s.minorLabelHeight+s.majorLabelHeight;t+=e(this,"width",i.offsetWidth),t+=e(this,"height",d),this._updateConversion();var l=z.convert(n.start,"Number"),u=z.convert(n.end,"Number"),p=this.toTime(5*(s.minorCharWidth||10)).valueOf()-this.toTime(0).valueOf();this.step=new TimeStep(new Date(l),new Date(u),p),t+=e(s.range,"start",l),t+=e(s.range,"end",u),t+=e(s.range,"minimumStep",p.valueOf())}return t>0},g.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},m.prototype=new u,m.prototype.setOptions=u.prototype.setOptions,m.prototype.getContainer=function(){return this.frame},m.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCurrentTime"))return void(t&&(i.removeChild(t),delete this.frame));t||(t=document.createElement("div"),t.className="currenttime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t),this.frame=t),e.conversion||e._updateConversion();var n=new Date,s=e.toScreen(n);t.style.left=s+"px",t.title="Current time: "+n,void 0!==this.currentTimeTimer&&(clearTimeout(this.currentTimeTimer),delete this.currentTimeTimer);var o=this,r=1/e.conversion.scale/2;return 30>r&&(r=30),this.currentTimeTimer=setTimeout(function(){o.repaint()},r),!1},v.prototype=new u,v.prototype.setOptions=u.prototype.setOptions,v.prototype.getContainer=function(){return this.frame},v.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCustomTime"))return void(t&&(i.removeChild(t),delete this.frame));if(!t){t=document.createElement("div"),t.className="customtime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t);var n=document.createElement("div");n.style.position="relative",n.style.top="0px",n.style.left="-10px",n.style.height="100%",n.style.width="20px",t.appendChild(n),this.frame=t,this.subscribe(this,"movetime")}e.conversion||e._updateConversion();var s=e.toScreen(this.customTime);return t.style.left=s+"px",t.title="Time: "+this.customTime,!1},v.prototype._setCustomTime=function(t){this.customTime=new Date(t.valueOf()),this.repaint()},v.prototype._getCustomTime=function(){return new Date(this.customTime.valueOf())},v.prototype.subscribe=function(t,e){var i=this,n={component:t,event:e,callback:function(t){i._onMouseDown(t,n)},params:{}};t.on("mousedown",n.callback),i.listeners.push(n)},v.prototype.on=function(t,e){var i=this.frame;if(!i)throw new Error("Cannot add event listener: no parent attached");F.addListener(this,t,e),z.addEventListener(i,t,e)},v.prototype._onMouseDown=function(t,e){t=t||window.event;var i=e.params,n=t.which?1==t.which:1==t.button;if(n){i.mouseX=z.getPageX(t),i.moved=!1,i.customTime=this.customTime;var s=this;i.onMouseMove||(i.onMouseMove=function(t){s._onMouseMove(t,e)},z.addEventListener(document,"mousemove",i.onMouseMove)),i.onMouseUp||(i.onMouseUp=function(t){s._onMouseUp(t,e)},z.addEventListener(document,"mouseup",i.onMouseUp)),z.stopPropagation(t),z.preventDefault(t)}},v.prototype._onMouseMove=function(t,e){t=t||window.event;var i=e.params,n=this.parent,s=z.getPageX(t);void 0===i.mouseX&&(i.mouseX=s);var o=s-i.mouseX;Math.abs(o)>=1&&(i.moved=!0);var r=n.toScreen(i.customTime),a=r+o,h=n.toTime(a);this._setCustomTime(h),F.trigger(this,"timechange",{customTime:this.customTime}),z.preventDefault(t)},v.prototype._onMouseUp=function(t,e){t=t||window.event;var i=e.params;i.onMouseMove&&(z.removeEventListener(document,"mousemove",i.onMouseMove),i.onMouseMove=null),i.onMouseUp&&(z.removeEventListener(document,"mouseup",i.onMouseUp),i.onMouseUp=null),i.moved&&F.trigger(this,"timechanged",{customTime:this.customTime})},y.prototype=new p,y.types={box:w,range:S,rangeoverflow:E,point:b},y.prototype.setOptions=u.prototype.setOptions,y.prototype.setRange=function(t){if(!(t instanceof h||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},y.prototype.setSelection=function(t){var e,i,n,s,o;if(t){if(!Array.isArray(t))throw new TypeError("Array expected");for(e=0,i=this.selection.length;i>e;e++)n=this.selection[e],s=this.items[n],s&&s.unselect();for(this.selection=[],e=0,i=t.length;i>e;e++)n=t[e],s=this.items[n],s&&(this.selection.push(n),s.select());o=this.selection.concat([]),F.trigger(this,"select",{ids:o}),this.controller&&this.requestRepaint()}},y.prototype.getSelection=function(){return this.selection.concat([])},y.prototype._deselect=function(t){for(var e=this.selection,i=0,n=e.length;n>i;i++)if(e[i]==t){e.splice(i,1);break}},y.prototype.repaint=function(){var t=0,e=z.updateProperty,i=z.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.defaultOptions,r=this.frame;if(!r){r=document.createElement("div"),r.className="itemset";var a=n.className;a&&z.addClassName(r,z.option.asString(a));var h=document.createElement("div");h.className="background",r.appendChild(h),this.dom.background=h;var c=document.createElement("div");c.className="foreground",r.appendChild(c),this.dom.foreground=c;var d=document.createElement("div");d.className="itemset-axis",this.dom.axis=d,this.frame=r,t+=1}if(!this.parent)throw new Error("Cannot repaint itemset: no parent attached");var l=this.parent.getContainer();if(!l)throw new Error("Cannot repaint itemset: parent has no container element");r.parentNode||(l.appendChild(r),t+=1),this.dom.axis.parentNode||(l.appendChild(this.dom.axis),t+=1),t+=e(r.style,"left",i(n.left,"0px")),t+=e(r.style,"top",i(n.top,"0px")),t+=e(r.style,"width",i(n.width,"100%")),t+=e(r.style,"height",i(n.height,this.height+"px")),t+=e(this.dom.axis.style,"left",i(n.left,"0px")),t+=e(this.dom.axis.style,"width",i(n.width,"100%")),t+="bottom"==s?e(this.dom.axis.style,"top",this.height+this.top+"px"):e(this.dom.axis.style,"top",this.top+"px"),this._updateConversion();var u=this,p=this.queue,f=this.itemsData,g=this.items,m={};for(var v in p)if(p.hasOwnProperty(v)){var _=p[v],w=g[v],b=_.action;switch(b){case"add":case"update":var S=f&&f.get(v,m);if(S){var E=S.type||S.start&&S.end&&"range"||n.type||"box",T=y.types[E];if(w&&(T&&w instanceof T?(w.data=S,t++):(t+=w.hide(),w=null)),!w){if(!T)throw new TypeError('Unknown item type "'+E+'"');w=new T(u,S,n,o),w.id=_.id,t++}w.repaint(),g[v]=w}delete p[v];break;case"remove":w&&(w.selected&&u._deselect(v),t+=w.hide()),delete g[v],delete p[v];break;default:console.log('Error: unknown action "'+b+'"')}}return z.forEach(this.items,function(e){e.visible?(t+=e.show(),e.reposition()):t+=e.hide()}),t>0},y.prototype.getForeground=function(){return this.dom.foreground -},y.prototype.getBackground=function(){return this.dom.background},y.prototype.getAxis=function(){return this.dom.axis},y.prototype.reflow=function(){var t=0,e=this.options,i=e.margin&&e.margin.axis||this.defaultOptions.margin.axis,n=e.margin&&e.margin.item||this.defaultOptions.margin.item,s=z.updateProperty,o=z.option.asNumber,r=z.option.asSize,a=this.frame;if(a){this._updateConversion(),z.forEach(this.items,function(e){t+=e.reflow()}),this.stack.update();var h,c=o(e.maxHeight),d=null!=r(e.height);if(d)h=a.offsetHeight;else{var l=this.stack.ordered;if(l.length){var u=l[0].top,p=l[0].top+l[0].height;z.forEach(l,function(t){u=Math.min(u,t.top),p=Math.max(p,t.top+t.height)}),h=p-u+i+n}else h=i+n}null!=c&&(h=Math.min(h,c)),t+=s(this,"height",h),t+=s(this,"top",a.offsetTop),t+=s(this,"left",a.offsetLeft),t+=s(this,"width",a.offsetWidth)}else t+=1;return t>0},y.prototype.hide=function(){var t=!1;return this.frame&&this.frame.parentNode&&(this.frame.parentNode.removeChild(this.frame),t=!0),this.dom.axis&&this.dom.axis.parentNode&&(this.dom.axis.parentNode.removeChild(this.dom.axis),t=!0),t},y.prototype.setItems=function(t){var e,i=this,n=this.itemsData;if(t){if(!(t instanceof o||t instanceof r))throw new TypeError("Data must be an instance of DataSet");this.itemsData=t}else this.itemsData=null;if(n&&(z.forEach(this.listeners,function(t,e){n.unsubscribe(e,t)}),e=n.getIds(),this._onRemove(e)),this.itemsData){var s=this.id;z.forEach(this.listeners,function(t,e){i.itemsData.subscribe(e,t,s)}),e=this.itemsData.getIds(),this._onAdd(e)}},y.prototype.getItems=function(){return this.itemsData},y.prototype._onUpdate=function(t){this._toQueue("update",t)},y.prototype._onAdd=function(t){this._toQueue("add",t)},y.prototype._onRemove=function(t){this._toQueue("remove",t)},y.prototype._toQueue=function(t,e){var i=this.queue;e.forEach(function(e){i[e]={id:e,action:t}}),this.controller&&this.requestRepaint()},y.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},y.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},y.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},_.prototype.select=function(){this.selected=!0,this.visible&&this.repaint()},_.prototype.unselect=function(){this.selected=!1,this.visible&&this.repaint()},_.prototype.show=function(){return!1},_.prototype.hide=function(){return!1},_.prototype.repaint=function(){return!1},_.prototype.reflow=function(){return!1},_.prototype.getWidth=function(){return this.width},w.prototype=new _(null,null),w.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");if(!e.box.parentNode){var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");i.appendChild(e.box),t=!0}if(!e.line.parentNode){var n=this.parent.getBackground();if(!n)throw new Error("Cannot repaint time axis: parent has no background container element");n.appendChild(e.line),t=!0}if(!e.dot.parentNode){var s=this.parent.getAxis();if(!n)throw new Error("Cannot repaint time axis: parent has no axis container element");s.appendChild(e.dot),t=!0}if(this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var o=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=o&&(this.className=o,e.box.className="item box"+o,e.line.className="item line"+o,e.dot.className="item dot"+o,t=!0)}return t},w.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},w.prototype.hide=function(){var t=!1,e=this.dom;return e&&(e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),e.line.parentNode&&e.line.parentNode.removeChild(e.line),e.dot.parentNode&&e.dot.parentNode.removeChild(e.dot)),t},w.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,c,d,l,u=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(d=this.data,l=this.parent&&this.parent.range,d&&l){var p=l.end-l.start;this.visible=d.start>l.start-p&&d.start0},w.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("DIV"),t.content=document.createElement("DIV"),t.content.className="content",t.box.appendChild(t.content),t.line=document.createElement("DIV"),t.line.className="line",t.dot=document.createElement("DIV"),t.dot.className="dot",t.box["timeline-item"]=this)},w.prototype.reposition=function(){var t=this.dom,e=this.props,i=this.options.orientation||this.defaultOptions.orientation;if(t){var n=t.box,s=t.line,o=t.dot;n.style.left=this.left+"px",n.style.top=this.top+"px",s.style.left=e.line.left+"px","top"==i?(s.style.top="0px",s.style.height=this.top+"px"):(s.style.top=this.top+this.height+"px",s.style.height=Math.max(this.parent.height-this.top-this.height+this.props.dot.height/2,0)+"px"),o.style.left=e.dot.left+"px",o.style.top=e.dot.top+"px"}},b.prototype=new _(null,null),b.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.point.parentNode||(i.appendChild(e.point),i.appendChild(e.point),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.point.className="item point"+n,t=!0)}return t},b.prototype.show=function(){return this.dom&&this.dom.point.parentNode?!1:this.repaint()},b.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.point.parentNode&&(e.point.parentNode.removeChild(e.point),t=!0),t},b.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,c,d=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(h=this.data,c=this.parent&&this.parent.range,h&&c){var l=c.end-c.start;this.visible=h.start>c.start-l&&h.start0},b.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.point=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.point.appendChild(t.content),t.dot=document.createElement("div"),t.dot.className="dot",t.point.appendChild(t.dot),t.point["timeline-item"]=this)},b.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.point.style.top=this.top+"px",t.point.style.left=this.left+"px",t.content.style.marginLeft=e.content.marginLeft+"px",t.dot.style.top=e.dot.top+"px")},S.prototype=new _(null,null),S.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.box.className="item range"+n,t=!0)}return t},S.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},S.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),t},S.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,c,d,l,u,p,f,g,m=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(void 0==this.data.end)throw new Error('Property "end" missing in item '+this.data.id);return h=this.data,c=this.parent&&this.parent.range,this.visible=h&&c?h.startc.start:!1,this.visible&&(t=this.dom,t?(e=this.props,i=this.options,o=this.parent,r=o.toScreen(this.data.start),a=o.toScreen(this.data.end),d=z.updateProperty,l=t.box,u=o.width,f=i.orientation||this.defaultOptions.orientation,n=i.margin&&i.margin.axis||this.defaultOptions.margin.axis,s=i.padding||this.defaultOptions.padding,m+=d(e.content,"width",t.content.offsetWidth),m+=d(this,"height",l.offsetHeight),-u>r&&(r=-u),a>2*u&&(a=2*u),p=0>r?Math.min(-r,a-r-e.content.width-2*s):0,m+=d(e.content,"left",p),"top"==f?(g=n,m+=d(this,"top",g)):(g=o.height-this.height-n,m+=d(this,"top",g)),m+=d(this,"left",r),m+=d(this,"width",Math.max(a-r,1))):m+=1),m>0},S.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content),t.box["timeline-item"]=this)},S.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.box.style.top=this.top+"px",t.box.style.left=this.left+"px",t.box.style.width=this.width+"px",t.content.style.left=e.content.left+"px")},E.prototype=new S(null,null),E.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=this.data.className?" "+this.data.className:"";this.className!=n&&(this.className=n,e.box.className="item rangeoverflow"+n,t=!0)}return t},E.prototype.getWidth=function(){return void 0!==this.props.content&&this.width0},x.prototype=new p,x.prototype.setOptions=u.prototype.setOptions,x.prototype.setRange=function(){},x.prototype.setItems=function(t){this.itemsData=t;for(var e in this.groups)if(this.groups.hasOwnProperty(e)){var i=this.groups[e];i.setItems(t)}},x.prototype.getItems=function(){return this.itemsData},x.prototype.setRange=function(t){this.range=t},x.prototype.setGroups=function(t){var e,i=this;if(this.groupsData&&(z.forEach(this.listeners,function(t,e){i.groupsData.unsubscribe(e,t)}),e=this.groupsData.getIds(),this._onRemove(e)),t?t instanceof o?this.groupsData=t:(this.groupsData=new o({convert:{start:"Date",end:"Date"}}),this.groupsData.add(t)):this.groupsData=null,this.groupsData){var n=this.id;z.forEach(this.listeners,function(t,e){i.groupsData.subscribe(e,t,n)}),e=this.groupsData.getIds(),this._onAdd(e)}},x.prototype.getGroups=function(){return this.groupsData},x.prototype.setSelection=function(t){var e=[],i=this.groups;for(var n in i)if(i.hasOwnProperty(n)){var s=i[n];s.setSelection(t)}return e},x.prototype.getSelection=function(){var t=[],e=this.groups;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];t=t.concat(n.getSelection())}return t},x.prototype.repaint=function(){var t,e,i,n,s=0,o=z.updateProperty,r=z.option.asSize,a=z.option.asElement,h=this.options,c=this.dom.frame,d=this.dom.labels,l=this.dom.labelSet;if(!this.parent)throw new Error("Cannot repaint groupset: no parent attached");var u=this.parent.getContainer();if(!u)throw new Error("Cannot repaint groupset: parent has no container element");if(!c){c=document.createElement("div"),c.className="groupset",this.dom.frame=c;var p=h.className;p&&z.addClassName(c,z.option.asString(p)),s+=1}c.parentNode||(u.appendChild(c),s+=1);var f=a(h.labelContainer);if(!f)throw new Error('Cannot repaint groupset: option "labelContainer" not defined');d||(d=document.createElement("div"),d.className="labels",this.dom.labels=d),l||(l=document.createElement("div"),l.className="label-set",d.appendChild(l),this.dom.labelSet=l),d.parentNode&&d.parentNode==f||(d.parentNode&&d.parentNode.removeChild(d.parentNode),f.appendChild(d)),s+=o(c.style,"height",r(h.height,this.height+"px")),s+=o(c.style,"top",r(h.top,"0px")),s+=o(c.style,"left",r(h.left,"0px")),s+=o(c.style,"width",r(h.width,"100%")),s+=o(l.style,"top",r(h.top,"0px")),s+=o(l.style,"height",r(h.height,this.height+"px"));var g=this,m=this.queue,v=this.groups,y=this.groupsData,_=Object.keys(m);if(_.length){_.forEach(function(t){var e=m[t],i=v[t];switch(e){case"add":case"update":if(!i){var n=Object.create(g.options);z.extend(n,{height:null,maxHeight:null}),i=new T(g,t,n),i.setItems(g.itemsData),v[t]=i,g.controller.add(i)}i.data=y.get(t),delete m[t];break;case"remove":i&&(i.setItems(),delete v[t],g.controller.remove(i)),delete m[t];break;default:console.log('Error: unknown action "'+e+'"')}});var w=this.groupsData.getIds({order:this.options.groupOrder});for(t=0;t0},x.prototype._createLabel=function(t){var e=this.groups[t],i=document.createElement("div");i.className="label";var n=document.createElement("div");n.className="inner",i.appendChild(n);var s=e.data&&e.data.content;s instanceof Element?n.appendChild(s):void 0!=s&&(n.innerHTML=s);var o=e.data&&e.data.className;return o&&z.addClassName(i,o),e.label=i,i},x.prototype.getContainer=function(){return this.dom.frame},x.prototype.getLabelsWidth=function(){return this.props.labels.width},x.prototype.reflow=function(){var t,e,i=0,n=this.options,s=z.updateProperty,o=z.option.asNumber,r=z.option.asSize,a=this.dom.frame;if(a){var h,c=o(n.maxHeight),d=null!=r(n.height);if(d)h=a.offsetHeight;else{h=0;for(t in this.groups)this.groups.hasOwnProperty(t)&&(e=this.groups[t],h+=e.height)}null!=c&&(h=Math.min(h,c)),i+=s(this,"height",h),i+=s(this,"top",a.offsetTop),i+=s(this,"left",a.offsetLeft),i+=s(this,"width",a.offsetWidth)}var l=0;for(t in this.groups)if(this.groups.hasOwnProperty(t)){e=this.groups[t];var u=e.props&&e.props.label&&e.props.label.width||0;l=Math.max(l,u)}return i+=s(this.props.labels,"width",l),i>0},x.prototype.hide=function(){return this.dom.frame&&this.dom.frame.parentNode?(this.dom.frame.parentNode.removeChild(this.dom.frame),!0):!1},x.prototype.show=function(){return this.dom.frame&&this.dom.frame.parentNode?!1:this.repaint()},x.prototype._onUpdate=function(t){this._toQueue(t,"update")},x.prototype._onAdd=function(t){this._toQueue(t,"add")},x.prototype._onRemove=function(t){this._toQueue(t,"remove")},x.prototype._toQueue=function(t,e){var i=this.queue;t.forEach(function(t){i[t]=e}),this.controller&&this.requestRepaint()},C.prototype.setOptions=function(t){z.extend(this.options,t),this.range.setRange(t.start,t.end),this.controller.reflow(),this.controller.repaint()},C.prototype.setCustomTime=function(t){this.customtime._setCustomTime(t)},C.prototype.getCustomTime=function(){return new Date(this.customtime.customTime.valueOf())},C.prototype.setItems=function(t){var e,i=null==this.itemsData;if(t?t instanceof o&&(e=t):e=null,t instanceof o||(e=new o({convert:{start:"Date",end:"Date"}}),e.add(t)),this.itemsData=e,this.content.setItems(e),i&&(void 0==this.options.start||void 0==this.options.end)){var n=this.getItemRange(),s=n.min,r=n.max;if(null!=s&&null!=r){var a=r.valueOf()-s.valueOf();0>=a&&(a=864e5),s=new Date(s.valueOf()-.05*a),r=new Date(r.valueOf()+.05*a)}void 0!=this.options.start&&(s=z.convert(this.options.start,"Date")),void 0!=this.options.end&&(r=z.convert(this.options.end,"Date")),(null!=s||null!=r)&&this.range.setRange(s,r)}},C.prototype.setGroups=function(t){var e=this;this.groupsData=t;var i=this.groupsData?x:y;if(!(this.content instanceof i)){this.content&&(this.content.hide(),this.content.setItems&&this.content.setItems(),this.content.setGroups&&this.content.setGroups(),this.controller.remove(this.content));var n=Object.create(this.options);z.extend(n,{top:function(){return"top"==e.options.orientation?e.timeaxis.height:e.itemPanel.height-e.timeaxis.height-e.content.height},left:null,width:"100%",height:function(){return e.options.height?e.itemPanel.height-e.timeaxis.height:null},maxHeight:function(){if(e.options.maxHeight){if(!z.isNumber(e.options.maxHeight))throw new TypeError("Number expected for property maxHeight");return e.options.maxHeight-e.timeaxis.height}return null},labelContainer:function(){return e.labelPanel.getContainer()}}),this.content=new i(this.itemPanel,[this.timeaxis],n),this.content.setRange&&this.content.setRange(this.range),this.content.setItems&&this.content.setItems(this.itemsData),this.content.setGroups&&this.content.setGroups(this.groupsData),this.controller.add(this.content)}},C.prototype.getItemRange=function(){var t=this.itemsData,e=null,i=null;if(t){var n=t.min("start");e=n?n.start.valueOf():null;var s=t.max("start");s&&(i=s.start.valueOf());var o=t.max("end");o&&(i=null==i?o.end.valueOf():Math.max(i,o.end.valueOf()))}return{min:null!=e?new Date(e):null,max:null!=i?new Date(i):null}},C.prototype.setSelection=function(t){this.content&&this.content.setSelection(t)},C.prototype.getSelection=function(){return this.content?this.content.getSelection():[]},C.prototype.on=function(t,e){var i=["rangechange","rangechanged","select"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());F.addListener(this,t,e)},C.prototype.off=function(t,e){F.removeListener(this,t,e)},C.prototype._trigger=function(t,e){F.trigger(this,t,e||{})},C.prototype._onSelectItem=function(t){var e=this._itemFromTarget(t),i=e?[e.id]:[];this.setSelection(i),this._trigger("select",{items:this.getSelection()}),t.stopPropagation()},C.prototype._onMultiSelectItem=function(t){var e,i=this._itemFromTarget(t);if(i){e=this.getSelection();var n=e.indexOf(i.id);-1==n?e.push(i.id):e.splice(n,1),this.setSelection(e),this._trigger("select",{items:this.getSelection()}),t.stopPropagation()}},C.prototype._itemFromTarget=function(t){for(var e=t.target;e;){if(e.hasOwnProperty("timeline-item"))return e["timeline-item"];e=e.parentNode}return null},function(t){function e(t){return C=t,u()}function i(){M=0,D=C.charAt(0)}function n(){M++,D=C.charAt(M)}function s(){return C.charAt(M+1)}function o(t){return N.test(t)}function r(t,e){if(t||(t={}),e)for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function a(t,e,i){for(var n=e.split("."),s=t;n.length;){var o=n.shift();n.length?(s[o]||(s[o]={}),s=s[o]):s[o]=i}}function h(t,e){for(var i,n,s=null,o=[t],a=t;a.parent;)o.push(a.parent),a=a.parent;if(a.nodes)for(i=0,n=a.nodes.length;n>i;i++)if(e.id===a.nodes[i].id){s=a.nodes[i];break}for(s||(s={id:e.id},t.node&&(s.attr=r(s.attr,t.node))),i=o.length-1;i>=0;i--){var h=o[i];h.nodes||(h.nodes=[]),-1==h.nodes.indexOf(s)&&h.nodes.push(s)}e.attr&&(s.attr=r(s.attr,e.attr))}function c(t,e){if(t.edges||(t.edges=[]),t.edges.push(e),t.edge){var i=r({},t.edge);e.attr=r(i,e.attr)}}function d(t,e,i,n,s){var o={from:e,to:i,type:n};return t.edge&&(o.attr=r({},t.edge)),o.attr=r(o.attr||{},s),o}function l(){for(I=T.NULL,O="";" "==D||" "==D||"\n"==D||"\r"==D;)n();do{var t=!1;if("#"==D){for(var e=M-1;" "==C.charAt(e)||" "==C.charAt(e);)e--;if("\n"==C.charAt(e)||""==C.charAt(e)){for(;""!=D&&"\n"!=D;)n();t=!0}}if("/"==D&&"/"==s()){for(;""!=D&&"\n"!=D;)n();t=!0}if("/"==D&&"*"==s()){for(;""!=D;){if("*"==D&&"/"==s()){n(),n();break}n()}t=!0}for(;" "==D||" "==D||"\n"==D||"\r"==D;)n()}while(t);if(""==D)return void(I=T.DELIMITER);var i=D+s();if(x[i])return I=T.DELIMITER,O=i,n(),void n();if(x[D])return I=T.DELIMITER,O=D,void n();if(o(D)||"-"==D){for(O+=D,n();o(D);)O+=D,n();return"false"==O?O=!1:"true"==O?O=!0:isNaN(Number(O))||(O=Number(O)),void(I=T.IDENTIFIER)}if('"'==D){for(n();""!=D&&('"'!=D||'"'==D&&'"'==s());)O+=D,'"'==D&&n(),n();if('"'!=D)throw w('End of string " expected');return n(),void(I=T.IDENTIFIER)}for(I=T.UNKNOWN;""!=D;)O+=D,n();throw new SyntaxError('Syntax error in part "'+b(O,30)+'"')}function u(){var t={};if(i(),l(),"strict"==O&&(t.strict=!0,l()),("graph"==O||"digraph"==O)&&(t.type=O,l()),I==T.IDENTIFIER&&(t.id=O,l()),"{"!=O)throw w("Angle bracket { expected");if(l(),p(t),"}"!=O)throw w("Angle bracket } expected");if(l(),""!==O)throw w("End of file expected");return l(),delete t.node,delete t.edge,delete t.graph,t}function p(t){for(;""!==O&&"}"!=O;)f(t),";"==O&&l()}function f(t){var e=g(t);if(e)return void y(t,e);var i=m(t);if(!i){if(I!=T.IDENTIFIER)throw w("Identifier expected");var n=O;if(l(),"="==O){if(l(),I!=T.IDENTIFIER)throw w("Identifier expected");t[n]=O,l()}else v(t,n)}}function g(t){var e=null;if("subgraph"==O&&(e={},e.type="subgraph",l(),I==T.IDENTIFIER&&(e.id=O,l())),"{"==O){if(l(),e||(e={}),e.parent=t,e.node=t.node,e.edge=t.edge,e.graph=t.graph,p(e),"}"!=O)throw w("Angle bracket } expected");l(),delete e.node,delete e.edge,delete e.graph,delete e.parent,t.subgraphs||(t.subgraphs=[]),t.subgraphs.push(e)}return e}function m(t){return"node"==O?(l(),t.node=_(),"node"):"edge"==O?(l(),t.edge=_(),"edge"):"graph"==O?(l(),t.graph=_(),"graph"):null}function v(t,e){var i={id:e},n=_();n&&(i.attr=n),h(t,i),y(t,e)}function y(t,e){for(;"->"==O||"--"==O;){var i,n=O;l();var s=g(t);if(s)i=s;else{if(I!=T.IDENTIFIER)throw w("Identifier or subgraph expected");i=O,h(t,{id:i}),l()}var o=_(),r=d(t,e,i,n,o);c(t,r),e=i}}function _(){for(var t=null;"["==O;){for(l(),t={};""!==O&&"]"!=O;){if(I!=T.IDENTIFIER)throw w("Attribute name expected");var e=O;if(l(),"="!=O)throw w("Equal sign = expected");if(l(),I!=T.IDENTIFIER)throw w("Attribute value expected");var i=O;a(t,e,i),l(),","==O&&l()}if("]"!=O)throw w("Bracket ] expected");l()}return t}function w(t){return new SyntaxError(t+', got "'+b(O,30)+'" (char '+M+")")}function b(t,e){return t.length<=e?t:t.substr(0,27)+"..."}function S(t,e,i){t instanceof Array?t.forEach(function(t){e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}):e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}function E(t){function i(t){var e={from:t.from,to:t.to};return r(e,t.attr),e.style="->"==t.type?"arrow":"line",e}var n=e(t),s={nodes:[],edges:[],options:{}};return n.nodes&&n.nodes.forEach(function(t){var e={id:t.id,label:String(t.label||t.id)};r(e,t.attr),e.image&&(e.shape="image"),s.nodes.push(e)}),n.edges&&n.edges.forEach(function(t){var e,n;e=t.from instanceof Object?t.from.nodes:{id:t.from},n=t.to instanceof Object?t.to.nodes:{id:t.to},t.from instanceof Object&&t.from.edges&&t.from.edges.forEach(function(t){var e=i(t);s.edges.push(e)}),S(e,n,function(e,n){var o=d(s,e.id,n.id,t.type,t.attr),r=i(o);s.edges.push(r)}),t.to instanceof Object&&t.to.edges&&t.to.edges.forEach(function(t){var e=i(t);s.edges.push(e)})}),n.attr&&(s.options=n.attr),s}var T={NULL:0,DELIMITER:1,IDENTIFIER:2,UNKNOWN:3},x={"{":!0,"}":!0,"[":!0,"]":!0,";":!0,"=":!0,",":!0,"->":!0,"--":!0},C="",M=0,D="",O="",I=T.NULL,N=/[a-zA-Z_0-9.:#]/;t.parseDOT=e,t.DOTToGraph=E}("undefined"!=typeof z?z:n),"undefined"!=typeof CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.circle=function(t,e,i){this.beginPath(),this.arc(t,e,i,0,2*Math.PI,!1)},CanvasRenderingContext2D.prototype.square=function(t,e,i){this.beginPath(),this.rect(t-i,e-i,2*i,2*i)},CanvasRenderingContext2D.prototype.triangle=function(t,e,i){this.beginPath();var n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e-(r-o)),this.lineTo(t+s,e+o),this.lineTo(t-s,e+o),this.lineTo(t,e-(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.triangleDown=function(t,e,i){this.beginPath();var n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e+(r-o)),this.lineTo(t+s,e-o),this.lineTo(t-s,e-o),this.lineTo(t,e+(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.star=function(t,e,i){this.beginPath();for(var n=0;10>n;n++){var s=n%2===0?1.3*i:.5*i;this.lineTo(t+s*Math.sin(2*n*Math.PI/10),e-s*Math.cos(2*n*Math.PI/10))}this.closePath()},CanvasRenderingContext2D.prototype.roundRect=function(t,e,i,n,s){var o=Math.PI/180;0>i-2*s&&(s=i/2),0>n-2*s&&(s=n/2),this.beginPath(),this.moveTo(t+s,e),this.lineTo(t+i-s,e),this.arc(t+i-s,e+s,s,270*o,360*o,!1),this.lineTo(t+i,e+n-s),this.arc(t+i-s,e+n-s,s,0,90*o,!1),this.lineTo(t+s,e+n),this.arc(t+s,e+n-s,s,90*o,180*o,!1),this.lineTo(t,e+s),this.arc(t+s,e+s,s,180*o,270*o,!1)},CanvasRenderingContext2D.prototype.ellipse=function(t,e,i,n){var s=.5522848,o=i/2*s,r=n/2*s,a=t+i,h=e+n,c=t+i/2,d=e+n/2;this.beginPath(),this.moveTo(t,d),this.bezierCurveTo(t,d-r,c-o,e,c,e),this.bezierCurveTo(c+o,e,a,d-r,a,d),this.bezierCurveTo(a,d+r,c+o,h,c,h),this.bezierCurveTo(c-o,h,t,d+r,t,d)},CanvasRenderingContext2D.prototype.database=function(t,e,i,n){var s=1/3,o=i,r=n*s,a=.5522848,h=o/2*a,c=r/2*a,d=t+o,l=e+r,u=t+o/2,p=e+r/2,f=e+(n-r/2),g=e+n;this.beginPath(),this.moveTo(d,p),this.bezierCurveTo(d,p+c,u+h,l,u,l),this.bezierCurveTo(u-h,l,t,p+c,t,p),this.bezierCurveTo(t,p-c,u-h,e,u,e),this.bezierCurveTo(u+h,e,d,p-c,d,p),this.lineTo(d,f),this.bezierCurveTo(d,f+c,u+h,g,u,g),this.bezierCurveTo(u-h,g,t,f+c,t,f),this.lineTo(t,p)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,n){var s=t-n*Math.cos(i),o=e-n*Math.sin(i),r=t-.9*n*Math.cos(i),a=e-.9*n*Math.sin(i),h=s+n/3*Math.cos(i+.5*Math.PI),c=o+n/3*Math.sin(i+.5*Math.PI),d=s+n/3*Math.cos(i-.5*Math.PI),l=o+n/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,c),this.lineTo(r,a),this.lineTo(d,l),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,n,s){s||(s=[10,5]),0==u&&(u=.001);var o=s.length;this.moveTo(t,e);for(var r=i-t,a=n-e,h=a/r,c=Math.sqrt(r*r+a*a),d=0,l=!0;c>=.1;){var u=s[d++%o];u>c&&(u=c);var p=Math.sqrt(u*u/(1+h*h));0>r&&(p=-p),t+=p,e+=h*p,this[l?"lineTo":"moveTo"](t,e),c-=u,l=!l}}),M.prototype.resetCluster=function(){this.formationScale=void 0,this.clusterSize=1,this.containedNodes={},this.containedEdges={},this.clusterSessions=[]},M.prototype.attachEdge=function(t){-1==this.edges.indexOf(t)&&this.edges.push(t),-1==this.dynamicEdges.indexOf(t)&&this.dynamicEdges.push(t),this.dynamicEdgesLength=this.dynamicEdges.length,this._updateMass()},M.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&(this.edges.splice(e,1),this.dynamicEdges.splice(e,1)),this.dynamicEdgesLength=this.dynamicEdges.length,this._updateMass()},M.prototype._updateMass=function(){this.mass=1+.6*this.edges.length},M.prototype.setProperties=function(t,e){if(t){if(this.originalLabel=void 0,void 0!==t.id&&(this.id=t.id),void 0!==t.label&&(this.label=t.label,this.originalLabel=t.label),void 0!==t.title&&(this.title=t.title),void 0!==t.group&&(this.group=t.group),void 0!==t.x&&(this.x=t.x),void 0!==t.y&&(this.y=t.y),void 0!==t.value&&(this.value=t.value),void 0!==t.horizontalAlignLeft&&(this.horizontalAlignLeft=t.horizontalAlignLeft),void 0!==t.verticalAlignTop&&(this.verticalAlignTop=t.verticalAlignTop),void 0!==t.triggerFunction&&(this.triggerFunction=t.triggerFunction),void 0===this.id)throw"Node must have an id";if(this.group){var i=this.grouplist.get(this.group);for(var n in i)i.hasOwnProperty(n)&&(this[n]=i[n])}if(void 0!==t.shape&&(this.shape=t.shape),void 0!==t.image&&(this.image=t.image),void 0!==t.radius&&(this.radius=t.radius),void 0!==t.color&&(this.color=M.parseColor(t.color)),void 0!==t.fontColor&&(this.fontColor=t.fontColor),void 0!==t.fontSize&&(this.fontSize=t.fontSize),void 0!==t.fontFace&&(this.fontFace=t.fontFace),void 0!==this.image){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.image)}switch(this.xFixed=this.xFixed||void 0!==t.x&&t.fixed,this.yFixed=this.yFixed||void 0!==t.y&&t.fixed,this.radiusFixed=this.radiusFixed||void 0!==t.radius,"image"==this.shape&&(this.radiusMin=e.nodes.widthMin,this.radiusMax=e.nodes.widthMax),this.shape){case"database":this.draw=this._drawDatabase,this.resize=this._resizeDatabase;break;case"box":this.draw=this._drawBox,this.resize=this._resizeBox;break;case"circle":this.draw=this._drawCircle,this.resize=this._resizeCircle;break;case"ellipse":this.draw=this._drawEllipse,this.resize=this._resizeEllipse;break;case"image":this.draw=this._drawImage,this.resize=this._resizeImage;break;case"text":this.draw=this._drawText,this.resize=this._resizeText;break;case"dot":this.draw=this._drawDot,this.resize=this._resizeShape;break;case"square":this.draw=this._drawSquare,this.resize=this._resizeShape;break;case"triangle":this.draw=this._drawTriangle,this.resize=this._resizeShape;break;case"triangleDown":this.draw=this._drawTriangleDown,this.resize=this._resizeShape; -break;case"star":this.draw=this._drawStar,this.resize=this._resizeShape;break;default:this.draw=this._drawEllipse,this.resize=this._resizeEllipse}this._reset()}},M.parseColor=function(t){var e;return z.isString(t)?e={border:t,background:t,highlight:{border:t,background:t}}:(e={},e.background=t.background||"white",e.border=t.border||e.background,z.isString(t.highlight)?e.highlight={border:t.highlight,background:t.highlight}:(e.highlight={},e.highlight.background=t.highlight&&t.highlight.background||e.background,e.highlight.border=t.highlight&&t.highlight.border||e.border)),e},M.prototype.select=function(){this.selected=!0,this._reset()},M.prototype.unselect=function(){this.selected=!1,this._reset()},M.prototype.clearSizeCache=function(){this._reset()},M.prototype._reset=function(){this.width=void 0,this.height=void 0},M.prototype.getTitle=function(){return this.title},M.prototype.distanceToBorder=function(t,e){var i=1;switch(this.width||this.resize(t),this.shape){case"circle":case"dot":return this.radius+i;case"ellipse":var n=this.width/2,s=this.height/2,o=Math.sin(e)*n,r=Math.cos(e)*s;return n*s/Math.sqrt(o*o+r*r);case"box":case"image":case"text":default:return this.width?Math.min(Math.abs(this.width/2/Math.cos(e)),Math.abs(this.height/2/Math.sin(e)))+i:0}},M.prototype._setForce=function(t,e){this.fx=t,this.fy=e},M.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},M.prototype.discreteStep=function(t){if(!this.xFixed){var e=-this.damping*this.vx,i=(this.fx+e)/this.mass;this.vx+=i*t,this.x+=this.vx*t}if(!this.yFixed){var n=-this.damping*this.vy,s=(this.fy+n)/this.mass;this.vy+=s*t,this.y+=this.vy*t}},M.prototype.isFixed=function(){return this.xFixed&&this.yFixed},M.prototype.isMoving=function(t){return Math.abs(this.vx)>t||Math.abs(this.vy)>t?!0:(this.vx=0,this.vy=0,!1)},M.prototype.isSelected=function(){return this.selected},M.prototype.getValue=function(){return this.value},M.prototype.getDistance=function(t,e){var i=this.x-t,n=this.y-e;return Math.sqrt(i*i+n*n)},M.prototype.setValueRange=function(t,e){if(!this.radiusFixed&&void 0!==this.value)if(e==t)this.radius=(this.radiusMin+this.radiusMax)/2;else{var i=(this.radiusMax-this.radiusMin)/(e-t);this.radius=(this.value-t)*i+this.radiusMin}this.baseRadiusValue=this.radius},M.prototype.draw=function(){throw"Draw method not initialized for node"},M.prototype.resize=function(){throw"Resize method not initialized for node"},M.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},M.prototype._resizeImage=function(){if(!this.width||!this.height){var t,e;if(this.value){this.radius=this.baseRadiusValue;var i=this.imageObj.height/this.imageObj.width;void 0!==i?(t=this.radius||this.imageObj.width,e=this.radius*i||this.imageObj.height):(t=0,e=0)}else t=this.imageObj.width,e=this.imageObj.height;this.width=t,this.height=e,this.width>0&&this.height>0&&(this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor)}},M.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e;if(0!=this.imageObj.width){if(this.clusterSize>1){var i=this.clusterSize>1?10:0;i*=this.graphScaleInv,i=Math.min(.2*this.width,i),t.globalAlpha=.5,t.drawImage(this.imageObj,this.left-i,this.top-i,this.width+2*i,this.height+2*i)}t.globalAlpha=1,t.drawImage(this.imageObj,this.left,this.top,this.width,this.height),e=this.y+this.height/2}else e=this.y;this._label(t,this.label,this.x,e,void 0,"top")},M.prototype._resizeBox=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=.5*(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=.5*(this.clusterSize-1)*this.clusterSizeHeightFactor}},M.prototype._drawBox=function(t){this._resizeBox(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.roundRect(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth,this.radius),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.roundRect(this.left,this.top,this.width,this.height,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeDatabase=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=i.width+2*e;this.width=n,this.height=n,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawDatabase=function(t){this._resizeDatabase(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.database(this.x-this.width/2-2*t.lineWidth,this.y-.5*this.height-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.database(this.x-this.width/2,this.y-.5*this.height,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=Math.max(i.width,i.height)+2*e;this.radius=n/2,this.width=n,this.height=n,this.radius+=.5*(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawCircle=function(t){this._resizeCircle(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.circle(this.x,this.y,this.radius+2*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.circle(this.x,this.y,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeEllipse=function(t){if(!this.width){var e=this.getTextSize(t);this.width=1.5*e.width,this.height=2*e.height,this.width1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.ellipse(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.ellipse(this.left,this.top,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._drawDot=function(t){this._drawShape(t,"circle")},M.prototype._drawTriangle=function(t){this._drawShape(t,"triangle")},M.prototype._drawTriangleDown=function(t){this._drawShape(t,"triangleDown")},M.prototype._drawSquare=function(t){this._drawShape(t,"square")},M.prototype._drawStar=function(t){this._drawShape(t,"star")},M.prototype._resizeShape=function(){if(!this.width){this.radius=this.baseRadiusValue;var t=2*this.radius;this.width=t,this.height=t,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=.5*(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawShape=function(t,e){this._resizeShape(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var i=2.5,n=2,s=2;switch(e){case"dot":s=2;break;case"square":s=2;break;case"triangle":s=3;break;case"triangleDown":s=3;break;case"star":s=4}t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?n:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t[e](this.x,this.y,this.radius+s*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?n:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t[e](this.x,this.y,this.radius),t.fill(),t.stroke(),this.label&&this._label(t,this.label,this.x,this.y+this.height/2,void 0,"top")},M.prototype._resizeText=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor}},M.prototype._drawText=function(t){this._resizeText(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,this._label(t,this.label,this.x,this.y)},M.prototype._label=function(t,e,i,n,s,o){if(e){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle=this.fontColor||"black",t.textAlign=s||"center",t.textBaseline=o||"middle";for(var r=e.split("\n"),a=r.length,h=this.fontSize+4,c=n+(1-a)/2*h,d=0;a>d;d++)t.fillText(r[d],i,c),c+=h}},M.prototype.getTextSize=function(t){if(void 0!==this.label){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace;for(var e=this.label.split("\n"),i=(this.fontSize+4)*e.length,n=0,s=0,o=e.length;o>s;s++)n=Math.max(n,t.measureText(e[s]).width);return{width:n,height:i}}return{width:0,height:0}},M.prototype.inArea=function(){return void 0!==this.width?this.x+this.width*this.graphScaleInv>=this.canvasTopLeft.x&&this.x-this.width*this.graphScaleInv=this.canvasTopLeft.y&&this.y-this.height*this.graphScaleInv=this.canvasTopLeft.x&&this.x=this.canvasTopLeft.y&&this.yh},D.prototype._drawLine=function(t){t.strokeStyle=this.color,t.lineWidth=this._getLineWidth();var e;if(this.from!=this.to)this._line(t),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y));else{var i,n,s=this.length/4,o=this.from;o.width||o.resize(t),o.width>o.height?(i=o.x+o.width/2,n=o.y-s):(i=o.x+s,n=o.y-o.height/2),this._circle(t,i,n,s),e=this._pointOnCircle(i,n,s,.5),this._label(t,this.label,e.x,e.y)}},D.prototype._getLineWidth=function(){return 1==this.selected?Math.min(2*this.width,this.widthMax)*this.graphScaleInv:this.width*this.graphScaleInv},D.prototype._line=function(t){t.beginPath(),t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y),t.stroke()},D.prototype._circle=function(t,e,i,n){t.beginPath(),t.arc(e,i,n,0,2*Math.PI,!1),t.stroke()},D.prototype._label=function(t,e,i,n){if(e){t.font=(this.from.selected||this.to.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle="white";var s=t.measureText(e).width,o=this.fontSize,r=i-s/2,a=n-o/2;t.fillRect(r,a,s,o),t.fillStyle=this.fontColor||"black",t.textAlign="left",t.textBaseline="top",t.fillText(e,r,a)}},D.prototype._drawDashLine=function(t){if(t.strokeStyle=this.color,t.lineWidth=this._getLineWidth(),t.beginPath(),t.lineCap="round",void 0!==this.dash.altLength?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]):void 0!==this.dash.length&&void 0!==this.dash.gap?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap]):(t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y)),t.stroke(),this.label){var e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}},D.prototype._pointOnLine=function(t){return{x:(1-t)*this.from.x+t*this.to.x,y:(1-t)*this.from.y+t*this.to.y}},D.prototype._pointOnCircle=function(t,e,i,n){var s=2*(n-3/8)*Math.PI;return{x:t+i*Math.cos(s),y:e-i*Math.sin(s)}},D.prototype._drawArrowCenter=function(t){var e;if(t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth(),this.from!=this.to){this._line(t);var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),n=10+5*this.width;e=this._pointOnLine(.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y))}else{var s,o,r=this.length/4,a=this.from;a.width||a.resize(t),a.width>a.height?(s=a.x+a.width/2,o=a.y-r):(s=a.x+r,o=a.y-a.height/2),this._circle(t,s,o,r);var i=.2*Math.PI,n=10+5*this.width;e=this._pointOnCircle(s,o,r,.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(s,o,r,.5),this._label(t,this.label,e.x,e.y))}},D.prototype._drawArrow=function(t){t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth();var e,i;if(this.from!=this.to){e=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x);var n=this.to.x-this.from.x,s=this.to.y-this.from.y,o=Math.sqrt(n*n+s*s),r=this.from.distanceToBorder(t,e+Math.PI),a=(o-r)/o,h=a*this.from.x+(1-a)*this.to.x,c=a*this.from.y+(1-a)*this.to.y,d=this.to.distanceToBorder(t,e),l=(o-d)/o,u=(1-l)*this.from.x+l*this.to.x,p=(1-l)*this.from.y+l*this.to.y;if(t.beginPath(),t.moveTo(h,c),t.lineTo(u,p),t.stroke(),i=10+5*this.width,t.arrow(u,p,e,i),t.fill(),t.stroke(),this.label){var f=this._pointOnLine(.5);this._label(t,this.label,f.x,f.y)}}else{var g,m,v,y=this.from,_=this.length/4;y.width||y.resize(t),y.width>y.height?(g=y.x+y.width/2,m=y.y-_,v={x:g,y:y.y,angle:.9*Math.PI}):(g=y.x+_,m=y.y-y.height/2,v={x:y.x,y:m,angle:.6*Math.PI}),t.beginPath(),t.arc(g,m,_,0,2*Math.PI,!1),t.stroke(),i=10+5*this.width,t.arrow(v.x,v.y,v.angle,i),t.fill(),t.stroke(),this.label&&(f=this._pointOnCircle(g,m,_,.5),this._label(t,this.label,f.x,f.y))}},D._dist=function(t,e,i,n,s,o){var r=i-t,a=n-e,h=r*r+a*a,c=((s-t)*r+(o-e)*a)/h;c>1?c=1:0>c&&(c=0);var d=t+c*r,l=e+c*a,u=d-s,p=l-o;return Math.sqrt(u*u+p*p)},D.prototype.setScale=function(t){this.graphScaleInv=1/t},D.prototype.select=function(){this.selected=!0},D.prototype.unselect=function(){this.selected=!1},O.prototype.setPosition=function(t,e){this.x=parseInt(t),this.y=parseInt(e)},O.prototype.setText=function(t){this.frame.innerHTML=t},O.prototype.show=function(t){if(void 0===t&&(t=!0),t){var e=this.frame.clientHeight,i=this.frame.clientWidth,n=this.frame.parentNode.clientHeight,s=this.frame.parentNode.clientWidth,o=this.y-e;o+e+this.padding>n&&(o=n-e-this.padding),os&&(r=s-i-this.padding),rAdd Node
    Edit Selected
    Connect Node
    Delete selected";var t=document.getElementById("manipulate-addNode");t.onclick=this._createAddToolbar.bind(this);var e=document.getElementById("manipulate-editNode");e.onclick=this._createEditToolbar.bind(this);var i=document.getElementById("manipulate-connectNode");i.onclick=this._createConnectToolbar.bind(this);var n=document.getElementById("manipulate-delete");n.onclick=this._deleteSelected.bind(this)},_createAddToolbar:function(){this._clearManipulatorBar(),this.off("select",this.boundFunction),this.manipulationDiv.innerHTML="Back
    Click in an empty space to place a new node";var t=document.getElementById("manipulate-back");t.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._addNode.bind(this),this.on("select",this.boundFunction)},_createEditToolbar:function(){this.selectForEdit=!1,this._clearManipulatorBar(),this.off("select",this.boundFunction);var t="";if(this._selectionIsEmpty()?t="Select a node or edge to edit.":this._getSelectedObjectCount()>1?(t="Select a single node or edge to edit.",this._unselectAll()):this._getSelectedNodeCount()>0?this._createEditNodeToolbar():this._createEditEdgeToolbar(),""!=t){this.selectForEdit=!0,this.manipulationDiv.innerHTML="Back
    "+t+"";var e=document.getElementById("manipulate-back");e.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._createEditToolbar.bind(this),this.on("select",this.boundFunction)}},_createEditNodeToolbar:function(){console.log("here)"),this.selectForEdit=!1,this._clearManipulatorBar(),this.off("select",this.boundFunction);var t=this._getEditObject();this.manipulationDiv.innerHTML="Back
    label:
    color:
    ";var e=document.getElementById("manipulate-back");e.onclick=this._createManipulatorBar.bind(this);var i=document.getElementById("manipulator-obj-save");i.onclick=this._saveNodeData.bind(this),this.boundFunction=this._createManipulatorBar.bind(this),this.on("select",this.boundFunction)},_saveNodeData:function(){var t=this._getEditObject();t.label=document.getElementById("manipulator-obj-label").innerHTML;document.getElementById("manipulator-obj-label").innerHTML;t.color.background=document.getElementById("manipulator-obj-label").innerHTML},_createEditEdgeToolbar:function(){},_createConnectToolbar:function(){this._clearManipulatorBar(),this.off("select",this.boundFunction),this._unselectAll(),this.selectingForConnection=!1,this.manipulationDiv.innerHTML="Back
    Select the node you want to connect to other nodes.";var t=document.getElementById("manipulate-back");t.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._handleConnect.bind(this),this.on("select",this.boundFunction)},_handleConnect:function(){this.selectingForConnection=!1,this._clusterInSelection()?(this._unselectClusters(!0),this._setManipulationMessage(this._selectionIsEmpty()?"Select the node you want to connect to other nodes (Clusters are not allowed).":"Click on the node you want to connect this node to (Clusters are not allowed).")):this._selectionIsEmpty()?this._setManipulationMessage("Select the node you want to connect to other nodes."):2==this._getSelectedNodeCount()?(this._connectNodes(),this._restoreSourceNode(),this._setManipulationMessage("Click on another node you want to connect this node to or go back.")):(this._setManipulationMessage("Click on the node you want to connect this node."),this._setSourceNode(),this.selectingForConnection=!0)},_getEditObject:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t))return this.selectionObj[t];return null},_setSourceNode:function(){for(var t in this.selectionObj)this.selectionObj.hasOwnProperty(t)&&this.selectionObj[t]instanceof M&&(this.manipulationSourceNode=this.selectionObj[t])},_getTargetNode:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t)&&this.selectionObj[t]instanceof M&&this.manipulationSourceNode.id!=this.selectionObj[t].id)return this.selectionObj[t];return null},_restoreSourceNode:function(){this._unselectAll(!0),this._selectObject(this.manipulationSourceNode)},_setManipulationMessage:function(t){var e=document.getElementById("manipulatorLabel");e.innerHTML=t},_addNode:function(){if(this._selectionIsEmpty()){var t=this._pointerToPositionObject(this.pointerPosition);this.createNodeOnClick=!0,this.nodesData.add({id:z.randomUUID(),x:t.left,y:t.top,label:"new",fixed:!1}),this.createNodeOnClick=!1,this.moving=!0,this.start()}},_connectNodes:function(){var t=this._getTargetNode(),e=this.manipulationSourceNode;this.edgesData.add({from:e.id,to:t.id}),this.moving=!0,this.start()},_deleteSelected:function(){if(this._clusterInSelection())alert("Clusters cannot be deleted.");else{var t=this.getSelectedNodes(),e=this.getSelectedEdges();this._removeEdges(e),this._removeNodes(t),this._redraw()}}},R={_putDataInSector:function(){this.sectors.active[this._sector()].nodes=this.nodes,this.sectors.active[this._sector()].edges=this.edges,this.sectors.active[this._sector()].nodeIndices=this.nodeIndices},_switchToSector:function(t,e){void 0===e||"active"==e?this._switchToActiveSector(t):this._switchToFrozenSector(t)},_switchToActiveSector:function(t){this.nodeIndices=this.sectors.active[t].nodeIndices,this.nodes=this.sectors.active[t].nodes,this.edges=this.sectors.active[t].edges},_switchToFrozenSector:function(t){this.nodeIndices=this.sectors.frozen[t].nodeIndices,this.nodes=this.sectors.frozen[t].nodes,this.edges=this.sectors.frozen[t].edges},_switchToNavigationSector:function(){this.nodeIndices=this.sectors.navigation.nodeIndices,this.nodes=this.sectors.navigation.nodes,this.edges=this.sectors.navigation.edges},_loadLatestSector:function(){this._switchToSector(this._sector())},_sector:function(){return this.activeSector[this.activeSector.length-1]},_previousSector:function(){if(this.activeSector.length>1)return this.activeSector[this.activeSector.length-2];throw new TypeError("there are not enough sectors in the this.activeSector array.")},_setActiveSector:function(t){this.activeSector.push(t)},_forgetLastSector:function(){this.activeSector.pop()},_createNewSector:function(t){this.sectors.active[t]={nodes:{},edges:{},nodeIndices:[],formationScale:this.scale,drawingNode:void 0},this.sectors.active[t].drawingNode=new M({id:t,color:{background:"#eaefef",border:"495c5e"}},{},{},this.constants),this.sectors.active[t].drawingNode.clusterSize=2},_deleteActiveSector:function(t){delete this.sectors.active[t]},_deleteFrozenSector:function(t){delete this.sectors.frozen[t]},_freezeSector:function(t){this.sectors.frozen[t]=this.sectors.active[t],this._deleteActiveSector(t)},_activateSector:function(t){this.sectors.active[t]=this.sectors.frozen[t],this._deleteFrozenSector(t)},_mergeThisWithFrozen:function(t){for(var e in this.nodes)this.nodes.hasOwnProperty(e)&&(this.sectors.frozen[t].nodes[e]=this.nodes[e]);for(var i in this.edges)this.edges.hasOwnProperty(i)&&(this.sectors.frozen[t].edges[i]=this.edges[i]);for(var n=0;n1?this[t](n[0],n[1]):this[t](e)}this._loadLatestSector()},_doInAllFrozenSectors:function(t,e){if(void 0===e)for(var i in this.sectors.frozen)this.sectors.frozen.hasOwnProperty(i)&&(this._switchToFrozenSector(i),this[t]());else for(var i in this.sectors.frozen)if(this.sectors.frozen.hasOwnProperty(i)){this._switchToFrozenSector(i);var n=Array.prototype.splice.call(arguments,1);n.length>1?this[t](n[0],n[1]):this[t](e)}this._loadLatestSector()},_doInNavigationSector:function(t,e){if(this._switchToNavigationSector(),void 0===e)this[t]();else{var i=Array.prototype.splice.call(arguments,1);i.length>1?this[t](i[0],i[1]):this[t](e)}this._loadLatestSector()},_doInAllSectors:function(t,e){var i=Array.prototype.splice.call(arguments,1);void 0===e?(this._doInAllActiveSectors(t),this._doInAllFrozenSectors(t)):i.length>1?(this._doInAllActiveSectors(t,i[0],i[1]),this._doInAllFrozenSectors(t,i[0],i[1])):(this._doInAllActiveSectors(t,e),this._doInAllFrozenSectors(t,e))},_clearNodeIndexList:function(){var t=this._sector();this.sectors.active[t].nodeIndices=[],this.nodeIndices=this.sectors.active[t].nodeIndices},_drawSectorNodes:function(t,e){var i,n=1e9,s=-1e9,o=1e9,r=-1e9; -for(var a in this.sectors[e])if(this.sectors[e].hasOwnProperty(a)&&void 0!==this.sectors[e][a].drawingNode){this._switchToSector(a,e),n=1e9,s=-1e9,o=1e9,r=-1e9;for(var h in this.nodes)this.nodes.hasOwnProperty(h)&&(i=this.nodes[h],i.resize(t),o>i.x-.5*i.width&&(o=i.x-.5*i.width),ri.y-.5*i.height&&(n=i.y-.5*i.height),st&&n>s;)s%3==0?this.forceAggregateHubs():this.increaseClusterLevel(),i=this.nodeIndices.length,s+=1;s>1&&1==e&&this.repositionNodes()},openCluster:function(t){var e=this.moving;if(t.clusterSize>this.constants.clustering.sectorThreshold&&this._nodeInActiveArea(t)&&("default"!=this._sector()||1!=this.nodeIndices.length)){this._addSector(t);for(var i=0;this.nodeIndices.lengthi;)this.decreaseClusterLevel(),i+=1}else this._expandClusterNode(t,!1,!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels();this.moving!=e&&this.start()},updateClustersDefault:function(){1==this.constants.clustering.enabled&&this.updateClusters(0,!1,!1)},increaseClusterLevel:function(){this.updateClusters(-1,!1,!0)},decreaseClusterLevel:function(){this.updateClusters(1,!1,!0)},updateClusters:function(t,e,i){var n=this.moving,s=this.nodeIndices.length;this.previousScale>this.scale&&0==t&&this._collapseSector(),this.previousScale>this.scale||-1==t?this._formClusters(i):(this.previousScalethis.scale||-1==t)&&(this._aggregateHubs(i),this._updateNodeIndexList()),(this.previousScale>this.scale||-1==t)&&(this.handleChains(),this._updateNodeIndexList()),this.previousScale=this.scale,this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.lengththis.constants.clustering.chainThreshold&&this._reduceAmountOfChains(1-this.constants.clustering.chainThreshold/t)},_aggregateHubs:function(t){this._getHubSize(),this._formClustersByHub(t,!1)},forceAggregateHubs:function(){var t=this.moving,e=this.nodeIndices.length;this._aggregateHubs(!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.length!=e&&(this.clusterSession+=1),this.moving!=t&&this.start()},_openClustersBySize:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];1==e.inView()&&(e.width*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientWidth||e.height*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientHeight)&&this.openCluster(e)}},_openClusters:function(t,e){for(var i=0;i1&&(t.clusterSizei)){var r=o.from,a=o.to;o.to.mass>o.from.mass&&(r=o.to,a=o.from),1==a.dynamicEdgesLength?this._addToCluster(r,a,!1):1==r.dynamicEdgesLength&&this._addToCluster(a,r,!1)}}},_forceClustersByZoom:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];if(1==e.dynamicEdgesLength&&0!=e.dynamicEdges.length){var i=e.dynamicEdges[0],n=i.toId==e.id?this.nodes[i.fromId]:this.nodes[i.toId];e.id!=n.id&&(n.mass>e.mass?this._addToCluster(n,e,!0):this._addToCluster(e,n,!0))}}},_formClustersByHub:function(t,e){for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&this._formClusterFromHub(this.nodes[i],t,e)},_formClusterFromHub:function(t,e,i,n){if(void 0===n&&(n=0),t.dynamicEdgesLength>=this.hubThreshold&&0==i||t.dynamicEdgesLength==this.hubThreshold&&1==i){for(var s,o,r,a=this.constants.clustering.clusterEdgeThreshold/this.scale,h=!1,c=[],d=t.dynamicEdges.length,l=0;d>l;l++)c.push(t.dynamicEdges[l].id);if(0==e)for(h=!1,l=0;d>l;l++){var u=this.edges[c[l]];if(void 0!==u&&u.connected&&u.toId!=u.fromId&&(s=u.to.x-u.from.x,o=u.to.y-u.from.y,r=Math.sqrt(s*s+o*o),a>r)){h=!0;break}}if(!e&&h||e)for(l=0;d>l;l++)if(u=this.edges[c[l]],void 0!==u){var p=this.nodes[u.fromId==t.id?u.toId:u.fromId];p.dynamicEdges.length<=this.hubThreshold+n&&p.id!=t.id&&this._addToCluster(t,p,e)}}},_addToCluster:function(t,e,i){t.containedNodes[e.id]=e;for(var n=0;n1)for(var n=0;n1&&(e.label="[".concat(String(e.clusterSize),"]"))}for(t in this.nodes)this.nodes.hasOwnProperty(t)&&(e=this.nodes[t],1==e.clusterSize&&(e.label=void 0!==e.originalLabel?e.originalLabel:String(e.id)))},_nodeInActiveArea:function(t){return Math.abs(t.x-this.areaCenter.x)<=this.constants.clustering.activeAreaBoxSize/this.scale&&Math.abs(t.y-this.areaCenter.y)<=this.constants.clustering.activeAreaBoxSize/this.scale},repositionNodes:function(){for(var t=0;tn&&(n=o.dynamicEdgesLength),t+=o.dynamicEdgesLength,e+=Math.pow(o.dynamicEdgesLength,2),i+=1}t/=i,e/=i;var r=e-Math.pow(t,2),a=Math.sqrt(r);this.hubThreshold=Math.floor(t+2*a),this.hubThreshold>n&&(this.hubThreshold=n)},_reduceAmountOfChains:function(t){this.hubThreshold=2;var e=Math.floor(this.nodeIndices.length*t);for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&e>0&&(this._formClusterFromHub(this.nodes[i],!0,!0,1),e-=1)},_getChainFraction:function(){var t=0,e=0;for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&(2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&(t+=1),e+=1);return t/e}},j={_getNodesOverlappingWith:function(t,e){var i=this.nodes;for(var n in i)i.hasOwnProperty(n)&&i[n].isOverlappingWith(t)&&e.push(n)},_getAllNodesOverlappingWith:function(t){var e=[];return this._doInAllActiveSectors("_getNodesOverlappingWith",t,e),e},_getAllNavigationNodesOverlappingWith:function(t){var e=[];return this._doInNavigationSector("_getNodesOverlappingWith",t,e),e},_pointerToPositionObject:function(t){var e=this._canvasToX(t.x),i=this._canvasToY(t.y);return{left:e,top:i,right:e,bottom:i}},_pointerToScreenPositionObject:function(t){var e=t.x,i=t.y;return{left:e,top:i,right:e,bottom:i}},_getNavigationNodeAt:function(t){var e=this._pointerToScreenPositionObject(t),i=this._getAllNavigationNodesOverlappingWith(e);return i.length>0?this.sectors.navigation.nodes[i[i.length-1]]:null},_getNodeAt:function(t){var e=this._pointerToPositionObject(t),i=this._getAllNodesOverlappingWith(e);return i.length>0?this.nodes[i[i.length-1]]:null},_getEdgesOverlappingWith:function(t,e){var i=this.edges;for(var n in i)i.hasOwnProperty(n)&&i[n].isOverlappingWith(t)&&e.push(n)},_getAllEdgesOverlappingWith:function(t){var e=[];return this._doInAllActiveSectors("_getEdgesOverlappingWith",t,e),e},_getEdgeAt:function(t){var e=this._pointerToPositionObject(t),i=this._getAllEdgesOverlappingWith(e);return i.length>0?this.edges[i[i.length-1]]:null},_addToSelection:function(t){this.selectionObj[t.id]=t},_removeFromSelection:function(t){delete this.selectionObj[t.id]},_unselectAll:function(t){void 0===t&&(t=!1);for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e].unselect();this.selectionObj={},0==t&&this._trigger("select",{nodes:this.getSelection()})},_unselectClusters:function(t){void 0===t&&(t=!1);for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e]instanceof M&&this.selectionObj[e].clusterSize>1&&this.selectionObj[e].unselect();0==t&&this._trigger("select",{nodes:this.getSelection()})},_getSelectedNodeCount:function(){var t=0;for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e]instanceof M&&(t+=1);return t},_getSelectedEdgeCount:function(){var t=0;for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e]instanceof D&&(t+=1);return t},_getSelectedObjectCount:function(){var t=0;for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&(t+=1);return t},_selectionIsEmpty:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t))return!1;return!0},_clusterInSelection:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t)&&this.selectionObj[t]instanceof M&&this.selectionObj[t].clusterSize>1)return!0;return!1},_selectConnectedEdges:function(t){for(var e=0;ee;e++){n=t[e];var s=this.nodes[n];if(!s)throw new RangeError('Node with id "'+n+'" not found');this._selectObject(s,!0,!0)}this.redraw()},_updateSelection:function(){for(var t in this.selectionObj)this.selectionObj.hasOwnProperty(t)&&(this.selectionObj[t]instanceof M?this.nodes.hasOwnProperty(t)||delete this.selectionObj[t]:this.edges.hasOwnProperty(t)||delete this.selectionObj[t])}},U={_relocateNavigation:function(){if(void 0!==this.sectors){var t=this.navigationClientWidth-this.frame.canvas.clientWidth,e=this.navigationClientHeight-this.frame.canvas.clientHeight;this.navigationClientWidth=this.frame.canvas.clientWidth,this.navigationClientHeight=this.frame.canvas.clientHeight;var i=null;for(var n in this.sectors.navigation.nodes)this.sectors.navigation.nodes.hasOwnProperty(n)&&(i=this.sectors.navigation.nodes[n],i.horizontalAlignLeft||(i.x-=t),i.verticalAlignTop||(i.y-=e))}},_loadNavigationElements:function(){var t=this.constants.navigation.iconPath;this.navigationClientWidth=this.frame.canvas.clientWidth,this.navigationClientHeight=this.frame.canvas.clientHeight,void 0===this.navigationClientWidth&&(this.navigationClientWidth=0,this.navigationClientHeight=0);for(var e=15,i=7,n=[{id:"navigation_up",shape:"image",image:t+"/uparrow.png",triggerFunction:"_moveUp",verticalAlignTop:!1,x:45+e+i,y:this.navigationClientHeight-45-e-i},{id:"navigation_down",shape:"image",image:t+"/downarrow.png",triggerFunction:"_moveDown",verticalAlignTop:!1,x:45+e+i,y:this.navigationClientHeight-15-e},{id:"navigation_left",shape:"image",image:t+"/leftarrow.png",triggerFunction:"_moveLeft",verticalAlignTop:!1,x:15+e,y:this.navigationClientHeight-15-e},{id:"navigation_right",shape:"image",image:t+"/rightarrow.png",triggerFunction:"_moveRight",verticalAlignTop:!1,x:75+e+2*i,y:this.navigationClientHeight-15-e},{id:"navigation_plus",shape:"image",image:t+"/plus.png",triggerFunction:"_zoomIn",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-45-e-i,y:this.navigationClientHeight-15-e},{id:"navigation_min",shape:"image",image:t+"/minus.png",triggerFunction:"_zoomOut",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-15-e,y:this.navigationClientHeight-15-e},{id:"navigation_zoomExtends",shape:"image",image:t+"/zoomExtends.png",triggerFunction:"zoomToFit",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-15-e,y:this.navigationClientHeight-45-e-i}],s=null,o=0;ot.x-t.width&&(n=t.x-t.width),st.y-t.height&&(e=t.y-t.height),i=this.constants.clustering.initialMaxNodes)var n=38.8467/(e-14.50184)+.0116;else var n=42.54117319/(e+39.31966387)+.1944405;else{var s=1.1*(Math.abs(i.minX)+Math.abs(i.maxX)),o=1.1*(Math.abs(i.minY)+Math.abs(i.maxY)),r=this.frame.canvas.clientWidth/s,a=this.frame.canvas.clientHeight/o;n=a>=r?r:a}n>1&&(n=1),this.pinch.mousewheelScale=n,this._setScale(n),this._centerGraph(i),this.start()},I.prototype._updateNodeIndexList=function(){this._clearNodeIndexList();for(var t in this.nodes)this.nodes.hasOwnProperty(t)&&this.nodeIndices.push(t)},I.prototype.setData=function(t,e){if(void 0===e&&(e=!1),t&&t.dot&&(t.nodes||t.edges))throw new SyntaxError('Data must contain either parameter "dot" or parameter pair "nodes" and "edges", but not both.');if(this.setOptions(t&&t.options),t&&t.dot){if(t&&t.dot){var i=B.util.DOTToGraph(t.dot);return void this.setData(i)}}else this._setNodes(t&&t.nodes),this._setEdges(t&&t.edges);this._putDataInSector(),e||(this.stabilize&&this._doStabilize(),this.moving=!0,this.start())},I.prototype.setOptions=function(t){if(t){if(void 0!==t.width&&(this.width=t.width),void 0!==t.height&&(this.height=t.height),void 0!==t.stabilize&&(this.stabilize=t.stabilize),void 0!==t.selectable&&(this.selectable=t.selectable),t.clustering){this.constants.clustering.enabled=!0;for(var e in t.clustering)t.clustering.hasOwnProperty(e)&&(this.constants.clustering[e]=t.clustering[e])}else void 0!==t.clustering&&(this.constants.clustering.enabled=!1);if(t.navigation){this.constants.navigation.enabled=!0;for(var e in t.navigation)t.navigation.hasOwnProperty(e)&&(this.constants.navigation[e]=t.navigation[e])}else void 0!==t.navigation&&(this.constants.navigation.enabled=!1);if(t.keyboard){this.constants.keyboard.enabled=!0;for(var e in t.keyboard)t.keyboard.hasOwnProperty(e)&&(this.constants.keyboard[e]=t.keyboard[e])}else void 0!==t.keyboard&&(this.constants.keyboard.enabled=!1);if(t.edges){for(e in t.edges)t.edges.hasOwnProperty(e)&&(this.constants.edges[e]=t.edges[e]);void 0!==t.edges.length&&t.nodes&&void 0===t.nodes.distance&&(this.constants.edges.length=t.edges.length,this.constants.nodes.distance=1.25*t.edges.length),t.edges.fontColor||(this.constants.edges.fontColor=t.edges.color),t.edges.dash&&(void 0!==t.edges.dash.length&&(this.constants.edges.dash.length=t.edges.dash.length),void 0!==t.edges.dash.gap&&(this.constants.edges.dash.gap=t.edges.dash.gap),void 0!==t.edges.dash.altLength&&(this.constants.edges.dash.altLength=t.edges.dash.altLength))}if(t.nodes){for(e in t.nodes)t.nodes.hasOwnProperty(e)&&(this.constants.nodes[e]=t.nodes[e]);t.nodes.color&&(this.constants.nodes.color=M.parseColor(t.nodes.color))}if(t.groups)for(var i in t.groups)if(t.groups.hasOwnProperty(i)){var n=t.groups[i];this.groups.add(i,n)}}this.setSize(this.width,this.height),this._setTranslation(this.frame.clientWidth/2,this.frame.clientHeight/2),this._setScale(1),this._loadNavigationControls(),this._createKeyBinds(),this._redraw()},I.prototype.on=function(t,e){var i=["select"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());F.addListener(this,t,e)},I.prototype.off=function(t,e){F.removeListener(this,t,e)},I.prototype._trigger=function(t,e){F.trigger(this,t,e)},I.prototype._create=function(){for(;this.containerElement.hasChildNodes();)this.containerElement.removeChild(this.containerElement.firstChild);if(this.frame=document.createElement("div"),this.frame.className="graph-frame",this.frame.style.position="relative",this.frame.style.overflow="hidden",this.frame.style.zIndex="1",this.frame.canvas=document.createElement("canvas"),this.frame.canvas.style.position="relative",this.frame.appendChild(this.frame.canvas),!this.frame.canvas.getContext){var t=document.createElement("DIV");t.style.color="red",t.style.fontWeight="bold",t.style.padding="10px",t.innerHTML="Error: your browser does not support HTML canvas",this.frame.canvas.appendChild(t)}var e=this;this.drag={},this.pinch={},this.hammer=N(this.frame.canvas,{prevent_default:!0}),this.hammer.on("tap",e._onTap.bind(e)),this.hammer.on("doubletap",e._onDoubleTap.bind(e)),this.hammer.on("hold",e._onHold.bind(e)),this.hammer.on("pinch",e._onPinch.bind(e)),this.hammer.on("touch",e._onTouch.bind(e)),this.hammer.on("dragstart",e._onDragStart.bind(e)),this.hammer.on("drag",e._onDrag.bind(e)),this.hammer.on("dragend",e._onDragEnd.bind(e)),this.hammer.on("release",e._onRelease.bind(e)),this.hammer.on("mousewheel",e._onMouseWheel.bind(e)),this.hammer.on("DOMMouseScroll",e._onMouseWheel.bind(e)),this.hammer.on("mousemove",e._onMouseMoveTitle.bind(e)),this.containerElement.appendChild(this.frame)},I.prototype._createKeyBinds=function(){var t=this;this.mousetrap=k,this.mousetrap.reset(),1==this.constants.keyboard.enabled&&(this.mousetrap.bind("up",this._moveUp.bind(t),"keydown"),this.mousetrap.bind("up",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("down",this._moveDown.bind(t),"keydown"),this.mousetrap.bind("down",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("left",this._moveLeft.bind(t),"keydown"),this.mousetrap.bind("left",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("right",this._moveRight.bind(t),"keydown"),this.mousetrap.bind("right",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("=",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("=",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("-",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("-",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("[",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("[",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("]",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("]",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pageup",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("pageup",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pagedown",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("pagedown",this._stopZoom.bind(t),"keyup"))},I.prototype._getPointer=function(t){return{x:t.pageX-B.util.getAbsoluteLeft(this.frame.canvas),y:t.pageY-B.util.getAbsoluteTop(this.frame.canvas)}},I.prototype._onTouch=function(t){this.drag.pointer=this._getPointer(t.gesture.touches[0]),this.drag.pinched=!1,this.pinch.scale=this._getScale(),this._handleTouch(this.drag.pointer)},I.prototype._onDragStart=function(){var t=this.drag,e=this._getNodeAt(t.pointer);if(t.dragging=!0,t.selection=[],t.translation=this._getTranslation(),t.nodeId=null,null!=e){t.nodeId=e.id,e.isSelected()||this._selectObject(e,!1);for(var i in this.selectionObj)if(this.selectionObj.hasOwnProperty(i)){var n=this.selectionObj[i];if(n instanceof M){var s={id:n.id,node:n,x:n.x,y:n.y,xFixed:n.xFixed,yFixed:n.yFixed};n.xFixed=!0,n.yFixed=!0,t.selection.push(s)}}}},I.prototype._onDrag=function(t){if(!this.drag.pinched){var e=this._getPointer(t.gesture.touches[0]),i=this,n=this.drag,s=n.selection;if(s&&s.length){var o=e.x-n.pointer.x,r=e.y-n.pointer.y;s.forEach(function(t){var e=t.node;t.xFixed||(e.x=i._canvasToX(i._xToCanvas(t.x)+o)),t.yFixed||(e.y=i._canvasToY(i._yToCanvas(t.y)+r))}),this.moving||(this.moving=!0,this.start())}else{var a=e.x-this.drag.pointer.x,h=e.y-this.drag.pointer.y;this._setTranslation(this.drag.translation.x+a,this.drag.translation.y+h),this._redraw(),this.moved=!0}}},I.prototype._onDragEnd=function(){this.drag.dragging=!1;var t=this.drag.selection;t&&t.forEach(function(t){t.node.xFixed=t.xFixed,t.node.yFixed=t.yFixed})},I.prototype._onTap=function(t){var e=this._getPointer(t.gesture.touches[0]);this.pointerPosition=e,this._handleTap(e)},I.prototype._onDoubleTap=function(t){var e=this._getPointer(t.gesture.touches[0]);this._handleDoubleTap(e)},I.prototype._onHold=function(t){var e=this._getPointer(t.gesture.touches[0]);this.pointerPosition=e,this._handleOnHold(e)},I.prototype._onRelease=function(){this._handleOnRelease()},I.prototype._onPinch=function(t){var e=this._getPointer(t.gesture.center);this.drag.pinched=!0,"scale"in this.pinch||(this.pinch.scale=1);var i=this.pinch.scale*t.gesture.scale;this._zoom(i,e)},I.prototype._zoom=function(t,e){var i=this._getScale();1e-5>t&&(t=1e-5),t>10&&(t=10);var n=this._getTranslation(),s=t/i,o=(1-s)*e.x+n.x*s,r=(1-s)*e.y+n.y*s;return this.areaCenter={x:this._canvasToX(e.x),y:this._canvasToY(e.y)},this.pinch.mousewheelScale=t,this._setScale(t),this._setTranslation(o,r),this.updateClustersDefault(),this._redraw(),t},I.prototype._onMouseWheel=function(t){var e=0;if(t.wheelDelta?e=t.wheelDelta/120:t.detail&&(e=-t.detail/3),e){"mousewheelScale"in this.pinch||(this.pinch.mousewheelScale=1);var i=this.pinch.mousewheelScale,n=e/10;0>e&&(n/=1-n),i*=1+n;var s=z.fakeGesture(this,t),o=this._getPointer(s.center);i=this._zoom(i,o)}t.preventDefault()},I.prototype._onMouseMoveTitle=function(t){var e=z.fakeGesture(this,t),i=this._getPointer(e.center);this.popupNode&&this._checkHidePopup(i);var n=this,s=function(){n._checkShowPopup(i)};this.popupTimer&&clearInterval(this.popupTimer),this.drag.dragging||(this.popupTimer=setTimeout(s,300))},I.prototype._checkShowPopup=function(t){var e,i={left:this._canvasToX(t.x),top:this._canvasToY(t.y),right:this._canvasToX(t.x),bottom:this._canvasToY(t.y)},n=this.popupNode;if(void 0==this.popupNode){var s=this.nodes;for(e in s)if(s.hasOwnProperty(e)){var o=s[e];if(void 0!==o.getTitle()&&o.isOverlappingWith(i)){this.popupNode=o;break}}}if(void 0===this.popupNode){var r=this.edges;for(e in r)if(r.hasOwnProperty(e)){var a=r[e];if(a.connected&&void 0!==a.getTitle()&&a.isOverlappingWith(i)){this.popupNode=a;break}}}if(this.popupNode){if(this.popupNode!=n){var h=this;h.popup||(h.popup=new O(h.frame)),h.popup.setPosition(t.x-3,t.y-3),h.popup.setText(h.popupNode.getTitle()),h.popup.show()}}else this.popup&&this.popup.hide()},I.prototype._checkHidePopup=function(t){this.popupNode&&this._getNodeAt(t)||(this.popupNode=void 0,this.popup&&this.popup.hide())},I.prototype._getConnectionCount=function(t){function e(t){for(var e=[],i=0,n=t.length;n>i;i++)for(var s=t[i],o=s.edges,r=0,a=o.length;a>r;r++){var h=o[r],c=null;h.from==s?c=h.to:h.to==s&&(c=h.from);var d,l;if(c)for(d=0,l=t.length;l>d;d++)if(t[d]==c){c=null;break}if(c)for(d=0,l=e.length;l>d;d++)if(e[d]==c){c=null;break}c&&e.push(c)}return e}void 0==t&&(t=1);var i=[],n=this.nodes;for(var s in n)if(n.hasOwnProperty(s)){for(var o=[n[s]],r=0;t>r;r++)o=o.concat(e(o));i.push(o)}for(var a=[],h=0,c=i.length;c>h;h++)a.push(i[h].length);return a},I.prototype.setSize=function(t,e){this.frame.style.width=t,this.frame.style.height=e,this.frame.canvas.style.width="100%",this.frame.canvas.style.height="100%",this.frame.canvas.width=this.frame.canvas.clientWidth,this.frame.canvas.height=this.frame.canvas.clientHeight,void 0!==this.manipulationDiv&&(this.manipulationDiv.style.width=this.frame.canvas.clientWidth),1==this.constants.navigation.enabled&&this._relocateNavigation() -},I.prototype._setNodes=function(t){var e=this.nodesData;if(t instanceof o||t instanceof r)this.nodesData=t;else if(t instanceof Array)this.nodesData=new o,this.nodesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.nodesData=new o}if(e&&z.forEach(this.nodesListeners,function(t,i){e.unsubscribe(i,t)}),this.nodes={},this.nodesData){var i=this;z.forEach(this.nodesListeners,function(t,e){i.nodesData.subscribe(e,t)});var n=this.nodesData.getIds();this._addNodes(n)}this._updateSelection()},I.prototype._addNodes=function(t){for(var e,i=0,n=t.length;n>i;i++){e=t[i];var s=this.nodesData.get(e),o=new M(s,this.images,this.groups,this.constants);if(this.nodes[e]=o,!o.isFixed()&&1!=this.createNodeOnClick){var r=2*this.constants.edges.length,a=t.length,h=2*Math.PI*(i/a);o.x=r*Math.cos(h),o.y=r*Math.sin(h),this.moving=!0}}this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(this.nodes),this.updateLabels()},I.prototype._updateNodes=function(t){for(var e=this.nodes,i=this.nodesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o],a=i.get(o);r?r.setProperties(a,this.constants):(r=new M(properties,this.images,this.groups,this.constants),e[o]=r,r.isFixed()||(this.moving=!0))}this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(e)},I.prototype._removeNodes=function(t){for(var e=this.nodes,i=0,n=t.length;n>i;i++){var s=t[i];delete e[s]}this._updateNodeIndexList(),this._reconnectEdges(),this._updateSelection(),this._updateValueRange(e)},I.prototype._setEdges=function(t){var e=this.edgesData;if(t instanceof o||t instanceof r)this.edgesData=t;else if(t instanceof Array)this.edgesData=new o,this.edgesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.edgesData=new o}if(e&&z.forEach(this.edgesListeners,function(t,i){e.unsubscribe(i,t)}),this.edges={},this.edgesData){var i=this;z.forEach(this.edgesListeners,function(t,e){i.edgesData.subscribe(e,t)});var n=this.edgesData.getIds();this._addEdges(n)}this._reconnectEdges()},I.prototype._addEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o];r&&r.disconnect();var a=i.get(o,{showInternalIds:!0});e[o]=new D(a,this,this.constants)}this.moving=!0,this._updateValueRange(e)},I.prototype._updateEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=i.get(o),a=e[o];a?(a.disconnect(),a.setProperties(r,this.constants),a.connect()):(a=new D(r,this,this.constants),this.edges[o]=a)}this.moving=!0,this._updateValueRange(e)},I.prototype._removeEdges=function(t){for(var e=this.edges,i=0,n=t.length;n>i;i++){var s=t[i],o=e[s];o&&(o.disconnect(),delete e[s])}this.moving=!0,this._updateValueRange(e)},I.prototype._reconnectEdges=function(){var t,e=this.nodes,i=this.edges;for(t in e)e.hasOwnProperty(t)&&(e[t].edges=[]);for(t in i)if(i.hasOwnProperty(t)){var n=i[t];n.from=null,n.to=null,n.connect()}},I.prototype._updateValueRange=function(t){var e,i=void 0,n=void 0;for(e in t)if(t.hasOwnProperty(e)){var s=t[e].getValue();void 0!==s&&(i=void 0===i?s:Math.min(s,i),n=void 0===n?s:Math.max(s,n))}if(void 0!==i&&void 0!==n)for(e in t)t.hasOwnProperty(e)&&t[e].setValueRange(i,n)},I.prototype.redraw=function(){this.setSize(this.width,this.height),this._redraw()},I.prototype._redraw=function(){var t=this.frame.canvas.getContext("2d"),e=this.frame.canvas.width,i=this.frame.canvas.height;t.clearRect(0,0,e,i),t.save(),t.translate(this.translation.x,this.translation.y),t.scale(this.scale,this.scale),this.canvasTopLeft={x:this._canvasToX(0),y:this._canvasToY(0)},this.canvasBottomRight={x:this._canvasToX(this.frame.canvas.clientWidth),y:this._canvasToY(this.frame.canvas.clientHeight)},this._doInAllSectors("_drawAllSectorNodes",t),this._doInAllSectors("_drawEdges",t),this._doInAllSectors("_drawNodes",t,!0),t.restore(),1==this.constants.navigation.enabled&&this._doInNavigationSector("_drawNodes",t,!0)},I.prototype._setTranslation=function(t,e){void 0===this.translation&&(this.translation={x:0,y:0}),void 0!==t&&(this.translation.x=t),void 0!==e&&(this.translation.y=e)},I.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},I.prototype._setScale=function(t){this.scale=t},I.prototype._getScale=function(){return this.scale},I.prototype._canvasToX=function(t){return(t-this.translation.x)/this.scale},I.prototype._xToCanvas=function(t){return t*this.scale+this.translation.x},I.prototype._canvasToY=function(t){return(t-this.translation.y)/this.scale},I.prototype._yToCanvas=function(t){return t*this.scale+this.translation.y},I.prototype._drawNodes=function(t,e){void 0===e&&(e=!1);var i=this.nodes,n=[];for(var s in i)i.hasOwnProperty(s)&&(i[s].setScaleAndPos(this.scale,this.canvasTopLeft,this.canvasBottomRight),i[s].isSelected()?n.push(s):(i[s].inArea()||e)&&i[s].draw(t));for(var o=0,r=n.length;r>o;o++)(i[n[o]].inArea()||e)&&i[n[o]].draw(t)},I.prototype._drawEdges=function(t){var e=this.edges;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];n.setScale(this.scale),n.connected&&e[i].draw(t)}},I.prototype._doStabilize=function(){for(var t=0,e=this.constants.minVelocity,i=!1;!i&&tthis.constants.clustering.clusterThreshold&&1==this.constants.clustering.enabled&&this.clusterToFit(this.constants.clustering.reduceToNodes,!1),this._calculateForces())},I.prototype._calculateForces=function(){var t,e,i,n,s,o,r,a,h,c,d,l,u,p,f,g,m,v,y=this.nodes,_=this.edges,w=.08*this.forceFactor;for(g=0;gn&&(i=Math.atan2(e,t),r=.5*b>n?1:T*n+E,r*=0==v?1:1+v*this.constants.clustering.forceAmplification,r*=this.forceFactor,s=Math.cos(i)*r,o=Math.sin(i)*r,l._addForce(-s,-o),u._addForce(s,o))}for(f in _)_.hasOwnProperty(f)&&(p=_[f],p.connected&&this.nodes.hasOwnProperty(p.toId)&&this.nodes.hasOwnProperty(p.fromId)&&(v=p.to.clusterSize+p.from.clusterSize-2,t=p.to.x-p.from.x,e=p.to.y-p.from.y,c=p.length,c+=v*this.constants.clustering.edgeGrowth,h=Math.sqrt(t*t+e*e),i=Math.atan2(e,t),a=p.stiffness*(c-h)*this.forceFactor,s=Math.cos(i)*a,o=Math.sin(i)*a,p.from._addForce(-s,-o),p.to._addForce(s,o)))},I.prototype._isMoving=function(t){var e=t/this.scale,i=this.nodes;for(var n in i)if(i.hasOwnProperty(n)&&i[n].isMoving(e))return!0;return!1},I.prototype._discreteStepNodes=function(){var t=.01,e=this.nodes;for(var i in e)e.hasOwnProperty(i)&&e[i].discreteStep(t);var n=this.constants.minVelocity;this.moving=this._isMoving(n)},I.prototype.start=function(){if(!this.freezeSimulation)if(this.moving&&(this._doInAllActiveSectors("_initializeForceCalculation"),this._doInAllActiveSectors("_discreteStepNodes"),this._findCenter(this._getRange())),this.moving||0!=this.xIncrement||0!=this.yIncrement||0!=this.zoomIncrement){if(!this.timer){var t=this;this.timer=window.setTimeout(function(){if(t.timer=void 0,0!=t.xIncrement||0!=t.yIncrement){var e=t._getTranslation();t._setTranslation(e.x+t.xIncrement,e.y+t.yIncrement)}if(0!=t.zoomIncrement){var i={x:t.frame.canvas.clientWidth/2,y:t.frame.canvas.clientHeight/2};t._zoom(t.scale*(1+t.zoomIncrement),i)}t.start(),t._redraw()},this.renderTimestep)}}else this._redraw()},I.prototype.singleStep=function(){if(this.moving){this._initializeForceCalculation(),this._discreteStepNodes();var t=this.constants.minVelocity;this.moving=this._isMoving(t),this._redraw()}},I.prototype.toggleFreeze=function(){0==this.freezeSimulation?this.freezeSimulation=!0:(this.freezeSimulation=!1,this.start())},I.prototype._loadClusterSystem=function(){this.clusterSession=0,this.hubThreshold=5;for(var t in W)W.hasOwnProperty(t)&&(I.prototype[t]=W[t])},I.prototype._loadSectorSystem=function(){this.sectors={},this.activeSector=["default"],this.sectors.active={},this.sectors.active["default"]={nodes:{},edges:{},nodeIndices:[],formationScale:1,drawingNode:void 0},this.sectors.frozen={},this.sectors.navigation={nodes:{},edges:{},nodeIndices:[],formationScale:1,drawingNode:void 0},this.nodeIndices=this.sectors.active["default"].nodeIndices;for(var t in R)R.hasOwnProperty(t)&&(I.prototype[t]=R[t])},I.prototype._loadSelectionSystem=function(){this.selectionObj={};for(var t in j)j.hasOwnProperty(t)&&(I.prototype[t]=j[t])},I.prototype._loadManipulationSystem=function(){this.manipulationDiv=document.createElement("div"),this.manipulationDiv.className="graph-manipulationDiv",this.containerElement.insertBefore(this.manipulationDiv,this.frame);for(var t in H)H.hasOwnProperty(t)&&(I.prototype[t]=H[t]);this._createManipulatorBar()},I.prototype._loadNavigationControls=function(){for(var t in U)U.hasOwnProperty(t)&&(I.prototype[t]=U[t]);1==this.constants.navigation.enabled&&this._loadNavigationElements()},I.prototype._relocateNavigation=function(){},I.prototype._unHighlightAll=function(){};var B={util:z,events:F,Controller:l,DataSet:o,DataView:r,Range:h,Stack:a,TimeStep:TimeStep,EventBus:s,components:{items:{Item:_,ItemBox:w,ItemPoint:b,ItemRange:S},Component:u,Panel:p,RootPanel:f,ItemSet:y,TimeAxis:g},graph:{Node:M,Edge:D,Popup:O,Groups:Groups,Images:Images},Timeline:C,Graph:I};"undefined"!=typeof n&&(n=B),"undefined"!=typeof i&&"undefined"!=typeof i.exports&&(i.exports=B),"function"==typeof t&&t(function(){return B}),"undefined"!=typeof window&&(window.vis=B)},{hammerjs:2,moment:3,mousetrap:4}],2:[function(t,e){!function(t,i){"use strict";function n(){if(!s.READY){s.event.determineEventTypes();for(var t in s.gestures)s.gestures.hasOwnProperty(t)&&s.detection.register(s.gestures[t]);s.event.onTouch(s.DOCUMENT,s.EVENT_MOVE,s.detection.detect),s.event.onTouch(s.DOCUMENT,s.EVENT_END,s.detection.detect),s.READY=!0}}var s=function(t,e){return new s.Instance(t,e||{})};s.defaults={stop_browser_behavior:{userSelect:"none",touchAction:"none",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}},s.HAS_POINTEREVENTS=navigator.pointerEnabled||navigator.msPointerEnabled,s.HAS_TOUCHEVENTS="ontouchstart"in t,s.MOBILE_REGEX=/mobile|tablet|ip(ad|hone|od)|android/i,s.NO_MOUSEEVENTS=s.HAS_TOUCHEVENTS&&navigator.userAgent.match(s.MOBILE_REGEX),s.EVENT_TYPES={},s.DIRECTION_DOWN="down",s.DIRECTION_LEFT="left",s.DIRECTION_UP="up",s.DIRECTION_RIGHT="right",s.POINTER_MOUSE="mouse",s.POINTER_TOUCH="touch",s.POINTER_PEN="pen",s.EVENT_START="start",s.EVENT_MOVE="move",s.EVENT_END="end",s.DOCUMENT=document,s.plugins={},s.READY=!1,s.Instance=function(t,e){var i=this;return n(),this.element=t,this.enabled=!0,this.options=s.utils.extend(s.utils.extend({},s.defaults),e||{}),this.options.stop_browser_behavior&&s.utils.stopDefaultBrowserBehavior(this.element,this.options.stop_browser_behavior),s.event.onTouch(t,s.EVENT_START,function(t){i.enabled&&s.detection.startDetect(i,t)}),this},s.Instance.prototype={on:function(t,e){for(var i=t.split(" "),n=0;n0&&e==s.EVENT_END?e=s.EVENT_MOVE:d||(e=s.EVENT_END),d||null===o?o=h:h=o,i.call(s.detection,n.collectEventData(t,e,h)),s.HAS_POINTEREVENTS&&e==s.EVENT_END&&(d=s.PointerEvent.updatePointer(e,h))),d||(o=null,r=!1,a=!1,s.PointerEvent.reset())}})},determineEventTypes:function(){var t;t=s.HAS_POINTEREVENTS?s.PointerEvent.getEvents():s.NO_MOUSEEVENTS?["touchstart","touchmove","touchend touchcancel"]:["touchstart mousedown","touchmove mousemove","touchend touchcancel mouseup"],s.EVENT_TYPES[s.EVENT_START]=t[0],s.EVENT_TYPES[s.EVENT_MOVE]=t[1],s.EVENT_TYPES[s.EVENT_END]=t[2]},getTouchList:function(t){return s.HAS_POINTEREVENTS?s.PointerEvent.getTouchList():t.touches?t.touches:[{identifier:1,pageX:t.pageX,pageY:t.pageY,target:t.target}]},collectEventData:function(t,e,i){var n=this.getTouchList(i,e),o=s.POINTER_TOUCH;return(i.type.match(/mouse/)||s.PointerEvent.matchType(s.POINTER_MOUSE,i))&&(o=s.POINTER_MOUSE),{center:s.utils.getCenter(n),timeStamp:(new Date).getTime(),target:i.target,touches:n,eventType:e,pointerType:o,srcEvent:i,preventDefault:function(){this.srcEvent.preventManipulation&&this.srcEvent.preventManipulation(),this.srcEvent.preventDefault&&this.srcEvent.preventDefault()},stopPropagation:function(){this.srcEvent.stopPropagation()},stopDetect:function(){return s.detection.stopDetect()}}}},s.PointerEvent={pointers:{},getTouchList:function(){var t=this,e=[];return Object.keys(t.pointers).sort().forEach(function(i){e.push(t.pointers[i])}),e},updatePointer:function(t,e){return t==s.EVENT_END?this.pointers={}:(e.identifier=e.pointerId,this.pointers[e.pointerId]=e),Object.keys(this.pointers).length},matchType:function(t,e){if(!e.pointerType)return!1;var i={};return i[s.POINTER_MOUSE]=e.pointerType==e.MSPOINTER_TYPE_MOUSE||e.pointerType==s.POINTER_MOUSE,i[s.POINTER_TOUCH]=e.pointerType==e.MSPOINTER_TYPE_TOUCH||e.pointerType==s.POINTER_TOUCH,i[s.POINTER_PEN]=e.pointerType==e.MSPOINTER_TYPE_PEN||e.pointerType==s.POINTER_PEN,i[t]},getEvents:function(){return["pointerdown MSPointerDown","pointermove MSPointerMove","pointerup pointercancel MSPointerUp MSPointerCancel"]},reset:function(){this.pointers={}}},s.utils={extend:function(t,e,n){for(var s in e)t[s]!==i&&n||(t[s]=e[s]);return t},hasParent:function(t,e){for(;t;){if(t==e)return!0;t=t.parentNode}return!1},getCenter:function(t){for(var e=[],i=[],n=0,s=t.length;s>n;n++)e.push(t[n].pageX),i.push(t[n].pageY);return{pageX:(Math.min.apply(Math,e)+Math.max.apply(Math,e))/2,pageY:(Math.min.apply(Math,i)+Math.max.apply(Math,i))/2}},getVelocity:function(t,e,i){return{x:Math.abs(e/t)||0,y:Math.abs(i/t)||0}},getAngle:function(t,e){var i=e.pageY-t.pageY,n=e.pageX-t.pageX;return 180*Math.atan2(i,n)/Math.PI},getDirection:function(t,e){var i=Math.abs(t.pageX-e.pageX),n=Math.abs(t.pageY-e.pageY);return i>=n?t.pageX-e.pageX>0?s.DIRECTION_LEFT:s.DIRECTION_RIGHT:t.pageY-e.pageY>0?s.DIRECTION_UP:s.DIRECTION_DOWN},getDistance:function(t,e){var i=e.pageX-t.pageX,n=e.pageY-t.pageY;return Math.sqrt(i*i+n*n)},getScale:function(t,e){return t.length>=2&&e.length>=2?this.getDistance(e[0],e[1])/this.getDistance(t[0],t[1]):1},getRotation:function(t,e){return t.length>=2&&e.length>=2?this.getAngle(e[1],e[0])-this.getAngle(t[1],t[0]):0},isVertical:function(t){return t==s.DIRECTION_UP||t==s.DIRECTION_DOWN},stopDefaultBrowserBehavior:function(t,e){var i,n=["webkit","khtml","moz","ms","o",""];if(e&&t.style){for(var s=0;si;i++){var o=this.gestures[i];if(!this.stopped&&e[o.name]!==!1&&o.handler.call(o,t,this.current.inst)===!1){this.stopDetect();break}}return this.current&&(this.current.lastEvent=t),t.eventType==s.EVENT_END&&!t.touches.length-1&&this.stopDetect(),t}},stopDetect:function(){this.previous=s.utils.extend({},this.current),this.current=null,this.stopped=!0},extendEventData:function(t){var e=this.current.startEvent;if(e&&(t.touches.length!=e.touches.length||t.touches===e.touches)){e.touches=[];for(var i=0,n=t.touches.length;n>i;i++)e.touches.push(s.utils.extend({},t.touches[i]))}var o=t.timeStamp-e.timeStamp,r=t.center.pageX-e.center.pageX,a=t.center.pageY-e.center.pageY,h=s.utils.getVelocity(o,r,a);return s.utils.extend(t,{deltaTime:o,deltaX:r,deltaY:a,velocityX:h.x,velocityY:h.y,distance:s.utils.getDistance(e.center,t.center),angle:s.utils.getAngle(e.center,t.center),direction:s.utils.getDirection(e.center,t.center),scale:s.utils.getScale(e.touches,t.touches),rotation:s.utils.getRotation(e.touches,t.touches),startEvent:e}),t},register:function(t){var e=t.defaults||{};return e[t.name]===i&&(e[t.name]=!0),s.utils.extend(s.defaults,e,!0),t.index=t.index||1e3,this.gestures.push(t),this.gestures.sort(function(t,e){return t.indexe.index?1:0}),this.gestures}},s.gestures=s.gestures||{},s.gestures.Hold={name:"hold",index:10,defaults:{hold_timeout:500,hold_threshold:1},timer:null,handler:function(t,e){switch(t.eventType){case s.EVENT_START:clearTimeout(this.timer),s.detection.current.name=this.name,this.timer=setTimeout(function(){"hold"==s.detection.current.name&&e.trigger("hold",t)},e.options.hold_timeout);break;case s.EVENT_MOVE:t.distance>e.options.hold_threshold&&clearTimeout(this.timer);break;case s.EVENT_END:clearTimeout(this.timer)}}},s.gestures.Tap={name:"tap",index:100,defaults:{tap_max_touchtime:250,tap_max_distance:10,tap_always:!0,doubletap_distance:20,doubletap_interval:300},handler:function(t,e){if(t.eventType==s.EVENT_END){var i=s.detection.previous,n=!1;if(t.deltaTime>e.options.tap_max_touchtime||t.distance>e.options.tap_max_distance)return;i&&"tap"==i.name&&t.timeStamp-i.lastEvent.timeStamp0&&t.touches.length>e.options.swipe_max_touches)return;(t.velocityX>e.options.swipe_velocity||t.velocityY>e.options.swipe_velocity)&&(e.trigger(this.name,t),e.trigger(this.name+t.direction,t))}}},s.gestures.Drag={name:"drag",index:50,defaults:{drag_min_distance:10,drag_max_touches:1,drag_block_horizontal:!1,drag_block_vertical:!1,drag_lock_to_axis:!1,drag_lock_min_distance:25},triggered:!1,handler:function(t,e){if(s.detection.current.name!=this.name&&this.triggered)return e.trigger(this.name+"end",t),void(this.triggered=!1);if(!(e.options.drag_max_touches>0&&t.touches.length>e.options.drag_max_touches))switch(t.eventType){case s.EVENT_START:this.triggered=!1;break;case s.EVENT_MOVE:if(t.distancee.options.transform_min_rotation&&e.trigger("rotate",t),i>e.options.transform_min_scale&&(e.trigger("pinch",t),e.trigger("pinch"+(t.scale<1?"in":"out"),t));break;case s.EVENT_END:this.triggered&&e.trigger(this.name+"end",t),this.triggered=!1}}},s.gestures.Touch={name:"touch",index:-1/0,defaults:{prevent_default:!1,prevent_mouseevents:!1},handler:function(t,e){return e.options.prevent_mouseevents&&t.pointerType==s.POINTER_MOUSE?void t.stopDetect():(e.options.prevent_default&&t.preventDefault(),void(t.eventType==s.EVENT_START&&e.trigger(this.name,t)))}},s.gestures.Release={name:"release",index:1/0,handler:function(t,e){t.eventType==s.EVENT_END&&e.trigger(this.name,t)}},"object"==typeof e&&"object"==typeof e.exports?e.exports=s:(t.Hammer=s,"function"==typeof t.define&&t.define.amd&&t.define("hammer",[],function(){return s}))}(this)},{}],3:[function(e,i){(function(n){function s(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function o(t,e){return function(i){return p(t.call(this,i),e)}}function r(t,e){return function(i){return this.lang().ordinal(t.call(this,i),e)}}function a(){}function h(t){x(t),d(this,t)}function c(t){var e=_(t),i=e.year||0,n=e.month||0,s=e.week||0,o=e.day||0,r=e.hour||0,a=e.minute||0,h=e.second||0,c=e.millisecond||0;this._milliseconds=+c+1e3*h+6e4*a+36e5*r,this._days=+o+7*s,this._months=+n+12*i,this._data={},this._bubble()}function d(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return e.hasOwnProperty("toString")&&(t.toString=e.toString),e.hasOwnProperty("valueOf")&&(t.valueOf=e.valueOf),t}function l(t){var e,i={};for(e in t)t.hasOwnProperty(e)&&_e.hasOwnProperty(e)&&(i[e]=t[e]);return i}function u(t){return 0>t?Math.ceil(t):Math.floor(t)}function p(t,e,i){for(var n=""+Math.abs(t),s=t>=0;n.lengthn;n++)(i&&t[n]!==e[n]||!i&&b(t[n])!==b(e[n]))&&r++;return r+o}function y(t){if(t){var e=t.toLowerCase().replace(/(.)s$/,"$1");t=Xe[t]||Ze[e]||e}return t}function _(t){var e,i,n={};for(i in t)t.hasOwnProperty(i)&&(e=y(i),e&&(n[e]=t[i]));return n}function w(t){var e,i;if(0===t.indexOf("week"))e=7,i="day";else{if(0!==t.indexOf("month"))return;e=12,i="month"}re[t]=function(s,o){var r,a,h=re.fn._lang[t],c=[];if("number"==typeof s&&(o=s,s=n),a=function(t){var e=re().utc().set(i,t);return h.call(re.fn._lang,e,s||"")},null!=o)return a(o);for(r=0;e>r;r++)c.push(a(r));return c}}function b(t){var e=+t,i=0;return 0!==e&&isFinite(e)&&(i=e>=0?Math.floor(e):Math.ceil(e)),i}function S(t,e){return new Date(Date.UTC(t,e+1,0)).getUTCDate()}function E(t){return T(t)?366:365}function T(t){return t%4===0&&t%100!==0||t%400===0}function x(t){var e;t._a&&-2===t._pf.overflow&&(e=t._a[ue]<0||t._a[ue]>11?ue:t._a[pe]<1||t._a[pe]>S(t._a[le],t._a[ue])?pe:t._a[fe]<0||t._a[fe]>23?fe:t._a[ge]<0||t._a[ge]>59?ge:t._a[me]<0||t._a[me]>59?me:t._a[ve]<0||t._a[ve]>999?ve:-1,t._pf._overflowDayOfYear&&(le>e||e>pe)&&(e=pe),t._pf.overflow=e)}function C(t){return null==t._isValid&&(t._isValid=!isNaN(t._d.getTime())&&t._pf.overflow<0&&!t._pf.empty&&!t._pf.invalidMonth&&!t._pf.nullInput&&!t._pf.invalidFormat&&!t._pf.userInvalidated,t._strict&&(t._isValid=t._isValid&&0===t._pf.charsLeftOver&&0===t._pf.unusedTokens.length)),t._isValid}function M(t){return t?t.toLowerCase().replace("_","-"):t}function D(t,e){return e._isUTC?re(t).zone(e._offset||0):re(t).local()}function O(t,e){return e.abbr=t,ye[t]||(ye[t]=new a),ye[t].set(e),ye[t]}function I(t){delete ye[t]}function N(t){var i,n,s,o,r=0,a=function(t){if(!ye[t]&&we)try{e("./lang/"+t)}catch(i){}return ye[t]};if(!t)return re.fn._lang;if(!g(t)){if(n=a(t))return n;t=[t]}for(;r0;){if(n=a(o.slice(0,i).join("-")))return n;if(s&&s.length>=i&&v(o,s,!0)>=i-1)break;i--}r++}return re.fn._lang}function L(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function k(t){var e,i,n=t.match(Te);for(e=0,i=n.length;i>e;e++)n[e]=Je[n[e]]?Je[n[e]]:L(n[e]);return function(s){var o="";for(e=0;i>e;e++)o+=n[e]instanceof Function?n[e].call(s,t):n[e];return o}}function A(t,e){return t.isValid()?(e=z(e,t.lang()),Ke[e]||(Ke[e]=k(e)),Ke[e](t)):t.lang().invalidDate()}function z(t,e){function i(t){return e.longDateFormat(t)||t}var n=5;for(xe.lastIndex=0;n>=0&&xe.test(t);)t=t.replace(xe,i),xe.lastIndex=0,n-=1;return t}function P(t,e){var i,n=e._strict;switch(t){case"DDDD":return Fe;case"YYYY":case"GGGG":case"gggg":return n?Ye:De;case"Y":case"G":case"g":return Re;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return n?He:Oe;case"S":if(n)return ze;case"SS":if(n)return Pe;case"SSS":if(n)return Fe;case"DDD":return Me;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Ne;case"a":case"A":return N(e._l)._meridiemParse;case"X":return Ae;case"Z":case"ZZ":return Le;case"T":return ke;case"SSSS":return Ie;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return n?Pe:Ce;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return Ce;default:return i=new RegExp(B(U(t.replace("\\","")),"i"))}}function F(t){t=t||"";var e=t.match(Le)||[],i=e[e.length-1]||[],n=(i+"").match(Ve)||["-",0,0],s=+(60*n[1])+b(n[2]);return"+"===n[0]?-s:s}function Y(t,e,i){var n,s=i._a;switch(t){case"M":case"MM":null!=e&&(s[ue]=b(e)-1);break;case"MMM":case"MMMM":n=N(i._l).monthsParse(e),null!=n?s[ue]=n:i._pf.invalidMonth=e;break;case"D":case"DD":null!=e&&(s[pe]=b(e));break;case"DDD":case"DDDD":null!=e&&(i._dayOfYear=b(e));break;case"YY":s[le]=b(e)+(b(e)>68?1900:2e3);break;case"YYYY":case"YYYYY":case"YYYYYY":s[le]=b(e);break;case"a":case"A":i._isPm=N(i._l).isPM(e);break;case"H":case"HH":case"h":case"hh":s[fe]=b(e);break;case"m":case"mm":s[ge]=b(e);break;case"s":case"ss":s[me]=b(e);break;case"S":case"SS":case"SSS":case"SSSS":s[ve]=b(1e3*("0."+e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,i._tzm=F(e);break;case"w":case"ww":case"W":case"WW":case"d":case"dd":case"ddd":case"dddd":case"e":case"E":t=t.substr(0,1);case"gg":case"gggg":case"GG":case"GGGG":case"GGGGG":t=t.substr(0,2),e&&(i._w=i._w||{},i._w[t]=e)}}function H(t){var e,i,n,s,o,r,a,h,c,d,l=[];if(!t._d){for(n=W(t),t._w&&null==t._a[pe]&&null==t._a[ue]&&(o=function(e){var i=parseInt(e,10);return e?e.length<3?i>68?1900+i:2e3+i:i:null==t._a[le]?re().weekYear():t._a[le]},r=t._w,null!=r.GG||null!=r.W||null!=r.E?a=te(o(r.GG),r.W||1,r.E,4,1):(h=N(t._l),c=null!=r.d?K(r.d,h):null!=r.e?parseInt(r.e,10)+h._week.dow:0,d=parseInt(r.w,10)||1,null!=r.d&&cE(s)&&(t._pf._overflowDayOfYear=!0),i=Z(s,0,t._dayOfYear),t._a[ue]=i.getUTCMonth(),t._a[pe]=i.getUTCDate()),e=0;3>e&&null==t._a[e];++e)t._a[e]=l[e]=n[e];for(;7>e;e++)t._a[e]=l[e]=null==t._a[e]?2===e?1:0:t._a[e];l[fe]+=b((t._tzm||0)/60),l[ge]+=b((t._tzm||0)%60),t._d=(t._useUTC?Z:X).apply(null,l)}}function R(t){var e;t._d||(e=_(t._i),t._a=[e.year,e.month,e.day,e.hour,e.minute,e.second,e.millisecond],H(t))}function W(t){var e=new Date;return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function j(t){t._a=[],t._pf.empty=!0;var e,i,n,s,o,r=N(t._l),a=""+t._i,h=a.length,c=0;for(n=z(t._f,r).match(Te)||[],e=0;e0&&t._pf.unusedInput.push(o),a=a.slice(a.indexOf(i)+i.length),c+=i.length),Je[s]?(i?t._pf.empty=!1:t._pf.unusedTokens.push(s),Y(s,i,t)):t._strict&&!i&&t._pf.unusedTokens.push(s);t._pf.charsLeftOver=h-c,a.length>0&&t._pf.unusedInput.push(a),t._isPm&&t._a[fe]<12&&(t._a[fe]+=12),t._isPm===!1&&12===t._a[fe]&&(t._a[fe]=0),H(t),x(t)}function U(t){return t.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,i,n,s){return e||i||n||s})}function B(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function V(t){var e,i,n,o,r;if(0===t._f.length)return t._pf.invalidFormat=!0,void(t._d=new Date(0/0));for(o=0;or)&&(n=r,i=e));d(t,i||e)}function G(t){var e,i,n=t._i,s=We.exec(n);if(s){for(t._pf.iso=!0,e=0,i=Ue.length;i>e;e++)if(Ue[e][1].exec(n)){t._f=Ue[e][0]+(s[6]||" ");break}for(e=0,i=Be.length;i>e;e++)if(Be[e][1].exec(n)){t._f+=Be[e][0];break}n.match(Le)&&(t._f+="Z"),j(t)}else t._d=new Date(n)}function q(t){var e=t._i,i=be.exec(e);e===n?t._d=new Date:i?t._d=new Date(+i[1]):"string"==typeof e?G(t):g(e)?(t._a=e.slice(0),H(t)):m(e)?t._d=new Date(+e):"object"==typeof e?R(t):t._d=new Date(e)}function X(t,e,i,n,s,o,r){var a=new Date(t,e,i,n,s,o,r);return 1970>t&&a.setFullYear(t),a}function Z(t){var e=new Date(Date.UTC.apply(null,arguments));return 1970>t&&e.setUTCFullYear(t),e}function K(t,e){if("string"==typeof t)if(isNaN(t)){if(t=e.weekdaysParse(t),"number"!=typeof t)return null}else t=parseInt(t,10);return t}function $(t,e,i,n,s){return s.relativeTime(e||1,!!i,t,n)}function Q(t,e,i){var n=de(Math.abs(t)/1e3),s=de(n/60),o=de(s/60),r=de(o/24),a=de(r/365),h=45>n&&["s",n]||1===s&&["m"]||45>s&&["mm",s]||1===o&&["h"]||22>o&&["hh",o]||1===r&&["d"]||25>=r&&["dd",r]||45>=r&&["M"]||345>r&&["MM",de(r/30)]||1===a&&["y"]||["yy",a];return h[2]=e,h[3]=t>0,h[4]=i,$.apply({},h)}function J(t,e,i){var n,s=i-e,o=i-t.day();return o>s&&(o-=7),s-7>o&&(o+=7),n=re(t).add("d",o),{week:Math.ceil(n.dayOfYear()/7),year:n.year()}}function te(t,e,i,n,s){var o,r,a=Z(t,0,1).getUTCDay();return i=null!=i?i:s,o=s-a+(a>n?7:0)-(s>a?7:0),r=7*(e-1)+(i-s)+o+1,{year:r>0?t:t-1,dayOfYear:r>0?r:E(t-1)+r}}function ee(t){var e=t._i,i=t._f;return null===e?re.invalid({nullInput:!0}):("string"==typeof e&&(t._i=e=N().preparse(e)),re.isMoment(e)?(t=l(e),t._d=new Date(+e._d)):i?g(i)?V(t):j(t):q(t),new h(t))}function ie(t,e){re.fn[t]=re.fn[t+"s"]=function(t){var i=this._isUTC?"UTC":"";return null!=t?(this._d["set"+i+e](t),re.updateOffset(this),this):this._d["get"+i+e]()}}function ne(t){re.duration.fn[t]=function(){return this._data[t]}}function se(t,e){re.duration.fn["as"+t]=function(){return+this/e}}function oe(t){var e=!1,i=re; -"undefined"==typeof ender&&(t?(ce.moment=function(){return!e&&console&&console.warn&&(e=!0,console.warn("Accessing Moment through the global scope is deprecated, and will be removed in an upcoming release.")),i.apply(null,arguments)},d(ce.moment,i)):ce.moment=re)}for(var re,ae,he="2.5.1",ce=this,de=Math.round,le=0,ue=1,pe=2,fe=3,ge=4,me=5,ve=6,ye={},_e={_isAMomentObject:null,_i:null,_f:null,_l:null,_strict:null,_isUTC:null,_offset:null,_pf:null,_lang:null},we="undefined"!=typeof i&&i.exports&&"undefined"!=typeof e,be=/^\/?Date\((\-?\d+)/i,Se=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,Ee=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,Te=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g,xe=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,Ce=/\d\d?/,Me=/\d{1,3}/,De=/\d{1,4}/,Oe=/[+\-]?\d{1,6}/,Ie=/\d+/,Ne=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Le=/Z|[\+\-]\d\d:?\d\d/gi,ke=/T/i,Ae=/[\+\-]?\d+(\.\d{1,3})?/,ze=/\d/,Pe=/\d\d/,Fe=/\d{3}/,Ye=/\d{4}/,He=/[+-]?\d{6}/,Re=/[+-]?\d+/,We=/^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,je="YYYY-MM-DDTHH:mm:ssZ",Ue=[["YYYYYY-MM-DD",/[+-]\d{6}-\d{2}-\d{2}/],["YYYY-MM-DD",/\d{4}-\d{2}-\d{2}/],["GGGG-[W]WW-E",/\d{4}-W\d{2}-\d/],["GGGG-[W]WW",/\d{4}-W\d{2}/],["YYYY-DDD",/\d{4}-\d{3}/]],Be=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d{1,3}/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],Ve=/([\+\-]|\d\d)/gi,Ge="Date|Hours|Minutes|Seconds|Milliseconds".split("|"),qe={Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6},Xe={ms:"millisecond",s:"second",m:"minute",h:"hour",d:"day",D:"date",w:"week",W:"isoWeek",M:"month",y:"year",DDD:"dayOfYear",e:"weekday",E:"isoWeekday",gg:"weekYear",GG:"isoWeekYear"},Ze={dayofyear:"dayOfYear",isoweekday:"isoWeekday",isoweek:"isoWeek",weekyear:"weekYear",isoweekyear:"isoWeekYear"},Ke={},$e="DDD w W M D d".split(" "),Qe="M D H h m s w W".split(" "),Je={M:function(){return this.month()+1},MMM:function(t){return this.lang().monthsShort(this,t)},MMMM:function(t){return this.lang().months(this,t)},D:function(){return this.date()},DDD:function(){return this.dayOfYear()},d:function(){return this.day()},dd:function(t){return this.lang().weekdaysMin(this,t)},ddd:function(t){return this.lang().weekdaysShort(this,t)},dddd:function(t){return this.lang().weekdays(this,t)},w:function(){return this.week()},W:function(){return this.isoWeek()},YY:function(){return p(this.year()%100,2)},YYYY:function(){return p(this.year(),4)},YYYYY:function(){return p(this.year(),5)},YYYYYY:function(){var t=this.year(),e=t>=0?"+":"-";return e+p(Math.abs(t),6)},gg:function(){return p(this.weekYear()%100,2)},gggg:function(){return p(this.weekYear(),4)},ggggg:function(){return p(this.weekYear(),5)},GG:function(){return p(this.isoWeekYear()%100,2)},GGGG:function(){return p(this.isoWeekYear(),4)},GGGGG:function(){return p(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.lang().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.lang().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return b(this.milliseconds()/100)},SS:function(){return p(b(this.milliseconds()/10),2)},SSS:function(){return p(this.milliseconds(),3)},SSSS:function(){return p(this.milliseconds(),3)},Z:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(b(t/60),2)+":"+p(b(t)%60,2)},ZZ:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(b(t/60),2)+p(b(t)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},X:function(){return this.unix()},Q:function(){return this.quarter()}},ti=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"];$e.length;)ae=$e.pop(),Je[ae+"o"]=r(Je[ae],ae);for(;Qe.length;)ae=Qe.pop(),Je[ae+ae]=o(Je[ae],2);for(Je.DDDD=o(Je.DDD,3),d(a.prototype,{set:function(t){var e,i;for(i in t)e=t[i],"function"==typeof e?this[i]=e:this["_"+i]=e},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(t){return this._months[t.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(t){return this._monthsShort[t.month()]},monthsParse:function(t){var e,i,n;for(this._monthsParse||(this._monthsParse=[]),e=0;12>e;e++)if(this._monthsParse[e]||(i=re.utc([2e3,e]),n="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[e]=new RegExp(n.replace(".",""),"i")),this._monthsParse[e].test(t))return e},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(t){return this._weekdays[t.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(t){return this._weekdaysShort[t.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(t){return this._weekdaysMin[t.day()]},weekdaysParse:function(t){var e,i,n;for(this._weekdaysParse||(this._weekdaysParse=[]),e=0;7>e;e++)if(this._weekdaysParse[e]||(i=re([2e3,1]).day(e),n="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[e]=new RegExp(n.replace(".",""),"i")),this._weekdaysParse[e].test(t))return e},_longDateFormat:{LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D YYYY",LLL:"MMMM D YYYY LT",LLLL:"dddd, MMMM D YYYY LT"},longDateFormat:function(t){var e=this._longDateFormat[t];return!e&&this._longDateFormat[t.toUpperCase()]&&(e=this._longDateFormat[t.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t]=e),e},isPM:function(t){return"p"===(t+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(t,e,i){return t>11?i?"pm":"PM":i?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(t,e){var i=this._calendar[t];return"function"==typeof i?i.apply(e):i},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(t,e,i,n){var s=this._relativeTime[i];return"function"==typeof s?s(t,e,i,n):s.replace(/%d/i,t)},pastFuture:function(t,e){var i=this._relativeTime[t>0?"future":"past"];return"function"==typeof i?i(e):i.replace(/%s/i,e)},ordinal:function(t){return this._ordinal.replace("%d",t)},_ordinal:"%d",preparse:function(t){return t},postformat:function(t){return t},week:function(t){return J(t,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),re=function(t,e,i,o){var r;return"boolean"==typeof i&&(o=i,i=n),r={},r._isAMomentObject=!0,r._i=t,r._f=e,r._l=i,r._strict=o,r._isUTC=!1,r._pf=s(),ee(r)},re.utc=function(t,e,i,o){var r;return"boolean"==typeof i&&(o=i,i=n),r={},r._isAMomentObject=!0,r._useUTC=!0,r._isUTC=!0,r._l=i,r._i=t,r._f=e,r._strict=o,r._pf=s(),ee(r).utc()},re.unix=function(t){return re(1e3*t)},re.duration=function(t,e){var i,n,s,o=t,r=null;return re.isDuration(t)?o={ms:t._milliseconds,d:t._days,M:t._months}:"number"==typeof t?(o={},e?o[e]=t:o.milliseconds=t):(r=Se.exec(t))?(i="-"===r[1]?-1:1,o={y:0,d:b(r[pe])*i,h:b(r[fe])*i,m:b(r[ge])*i,s:b(r[me])*i,ms:b(r[ve])*i}):(r=Ee.exec(t))&&(i="-"===r[1]?-1:1,s=function(t){var e=t&&parseFloat(t.replace(",","."));return(isNaN(e)?0:e)*i},o={y:s(r[2]),M:s(r[3]),d:s(r[4]),h:s(r[5]),m:s(r[6]),s:s(r[7]),w:s(r[8])}),n=new c(o),re.isDuration(t)&&t.hasOwnProperty("_lang")&&(n._lang=t._lang),n},re.version=he,re.defaultFormat=je,re.updateOffset=function(){},re.lang=function(t,e){var i;return t?(e?O(M(t),e):null===e?(I(t),t="en"):ye[t]||N(t),i=re.duration.fn._lang=re.fn._lang=N(t),i._abbr):re.fn._lang._abbr},re.langData=function(t){return t&&t._lang&&t._lang._abbr&&(t=t._lang._abbr),N(t)},re.isMoment=function(t){return t instanceof h||null!=t&&t.hasOwnProperty("_isAMomentObject")},re.isDuration=function(t){return t instanceof c},ae=ti.length-1;ae>=0;--ae)w(ti[ae]);for(re.normalizeUnits=function(t){return y(t)},re.invalid=function(t){var e=re.utc(0/0);return null!=t?d(e._pf,t):e._pf.userInvalidated=!0,e},re.parseZone=function(t){return re(t).parseZone()},d(re.fn=h.prototype,{clone:function(){return re(this)},valueOf:function(){return+this._d+6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().lang("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){var t=re(this).utc();return 00:!1},parsingFlags:function(){return d({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(){return this.zone(0)},local:function(){return this.zone(0),this._isUTC=!1,this},format:function(t){var e=A(this,t||re.defaultFormat);return this.lang().postformat(e)},add:function(t,e){var i;return i="string"==typeof t?re.duration(+e,t):re.duration(t,e),f(this,i,1),this},subtract:function(t,e){var i;return i="string"==typeof t?re.duration(+e,t):re.duration(t,e),f(this,i,-1),this},diff:function(t,e,i){var n,s,o=D(t,this),r=6e4*(this.zone()-o.zone());return e=y(e),"year"===e||"month"===e?(n=432e5*(this.daysInMonth()+o.daysInMonth()),s=12*(this.year()-o.year())+(this.month()-o.month()),s+=(this-re(this).startOf("month")-(o-re(o).startOf("month")))/n,s-=6e4*(this.zone()-re(this).startOf("month").zone()-(o.zone()-re(o).startOf("month").zone()))/n,"year"===e&&(s/=12)):(n=this-o,s="second"===e?n/1e3:"minute"===e?n/6e4:"hour"===e?n/36e5:"day"===e?(n-r)/864e5:"week"===e?(n-r)/6048e5:n),i?s:u(s)},from:function(t,e){return re.duration(this.diff(t)).lang(this.lang()._abbr).humanize(!e)},fromNow:function(t){return this.from(re(),t)},calendar:function(){var t=D(re(),this).startOf("day"),e=this.diff(t,"days",!0),i=-6>e?"sameElse":-1>e?"lastWeek":0>e?"lastDay":1>e?"sameDay":2>e?"nextDay":7>e?"nextWeek":"sameElse";return this.format(this.lang().calendar(i,this))},isLeapYear:function(){return T(this.year())},isDST:function(){return this.zone()+re(t).startOf(e)},isBefore:function(t,e){return e="undefined"!=typeof e?e:"millisecond",+this.clone().startOf(e)<+re(t).startOf(e)},isSame:function(t,e){return e=e||"ms",+this.clone().startOf(e)===+D(t,this).startOf(e)},min:function(t){return t=re.apply(null,arguments),this>t?this:t},max:function(t){return t=re.apply(null,arguments),t>this?this:t},zone:function(t){var e=this._offset||0;return null==t?this._isUTC?e:this._d.getTimezoneOffset():("string"==typeof t&&(t=F(t)),Math.abs(t)<16&&(t=60*t),this._offset=t,this._isUTC=!0,e!==t&&f(this,re.duration(e-t,"m"),1,!0),this)},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.zone(this._tzm):"string"==typeof this._i&&this.zone(this._i),this},hasAlignedHourOffset:function(t){return t=t?re(t).zone():0,(this.zone()-t)%60===0},daysInMonth:function(){return S(this.year(),this.month())},dayOfYear:function(t){var e=de((re(this).startOf("day")-re(this).startOf("year"))/864e5)+1;return null==t?e:this.add("d",t-e)},quarter:function(){return Math.ceil((this.month()+1)/3)},weekYear:function(t){var e=J(this,this.lang()._week.dow,this.lang()._week.doy).year;return null==t?e:this.add("y",t-e)},isoWeekYear:function(t){var e=J(this,1,4).year;return null==t?e:this.add("y",t-e)},week:function(t){var e=this.lang().week(this);return null==t?e:this.add("d",7*(t-e))},isoWeek:function(t){var e=J(this,1,4).week;return null==t?e:this.add("d",7*(t-e))},weekday:function(t){var e=(this.day()+7-this.lang()._week.dow)%7;return null==t?e:this.add("d",t-e)},isoWeekday:function(t){return null==t?this.day()||7:this.day(this.day()%7?t:t-7)},get:function(t){return t=y(t),this[t]()},set:function(t,e){return t=y(t),"function"==typeof this[t]&&this[t](e),this},lang:function(t){return t===n?this._lang:(this._lang=N(t),this)}}),ae=0;ae-1?!1:"INPUT"==i||"SELECT"==i||"TEXTAREA"==i||e.contentEditable&&"true"==e.contentEditable}function o(t,e){return t.sort().join(",")===e.sort().join(",")}function r(t){t=t||{};var e,i=!1;for(e in M)t[e]?i=!0:M[e]=0;i||(O=!1)}function a(t,e,i,n,s){var r,a,h=[];if(!x[t])return[];for("keyup"==i&&u(t)&&(e=[t]),r=0;r95&&112>t||b.hasOwnProperty(t)&&(_[b[t]]=t)}return _}function g(t,e,i){return i||(i=f()[t]?"keydown":"keypress"),"keypress"==i&&e.length&&(i="keydown"),i}function m(t,e,i,s){M[t]=0,s||(s=g(e[0],[]));var o,a=function(){O=s,++M[t],p()},h=function(t){c(i,t),"keyup"!==s&&(D=n(t)),setTimeout(r,10)};for(o=0;o1)return m(t,c,e,i);for(h="+"===t?["+"]:t.split("+"),o=0;o":".","?":"/","|":"\\"},T={option:"alt",command:"meta","return":"enter",escape:"esc"},x={},C={},M={},D=!1,O=!1,I=1;20>I;++I)b[111+I]="f"+I;for(I=0;9>=I;++I)b[I+96]=I;i(document,"keypress",l),i(document,"keydown",l),i(document,"keyup",l);var N={bind:function(t,e,i){return y(t instanceof Array?t:[t],e,i),C[t+":"+i]=e,this},unbind:function(t,e){return C[t+":"+e]&&(delete C[t+":"+e],this.bind(t,function(){},e)),this},trigger:function(t,e){return C[t+":"+e](),this},reset:function(){return x={},C={},this}};e.exports=N},{}]},{},[1])(1)}); \ No newline at end of file +!function(t){if("object"==typeof exports)module.exports=t();else if("function"==typeof define&&define.amd)define(t);else{var e;"undefined"!=typeof window?e=window:"undefined"!=typeof global?e=global:"undefined"!=typeof self&&(e=self),e.vis=t()}}(function(){var define,module,exports;return function t(e,i,n){function s(r,a){if(!i[r]){if(!e[r]){var h="function"==typeof require&&require;if(!a&&h)return h(r,!0);if(o)return o(r,!0);throw new Error("Cannot find module '"+r+"'")}var l=i[r]={exports:{}};e[r][0].call(l.exports,function(t){var i=e[r][1][t];return s(i?i:t)},l,l.exports,t,e,i,n)}return i[r].exports}for(var o="function"==typeof require&&require,r=0;ri;++i)t.call(e||this,this[i],i,this)}),Array.prototype.map||(Array.prototype.map=function(t,e){var i,n,s;if(null==this)throw new TypeError(" this is null or not defined");var o=Object(this),r=o.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(e&&(i=e),n=new Array(r),s=0;r>s;){var a,h;s in o&&(a=o[s],h=t.call(i,a,s,o),n[s]=h),s++}return n}),Array.prototype.filter||(Array.prototype.filter=function(t){"use strict";if(null==this)throw new TypeError;var e=Object(this),i=e.length>>>0;if("function"!=typeof t)throw new TypeError;for(var n=[],s=arguments[1],o=0;i>o;o++)if(o in e){var r=e[o];t.call(s,r,o,e)&&n.push(r)}return n}),Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,e=!{toString:null}.propertyIsEnumerable("toString"),i=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],n=i.length;return function(s){if("object"!=typeof s&&"function"!=typeof s||null===s)throw new TypeError("Object.keys called on non-object");var o=[];for(var r in s)t.call(s,r)&&o.push(r);if(e)for(var a=0;n>a;a++)t.call(s,i[a])&&o.push(i[a]);return o}}()),Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s}),Object.create||(Object.create=function(t){function e(){}if(arguments.length>1)throw new Error("Object.create implementation only accepts the first parameter.");return e.prototype=t,new e}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s});var util={};util.isNumber=function(t){return t instanceof Number||"number"==typeof t},util.isString=function(t){return t instanceof String||"string"==typeof t},util.isDate=function(t){if(t instanceof Date)return!0;if(util.isString(t)){var e=ASPDateRegex.exec(t);if(e)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},util.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},util.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},util.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var n=arguments[e];for(var s in n)n.hasOwnProperty(s)&&void 0!==n[s]&&(t[s]=n[s])}return t},util.convert=function(t,e){var i;if(void 0===t)return void 0;if(null===t)return null;if(!e)return t;if("string"!=typeof e&&!(e instanceof String))throw new Error("Type must be a string");switch(e){case"boolean":case"Boolean":return Boolean(t);case"number":case"Number":return Number(t.valueOf());case"string":case"String":return String(t);case"Date":if(util.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(moment.isMoment(t))return new Date(t.valueOf());if(util.isString(t))return i=ASPDateRegex.exec(t),i?new Date(Number(i[1])):moment(t).toDate();throw new Error("Cannot convert object of type "+util.getType(t)+" to type Date");case"Moment":if(util.isNumber(t))return moment(t);if(t instanceof Date)return moment(t.valueOf());if(moment.isMoment(t))return moment(t);if(util.isString(t))return i=ASPDateRegex.exec(t),moment(i?Number(i[1]):t);throw new Error("Cannot convert object of type "+util.getType(t)+" to type Date");case"ISODate":if(util.isNumber(t))return new Date(t);if(t instanceof Date)return t.toISOString();if(moment.isMoment(t))return t.toDate().toISOString();if(util.isString(t))return i=ASPDateRegex.exec(t),i?new Date(Number(i[1])).toISOString():new Date(t).toISOString();throw new Error("Cannot convert object of type "+util.getType(t)+" to type ISODate");case"ASPDate":if(util.isNumber(t))return"/Date("+t+")/";if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(util.isString(t)){i=ASPDateRegex.exec(t);var n;return n=i?new Date(Number(i[1])).valueOf():new Date(t).valueOf(),"/Date("+n+")/"}throw new Error("Cannot convert object of type "+util.getType(t)+" to type ASPDate");default:throw new Error("Cannot convert object of type "+util.getType(t)+' to type "'+e+'"')}};var ASPDateRegex=/^\/?Date\((\-?\d+)/i;util.getType=function(t){var e=typeof t;return"object"==e?null==t?"null":t instanceof Boolean?"Boolean":t instanceof Number?"Number":t instanceof String?"String":t instanceof Array?"Array":t instanceof Date?"Date":"Object":"number"==e?"Number":"boolean"==e?"Boolean":"string"==e?"String":e},util.getAbsoluteLeft=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetLeft,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetLeft,n-=s.scrollLeft,s=s.offsetParent;return n},util.getAbsoluteTop=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetTop,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetTop,n-=s.scrollTop,s=s.offsetParent;return n},util.getPageY=function(t){if("pageY"in t)return t.pageY;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientY:t.clientY;var i=document.documentElement,n=document.body;return e+(i&&i.scrollTop||n&&n.scrollTop||0)-(i&&i.clientTop||n&&n.clientTop||0)},util.getPageX=function(t){if("pageY"in t)return t.pageX;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientX:t.clientX;var i=document.documentElement,n=document.body;return e+(i&&i.scrollLeft||n&&n.scrollLeft||0)-(i&&i.clientLeft||n&&n.clientLeft||0)},util.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},util.removeClassName=function(t,e){var i=t.className.split(" "),n=i.indexOf(e);-1!=n&&(i.splice(n,1),t.className=i.join(" "))},util.forEach=function(t,e){var i,n;if(t instanceof Array)for(i=0,n=t.length;n>i;i++)e(t[i],i,t);else for(i in t)t.hasOwnProperty(i)&&e(t[i],i,t)},util.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},util.addEventListener=function(t,e,i,n){t.addEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.addEventListener(e,i,n)):t.attachEvent("on"+e,i)},util.removeEventListener=function(t,e,i,n){t.removeEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.removeEventListener(e,i,n)):t.detachEvent("on"+e,i)},util.getTarget=function(t){t||(t=window.event);var e;return t.target?e=t.target:t.srcElement&&(e=t.srcElement),void 0!=e.nodeType&&3==e.nodeType&&(e=e.parentNode),e},util.stopPropagation=function(t){t||(t=window.event),t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},util.fakeGesture=function(t,e){var i=null;return Hammer.event.collectEventData(this,i,e)},util.preventDefault=function(t){t||(t=window.event),t.preventDefault?t.preventDefault():t.returnValue=!1},util.option={},util.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},util.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},util.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?String(t):e||null},util.option.asSize=function(t,e){return"function"==typeof t&&(t=t()),util.isString(t)?t:util.isNumber(t)?t+"px":e||null},util.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null},util.GiveDec=function GiveDec(Hex){return Value="A"==Hex?10:"B"==Hex?11:"C"==Hex?12:"D"==Hex?13:"E"==Hex?14:"F"==Hex?15:eval(Hex)},util.GiveHex=function(t){return Value=10==t?"A":11==t?"B":12==t?"C":13==t?"D":14==t?"E":15==t?"F":""+t},util.hexToRGB=function(t){t=t.replace("#","").toUpperCase();var e=util.GiveDec(t.substring(0,1)),i=util.GiveDec(t.substring(1,2)),n=util.GiveDec(t.substring(2,3)),s=util.GiveDec(t.substring(3,4)),o=util.GiveDec(t.substring(4,5)),r=util.GiveDec(t.substring(5,6)),a=16*e+i,h=16*n+s,i=16*o+r;return{r:a,g:h,b:i}},util.RGBToHex=function(t,e,i){var n=util.GiveHex(Math.floor(t/16)),s=util.GiveHex(t%16),o=util.GiveHex(Math.floor(e/16)),r=util.GiveHex(e%16),a=util.GiveHex(Math.floor(i/16)),h=util.GiveHex(i%16),l=n+s+o+r+a+h;return"#"+l},util.RGBToHSV=function(t,e,i){t/=255,e/=255,i/=255;var n=Math.min(t,Math.min(e,i)),s=Math.max(t,Math.max(e,i));if(n==s)return{h:0,s:0,v:n};var o=t==n?e-i:i==n?t-e:i-t,r=t==n?3:i==n?1:5,a=60*(r-o/(s-n))/360,h=(s-n)/s,l=s;return{h:a,s:h,v:l}},util.HSVToRGB=function(t,e,i){var n,s,o,r=Math.floor(6*t),a=6*t-r,h=i*(1-e),l=i*(1-a*e),c=i*(1-(1-a)*e);switch(r%6){case 0:n=i,s=c,o=h;break;case 1:n=l,s=i,o=h;break;case 2:n=h,s=i,o=c;break;case 3:n=h,s=l,o=i;break;case 4:n=c,s=h,o=i;break;case 5:n=i,s=h,o=l}return{r:Math.floor(255*n),g:Math.floor(255*s),b:Math.floor(255*o)}},util.HSVToHex=function(t,e,i){var n=util.HSVToRGB(t,e,i);return util.RGBToHex(n.r,n.g,n.b)},util.hexToHSV=function(t){var e=util.hexToRGB(t);return util.RGBToHSV(e.r,e.g,e.b)};var events={listeners:[],indexOf:function(t){for(var e=this.listeners,i=0,n=this.listeners.length;n>i;i++){var s=e[i];if(s&&s.object==t)return i}return-1},addListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];s||(s={object:t,events:{}},this.listeners.push(s));var o=s.events[e];o||(o=[],s.events[e]=o),-1==o.indexOf(i)&&o.push(i)},removeListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];o&&(n=o.indexOf(i),-1!=n&&o.splice(n,1),0==o.length&&delete s.events[e]);var r=0,a=s.events;for(var h in a)a.hasOwnProperty(h)&&r++;0==r&&delete this.listeners[n]}},removeAllListeners:function(){this.listeners=[]},trigger:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];if(o)for(var r=0,a=o.length;a>r;r++)o[r](i)}}};EventBus.prototype.on=function(t,e,i){var n=t instanceof RegExp?t:new RegExp(t.replace("*","\\w+")),s={id:util.randomUUID(),event:t,regexp:n,callback:"function"==typeof e?e:null,target:i};return this.subscriptions.push(s),s.id},EventBus.prototype.off=function(t){for(var e=0;eo;o++)i=s._addItem(t[o]),n.push(i);else if(util.isDataTable(t))for(var a=this._getColumnNames(t),h=0,l=t.getNumberOfRows();l>h;h++){for(var c={},d=0,u=a.length;u>d;d++){var p=a[d];c[p]=t.getValue(h,d)}i=s._addItem(c),n.push(i)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");i=s._addItem(t),n.push(i)}return n.length&&this._trigger("add",{items:n},e),n},DataSet.prototype.update=function(t,e){var i=[],n=[],s=this,o=s.fieldId,r=function(t){var e=t[o];s.data[e]?(e=s._updateItem(t),n.push(e)):(e=s._addItem(t),i.push(e))};if(t instanceof Array)for(var a=0,h=t.length;h>a;a++)r(t[a]);else if(util.isDataTable(t))for(var l=this._getColumnNames(t),c=0,d=t.getNumberOfRows();d>c;c++){for(var u={},p=0,f=l.length;f>p;p++){var g=l[p];u[g]=t.getValue(c,p)}r(u)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");r(t)}return i.length&&this._trigger("add",{items:i},e),n.length&&this._trigger("update",{items:n},e),i.concat(n)},DataSet.prototype.get=function(){var t,e,i,n,s=this,o=this.showInternalIds,r=util.getType(arguments[0]);"String"==r||"Number"==r?(t=arguments[0],i=arguments[1],n=arguments[2]):"Array"==r?(e=arguments[0],i=arguments[1],n=arguments[2]):(i=arguments[0],n=arguments[1]);var a;if(i&&i.type){if(a="DataTable"==i.type?"DataTable":"Array",n&&a!=util.getType(n))throw new Error('Type of parameter "data" ('+util.getType(n)+") does not correspond with specified options.type ("+i.type+")");if("DataTable"==a&&!util.isDataTable(n))throw new Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else a=n?"DataTable"==util.getType(n)?"DataTable":"Array":"Array";void 0!=i&&void 0!=i.showInternalIds&&(this.showInternalIds=i.showInternalIds);var h,l,c,d,u=i&&i.convert||this.options.convert,p=i&&i.filter,f=[];if(void 0!=t)h=s._getItem(t,u),p&&!p(h)&&(h=null);else if(void 0!=e)for(c=0,d=e.length;d>c;c++)h=s._getItem(e[c],u),(!p||p(h))&&f.push(h);else for(l in this.data)this.data.hasOwnProperty(l)&&(h=s._getItem(l,u),(!p||p(h))&&f.push(h));if(this.showInternalIds=o,i&&i.order&&void 0==t&&this._sort(f,i.order),i&&i.fields){var g=i.fields;if(void 0!=t)h=this._filterFields(h,g);else for(c=0,d=f.length;d>c;c++)f[c]=this._filterFields(f[c],g)}if("DataTable"==a){var m=this._getColumnNames(n);if(void 0!=t)s._appendRow(n,m,h);else for(c=0,d=f.length;d>c;c++)s._appendRow(n,m,f[c]);return n}if(void 0!=t)return h;if(n){for(c=0,d=f.length;d>c;c++)n.push(f[c]);return n}return f},DataSet.prototype.getIds=function(t){var e,i,n,s,o,r=this.data,a=t&&t.filter,h=t&&t.order,l=t&&t.convert||this.options.convert,c=[];if(a)if(h){o=[];for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,l),a(s)&&o.push(s));for(this._sort(o,h),e=0,i=o.length;i>e;e++)c[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,l),a(s)&&c.push(s[this.fieldId]));else if(h){o=[];for(n in r)r.hasOwnProperty(n)&&o.push(r[n]);for(this._sort(o,h),e=0,i=o.length;i>e;e++)c[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=r[n],c.push(s[this.fieldId]));return c},DataSet.prototype.forEach=function(t,e){var i,n,s=e&&e.filter,o=e&&e.convert||this.options.convert,r=this.data;if(e&&e.order)for(var a=this.get(e),h=0,l=a.length;l>h;h++)i=a[h],n=i[this.fieldId],t(i,n);else for(n in r)r.hasOwnProperty(n)&&(i=this._getItem(n,o),(!s||s(i))&&t(i,n))},DataSet.prototype.map=function(t,e){var i,n=e&&e.filter,s=e&&e.convert||this.options.convert,o=[],r=this.data;for(var a in r)r.hasOwnProperty(a)&&(i=this._getItem(a,s),(!n||n(i))&&o.push(t(i,a)));return e&&e.order&&this._sort(o,e.order),o},DataSet.prototype._filterFields=function(t,e){var i={};for(var n in t)t.hasOwnProperty(n)&&-1!=e.indexOf(n)&&(i[n]=t[n]);return i},DataSet.prototype._sort=function(t,e){if(util.isString(e)){var i=e;t.sort(function(t,e){var n=t[i],s=e[i];return n>s?1:s>n?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},DataSet.prototype.remove=function(t,e){var i,n,s,o=[];if(t instanceof Array)for(i=0,n=t.length;n>i;i++)s=this._remove(t[i]),null!=s&&o.push(s);else s=this._remove(t),null!=s&&o.push(s);return o.length&&this._trigger("remove",{items:o},e),o},DataSet.prototype._remove=function(t){if(util.isNumber(t)||util.isString(t)){if(this.data[t])return delete this.data[t],delete this.internalIds[t],t}else if(t instanceof Object){var e=t[this.fieldId];if(e&&this.data[e])return delete this.data[e],delete this.internalIds[e],e}return null},DataSet.prototype.clear=function(t){var e=Object.keys(this.data);return this.data={},this.internalIds={},this._trigger("remove",{items:e},t),e},DataSet.prototype.max=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||r>n)&&(i=o,n=r)}return i},DataSet.prototype.min=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||n>r)&&(i=o,n=r)}return i},DataSet.prototype.distinct=function(t){var e=this.data,i=[],n=this.options.convert[t],s=0;for(var o in e)if(e.hasOwnProperty(o)){for(var r=e[o],a=util.convert(r[t],n),h=!1,l=0;s>l;l++)if(i[l]==a){h=!0;break}h||(i[s]=a,s++)}return i},DataSet.prototype._addItem=function(t){var e=t[this.fieldId];if(void 0!=e){if(this.data[e])throw new Error("Cannot add item: item with id "+e+" already exists")}else e=util.randomUUID(),t[this.fieldId]=e,this.internalIds[e]=t;var i={};for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=util.convert(t[n],s)}return this.data[e]=i,e},DataSet.prototype._getItem=function(t,e){var i,n,s=this.data[t];if(!s)return null;var o={},r=this.fieldId,a=this.internalIds;if(e)for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a&&!this.showInternalIds||(o[i]=util.convert(n,e[i])));else for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a&&!this.showInternalIds||(o[i]=n));return o},DataSet.prototype._updateItem=function(t){var e=t[this.fieldId];if(void 0==e)throw new Error("Cannot update item: item has no id (item: "+JSON.stringify(t)+")");var i=this.data[e];if(!i)throw new Error("Cannot update item: no item with id "+e+" found");for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=util.convert(t[n],s)}return e},DataSet.prototype.isInternalId=function(t){return t in this.internalIds},DataSet.prototype._getColumnNames=function(t){for(var e=[],i=0,n=t.getNumberOfColumns();n>i;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},DataSet.prototype._appendRow=function(t,e,i){for(var n=t.addRow(),s=0,o=e.length;o>s;s++){var r=e[s];t.setValue(n,s,i[r])}},DataView.prototype.setData=function(t){var e,i,n;if(this.data){this.data.unsubscribe&&this.data.unsubscribe("*",this.listener),e=[];for(var s in this.ids)this.ids.hasOwnProperty(s)&&e.push(s);this.ids={},this._trigger("remove",{items:e})}if(this.data=t,this.data){for(this.fieldId=this.options.fieldId||this.data&&this.data.options&&this.data.options.fieldId||"id",e=this.data.getIds({filter:this.options&&this.options.filter}),i=0,n=e.length;n>i;i++)s=e[i],this.ids[s]=!0;this._trigger("add",{items:e}),this.data.subscribe&&this.data.subscribe("*",this.listener)}},DataView.prototype.get=function(){var t,e,i,n=this,s=util.getType(arguments[0]);"String"==s||"Number"==s||"Array"==s?(t=arguments[0],e=arguments[1],i=arguments[2]):(e=arguments[0],i=arguments[1]);var o=util.extend({},this.options,e);this.options.filter&&e&&e.filter&&(o.filter=function(t){return n.options.filter(t)&&e.filter(t)});var r=[];return void 0!=t&&r.push(t),r.push(o),r.push(i),this.data&&this.data.get.apply(this.data,r)},DataView.prototype.getIds=function(t){var e;if(this.data){var i,n=this.options.filter; +i=t&&t.filter?n?function(e){return n(e)&&t.filter(e)}:t.filter:n,e=this.data.getIds({filter:i,order:t&&t.order})}else e=[];return e},DataView.prototype._onEvent=function(t,e,i){var n,s,o,r,a=e&&e.items,h=this.data,l=[],c=[],d=[];if(a&&h){switch(t){case"add":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r&&(this.ids[o]=!0,l.push(o));break;case"update":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r?this.ids[o]?c.push(o):(this.ids[o]=!0,l.push(o)):this.ids[o]&&(delete this.ids[o],d.push(o));break;case"remove":for(n=0,s=a.length;s>n;n++)o=a[n],this.ids[o]&&(delete this.ids[o],d.push(o))}l.length&&this._trigger("add",{items:l},i),c.length&&this._trigger("update",{items:c},i),d.length&&this._trigger("remove",{items:d},i)}},DataView.prototype.subscribe=DataSet.prototype.subscribe,DataView.prototype.unsubscribe=DataSet.prototype.unsubscribe,DataView.prototype._trigger=DataSet.prototype._trigger,TimeStep=function(t,e,i){this.current=new Date,this._start=new Date,this._end=new Date,this.autoScale=!0,this.scale=TimeStep.SCALE.DAY,this.step=1,this.setRange(t,e,i)},TimeStep.SCALE={MILLISECOND:1,SECOND:2,MINUTE:3,HOUR:4,DAY:5,WEEKDAY:6,MONTH:7,YEAR:8},TimeStep.prototype.setRange=function(t,e,i){if(!(t instanceof Date&&e instanceof Date))throw"No legal start or end date in method setRange";this._start=void 0!=t?new Date(t.valueOf()):new Date,this._end=void 0!=e?new Date(e.valueOf()):new Date,this.autoScale&&this.setMinimumStep(i)},TimeStep.prototype.first=function(){this.current=new Date(this._start.valueOf()),this.roundToMinor()},TimeStep.prototype.roundToMinor=function(){switch(this.scale){case TimeStep.SCALE.YEAR:this.current.setFullYear(this.step*Math.floor(this.current.getFullYear()/this.step)),this.current.setMonth(0);case TimeStep.SCALE.MONTH:this.current.setDate(1);case TimeStep.SCALE.DAY:case TimeStep.SCALE.WEEKDAY:this.current.setHours(0);case TimeStep.SCALE.HOUR:this.current.setMinutes(0);case TimeStep.SCALE.MINUTE:this.current.setSeconds(0);case TimeStep.SCALE.SECOND:this.current.setMilliseconds(0)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.setMilliseconds(this.current.getMilliseconds()-this.current.getMilliseconds()%this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()-this.current.getSeconds()%this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()-this.current.getMinutes()%this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()-this.current.getHours()%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()-1-(this.current.getDate()-1)%this.step+1);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()-this.current.getMonth()%this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()-this.current.getFullYear()%this.step)}},TimeStep.prototype.hasNext=function(){return this.current.valueOf()<=this._end.valueOf()},TimeStep.prototype.next=function(){var t=this.current.valueOf();if(this.current.getMonth()<6)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current=new Date(this.current.valueOf()+1e3*this.step);break;case TimeStep.SCALE.MINUTE:this.current=new Date(this.current.valueOf()+1e3*this.step*60);break;case TimeStep.SCALE.HOUR:this.current=new Date(this.current.valueOf()+1e3*this.step*60*60);var e=this.current.getHours();this.current.setHours(e-e%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}else switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()+this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()+this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()+this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.getMilliseconds()0&&(this.step=e),this.autoScale=!1},TimeStep.prototype.setAutoScale=function(t){this.autoScale=t},TimeStep.prototype.setMinimumStep=function(t){if(void 0!=t){var e=31104e6,i=2592e6,n=864e5,s=36e5,o=6e4,r=1e3,a=1;1e3*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1e3),500*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=500),100*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=100),50*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=50),10*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=10),5*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=5),e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1),3*i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=3),i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=1),5*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=5),2*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=2),n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=1),n/2>t&&(this.scale=TimeStep.SCALE.WEEKDAY,this.step=1),4*s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=4),s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=1),15*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=15),10*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=10),5*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=5),o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=1),15*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=15),10*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=10),5*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=5),r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=1),200*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=200),100*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=100),50*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=50),10*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=10),5*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=5),a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=1)}},TimeStep.prototype.snap=function(t){if(this.scale==TimeStep.SCALE.YEAR){var e=t.getFullYear()+Math.round(t.getMonth()/12);t.setFullYear(Math.round(e/this.step)*this.step),t.setMonth(0),t.setDate(0),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MONTH)t.getDate()>15?(t.setDate(1),t.setMonth(t.getMonth()+1)):t.setDate(1),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0);else if(this.scale==TimeStep.SCALE.DAY||this.scale==TimeStep.SCALE.WEEKDAY){switch(this.step){case 5:case 2:t.setHours(24*Math.round(t.getHours()/24));break;default:t.setHours(12*Math.round(t.getHours()/12))}t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.HOUR){switch(this.step){case 4:t.setMinutes(60*Math.round(t.getMinutes()/60));break;default:t.setMinutes(30*Math.round(t.getMinutes()/30))}t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MINUTE){switch(this.step){case 15:case 10:t.setMinutes(5*Math.round(t.getMinutes()/5)),t.setSeconds(0);break;case 5:t.setSeconds(60*Math.round(t.getSeconds()/60));break;default:t.setSeconds(30*Math.round(t.getSeconds()/30))}t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.SECOND)switch(this.step){case 15:case 10:t.setSeconds(5*Math.round(t.getSeconds()/5)),t.setMilliseconds(0);break;case 5:t.setMilliseconds(1e3*Math.round(t.getMilliseconds()/1e3));break;default:t.setMilliseconds(500*Math.round(t.getMilliseconds()/500))}else if(this.scale==TimeStep.SCALE.MILLISECOND){var i=this.step>5?this.step/2:1;t.setMilliseconds(Math.round(t.getMilliseconds()/i)*i)}},TimeStep.prototype.isMajor=function(){switch(this.scale){case TimeStep.SCALE.MILLISECOND:return 0==this.current.getMilliseconds();case TimeStep.SCALE.SECOND:return 0==this.current.getSeconds();case TimeStep.SCALE.MINUTE:return 0==this.current.getHours()&&0==this.current.getMinutes();case TimeStep.SCALE.HOUR:return 0==this.current.getHours();case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return 1==this.current.getDate();case TimeStep.SCALE.MONTH:return 0==this.current.getMonth();case TimeStep.SCALE.YEAR:return!1;default:return!1}},TimeStep.prototype.getLabelMinor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return moment(t).format("SSS");case TimeStep.SCALE.SECOND:return moment(t).format("s");case TimeStep.SCALE.MINUTE:return moment(t).format("HH:mm");case TimeStep.SCALE.HOUR:return moment(t).format("HH:mm");case TimeStep.SCALE.WEEKDAY:return moment(t).format("ddd D");case TimeStep.SCALE.DAY:return moment(t).format("D");case TimeStep.SCALE.MONTH:return moment(t).format("MMM");case TimeStep.SCALE.YEAR:return moment(t).format("YYYY");default:return""}},TimeStep.prototype.getLabelMajor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return moment(t).format("HH:mm:ss");case TimeStep.SCALE.SECOND:return moment(t).format("D MMMM HH:mm");case TimeStep.SCALE.MINUTE:case TimeStep.SCALE.HOUR:return moment(t).format("ddd D MMMM");case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return moment(t).format("MMMM YYYY");case TimeStep.SCALE.MONTH:return moment(t).format("YYYY");case TimeStep.SCALE.YEAR:return"";default:return""}},Stack.prototype.setOptions=function(t){util.extend(this.options,t)},Stack.prototype.update=function(){this._order(),this._stack()},Stack.prototype._order=function(){var t=this.parent.items;if(!t)throw new Error("Cannot stack items: parent does not contain items");var e=[],i=0;util.forEach(t,function(t){t.visible&&(e[i]=t,i++)});var n=this.options.order||this.defaultOptions.order;if("function"!=typeof n)throw new Error("Option order must be a function");e.sort(n),this.ordered=e},Stack.prototype._stack=function(){var t,e,i,n=this.ordered,s=this.options,o=s.orientation||this.defaultOptions.orientation,r="top"==o;for(i=s.margin&&void 0!==s.margin.item?s.margin.item:this.defaultOptions.margin.item,t=0,e=n.length;e>t;t++){var a=n[t],h=null;do h=this.checkOverlap(n,t,0,t-1,i),null!=h&&(a.top=r?h.top+h.height+i:h.top-a.height-i);while(h)}},Stack.prototype.checkOverlap=function(t,e,i,n,s){for(var o=this.collision,r=t[e],a=n;a>=i;a--){var h=t[a];if(o(r,h,s)&&a!=e)return h}return null},Stack.prototype.collision=function(t,e,i){return t.left-ie.left&&t.top-ie.top},Range.prototype.setOptions=function(t){util.extend(this.options,t),null!==this.start&&null!==this.end&&this.setRange(this.start,this.end)},Range.prototype.subscribe=function(t,e,i){function n(e){s._onMouseWheel(e,t,i)}var s=this;if("move"==e)t.on("dragstart",function(e){s._onDragStart(e,t)}),t.on("drag",function(e){s._onDrag(e,t,i)}),t.on("dragend",function(e){s._onDragEnd(e,t)});else{if("zoom"!=e)throw new TypeError('Unknown event "'+e+'". Choose "move" or "zoom".');t.on("mousewheel",n),t.on("DOMMouseScroll",n),t.on("touch",function(){s._onTouch()}),t.on("pinch",function(e){s._onPinch(e,t,i)})}},Range.prototype.on=function(t,e){var i=["rangechange","rangechanged"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());events.addListener(this,t,e)},Range.prototype.off=function(t,e){events.removeListener(this,t,e)},Range.prototype._trigger=function(t){events.trigger(this,t,{start:this.start,end:this.end})},Range.prototype.setRange=function(t,e){var i=this._applyRange(t,e);i&&(this._trigger("rangechange"),this._trigger("rangechanged"))},Range.prototype._applyRange=function(t,e){var i,n=null!=t?util.convert(t,"Date").valueOf():this.start,s=null!=e?util.convert(e,"Date").valueOf():this.end,o=null!=this.options.max?util.convert(this.options.max,"Date").valueOf():null,r=null!=this.options.min?util.convert(this.options.min,"Date").valueOf():null;if(isNaN(n)||null===n)throw new Error('Invalid start "'+t+'"');if(isNaN(s)||null===s)throw new Error('Invalid end "'+e+'"');if(n>s&&(s=n),null!==r&&r>n&&(i=r-n,n+=i,s+=i,null!=o&&s>o&&(s=o)),null!==o&&s>o&&(i=s-o,n-=i,s-=i,null!=r&&r>n&&(n=r)),null!==this.options.zoomMin){var a=parseFloat(this.options.zoomMin);0>a&&(a=0),a>s-n&&(this.end-this.start===a?(n=this.start,s=this.end):(i=a-(s-n),n-=i/2,s+=i/2))}if(null!==this.options.zoomMax){var h=parseFloat(this.options.zoomMax);0>h&&(h=0),s-n>h&&(this.end-this.start===h?(n=this.start,s=this.end):(i=s-n-h,n+=i/2,s-=i/2))}var l=this.start!=n||this.end!=s;return this.start=n,this.end=s,l},Range.prototype.getRange=function(){return{start:this.start,end:this.end}},Range.prototype.conversion=function(t){return Range.conversion(this.start,this.end,t)},Range.conversion=function(t,e,i){return 0!=i&&e-t!=0?{offset:t,scale:i/(e-t)}:{offset:0,scale:1}};var touchParams={};Range.prototype._onDragStart=function(t,e){if(!touchParams.pinching){touchParams.start=this.start,touchParams.end=this.end;var i=e.frame;i&&(i.style.cursor="move")}},Range.prototype._onDrag=function(t,e,i){if(validateDirection(i),!touchParams.pinching){var n="horizontal"==i?t.gesture.deltaX:t.gesture.deltaY,s=touchParams.end-touchParams.start,o="horizontal"==i?e.width:e.height,r=-n/o*s;this._applyRange(touchParams.start+r,touchParams.end+r),this._trigger("rangechange")}},Range.prototype._onDragEnd=function(t,e){touchParams.pinching||(e.frame&&(e.frame.style.cursor="auto"),this._trigger("rangechanged"))},Range.prototype._onMouseWheel=function(t,e,i){validateDirection(i);var n=0;if(t.wheelDelta?n=t.wheelDelta/120:t.detail&&(n=-t.detail/3),n){var s;s=0>n?1-n/5:1/(1+n/5);var o=util.fakeGesture(this,t),r=getPointer(o.touches[0],e.frame),a=this._pointerToDate(e,i,r);this.zoom(s,a)}util.preventDefault(t)},Range.prototype._onTouch=function(){touchParams.start=this.start,touchParams.end=this.end,touchParams.pinching=!1,touchParams.center=null},Range.prototype._onPinch=function(t,e,i){if(touchParams.pinching=!0,t.gesture.touches.length>1){touchParams.center||(touchParams.center=getPointer(t.gesture.center,e.frame));var n=1/t.gesture.scale,s=this._pointerToDate(e,i,touchParams.center),o=getPointer(t.gesture.center,e.frame),r=(this._pointerToDate(e,i,o),parseInt(s+(touchParams.start-s)*n)),a=parseInt(s+(touchParams.end-s)*n);this.setRange(r,a)}},Range.prototype._pointerToDate=function(t,e,i){var n;if("horizontal"==e){var s=t.width;return n=this.conversion(s),i.x/n.scale+n.offset}var o=t.height;return n=this.conversion(o),i.y/n.scale+n.offset},Range.prototype.zoom=function(t,e){null==e&&(e=(this.start+this.end)/2);var i=e+(this.start-e)*t,n=e+(this.end-e)*t;this.setRange(i,n)},Range.prototype.move=function(t){var e=this.end-this.start,i=this.start+e*t,n=this.end+e*t;this.start=i,this.end=n},Range.prototype.moveTo=function(t){var e=(this.start+this.end)/2,i=e-t,n=this.start-i,s=this.end-i;this.setRange(n,s)},Controller.prototype.add=function(t){if(void 0==t.id)throw new Error("Component has no field id");if(!(t instanceof Component||t instanceof Controller))throw new TypeError("Component must be an instance of prototype Component or Controller");t.controller=this,this.components[t.id]=t},Controller.prototype.remove=function(t){var e;for(e in this.components)if(this.components.hasOwnProperty(e)&&(e==t||this.components[e]==t))break;e&&delete this.components[e]},Controller.prototype.requestReflow=function(t){if(t)this.reflow();else if(!this.reflowTimer){var e=this;this.reflowTimer=setTimeout(function(){e.reflowTimer=void 0,e.reflow()},0)}},Controller.prototype.requestRepaint=function(t){if(t)this.repaint();else if(!this.repaintTimer){var e=this;this.repaintTimer=setTimeout(function(){e.repaintTimer=void 0,e.repaint()},0)}},Controller.prototype.repaint=function t(){function t(n,s){s in i||(n.depends&&n.depends.forEach(function(e){t(e,e.id)}),n.parent&&t(n.parent,n.parent.id),e=n.repaint()||e,i[s]=!0)}var e=!1;this.repaintTimer&&(clearTimeout(this.repaintTimer),this.repaintTimer=void 0);var i={};util.forEach(this.components,t),e&&this.reflow()},Controller.prototype.reflow=function e(){function e(n,s){s in i||(n.depends&&n.depends.forEach(function(t){e(t,t.id)}),n.parent&&e(n.parent,n.parent.id),t=n.reflow()||t,i[s]=!0)}var t=!1;this.reflowTimer&&(clearTimeout(this.reflowTimer),this.reflowTimer=void 0);var i={};util.forEach(this.components,e),t&&this.repaint()},Component.prototype.setOptions=function(t){t&&(util.extend(this.options,t),this.controller&&(this.requestRepaint(),this.requestReflow()))},Component.prototype.getOption=function(t){var e;return this.options&&(e=this.options[t]),void 0===e&&this.defaultOptions&&(e=this.defaultOptions[t]),e},Component.prototype.getContainer=function(){return null},Component.prototype.getFrame=function(){return this.frame},Component.prototype.repaint=function(){return!1},Component.prototype.reflow=function(){return!1},Component.prototype.hide=function(){return this.frame&&this.frame.parentNode?(this.frame.parentNode.removeChild(this.frame),!0):!1},Component.prototype.show=function(){return this.frame&&this.frame.parentNode?!1:this.repaint()},Component.prototype.requestRepaint=function(){if(!this.controller)throw new Error("Cannot request a repaint: no controller configured");this.controller.requestRepaint()},Component.prototype.requestReflow=function(){if(!this.controller)throw new Error("Cannot request a reflow: no controller configured");this.controller.requestReflow()},Panel.prototype=new Component,Panel.prototype.setOptions=Component.prototype.setOptions,Panel.prototype.getContainer=function(){return this.frame},Panel.prototype.repaint=function(){var t=0,e=util.updateProperty,i=util.option.asSize,n=this.options,s=this.frame;if(!s){s=document.createElement("div"),s.className="panel";var o=n.className;o&&("function"==typeof o?util.addClassName(s,String(o())):util.addClassName(s,String(o))),this.frame=s,t+=1}if(!s.parentNode){if(!this.parent)throw new Error("Cannot repaint panel: no parent attached");var r=this.parent.getContainer();if(!r)throw new Error("Cannot repaint panel: parent has no container element");r.appendChild(s),t+=1}return t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),t>0},Panel.prototype.reflow=function(){var t=0,e=util.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},RootPanel.prototype=new Panel,RootPanel.prototype.setOptions=Component.prototype.setOptions,RootPanel.prototype.repaint=function(){var t=0,e=util.updateProperty,i=util.option.asSize,n=this.options,s=this.frame;if(s||(s=document.createElement("div"),this.frame=s,t+=1),!s.parentNode){if(!this.container)throw new Error("Cannot repaint root panel: no container attached");this.container.appendChild(s),t+=1}s.className="vis timeline rootpanel "+n.orientation;var o=n.className;return o&&util.addClassName(s,util.option.asString(o)),t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),this._updateEventEmitters(),this._updateWatch(),t>0},RootPanel.prototype.reflow=function(){var t=0,e=util.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},RootPanel.prototype._updateWatch=function(){var t=this.getOption("autoResize");t?this._watch():this._unwatch()},RootPanel.prototype._watch=function(){var t=this;this._unwatch();var e=function(){var e=t.getOption("autoResize");return e?void(t.frame&&(t.frame.clientWidth!=t.width||t.frame.clientHeight!=t.height)&&t.requestReflow()):void t._unwatch()};util.addEventListener(window,"resize",e),this.watchTimer=setInterval(e,1e3)},RootPanel.prototype._unwatch=function(){this.watchTimer&&(clearInterval(this.watchTimer),this.watchTimer=void 0)},RootPanel.prototype.on=function(t,e){var i=this.listeners[t];i||(i=[],this.listeners[t]=i),i.push(e),this._updateEventEmitters()},RootPanel.prototype._updateEventEmitters=function(){if(this.listeners){var t=this;util.forEach(this.listeners,function(e,i){if(t.emitters||(t.emitters={}),!(i in t.emitters)){var n=t.frame;if(n){var s=function(t){e.forEach(function(e){e(t)})};t.emitters[i]=s,t.hammer||(t.hammer=Hammer(n,{prevent_default:!0})),t.hammer.on(i,s)}}})}},TimeAxis.prototype=new Component,TimeAxis.prototype.setOptions=Component.prototype.setOptions,TimeAxis.prototype.setRange=function(t){if(!(t instanceof Range||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},TimeAxis.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},TimeAxis.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},TimeAxis.prototype.repaint=function(){var t=0,e=util.updateProperty,i=util.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.props,r=this.step,a=this.frame;if(a||(a=document.createElement("div"),this.frame=a,t+=1),a.className="axis",!a.parentNode){if(!this.parent)throw new Error("Cannot repaint time axis: no parent attached");var h=this.parent.getContainer();if(!h)throw new Error("Cannot repaint time axis: parent has no container element");h.appendChild(a),t+=1}var l=a.parentNode;if(l){var c=a.nextSibling;l.removeChild(a);var d="bottom"==s&&this.props.parentHeight&&this.height?this.props.parentHeight-this.height+"px":"0px";if(t+=e(a.style,"top",i(n.top,d)),t+=e(a.style,"left",i(n.left,"0px")),t+=e(a.style,"width",i(n.width,"100%")),t+=e(a.style,"height",i(n.height,this.height+"px")),this._repaintMeasureChars(),this.step){this._repaintStart(),r.first();for(var u=void 0,p=0;r.hasNext()&&1e3>p;){p++;var f=r.getCurrent(),g=this.toScreen(f),m=r.isMajor();this.getOption("showMinorLabels")&&this._repaintMinorText(g,r.getLabelMinor()),m&&this.getOption("showMajorLabels")?(g>0&&(void 0==u&&(u=g),this._repaintMajorText(g,r.getLabelMajor())),this._repaintMajorLine(g)):this._repaintMinorLine(g),r.next()}if(this.getOption("showMajorLabels")){var v=this.toTime(0),y=r.getLabelMajor(v),_=y.length*(o.majorCharWidth||10)+10;(void 0==u||u>_)&&this._repaintMajorText(0,y)}this._repaintEnd()}this._repaintLine(),c?l.insertBefore(a,c):l.appendChild(a)}return t>0},TimeAxis.prototype._repaintStart=function(){var t=this.dom,e=t.redundant;e.majorLines=t.majorLines,e.majorTexts=t.majorTexts,e.minorLines=t.minorLines,e.minorTexts=t.minorTexts,t.majorLines=[],t.majorTexts=[],t.minorLines=[],t.minorTexts=[]},TimeAxis.prototype._repaintEnd=function(){util.forEach(this.dom.redundant,function(t){for(;t.length;){var e=t.pop();e&&e.parentNode&&e.parentNode.removeChild(e)}})},TimeAxis.prototype._repaintMinorText=function(t,e){var i=this.dom.redundant.minorTexts.shift();if(!i){var n=document.createTextNode("");i=document.createElement("div"),i.appendChild(n),i.className="text minor",this.frame.appendChild(i)}this.dom.minorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.left=t+"px",i.style.top=this.props.minorLabelTop+"px"},TimeAxis.prototype._repaintMajorText=function(t,e){var i=this.dom.redundant.majorTexts.shift();if(!i){var n=document.createTextNode(e);i=document.createElement("div"),i.className="text major",i.appendChild(n),this.frame.appendChild(i)}this.dom.majorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.top=this.props.majorLabelTop+"px",i.style.left=t+"px"},TimeAxis.prototype._repaintMinorLine=function(t){var e=this.dom.redundant.minorLines.shift();e||(e=document.createElement("div"),e.className="grid vertical minor",this.frame.appendChild(e)),this.dom.minorLines.push(e);var i=this.props;e.style.top=i.minorLineTop+"px",e.style.height=i.minorLineHeight+"px",e.style.left=t-i.minorLineWidth/2+"px"},TimeAxis.prototype._repaintMajorLine=function(t){var e=this.dom.redundant.majorLines.shift();e||(e=document.createElement("DIV"),e.className="grid vertical major",this.frame.appendChild(e)),this.dom.majorLines.push(e);var i=this.props;e.style.top=i.majorLineTop+"px",e.style.left=t-i.majorLineWidth/2+"px",e.style.height=i.majorLineHeight+"px"},TimeAxis.prototype._repaintLine=function(){{var t=this.dom.line,e=this.frame;this.options}this.getOption("showMinorLabels")||this.getOption("showMajorLabels")?(t?(e.removeChild(t),e.appendChild(t)):(t=document.createElement("div"),t.className="grid horizontal major",e.appendChild(t),this.dom.line=t),t.style.top=this.props.lineTop+"px"):t&&t.parentElement&&(e.removeChild(t.line),delete this.dom.line)},TimeAxis.prototype._repaintMeasureChars=function(){var t,e=this.dom;if(!e.measureCharMinor){t=document.createTextNode("0");var i=document.createElement("DIV");i.className="text minor measure",i.appendChild(t),this.frame.appendChild(i),e.measureCharMinor=i}if(!e.measureCharMajor){t=document.createTextNode("0");var n=document.createElement("DIV");n.className="text major measure",n.appendChild(t),this.frame.appendChild(n),e.measureCharMajor=n}},TimeAxis.prototype.reflow=function(){var t=0,e=util.updateProperty,i=this.frame,n=this.range;if(!n)throw new Error("Cannot repaint time axis: no range configured");if(i){t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft);var s=this.props,o=this.getOption("showMinorLabels"),r=this.getOption("showMajorLabels"),a=this.dom.measureCharMinor,h=this.dom.measureCharMajor;a&&(s.minorCharHeight=a.clientHeight,s.minorCharWidth=a.clientWidth),h&&(s.majorCharHeight=h.clientHeight,s.majorCharWidth=h.clientWidth);var l=i.parentNode?i.parentNode.offsetHeight:0;switch(l!=s.parentHeight&&(s.parentHeight=l,t+=1),this.getOption("orientation")){case"bottom":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.minorLabelTop=0,s.majorLabelTop=s.minorLabelTop+s.minorLabelHeight,s.minorLineTop=-this.top,s.minorLineHeight=Math.max(this.top+s.majorLabelHeight,0),s.minorLineWidth=1,s.majorLineTop=-this.top,s.majorLineHeight=Math.max(this.top+s.minorLabelHeight+s.majorLabelHeight,0),s.majorLineWidth=1,s.lineTop=0;break;case"top":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.majorLabelTop=0,s.minorLabelTop=s.majorLabelTop+s.majorLabelHeight,s.minorLineTop=s.minorLabelTop,s.minorLineHeight=Math.max(l-s.majorLabelHeight-this.top),s.minorLineWidth=1,s.majorLineTop=0,s.majorLineHeight=Math.max(l-this.top),s.majorLineWidth=1,s.lineTop=s.majorLabelHeight+s.minorLabelHeight;break;default:throw new Error('Unkown orientation "'+this.getOption("orientation")+'"')}var c=s.minorLabelHeight+s.majorLabelHeight;t+=e(this,"width",i.offsetWidth),t+=e(this,"height",c),this._updateConversion();var d=util.convert(n.start,"Number"),u=util.convert(n.end,"Number"),p=this.toTime(5*(s.minorCharWidth||10)).valueOf()-this.toTime(0).valueOf();this.step=new TimeStep(new Date(d),new Date(u),p),t+=e(s.range,"start",d),t+=e(s.range,"end",u),t+=e(s.range,"minimumStep",p.valueOf())}return t>0},TimeAxis.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):Range.conversion(t.start,t.end,this.width)},CurrentTime.prototype=new Component,CurrentTime.prototype.setOptions=Component.prototype.setOptions,CurrentTime.prototype.getContainer=function(){return this.frame},CurrentTime.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCurrentTime"))return void(t&&(i.removeChild(t),delete this.frame));t||(t=document.createElement("div"),t.className="currenttime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t),this.frame=t),e.conversion||e._updateConversion();var n=new Date,s=e.toScreen(n);t.style.left=s+"px",t.title="Current time: "+n,void 0!==this.currentTimeTimer&&(clearTimeout(this.currentTimeTimer),delete this.currentTimeTimer);var o=this,r=1/e.conversion.scale/2;return 30>r&&(r=30),this.currentTimeTimer=setTimeout(function(){o.repaint()},r),!1},CustomTime.prototype=new Component,CustomTime.prototype.setOptions=Component.prototype.setOptions,CustomTime.prototype.getContainer=function(){return this.frame},CustomTime.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCustomTime"))return void(t&&(i.removeChild(t),delete this.frame));if(!t){t=document.createElement("div"),t.className="customtime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t);var n=document.createElement("div");n.style.position="relative",n.style.top="0px",n.style.left="-10px",n.style.height="100%",n.style.width="20px",t.appendChild(n),this.frame=t,this.subscribe(this,"movetime")}e.conversion||e._updateConversion();var s=e.toScreen(this.customTime);return t.style.left=s+"px",t.title="Time: "+this.customTime,!1},CustomTime.prototype._setCustomTime=function(t){this.customTime=new Date(t.valueOf()),this.repaint()},CustomTime.prototype._getCustomTime=function(){return new Date(this.customTime.valueOf())},CustomTime.prototype.subscribe=function(t,e){var i=this,n={component:t,event:e,callback:function(t){i._onMouseDown(t,n)},params:{}};t.on("mousedown",n.callback),i.listeners.push(n)},CustomTime.prototype.on=function(t,e){var i=this.frame;if(!i)throw new Error("Cannot add event listener: no parent attached");events.addListener(this,t,e),util.addEventListener(i,t,e)},CustomTime.prototype._onMouseDown=function(t,e){t=t||window.event;var i=e.params,n=t.which?1==t.which:1==t.button;if(n){i.mouseX=util.getPageX(t),i.moved=!1,i.customTime=this.customTime;var s=this;i.onMouseMove||(i.onMouseMove=function(t){s._onMouseMove(t,e)},util.addEventListener(document,"mousemove",i.onMouseMove)),i.onMouseUp||(i.onMouseUp=function(t){s._onMouseUp(t,e)},util.addEventListener(document,"mouseup",i.onMouseUp)),util.stopPropagation(t),util.preventDefault(t)}},CustomTime.prototype._onMouseMove=function(t,e){t=t||window.event;var i=e.params,n=this.parent,s=util.getPageX(t);void 0===i.mouseX&&(i.mouseX=s);var o=s-i.mouseX;Math.abs(o)>=1&&(i.moved=!0);var r=n.toScreen(i.customTime),a=r+o,h=n.toTime(a);this._setCustomTime(h),events.trigger(this,"timechange",{customTime:this.customTime}),util.preventDefault(t)},CustomTime.prototype._onMouseUp=function(t,e){t=t||window.event;var i=e.params;i.onMouseMove&&(util.removeEventListener(document,"mousemove",i.onMouseMove),i.onMouseMove=null),i.onMouseUp&&(util.removeEventListener(document,"mouseup",i.onMouseUp),i.onMouseUp=null),i.moved&&events.trigger(this,"timechanged",{customTime:this.customTime}) +},ItemSet.prototype=new Panel,ItemSet.types={box:ItemBox,range:ItemRange,rangeoverflow:ItemRangeOverflow,point:ItemPoint},ItemSet.prototype.setOptions=Component.prototype.setOptions,ItemSet.prototype.setRange=function(t){if(!(t instanceof Range||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},ItemSet.prototype.setSelection=function(t){var e,i,n,s,o;if(t){if(!Array.isArray(t))throw new TypeError("Array expected");for(e=0,i=this.selection.length;i>e;e++)n=this.selection[e],s=this.items[n],s&&s.unselect();for(this.selection=[],e=0,i=t.length;i>e;e++)n=t[e],s=this.items[n],s&&(this.selection.push(n),s.select());o=this.selection.concat([]),events.trigger(this,"select",{ids:o}),this.controller&&this.requestRepaint()}},ItemSet.prototype.getSelection=function(){return this.selection.concat([])},ItemSet.prototype._deselect=function(t){for(var e=this.selection,i=0,n=e.length;n>i;i++)if(e[i]==t){e.splice(i,1);break}},ItemSet.prototype.repaint=function(){var t=0,e=util.updateProperty,i=util.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.defaultOptions,r=this.frame;if(!r){r=document.createElement("div"),r.className="itemset";var a=n.className;a&&util.addClassName(r,util.option.asString(a));var h=document.createElement("div");h.className="background",r.appendChild(h),this.dom.background=h;var l=document.createElement("div");l.className="foreground",r.appendChild(l),this.dom.foreground=l;var c=document.createElement("div");c.className="itemset-axis",this.dom.axis=c,this.frame=r,t+=1}if(!this.parent)throw new Error("Cannot repaint itemset: no parent attached");var d=this.parent.getContainer();if(!d)throw new Error("Cannot repaint itemset: parent has no container element");r.parentNode||(d.appendChild(r),t+=1),this.dom.axis.parentNode||(d.appendChild(this.dom.axis),t+=1),t+=e(r.style,"left",i(n.left,"0px")),t+=e(r.style,"top",i(n.top,"0px")),t+=e(r.style,"width",i(n.width,"100%")),t+=e(r.style,"height",i(n.height,this.height+"px")),t+=e(this.dom.axis.style,"left",i(n.left,"0px")),t+=e(this.dom.axis.style,"width",i(n.width,"100%")),t+="bottom"==s?e(this.dom.axis.style,"top",this.height+this.top+"px"):e(this.dom.axis.style,"top",this.top+"px"),this._updateConversion();var u=this,p=this.queue,f=this.itemsData,g=this.items,m={};for(var v in p)if(p.hasOwnProperty(v)){var y=p[v],_=g[v],b=y.action;switch(b){case"add":case"update":var w=f&&f.get(v,m);if(w){var S=w.type||w.start&&w.end&&"range"||n.type||"box",T=ItemSet.types[S];if(_&&(T&&_ instanceof T?(_.data=w,t++):(t+=_.hide(),_=null)),!_){if(!T)throw new TypeError('Unknown item type "'+S+'"');_=new T(u,w,n,o),_.id=y.id,t++}_.repaint(),g[v]=_}delete p[v];break;case"remove":_&&(_.selected&&u._deselect(v),t+=_.hide()),delete g[v],delete p[v];break;default:console.log('Error: unknown action "'+b+'"')}}return util.forEach(this.items,function(e){e.visible?(t+=e.show(),e.reposition()):t+=e.hide()}),t>0},ItemSet.prototype.getForeground=function(){return this.dom.foreground},ItemSet.prototype.getBackground=function(){return this.dom.background},ItemSet.prototype.getAxis=function(){return this.dom.axis},ItemSet.prototype.reflow=function(){var t=0,e=this.options,i=e.margin&&e.margin.axis||this.defaultOptions.margin.axis,n=e.margin&&e.margin.item||this.defaultOptions.margin.item,s=util.updateProperty,o=util.option.asNumber,r=util.option.asSize,a=this.frame;if(a){this._updateConversion(),util.forEach(this.items,function(e){t+=e.reflow()}),this.stack.update();var h,l=o(e.maxHeight),c=null!=r(e.height);if(c)h=a.offsetHeight;else{var d=this.stack.ordered;if(d.length){var u=d[0].top,p=d[0].top+d[0].height;util.forEach(d,function(t){u=Math.min(u,t.top),p=Math.max(p,t.top+t.height)}),h=p-u+i+n}else h=i+n}null!=l&&(h=Math.min(h,l)),t+=s(this,"height",h),t+=s(this,"top",a.offsetTop),t+=s(this,"left",a.offsetLeft),t+=s(this,"width",a.offsetWidth)}else t+=1;return t>0},ItemSet.prototype.hide=function(){var t=!1;return this.frame&&this.frame.parentNode&&(this.frame.parentNode.removeChild(this.frame),t=!0),this.dom.axis&&this.dom.axis.parentNode&&(this.dom.axis.parentNode.removeChild(this.dom.axis),t=!0),t},ItemSet.prototype.setItems=function(t){var e,i=this,n=this.itemsData;if(t){if(!(t instanceof DataSet||t instanceof DataView))throw new TypeError("Data must be an instance of DataSet");this.itemsData=t}else this.itemsData=null;if(n&&(util.forEach(this.listeners,function(t,e){n.unsubscribe(e,t)}),e=n.getIds(),this._onRemove(e)),this.itemsData){var s=this.id;util.forEach(this.listeners,function(t,e){i.itemsData.subscribe(e,t,s)}),e=this.itemsData.getIds(),this._onAdd(e)}},ItemSet.prototype.getItems=function(){return this.itemsData},ItemSet.prototype._onUpdate=function(t){this._toQueue("update",t)},ItemSet.prototype._onAdd=function(t){this._toQueue("add",t)},ItemSet.prototype._onRemove=function(t){this._toQueue("remove",t)},ItemSet.prototype._toQueue=function(t,e){var i=this.queue;e.forEach(function(e){i[e]={id:e,action:t}}),this.controller&&this.requestRepaint()},ItemSet.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):Range.conversion(t.start,t.end,this.width)},ItemSet.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},ItemSet.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},Item.prototype.select=function(){this.selected=!0,this.visible&&this.repaint()},Item.prototype.unselect=function(){this.selected=!1,this.visible&&this.repaint()},Item.prototype.show=function(){return!1},Item.prototype.hide=function(){return!1},Item.prototype.repaint=function(){return!1},Item.prototype.reflow=function(){return!1},Item.prototype.getWidth=function(){return this.width},ItemBox.prototype=new Item(null,null),ItemBox.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");if(!e.box.parentNode){var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");i.appendChild(e.box),t=!0}if(!e.line.parentNode){var n=this.parent.getBackground();if(!n)throw new Error("Cannot repaint time axis: parent has no background container element");n.appendChild(e.line),t=!0}if(!e.dot.parentNode){var s=this.parent.getAxis();if(!n)throw new Error("Cannot repaint time axis: parent has no axis container element");s.appendChild(e.dot),t=!0}if(this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var o=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=o&&(this.className=o,e.box.className="item box"+o,e.line.className="item line"+o,e.dot.className="item dot"+o,t=!0)}return t},ItemBox.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},ItemBox.prototype.hide=function(){var t=!1,e=this.dom;return e&&(e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),e.line.parentNode&&e.line.parentNode.removeChild(e.line),e.dot.parentNode&&e.dot.parentNode.removeChild(e.dot)),t},ItemBox.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,l,c,d,u=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(c=this.data,d=this.parent&&this.parent.range,c&&d){var p=d.end-d.start;this.visible=c.start>d.start-p&&c.start0},ItemBox.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("DIV"),t.content=document.createElement("DIV"),t.content.className="content",t.box.appendChild(t.content),t.line=document.createElement("DIV"),t.line.className="line",t.dot=document.createElement("DIV"),t.dot.className="dot",t.box["timeline-item"]=this)},ItemBox.prototype.reposition=function(){var t=this.dom,e=this.props,i=this.options.orientation||this.defaultOptions.orientation;if(t){var n=t.box,s=t.line,o=t.dot;n.style.left=this.left+"px",n.style.top=this.top+"px",s.style.left=e.line.left+"px","top"==i?(s.style.top="0px",s.style.height=this.top+"px"):(s.style.top=this.top+this.height+"px",s.style.height=Math.max(this.parent.height-this.top-this.height+this.props.dot.height/2,0)+"px"),o.style.left=e.dot.left+"px",o.style.top=e.dot.top+"px"}},ItemPoint.prototype=new Item(null,null),ItemPoint.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.point.parentNode||(i.appendChild(e.point),i.appendChild(e.point),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.point.className="item point"+n,t=!0)}return t},ItemPoint.prototype.show=function(){return this.dom&&this.dom.point.parentNode?!1:this.repaint()},ItemPoint.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.point.parentNode&&(e.point.parentNode.removeChild(e.point),t=!0),t},ItemPoint.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,l,c=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(h=this.data,l=this.parent&&this.parent.range,h&&l){var d=l.end-l.start;this.visible=h.start>l.start-d&&h.start0},ItemPoint.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.point=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.point.appendChild(t.content),t.dot=document.createElement("div"),t.dot.className="dot",t.point.appendChild(t.dot),t.point["timeline-item"]=this)},ItemPoint.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.point.style.top=this.top+"px",t.point.style.left=this.left+"px",t.content.style.marginLeft=e.content.marginLeft+"px",t.dot.style.top=e.dot.top+"px")},ItemRange.prototype=new Item(null,null),ItemRange.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.box.className="item range"+n,t=!0)}return t},ItemRange.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},ItemRange.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),t},ItemRange.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,l,c,d,u,p,f,g,m=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(void 0==this.data.end)throw new Error('Property "end" missing in item '+this.data.id);return h=this.data,l=this.parent&&this.parent.range,this.visible=h&&l?h.startl.start:!1,this.visible&&(t=this.dom,t?(e=this.props,i=this.options,o=this.parent,r=o.toScreen(this.data.start),a=o.toScreen(this.data.end),c=util.updateProperty,d=t.box,u=o.width,f=i.orientation||this.defaultOptions.orientation,n=i.margin&&i.margin.axis||this.defaultOptions.margin.axis,s=i.padding||this.defaultOptions.padding,m+=c(e.content,"width",t.content.offsetWidth),m+=c(this,"height",d.offsetHeight),-u>r&&(r=-u),a>2*u&&(a=2*u),p=0>r?Math.min(-r,a-r-e.content.width-2*s):0,m+=c(e.content,"left",p),"top"==f?(g=n,m+=c(this,"top",g)):(g=o.height-this.height-n,m+=c(this,"top",g)),m+=c(this,"left",r),m+=c(this,"width",Math.max(a-r,1))):m+=1),m>0},ItemRange.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content),t.box["timeline-item"]=this)},ItemRange.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.box.style.top=this.top+"px",t.box.style.left=this.left+"px",t.box.style.width=this.width+"px",t.content.style.left=e.content.left+"px")},ItemRangeOverflow.prototype=new ItemRange(null,null),ItemRangeOverflow.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=this.data.className?" "+this.data.className:"";this.className!=n&&(this.className=n,e.box.className="item rangeoverflow"+n,t=!0)}return t},ItemRangeOverflow.prototype.getWidth=function(){return void 0!==this.props.content&&this.width0},GroupSet.prototype=new Panel,GroupSet.prototype.setOptions=Component.prototype.setOptions,GroupSet.prototype.setRange=function(){},GroupSet.prototype.setItems=function(t){this.itemsData=t;for(var e in this.groups)if(this.groups.hasOwnProperty(e)){var i=this.groups[e];i.setItems(t)}},GroupSet.prototype.getItems=function(){return this.itemsData},GroupSet.prototype.setRange=function(t){this.range=t},GroupSet.prototype.setGroups=function(t){var e,i=this;if(this.groupsData&&(util.forEach(this.listeners,function(t,e){i.groupsData.unsubscribe(e,t)}),e=this.groupsData.getIds(),this._onRemove(e)),t?t instanceof DataSet?this.groupsData=t:(this.groupsData=new DataSet({convert:{start:"Date",end:"Date"}}),this.groupsData.add(t)):this.groupsData=null,this.groupsData){var n=this.id;util.forEach(this.listeners,function(t,e){i.groupsData.subscribe(e,t,n)}),e=this.groupsData.getIds(),this._onAdd(e)}},GroupSet.prototype.getGroups=function(){return this.groupsData},GroupSet.prototype.setSelection=function(t){var e=[],i=this.groups;for(var n in i)if(i.hasOwnProperty(n)){var s=i[n];s.setSelection(t)}return e},GroupSet.prototype.getSelection=function(){var t=[],e=this.groups;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];t=t.concat(n.getSelection())}return t},GroupSet.prototype.repaint=function(){var t,e,i,n,s=0,o=util.updateProperty,r=util.option.asSize,a=util.option.asElement,h=this.options,l=this.dom.frame,c=this.dom.labels,d=this.dom.labelSet;if(!this.parent)throw new Error("Cannot repaint groupset: no parent attached");var u=this.parent.getContainer();if(!u)throw new Error("Cannot repaint groupset: parent has no container element");if(!l){l=document.createElement("div"),l.className="groupset",this.dom.frame=l;var p=h.className;p&&util.addClassName(l,util.option.asString(p)),s+=1}l.parentNode||(u.appendChild(l),s+=1);var f=a(h.labelContainer);if(!f)throw new Error('Cannot repaint groupset: option "labelContainer" not defined');c||(c=document.createElement("div"),c.className="labels",this.dom.labels=c),d||(d=document.createElement("div"),d.className="label-set",c.appendChild(d),this.dom.labelSet=d),c.parentNode&&c.parentNode==f||(c.parentNode&&c.parentNode.removeChild(c.parentNode),f.appendChild(c)),s+=o(l.style,"height",r(h.height,this.height+"px")),s+=o(l.style,"top",r(h.top,"0px")),s+=o(l.style,"left",r(h.left,"0px")),s+=o(l.style,"width",r(h.width,"100%")),s+=o(d.style,"top",r(h.top,"0px")),s+=o(d.style,"height",r(h.height,this.height+"px"));var g=this,m=this.queue,v=this.groups,y=this.groupsData,_=Object.keys(m);if(_.length){_.forEach(function(t){var e=m[t],i=v[t];switch(e){case"add":case"update":if(!i){var n=Object.create(g.options);util.extend(n,{height:null,maxHeight:null}),i=new Group(g,t,n),i.setItems(g.itemsData),v[t]=i,g.controller.add(i)}i.data=y.get(t),delete m[t];break;case"remove":i&&(i.setItems(),delete v[t],g.controller.remove(i)),delete m[t];break;default:console.log('Error: unknown action "'+e+'"')}});var b=this.groupsData.getIds({order:this.options.groupOrder});for(t=0;t0},GroupSet.prototype._createLabel=function(t){var e=this.groups[t],i=document.createElement("div");i.className="label";var n=document.createElement("div");n.className="inner",i.appendChild(n);var s=e.data&&e.data.content;s instanceof Element?n.appendChild(s):void 0!=s&&(n.innerHTML=s);var o=e.data&&e.data.className;return o&&util.addClassName(i,o),e.label=i,i},GroupSet.prototype.getContainer=function(){return this.dom.frame},GroupSet.prototype.getLabelsWidth=function(){return this.props.labels.width},GroupSet.prototype.reflow=function(){var t,e,i=0,n=this.options,s=util.updateProperty,o=util.option.asNumber,r=util.option.asSize,a=this.dom.frame;if(a){var h,l=o(n.maxHeight),c=null!=r(n.height);if(c)h=a.offsetHeight;else{h=0;for(t in this.groups)this.groups.hasOwnProperty(t)&&(e=this.groups[t],h+=e.height)}null!=l&&(h=Math.min(h,l)),i+=s(this,"height",h),i+=s(this,"top",a.offsetTop),i+=s(this,"left",a.offsetLeft),i+=s(this,"width",a.offsetWidth)}var d=0;for(t in this.groups)if(this.groups.hasOwnProperty(t)){e=this.groups[t];var u=e.props&&e.props.label&&e.props.label.width||0;d=Math.max(d,u)}return i+=s(this.props.labels,"width",d),i>0},GroupSet.prototype.hide=function(){return this.dom.frame&&this.dom.frame.parentNode?(this.dom.frame.parentNode.removeChild(this.dom.frame),!0):!1},GroupSet.prototype.show=function(){return this.dom.frame&&this.dom.frame.parentNode?!1:this.repaint()},GroupSet.prototype._onUpdate=function(t){this._toQueue(t,"update")},GroupSet.prototype._onAdd=function(t){this._toQueue(t,"add")},GroupSet.prototype._onRemove=function(t){this._toQueue(t,"remove")},GroupSet.prototype._toQueue=function(t,e){var i=this.queue;t.forEach(function(t){i[t]=e}),this.controller&&this.requestRepaint()},Timeline.prototype.setOptions=function(t){util.extend(this.options,t),this.range.setRange(t.start,t.end),this.controller.reflow(),this.controller.repaint()},Timeline.prototype.setCustomTime=function(t){this.customtime._setCustomTime(t)},Timeline.prototype.getCustomTime=function(){return new Date(this.customtime.customTime.valueOf())},Timeline.prototype.setItems=function(t){var e,i=null==this.itemsData;if(t?t instanceof DataSet&&(e=t):e=null,t instanceof DataSet||(e=new DataSet({convert:{start:"Date",end:"Date"}}),e.add(t)),this.itemsData=e,this.content.setItems(e),i&&(void 0==this.options.start||void 0==this.options.end)){var n=this.getItemRange(),s=n.min,o=n.max;if(null!=s&&null!=o){var r=o.valueOf()-s.valueOf();0>=r&&(r=864e5),s=new Date(s.valueOf()-.05*r),o=new Date(o.valueOf()+.05*r)}void 0!=this.options.start&&(s=util.convert(this.options.start,"Date")),void 0!=this.options.end&&(o=util.convert(this.options.end,"Date")),(null!=s||null!=o)&&this.range.setRange(s,o)}},Timeline.prototype.setGroups=function(t){var e=this;this.groupsData=t;var i=this.groupsData?GroupSet:ItemSet;if(!(this.content instanceof i)){this.content&&(this.content.hide(),this.content.setItems&&this.content.setItems(),this.content.setGroups&&this.content.setGroups(),this.controller.remove(this.content));var n=Object.create(this.options);util.extend(n,{top:function(){return"top"==e.options.orientation?e.timeaxis.height:e.itemPanel.height-e.timeaxis.height-e.content.height},left:null,width:"100%",height:function(){return e.options.height?e.itemPanel.height-e.timeaxis.height:null},maxHeight:function(){if(e.options.maxHeight){if(!util.isNumber(e.options.maxHeight))throw new TypeError("Number expected for property maxHeight");return e.options.maxHeight-e.timeaxis.height}return null},labelContainer:function(){return e.labelPanel.getContainer()}}),this.content=new i(this.itemPanel,[this.timeaxis],n),this.content.setRange&&this.content.setRange(this.range),this.content.setItems&&this.content.setItems(this.itemsData),this.content.setGroups&&this.content.setGroups(this.groupsData),this.controller.add(this.content)}},Timeline.prototype.getItemRange=function(){var t=this.itemsData,e=null,i=null;if(t){var n=t.min("start");e=n?n.start.valueOf():null;var s=t.max("start");s&&(i=s.start.valueOf());var o=t.max("end");o&&(i=null==i?o.end.valueOf():Math.max(i,o.end.valueOf()))}return{min:null!=e?new Date(e):null,max:null!=i?new Date(i):null}},Timeline.prototype.setSelection=function(t){this.content&&this.content.setSelection(t)},Timeline.prototype.getSelection=function(){return this.content?this.content.getSelection():[]},Timeline.prototype.on=function(t,e){var i=["rangechange","rangechanged","select"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());events.addListener(this,t,e)},Timeline.prototype.off=function(t,e){events.removeListener(this,t,e)},Timeline.prototype._trigger=function(t,e){events.trigger(this,t,e||{})},Timeline.prototype._onSelectItem=function(t){var e=this._itemFromTarget(t),i=e?[e.id]:[];this.setSelection(i),this._trigger("select",{items:this.getSelection()}),t.stopPropagation()},Timeline.prototype._onMultiSelectItem=function(t){var e,i=this._itemFromTarget(t);if(i){e=this.getSelection();var n=e.indexOf(i.id);-1==n?e.push(i.id):e.splice(n,1),this.setSelection(e),this._trigger("select",{items:this.getSelection()}),t.stopPropagation()}},Timeline.prototype._itemFromTarget=function(t){for(var e=t.target;e;){if(e.hasOwnProperty("timeline-item"))return e["timeline-item"];e=e.parentNode}return null},function(t){function e(t){return C=t,u()}function i(){M=0,D=C.charAt(0)}function n(){M++,D=C.charAt(M)}function s(){return C.charAt(M+1)}function o(t){return O.test(t)}function r(t,e){if(t||(t={}),e)for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function a(t,e,i){for(var n=e.split("."),s=t;n.length;){var o=n.shift();n.length?(s[o]||(s[o]={}),s=s[o]):s[o]=i}}function h(t,e){for(var i,n,s=null,o=[t],a=t;a.parent;)o.push(a.parent),a=a.parent;if(a.nodes)for(i=0,n=a.nodes.length;n>i;i++)if(e.id===a.nodes[i].id){s=a.nodes[i];break}for(s||(s={id:e.id},t.node&&(s.attr=r(s.attr,t.node))),i=o.length-1;i>=0;i--){var h=o[i];h.nodes||(h.nodes=[]),-1==h.nodes.indexOf(s)&&h.nodes.push(s)}e.attr&&(s.attr=r(s.attr,e.attr))}function l(t,e){if(t.edges||(t.edges=[]),t.edges.push(e),t.edge){var i=r({},t.edge);e.attr=r(i,e.attr)}}function c(t,e,i,n,s){var o={from:e,to:i,type:n};return t.edge&&(o.attr=r({},t.edge)),o.attr=r(o.attr||{},s),o}function d(){for(N=E.NULL,I="";" "==D||" "==D||"\n"==D||"\r"==D;)n();do{var t=!1;if("#"==D){for(var e=M-1;" "==C.charAt(e)||" "==C.charAt(e);)e--;if("\n"==C.charAt(e)||""==C.charAt(e)){for(;""!=D&&"\n"!=D;)n();t=!0}}if("/"==D&&"/"==s()){for(;""!=D&&"\n"!=D;)n();t=!0}if("/"==D&&"*"==s()){for(;""!=D;){if("*"==D&&"/"==s()){n(),n();break}n()}t=!0}for(;" "==D||" "==D||"\n"==D||"\r"==D;)n()}while(t);if(""==D)return void(N=E.DELIMITER);var i=D+s();if(x[i])return N=E.DELIMITER,I=i,n(),void n();if(x[D])return N=E.DELIMITER,I=D,void n();if(o(D)||"-"==D){for(I+=D,n();o(D);)I+=D,n();return"false"==I?I=!1:"true"==I?I=!0:isNaN(Number(I))||(I=Number(I)),void(N=E.IDENTIFIER)}if('"'==D){for(n();""!=D&&('"'!=D||'"'==D&&'"'==s());)I+=D,'"'==D&&n(),n();if('"'!=D)throw b('End of string " expected');return n(),void(N=E.IDENTIFIER)}for(N=E.UNKNOWN;""!=D;)I+=D,n();throw new SyntaxError('Syntax error in part "'+w(I,30)+'"')}function u(){var t={};if(i(),d(),"strict"==I&&(t.strict=!0,d()),("graph"==I||"digraph"==I)&&(t.type=I,d()),N==E.IDENTIFIER&&(t.id=I,d()),"{"!=I)throw b("Angle bracket { expected");if(d(),p(t),"}"!=I)throw b("Angle bracket } expected");if(d(),""!==I)throw b("End of file expected");return d(),delete t.node,delete t.edge,delete t.graph,t}function p(t){for(;""!==I&&"}"!=I;)f(t),";"==I&&d()}function f(t){var e=g(t);if(e)return void y(t,e);var i=m(t);if(!i){if(N!=E.IDENTIFIER)throw b("Identifier expected");var n=I;if(d(),"="==I){if(d(),N!=E.IDENTIFIER)throw b("Identifier expected");t[n]=I,d()}else v(t,n)}}function g(t){var e=null;if("subgraph"==I&&(e={},e.type="subgraph",d(),N==E.IDENTIFIER&&(e.id=I,d())),"{"==I){if(d(),e||(e={}),e.parent=t,e.node=t.node,e.edge=t.edge,e.graph=t.graph,p(e),"}"!=I)throw b("Angle bracket } expected");d(),delete e.node,delete e.edge,delete e.graph,delete e.parent,t.subgraphs||(t.subgraphs=[]),t.subgraphs.push(e)}return e}function m(t){return"node"==I?(d(),t.node=_(),"node"):"edge"==I?(d(),t.edge=_(),"edge"):"graph"==I?(d(),t.graph=_(),"graph"):null}function v(t,e){var i={id:e},n=_();n&&(i.attr=n),h(t,i),y(t,e)}function y(t,e){for(;"->"==I||"--"==I;){var i,n=I;d();var s=g(t);if(s)i=s;else{if(N!=E.IDENTIFIER)throw b("Identifier or subgraph expected");i=I,h(t,{id:i}),d()}var o=_(),r=c(t,e,i,n,o);l(t,r),e=i}}function _(){for(var t=null;"["==I;){for(d(),t={};""!==I&&"]"!=I;){if(N!=E.IDENTIFIER)throw b("Attribute name expected");var e=I;if(d(),"="!=I)throw b("Equal sign = expected");if(d(),N!=E.IDENTIFIER)throw b("Attribute value expected");var i=I;a(t,e,i),d(),","==I&&d()}if("]"!=I)throw b("Bracket ] expected");d()}return t}function b(t){return new SyntaxError(t+', got "'+w(I,30)+'" (char '+M+")")}function w(t,e){return t.length<=e?t:t.substr(0,27)+"..."}function S(t,e,i){t instanceof Array?t.forEach(function(t){e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}):e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}function T(t){function i(t){var e={from:t.from,to:t.to};return r(e,t.attr),e.style="->"==t.type?"arrow":"line",e}var n=e(t),s={nodes:[],edges:[],options:{}};return n.nodes&&n.nodes.forEach(function(t){var e={id:t.id,label:String(t.label||t.id)};r(e,t.attr),e.image&&(e.shape="image"),s.nodes.push(e)}),n.edges&&n.edges.forEach(function(t){var e,n;e=t.from instanceof Object?t.from.nodes:{id:t.from},n=t.to instanceof Object?t.to.nodes:{id:t.to},t.from instanceof Object&&t.from.edges&&t.from.edges.forEach(function(t){var e=i(t);s.edges.push(e)}),S(e,n,function(e,n){var o=c(s,e.id,n.id,t.type,t.attr),r=i(o);s.edges.push(r)}),t.to instanceof Object&&t.to.edges&&t.to.edges.forEach(function(t){var e=i(t);s.edges.push(e)})}),n.attr&&(s.options=n.attr),s}var E={NULL:0,DELIMITER:1,IDENTIFIER:2,UNKNOWN:3},x={"{":!0,"}":!0,"[":!0,"]":!0,";":!0,"=":!0,",":!0,"->":!0,"--":!0},C="",M=0,D="",I="",N=E.NULL,O=/[a-zA-Z_0-9.:#]/;t.parseDOT=e,t.DOTToGraph=T}("undefined"!=typeof util?util:exports),"undefined"!=typeof CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.circle=function(t,e,i){this.beginPath(),this.arc(t,e,i,0,2*Math.PI,!1)},CanvasRenderingContext2D.prototype.square=function(t,e,i){this.beginPath(),this.rect(t-i,e-i,2*i,2*i)},CanvasRenderingContext2D.prototype.triangle=function(t,e,i){this.beginPath();var n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e-(r-o)),this.lineTo(t+s,e+o),this.lineTo(t-s,e+o),this.lineTo(t,e-(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.triangleDown=function(t,e,i){this.beginPath();var n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e+(r-o)),this.lineTo(t+s,e-o),this.lineTo(t-s,e-o),this.lineTo(t,e+(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.star=function(t,e,i){this.beginPath();for(var n=0;10>n;n++){var s=n%2===0?1.3*i:.5*i;this.lineTo(t+s*Math.sin(2*n*Math.PI/10),e-s*Math.cos(2*n*Math.PI/10))}this.closePath()},CanvasRenderingContext2D.prototype.roundRect=function(t,e,i,n,s){var o=Math.PI/180;0>i-2*s&&(s=i/2),0>n-2*s&&(s=n/2),this.beginPath(),this.moveTo(t+s,e),this.lineTo(t+i-s,e),this.arc(t+i-s,e+s,s,270*o,360*o,!1),this.lineTo(t+i,e+n-s),this.arc(t+i-s,e+n-s,s,0,90*o,!1),this.lineTo(t+s,e+n),this.arc(t+s,e+n-s,s,90*o,180*o,!1),this.lineTo(t,e+s),this.arc(t+s,e+s,s,180*o,270*o,!1)},CanvasRenderingContext2D.prototype.ellipse=function(t,e,i,n){var s=.5522848,o=i/2*s,r=n/2*s,a=t+i,h=e+n,l=t+i/2,c=e+n/2;this.beginPath(),this.moveTo(t,c),this.bezierCurveTo(t,c-r,l-o,e,l,e),this.bezierCurveTo(l+o,e,a,c-r,a,c),this.bezierCurveTo(a,c+r,l+o,h,l,h),this.bezierCurveTo(l-o,h,t,c+r,t,c)},CanvasRenderingContext2D.prototype.database=function(t,e,i,n){var s=1/3,o=i,r=n*s,a=.5522848,h=o/2*a,l=r/2*a,c=t+o,d=e+r,u=t+o/2,p=e+r/2,f=e+(n-r/2),g=e+n; +this.beginPath(),this.moveTo(c,p),this.bezierCurveTo(c,p+l,u+h,d,u,d),this.bezierCurveTo(u-h,d,t,p+l,t,p),this.bezierCurveTo(t,p-l,u-h,e,u,e),this.bezierCurveTo(u+h,e,c,p-l,c,p),this.lineTo(c,f),this.bezierCurveTo(c,f+l,u+h,g,u,g),this.bezierCurveTo(u-h,g,t,f+l,t,f),this.lineTo(t,p)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,n){var s=t-n*Math.cos(i),o=e-n*Math.sin(i),r=t-.9*n*Math.cos(i),a=e-.9*n*Math.sin(i),h=s+n/3*Math.cos(i+.5*Math.PI),l=o+n/3*Math.sin(i+.5*Math.PI),c=s+n/3*Math.cos(i-.5*Math.PI),d=o+n/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,l),this.lineTo(r,a),this.lineTo(c,d),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,n,s){s||(s=[10,5]),0==u&&(u=.001);var o=s.length;this.moveTo(t,e);for(var r=i-t,a=n-e,h=a/r,l=Math.sqrt(r*r+a*a),c=0,d=!0;l>=.1;){var u=s[c++%o];u>l&&(u=l);var p=Math.sqrt(u*u/(1+h*h));0>r&&(p=-p),t+=p,e+=h*p,this[d?"lineTo":"moveTo"](t,e),l-=u,d=!d}}),Node.prototype.resetCluster=function(){this.formationScale=void 0,this.clusterSize=1,this.containedNodes={},this.containedEdges={},this.clusterSessions=[]},Node.prototype.attachEdge=function(t){-1==this.edges.indexOf(t)&&this.edges.push(t),-1==this.dynamicEdges.indexOf(t)&&this.dynamicEdges.push(t),this.dynamicEdgesLength=this.dynamicEdges.length,this._updateMass()},Node.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&(this.edges.splice(e,1),this.dynamicEdges.splice(e,1)),this.dynamicEdgesLength=this.dynamicEdges.length,this._updateMass()},Node.prototype._updateMass=function(){this.mass=1},Node.prototype.setProperties=function(t,e){if(t){if(this.originalLabel=void 0,void 0!==t.id&&(this.id=t.id),void 0!==t.label&&(this.label=t.label,this.originalLabel=t.label),void 0!==t.title&&(this.title=t.title),void 0!==t.group&&(this.group=t.group),void 0!==t.x&&(this.x=t.x),void 0!==t.y&&(this.y=t.y),void 0!==t.value&&(this.value=t.value),void 0!==t.horizontalAlignLeft&&(this.horizontalAlignLeft=t.horizontalAlignLeft),void 0!==t.verticalAlignTop&&(this.verticalAlignTop=t.verticalAlignTop),void 0!==t.triggerFunction&&(this.triggerFunction=t.triggerFunction),void 0===this.id)throw"Node must have an id";if(this.group){var i=this.grouplist.get(this.group);for(var n in i)i.hasOwnProperty(n)&&(this[n]=i[n])}if(void 0!==t.shape&&(this.shape=t.shape),void 0!==t.image&&(this.image=t.image),void 0!==t.radius&&(this.radius=t.radius),void 0!==t.color&&(this.color=Node.parseColor(t.color)),void 0!==t.fontColor&&(this.fontColor=t.fontColor),void 0!==t.fontSize&&(this.fontSize=t.fontSize),void 0!==t.fontFace&&(this.fontFace=t.fontFace),void 0!==this.image){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.image)}switch(this.xFixed=this.xFixed||void 0!==t.x&&t.fixed,this.yFixed=this.yFixed||void 0!==t.y&&t.fixed,this.radiusFixed=this.radiusFixed||void 0!==t.radius,"image"==this.shape&&(this.radiusMin=e.nodes.widthMin,this.radiusMax=e.nodes.widthMax),this.shape){case"database":this.draw=this._drawDatabase,this.resize=this._resizeDatabase;break;case"box":this.draw=this._drawBox,this.resize=this._resizeBox;break;case"circle":this.draw=this._drawCircle,this.resize=this._resizeCircle;break;case"ellipse":this.draw=this._drawEllipse,this.resize=this._resizeEllipse;break;case"image":this.draw=this._drawImage,this.resize=this._resizeImage;break;case"text":this.draw=this._drawText,this.resize=this._resizeText;break;case"dot":this.draw=this._drawDot,this.resize=this._resizeShape;break;case"square":this.draw=this._drawSquare,this.resize=this._resizeShape;break;case"triangle":this.draw=this._drawTriangle,this.resize=this._resizeShape;break;case"triangleDown":this.draw=this._drawTriangleDown,this.resize=this._resizeShape;break;case"star":this.draw=this._drawStar,this.resize=this._resizeShape;break;default:this.draw=this._drawEllipse,this.resize=this._resizeEllipse}this._reset()}},Node.parseColor=function(t){var e;return util.isString(t)?e={border:t,background:t,highlight:{border:t,background:t}}:(e={},e.background=t.background||"white",e.border=t.border||e.background,util.isString(t.highlight)?e.highlight={border:t.highlight,background:t.highlight}:(e.highlight={},e.highlight.background=t.highlight&&t.highlight.background||e.background,e.highlight.border=t.highlight&&t.highlight.border||e.border)),e},Node.prototype.select=function(){this.selected=!0,this._reset()},Node.prototype.unselect=function(){this.selected=!1,this._reset()},Node.prototype.clearSizeCache=function(){this._reset()},Node.prototype._reset=function(){this.width=void 0,this.height=void 0},Node.prototype.getTitle=function(){return this.title},Node.prototype.distanceToBorder=function(t,e){var i=1;switch(this.width||this.resize(t),this.shape){case"circle":case"dot":return this.radius+i;case"ellipse":var n=this.width/2,s=this.height/2,o=Math.sin(e)*n,r=Math.cos(e)*s;return n*s/Math.sqrt(o*o+r*r);case"box":case"image":case"text":default:return this.width?Math.min(Math.abs(this.width/2/Math.cos(e)),Math.abs(this.height/2/Math.sin(e)))+i:0}},Node.prototype._setForce=function(t,e){this.fx=t,this.fy=e},Node.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},Node.prototype.discreteStep=function(t){if(!this.xFixed){var e=-this.damping*this.vx,i=(this.fx+e)/this.mass;this.vx+=i*t,this.x+=this.vx*t}if(!this.yFixed){var n=-this.damping*this.vy,s=(this.fy+n)/this.mass;this.vy+=s*t,this.y+=this.vy*t}},Node.prototype.isFixed=function(){return this.xFixed&&this.yFixed},Node.prototype.isMoving=function(t){return Math.abs(this.vx)>t||Math.abs(this.vy)>t?!0:(this.vx=0,this.vy=0,!1)},Node.prototype.isSelected=function(){return this.selected},Node.prototype.getValue=function(){return this.value},Node.prototype.getDistance=function(t,e){var i=this.x-t,n=this.y-e;return Math.sqrt(i*i+n*n)},Node.prototype.setValueRange=function(t,e){if(!this.radiusFixed&&void 0!==this.value)if(e==t)this.radius=(this.radiusMin+this.radiusMax)/2;else{var i=(this.radiusMax-this.radiusMin)/(e-t);this.radius=(this.value-t)*i+this.radiusMin}this.baseRadiusValue=this.radius},Node.prototype.draw=function(){throw"Draw method not initialized for node"},Node.prototype.resize=function(){throw"Resize method not initialized for node"},Node.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},Node.prototype._resizeImage=function(){if(!this.width||!this.height){var t,e;if(this.value){this.radius=this.baseRadiusValue;var i=this.imageObj.height/this.imageObj.width;void 0!==i?(t=this.radius||this.imageObj.width,e=this.radius*i||this.imageObj.height):(t=0,e=0)}else t=this.imageObj.width,e=this.imageObj.height;this.width=t,this.height=e,this.width>0&&this.height>0&&(this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor)}},Node.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e;if(0!=this.imageObj.width){if(this.clusterSize>1){var i=this.clusterSize>1?10:0;i*=this.graphScaleInv,i=Math.min(.2*this.width,i),t.globalAlpha=.5,t.drawImage(this.imageObj,this.left-i,this.top-i,this.width+2*i,this.height+2*i)}t.globalAlpha=1,t.drawImage(this.imageObj,this.left,this.top,this.width,this.height),e=this.y+this.height/2}else e=this.y;this._label(t,this.label,this.x,e,void 0,"top")},Node.prototype._resizeBox=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=.5*(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=.5*(this.clusterSize-1)*this.clusterSizeHeightFactor}},Node.prototype._drawBox=function(t){this._resizeBox(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.roundRect(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth,this.radius),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.roundRect(this.left,this.top,this.width,this.height,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.prototype._resizeDatabase=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=i.width+2*e;this.width=n,this.height=n,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor}},Node.prototype._drawDatabase=function(t){this._resizeDatabase(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.database(this.x-this.width/2-2*t.lineWidth,this.y-.5*this.height-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.database(this.x-this.width/2,this.y-.5*this.height,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=Math.max(i.width,i.height)+2*e;this.radius=n/2,this.width=n,this.height=n,this.radius+=.5*(this.clusterSize-1)*this.clusterSizeRadiusFactor}},Node.prototype._drawCircle=function(){},Node.prototype._resizeEllipse=function(t){if(!this.width){var e=this.getTextSize(t);this.width=1.5*e.width,this.height=2*e.height,this.width1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.ellipse(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.ellipse(this.left,this.top,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.prototype._drawDot=function(t){this._drawShape(t,"circle")},Node.prototype._drawTriangle=function(t){this._drawShape(t,"triangle")},Node.prototype._drawTriangleDown=function(t){this._drawShape(t,"triangleDown")},Node.prototype._drawSquare=function(t){this._drawShape(t,"square")},Node.prototype._drawStar=function(t){this._drawShape(t,"star")},Node.prototype._resizeShape=function(){if(!this.width){this.radius=this.baseRadiusValue;var t=2*this.radius;this.width=t,this.height=t,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=.5*(this.clusterSize-1)*this.clusterSizeRadiusFactor}},Node.prototype._drawShape=function(t,e){this._resizeShape(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var i=2.5,n=2,s=2;switch(e){case"dot":s=2;break;case"square":s=2;break;case"triangle":s=3;break;case"triangleDown":s=3;break;case"star":s=4}t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?n:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t[e](this.x,this.y,this.radius+s*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?n:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t[e](this.x,this.y,this.radius),t.fill(),t.stroke(),this.label&&this._label(t,this.label,this.x,this.y+this.height/2,void 0,"top")},Node.prototype._resizeText=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor}},Node.prototype._drawText=function(t){this._resizeText(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,this._label(t,this.label,this.x,this.y)},Node.prototype._label=function(t,e,i,n,s,o){if(e){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle=this.fontColor||"black",t.textAlign=s||"center",t.textBaseline=o||"middle";for(var r=e.split("\n"),a=r.length,h=this.fontSize+4,l=n+(1-a)/2*h,c=0;a>c;c++)t.fillText(r[c],i,l),l+=h}},Node.prototype.getTextSize=function(t){if(void 0!==this.label){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace;for(var e=this.label.split("\n"),i=(this.fontSize+4)*e.length,n=0,s=0,o=e.length;o>s;s++)n=Math.max(n,t.measureText(e[s]).width);return{width:n,height:i}}return{width:0,height:0}},Node.prototype.inArea=function(){return void 0!==this.width?this.x+this.width*this.graphScaleInv>=this.canvasTopLeft.x&&this.x-this.width*this.graphScaleInv=this.canvasTopLeft.y&&this.y-this.height*this.graphScaleInv=this.canvasTopLeft.x&&this.x=this.canvasTopLeft.y&&this.yh},Edge.prototype._drawLine=function(t){t.strokeStyle=this.color,t.lineWidth=this._getLineWidth();var e;if(this.from!=this.to)this._line(t),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y));else{var i,n,s=this.length/4,o=this.from;o.width||o.resize(t),o.width>o.height?(i=o.x+o.width/2,n=o.y-s):(i=o.x+s,n=o.y-o.height/2),this._circle(t,i,n,s),e=this._pointOnCircle(i,n,s,.5),this._label(t,this.label,e.x,e.y)}},Edge.prototype._getLineWidth=function(){return 1==this.selected?Math.min(2*this.width,this.widthMax)*this.graphScaleInv:this.width*this.graphScaleInv},Edge.prototype._line=function(t){t.beginPath(),t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y),t.stroke()},Edge.prototype._circle=function(t,e,i,n){t.beginPath(),t.arc(e,i,n,0,2*Math.PI,!1),t.stroke()},Edge.prototype._label=function(t,e,i,n){if(e){t.font=(this.from.selected||this.to.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle="white";var s=t.measureText(e).width,o=this.fontSize,r=i-s/2,a=n-o/2;t.fillRect(r,a,s,o),t.fillStyle=this.fontColor||"black",t.textAlign="left",t.textBaseline="top",t.fillText(e,r,a)}},Edge.prototype._drawDashLine=function(t){if(t.strokeStyle=this.color,t.lineWidth=this._getLineWidth(),t.beginPath(),t.lineCap="round",void 0!==this.dash.altLength?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]):void 0!==this.dash.length&&void 0!==this.dash.gap?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap]):(t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y)),t.stroke(),this.label){var e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}},Edge.prototype._pointOnLine=function(t){return{x:(1-t)*this.from.x+t*this.to.x,y:(1-t)*this.from.y+t*this.to.y}},Edge.prototype._pointOnCircle=function(t,e,i,n){var s=2*(n-3/8)*Math.PI;return{x:t+i*Math.cos(s),y:e-i*Math.sin(s)}},Edge.prototype._drawArrowCenter=function(t){var e;if(t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth(),this.from!=this.to){this._line(t);var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),n=10+5*this.width;e=this._pointOnLine(.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y))}else{var s,o,r=this.length/4,a=this.from;a.width||a.resize(t),a.width>a.height?(s=a.x+a.width/2,o=a.y-r):(s=a.x+r,o=a.y-a.height/2),this._circle(t,s,o,r);var i=.2*Math.PI,n=10+5*this.width;e=this._pointOnCircle(s,o,r,.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(s,o,r,.5),this._label(t,this.label,e.x,e.y))}},Edge.prototype._drawArrow=function(t){t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth();var e,i;if(this.from!=this.to){e=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x);var n=this.to.x-this.from.x,s=this.to.y-this.from.y,o=Math.sqrt(n*n+s*s),r=this.from.distanceToBorder(t,e+Math.PI),a=(o-r)/o,h=a*this.from.x+(1-a)*this.to.x,l=a*this.from.y+(1-a)*this.to.y,c=this.to.distanceToBorder(t,e),d=(o-c)/o,u=(1-d)*this.from.x+d*this.to.x,p=(1-d)*this.from.y+d*this.to.y;if(t.beginPath(),t.moveTo(h,l),t.lineTo(u,p),t.stroke(),i=10+5*this.width,t.arrow(u,p,e,i),t.fill(),t.stroke(),this.label){var f=this._pointOnLine(.5);this._label(t,this.label,f.x,f.y)}}else{var g,m,v,y=this.from,_=this.length/4;y.width||y.resize(t),y.width>y.height?(g=y.x+y.width/2,m=y.y-_,v={x:g,y:y.y,angle:.9*Math.PI}):(g=y.x+_,m=y.y-y.height/2,v={x:y.x,y:m,angle:.6*Math.PI}),t.beginPath(),t.arc(g,m,_,0,2*Math.PI,!1),t.stroke(),i=10+5*this.width,t.arrow(v.x,v.y,v.angle,i),t.fill(),t.stroke(),this.label&&(f=this._pointOnCircle(g,m,_,.5),this._label(t,this.label,f.x,f.y))}},Edge._dist=function(t,e,i,n,s,o){var r=i-t,a=n-e,h=r*r+a*a,l=((s-t)*r+(o-e)*a)/h;l>1?l=1:0>l&&(l=0);var c=t+l*r,d=e+l*a,u=c-s,p=d-o;return Math.sqrt(u*u+p*p)},Edge.prototype.setScale=function(t){this.graphScaleInv=1/t},Edge.prototype.select=function(){this.selected=!0},Edge.prototype.unselect=function(){this.selected=!1},Popup.prototype.setPosition=function(t,e){this.x=parseInt(t),this.y=parseInt(e)},Popup.prototype.setText=function(t){this.frame.innerHTML=t},Popup.prototype.show=function(t){if(void 0===t&&(t=!0),t){var e=this.frame.clientHeight,i=this.frame.clientWidth,n=this.frame.parentNode.clientHeight,s=this.frame.parentNode.clientWidth,o=this.y-e;o+e+this.padding>n&&(o=n-e-this.padding),os&&(r=s-i-this.padding),rthis.constants.clustering.clusterThreshold&&1==this.constants.clustering.enabled&&this.clusterToFit(this.constants.clustering.reduceToNodes,!1),this._calculateForcesBarnesHut())},_calculateForcesOriginal:function(){var t=Date.now();this._calculateGravitationalForces(1);var e=Date.now();this._calculateRepulsionForces();var i=Date.now(),n=Date.now();echo("Time repulsion part:",i-e),echo("Time total force calc:",n-t)},_calculateForcesBarnesHut:function(){var t=Date.now();this._clearForces();var e=Date.now();this._calculateBarnesHutForces();var i=Date.now();this._calculateSpringForces(1);var n=Date.now();echo("Time repulsion part:",i-e),echo("Time total force calc:",n-t)},_clearForces:function(){for(var t,e=this.nodes,i=0;in&&(i=Math.atan2(e,t),a=.5*g>n?1:m*n+f,a*=0==r?1:1+r*this.constants.clustering.forceAmplification,s=Math.cos(i)*a,o=Math.sin(i)*a,h._addForce(-s,-o),l._addForce(s,o))}},_calculateSpringForces:function(t){var e,i,n,s,o,r,a,h,l,c,d,u=this.edges;for(c in u)u.hasOwnProperty(c)&&(l=u[c],l.connected&&this.nodes.hasOwnProperty(l.toId)&&this.nodes.hasOwnProperty(l.fromId)&&(d=l.to.clusterSize+l.from.clusterSize-2,e=l.to.x-l.from.x,i=l.to.y-l.from.y,h=l.length,h+=d*this.constants.clustering.edgeGrowth,a=Math.sqrt(e*e+i*i),n=Math.atan2(i,e),r=l.stiffness*(h-a)*t,s=Math.cos(n)*r,o=Math.sin(n)*r,l.from._addForce(-s,-o),l.to._addForce(s,o)))},_calculateBarnesHutForces:function(){this._formBarnesHutTree();var t,e=this.nodes,i=this.nodeIndices,n=i.length,s=this.barnesHutTree;this.maxAllowedForce=100,this.theta=.8,this.graviationalConstant=-1e4;for(var o=0;n>o;o++)t=e[i[o]],this._getForceContribution(s.root.children.NW,t),this._getForceContribution(s.root.children.NE,t),this._getForceContribution(s.root.children.SW,t),this._getForceContribution(s.root.children.SE,t);for(o=0;n>o;o++)t=e[i[o]],t.fx=Math.abs(t.fx)>this.maxAllowedForce?t.fx<0?-this.maxAllowedForce:this.maxAllowedForce:t.fx,t.fy=Math.abs(t.fy)>this.maxAllowedForce?t.fy<0?-this.maxAllowedForce:this.maxAllowedForce:t.fy},_getForceContribution:function(t,e){if(t.childrenCount>0){var i,n,s;if(i=t.CenterOfMass.x-e.x,n=t.CenterOfMass.y-e.y,s=Math.sqrt(i*i+n*n),s>0){var o=1/s;t.size*o>this.theta?4==t.childrenCount?(this._getForceContribution(t.children.NW,e),this._getForceContribution(t.children.NE,e),this._getForceContribution(t.children.SW,e),this._getForceContribution(t.children.SE,e)):this._getForceOnNode(t,e,i,n,o):this._getForceOnNode(t,e,i,n,o)}}},_getForceOnNode:function(t,e,i,n,s){var o=this.graviationalConstant*t.mass*e.mass*s*s,r=Math.atan2(n,i),a=Math.cos(r)*o,h=Math.sin(r)*o;e._addForce(a,h)},_formBarnesHutTree:function(){for(var t,e=this.nodes,i=this.nodeIndices,n=i.length,s=Number.MAX_VALUE,o=Number.MAX_VALUE,r=-Number.MAX_VALUE,a=-Number.MAX_VALUE,h=0;n>h;h++){var l=e[i[h]].x,c=e[i[h]].y;s>l&&(s=l),l>r&&(r=l),o>c&&(o=c),c>a&&(a=c)}var d=Math.abs(r-s)-Math.abs(a-o);d>0?(o-=.5*d,a+=.5*d):(s+=.5*d,a-=.5*d);var u={root:{CenterOfMass:{x:0,y:0},mass:0,range:{minX:s,maxX:r,minY:o,maxY:a},size:Math.abs(r-s),children:{data:null},childrenCount:4}};for(this._splitBranch(u.root),h=0;n>h;h++)t=e[i[h]],this._placeInTree(u.root,t);this.barnesHutTree=u},_updateBranchMass:function(t,e){var i=t.mass+e.mass,n=1/i;t.CenterOfMass.x=t.CenterOfMass.x*t.mass+e.x*e.mass,t.CenterOfMass.x*=n,t.CenterOfMass.y=t.CenterOfMass.y*t.mass+e.y*e.mass,t.CenterOfMass.y*=n,t.mass=i},_placeInTree:function(t,e){this._updateBranchMass(t,e),t.children.NW.range.maxX>e.x?t.children.NW.range.maxY>e.y?this._placeInRegion(t,e,"NW"):this._placeInRegion(t,e,"SW"):t.children.NE.range.maxY>e.y?this._placeInRegion(t,e,"NE"):this._placeInRegion(t,e,"SE")},_placeInRegion:function(t,e,i){switch(t.children[i].childrenCount){case 0:t.children[i].children.data=e,t.children[i].childrenCount=1,this._updateBranchMass(t.children[i],e);break;case 1:this._splitBranch(t.children[i]),this._placeInTree(t.children[i],e);break;case 4:this._placeInTree(t.children[i],e)}},_splitBranch:function(t){var e=null;1==t.childrenCount&&(e=t.children.data,t.mass=0,t.CenterOfMass.x=0,t.CenterOfMass.y=0),t.childrenCount=4,t.children.data=null,this._insertRegion(t,"NW"),this._insertRegion(t,"NE"),this._insertRegion(t,"SW"),this._insertRegion(t,"SE"),null!=e&&this._placeInTree(t,e)},_insertRegion:function(t,e){var i,n,s,o;switch(e){case"NW":i=t.range.minX,n=t.range.minX+t.size,s=t.range.minY,o=t.range.minY+t.size;break;case"NE":i=t.range.minX+t.size,n=t.range.maxX,s=t.range.minY,o=t.range.minY+t.size;break;case"SW":i=t.range.minX,n=t.range.minX+t.size,s=t.range.minY+t.size,o=t.range.maxY;break;case"SE":i=t.range.minX+t.size,n=t.range.maxX,s=t.range.minY+t.size,o=t.range.maxY}t.children[e]={CenterOfMass:{x:0,y:0},mass:0,range:{minX:i,maxX:n,minY:s,maxY:o},size:.5*t.size,children:{data:null},childrenCount:0}},_drawTree:function(t,e){void 0!==this.barnesHutTree&&(t.lineWidth=2,this._drawBranch(this.barnesHutTree.root,t,e))},_drawBranch:function(t,e,i){void 0===i&&(i="#FF0000"),4==t.childrenCount&&(this._drawBranch(t.children.NW,e),this._drawBranch(t.children.NE,e),this._drawBranch(t.children.SE,e),this._drawBranch(t.children.SW,e)),e.strokeStyle=i,e.beginPath(),e.moveTo(t.range.minX,t.range.minY),e.lineTo(t.range.maxX,t.range.minY),e.stroke(),e.beginPath(),e.moveTo(t.range.maxX,t.range.minY),e.lineTo(t.range.maxX,t.range.maxY),e.stroke(),e.beginPath(),e.moveTo(t.range.maxX,t.range.maxY),e.lineTo(t.range.minX,t.range.maxY),e.stroke(),e.beginPath(),e.moveTo(t.range.minX,t.range.maxY),e.lineTo(t.range.minX,t.range.minY),e.stroke()}},manipulationMixin={_clearManipulatorBar:function(){for(;this.manipulationDiv.hasChildNodes();)this.manipulationDiv.removeChild(this.manipulationDiv.firstChild)},_createManipulatorBar:function(){for(this.off("select",this.boundFunction),this.blockConnectingEdgeSelection=!1,this.forceAppendSelection=!1;this.manipulationDiv.hasChildNodes();)this.manipulationDiv.removeChild(this.manipulationDiv.firstChild);this.manipulationDiv.innerHTML="Add Node
    Edit Selected
    Connect Node
    Delete selected";var t=document.getElementById("manipulate-addNode");t.onclick=this._createAddToolbar.bind(this);var e=document.getElementById("manipulate-editNode");e.onclick=this._createEditToolbar.bind(this);var i=document.getElementById("manipulate-connectNode");i.onclick=this._createConnectToolbar.bind(this);var n=document.getElementById("manipulate-delete");n.onclick=this._createDeletionToolbar.bind(this)},_createAddToolbar:function(){this._clearManipulatorBar(),this.off("select",this.boundFunction),this.manipulationDiv.innerHTML="Back
    Click in an empty space to place a new node";var t=document.getElementById("manipulate-back"); +t.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._addNode.bind(this),this.on("select",this.boundFunction)},_createEditToolbar:function(){this.blockConnectingEdgeSelection=!1,this._clearManipulatorBar(),this.off("select",this.boundFunction);var t="";if(this._selectionIsEmpty()?t="Select a node or edge to edit.":this._getSelectedObjectCount()>1?(t="Select a single node or edge to edit.",this._unselectAll(!0)):this._clusterInSelection()?(t="You cannot edit a cluster.",this._unselectAll(!0)):this._getSelectedNodeCount()>0?this._createEditNodeToolbar():this._createEditEdgeToolbar(),""!=t){this.blockConnectingEdgeSelection=!0,this.manipulationDiv.innerHTML="Back
    "+t+"";var e=document.getElementById("manipulate-back");e.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._createEditToolbar.bind(this),this.on("select",this.boundFunction)}},_createEditNodeToolbar:function(){this.blockConnectingEdgeSelection=!1,this._clearManipulatorBar(),this.off("select",this.boundFunction);var t=this._getEditObject();this.manipulationDiv.innerHTML="Cancel
    label:
    color:
    ";var e=document.getElementById("manipulate-back");e.onclick=this._createManipulatorBar.bind(this);var i=document.getElementById("manipulator-obj-save");i.onclick=this._saveNodeData.bind(this),this.boundFunction=this._createManipulatorBar.bind(this),this.on("select",this.boundFunction)},_saveNodeData:function(){var t=this._getEditObject().id,e=document.getElementById("manipulator-obj-label").value,i=document.getElementById("manipulator-obj-color").value,n=util.hexToHSV(i),s={h:n.h,s:.45*n.s,v:Math.min(1,1.05*n.v)},o={h:n.h,s:Math.min(1,1.25*n.v),v:.6*n.v},r=util.HSVToHex(o.h,o.h,o.v),a=util.HSVToHex(s.h,s.s,s.v),h={id:t,label:e,color:{background:i,border:r,highlight:{background:a,border:r}}};this.nodesData.update(h),this._createManipulatorBar()},_createEditEdgeToolbar:function(){this.blockConnectingEdgeSelection=!1,this._clearManipulatorBar(),this.off("select",this.boundFunction),this.manipulationDiv.innerHTML="Back
    Currently only nodes can be edited.";var t=document.getElementById("manipulate-back");t.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._createManipulatorBar.bind(this),this.on("select",this.boundFunction)},_createConnectToolbar:function(){this._clearManipulatorBar(),this.off("select",this.boundFunction),this._unselectAll(),this.forceAppendSelection=!1,this.blockConnectingEdgeSelection=!0,this.manipulationDiv.innerHTML="Back
    Select the node you want to connect to other nodes.";var t=document.getElementById("manipulate-back");t.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._handleConnect.bind(this),this.on("select",this.boundFunction)},_createDeletionToolbar:function(){if(this._clearManipulatorBar(),this.off("select",this.boundFunction),this._selectionIsEmpty()){this.manipulationDiv.innerHTML="Cannot delete an empty selection.";var t=this;window.setTimeout(function(){t._createManipulatorBar()},1500)}else{this.manipulationDiv.innerHTML="Back
    Are you sure? This cannot be undone.
    Yes.";var e=document.getElementById("manipulate-back");e.onclick=this._createManipulatorBar.bind(this);var i=document.getElementById("manipulate-acceptDelete");i.onclick=this._deleteSelected.bind(this),this.boundFunction=this._createManipulatorBar.bind(this),this.on("select",this.boundFunction)}},_handleConnect:function(){this.forceAppendSelection=!1,this._clusterInSelection()?(this._unselectClusters(!0),this._selectionIsEmpty()?this._setManipulationMessage("You cannot connect anything to a cluster."):(this._setManipulationMessage("You cannot connect a node to a cluster."),this.forceAppendSelection=!0)):this._selectionIsEmpty()?this._setManipulationMessage("Select the node you want to connect to other nodes."):2==this._getSelectedNodeCount()?(this._connectNodes(),this._restoreSourceNode(),this._setManipulationMessage("Click on another node you want to connect this node to or go back.")):(this._setManipulationMessage("Click on the node you want to connect this node."),this._setSourceNode(),this.forceAppendSelection=!0)},_getEditObject:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t))return this.selectionObj[t];return null},_setSourceNode:function(){for(var t in this.selectionObj)this.selectionObj.hasOwnProperty(t)&&this.selectionObj[t]instanceof Node&&(this.manipulationSourceNode=this.selectionObj[t])},_getTargetNode:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t)&&this.selectionObj[t]instanceof Node&&this.manipulationSourceNode.id!=this.selectionObj[t].id)return this.selectionObj[t];return null},_restoreSourceNode:function(){this._unselectAll(!0),this._selectObject(this.manipulationSourceNode)},_setManipulationMessage:function(t){var e=document.getElementById("manipulatorLabel");e.innerHTML=t},_addNode:function(){if(this._selectionIsEmpty()){var t=this._pointerToPositionObject(this.pointerPosition);this.createNodeOnClick=!0,this.nodesData.add({id:util.randomUUID(),x:t.left,y:t.top,label:"new",fixed:!1}),this.createNodeOnClick=!1,this.moving=!0,this.start()}},_connectNodes:function(){var t=this._getTargetNode(),e=this.manipulationSourceNode;this.edgesData.add({from:e.id,to:t.id}),this.moving=!0,this.start()},_deleteSelected:function(){if(this._clusterInSelection())alert("Clusters cannot be deleted.");else{var t=this.getSelectedNodes(),e=this.getSelectedEdges();this._removeEdges(e),this._removeNodes(t),this.moving=!0,this.start()}}},SectorMixin={_putDataInSector:function(){this.sectors.active[this._sector()].nodes=this.nodes,this.sectors.active[this._sector()].edges=this.edges,this.sectors.active[this._sector()].nodeIndices=this.nodeIndices},_switchToSector:function(t,e){void 0===e||"active"==e?this._switchToActiveSector(t):this._switchToFrozenSector(t)},_switchToActiveSector:function(t){this.nodeIndices=this.sectors.active[t].nodeIndices,this.nodes=this.sectors.active[t].nodes,this.edges=this.sectors.active[t].edges},_switchToFrozenSector:function(t){this.nodeIndices=this.sectors.frozen[t].nodeIndices,this.nodes=this.sectors.frozen[t].nodes,this.edges=this.sectors.frozen[t].edges},_switchToNavigationSector:function(){this.nodeIndices=this.sectors.navigation.nodeIndices,this.nodes=this.sectors.navigation.nodes,this.edges=this.sectors.navigation.edges},_loadLatestSector:function(){this._switchToSector(this._sector())},_sector:function(){return this.activeSector[this.activeSector.length-1]},_previousSector:function(){if(this.activeSector.length>1)return this.activeSector[this.activeSector.length-2];throw new TypeError("there are not enough sectors in the this.activeSector array.")},_setActiveSector:function(t){this.activeSector.push(t)},_forgetLastSector:function(){this.activeSector.pop()},_createNewSector:function(t){this.sectors.active[t]={nodes:{},edges:{},nodeIndices:[],formationScale:this.scale,drawingNode:void 0},this.sectors.active[t].drawingNode=new Node({id:t,color:{background:"#eaefef",border:"495c5e"}},{},{},this.constants),this.sectors.active[t].drawingNode.clusterSize=2},_deleteActiveSector:function(t){delete this.sectors.active[t]},_deleteFrozenSector:function(t){delete this.sectors.frozen[t]},_freezeSector:function(t){this.sectors.frozen[t]=this.sectors.active[t],this._deleteActiveSector(t)},_activateSector:function(t){this.sectors.active[t]=this.sectors.frozen[t],this._deleteFrozenSector(t)},_mergeThisWithFrozen:function(t){for(var e in this.nodes)this.nodes.hasOwnProperty(e)&&(this.sectors.frozen[t].nodes[e]=this.nodes[e]);for(var i in this.edges)this.edges.hasOwnProperty(i)&&(this.sectors.frozen[t].edges[i]=this.edges[i]);for(var n=0;n1?this[t](n[0],n[1]):this[t](e)}this._loadLatestSector()},_doInAllFrozenSectors:function(t,e){if(void 0===e)for(var i in this.sectors.frozen)this.sectors.frozen.hasOwnProperty(i)&&(this._switchToFrozenSector(i),this[t]());else for(var i in this.sectors.frozen)if(this.sectors.frozen.hasOwnProperty(i)){this._switchToFrozenSector(i);var n=Array.prototype.splice.call(arguments,1);n.length>1?this[t](n[0],n[1]):this[t](e)}this._loadLatestSector()},_doInNavigationSector:function(t,e){if(this._switchToNavigationSector(),void 0===e)this[t]();else{var i=Array.prototype.splice.call(arguments,1);i.length>1?this[t](i[0],i[1]):this[t](e)}this._loadLatestSector()},_doInAllSectors:function(t,e){var i=Array.prototype.splice.call(arguments,1);void 0===e?(this._doInAllActiveSectors(t),this._doInAllFrozenSectors(t)):i.length>1?(this._doInAllActiveSectors(t,i[0],i[1]),this._doInAllFrozenSectors(t,i[0],i[1])):(this._doInAllActiveSectors(t,e),this._doInAllFrozenSectors(t,e))},_clearNodeIndexList:function(){var t=this._sector();this.sectors.active[t].nodeIndices=[],this.nodeIndices=this.sectors.active[t].nodeIndices},_drawSectorNodes:function(t,e){var i,n=1e9,s=-1e9,o=1e9,r=-1e9;for(var a in this.sectors[e])if(this.sectors[e].hasOwnProperty(a)&&void 0!==this.sectors[e][a].drawingNode){this._switchToSector(a,e),n=1e9,s=-1e9,o=1e9,r=-1e9;for(var h in this.nodes)this.nodes.hasOwnProperty(h)&&(i=this.nodes[h],i.resize(t),o>i.x-.5*i.width&&(o=i.x-.5*i.width),ri.y-.5*i.height&&(n=i.y-.5*i.height),st&&n>s;)s%3==0?this.forceAggregateHubs():this.increaseClusterLevel(),i=this.nodeIndices.length,s+=1;s>1&&1==e&&this.repositionNodes()},openCluster:function(t){var e=this.moving;if(t.clusterSize>this.constants.clustering.sectorThreshold&&this._nodeInActiveArea(t)&&("default"!=this._sector()||1!=this.nodeIndices.length)){this._addSector(t);for(var i=0;this.nodeIndices.lengthi;)this.decreaseClusterLevel(),i+=1}else this._expandClusterNode(t,!1,!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels();this.moving!=e&&this.start()},updateClustersDefault:function(){1==this.constants.clustering.enabled&&this.updateClusters(0,!1,!1)},increaseClusterLevel:function(){this.updateClusters(-1,!1,!0)},decreaseClusterLevel:function(){this.updateClusters(1,!1,!0)},updateClusters:function(t,e,i){var n=this.moving,s=this.nodeIndices.length;this.previousScale>this.scale&&0==t&&this._collapseSector(),this.previousScale>this.scale||-1==t?this._formClusters(i):(this.previousScalethis.scale||-1==t)&&(this._aggregateHubs(i),this._updateNodeIndexList()),(this.previousScale>this.scale||-1==t)&&(this.handleChains(),this._updateNodeIndexList()),this.previousScale=this.scale,this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.lengththis.constants.clustering.chainThreshold&&this._reduceAmountOfChains(1-this.constants.clustering.chainThreshold/t)},_aggregateHubs:function(t){this._getHubSize(),this._formClustersByHub(t,!1)},forceAggregateHubs:function(){var t=this.moving,e=this.nodeIndices.length;this._aggregateHubs(!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.length!=e&&(this.clusterSession+=1),this.moving!=t&&this.start()},_openClustersBySize:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];1==e.inView()&&(e.width*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientWidth||e.height*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientHeight)&&this.openCluster(e)}},_openClusters:function(t,e){for(var i=0;i1&&(t.clusterSizei)){var r=o.from,a=o.to;o.to.mass>o.from.mass&&(r=o.to,a=o.from),1==a.dynamicEdgesLength?this._addToCluster(r,a,!1):1==r.dynamicEdgesLength&&this._addToCluster(a,r,!1)}}},_forceClustersByZoom:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];if(1==e.dynamicEdgesLength&&0!=e.dynamicEdges.length){var i=e.dynamicEdges[0],n=i.toId==e.id?this.nodes[i.fromId]:this.nodes[i.toId];e.id!=n.id&&(n.mass>e.mass?this._addToCluster(n,e,!0):this._addToCluster(e,n,!0))}}},_formClustersByHub:function(t,e){for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&this._formClusterFromHub(this.nodes[i],t,e)},_formClusterFromHub:function(t,e,i,n){if(void 0===n&&(n=0),t.dynamicEdgesLength>=this.hubThreshold&&0==i||t.dynamicEdgesLength==this.hubThreshold&&1==i){for(var s,o,r,a=this.constants.clustering.clusterEdgeThreshold/this.scale,h=!1,l=[],c=t.dynamicEdges.length,d=0;c>d;d++)l.push(t.dynamicEdges[d].id);if(0==e)for(h=!1,d=0;c>d;d++){var u=this.edges[l[d]];if(void 0!==u&&u.connected&&u.toId!=u.fromId&&(s=u.to.x-u.from.x,o=u.to.y-u.from.y,r=Math.sqrt(s*s+o*o),a>r)){h=!0;break}}if(!e&&h||e)for(d=0;c>d;d++)if(u=this.edges[l[d]],void 0!==u){var p=this.nodes[u.fromId==t.id?u.toId:u.fromId];p.dynamicEdges.length<=this.hubThreshold+n&&p.id!=t.id&&this._addToCluster(t,p,e)}}},_addToCluster:function(t,e,i){t.containedNodes[e.id]=e;for(var n=0;n1)for(var n=0;n1&&(e.label="[".concat(String(e.clusterSize),"]"))}for(t in this.nodes)this.nodes.hasOwnProperty(t)&&(e=this.nodes[t],1==e.clusterSize&&(e.label=void 0!==e.originalLabel?e.originalLabel:String(e.id)))},_nodeInActiveArea:function(t){return Math.abs(t.x-this.areaCenter.x)<=this.constants.clustering.activeAreaBoxSize/this.scale&&Math.abs(t.y-this.areaCenter.y)<=this.constants.clustering.activeAreaBoxSize/this.scale},repositionNodes:function(){for(var t=0;tn&&(n=o.dynamicEdgesLength),t+=o.dynamicEdgesLength,e+=Math.pow(o.dynamicEdgesLength,2),i+=1}t/=i,e/=i;var r=e-Math.pow(t,2),a=Math.sqrt(r);this.hubThreshold=Math.floor(t+2*a),this.hubThreshold>n&&(this.hubThreshold=n)},_reduceAmountOfChains:function(t){this.hubThreshold=2;var e=Math.floor(this.nodeIndices.length*t);for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&e>0&&(this._formClusterFromHub(this.nodes[i],!0,!0,1),e-=1)},_getChainFraction:function(){var t=0,e=0;for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&(2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&(t+=1),e+=1);return t/e}},SelectionMixin={_getNodesOverlappingWith:function(t,e){var i=this.nodes;for(var n in i)i.hasOwnProperty(n)&&i[n].isOverlappingWith(t)&&e.push(n)},_getAllNodesOverlappingWith:function(t){var e=[];return this._doInAllActiveSectors("_getNodesOverlappingWith",t,e),e},_getAllNavigationNodesOverlappingWith:function(t){var e=[];return this._doInNavigationSector("_getNodesOverlappingWith",t,e),e},_pointerToPositionObject:function(t){var e=this._canvasToX(t.x),i=this._canvasToY(t.y);return{left:e,top:i,right:e,bottom:i}},_pointerToScreenPositionObject:function(t){var e=t.x,i=t.y;return{left:e,top:i,right:e,bottom:i}},_getNavigationNodeAt:function(t){var e=this._pointerToScreenPositionObject(t),i=this._getAllNavigationNodesOverlappingWith(e);return i.length>0?this.sectors.navigation.nodes[i[i.length-1]]:null},_getNodeAt:function(t){var e=this._pointerToPositionObject(t),i=this._getAllNodesOverlappingWith(e);return i.length>0?this.nodes[i[i.length-1]]:null},_getEdgesOverlappingWith:function(t,e){var i=this.edges;for(var n in i)i.hasOwnProperty(n)&&i[n].isOverlappingWith(t)&&e.push(n)},_getAllEdgesOverlappingWith:function(t){var e=[];return this._doInAllActiveSectors("_getEdgesOverlappingWith",t,e),e},_getEdgeAt:function(t){var e=this._pointerToPositionObject(t),i=this._getAllEdgesOverlappingWith(e);return i.length>0?this.edges[i[i.length-1]]:null},_addToSelection:function(t){this.selectionObj[t.id]=t},_removeFromSelection:function(t){delete this.selectionObj[t.id]},_unselectAll:function(t){void 0===t&&(t=!1);for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e].unselect();this.selectionObj={},0==t&&this._trigger("select",this.getSelection())},_unselectClusters:function(t){void 0===t&&(t=!1);for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e]instanceof Node&&this.selectionObj[e].clusterSize>1&&(this.selectionObj[e].unselect(),this._removeFromSelection(this.selectionObj[e]));0==t&&this._trigger("select",this.getSelection())},_getSelectedNodeCount:function(){var t=0;for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e]instanceof Node&&(t+=1);return t},_getSelectedEdgeCount:function(){var t=0;for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e]instanceof Edge&&(t+=1);return t},_getSelectedObjectCount:function(){var t=0;for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&(t+=1);return t},_selectionIsEmpty:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t))return!1;return!0},_clusterInSelection:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t)&&this.selectionObj[t]instanceof Node&&this.selectionObj[t].clusterSize>1)return!0;return!1},_selectConnectedEdges:function(t){for(var e=0;ee;e++){n=t[e];var s=this.nodes[n];if(!s)throw new RangeError('Node with id "'+n+'" not found');this._selectObject(s,!0,!0)}this.redraw()},_updateSelection:function(){for(var t in this.selectionObj)this.selectionObj.hasOwnProperty(t)&&(this.selectionObj[t]instanceof Node?this.nodes.hasOwnProperty(t)||delete this.selectionObj[t]:this.edges.hasOwnProperty(t)||delete this.selectionObj[t])}},NavigationMixin={_relocateNavigation:function(){if(void 0!==this.sectors){var t=this.navigationClientWidth-this.frame.canvas.clientWidth,e=this.navigationClientHeight-this.frame.canvas.clientHeight;this.navigationClientWidth=this.frame.canvas.clientWidth,this.navigationClientHeight=this.frame.canvas.clientHeight;var i=null;for(var n in this.sectors.navigation.nodes)this.sectors.navigation.nodes.hasOwnProperty(n)&&(i=this.sectors.navigation.nodes[n],i.horizontalAlignLeft||(i.x-=t),i.verticalAlignTop||(i.y-=e))}},_loadNavigationElements:function(){var t=this.constants.navigation.iconPath;this.navigationClientWidth=this.frame.canvas.clientWidth,this.navigationClientHeight=this.frame.canvas.clientHeight,void 0===this.navigationClientWidth&&(this.navigationClientWidth=0,this.navigationClientHeight=0);for(var e=15,i=7,n=[{id:"navigation_up",shape:"image",image:t+"/uparrow.png",triggerFunction:"_moveUp",verticalAlignTop:!1,x:45+e+i,y:this.navigationClientHeight-45-e-i},{id:"navigation_down",shape:"image",image:t+"/downarrow.png",triggerFunction:"_moveDown",verticalAlignTop:!1,x:45+e+i,y:this.navigationClientHeight-15-e},{id:"navigation_left",shape:"image",image:t+"/leftarrow.png",triggerFunction:"_moveLeft",verticalAlignTop:!1,x:15+e,y:this.navigationClientHeight-15-e},{id:"navigation_right",shape:"image",image:t+"/rightarrow.png",triggerFunction:"_moveRight",verticalAlignTop:!1,x:75+e+2*i,y:this.navigationClientHeight-15-e},{id:"navigation_plus",shape:"image",image:t+"/plus.png",triggerFunction:"_zoomIn",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-45-e-i,y:this.navigationClientHeight-15-e},{id:"navigation_min",shape:"image",image:t+"/minus.png",triggerFunction:"_zoomOut",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-15-e,y:this.navigationClientHeight-15-e},{id:"navigation_zoomExtends",shape:"image",image:t+"/zoomExtends.png",triggerFunction:"zoomToFit",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-15-e,y:this.navigationClientHeight-45-e-i}],s=null,o=0;ot.x-t.width&&(n=t.x-t.width),st.y-t.height&&(e=t.y-t.height),i=this.constants.clustering.initialMaxNodes)var n=38.8467/(e-14.50184)+.0116;else var n=42.54117319/(e+39.31966387)+.1944405;else{var s=1.1*(Math.abs(i.minX)+Math.abs(i.maxX)),o=1.1*(Math.abs(i.minY)+Math.abs(i.maxY)),r=this.frame.canvas.clientWidth/s,a=this.frame.canvas.clientHeight/o;n=a>=r?r:a}n>1&&(n=1),this.pinch.mousewheelScale=n,this._setScale(n),this._centerGraph(i),this.start()},Graph.prototype._updateNodeIndexList=function(){this._clearNodeIndexList();for(var t in this.nodes)this.nodes.hasOwnProperty(t)&&this.nodeIndices.push(t)},Graph.prototype.setData=function(t,e){if(void 0===e&&(e=!1),t&&t.dot&&(t.nodes||t.edges))throw new SyntaxError('Data must contain either parameter "dot" or parameter pair "nodes" and "edges", but not both.');if(this.setOptions(t&&t.options),t&&t.dot){if(t&&t.dot){var i=vis.util.DOTToGraph(t.dot);return void this.setData(i)}}else this._setNodes(t&&t.nodes),this._setEdges(t&&t.edges);this._putDataInSector(),e||(this.stabilize&&this._doStabilize(),this.moving=!0,this.start())},Graph.prototype.setOptions=function(t){if(t){if(void 0!==t.width&&(this.width=t.width),void 0!==t.height&&(this.height=t.height),void 0!==t.stabilize&&(this.stabilize=t.stabilize),void 0!==t.selectable&&(this.selectable=t.selectable),t.clustering){this.constants.clustering.enabled=!0;for(var e in t.clustering)t.clustering.hasOwnProperty(e)&&(this.constants.clustering[e]=t.clustering[e])}else void 0!==t.clustering&&(this.constants.clustering.enabled=!1);if(t.navigation){this.constants.navigation.enabled=!0;for(var e in t.navigation)t.navigation.hasOwnProperty(e)&&(this.constants.navigation[e]=t.navigation[e])}else void 0!==t.navigation&&(this.constants.navigation.enabled=!1);if(t.keyboard){this.constants.keyboard.enabled=!0;for(var e in t.keyboard)t.keyboard.hasOwnProperty(e)&&(this.constants.keyboard[e]=t.keyboard[e])}else void 0!==t.keyboard&&(this.constants.keyboard.enabled=!1);if(t.dataManipulationToolbar){this.constants.dataManipulationToolbar.enabled=!0;for(var e in t.dataManipulationToolbar)t.dataManipulationToolbar.hasOwnProperty(e)&&(this.constants.dataManipulationToolbar[e]=t.dataManipulationToolbar[e])}else void 0!==t.dataManipulationToolbar&&(this.constants.dataManipulationToolbar.enabled=!1);if(t.edges){for(e in t.edges)t.edges.hasOwnProperty(e)&&(this.constants.edges[e]=t.edges[e]);void 0!==t.edges.length&&t.nodes&&void 0===t.nodes.distance&&(this.constants.edges.length=t.edges.length,this.constants.nodes.distance=1.25*t.edges.length),t.edges.fontColor||(this.constants.edges.fontColor=t.edges.color),t.edges.dash&&(void 0!==t.edges.dash.length&&(this.constants.edges.dash.length=t.edges.dash.length),void 0!==t.edges.dash.gap&&(this.constants.edges.dash.gap=t.edges.dash.gap),void 0!==t.edges.dash.altLength&&(this.constants.edges.dash.altLength=t.edges.dash.altLength))}if(t.nodes){for(e in t.nodes)t.nodes.hasOwnProperty(e)&&(this.constants.nodes[e]=t.nodes[e]);t.nodes.color&&(this.constants.nodes.color=Node.parseColor(t.nodes.color))}if(t.groups)for(var i in t.groups)if(t.groups.hasOwnProperty(i)){var n=t.groups[i];this.groups.add(i,n)}}this._loadNavigationControls(),this._loadManipulationSystem(),this._createKeyBinds(),this.setSize(this.width,this.height),this._setTranslation(this.frame.clientWidth/2,this.frame.clientHeight/2),this._setScale(1),this._redraw()},Graph.prototype.on=function(t,e){var i=["select"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());events.addListener(this,t,e)},Graph.prototype.off=function(t,e){events.removeListener(this,t,e)},Graph.prototype._trigger=function(t,e){events.trigger(this,t,e)},Graph.prototype._create=function(){for(;this.containerElement.hasChildNodes();)this.containerElement.removeChild(this.containerElement.firstChild);if(this.frame=document.createElement("div"),this.frame.className="graph-frame",this.frame.style.position="relative",this.frame.style.overflow="hidden",this.frame.style.zIndex="1",this.frame.canvas=document.createElement("canvas"),this.frame.canvas.style.position="relative",this.frame.appendChild(this.frame.canvas),!this.frame.canvas.getContext){var t=document.createElement("DIV");t.style.color="red",t.style.fontWeight="bold",t.style.padding="10px",t.innerHTML="Error: your browser does not support HTML canvas",this.frame.canvas.appendChild(t)}var e=this;this.drag={},this.pinch={},this.hammer=Hammer(this.frame.canvas,{prevent_default:!0}),this.hammer.on("tap",e._onTap.bind(e)),this.hammer.on("doubletap",e._onDoubleTap.bind(e)),this.hammer.on("hold",e._onHold.bind(e)),this.hammer.on("pinch",e._onPinch.bind(e)),this.hammer.on("touch",e._onTouch.bind(e)),this.hammer.on("dragstart",e._onDragStart.bind(e)),this.hammer.on("drag",e._onDrag.bind(e)),this.hammer.on("dragend",e._onDragEnd.bind(e)),this.hammer.on("release",e._onRelease.bind(e)),this.hammer.on("mousewheel",e._onMouseWheel.bind(e)),this.hammer.on("DOMMouseScroll",e._onMouseWheel.bind(e)),this.hammer.on("mousemove",e._onMouseMoveTitle.bind(e)),this.containerElement.appendChild(this.frame)},Graph.prototype._createKeyBinds=function(){var t=this;this.mousetrap=mousetrap,this.mousetrap.reset(),1==this.constants.keyboard.enabled&&(this.mousetrap.bind("up",this._moveUp.bind(t),"keydown"),this.mousetrap.bind("up",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("down",this._moveDown.bind(t),"keydown"),this.mousetrap.bind("down",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("left",this._moveLeft.bind(t),"keydown"),this.mousetrap.bind("left",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("right",this._moveRight.bind(t),"keydown"),this.mousetrap.bind("right",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("=",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("=",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("-",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("-",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("[",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("[",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("]",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("]",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pageup",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("pageup",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pagedown",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("pagedown",this._stopZoom.bind(t),"keyup")),this.mousetrap.bind("b",this._formBarnesHutTree.bind(t)),1==this.constants.dataManipulationToolbar.enabled&&this.mousetrap.bind("escape",this._createManipulatorBar.bind(t))},Graph.prototype._getPointer=function(t){return{x:t.pageX-vis.util.getAbsoluteLeft(this.frame.canvas),y:t.pageY-vis.util.getAbsoluteTop(this.frame.canvas)}},Graph.prototype._onTouch=function(t){this.drag.pointer=this._getPointer(t.gesture.touches[0]),this.drag.pinched=!1,this.pinch.scale=this._getScale(),this._handleTouch(this.drag.pointer)},Graph.prototype._onDragStart=function(){var t=this.drag,e=this._getNodeAt(t.pointer);if(t.dragging=!0,t.selection=[],t.translation=this._getTranslation(),t.nodeId=null,null!=e){t.nodeId=e.id,e.isSelected()||this._selectObject(e,!1);for(var i in this.selectionObj)if(this.selectionObj.hasOwnProperty(i)){var n=this.selectionObj[i];if(n instanceof Node){var s={id:n.id,node:n,x:n.x,y:n.y,xFixed:n.xFixed,yFixed:n.yFixed};n.xFixed=!0,n.yFixed=!0,t.selection.push(s)}}}},Graph.prototype._onDrag=function(t){if(!this.drag.pinched){var e=this._getPointer(t.gesture.touches[0]),i=this,n=this.drag,s=n.selection;if(s&&s.length){var o=e.x-n.pointer.x,r=e.y-n.pointer.y;s.forEach(function(t){var e=t.node;t.xFixed||(e.x=i._canvasToX(i._xToCanvas(t.x)+o)),t.yFixed||(e.y=i._canvasToY(i._yToCanvas(t.y)+r))}),this.moving||(this.moving=!0,this.start())}else{var a=e.x-this.drag.pointer.x,h=e.y-this.drag.pointer.y;this._setTranslation(this.drag.translation.x+a,this.drag.translation.y+h),this._redraw(),this.moved=!0}}},Graph.prototype._onDragEnd=function(){this.drag.dragging=!1;var t=this.drag.selection;t&&t.forEach(function(t){t.node.xFixed=t.xFixed,t.node.yFixed=t.yFixed})},Graph.prototype._onTap=function(t){var e=this._getPointer(t.gesture.touches[0]);this.pointerPosition=e,this._handleTap(e)},Graph.prototype._onDoubleTap=function(t){var e=this._getPointer(t.gesture.touches[0]);this._handleDoubleTap(e)},Graph.prototype._onHold=function(t){var e=this._getPointer(t.gesture.touches[0]);this.pointerPosition=e,this._handleOnHold(e)},Graph.prototype._onRelease=function(){this._handleOnRelease()},Graph.prototype._onPinch=function(t){var e=this._getPointer(t.gesture.center);this.drag.pinched=!0,"scale"in this.pinch||(this.pinch.scale=1);var i=this.pinch.scale*t.gesture.scale;this._zoom(i,e)},Graph.prototype._zoom=function(t,e){var i=this._getScale();1e-5>t&&(t=1e-5),t>10&&(t=10);var n=this._getTranslation(),s=t/i,o=(1-s)*e.x+n.x*s,r=(1-s)*e.y+n.y*s;return this.areaCenter={x:this._canvasToX(e.x),y:this._canvasToY(e.y)},this.pinch.mousewheelScale=t,this._setScale(t),this._setTranslation(o,r),this.updateClustersDefault(),this._redraw(),t},Graph.prototype._onMouseWheel=function(t){var e=0;if(t.wheelDelta?e=t.wheelDelta/120:t.detail&&(e=-t.detail/3),e){"mousewheelScale"in this.pinch||(this.pinch.mousewheelScale=1);var i=this.pinch.mousewheelScale,n=e/10;0>e&&(n/=1-n),i*=1+n;var s=util.fakeGesture(this,t),o=this._getPointer(s.center);i=this._zoom(i,o)}t.preventDefault()},Graph.prototype._onMouseMoveTitle=function(t){var e=util.fakeGesture(this,t),i=this._getPointer(e.center);this.popupNode&&this._checkHidePopup(i);var n=this,s=function(){n._checkShowPopup(i)};this.popupTimer&&clearInterval(this.popupTimer),this.drag.dragging||(this.popupTimer=setTimeout(s,300))},Graph.prototype._checkShowPopup=function(t){var e,i={left:this._canvasToX(t.x),top:this._canvasToY(t.y),right:this._canvasToX(t.x),bottom:this._canvasToY(t.y)},n=this.popupNode;if(void 0==this.popupNode){var s=this.nodes;for(e in s)if(s.hasOwnProperty(e)){var o=s[e];if(void 0!==o.getTitle()&&o.isOverlappingWith(i)){this.popupNode=o;break}}}if(void 0===this.popupNode){var r=this.edges;for(e in r)if(r.hasOwnProperty(e)){var a=r[e];if(a.connected&&void 0!==a.getTitle()&&a.isOverlappingWith(i)){this.popupNode=a;break}}}if(this.popupNode){if(this.popupNode!=n){var h=this;h.popup||(h.popup=new Popup(h.frame)),h.popup.setPosition(t.x-3,t.y-3),h.popup.setText(h.popupNode.getTitle()),h.popup.show()}}else this.popup&&this.popup.hide()},Graph.prototype._checkHidePopup=function(t){this.popupNode&&this._getNodeAt(t)||(this.popupNode=void 0,this.popup&&this.popup.hide())},Graph.prototype._getConnectionCount=function(t){function e(t){for(var e=[],i=0,n=t.length;n>i;i++)for(var s=t[i],o=s.edges,r=0,a=o.length;a>r;r++){var h=o[r],l=null;h.from==s?l=h.to:h.to==s&&(l=h.from);var c,d;if(l)for(c=0,d=t.length;d>c;c++)if(t[c]==l){l=null;break}if(l)for(c=0,d=e.length;d>c;c++)if(e[c]==l){l=null;break}l&&e.push(l)}return e}void 0==t&&(t=1);var i=[],n=this.nodes;for(var s in n)if(n.hasOwnProperty(s)){for(var o=[n[s]],r=0;t>r;r++)o=o.concat(e(o));i.push(o)}for(var a=[],h=0,l=i.length;l>h;h++)a.push(i[h].length);return a},Graph.prototype.setSize=function(t,e){this.frame.style.width=t,this.frame.style.height=e,this.frame.canvas.style.width="100%",this.frame.canvas.style.height="100%",this.frame.canvas.width=this.frame.canvas.clientWidth,this.frame.canvas.height=this.frame.canvas.clientHeight,void 0!==this.manipulationDiv&&(this.manipulationDiv.style.width=this.frame.canvas.clientWidth),1==this.constants.navigation.enabled&&this._relocateNavigation()},Graph.prototype._setNodes=function(t){var e=this.nodesData;if(t instanceof DataSet||t instanceof DataView)this.nodesData=t;else if(t instanceof Array)this.nodesData=new DataSet,this.nodesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.nodesData=new DataSet}if(e&&util.forEach(this.nodesListeners,function(t,i){e.unsubscribe(i,t)}),this.nodes={},this.nodesData){var i=this;util.forEach(this.nodesListeners,function(t,e){i.nodesData.subscribe(e,t)});var n=this.nodesData.getIds();this._addNodes(n)}this._updateSelection()},Graph.prototype._addNodes=function(t){for(var e,i=0,n=t.length;n>i;i++){e=t[i];var s=this.nodesData.get(e),o=new Node(s,this.images,this.groups,this.constants);if(this.nodes[e]=o,!o.isFixed()&&1!=this.createNodeOnClick){var r=20*this.constants.edges.length,a=t.length,h=2*Math.PI*(i/a);o.x=r*Math.cos(h),o.y=r*Math.sin(h),this.moving=!0}}this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(this.nodes),this.updateLabels()},Graph.prototype._updateNodes=function(t){for(var e=this.nodes,i=this.nodesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o],a=i.get(o);r?r.setProperties(a,this.constants):(r=new Node(properties,this.images,this.groups,this.constants),e[o]=r,r.isFixed()||(this.moving=!0))}this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(e)},Graph.prototype._removeNodes=function(t){for(var e=this.nodes,i=0,n=t.length;n>i;i++){var s=t[i];delete e[s]}this._updateNodeIndexList(),this._reconnectEdges(),this._updateSelection(),this._updateValueRange(e)},Graph.prototype._setEdges=function(t){var e=this.edgesData;if(t instanceof DataSet||t instanceof DataView)this.edgesData=t;else if(t instanceof Array)this.edgesData=new DataSet,this.edgesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.edgesData=new DataSet}if(e&&util.forEach(this.edgesListeners,function(t,i){e.unsubscribe(i,t)}),this.edges={},this.edgesData){var i=this;util.forEach(this.edgesListeners,function(t,e){i.edgesData.subscribe(e,t)});var n=this.edgesData.getIds();this._addEdges(n)}this._reconnectEdges()},Graph.prototype._addEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o];r&&r.disconnect();var a=i.get(o,{showInternalIds:!0});e[o]=new Edge(a,this,this.constants)}this.moving=!0,this._updateValueRange(e)},Graph.prototype._updateEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=i.get(o),a=e[o];a?(a.disconnect(),a.setProperties(r,this.constants),a.connect()):(a=new Edge(r,this,this.constants),this.edges[o]=a)}this.moving=!0,this._updateValueRange(e)},Graph.prototype._removeEdges=function(t){for(var e=this.edges,i=0,n=t.length;n>i;i++){var s=t[i],o=e[s];o&&(o.disconnect(),delete e[s])}this.moving=!0,this._updateValueRange(e)},Graph.prototype._reconnectEdges=function(){var t,e=this.nodes,i=this.edges;for(t in e)e.hasOwnProperty(t)&&(e[t].edges=[]);for(t in i)if(i.hasOwnProperty(t)){var n=i[t];n.from=null,n.to=null,n.connect()}},Graph.prototype._updateValueRange=function(t){var e,i=void 0,n=void 0;for(e in t)if(t.hasOwnProperty(e)){var s=t[e].getValue();void 0!==s&&(i=void 0===i?s:Math.min(s,i),n=void 0===n?s:Math.max(s,n))}if(void 0!==i&&void 0!==n)for(e in t)t.hasOwnProperty(e)&&t[e].setValueRange(i,n)},Graph.prototype.redraw=function(){this.setSize(this.width,this.height),this._redraw()},Graph.prototype._redraw=function(){var t=this.frame.canvas.getContext("2d"),e=this.frame.canvas.width,i=this.frame.canvas.height;t.clearRect(0,0,e,i),t.save(),t.translate(this.translation.x,this.translation.y),t.scale(this.scale,this.scale),this.canvasTopLeft={x:this._canvasToX(0),y:this._canvasToY(0)},this.canvasBottomRight={x:this._canvasToX(this.frame.canvas.clientWidth),y:this._canvasToY(this.frame.canvas.clientHeight)},this._doInAllSectors("_drawAllSectorNodes",t),this._doInAllSectors("_drawEdges",t),this._doInAllSectors("_drawNodes",t,!0),this._drawTree(t,"#F00F0F"),t.restore(),1==this.constants.navigation.enabled&&this._doInNavigationSector("_drawNodes",t,!0)},Graph.prototype._setTranslation=function(t,e){void 0===this.translation&&(this.translation={x:0,y:0}),void 0!==t&&(this.translation.x=t),void 0!==e&&(this.translation.y=e)},Graph.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},Graph.prototype._setScale=function(t){this.scale=t},Graph.prototype._getScale=function(){return this.scale},Graph.prototype._canvasToX=function(t){return(t-this.translation.x)/this.scale},Graph.prototype._xToCanvas=function(t){return t*this.scale+this.translation.x},Graph.prototype._canvasToY=function(t){return(t-this.translation.y)/this.scale},Graph.prototype._yToCanvas=function(t){return t*this.scale+this.translation.y},Graph.prototype._drawNodes=function(t,e){void 0===e&&(e=!1);var i=this.nodes,n=[];for(var s in i)i.hasOwnProperty(s)&&(i[s].setScaleAndPos(this.scale,this.canvasTopLeft,this.canvasBottomRight),i[s].isSelected()?n.push(s):(i[s].inArea()||e)&&i[s].draw(t));for(var o=0,r=n.length;r>o;o++)(i[n[o]].inArea()||e)&&i[n[o]].draw(t)},Graph.prototype._drawEdges=function(t){var e=this.edges;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];n.setScale(this.scale),n.connected&&e[i].draw(t)}},Graph.prototype._doStabilize=function(){for(var t=0,e=this.constants.minVelocity,i=!1;!i&&t0&&e==s.EVENT_END?e=s.EVENT_MOVE:c||(e=s.EVENT_END),c||null===o?o=h:h=o,i.call(s.detection,n.collectEventData(t,e,h)),s.HAS_POINTEREVENTS&&e==s.EVENT_END&&(c=s.PointerEvent.updatePointer(e,h))),c||(o=null,r=!1,a=!1,s.PointerEvent.reset())}})},determineEventTypes:function(){var t;t=s.HAS_POINTEREVENTS?s.PointerEvent.getEvents():s.NO_MOUSEEVENTS?["touchstart","touchmove","touchend touchcancel"]:["touchstart mousedown","touchmove mousemove","touchend touchcancel mouseup"],s.EVENT_TYPES[s.EVENT_START]=t[0],s.EVENT_TYPES[s.EVENT_MOVE]=t[1],s.EVENT_TYPES[s.EVENT_END]=t[2]},getTouchList:function(t){return s.HAS_POINTEREVENTS?s.PointerEvent.getTouchList():t.touches?t.touches:[{identifier:1,pageX:t.pageX,pageY:t.pageY,target:t.target}]},collectEventData:function(t,e,i){var n=this.getTouchList(i,e),o=s.POINTER_TOUCH;return(i.type.match(/mouse/)||s.PointerEvent.matchType(s.POINTER_MOUSE,i))&&(o=s.POINTER_MOUSE),{center:s.utils.getCenter(n),timeStamp:(new Date).getTime(),target:i.target,touches:n,eventType:e,pointerType:o,srcEvent:i,preventDefault:function(){this.srcEvent.preventManipulation&&this.srcEvent.preventManipulation(),this.srcEvent.preventDefault&&this.srcEvent.preventDefault()},stopPropagation:function(){this.srcEvent.stopPropagation()},stopDetect:function(){return s.detection.stopDetect()}}}},s.PointerEvent={pointers:{},getTouchList:function(){var t=this,e=[];return Object.keys(t.pointers).sort().forEach(function(i){e.push(t.pointers[i])}),e},updatePointer:function(t,e){return t==s.EVENT_END?this.pointers={}:(e.identifier=e.pointerId,this.pointers[e.pointerId]=e),Object.keys(this.pointers).length},matchType:function(t,e){if(!e.pointerType)return!1;var i={};return i[s.POINTER_MOUSE]=e.pointerType==e.MSPOINTER_TYPE_MOUSE||e.pointerType==s.POINTER_MOUSE,i[s.POINTER_TOUCH]=e.pointerType==e.MSPOINTER_TYPE_TOUCH||e.pointerType==s.POINTER_TOUCH,i[s.POINTER_PEN]=e.pointerType==e.MSPOINTER_TYPE_PEN||e.pointerType==s.POINTER_PEN,i[t]},getEvents:function(){return["pointerdown MSPointerDown","pointermove MSPointerMove","pointerup pointercancel MSPointerUp MSPointerCancel"]},reset:function(){this.pointers={}}},s.utils={extend:function(t,e,n){for(var s in e)t[s]!==i&&n||(t[s]=e[s]);return t},hasParent:function(t,e){for(;t;){if(t==e)return!0;t=t.parentNode}return!1},getCenter:function(t){for(var e=[],i=[],n=0,s=t.length;s>n;n++)e.push(t[n].pageX),i.push(t[n].pageY);return{pageX:(Math.min.apply(Math,e)+Math.max.apply(Math,e))/2,pageY:(Math.min.apply(Math,i)+Math.max.apply(Math,i))/2}},getVelocity:function(t,e,i){return{x:Math.abs(e/t)||0,y:Math.abs(i/t)||0}},getAngle:function(t,e){var i=e.pageY-t.pageY,n=e.pageX-t.pageX;return 180*Math.atan2(i,n)/Math.PI},getDirection:function(t,e){var i=Math.abs(t.pageX-e.pageX),n=Math.abs(t.pageY-e.pageY);return i>=n?t.pageX-e.pageX>0?s.DIRECTION_LEFT:s.DIRECTION_RIGHT:t.pageY-e.pageY>0?s.DIRECTION_UP:s.DIRECTION_DOWN},getDistance:function(t,e){var i=e.pageX-t.pageX,n=e.pageY-t.pageY;return Math.sqrt(i*i+n*n)},getScale:function(t,e){return t.length>=2&&e.length>=2?this.getDistance(e[0],e[1])/this.getDistance(t[0],t[1]):1},getRotation:function(t,e){return t.length>=2&&e.length>=2?this.getAngle(e[1],e[0])-this.getAngle(t[1],t[0]):0},isVertical:function(t){return t==s.DIRECTION_UP||t==s.DIRECTION_DOWN},stopDefaultBrowserBehavior:function(t,e){var i,n=["webkit","khtml","moz","ms","o",""];if(e&&t.style){for(var s=0;si;i++){var o=this.gestures[i];if(!this.stopped&&e[o.name]!==!1&&o.handler.call(o,t,this.current.inst)===!1){this.stopDetect();break}}return this.current&&(this.current.lastEvent=t),t.eventType==s.EVENT_END&&!t.touches.length-1&&this.stopDetect(),t}},stopDetect:function(){this.previous=s.utils.extend({},this.current),this.current=null,this.stopped=!0},extendEventData:function(t){var e=this.current.startEvent;if(e&&(t.touches.length!=e.touches.length||t.touches===e.touches)){e.touches=[];for(var i=0,n=t.touches.length;n>i;i++)e.touches.push(s.utils.extend({},t.touches[i]))}var o=t.timeStamp-e.timeStamp,r=t.center.pageX-e.center.pageX,a=t.center.pageY-e.center.pageY,h=s.utils.getVelocity(o,r,a);return s.utils.extend(t,{deltaTime:o,deltaX:r,deltaY:a,velocityX:h.x,velocityY:h.y,distance:s.utils.getDistance(e.center,t.center),angle:s.utils.getAngle(e.center,t.center),direction:s.utils.getDirection(e.center,t.center),scale:s.utils.getScale(e.touches,t.touches),rotation:s.utils.getRotation(e.touches,t.touches),startEvent:e}),t},register:function(t){var e=t.defaults||{};return e[t.name]===i&&(e[t.name]=!0),s.utils.extend(s.defaults,e,!0),t.index=t.index||1e3,this.gestures.push(t),this.gestures.sort(function(t,e){return t.indexe.index?1:0}),this.gestures}},s.gestures=s.gestures||{},s.gestures.Hold={name:"hold",index:10,defaults:{hold_timeout:500,hold_threshold:1},timer:null,handler:function(t,e){switch(t.eventType){case s.EVENT_START:clearTimeout(this.timer),s.detection.current.name=this.name,this.timer=setTimeout(function(){"hold"==s.detection.current.name&&e.trigger("hold",t)},e.options.hold_timeout);break;case s.EVENT_MOVE:t.distance>e.options.hold_threshold&&clearTimeout(this.timer);break;case s.EVENT_END:clearTimeout(this.timer)}}},s.gestures.Tap={name:"tap",index:100,defaults:{tap_max_touchtime:250,tap_max_distance:10,tap_always:!0,doubletap_distance:20,doubletap_interval:300},handler:function(t,e){if(t.eventType==s.EVENT_END){var i=s.detection.previous,n=!1;if(t.deltaTime>e.options.tap_max_touchtime||t.distance>e.options.tap_max_distance)return;i&&"tap"==i.name&&t.timeStamp-i.lastEvent.timeStamp0&&t.touches.length>e.options.swipe_max_touches)return;(t.velocityX>e.options.swipe_velocity||t.velocityY>e.options.swipe_velocity)&&(e.trigger(this.name,t),e.trigger(this.name+t.direction,t))}}},s.gestures.Drag={name:"drag",index:50,defaults:{drag_min_distance:10,drag_max_touches:1,drag_block_horizontal:!1,drag_block_vertical:!1,drag_lock_to_axis:!1,drag_lock_min_distance:25},triggered:!1,handler:function(t,e){if(s.detection.current.name!=this.name&&this.triggered)return e.trigger(this.name+"end",t),void(this.triggered=!1);if(!(e.options.drag_max_touches>0&&t.touches.length>e.options.drag_max_touches))switch(t.eventType){case s.EVENT_START:this.triggered=!1;break;case s.EVENT_MOVE:if(t.distancee.options.transform_min_rotation&&e.trigger("rotate",t),i>e.options.transform_min_scale&&(e.trigger("pinch",t),e.trigger("pinch"+(t.scale<1?"in":"out"),t));break;case s.EVENT_END:this.triggered&&e.trigger(this.name+"end",t),this.triggered=!1}}},s.gestures.Touch={name:"touch",index:-1/0,defaults:{prevent_default:!1,prevent_mouseevents:!1},handler:function(t,e){return e.options.prevent_mouseevents&&t.pointerType==s.POINTER_MOUSE?void t.stopDetect():(e.options.prevent_default&&t.preventDefault(),void(t.eventType==s.EVENT_START&&e.trigger(this.name,t)))}},s.gestures.Release={name:"release",index:1/0,handler:function(t,e){t.eventType==s.EVENT_END&&e.trigger(this.name,t)}},"object"==typeof e&&"object"==typeof e.exports?e.exports=s:(t.Hammer=s,"function"==typeof t.define&&t.define.amd&&t.define("hammer",[],function(){return s}))}(this)},{}],3:[function(t,e){(function(i){function n(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function s(t,e){return function(i){return u(t.call(this,i),e)}}function o(t,e){return function(i){return this.lang().ordinal(t.call(this,i),e)}}function r(){}function a(t){E(t),l(this,t)}function h(t){var e=y(t),i=e.year||0,n=e.month||0,s=e.week||0,o=e.day||0,r=e.hour||0,a=e.minute||0,h=e.second||0,l=e.millisecond||0;this._milliseconds=+l+1e3*h+6e4*a+36e5*r,this._days=+o+7*s,this._months=+n+12*i,this._data={},this._bubble()}function l(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return e.hasOwnProperty("toString")&&(t.toString=e.toString),e.hasOwnProperty("valueOf")&&(t.valueOf=e.valueOf),t}function c(t){var e,i={};for(e in t)t.hasOwnProperty(e)&&ye.hasOwnProperty(e)&&(i[e]=t[e]);return i}function d(t){return 0>t?Math.ceil(t):Math.floor(t)}function u(t,e,i){for(var n=""+Math.abs(t),s=t>=0;n.lengthn;n++)(i&&t[n]!==e[n]||!i&&b(t[n])!==b(e[n]))&&r++;return r+o}function v(t){if(t){var e=t.toLowerCase().replace(/(.)s$/,"$1");t=Xe[t]||qe[e]||e}return t}function y(t){var e,i,n={};for(i in t)t.hasOwnProperty(i)&&(e=v(i),e&&(n[e]=t[i]));return n}function _(t){var e,n;if(0===t.indexOf("week"))e=7,n="day";else{if(0!==t.indexOf("month"))return;e=12,n="month"}oe[t]=function(s,o){var r,a,h=oe.fn._lang[t],l=[];if("number"==typeof s&&(o=s,s=i),a=function(t){var e=oe().utc().set(n,t);return h.call(oe.fn._lang,e,s||"")},null!=o)return a(o);for(r=0;e>r;r++)l.push(a(r));return l}}function b(t){var e=+t,i=0;return 0!==e&&isFinite(e)&&(i=e>=0?Math.floor(e):Math.ceil(e)),i}function w(t,e){return new Date(Date.UTC(t,e+1,0)).getUTCDate()}function S(t){return T(t)?366:365}function T(t){return t%4===0&&t%100!==0||t%400===0}function E(t){var e;t._a&&-2===t._pf.overflow&&(e=t._a[de]<0||t._a[de]>11?de:t._a[ue]<1||t._a[ue]>w(t._a[ce],t._a[de])?ue:t._a[pe]<0||t._a[pe]>23?pe:t._a[fe]<0||t._a[fe]>59?fe:t._a[ge]<0||t._a[ge]>59?ge:t._a[me]<0||t._a[me]>999?me:-1,t._pf._overflowDayOfYear&&(ce>e||e>ue)&&(e=ue),t._pf.overflow=e)}function x(t){return null==t._isValid&&(t._isValid=!isNaN(t._d.getTime())&&t._pf.overflow<0&&!t._pf.empty&&!t._pf.invalidMonth&&!t._pf.nullInput&&!t._pf.invalidFormat&&!t._pf.userInvalidated,t._strict&&(t._isValid=t._isValid&&0===t._pf.charsLeftOver&&0===t._pf.unusedTokens.length)),t._isValid}function C(t){return t?t.toLowerCase().replace("_","-"):t}function M(t,e){return e._isUTC?oe(t).zone(e._offset||0):oe(t).local()}function D(t,e){return e.abbr=t,ve[t]||(ve[t]=new r),ve[t].set(e),ve[t]}function I(t){delete ve[t]}function N(e){var i,n,s,o,r=0,a=function(e){if(!ve[e]&&_e)try{t("./lang/"+e)}catch(i){}return ve[e]};if(!e)return oe.fn._lang;if(!f(e)){if(n=a(e))return n;e=[e]}for(;r0;){if(n=a(o.slice(0,i).join("-")))return n;if(s&&s.length>=i&&m(o,s,!0)>=i-1)break;i--}r++}return oe.fn._lang}function O(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function L(t){var e,i,n=t.match(Te);for(e=0,i=n.length;i>e;e++)n[e]=Qe[n[e]]?Qe[n[e]]:O(n[e]);return function(s){var o="";for(e=0;i>e;e++)o+=n[e]instanceof Function?n[e].call(s,t):n[e];return o}}function k(t,e){return t.isValid()?(e=A(e,t.lang()),Ze[e]||(Ze[e]=L(e)),Ze[e](t)):t.lang().invalidDate()}function A(t,e){function i(t){return e.longDateFormat(t)||t}var n=5;for(Ee.lastIndex=0;n>=0&&Ee.test(t);)t=t.replace(Ee,i),Ee.lastIndex=0,n-=1;return t}function P(t,e){var i,n=e._strict;switch(t){case"DDDD":return ze;case"YYYY":case"GGGG":case"gggg":return n?Fe:Me;case"Y":case"G":case"g":return Ye;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return n?Re:De;case"S":if(n)return Ae;case"SS":if(n)return Pe;case"SSS":if(n)return ze;case"DDD":return Ce;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Ne;case"a":case"A":return N(e._l)._meridiemParse;case"X":return ke;case"Z":case"ZZ":return Oe;case"T":return Le;case"SSSS":return Ie;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return n?Pe:xe;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return xe;default:return i=new RegExp(G(j(t.replace("\\","")),"i"))}}function z(t){t=t||"";var e=t.match(Oe)||[],i=e[e.length-1]||[],n=(i+"").match(Ue)||["-",0,0],s=+(60*n[1])+b(n[2]);return"+"===n[0]?-s:s}function F(t,e,i){var n,s=i._a;switch(t){case"M":case"MM":null!=e&&(s[de]=b(e)-1);break;case"MMM":case"MMMM":n=N(i._l).monthsParse(e),null!=n?s[de]=n:i._pf.invalidMonth=e;break;case"D":case"DD":null!=e&&(s[ue]=b(e));break;case"DDD":case"DDDD":null!=e&&(i._dayOfYear=b(e));break;case"YY":s[ce]=b(e)+(b(e)>68?1900:2e3);break;case"YYYY":case"YYYYY":case"YYYYYY":s[ce]=b(e);break;case"a":case"A":i._isPm=N(i._l).isPM(e);break;case"H":case"HH":case"h":case"hh":s[pe]=b(e);break;case"m":case"mm":s[fe]=b(e);break;case"s":case"ss":s[ge]=b(e);break;case"S":case"SS":case"SSS":case"SSSS":s[me]=b(1e3*("0."+e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,i._tzm=z(e);break;case"w":case"ww":case"W":case"WW":case"d":case"dd":case"ddd":case"dddd":case"e":case"E":t=t.substr(0,1);case"gg":case"gggg":case"GG":case"GGGG":case"GGGGG":t=t.substr(0,2),e&&(i._w=i._w||{},i._w[t]=e)}}function R(t){var e,i,n,s,o,r,a,h,l,c,d=[];if(!t._d){for(n=H(t),t._w&&null==t._a[ue]&&null==t._a[de]&&(o=function(e){var i=parseInt(e,10);return e?e.length<3?i>68?1900+i:2e3+i:i:null==t._a[ce]?oe().weekYear():t._a[ce]},r=t._w,null!=r.GG||null!=r.W||null!=r.E?a=J(o(r.GG),r.W||1,r.E,4,1):(h=N(t._l),l=null!=r.d?Z(r.d,h):null!=r.e?parseInt(r.e,10)+h._week.dow:0,c=parseInt(r.w,10)||1,null!=r.d&&lS(s)&&(t._pf._overflowDayOfYear=!0),i=q(s,0,t._dayOfYear),t._a[de]=i.getUTCMonth(),t._a[ue]=i.getUTCDate()),e=0;3>e&&null==t._a[e];++e)t._a[e]=d[e]=n[e];for(;7>e;e++)t._a[e]=d[e]=null==t._a[e]?2===e?1:0:t._a[e];d[pe]+=b((t._tzm||0)/60),d[fe]+=b((t._tzm||0)%60),t._d=(t._useUTC?q:X).apply(null,d)}}function Y(t){var e;t._d||(e=y(t._i),t._a=[e.year,e.month,e.day,e.hour,e.minute,e.second,e.millisecond],R(t))}function H(t){var e=new Date;return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function W(t){t._a=[],t._pf.empty=!0;var e,i,n,s,o,r=N(t._l),a=""+t._i,h=a.length,l=0;for(n=A(t._f,r).match(Te)||[],e=0;e0&&t._pf.unusedInput.push(o),a=a.slice(a.indexOf(i)+i.length),l+=i.length),Qe[s]?(i?t._pf.empty=!1:t._pf.unusedTokens.push(s),F(s,i,t)):t._strict&&!i&&t._pf.unusedTokens.push(s);t._pf.charsLeftOver=h-l,a.length>0&&t._pf.unusedInput.push(a),t._isPm&&t._a[pe]<12&&(t._a[pe]+=12),t._isPm===!1&&12===t._a[pe]&&(t._a[pe]=0),R(t),E(t)}function j(t){return t.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,i,n,s){return e||i||n||s})}function G(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function U(t){var e,i,s,o,r;if(0===t._f.length)return t._pf.invalidFormat=!0,void(t._d=new Date(0/0));for(o=0;or)&&(s=r,i=e));l(t,i||e)}function B(t){var e,i,n=t._i,s=He.exec(n);if(s){for(t._pf.iso=!0,e=0,i=je.length;i>e;e++)if(je[e][1].exec(n)){t._f=je[e][0]+(s[6]||" ");break}for(e=0,i=Ge.length;i>e;e++)if(Ge[e][1].exec(n)){t._f+=Ge[e][0];break}n.match(Oe)&&(t._f+="Z"),W(t)}else t._d=new Date(n)}function V(t){var e=t._i,n=be.exec(e);e===i?t._d=new Date:n?t._d=new Date(+n[1]):"string"==typeof e?B(t):f(e)?(t._a=e.slice(0),R(t)):g(e)?t._d=new Date(+e):"object"==typeof e?Y(t):t._d=new Date(e)}function X(t,e,i,n,s,o,r){var a=new Date(t,e,i,n,s,o,r);return 1970>t&&a.setFullYear(t),a}function q(t){var e=new Date(Date.UTC.apply(null,arguments));return 1970>t&&e.setUTCFullYear(t),e}function Z(t,e){if("string"==typeof t)if(isNaN(t)){if(t=e.weekdaysParse(t),"number"!=typeof t)return null}else t=parseInt(t,10);return t}function K(t,e,i,n,s){return s.relativeTime(e||1,!!i,t,n)}function $(t,e,i){var n=le(Math.abs(t)/1e3),s=le(n/60),o=le(s/60),r=le(o/24),a=le(r/365),h=45>n&&["s",n]||1===s&&["m"]||45>s&&["mm",s]||1===o&&["h"]||22>o&&["hh",o]||1===r&&["d"]||25>=r&&["dd",r]||45>=r&&["M"]||345>r&&["MM",le(r/30)]||1===a&&["y"]||["yy",a];return h[2]=e,h[3]=t>0,h[4]=i,K.apply({},h)}function Q(t,e,i){var n,s=i-e,o=i-t.day();return o>s&&(o-=7),s-7>o&&(o+=7),n=oe(t).add("d",o),{week:Math.ceil(n.dayOfYear()/7),year:n.year()}}function J(t,e,i,n,s){var o,r,a=q(t,0,1).getUTCDay();return i=null!=i?i:s,o=s-a+(a>n?7:0)-(s>a?7:0),r=7*(e-1)+(i-s)+o+1,{year:r>0?t:t-1,dayOfYear:r>0?r:S(t-1)+r}}function te(t){var e=t._i,i=t._f;return null===e?oe.invalid({nullInput:!0}):("string"==typeof e&&(t._i=e=N().preparse(e)),oe.isMoment(e)?(t=c(e),t._d=new Date(+e._d)):i?f(i)?U(t):W(t):V(t),new a(t))}function ee(t,e){oe.fn[t]=oe.fn[t+"s"]=function(t){var i=this._isUTC?"UTC":"";return null!=t?(this._d["set"+i+e](t),oe.updateOffset(this),this):this._d["get"+i+e]()}}function ie(t){oe.duration.fn[t]=function(){return this._data[t]}}function ne(t,e){oe.duration.fn["as"+t]=function(){return+this/e}}function se(t){var e=!1,i=oe;"undefined"==typeof ender&&(t?(he.moment=function(){return!e&&console&&console.warn&&(e=!0,console.warn("Accessing Moment through the global scope is deprecated, and will be removed in an upcoming release.")),i.apply(null,arguments)},l(he.moment,i)):he.moment=oe)}for(var oe,re,ae="2.5.1",he=this,le=Math.round,ce=0,de=1,ue=2,pe=3,fe=4,ge=5,me=6,ve={},ye={_isAMomentObject:null,_i:null,_f:null,_l:null,_strict:null,_isUTC:null,_offset:null,_pf:null,_lang:null},_e="undefined"!=typeof e&&e.exports&&"undefined"!=typeof t,be=/^\/?Date\((\-?\d+)/i,we=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,Se=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,Te=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g,Ee=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,xe=/\d\d?/,Ce=/\d{1,3}/,Me=/\d{1,4}/,De=/[+\-]?\d{1,6}/,Ie=/\d+/,Ne=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Oe=/Z|[\+\-]\d\d:?\d\d/gi,Le=/T/i,ke=/[\+\-]?\d+(\.\d{1,3})?/,Ae=/\d/,Pe=/\d\d/,ze=/\d{3}/,Fe=/\d{4}/,Re=/[+-]?\d{6}/,Ye=/[+-]?\d+/,He=/^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,We="YYYY-MM-DDTHH:mm:ssZ",je=[["YYYYYY-MM-DD",/[+-]\d{6}-\d{2}-\d{2}/],["YYYY-MM-DD",/\d{4}-\d{2}-\d{2}/],["GGGG-[W]WW-E",/\d{4}-W\d{2}-\d/],["GGGG-[W]WW",/\d{4}-W\d{2}/],["YYYY-DDD",/\d{4}-\d{3}/]],Ge=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d{1,3}/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],Ue=/([\+\-]|\d\d)/gi,Be="Date|Hours|Minutes|Seconds|Milliseconds".split("|"),Ve={Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6},Xe={ms:"millisecond",s:"second",m:"minute",h:"hour",d:"day",D:"date",w:"week",W:"isoWeek",M:"month",y:"year",DDD:"dayOfYear",e:"weekday",E:"isoWeekday",gg:"weekYear",GG:"isoWeekYear"},qe={dayofyear:"dayOfYear",isoweekday:"isoWeekday",isoweek:"isoWeek",weekyear:"weekYear",isoweekyear:"isoWeekYear"},Ze={},Ke="DDD w W M D d".split(" "),$e="M D H h m s w W".split(" "),Qe={M:function(){return this.month()+1},MMM:function(t){return this.lang().monthsShort(this,t)},MMMM:function(t){return this.lang().months(this,t)},D:function(){return this.date()},DDD:function(){return this.dayOfYear()},d:function(){return this.day()},dd:function(t){return this.lang().weekdaysMin(this,t)},ddd:function(t){return this.lang().weekdaysShort(this,t)},dddd:function(t){return this.lang().weekdays(this,t)},w:function(){return this.week()},W:function(){return this.isoWeek()},YY:function(){return u(this.year()%100,2)},YYYY:function(){return u(this.year(),4)},YYYYY:function(){return u(this.year(),5)},YYYYYY:function(){var t=this.year(),e=t>=0?"+":"-";return e+u(Math.abs(t),6)},gg:function(){return u(this.weekYear()%100,2)},gggg:function(){return u(this.weekYear(),4)},ggggg:function(){return u(this.weekYear(),5)},GG:function(){return u(this.isoWeekYear()%100,2)},GGGG:function(){return u(this.isoWeekYear(),4)},GGGGG:function(){return u(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.lang().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.lang().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return b(this.milliseconds()/100)},SS:function(){return u(b(this.milliseconds()/10),2)},SSS:function(){return u(this.milliseconds(),3)},SSSS:function(){return u(this.milliseconds(),3)},Z:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+u(b(t/60),2)+":"+u(b(t)%60,2)},ZZ:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+u(b(t/60),2)+u(b(t)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},X:function(){return this.unix()},Q:function(){return this.quarter()}},Je=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"];Ke.length;)re=Ke.pop(),Qe[re+"o"]=o(Qe[re],re);for(;$e.length;)re=$e.pop(),Qe[re+re]=s(Qe[re],2);for(Qe.DDDD=s(Qe.DDD,3),l(r.prototype,{set:function(t){var e,i;for(i in t)e=t[i],"function"==typeof e?this[i]=e:this["_"+i]=e},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(t){return this._months[t.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(t){return this._monthsShort[t.month()]},monthsParse:function(t){var e,i,n;for(this._monthsParse||(this._monthsParse=[]),e=0;12>e;e++)if(this._monthsParse[e]||(i=oe.utc([2e3,e]),n="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[e]=new RegExp(n.replace(".",""),"i")),this._monthsParse[e].test(t))return e},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(t){return this._weekdays[t.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(t){return this._weekdaysShort[t.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(t){return this._weekdaysMin[t.day()]},weekdaysParse:function(t){var e,i,n;for(this._weekdaysParse||(this._weekdaysParse=[]),e=0;7>e;e++)if(this._weekdaysParse[e]||(i=oe([2e3,1]).day(e),n="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[e]=new RegExp(n.replace(".",""),"i")),this._weekdaysParse[e].test(t))return e},_longDateFormat:{LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D YYYY",LLL:"MMMM D YYYY LT",LLLL:"dddd, MMMM D YYYY LT"},longDateFormat:function(t){var e=this._longDateFormat[t];return!e&&this._longDateFormat[t.toUpperCase()]&&(e=this._longDateFormat[t.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t]=e),e},isPM:function(t){return"p"===(t+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(t,e,i){return t>11?i?"pm":"PM":i?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(t,e){var i=this._calendar[t];return"function"==typeof i?i.apply(e):i},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(t,e,i,n){var s=this._relativeTime[i];return"function"==typeof s?s(t,e,i,n):s.replace(/%d/i,t)},pastFuture:function(t,e){var i=this._relativeTime[t>0?"future":"past"];return"function"==typeof i?i(e):i.replace(/%s/i,e)},ordinal:function(t){return this._ordinal.replace("%d",t)},_ordinal:"%d",preparse:function(t){return t},postformat:function(t){return t},week:function(t){return Q(t,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),oe=function(t,e,s,o){var r;return"boolean"==typeof s&&(o=s,s=i),r={},r._isAMomentObject=!0,r._i=t,r._f=e,r._l=s,r._strict=o,r._isUTC=!1,r._pf=n(),te(r)},oe.utc=function(t,e,s,o){var r;return"boolean"==typeof s&&(o=s,s=i),r={},r._isAMomentObject=!0,r._useUTC=!0,r._isUTC=!0,r._l=s,r._i=t,r._f=e,r._strict=o,r._pf=n(),te(r).utc()},oe.unix=function(t){return oe(1e3*t)},oe.duration=function(t,e){var i,n,s,o=t,r=null;return oe.isDuration(t)?o={ms:t._milliseconds,d:t._days,M:t._months}:"number"==typeof t?(o={},e?o[e]=t:o.milliseconds=t):(r=we.exec(t))?(i="-"===r[1]?-1:1,o={y:0,d:b(r[ue])*i,h:b(r[pe])*i,m:b(r[fe])*i,s:b(r[ge])*i,ms:b(r[me])*i}):(r=Se.exec(t))&&(i="-"===r[1]?-1:1,s=function(t){var e=t&&parseFloat(t.replace(",","."));return(isNaN(e)?0:e)*i},o={y:s(r[2]),M:s(r[3]),d:s(r[4]),h:s(r[5]),m:s(r[6]),s:s(r[7]),w:s(r[8])}),n=new h(o),oe.isDuration(t)&&t.hasOwnProperty("_lang")&&(n._lang=t._lang),n},oe.version=ae,oe.defaultFormat=We,oe.updateOffset=function(){},oe.lang=function(t,e){var i;return t?(e?D(C(t),e):null===e?(I(t),t="en"):ve[t]||N(t),i=oe.duration.fn._lang=oe.fn._lang=N(t),i._abbr):oe.fn._lang._abbr},oe.langData=function(t){return t&&t._lang&&t._lang._abbr&&(t=t._lang._abbr),N(t)},oe.isMoment=function(t){return t instanceof a||null!=t&&t.hasOwnProperty("_isAMomentObject")},oe.isDuration=function(t){return t instanceof h},re=Je.length-1;re>=0;--re)_(Je[re]);for(oe.normalizeUnits=function(t){return v(t)},oe.invalid=function(t){var e=oe.utc(0/0);return null!=t?l(e._pf,t):e._pf.userInvalidated=!0,e},oe.parseZone=function(t){return oe(t).parseZone()},l(oe.fn=a.prototype,{clone:function(){return oe(this)},valueOf:function(){return+this._d+6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().lang("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){var t=oe(this).utc();return 00:!1},parsingFlags:function(){return l({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(){return this.zone(0)},local:function(){return this.zone(0),this._isUTC=!1,this},format:function(t){var e=k(this,t||oe.defaultFormat);return this.lang().postformat(e)},add:function(t,e){var i;return i="string"==typeof t?oe.duration(+e,t):oe.duration(t,e),p(this,i,1),this},subtract:function(t,e){var i;return i="string"==typeof t?oe.duration(+e,t):oe.duration(t,e),p(this,i,-1),this},diff:function(t,e,i){var n,s,o=M(t,this),r=6e4*(this.zone()-o.zone());return e=v(e),"year"===e||"month"===e?(n=432e5*(this.daysInMonth()+o.daysInMonth()),s=12*(this.year()-o.year())+(this.month()-o.month()),s+=(this-oe(this).startOf("month")-(o-oe(o).startOf("month")))/n,s-=6e4*(this.zone()-oe(this).startOf("month").zone()-(o.zone()-oe(o).startOf("month").zone()))/n,"year"===e&&(s/=12)):(n=this-o,s="second"===e?n/1e3:"minute"===e?n/6e4:"hour"===e?n/36e5:"day"===e?(n-r)/864e5:"week"===e?(n-r)/6048e5:n),i?s:d(s)},from:function(t,e){return oe.duration(this.diff(t)).lang(this.lang()._abbr).humanize(!e)},fromNow:function(t){return this.from(oe(),t)},calendar:function(){var t=M(oe(),this).startOf("day"),e=this.diff(t,"days",!0),i=-6>e?"sameElse":-1>e?"lastWeek":0>e?"lastDay":1>e?"sameDay":2>e?"nextDay":7>e?"nextWeek":"sameElse";return this.format(this.lang().calendar(i,this))},isLeapYear:function(){return T(this.year())},isDST:function(){return this.zone()+oe(t).startOf(e)},isBefore:function(t,e){return e="undefined"!=typeof e?e:"millisecond",+this.clone().startOf(e)<+oe(t).startOf(e)},isSame:function(t,e){return e=e||"ms",+this.clone().startOf(e)===+M(t,this).startOf(e)},min:function(t){return t=oe.apply(null,arguments),this>t?this:t},max:function(t){return t=oe.apply(null,arguments),t>this?this:t},zone:function(t){var e=this._offset||0;return null==t?this._isUTC?e:this._d.getTimezoneOffset():("string"==typeof t&&(t=z(t)),Math.abs(t)<16&&(t=60*t),this._offset=t,this._isUTC=!0,e!==t&&p(this,oe.duration(e-t,"m"),1,!0),this)},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.zone(this._tzm):"string"==typeof this._i&&this.zone(this._i),this},hasAlignedHourOffset:function(t){return t=t?oe(t).zone():0,(this.zone()-t)%60===0},daysInMonth:function(){return w(this.year(),this.month())},dayOfYear:function(t){var e=le((oe(this).startOf("day")-oe(this).startOf("year"))/864e5)+1;return null==t?e:this.add("d",t-e)},quarter:function(){return Math.ceil((this.month()+1)/3)},weekYear:function(t){var e=Q(this,this.lang()._week.dow,this.lang()._week.doy).year;return null==t?e:this.add("y",t-e)},isoWeekYear:function(t){var e=Q(this,1,4).year;return null==t?e:this.add("y",t-e)},week:function(t){var e=this.lang().week(this);return null==t?e:this.add("d",7*(t-e))},isoWeek:function(t){var e=Q(this,1,4).week;return null==t?e:this.add("d",7*(t-e))},weekday:function(t){var e=(this.day()+7-this.lang()._week.dow)%7;return null==t?e:this.add("d",t-e)},isoWeekday:function(t){return null==t?this.day()||7:this.day(this.day()%7?t:t-7)},get:function(t){return t=v(t),this[t]()},set:function(t,e){return t=v(t),"function"==typeof this[t]&&this[t](e),this},lang:function(t){return t===i?this._lang:(this._lang=N(t),this)}}),re=0;re-1?!1:"INPUT"==i||"SELECT"==i||"TEXTAREA"==i||e.contentEditable&&"true"==e.contentEditable}function o(t,e){return t.sort().join(",")===e.sort().join(",")}function r(t){t=t||{};var e,i=!1;for(e in M)t[e]?i=!0:M[e]=0;i||(I=!1)}function a(t,e,i,n,s){var r,a,h=[];if(!x[t])return[];for("keyup"==i&&u(t)&&(e=[t]),r=0;r95&&112>t||w.hasOwnProperty(t)&&(_[w[t]]=t)}return _}function g(t,e,i){return i||(i=f()[t]?"keydown":"keypress"),"keypress"==i&&e.length&&(i="keydown"),i}function m(t,e,i,s){M[t]=0,s||(s=g(e[0],[]));var o,a=function(){I=s,++M[t],p()},h=function(t){l(i,t),"keyup"!==s&&(D=n(t)),setTimeout(r,10)};for(o=0;o1)return m(t,l,e,i);for(h="+"===t?["+"]:t.split("+"),o=0;o":".","?":"/","|":"\\"},E={option:"alt",command:"meta","return":"enter",escape:"esc"},x={},C={},M={},D=!1,I=!1,N=1;20>N;++N)w[111+N]="f"+N;for(N=0;9>=N;++N)w[N+96]=N;i(document,"keypress",d),i(document,"keydown",d),i(document,"keyup",d);var O={bind:function(t,e,i){return y(t instanceof Array?t:[t],e,i),C[t+":"+i]=e,this},unbind:function(t,e){return C[t+":"+e]&&(delete C[t+":"+e],this.bind(t,function(){},e)),this},trigger:function(t,e){return C[t+":"+e](),this},reset:function(){return x={},C={},this}};e.exports=O},{}]},{},[1])(1)}); \ No newline at end of file diff --git a/examples/graph/02_random_nodes.html b/examples/graph/02_random_nodes.html index f5a05364..a900ccbd 100755 --- a/examples/graph/02_random_nodes.html +++ b/examples/graph/02_random_nodes.html @@ -57,6 +57,7 @@ j++; } + var from = i; var to = j; edges.push({ diff --git a/examples/graph/21_data_manipulation.html b/examples/graph/21_data_manipulation.html index d2c3ba7b..4b7236bf 100644 --- a/examples/graph/21_data_manipulation.html +++ b/examples/graph/21_data_manipulation.html @@ -220,7 +220,7 @@ length: 50 }, stabilize: false, - clustering:true, + clustering:false, navigation: true, keyboard: true, dataManipulationToolbar: true diff --git a/examples/graph/22_les_miserables.html b/examples/graph/22_les_miserables.html new file mode 100644 index 00000000..d6919f3f --- /dev/null +++ b/examples/graph/22_les_miserables.html @@ -0,0 +1,373 @@ + + + + Graph | Multiline text + + + + + + + + + +
    + + diff --git a/src/graph/ClusterMixin.js b/src/graph/ClusterMixin.js index 4cf7a6e6..f63c404f 100644 --- a/src/graph/ClusterMixin.js +++ b/src/graph/ClusterMixin.js @@ -654,7 +654,7 @@ var ClusterMixin = { /** * This function will apply the changes made to the remainingEdges during the formation of the clusters. - * This is a seperate function to allow for level-wise collapsing of the node tree. + * This is a seperate function to allow for level-wise collapsing of the node barnesHutTree. * It has to be called if a level is collapsed. It is called by _formClusters(). * @private */ diff --git a/src/graph/Edge.js b/src/graph/Edge.js index 145dac2b..e61b9083 100644 --- a/src/graph/Edge.js +++ b/src/graph/Edge.js @@ -82,10 +82,10 @@ Edge.prototype.setProperties = function(properties, constants) { if (properties.fontSize !== undefined) {this.fontSize = properties.fontSize;} if (properties.fontFace !== undefined) {this.fontFace = properties.fontFace;} } - if (properties.title !== undefined) {this.title = properties.title;} - if (properties.width !== undefined) {this.width = properties.width;} - if (properties.value !== undefined) {this.value = properties.value;} - if (properties.length !== undefined) {this.length = properties.length;} + if (properties.title !== undefined) {this.title = properties.title;} + if (properties.width !== undefined) {this.width = properties.width;} + if (properties.value !== undefined) {this.value = properties.value;} + if (properties.length !== undefined) {this.length = properties.length;} // Added to support dashed lines // David Jordan diff --git a/src/graph/Graph.js b/src/graph/Graph.js index 408ab33c..25367a32 100644 --- a/src/graph/Graph.js +++ b/src/graph/Graph.js @@ -20,15 +20,13 @@ function Graph (container, data, options) { this.stabilize = true; // stabilize before displaying the graph this.selectable = true; - this.forceFactor = 50000; - // set constant values this.constants = { nodes: { radiusMin: 5, radiusMax: 20, radius: 5, - distance: 100, // px + distance: 100, // px shape: 'ellipse', image: undefined, widthMin: 16, // px @@ -97,7 +95,7 @@ function Graph (container, data, options) { dataManipulationToolbar: { enabled: false }, - minVelocity: 2, // px/s + minVelocity: 0.2, // px/s maxIterations: 1000 // maximum number of iteration to stabilize }; @@ -113,6 +111,9 @@ function Graph (container, data, options) { this.yIncrement = 0; this.zoomIncrement = 0; + // load the force calculation functions, grouped under the physics system. + this._loadPhysicsSystem(); + // create a frame and canvas this._create(); @@ -635,6 +636,7 @@ Graph.prototype._createKeyBinds = function() { this.mousetrap.bind("pagedown",this._zoomOut.bind(me),"keydown"); this.mousetrap.bind("pagedown",this._stopZoom.bind(me), "keyup"); } + this.mousetrap.bind("b",this._formBarnesHutTree.bind(me)); if (this.constants.dataManipulationToolbar.enabled == true) { this.mousetrap.bind("escape",this._createManipulatorBar.bind(me)); @@ -1209,7 +1211,7 @@ Graph.prototype._addNodes = function(ids) { if (!node.isFixed() && this.createNodeOnClick != true) { // TODO: position new nodes in a smarter way! - var radius = this.constants.edges.length * 2; + var radius = this.constants.edges.length; var count = ids.length; var angle = 2 * Math.PI * (i / count); node.x = radius * Math.cos(angle); @@ -1494,6 +1496,8 @@ Graph.prototype._redraw = function() { this._doInAllSectors("_drawEdges",ctx); this._doInAllSectors("_drawNodes",ctx,true); + //this._drawTree(ctx,"#F00F0F"); + // restore original scaling and translation ctx.restore(); @@ -1669,233 +1673,9 @@ Graph.prototype._doStabilize = function() { count++; } this.zoomToFit(); - - // var end = new Date(); - - // console.log('Stabilized in ' + (end-start) + ' ms, ' + count + ' iterations' ); // TODO: cleanup -}; - - -/** - * Before calculating the forces, we check if we need to cluster to keep up performance and we check - * if there is more than one node. If it is just one node, we dont calculate anything. - * - * @private - */ -Graph.prototype._initializeForceCalculation = function() { - // stop calculation if there is only one node - if (this.nodeIndices.length == 1) { - this.nodes[this.nodeIndices[0]]._setForce(0,0); - } - else { - // if there are too many nodes on screen, we cluster without repositioning - if (this.nodeIndices.length > this.constants.clustering.clusterThreshold && this.constants.clustering.enabled == true) { - this.clusterToFit(this.constants.clustering.reduceToNodes, false); - } - - // we now start the force calculation - this._calculateForces(); - } }; -/** - * Calculate the external forces acting on the nodes - * Forces are caused by: edges, repulsing forces between nodes, gravity - * @private - */ -Graph.prototype._calculateForces = function() { -// var screenCenterPos = {"x":(0.5*(this.canvasTopLeft.x + this.canvasBottomRight.x)), -// "y":(0.5*(this.canvasTopLeft.y + this.canvasBottomRight.y))} - // create a local edge to the nodes and edges, that is faster - var dx, dy, angle, distance, fx, fy, - repulsingForce, springForce, length, edgeLength, - node, node1, node2, edge, edgeId, i, j, nodeId, xCenter, yCenter; - var clusterSize; - var nodes = this.nodes; - var edges = this.edges; - - // Gravity is required to keep separated groups from floating off - // the forces are reset to zero in this loop by using _setForce instead - // of _addForce - var gravity = 0.08 * this.forceFactor; - for (i = 0; i < this.nodeIndices.length; i++) { - node = nodes[this.nodeIndices[i]]; - // gravity does not apply when we are in a pocket sector - if (this._sector() == "default") { - dx = -node.x;// + screenCenterPos.x; - dy = -node.y;// + screenCenterPos.y; - - angle = Math.atan2(dy, dx); - fx = Math.cos(angle) * gravity; - fy = Math.sin(angle) * gravity; - } - else { - fx = 0; - fy = 0; - } - node._setForce(fx, fy); - - node.updateDamping(this.nodeIndices.length); - } - - // repulsing forces between nodes - var minimumDistance = this.constants.nodes.distance, - steepness = 10; // higher value gives steeper slope of the force around the given minimumDistance - - - // we loop from i over all but the last entree in the array - // j loops from i+1 to the last. This way we do not double count any of the indices, nor i == j - var a_base = (-2/3); var b = 4/3; - for (i = 0; i < this.nodeIndices.length-1; i++) { - node1 = nodes[this.nodeIndices[i]]; - for (j = i+1; j < this.nodeIndices.length; j++) { - node2 = nodes[this.nodeIndices[j]]; - clusterSize = (node1.clusterSize + node2.clusterSize - 2); - dx = node2.x - node1.x; - dy = node2.y - node1.y; - distance = Math.sqrt(dx * dx + dy * dy); - - - // clusters have a larger region of influence - minimumDistance = (clusterSize == 0) ? this.constants.nodes.distance : (this.constants.nodes.distance * (1 + clusterSize * this.constants.clustering.distanceAmplification)); - var a = a_base / minimumDistance; - if (distance < 2*minimumDistance) { // at 2.0 * the minimum distance, the force is 0.000045 - angle = Math.atan2(dy, dx); - - if (distance < 0.5*minimumDistance) { // at 0.5 * the minimum distance, the force is 0.993307 - repulsingForce = 1.0; - } - else { - // TODO: correct factor for repulsing force - //repulsingForce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force - //repulsingForce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force - //repulsingForce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)); // TODO: customize the repulsing force - repulsingForce = a * distance + b; // TODO: test the approximation of the function above - } - // amplify the repulsion for clusters. - repulsingForce *= (clusterSize == 0) ? 1 : 1 + clusterSize * this.constants.clustering.forceAmplification; - repulsingForce *= this.forceFactor; - - fx = Math.cos(angle) * repulsingForce; - fy = Math.sin(angle) * repulsingForce ; - - node1._addForce(-fx, -fy); - node2._addForce(fx, fy); - } - } - } - -/* - // repulsion of the edges on the nodes and - for (var nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - node = nodes[nodeId]; - for(var edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - - // get the center of the edge - xCenter = edge.from.x+(edge.to.x - edge.from.x)/2; - yCenter = edge.from.y+(edge.to.y - edge.from.y)/2; - - // calculate normally distributed force - dx = node.x - xCenter; - dy = node.y - yCenter; - distance = Math.sqrt(dx * dx + dy * dy); - if (distance < 2*minimumDistance) { // at 2.0 * the minimum distance, the force is 0.000045 - angle = Math.atan2(dy, dx); - - if (distance < 0.5*minimumDistance) { // at 0.5 * the minimum distance, the force is 0.993307 - repulsingForce = 1.0; - } - else { - // TODO: correct factor for repulsing force - //var repulsingforce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force - //repulsingforce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ), // TODO: customize the repulsing force - repulsingForce = 1 / (1 + Math.exp((distance / (minimumDistance / 2) - 1) * steepness)); // TODO: customize the repulsing force - } - fx = Math.cos(angle) * repulsingForce; - fy = Math.sin(angle) * repulsingForce; - node._addForce(fx, fy); - edge.from._addForce(-fx/2,-fy/2); - edge.to._addForce(-fx/2,-fy/2); - } - } - } - } - } -*/ - - // forces caused by the edges, modelled as springs - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.connected) { - // only calculate forces if nodes are in the same sector - if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { - clusterSize = (edge.to.clusterSize + edge.from.clusterSize - 2); - dx = (edge.to.x - edge.from.x); - dy = (edge.to.y - edge.from.y); - //edgeLength = (edge.from.width + edge.from.height + edge.to.width + edge.to.height)/2 || edge.length; // TODO: dmin - //edgeLength = (edge.from.width + edge.to.width)/2 || edge.length; // TODO: dmin - //edgeLength = 20 + ((edge.from.width + edge.to.width) || 0) / 2; - edgeLength = edge.length; - // this implies that the edges between big clusters are longer - edgeLength += clusterSize * this.constants.clustering.edgeGrowth; - length = Math.sqrt(dx * dx + dy * dy); - angle = Math.atan2(dy, dx); - - springForce = edge.stiffness * (edgeLength - length) * this.forceFactor; - - fx = Math.cos(angle) * springForce; - fy = Math.sin(angle) * springForce; - - edge.from._addForce(-fx, -fy); - edge.to._addForce(fx, fy); - } - } - } - } -/* - // TODO: re-implement repulsion of edges - - // repulsing forces between edges - var minimumDistance = this.constants.edges.distance, - steepness = 10; // higher value gives steeper slope of the force around the given minimumDistance - for (var l = 0; l < edges.length; l++) { - //Keep distance from other edge centers - for (var l2 = l + 1; l2 < this.edges.length; l2++) { - //var dmin = (nodes[n].width + nodes[n].height + nodes[n2].width + nodes[n2].height) / 1 || minimumDistance, // TODO: dmin - //var dmin = (nodes[n].width + nodes[n2].width)/2 || minimumDistance, // TODO: dmin - //dmin = 40 + ((nodes[n].width/2 + nodes[n2].width/2) || 0), - var lx = edges[l].from.x+(edges[l].to.x - edges[l].from.x)/2, - ly = edges[l].from.y+(edges[l].to.y - edges[l].from.y)/2, - l2x = edges[l2].from.x+(edges[l2].to.x - edges[l2].from.x)/2, - l2y = edges[l2].from.y+(edges[l2].to.y - edges[l2].from.y)/2, - - // calculate normally distributed force - dx = l2x - lx, - dy = l2y - ly, - distance = Math.sqrt(dx * dx + dy * dy), - angle = Math.atan2(dy, dx), - - - // TODO: correct factor for repulsing force - //var repulsingforce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force - //repulsingforce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ), // TODO: customize the repulsing force - repulsingforce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)), // TODO: customize the repulsing force - fx = Math.cos(angle) * repulsingforce, - fy = Math.sin(angle) * repulsingforce; - - edges[l].from._addForce(-fx, -fy); - edges[l].to._addForce(-fx, -fy); - edges[l2].from._addForce(fx, fy); - edges[l2].to._addForce(fx, fy); - } - } -*/ -}; /** @@ -1924,14 +1704,25 @@ Graph.prototype._isMoving = function(vmin) { * @private */ Graph.prototype._discreteStepNodes = function() { - var interval = 0.01; + var interval = 1.0; var nodes = this.nodes; - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - nodes[id].discreteStep(interval); + + this.constants.maxVelocity = 30; + + if (this.constants.maxVelocity > 0) { + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + nodes[id].discreteStepLimited(interval, this.constants.maxVelocity); + } + } + } + else { + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + nodes[id].discreteStep(interval); + } } } - var vmin = this.constants.minVelocity; this.moving = this._isMoving(vmin); }; @@ -1979,7 +1770,6 @@ Graph.prototype.start = function() { //this.time = this.end - this.startTime; //console.log('refresh time: ' + this.time); //this.startTime = window.performance.now(); - }, this.renderTimestep); } } @@ -2018,6 +1808,22 @@ Graph.prototype.toggleFreeze = function() { } }; + + +/** + * Mixin the physics system and initialize the parameters required. + * + * @private + */ +Graph.prototype._loadPhysicsSystem = function() { + for (var mixinFunction in physicsMixin) { + if (physicsMixin.hasOwnProperty(mixinFunction)) { + Graph.prototype[mixinFunction] = physicsMixin[mixinFunction]; + } + } +}; + + /** * Mixin the cluster system and initialize the parameters required. * diff --git a/src/graph/Node.js b/src/graph/Node.js index 43f34f1e..1225369b 100644 --- a/src/graph/Node.js +++ b/src/graph/Node.js @@ -21,6 +21,7 @@ * retrieving group properties * @param {Object} constants An object with default values for * example for the color + * */ function Node(properties, imagelist, grouplist, constants) { this.selected = false; @@ -73,8 +74,7 @@ function Node(properties, imagelist, grouplist, constants) { this.vx = 0.0; // velocity x this.vy = 0.0; // velocity y this.minForce = constants.minForce; - this.damping = 0.9; - this.dampingFactor = 75; + this.damping = 0.9; // this is manipulated in the updateDaming function this.graphScaleInv = 1; this.canvasTopLeft = {"x": -300, "y": -300}; @@ -128,7 +128,7 @@ Node.prototype.detachEdge = function(edge) { * @private */ Node.prototype._updateMass = function() { - this.mass = 1 + 0.6 * this.edges.length; // kg + this.mass = 1;// + 0.6 * this.edges.length; // kg }; /** @@ -390,6 +390,29 @@ Node.prototype.discreteStep = function(interval) { }; + +/** + * Perform one discrete step for the node + * @param {number} interval Time interval in seconds + */ +Node.prototype.discreteStepLimited = function(interval, maxVelocity) { + if (!this.xFixed) { + var dx = -this.damping * this.vx; // damping force + var ax = (this.fx + dx) / this.mass; // acceleration + this.vx += ax * interval; // velocity + this.vx = (Math.abs(this.vx) > maxVelocity) ? ((this.vx > 0) ? maxVelocity : -maxVelocity) : this.vx; + this.x += this.vx * interval; // position + } + + if (!this.yFixed) { + var dy = -this.damping * this.vy; // damping force + var ay = (this.fy + dy) / this.mass; // acceleration + this.vy += ay * interval; // velocity + this.vy = (Math.abs(this.vy) > maxVelocity) ? ((this.vy > 0) ? maxVelocity : -maxVelocity) : this.vy; + this.y += this.vy * interval; // position + } +}; + /** * Check if this node has a fixed x and y position * @return {boolean} true if fixed, false if not @@ -950,8 +973,7 @@ Node.prototype.setScale = function(scale) { * @param {Number} numberOfNodes */ Node.prototype.updateDamping = function(numberOfNodes) { - this.damping = (0.8 + 0.1*this.clusterSize * (1 + Math.pow(numberOfNodes,-2))); - this.damping *= this.dampingFactor; + this.damping = (1 + 0.1*this.clusterSize * (1 + Math.pow(numberOfNodes,-2))); }; diff --git a/src/graph/SelectionMixin.js b/src/graph/SelectionMixin.js index 7252ac15..5ed2272a 100644 --- a/src/graph/SelectionMixin.js +++ b/src/graph/SelectionMixin.js @@ -213,9 +213,7 @@ var SelectionMixin = { this.selectionObj = {}; if (doNotTrigger == false) { - this._trigger('select', { - nodes: this.getSelection() - }); + this._trigger('select', this.getSelection()); } }, @@ -242,9 +240,7 @@ var SelectionMixin = { } if (doNotTrigger == false) { - this._trigger('select', { - nodes: this.getSelection() - }); + this._trigger('select', this.getSelection()); } }, @@ -399,9 +395,7 @@ var SelectionMixin = { this._removeFromSelection(object); } if (doNotTrigger == false) { - this._trigger('select', { - nodes: this.getSelection() - }); + this._trigger('select', this.getSelection()); } }, diff --git a/src/graph/manipulationMixin.js b/src/graph/manipulationMixin.js index 9f1d6ad0..9bc261bb 100644 --- a/src/graph/manipulationMixin.js +++ b/src/graph/manipulationMixin.js @@ -442,6 +442,8 @@ var manipulationMixin = { /** * delete everything in the selection + * TODO : place the alert in the gui. + * * * @private */ @@ -460,4 +462,4 @@ var manipulationMixin = { } -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/graph/physicsMixin.js b/src/graph/physicsMixin.js new file mode 100644 index 00000000..c8edbd1c --- /dev/null +++ b/src/graph/physicsMixin.js @@ -0,0 +1,539 @@ +/** + * Created by Alex on 2/6/14. + */ + + +var physicsMixin = { + + /** + * Before calculating the forces, we check if we need to cluster to keep up performance and we check + * if there is more than one node. If it is just one node, we dont calculate anything. + * + * @private + */ + _initializeForceCalculation : function() { + // stop calculation if there is only one node + if (this.nodeIndices.length == 1) { + this.nodes[this.nodeIndices[0]]._setForce(0,0); + } + else { + // if there are too many nodes on screen, we cluster without repositioning + if (this.nodeIndices.length > this.constants.clustering.clusterThreshold && this.constants.clustering.enabled == true) { + this.clusterToFit(this.constants.clustering.reduceToNodes, false); + } + + // we now start the force calculation + this._calculateForcesBarnesHut(); +// this._calculateForcesOriginal(); + } + }, + + + /** + * Calculate the external forces acting on the nodes + * Forces are caused by: edges, repulsing forces between nodes, gravity + * @private + */ + _calculateForcesOriginal : function() { + // Gravity is required to keep separated groups from floating off + // the forces are reset to zero in this loop by using _setForce instead + // of _addForce + +// var startTimeAll = Date.now(); + + this._calculateGravitationalForces(1); + +// var startTimeRepulsion = Date.now(); + // All nodes repel eachother. + this._calculateRepulsionForces(); + +// var endTimeRepulsion = Date.now(); + + // the edges are strings + this._calculateSpringForces(1); + +// var endTimeAll = Date.now(); + +// echo("Time repulsion part:", endTimeRepulsion - startTimeRepulsion); +// echo("Time total force calc:", endTimeAll - startTimeAll); + }, + + /** + * Calculate the external forces acting on the nodes + * Forces are caused by: edges, repulsing forces between nodes, gravity + * @private + */ + _calculateForcesBarnesHut : function() { + // Gravity is required to keep separated groups from floating off + // the forces are reset to zero in this loop by using _setForce instead + // of _addForce + +// var startTimeAll = Date.now(); + + this._clearForces(); + +// var startTimeRepulsion = Date.now(); + // All nodes repel eachother. + this._calculateBarnesHutForces(); + +// var endTimeRepulsion = Date.now(); + + // the edges are strings + this._calculateSpringForces(1); + +// var endTimeAll = Date.now(); + +// echo("Time repulsion part:", endTimeRepulsion - startTimeRepulsion); +// echo("Time total force calc:", endTimeAll - startTimeAll); + }, + + + _clearForces : function() { + var node; + var nodes = this.nodes; + + for (var i = 0; i < this.nodeIndices.length; i++) { + node = nodes[this.nodeIndices[i]]; + node._setForce(0, 0); + node.updateDamping(this.nodeIndices.length); + } + }, + + _calculateGravitationalForces : function(boost) { + var dx, dy, angle, fx, fy, node, i; + var nodes = this.nodes; + var gravity = 0.08 * boost; + + for (i = 0; i < this.nodeIndices.length; i++) { + node = nodes[this.nodeIndices[i]]; + // gravity does not apply when we are in a pocket sector + if (this._sector() == "default") { + dx = -node.x;// + screenCenterPos.x; + dy = -node.y;// + screenCenterPos.y; + + angle = Math.atan2(dy, dx); + fx = Math.cos(angle) * gravity; + fy = Math.sin(angle) * gravity; + } + else { + fx = 0; + fy = 0; + } + node._setForce(fx, fy); + node.updateDamping(this.nodeIndices.length); + } + }, + + _calculateRepulsionForces : function() { + var dx, dy, angle, distance, fx, fy, clusterSize, + repulsingForce, node1, node2, i, j; + var nodes = this.nodes; + + // approximation constants + var a_base = (-2/3); + var b = 4/3; + + // repulsing forces between nodes + var minimumDistance = this.constants.nodes.distance; + //var steepness = 10; + + // we loop from i over all but the last entree in the array + // j loops from i+1 to the last. This way we do not double count any of the indices, nor i == j + for (i = 0; i < this.nodeIndices.length-1; i++) { + node1 = nodes[this.nodeIndices[i]]; + for (j = i+1; j < this.nodeIndices.length; j++) { + node2 = nodes[this.nodeIndices[j]]; + clusterSize = (node1.clusterSize + node2.clusterSize - 2); + dx = node2.x - node1.x; + dy = node2.y - node1.y; + distance = Math.sqrt(dx * dx + dy * dy); + + + // clusters have a larger region of influence + minimumDistance = (clusterSize == 0) ? this.constants.nodes.distance : (this.constants.nodes.distance * (1 + clusterSize * this.constants.clustering.distanceAmplification)); + var a = a_base / minimumDistance; + if (distance < 2*minimumDistance) { // at 2.0 * the minimum distance, the force is 0.000045 + angle = Math.atan2(dy, dx); + + if (distance < 0.5*minimumDistance) { // at 0.5 * the minimum distance, the force is 0.993307 + repulsingForce = 1.0; + } + else { + repulsingForce = a * distance + b; // linear approx of 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)) + } + // amplify the repulsion for clusters. + repulsingForce *= (clusterSize == 0) ? 1 : 1 + clusterSize * this.constants.clustering.forceAmplification; + + fx = Math.cos(angle) * repulsingForce; + fy = Math.sin(angle) * repulsingForce ; + + node1._addForce(-fx, -fy); + node2._addForce(fx, fy); + } + } + } + }, + + _calculateSpringForces : function(boost) { + var dx, dy, angle, fx, fy, springForce, length, edgeLength, edge, edgeId, clusterSize; + var edges = this.edges; + + // forces caused by the edges, modelled as springs + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.connected) { + // only calculate forces if nodes are in the same sector + if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { + clusterSize = (edge.to.clusterSize + edge.from.clusterSize - 2); + dx = (edge.to.x - edge.from.x); + dy = (edge.to.y - edge.from.y); + + edgeLength = edge.length; + + // this implies that the edges between big clusters are longer + edgeLength += clusterSize * this.constants.clustering.edgeGrowth; + length = Math.sqrt(dx * dx + dy * dy); + angle = Math.atan2(dy, dx); + + springForce = 0.02 * (edgeLength - length) * boost; + + fx = Math.cos(angle) * springForce; + fy = Math.sin(angle) * springForce; + + edge.from._addForce(-fx, -fy); + edge.to._addForce(fx, fy); + } + } + } + } + }, + + _calculateBarnesHutForces : function() { + this._formBarnesHutTree(); + + var nodes = this.nodes; + var nodeIndices = this.nodeIndices; + var node; + var nodeCount = nodeIndices.length; + + var barnesHutTree = this.barnesHutTree; + + this.theta = 0.2; + this.graviationalConstant = -10000; + + + // place the nodes one by one recursively + for (var i = 0; i < nodeCount; i++) { + node = nodes[nodeIndices[i]]; + // starting with root is irrelevant, it never passes the BarnesHut condition + this._getForceContribution(barnesHutTree.root.children.NW,node); + this._getForceContribution(barnesHutTree.root.children.NE,node); + this._getForceContribution(barnesHutTree.root.children.SW,node); + this._getForceContribution(barnesHutTree.root.children.SE,node); + } + }, + + _getForceContribution : function(parentBranch,node) { + // we get no force contribution from an empty region + if (parentBranch.childrenCount > 0) { + var dx,dy,distance; + + // get the distance from the center of mass to the node. + dx = parentBranch.CenterOfMass.x - node.x; + dy = parentBranch.CenterOfMass.y - node.y; + distance = Math.sqrt(dx * dx + dy * dy); + + if (distance > 0) { // distance is 0 if it looks to apply a force on itself. + // we invert it here because we need the inverted distance for the force calculation too. + var distanceInv = 1/distance; + // BarnesHut condition + if (parentBranch.size * distanceInv > this.theta) { + // Did not pass the condition, go into children if available + if (parentBranch.childrenCount == 4) { + this._getForceContribution(parentBranch.children.NW,node); + this._getForceContribution(parentBranch.children.NE,node); + this._getForceContribution(parentBranch.children.SW,node); + this._getForceContribution(parentBranch.children.SE,node); + } + else { // parentBranch must have only one node, if it was empty we wouldnt be here + this._getForceOnNode(parentBranch, node, dx ,dy, distanceInv); + } + } + else { + this._getForceOnNode(parentBranch, node, dx ,dy, distanceInv); + } + } + } + }, + + _getForceOnNode : function(parentBranch, node, dx ,dy, distanceInv) { + // even if the parentBranch only has one node, its Center of Mass is at the right place (the node in this case). + var gravityForce = this.graviationalConstant * parentBranch.mass * node.mass * distanceInv * distanceInv; + var angle = Math.atan2(dy, dx); + var fx = Math.cos(angle) * gravityForce; + var fy = Math.sin(angle) * gravityForce; + node._addForce(fx, fy); + }, + + + _formBarnesHutTree : function() { + var nodes = this.nodes; + var nodeIndices = this.nodeIndices; + var node; + var nodeCount = nodeIndices.length; + + var minX = Number.MAX_VALUE, + minY = Number.MAX_VALUE, + maxX =-Number.MAX_VALUE, + maxY =-Number.MAX_VALUE; + + // get the range of the nodes + for (var i = 0; i < nodeCount; i++) { + var x = nodes[nodeIndices[i]].x; + var y = nodes[nodeIndices[i]].y; + if (x < minX) { minX = x; } + if (x > maxX) { maxX = x; } + if (y < minY) { minY = y; } + if (y > maxY) { maxY = y; } + } + // make the range a square + var sizeDiff = Math.abs(maxX - minX) - Math.abs(maxY - minY); // difference between X and Y + if (sizeDiff > 0) {minY -= 0.5 * sizeDiff; maxY += 0.5 * sizeDiff;} // xSize > ySize + else {minX += 0.5 * sizeDiff; maxY -= 0.5 * sizeDiff;} // xSize < ySize + + + // construct the barnesHutTree + var barnesHutTree = {root:{ + CenterOfMass:{x:0,y:0}, // Center of Mass + mass:0, + range:{minX:minX,maxX:maxX,minY:minY,maxY:maxY}, + size: Math.abs(maxX - minX), + children: {data:null}, + childrenCount: 4 + }}; + this._splitBranch(barnesHutTree.root); + + // place the nodes one by one recursively + for (i = 0; i < nodeCount; i++) { + node = nodes[nodeIndices[i]]; + this._placeInTree(barnesHutTree.root,node); + } + + // make global + this.barnesHutTree = barnesHutTree + }, + + + _updateBranchMass : function(parentBranch, node) { + var totalMass = parentBranch.mass + node.mass; + var totalMassInv = 1/totalMass; + + parentBranch.CenterOfMass.x = parentBranch.CenterOfMass.x * parentBranch.mass + node.x * node.mass; + parentBranch.CenterOfMass.x *= totalMassInv; + + parentBranch.CenterOfMass.y = parentBranch.CenterOfMass.y * parentBranch.mass + node.y * node.mass; + parentBranch.CenterOfMass.y *= totalMassInv; + + parentBranch.mass = totalMass; + }, + + _placeInTree : function(parentBranch,node) { + // update the mass of the branch. + this._updateBranchMass(parentBranch,node); + + if (parentBranch.children.NW.range.maxX > node.x) { // in NW or SW + if (parentBranch.children.NW.range.maxY > node.y) { // in NW + this._placeInRegion(parentBranch,node,"NW"); + } + else { // in SW + this._placeInRegion(parentBranch,node,"SW"); + } + } + else { // in NE or SE + if (parentBranch.children.NE.range.maxY > node.y) { // in NE + this._placeInRegion(parentBranch,node,"NE"); + } + else { // in SE + this._placeInRegion(parentBranch,node,"SE"); + } + } + }, + + _placeInRegion : function(parentBranch,node,region) { + switch (parentBranch.children[region].childrenCount) { + case 0: // place node here + parentBranch.children[region].children.data = node; + parentBranch.children[region].childrenCount = 1; + this._updateBranchMass(parentBranch.children[region],node); + break; + case 1: // convert into children + this._splitBranch(parentBranch.children[region]); + this._placeInTree(parentBranch.children[region],node); + break; + case 4: // place in branch + this._placeInTree(parentBranch.children[region],node); + break; + } + }, + + _splitBranch : function(parentBranch) { + // if the branch is filled with a node, replace the node in the new subset. + var containedNode = null; + if (parentBranch.childrenCount == 1) { + containedNode = parentBranch.children.data; + parentBranch.mass = 0; parentBranch.CenterOfMass.x = 0; parentBranch.CenterOfMass.y = 0; + } + parentBranch.childrenCount = 4; + parentBranch.children.data = null; + this._insertRegion(parentBranch,"NW"); + this._insertRegion(parentBranch,"NE"); + this._insertRegion(parentBranch,"SW"); + this._insertRegion(parentBranch,"SE"); + + if (containedNode != null) { + this._placeInTree(parentBranch,containedNode); + } + }, + + + /** + * This function subdivides the region into four new segments. + * Specifically, this inserts a single new segment. + * It fills the children section of the parentBranch + * + * @param parentBranch + * @param region + * @param parentRange + * @private + */ + _insertRegion : function(parentBranch, region) { + var minX,maxX,minY,maxY; + switch (region) { + case "NW": + minX = parentBranch.range.minX; + maxX = parentBranch.range.minX + parentBranch.size; + minY = parentBranch.range.minY; + maxY = parentBranch.range.minY + parentBranch.size; + break; + case "NE": + minX = parentBranch.range.minX + parentBranch.size; + maxX = parentBranch.range.maxX; + minY = parentBranch.range.minY; + maxY = parentBranch.range.minY + parentBranch.size; + break; + case "SW": + minX = parentBranch.range.minX; + maxX = parentBranch.range.minX + parentBranch.size; + minY = parentBranch.range.minY + parentBranch.size; + maxY = parentBranch.range.maxY; + break; + case "SE": + minX = parentBranch.range.minX + parentBranch.size; + maxX = parentBranch.range.maxX; + minY = parentBranch.range.minY + parentBranch.size; + maxY = parentBranch.range.maxY; + break; + } + + parentBranch.children[region] = { + CenterOfMass:{x:0,y:0}, + mass:0, + range:{minX:minX,maxX:maxX,minY:minY,maxY:maxY}, + size: 0.5 * parentBranch.size, + children: {data:null}, + childrenCount: 0 + }; + }, + + + _drawTree : function(ctx,color) { + if (this.barnesHutTree !== undefined) { + + ctx.lineWidth = 2; + + this._drawBranch(this.barnesHutTree.root,ctx,color); + } + }, + + _drawBranch : function(branch,ctx,color) { + if (color === undefined) { + color = "#FF0000"; + } + + if (branch.childrenCount == 4) { + this._drawBranch(branch.children.NW,ctx); + this._drawBranch(branch.children.NE,ctx); + this._drawBranch(branch.children.SE,ctx); + this._drawBranch(branch.children.SW,ctx); + } + ctx.strokeStyle = color; + ctx.beginPath(); + ctx.moveTo(branch.range.minX,branch.range.minY); + ctx.lineTo(branch.range.maxX,branch.range.minY); + ctx.stroke(); + + ctx.beginPath(); + ctx.moveTo(branch.range.maxX,branch.range.minY); + ctx.lineTo(branch.range.maxX,branch.range.maxY); + ctx.stroke(); + + ctx.beginPath(); + ctx.moveTo(branch.range.maxX,branch.range.maxY); + ctx.lineTo(branch.range.minX,branch.range.maxY); + ctx.stroke(); + + ctx.beginPath(); + ctx.moveTo(branch.range.minX,branch.range.maxY); + ctx.lineTo(branch.range.minX,branch.range.minY); + ctx.stroke(); + + /* + if (branch.mass > 0) { + ctx.circle(branch.CenterOfMass.x, branch.CenterOfMass.y, 3*branch.mass); + ctx.stroke(); + } + */ + } + + + + + + + + + + + + + + + + + + +}; + +function echo() { + switch (arguments.length) { + case 1: + echoN1(arguments[0]); break; + case 2: + echoN2(arguments[0],arguments[1]); break; + case 3: + echoN3(arguments[0],arguments[1],arguments[2]); break; + } +} + +function echoN1(message) { + console.log(message); +} + +function echoN2(message1,message2) { + console.log(message1,message2); +} + +function echoN3(message1,message2,message3) { + console.log(message1,message2,message3); +} \ No newline at end of file From 2da8641aaa9a58f5b3ab9c62f886c2d178cc1a82 Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Sat, 8 Feb 2014 13:53:57 +0100 Subject: [PATCH 35/52] failed experiment to use branes Hut with repulsionfields. reverting. --- dist/vis.js | 20 ++++++++++---------- dist/vis.min.js | 12 ++++++------ examples/graph/22_les_miserables.html | 2 +- src/graph/Node.js | 16 ++++++++-------- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/dist/vis.js b/dist/vis.js index daedfde5..96804d48 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -4,8 +4,8 @@ * * A dynamic, browser-based visualization library. * - * @version 0.5.0-SNAPSHOT - * @date 2014-02-08 + * @version @@version + * @date @@date * * @license * Copyright (C) 2011-2014 Almende B.V, http://almende.com @@ -9150,13 +9150,13 @@ function Node(properties, imagelist, grouplist, constants) { this.clusterSizeRadiusFactor = constants.clustering.nodeScaling.radius; // mass, force, velocity - this.mass = 1; // kg (mass is adjusted for the number of connected edges) + this.mass = 1; // kg this.fx = 0.0; // external force x this.fy = 0.0; // external force y this.vx = 0.0; // velocity x this.vy = 0.0; // velocity y this.minForce = constants.minForce; - this.damping = 0.9; // this is manipulated in the updateDaming function + this.damping = 0.9; // this is manipulated in the updateDamping function this.graphScaleInv = 1; this.canvasTopLeft = {"x": -300, "y": -300}; @@ -9187,7 +9187,7 @@ Node.prototype.attachEdge = function(edge) { this.dynamicEdges.push(edge); } this.dynamicEdgesLength = this.dynamicEdges.length; - this._updateMass(); +// this._updateMass(); }; /** @@ -9201,7 +9201,7 @@ Node.prototype.detachEdge = function(edge) { this.dynamicEdges.splice(index, 1); } this.dynamicEdgesLength = this.dynamicEdges.length; - this._updateMass(); +// this._updateMass(); }; /** @@ -9209,9 +9209,9 @@ Node.prototype.detachEdge = function(edge) { * to it (more edges -> heavier node). * @private */ -Node.prototype._updateMass = function() { - this.mass = 1;// + 0.6 * this.edges.length; // kg -}; +//Node.prototype._updateMass = function() { +// this.mass = 1;// + 0.6 * this.edges.length; // kg +//}; /** * Set or overwrite properties for the node @@ -10055,7 +10055,7 @@ Node.prototype.setScale = function(scale) { * @param {Number} numberOfNodes */ Node.prototype.updateDamping = function(numberOfNodes) { - this.damping = (1 + 0.1*this.clusterSize * (1 + Math.pow(numberOfNodes,-2))); + this.damping = (0.9 + 0.1*this.clusterSize * (1 + Math.pow(numberOfNodes,-2))); }; diff --git a/dist/vis.min.js b/dist/vis.min.js index d32451d9..ebb86c98 100644 --- a/dist/vis.min.js +++ b/dist/vis.min.js @@ -5,7 +5,7 @@ * A dynamic, browser-based visualization library. * * @version 0.5.0-SNAPSHOT - * @date 2014-02-07 + * @date 2014-02-08 * * @license * Copyright (C) 2011-2014 Almende B.V, http://almende.com @@ -22,10 +22,10 @@ * License for the specific language governing permissions and limitations under * the License. */ -!function(t){if("object"==typeof exports)module.exports=t();else if("function"==typeof define&&define.amd)define(t);else{var e;"undefined"!=typeof window?e=window:"undefined"!=typeof global?e=global:"undefined"!=typeof self&&(e=self),e.vis=t()}}(function(){var define,module,exports;return function t(e,i,n){function s(r,a){if(!i[r]){if(!e[r]){var h="function"==typeof require&&require;if(!a&&h)return h(r,!0);if(o)return o(r,!0);throw new Error("Cannot find module '"+r+"'")}var l=i[r]={exports:{}};e[r][0].call(l.exports,function(t){var i=e[r][1][t];return s(i?i:t)},l,l.exports,t,e,i,n)}return i[r].exports}for(var o="function"==typeof require&&require,r=0;ri;++i)t.call(e||this,this[i],i,this)}),Array.prototype.map||(Array.prototype.map=function(t,e){var i,n,s;if(null==this)throw new TypeError(" this is null or not defined");var o=Object(this),r=o.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(e&&(i=e),n=new Array(r),s=0;r>s;){var a,h;s in o&&(a=o[s],h=t.call(i,a,s,o),n[s]=h),s++}return n}),Array.prototype.filter||(Array.prototype.filter=function(t){"use strict";if(null==this)throw new TypeError;var e=Object(this),i=e.length>>>0;if("function"!=typeof t)throw new TypeError;for(var n=[],s=arguments[1],o=0;i>o;o++)if(o in e){var r=e[o];t.call(s,r,o,e)&&n.push(r)}return n}),Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,e=!{toString:null}.propertyIsEnumerable("toString"),i=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],n=i.length;return function(s){if("object"!=typeof s&&"function"!=typeof s||null===s)throw new TypeError("Object.keys called on non-object");var o=[];for(var r in s)t.call(s,r)&&o.push(r);if(e)for(var a=0;n>a;a++)t.call(s,i[a])&&o.push(i[a]);return o}}()),Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s}),Object.create||(Object.create=function(t){function e(){}if(arguments.length>1)throw new Error("Object.create implementation only accepts the first parameter.");return e.prototype=t,new e}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s});var util={};util.isNumber=function(t){return t instanceof Number||"number"==typeof t},util.isString=function(t){return t instanceof String||"string"==typeof t},util.isDate=function(t){if(t instanceof Date)return!0;if(util.isString(t)){var e=ASPDateRegex.exec(t);if(e)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},util.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},util.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},util.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var n=arguments[e];for(var s in n)n.hasOwnProperty(s)&&void 0!==n[s]&&(t[s]=n[s])}return t},util.convert=function(t,e){var i;if(void 0===t)return void 0;if(null===t)return null;if(!e)return t;if("string"!=typeof e&&!(e instanceof String))throw new Error("Type must be a string");switch(e){case"boolean":case"Boolean":return Boolean(t);case"number":case"Number":return Number(t.valueOf());case"string":case"String":return String(t);case"Date":if(util.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(moment.isMoment(t))return new Date(t.valueOf());if(util.isString(t))return i=ASPDateRegex.exec(t),i?new Date(Number(i[1])):moment(t).toDate();throw new Error("Cannot convert object of type "+util.getType(t)+" to type Date");case"Moment":if(util.isNumber(t))return moment(t);if(t instanceof Date)return moment(t.valueOf());if(moment.isMoment(t))return moment(t);if(util.isString(t))return i=ASPDateRegex.exec(t),moment(i?Number(i[1]):t);throw new Error("Cannot convert object of type "+util.getType(t)+" to type Date");case"ISODate":if(util.isNumber(t))return new Date(t);if(t instanceof Date)return t.toISOString();if(moment.isMoment(t))return t.toDate().toISOString();if(util.isString(t))return i=ASPDateRegex.exec(t),i?new Date(Number(i[1])).toISOString():new Date(t).toISOString();throw new Error("Cannot convert object of type "+util.getType(t)+" to type ISODate");case"ASPDate":if(util.isNumber(t))return"/Date("+t+")/";if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(util.isString(t)){i=ASPDateRegex.exec(t);var n;return n=i?new Date(Number(i[1])).valueOf():new Date(t).valueOf(),"/Date("+n+")/"}throw new Error("Cannot convert object of type "+util.getType(t)+" to type ASPDate");default:throw new Error("Cannot convert object of type "+util.getType(t)+' to type "'+e+'"')}};var ASPDateRegex=/^\/?Date\((\-?\d+)/i;util.getType=function(t){var e=typeof t;return"object"==e?null==t?"null":t instanceof Boolean?"Boolean":t instanceof Number?"Number":t instanceof String?"String":t instanceof Array?"Array":t instanceof Date?"Date":"Object":"number"==e?"Number":"boolean"==e?"Boolean":"string"==e?"String":e},util.getAbsoluteLeft=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetLeft,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetLeft,n-=s.scrollLeft,s=s.offsetParent;return n},util.getAbsoluteTop=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetTop,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetTop,n-=s.scrollTop,s=s.offsetParent;return n},util.getPageY=function(t){if("pageY"in t)return t.pageY;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientY:t.clientY;var i=document.documentElement,n=document.body;return e+(i&&i.scrollTop||n&&n.scrollTop||0)-(i&&i.clientTop||n&&n.clientTop||0)},util.getPageX=function(t){if("pageY"in t)return t.pageX;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientX:t.clientX;var i=document.documentElement,n=document.body;return e+(i&&i.scrollLeft||n&&n.scrollLeft||0)-(i&&i.clientLeft||n&&n.clientLeft||0)},util.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},util.removeClassName=function(t,e){var i=t.className.split(" "),n=i.indexOf(e);-1!=n&&(i.splice(n,1),t.className=i.join(" "))},util.forEach=function(t,e){var i,n;if(t instanceof Array)for(i=0,n=t.length;n>i;i++)e(t[i],i,t);else for(i in t)t.hasOwnProperty(i)&&e(t[i],i,t)},util.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},util.addEventListener=function(t,e,i,n){t.addEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.addEventListener(e,i,n)):t.attachEvent("on"+e,i)},util.removeEventListener=function(t,e,i,n){t.removeEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.removeEventListener(e,i,n)):t.detachEvent("on"+e,i)},util.getTarget=function(t){t||(t=window.event);var e;return t.target?e=t.target:t.srcElement&&(e=t.srcElement),void 0!=e.nodeType&&3==e.nodeType&&(e=e.parentNode),e},util.stopPropagation=function(t){t||(t=window.event),t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},util.fakeGesture=function(t,e){var i=null;return Hammer.event.collectEventData(this,i,e)},util.preventDefault=function(t){t||(t=window.event),t.preventDefault?t.preventDefault():t.returnValue=!1},util.option={},util.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},util.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},util.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?String(t):e||null},util.option.asSize=function(t,e){return"function"==typeof t&&(t=t()),util.isString(t)?t:util.isNumber(t)?t+"px":e||null},util.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null},util.GiveDec=function GiveDec(Hex){return Value="A"==Hex?10:"B"==Hex?11:"C"==Hex?12:"D"==Hex?13:"E"==Hex?14:"F"==Hex?15:eval(Hex)},util.GiveHex=function(t){return Value=10==t?"A":11==t?"B":12==t?"C":13==t?"D":14==t?"E":15==t?"F":""+t},util.hexToRGB=function(t){t=t.replace("#","").toUpperCase();var e=util.GiveDec(t.substring(0,1)),i=util.GiveDec(t.substring(1,2)),n=util.GiveDec(t.substring(2,3)),s=util.GiveDec(t.substring(3,4)),o=util.GiveDec(t.substring(4,5)),r=util.GiveDec(t.substring(5,6)),a=16*e+i,h=16*n+s,i=16*o+r;return{r:a,g:h,b:i}},util.RGBToHex=function(t,e,i){var n=util.GiveHex(Math.floor(t/16)),s=util.GiveHex(t%16),o=util.GiveHex(Math.floor(e/16)),r=util.GiveHex(e%16),a=util.GiveHex(Math.floor(i/16)),h=util.GiveHex(i%16),l=n+s+o+r+a+h;return"#"+l},util.RGBToHSV=function(t,e,i){t/=255,e/=255,i/=255;var n=Math.min(t,Math.min(e,i)),s=Math.max(t,Math.max(e,i));if(n==s)return{h:0,s:0,v:n};var o=t==n?e-i:i==n?t-e:i-t,r=t==n?3:i==n?1:5,a=60*(r-o/(s-n))/360,h=(s-n)/s,l=s;return{h:a,s:h,v:l}},util.HSVToRGB=function(t,e,i){var n,s,o,r=Math.floor(6*t),a=6*t-r,h=i*(1-e),l=i*(1-a*e),c=i*(1-(1-a)*e);switch(r%6){case 0:n=i,s=c,o=h;break;case 1:n=l,s=i,o=h;break;case 2:n=h,s=i,o=c;break;case 3:n=h,s=l,o=i;break;case 4:n=c,s=h,o=i;break;case 5:n=i,s=h,o=l}return{r:Math.floor(255*n),g:Math.floor(255*s),b:Math.floor(255*o)}},util.HSVToHex=function(t,e,i){var n=util.HSVToRGB(t,e,i);return util.RGBToHex(n.r,n.g,n.b)},util.hexToHSV=function(t){var e=util.hexToRGB(t);return util.RGBToHSV(e.r,e.g,e.b)};var events={listeners:[],indexOf:function(t){for(var e=this.listeners,i=0,n=this.listeners.length;n>i;i++){var s=e[i];if(s&&s.object==t)return i}return-1},addListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];s||(s={object:t,events:{}},this.listeners.push(s));var o=s.events[e];o||(o=[],s.events[e]=o),-1==o.indexOf(i)&&o.push(i)},removeListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];o&&(n=o.indexOf(i),-1!=n&&o.splice(n,1),0==o.length&&delete s.events[e]);var r=0,a=s.events;for(var h in a)a.hasOwnProperty(h)&&r++;0==r&&delete this.listeners[n]}},removeAllListeners:function(){this.listeners=[]},trigger:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];if(o)for(var r=0,a=o.length;a>r;r++)o[r](i)}}};EventBus.prototype.on=function(t,e,i){var n=t instanceof RegExp?t:new RegExp(t.replace("*","\\w+")),s={id:util.randomUUID(),event:t,regexp:n,callback:"function"==typeof e?e:null,target:i};return this.subscriptions.push(s),s.id},EventBus.prototype.off=function(t){for(var e=0;eo;o++)i=s._addItem(t[o]),n.push(i);else if(util.isDataTable(t))for(var a=this._getColumnNames(t),h=0,l=t.getNumberOfRows();l>h;h++){for(var c={},d=0,u=a.length;u>d;d++){var p=a[d];c[p]=t.getValue(h,d)}i=s._addItem(c),n.push(i)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");i=s._addItem(t),n.push(i)}return n.length&&this._trigger("add",{items:n},e),n},DataSet.prototype.update=function(t,e){var i=[],n=[],s=this,o=s.fieldId,r=function(t){var e=t[o];s.data[e]?(e=s._updateItem(t),n.push(e)):(e=s._addItem(t),i.push(e))};if(t instanceof Array)for(var a=0,h=t.length;h>a;a++)r(t[a]);else if(util.isDataTable(t))for(var l=this._getColumnNames(t),c=0,d=t.getNumberOfRows();d>c;c++){for(var u={},p=0,f=l.length;f>p;p++){var g=l[p];u[g]=t.getValue(c,p)}r(u)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");r(t)}return i.length&&this._trigger("add",{items:i},e),n.length&&this._trigger("update",{items:n},e),i.concat(n)},DataSet.prototype.get=function(){var t,e,i,n,s=this,o=this.showInternalIds,r=util.getType(arguments[0]);"String"==r||"Number"==r?(t=arguments[0],i=arguments[1],n=arguments[2]):"Array"==r?(e=arguments[0],i=arguments[1],n=arguments[2]):(i=arguments[0],n=arguments[1]);var a;if(i&&i.type){if(a="DataTable"==i.type?"DataTable":"Array",n&&a!=util.getType(n))throw new Error('Type of parameter "data" ('+util.getType(n)+") does not correspond with specified options.type ("+i.type+")");if("DataTable"==a&&!util.isDataTable(n))throw new Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else a=n?"DataTable"==util.getType(n)?"DataTable":"Array":"Array";void 0!=i&&void 0!=i.showInternalIds&&(this.showInternalIds=i.showInternalIds);var h,l,c,d,u=i&&i.convert||this.options.convert,p=i&&i.filter,f=[];if(void 0!=t)h=s._getItem(t,u),p&&!p(h)&&(h=null);else if(void 0!=e)for(c=0,d=e.length;d>c;c++)h=s._getItem(e[c],u),(!p||p(h))&&f.push(h);else for(l in this.data)this.data.hasOwnProperty(l)&&(h=s._getItem(l,u),(!p||p(h))&&f.push(h));if(this.showInternalIds=o,i&&i.order&&void 0==t&&this._sort(f,i.order),i&&i.fields){var g=i.fields;if(void 0!=t)h=this._filterFields(h,g);else for(c=0,d=f.length;d>c;c++)f[c]=this._filterFields(f[c],g)}if("DataTable"==a){var m=this._getColumnNames(n);if(void 0!=t)s._appendRow(n,m,h);else for(c=0,d=f.length;d>c;c++)s._appendRow(n,m,f[c]);return n}if(void 0!=t)return h;if(n){for(c=0,d=f.length;d>c;c++)n.push(f[c]);return n}return f},DataSet.prototype.getIds=function(t){var e,i,n,s,o,r=this.data,a=t&&t.filter,h=t&&t.order,l=t&&t.convert||this.options.convert,c=[];if(a)if(h){o=[];for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,l),a(s)&&o.push(s));for(this._sort(o,h),e=0,i=o.length;i>e;e++)c[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,l),a(s)&&c.push(s[this.fieldId]));else if(h){o=[];for(n in r)r.hasOwnProperty(n)&&o.push(r[n]);for(this._sort(o,h),e=0,i=o.length;i>e;e++)c[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=r[n],c.push(s[this.fieldId]));return c},DataSet.prototype.forEach=function(t,e){var i,n,s=e&&e.filter,o=e&&e.convert||this.options.convert,r=this.data;if(e&&e.order)for(var a=this.get(e),h=0,l=a.length;l>h;h++)i=a[h],n=i[this.fieldId],t(i,n);else for(n in r)r.hasOwnProperty(n)&&(i=this._getItem(n,o),(!s||s(i))&&t(i,n))},DataSet.prototype.map=function(t,e){var i,n=e&&e.filter,s=e&&e.convert||this.options.convert,o=[],r=this.data;for(var a in r)r.hasOwnProperty(a)&&(i=this._getItem(a,s),(!n||n(i))&&o.push(t(i,a)));return e&&e.order&&this._sort(o,e.order),o},DataSet.prototype._filterFields=function(t,e){var i={};for(var n in t)t.hasOwnProperty(n)&&-1!=e.indexOf(n)&&(i[n]=t[n]);return i},DataSet.prototype._sort=function(t,e){if(util.isString(e)){var i=e;t.sort(function(t,e){var n=t[i],s=e[i];return n>s?1:s>n?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},DataSet.prototype.remove=function(t,e){var i,n,s,o=[];if(t instanceof Array)for(i=0,n=t.length;n>i;i++)s=this._remove(t[i]),null!=s&&o.push(s);else s=this._remove(t),null!=s&&o.push(s);return o.length&&this._trigger("remove",{items:o},e),o},DataSet.prototype._remove=function(t){if(util.isNumber(t)||util.isString(t)){if(this.data[t])return delete this.data[t],delete this.internalIds[t],t}else if(t instanceof Object){var e=t[this.fieldId];if(e&&this.data[e])return delete this.data[e],delete this.internalIds[e],e}return null},DataSet.prototype.clear=function(t){var e=Object.keys(this.data);return this.data={},this.internalIds={},this._trigger("remove",{items:e},t),e},DataSet.prototype.max=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||r>n)&&(i=o,n=r)}return i},DataSet.prototype.min=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||n>r)&&(i=o,n=r)}return i},DataSet.prototype.distinct=function(t){var e=this.data,i=[],n=this.options.convert[t],s=0;for(var o in e)if(e.hasOwnProperty(o)){for(var r=e[o],a=util.convert(r[t],n),h=!1,l=0;s>l;l++)if(i[l]==a){h=!0;break}h||(i[s]=a,s++)}return i},DataSet.prototype._addItem=function(t){var e=t[this.fieldId];if(void 0!=e){if(this.data[e])throw new Error("Cannot add item: item with id "+e+" already exists")}else e=util.randomUUID(),t[this.fieldId]=e,this.internalIds[e]=t;var i={};for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=util.convert(t[n],s)}return this.data[e]=i,e},DataSet.prototype._getItem=function(t,e){var i,n,s=this.data[t];if(!s)return null;var o={},r=this.fieldId,a=this.internalIds;if(e)for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a&&!this.showInternalIds||(o[i]=util.convert(n,e[i])));else for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a&&!this.showInternalIds||(o[i]=n));return o},DataSet.prototype._updateItem=function(t){var e=t[this.fieldId];if(void 0==e)throw new Error("Cannot update item: item has no id (item: "+JSON.stringify(t)+")");var i=this.data[e];if(!i)throw new Error("Cannot update item: no item with id "+e+" found");for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=util.convert(t[n],s)}return e},DataSet.prototype.isInternalId=function(t){return t in this.internalIds},DataSet.prototype._getColumnNames=function(t){for(var e=[],i=0,n=t.getNumberOfColumns();n>i;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},DataSet.prototype._appendRow=function(t,e,i){for(var n=t.addRow(),s=0,o=e.length;o>s;s++){var r=e[s];t.setValue(n,s,i[r])}},DataView.prototype.setData=function(t){var e,i,n;if(this.data){this.data.unsubscribe&&this.data.unsubscribe("*",this.listener),e=[];for(var s in this.ids)this.ids.hasOwnProperty(s)&&e.push(s);this.ids={},this._trigger("remove",{items:e})}if(this.data=t,this.data){for(this.fieldId=this.options.fieldId||this.data&&this.data.options&&this.data.options.fieldId||"id",e=this.data.getIds({filter:this.options&&this.options.filter}),i=0,n=e.length;n>i;i++)s=e[i],this.ids[s]=!0;this._trigger("add",{items:e}),this.data.subscribe&&this.data.subscribe("*",this.listener)}},DataView.prototype.get=function(){var t,e,i,n=this,s=util.getType(arguments[0]);"String"==s||"Number"==s||"Array"==s?(t=arguments[0],e=arguments[1],i=arguments[2]):(e=arguments[0],i=arguments[1]);var o=util.extend({},this.options,e);this.options.filter&&e&&e.filter&&(o.filter=function(t){return n.options.filter(t)&&e.filter(t)});var r=[];return void 0!=t&&r.push(t),r.push(o),r.push(i),this.data&&this.data.get.apply(this.data,r)},DataView.prototype.getIds=function(t){var e;if(this.data){var i,n=this.options.filter; +!function(t){if("object"==typeof exports)module.exports=t();else if("function"==typeof define&&define.amd)define(t);else{var e;"undefined"!=typeof window?e=window:"undefined"!=typeof global?e=global:"undefined"!=typeof self&&(e=self),e.vis=t()}}(function(){var define,module,exports;return function t(e,i,n){function s(r,a){if(!i[r]){if(!e[r]){var h="function"==typeof require&&require;if(!a&&h)return h(r,!0);if(o)return o(r,!0);throw new Error("Cannot find module '"+r+"'")}var l=i[r]={exports:{}};e[r][0].call(l.exports,function(t){var i=e[r][1][t];return s(i?i:t)},l,l.exports,t,e,i,n)}return i[r].exports}for(var o="function"==typeof require&&require,r=0;ri;++i)t.call(e||this,this[i],i,this)}),Array.prototype.map||(Array.prototype.map=function(t,e){var i,n,s;if(null==this)throw new TypeError(" this is null or not defined");var o=Object(this),r=o.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(e&&(i=e),n=new Array(r),s=0;r>s;){var a,h;s in o&&(a=o[s],h=t.call(i,a,s,o),n[s]=h),s++}return n}),Array.prototype.filter||(Array.prototype.filter=function(t){"use strict";if(null==this)throw new TypeError;var e=Object(this),i=e.length>>>0;if("function"!=typeof t)throw new TypeError;for(var n=[],s=arguments[1],o=0;i>o;o++)if(o in e){var r=e[o];t.call(s,r,o,e)&&n.push(r)}return n}),Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,e=!{toString:null}.propertyIsEnumerable("toString"),i=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],n=i.length;return function(s){if("object"!=typeof s&&"function"!=typeof s||null===s)throw new TypeError("Object.keys called on non-object");var o=[];for(var r in s)t.call(s,r)&&o.push(r);if(e)for(var a=0;n>a;a++)t.call(s,i[a])&&o.push(i[a]);return o}}()),Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s}),Object.create||(Object.create=function(t){function e(){}if(arguments.length>1)throw new Error("Object.create implementation only accepts the first parameter.");return e.prototype=t,new e}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s});var util={};util.isNumber=function(t){return t instanceof Number||"number"==typeof t},util.isString=function(t){return t instanceof String||"string"==typeof t},util.isDate=function(t){if(t instanceof Date)return!0;if(util.isString(t)){var e=ASPDateRegex.exec(t);if(e)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},util.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},util.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},util.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var n=arguments[e];for(var s in n)n.hasOwnProperty(s)&&void 0!==n[s]&&(t[s]=n[s])}return t},util.convert=function(t,e){var i;if(void 0===t)return void 0;if(null===t)return null;if(!e)return t;if("string"!=typeof e&&!(e instanceof String))throw new Error("Type must be a string");switch(e){case"boolean":case"Boolean":return Boolean(t);case"number":case"Number":return Number(t.valueOf());case"string":case"String":return String(t);case"Date":if(util.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(moment.isMoment(t))return new Date(t.valueOf());if(util.isString(t))return i=ASPDateRegex.exec(t),i?new Date(Number(i[1])):moment(t).toDate();throw new Error("Cannot convert object of type "+util.getType(t)+" to type Date");case"Moment":if(util.isNumber(t))return moment(t);if(t instanceof Date)return moment(t.valueOf());if(moment.isMoment(t))return moment(t);if(util.isString(t))return i=ASPDateRegex.exec(t),moment(i?Number(i[1]):t);throw new Error("Cannot convert object of type "+util.getType(t)+" to type Date");case"ISODate":if(util.isNumber(t))return new Date(t);if(t instanceof Date)return t.toISOString();if(moment.isMoment(t))return t.toDate().toISOString();if(util.isString(t))return i=ASPDateRegex.exec(t),i?new Date(Number(i[1])).toISOString():new Date(t).toISOString();throw new Error("Cannot convert object of type "+util.getType(t)+" to type ISODate");case"ASPDate":if(util.isNumber(t))return"/Date("+t+")/";if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(util.isString(t)){i=ASPDateRegex.exec(t);var n;return n=i?new Date(Number(i[1])).valueOf():new Date(t).valueOf(),"/Date("+n+")/"}throw new Error("Cannot convert object of type "+util.getType(t)+" to type ASPDate");default:throw new Error("Cannot convert object of type "+util.getType(t)+' to type "'+e+'"')}};var ASPDateRegex=/^\/?Date\((\-?\d+)/i;util.getType=function(t){var e=typeof t;return"object"==e?null==t?"null":t instanceof Boolean?"Boolean":t instanceof Number?"Number":t instanceof String?"String":t instanceof Array?"Array":t instanceof Date?"Date":"Object":"number"==e?"Number":"boolean"==e?"Boolean":"string"==e?"String":e},util.getAbsoluteLeft=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetLeft,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetLeft,n-=s.scrollLeft,s=s.offsetParent;return n},util.getAbsoluteTop=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetTop,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetTop,n-=s.scrollTop,s=s.offsetParent;return n},util.getPageY=function(t){if("pageY"in t)return t.pageY;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientY:t.clientY;var i=document.documentElement,n=document.body;return e+(i&&i.scrollTop||n&&n.scrollTop||0)-(i&&i.clientTop||n&&n.clientTop||0)},util.getPageX=function(t){if("pageY"in t)return t.pageX;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientX:t.clientX;var i=document.documentElement,n=document.body;return e+(i&&i.scrollLeft||n&&n.scrollLeft||0)-(i&&i.clientLeft||n&&n.clientLeft||0)},util.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},util.removeClassName=function(t,e){var i=t.className.split(" "),n=i.indexOf(e);-1!=n&&(i.splice(n,1),t.className=i.join(" "))},util.forEach=function(t,e){var i,n;if(t instanceof Array)for(i=0,n=t.length;n>i;i++)e(t[i],i,t);else for(i in t)t.hasOwnProperty(i)&&e(t[i],i,t)},util.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},util.addEventListener=function(t,e,i,n){t.addEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.addEventListener(e,i,n)):t.attachEvent("on"+e,i)},util.removeEventListener=function(t,e,i,n){t.removeEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.removeEventListener(e,i,n)):t.detachEvent("on"+e,i)},util.getTarget=function(t){t||(t=window.event);var e;return t.target?e=t.target:t.srcElement&&(e=t.srcElement),void 0!=e.nodeType&&3==e.nodeType&&(e=e.parentNode),e},util.stopPropagation=function(t){t||(t=window.event),t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},util.fakeGesture=function(t,e){var i=null;return Hammer.event.collectEventData(this,i,e)},util.preventDefault=function(t){t||(t=window.event),t.preventDefault?t.preventDefault():t.returnValue=!1},util.option={},util.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},util.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},util.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?String(t):e||null},util.option.asSize=function(t,e){return"function"==typeof t&&(t=t()),util.isString(t)?t:util.isNumber(t)?t+"px":e||null},util.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null},util.GiveDec=function GiveDec(Hex){return Value="A"==Hex?10:"B"==Hex?11:"C"==Hex?12:"D"==Hex?13:"E"==Hex?14:"F"==Hex?15:eval(Hex)},util.GiveHex=function(t){return Value=10==t?"A":11==t?"B":12==t?"C":13==t?"D":14==t?"E":15==t?"F":""+t},util.hexToRGB=function(t){t=t.replace("#","").toUpperCase();var e=util.GiveDec(t.substring(0,1)),i=util.GiveDec(t.substring(1,2)),n=util.GiveDec(t.substring(2,3)),s=util.GiveDec(t.substring(3,4)),o=util.GiveDec(t.substring(4,5)),r=util.GiveDec(t.substring(5,6)),a=16*e+i,h=16*n+s,i=16*o+r;return{r:a,g:h,b:i}},util.RGBToHex=function(t,e,i){var n=util.GiveHex(Math.floor(t/16)),s=util.GiveHex(t%16),o=util.GiveHex(Math.floor(e/16)),r=util.GiveHex(e%16),a=util.GiveHex(Math.floor(i/16)),h=util.GiveHex(i%16),l=n+s+o+r+a+h;return"#"+l},util.RGBToHSV=function(t,e,i){t/=255,e/=255,i/=255;var n=Math.min(t,Math.min(e,i)),s=Math.max(t,Math.max(e,i));if(n==s)return{h:0,s:0,v:n};var o=t==n?e-i:i==n?t-e:i-t,r=t==n?3:i==n?1:5,a=60*(r-o/(s-n))/360,h=(s-n)/s,l=s;return{h:a,s:h,v:l}},util.HSVToRGB=function(t,e,i){var n,s,o,r=Math.floor(6*t),a=6*t-r,h=i*(1-e),l=i*(1-a*e),c=i*(1-(1-a)*e);switch(r%6){case 0:n=i,s=c,o=h;break;case 1:n=l,s=i,o=h;break;case 2:n=h,s=i,o=c;break;case 3:n=h,s=l,o=i;break;case 4:n=c,s=h,o=i;break;case 5:n=i,s=h,o=l}return{r:Math.floor(255*n),g:Math.floor(255*s),b:Math.floor(255*o)}},util.HSVToHex=function(t,e,i){var n=util.HSVToRGB(t,e,i);return util.RGBToHex(n.r,n.g,n.b)},util.hexToHSV=function(t){var e=util.hexToRGB(t);return util.RGBToHSV(e.r,e.g,e.b)};var events={listeners:[],indexOf:function(t){for(var e=this.listeners,i=0,n=this.listeners.length;n>i;i++){var s=e[i];if(s&&s.object==t)return i}return-1},addListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];s||(s={object:t,events:{}},this.listeners.push(s));var o=s.events[e];o||(o=[],s.events[e]=o),-1==o.indexOf(i)&&o.push(i)},removeListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];o&&(n=o.indexOf(i),-1!=n&&o.splice(n,1),0==o.length&&delete s.events[e]);var r=0,a=s.events;for(var h in a)a.hasOwnProperty(h)&&r++;0==r&&delete this.listeners[n]}},removeAllListeners:function(){this.listeners=[]},trigger:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];if(o)for(var r=0,a=o.length;a>r;r++)o[r](i)}}};EventBus.prototype.on=function(t,e,i){var n=t instanceof RegExp?t:new RegExp(t.replace("*","\\w+")),s={id:util.randomUUID(),event:t,regexp:n,callback:"function"==typeof e?e:null,target:i};return this.subscriptions.push(s),s.id},EventBus.prototype.off=function(t){for(var e=0;eo;o++)i=s._addItem(t[o]),n.push(i);else if(util.isDataTable(t))for(var a=this._getColumnNames(t),h=0,l=t.getNumberOfRows();l>h;h++){for(var c={},d=0,u=a.length;u>d;d++){var p=a[d];c[p]=t.getValue(h,d)}i=s._addItem(c),n.push(i)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");i=s._addItem(t),n.push(i)}return n.length&&this._trigger("add",{items:n},e),n},DataSet.prototype.update=function(t,e){var i=[],n=[],s=this,o=s.fieldId,r=function(t){var e=t[o];s.data[e]?(e=s._updateItem(t),n.push(e)):(e=s._addItem(t),i.push(e))};if(t instanceof Array)for(var a=0,h=t.length;h>a;a++)r(t[a]);else if(util.isDataTable(t))for(var l=this._getColumnNames(t),c=0,d=t.getNumberOfRows();d>c;c++){for(var u={},p=0,f=l.length;f>p;p++){var g=l[p];u[g]=t.getValue(c,p)}r(u)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");r(t)}return i.length&&this._trigger("add",{items:i},e),n.length&&this._trigger("update",{items:n},e),i.concat(n)},DataSet.prototype.get=function(){var t,e,i,n,s=this,o=this.showInternalIds,r=util.getType(arguments[0]);"String"==r||"Number"==r?(t=arguments[0],i=arguments[1],n=arguments[2]):"Array"==r?(e=arguments[0],i=arguments[1],n=arguments[2]):(i=arguments[0],n=arguments[1]);var a;if(i&&i.type){if(a="DataTable"==i.type?"DataTable":"Array",n&&a!=util.getType(n))throw new Error('Type of parameter "data" ('+util.getType(n)+") does not correspond with specified options.type ("+i.type+")");if("DataTable"==a&&!util.isDataTable(n))throw new Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else a=n?"DataTable"==util.getType(n)?"DataTable":"Array":"Array";void 0!=i&&void 0!=i.showInternalIds&&(this.showInternalIds=i.showInternalIds);var h,l,c,d,u=i&&i.convert||this.options.convert,p=i&&i.filter,f=[];if(void 0!=t)h=s._getItem(t,u),p&&!p(h)&&(h=null);else if(void 0!=e)for(c=0,d=e.length;d>c;c++)h=s._getItem(e[c],u),(!p||p(h))&&f.push(h);else for(l in this.data)this.data.hasOwnProperty(l)&&(h=s._getItem(l,u),(!p||p(h))&&f.push(h));if(this.showInternalIds=o,i&&i.order&&void 0==t&&this._sort(f,i.order),i&&i.fields){var g=i.fields;if(void 0!=t)h=this._filterFields(h,g);else for(c=0,d=f.length;d>c;c++)f[c]=this._filterFields(f[c],g)}if("DataTable"==a){var m=this._getColumnNames(n);if(void 0!=t)s._appendRow(n,m,h);else for(c=0,d=f.length;d>c;c++)s._appendRow(n,m,f[c]);return n}if(void 0!=t)return h;if(n){for(c=0,d=f.length;d>c;c++)n.push(f[c]);return n}return f},DataSet.prototype.getIds=function(t){var e,i,n,s,o,r=this.data,a=t&&t.filter,h=t&&t.order,l=t&&t.convert||this.options.convert,c=[];if(a)if(h){o=[];for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,l),a(s)&&o.push(s));for(this._sort(o,h),e=0,i=o.length;i>e;e++)c[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,l),a(s)&&c.push(s[this.fieldId]));else if(h){o=[];for(n in r)r.hasOwnProperty(n)&&o.push(r[n]);for(this._sort(o,h),e=0,i=o.length;i>e;e++)c[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=r[n],c.push(s[this.fieldId]));return c},DataSet.prototype.forEach=function(t,e){var i,n,s=e&&e.filter,o=e&&e.convert||this.options.convert,r=this.data;if(e&&e.order)for(var a=this.get(e),h=0,l=a.length;l>h;h++)i=a[h],n=i[this.fieldId],t(i,n);else for(n in r)r.hasOwnProperty(n)&&(i=this._getItem(n,o),(!s||s(i))&&t(i,n))},DataSet.prototype.map=function(t,e){var i,n=e&&e.filter,s=e&&e.convert||this.options.convert,o=[],r=this.data;for(var a in r)r.hasOwnProperty(a)&&(i=this._getItem(a,s),(!n||n(i))&&o.push(t(i,a)));return e&&e.order&&this._sort(o,e.order),o},DataSet.prototype._filterFields=function(t,e){var i={};for(var n in t)t.hasOwnProperty(n)&&-1!=e.indexOf(n)&&(i[n]=t[n]);return i},DataSet.prototype._sort=function(t,e){if(util.isString(e)){var i=e;t.sort(function(t,e){var n=t[i],s=e[i];return n>s?1:s>n?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},DataSet.prototype.remove=function(t,e){var i,n,s,o=[];if(t instanceof Array)for(i=0,n=t.length;n>i;i++)s=this._remove(t[i]),null!=s&&o.push(s);else s=this._remove(t),null!=s&&o.push(s);return o.length&&this._trigger("remove",{items:o},e),o},DataSet.prototype._remove=function(t){if(util.isNumber(t)||util.isString(t)){if(this.data[t])return delete this.data[t],delete this.internalIds[t],t}else if(t instanceof Object){var e=t[this.fieldId];if(e&&this.data[e])return delete this.data[e],delete this.internalIds[e],e}return null},DataSet.prototype.clear=function(t){var e=Object.keys(this.data);return this.data={},this.internalIds={},this._trigger("remove",{items:e},t),e},DataSet.prototype.max=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||r>n)&&(i=o,n=r)}return i},DataSet.prototype.min=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||n>r)&&(i=o,n=r)}return i},DataSet.prototype.distinct=function(t){var e=this.data,i=[],n=this.options.convert[t],s=0;for(var o in e)if(e.hasOwnProperty(o)){for(var r=e[o],a=util.convert(r[t],n),h=!1,l=0;s>l;l++)if(i[l]==a){h=!0;break}h||(i[s]=a,s++)}return i},DataSet.prototype._addItem=function(t){var e=t[this.fieldId];if(void 0!=e){if(this.data[e])throw new Error("Cannot add item: item with id "+e+" already exists")}else e=util.randomUUID(),t[this.fieldId]=e,this.internalIds[e]=t;var i={};for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=util.convert(t[n],s)}return this.data[e]=i,e},DataSet.prototype._getItem=function(t,e){var i,n,s=this.data[t];if(!s)return null;var o={},r=this.fieldId,a=this.internalIds;if(e)for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a&&!this.showInternalIds||(o[i]=util.convert(n,e[i])));else for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a&&!this.showInternalIds||(o[i]=n));return o},DataSet.prototype._updateItem=function(t){var e=t[this.fieldId];if(void 0==e)throw new Error("Cannot update item: item has no id (item: "+JSON.stringify(t)+")");var i=this.data[e];if(!i)throw new Error("Cannot update item: no item with id "+e+" found");for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=util.convert(t[n],s)}return e},DataSet.prototype.isInternalId=function(t){return t in this.internalIds},DataSet.prototype._getColumnNames=function(t){for(var e=[],i=0,n=t.getNumberOfColumns();n>i;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},DataSet.prototype._appendRow=function(t,e,i){for(var n=t.addRow(),s=0,o=e.length;o>s;s++){var r=e[s];t.setValue(n,s,i[r])}},DataView.prototype.setData=function(t){var e,i,n;if(this.data){this.data.unsubscribe&&this.data.unsubscribe("*",this.listener),e=[];for(var s in this.ids)this.ids.hasOwnProperty(s)&&e.push(s);this.ids={},this._trigger("remove",{items:e})}if(this.data=t,this.data){for(this.fieldId=this.options.fieldId||this.data&&this.data.options&&this.data.options.fieldId||"id",e=this.data.getIds({filter:this.options&&this.options.filter}),i=0,n=e.length;n>i;i++)s=e[i],this.ids[s]=!0;this._trigger("add",{items:e}),this.data.subscribe&&this.data.subscribe("*",this.listener)}},DataView.prototype.get=function(){var t,e,i,n=this,s=util.getType(arguments[0]);"String"==s||"Number"==s||"Array"==s?(t=arguments[0],e=arguments[1],i=arguments[2]):(e=arguments[0],i=arguments[1]);var o=util.extend({},this.options,e);this.options.filter&&e&&e.filter&&(o.filter=function(t){return n.options.filter(t)&&e.filter(t)});var r=[];return void 0!=t&&r.push(t),r.push(o),r.push(i),this.data&&this.data.get.apply(this.data,r)},DataView.prototype.getIds=function(t){var e;if(this.data){var i,n=this.options.filter; i=t&&t.filter?n?function(e){return n(e)&&t.filter(e)}:t.filter:n,e=this.data.getIds({filter:i,order:t&&t.order})}else e=[];return e},DataView.prototype._onEvent=function(t,e,i){var n,s,o,r,a=e&&e.items,h=this.data,l=[],c=[],d=[];if(a&&h){switch(t){case"add":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r&&(this.ids[o]=!0,l.push(o));break;case"update":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r?this.ids[o]?c.push(o):(this.ids[o]=!0,l.push(o)):this.ids[o]&&(delete this.ids[o],d.push(o));break;case"remove":for(n=0,s=a.length;s>n;n++)o=a[n],this.ids[o]&&(delete this.ids[o],d.push(o))}l.length&&this._trigger("add",{items:l},i),c.length&&this._trigger("update",{items:c},i),d.length&&this._trigger("remove",{items:d},i)}},DataView.prototype.subscribe=DataSet.prototype.subscribe,DataView.prototype.unsubscribe=DataSet.prototype.unsubscribe,DataView.prototype._trigger=DataSet.prototype._trigger,TimeStep=function(t,e,i){this.current=new Date,this._start=new Date,this._end=new Date,this.autoScale=!0,this.scale=TimeStep.SCALE.DAY,this.step=1,this.setRange(t,e,i)},TimeStep.SCALE={MILLISECOND:1,SECOND:2,MINUTE:3,HOUR:4,DAY:5,WEEKDAY:6,MONTH:7,YEAR:8},TimeStep.prototype.setRange=function(t,e,i){if(!(t instanceof Date&&e instanceof Date))throw"No legal start or end date in method setRange";this._start=void 0!=t?new Date(t.valueOf()):new Date,this._end=void 0!=e?new Date(e.valueOf()):new Date,this.autoScale&&this.setMinimumStep(i)},TimeStep.prototype.first=function(){this.current=new Date(this._start.valueOf()),this.roundToMinor()},TimeStep.prototype.roundToMinor=function(){switch(this.scale){case TimeStep.SCALE.YEAR:this.current.setFullYear(this.step*Math.floor(this.current.getFullYear()/this.step)),this.current.setMonth(0);case TimeStep.SCALE.MONTH:this.current.setDate(1);case TimeStep.SCALE.DAY:case TimeStep.SCALE.WEEKDAY:this.current.setHours(0);case TimeStep.SCALE.HOUR:this.current.setMinutes(0);case TimeStep.SCALE.MINUTE:this.current.setSeconds(0);case TimeStep.SCALE.SECOND:this.current.setMilliseconds(0)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.setMilliseconds(this.current.getMilliseconds()-this.current.getMilliseconds()%this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()-this.current.getSeconds()%this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()-this.current.getMinutes()%this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()-this.current.getHours()%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()-1-(this.current.getDate()-1)%this.step+1);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()-this.current.getMonth()%this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()-this.current.getFullYear()%this.step)}},TimeStep.prototype.hasNext=function(){return this.current.valueOf()<=this._end.valueOf()},TimeStep.prototype.next=function(){var t=this.current.valueOf();if(this.current.getMonth()<6)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current=new Date(this.current.valueOf()+1e3*this.step);break;case TimeStep.SCALE.MINUTE:this.current=new Date(this.current.valueOf()+1e3*this.step*60);break;case TimeStep.SCALE.HOUR:this.current=new Date(this.current.valueOf()+1e3*this.step*60*60);var e=this.current.getHours();this.current.setHours(e-e%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}else switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()+this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()+this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()+this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.getMilliseconds()0&&(this.step=e),this.autoScale=!1},TimeStep.prototype.setAutoScale=function(t){this.autoScale=t},TimeStep.prototype.setMinimumStep=function(t){if(void 0!=t){var e=31104e6,i=2592e6,n=864e5,s=36e5,o=6e4,r=1e3,a=1;1e3*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1e3),500*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=500),100*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=100),50*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=50),10*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=10),5*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=5),e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1),3*i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=3),i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=1),5*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=5),2*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=2),n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=1),n/2>t&&(this.scale=TimeStep.SCALE.WEEKDAY,this.step=1),4*s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=4),s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=1),15*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=15),10*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=10),5*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=5),o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=1),15*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=15),10*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=10),5*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=5),r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=1),200*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=200),100*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=100),50*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=50),10*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=10),5*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=5),a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=1)}},TimeStep.prototype.snap=function(t){if(this.scale==TimeStep.SCALE.YEAR){var e=t.getFullYear()+Math.round(t.getMonth()/12);t.setFullYear(Math.round(e/this.step)*this.step),t.setMonth(0),t.setDate(0),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MONTH)t.getDate()>15?(t.setDate(1),t.setMonth(t.getMonth()+1)):t.setDate(1),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0);else if(this.scale==TimeStep.SCALE.DAY||this.scale==TimeStep.SCALE.WEEKDAY){switch(this.step){case 5:case 2:t.setHours(24*Math.round(t.getHours()/24));break;default:t.setHours(12*Math.round(t.getHours()/12))}t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.HOUR){switch(this.step){case 4:t.setMinutes(60*Math.round(t.getMinutes()/60));break;default:t.setMinutes(30*Math.round(t.getMinutes()/30))}t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MINUTE){switch(this.step){case 15:case 10:t.setMinutes(5*Math.round(t.getMinutes()/5)),t.setSeconds(0);break;case 5:t.setSeconds(60*Math.round(t.getSeconds()/60));break;default:t.setSeconds(30*Math.round(t.getSeconds()/30))}t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.SECOND)switch(this.step){case 15:case 10:t.setSeconds(5*Math.round(t.getSeconds()/5)),t.setMilliseconds(0);break;case 5:t.setMilliseconds(1e3*Math.round(t.getMilliseconds()/1e3));break;default:t.setMilliseconds(500*Math.round(t.getMilliseconds()/500))}else if(this.scale==TimeStep.SCALE.MILLISECOND){var i=this.step>5?this.step/2:1;t.setMilliseconds(Math.round(t.getMilliseconds()/i)*i)}},TimeStep.prototype.isMajor=function(){switch(this.scale){case TimeStep.SCALE.MILLISECOND:return 0==this.current.getMilliseconds();case TimeStep.SCALE.SECOND:return 0==this.current.getSeconds();case TimeStep.SCALE.MINUTE:return 0==this.current.getHours()&&0==this.current.getMinutes();case TimeStep.SCALE.HOUR:return 0==this.current.getHours();case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return 1==this.current.getDate();case TimeStep.SCALE.MONTH:return 0==this.current.getMonth();case TimeStep.SCALE.YEAR:return!1;default:return!1}},TimeStep.prototype.getLabelMinor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return moment(t).format("SSS");case TimeStep.SCALE.SECOND:return moment(t).format("s");case TimeStep.SCALE.MINUTE:return moment(t).format("HH:mm");case TimeStep.SCALE.HOUR:return moment(t).format("HH:mm");case TimeStep.SCALE.WEEKDAY:return moment(t).format("ddd D");case TimeStep.SCALE.DAY:return moment(t).format("D");case TimeStep.SCALE.MONTH:return moment(t).format("MMM");case TimeStep.SCALE.YEAR:return moment(t).format("YYYY");default:return""}},TimeStep.prototype.getLabelMajor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return moment(t).format("HH:mm:ss");case TimeStep.SCALE.SECOND:return moment(t).format("D MMMM HH:mm");case TimeStep.SCALE.MINUTE:case TimeStep.SCALE.HOUR:return moment(t).format("ddd D MMMM");case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return moment(t).format("MMMM YYYY");case TimeStep.SCALE.MONTH:return moment(t).format("YYYY");case TimeStep.SCALE.YEAR:return"";default:return""}},Stack.prototype.setOptions=function(t){util.extend(this.options,t)},Stack.prototype.update=function(){this._order(),this._stack()},Stack.prototype._order=function(){var t=this.parent.items;if(!t)throw new Error("Cannot stack items: parent does not contain items");var e=[],i=0;util.forEach(t,function(t){t.visible&&(e[i]=t,i++)});var n=this.options.order||this.defaultOptions.order;if("function"!=typeof n)throw new Error("Option order must be a function");e.sort(n),this.ordered=e},Stack.prototype._stack=function(){var t,e,i,n=this.ordered,s=this.options,o=s.orientation||this.defaultOptions.orientation,r="top"==o;for(i=s.margin&&void 0!==s.margin.item?s.margin.item:this.defaultOptions.margin.item,t=0,e=n.length;e>t;t++){var a=n[t],h=null;do h=this.checkOverlap(n,t,0,t-1,i),null!=h&&(a.top=r?h.top+h.height+i:h.top-a.height-i);while(h)}},Stack.prototype.checkOverlap=function(t,e,i,n,s){for(var o=this.collision,r=t[e],a=n;a>=i;a--){var h=t[a];if(o(r,h,s)&&a!=e)return h}return null},Stack.prototype.collision=function(t,e,i){return t.left-ie.left&&t.top-ie.top},Range.prototype.setOptions=function(t){util.extend(this.options,t),null!==this.start&&null!==this.end&&this.setRange(this.start,this.end)},Range.prototype.subscribe=function(t,e,i){function n(e){s._onMouseWheel(e,t,i)}var s=this;if("move"==e)t.on("dragstart",function(e){s._onDragStart(e,t)}),t.on("drag",function(e){s._onDrag(e,t,i)}),t.on("dragend",function(e){s._onDragEnd(e,t)});else{if("zoom"!=e)throw new TypeError('Unknown event "'+e+'". Choose "move" or "zoom".');t.on("mousewheel",n),t.on("DOMMouseScroll",n),t.on("touch",function(){s._onTouch()}),t.on("pinch",function(e){s._onPinch(e,t,i)})}},Range.prototype.on=function(t,e){var i=["rangechange","rangechanged"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());events.addListener(this,t,e)},Range.prototype.off=function(t,e){events.removeListener(this,t,e)},Range.prototype._trigger=function(t){events.trigger(this,t,{start:this.start,end:this.end})},Range.prototype.setRange=function(t,e){var i=this._applyRange(t,e);i&&(this._trigger("rangechange"),this._trigger("rangechanged"))},Range.prototype._applyRange=function(t,e){var i,n=null!=t?util.convert(t,"Date").valueOf():this.start,s=null!=e?util.convert(e,"Date").valueOf():this.end,o=null!=this.options.max?util.convert(this.options.max,"Date").valueOf():null,r=null!=this.options.min?util.convert(this.options.min,"Date").valueOf():null;if(isNaN(n)||null===n)throw new Error('Invalid start "'+t+'"');if(isNaN(s)||null===s)throw new Error('Invalid end "'+e+'"');if(n>s&&(s=n),null!==r&&r>n&&(i=r-n,n+=i,s+=i,null!=o&&s>o&&(s=o)),null!==o&&s>o&&(i=s-o,n-=i,s-=i,null!=r&&r>n&&(n=r)),null!==this.options.zoomMin){var a=parseFloat(this.options.zoomMin);0>a&&(a=0),a>s-n&&(this.end-this.start===a?(n=this.start,s=this.end):(i=a-(s-n),n-=i/2,s+=i/2))}if(null!==this.options.zoomMax){var h=parseFloat(this.options.zoomMax);0>h&&(h=0),s-n>h&&(this.end-this.start===h?(n=this.start,s=this.end):(i=s-n-h,n+=i/2,s-=i/2))}var l=this.start!=n||this.end!=s;return this.start=n,this.end=s,l},Range.prototype.getRange=function(){return{start:this.start,end:this.end}},Range.prototype.conversion=function(t){return Range.conversion(this.start,this.end,t)},Range.conversion=function(t,e,i){return 0!=i&&e-t!=0?{offset:t,scale:i/(e-t)}:{offset:0,scale:1}};var touchParams={};Range.prototype._onDragStart=function(t,e){if(!touchParams.pinching){touchParams.start=this.start,touchParams.end=this.end;var i=e.frame;i&&(i.style.cursor="move")}},Range.prototype._onDrag=function(t,e,i){if(validateDirection(i),!touchParams.pinching){var n="horizontal"==i?t.gesture.deltaX:t.gesture.deltaY,s=touchParams.end-touchParams.start,o="horizontal"==i?e.width:e.height,r=-n/o*s;this._applyRange(touchParams.start+r,touchParams.end+r),this._trigger("rangechange")}},Range.prototype._onDragEnd=function(t,e){touchParams.pinching||(e.frame&&(e.frame.style.cursor="auto"),this._trigger("rangechanged"))},Range.prototype._onMouseWheel=function(t,e,i){validateDirection(i);var n=0;if(t.wheelDelta?n=t.wheelDelta/120:t.detail&&(n=-t.detail/3),n){var s;s=0>n?1-n/5:1/(1+n/5);var o=util.fakeGesture(this,t),r=getPointer(o.touches[0],e.frame),a=this._pointerToDate(e,i,r);this.zoom(s,a)}util.preventDefault(t)},Range.prototype._onTouch=function(){touchParams.start=this.start,touchParams.end=this.end,touchParams.pinching=!1,touchParams.center=null},Range.prototype._onPinch=function(t,e,i){if(touchParams.pinching=!0,t.gesture.touches.length>1){touchParams.center||(touchParams.center=getPointer(t.gesture.center,e.frame));var n=1/t.gesture.scale,s=this._pointerToDate(e,i,touchParams.center),o=getPointer(t.gesture.center,e.frame),r=(this._pointerToDate(e,i,o),parseInt(s+(touchParams.start-s)*n)),a=parseInt(s+(touchParams.end-s)*n);this.setRange(r,a)}},Range.prototype._pointerToDate=function(t,e,i){var n;if("horizontal"==e){var s=t.width;return n=this.conversion(s),i.x/n.scale+n.offset}var o=t.height;return n=this.conversion(o),i.y/n.scale+n.offset},Range.prototype.zoom=function(t,e){null==e&&(e=(this.start+this.end)/2);var i=e+(this.start-e)*t,n=e+(this.end-e)*t;this.setRange(i,n)},Range.prototype.move=function(t){var e=this.end-this.start,i=this.start+e*t,n=this.end+e*t;this.start=i,this.end=n},Range.prototype.moveTo=function(t){var e=(this.start+this.end)/2,i=e-t,n=this.start-i,s=this.end-i;this.setRange(n,s)},Controller.prototype.add=function(t){if(void 0==t.id)throw new Error("Component has no field id");if(!(t instanceof Component||t instanceof Controller))throw new TypeError("Component must be an instance of prototype Component or Controller");t.controller=this,this.components[t.id]=t},Controller.prototype.remove=function(t){var e;for(e in this.components)if(this.components.hasOwnProperty(e)&&(e==t||this.components[e]==t))break;e&&delete this.components[e]},Controller.prototype.requestReflow=function(t){if(t)this.reflow();else if(!this.reflowTimer){var e=this;this.reflowTimer=setTimeout(function(){e.reflowTimer=void 0,e.reflow()},0)}},Controller.prototype.requestRepaint=function(t){if(t)this.repaint();else if(!this.repaintTimer){var e=this;this.repaintTimer=setTimeout(function(){e.repaintTimer=void 0,e.repaint()},0)}},Controller.prototype.repaint=function t(){function t(n,s){s in i||(n.depends&&n.depends.forEach(function(e){t(e,e.id)}),n.parent&&t(n.parent,n.parent.id),e=n.repaint()||e,i[s]=!0)}var e=!1;this.repaintTimer&&(clearTimeout(this.repaintTimer),this.repaintTimer=void 0);var i={};util.forEach(this.components,t),e&&this.reflow()},Controller.prototype.reflow=function e(){function e(n,s){s in i||(n.depends&&n.depends.forEach(function(t){e(t,t.id)}),n.parent&&e(n.parent,n.parent.id),t=n.reflow()||t,i[s]=!0)}var t=!1;this.reflowTimer&&(clearTimeout(this.reflowTimer),this.reflowTimer=void 0);var i={};util.forEach(this.components,e),t&&this.repaint()},Component.prototype.setOptions=function(t){t&&(util.extend(this.options,t),this.controller&&(this.requestRepaint(),this.requestReflow()))},Component.prototype.getOption=function(t){var e;return this.options&&(e=this.options[t]),void 0===e&&this.defaultOptions&&(e=this.defaultOptions[t]),e},Component.prototype.getContainer=function(){return null},Component.prototype.getFrame=function(){return this.frame},Component.prototype.repaint=function(){return!1},Component.prototype.reflow=function(){return!1},Component.prototype.hide=function(){return this.frame&&this.frame.parentNode?(this.frame.parentNode.removeChild(this.frame),!0):!1},Component.prototype.show=function(){return this.frame&&this.frame.parentNode?!1:this.repaint()},Component.prototype.requestRepaint=function(){if(!this.controller)throw new Error("Cannot request a repaint: no controller configured");this.controller.requestRepaint()},Component.prototype.requestReflow=function(){if(!this.controller)throw new Error("Cannot request a reflow: no controller configured");this.controller.requestReflow()},Panel.prototype=new Component,Panel.prototype.setOptions=Component.prototype.setOptions,Panel.prototype.getContainer=function(){return this.frame},Panel.prototype.repaint=function(){var t=0,e=util.updateProperty,i=util.option.asSize,n=this.options,s=this.frame;if(!s){s=document.createElement("div"),s.className="panel";var o=n.className;o&&("function"==typeof o?util.addClassName(s,String(o())):util.addClassName(s,String(o))),this.frame=s,t+=1}if(!s.parentNode){if(!this.parent)throw new Error("Cannot repaint panel: no parent attached");var r=this.parent.getContainer();if(!r)throw new Error("Cannot repaint panel: parent has no container element");r.appendChild(s),t+=1}return t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),t>0},Panel.prototype.reflow=function(){var t=0,e=util.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},RootPanel.prototype=new Panel,RootPanel.prototype.setOptions=Component.prototype.setOptions,RootPanel.prototype.repaint=function(){var t=0,e=util.updateProperty,i=util.option.asSize,n=this.options,s=this.frame;if(s||(s=document.createElement("div"),this.frame=s,t+=1),!s.parentNode){if(!this.container)throw new Error("Cannot repaint root panel: no container attached");this.container.appendChild(s),t+=1}s.className="vis timeline rootpanel "+n.orientation;var o=n.className;return o&&util.addClassName(s,util.option.asString(o)),t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),this._updateEventEmitters(),this._updateWatch(),t>0},RootPanel.prototype.reflow=function(){var t=0,e=util.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},RootPanel.prototype._updateWatch=function(){var t=this.getOption("autoResize");t?this._watch():this._unwatch()},RootPanel.prototype._watch=function(){var t=this;this._unwatch();var e=function(){var e=t.getOption("autoResize");return e?void(t.frame&&(t.frame.clientWidth!=t.width||t.frame.clientHeight!=t.height)&&t.requestReflow()):void t._unwatch()};util.addEventListener(window,"resize",e),this.watchTimer=setInterval(e,1e3)},RootPanel.prototype._unwatch=function(){this.watchTimer&&(clearInterval(this.watchTimer),this.watchTimer=void 0)},RootPanel.prototype.on=function(t,e){var i=this.listeners[t];i||(i=[],this.listeners[t]=i),i.push(e),this._updateEventEmitters()},RootPanel.prototype._updateEventEmitters=function(){if(this.listeners){var t=this;util.forEach(this.listeners,function(e,i){if(t.emitters||(t.emitters={}),!(i in t.emitters)){var n=t.frame;if(n){var s=function(t){e.forEach(function(e){e(t)})};t.emitters[i]=s,t.hammer||(t.hammer=Hammer(n,{prevent_default:!0})),t.hammer.on(i,s)}}})}},TimeAxis.prototype=new Component,TimeAxis.prototype.setOptions=Component.prototype.setOptions,TimeAxis.prototype.setRange=function(t){if(!(t instanceof Range||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},TimeAxis.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},TimeAxis.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},TimeAxis.prototype.repaint=function(){var t=0,e=util.updateProperty,i=util.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.props,r=this.step,a=this.frame;if(a||(a=document.createElement("div"),this.frame=a,t+=1),a.className="axis",!a.parentNode){if(!this.parent)throw new Error("Cannot repaint time axis: no parent attached");var h=this.parent.getContainer();if(!h)throw new Error("Cannot repaint time axis: parent has no container element");h.appendChild(a),t+=1}var l=a.parentNode;if(l){var c=a.nextSibling;l.removeChild(a);var d="bottom"==s&&this.props.parentHeight&&this.height?this.props.parentHeight-this.height+"px":"0px";if(t+=e(a.style,"top",i(n.top,d)),t+=e(a.style,"left",i(n.left,"0px")),t+=e(a.style,"width",i(n.width,"100%")),t+=e(a.style,"height",i(n.height,this.height+"px")),this._repaintMeasureChars(),this.step){this._repaintStart(),r.first();for(var u=void 0,p=0;r.hasNext()&&1e3>p;){p++;var f=r.getCurrent(),g=this.toScreen(f),m=r.isMajor();this.getOption("showMinorLabels")&&this._repaintMinorText(g,r.getLabelMinor()),m&&this.getOption("showMajorLabels")?(g>0&&(void 0==u&&(u=g),this._repaintMajorText(g,r.getLabelMajor())),this._repaintMajorLine(g)):this._repaintMinorLine(g),r.next()}if(this.getOption("showMajorLabels")){var v=this.toTime(0),y=r.getLabelMajor(v),_=y.length*(o.majorCharWidth||10)+10;(void 0==u||u>_)&&this._repaintMajorText(0,y)}this._repaintEnd()}this._repaintLine(),c?l.insertBefore(a,c):l.appendChild(a)}return t>0},TimeAxis.prototype._repaintStart=function(){var t=this.dom,e=t.redundant;e.majorLines=t.majorLines,e.majorTexts=t.majorTexts,e.minorLines=t.minorLines,e.minorTexts=t.minorTexts,t.majorLines=[],t.majorTexts=[],t.minorLines=[],t.minorTexts=[]},TimeAxis.prototype._repaintEnd=function(){util.forEach(this.dom.redundant,function(t){for(;t.length;){var e=t.pop();e&&e.parentNode&&e.parentNode.removeChild(e)}})},TimeAxis.prototype._repaintMinorText=function(t,e){var i=this.dom.redundant.minorTexts.shift();if(!i){var n=document.createTextNode("");i=document.createElement("div"),i.appendChild(n),i.className="text minor",this.frame.appendChild(i)}this.dom.minorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.left=t+"px",i.style.top=this.props.minorLabelTop+"px"},TimeAxis.prototype._repaintMajorText=function(t,e){var i=this.dom.redundant.majorTexts.shift();if(!i){var n=document.createTextNode(e);i=document.createElement("div"),i.className="text major",i.appendChild(n),this.frame.appendChild(i)}this.dom.majorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.top=this.props.majorLabelTop+"px",i.style.left=t+"px"},TimeAxis.prototype._repaintMinorLine=function(t){var e=this.dom.redundant.minorLines.shift();e||(e=document.createElement("div"),e.className="grid vertical minor",this.frame.appendChild(e)),this.dom.minorLines.push(e);var i=this.props;e.style.top=i.minorLineTop+"px",e.style.height=i.minorLineHeight+"px",e.style.left=t-i.minorLineWidth/2+"px"},TimeAxis.prototype._repaintMajorLine=function(t){var e=this.dom.redundant.majorLines.shift();e||(e=document.createElement("DIV"),e.className="grid vertical major",this.frame.appendChild(e)),this.dom.majorLines.push(e);var i=this.props;e.style.top=i.majorLineTop+"px",e.style.left=t-i.majorLineWidth/2+"px",e.style.height=i.majorLineHeight+"px"},TimeAxis.prototype._repaintLine=function(){{var t=this.dom.line,e=this.frame;this.options}this.getOption("showMinorLabels")||this.getOption("showMajorLabels")?(t?(e.removeChild(t),e.appendChild(t)):(t=document.createElement("div"),t.className="grid horizontal major",e.appendChild(t),this.dom.line=t),t.style.top=this.props.lineTop+"px"):t&&t.parentElement&&(e.removeChild(t.line),delete this.dom.line)},TimeAxis.prototype._repaintMeasureChars=function(){var t,e=this.dom;if(!e.measureCharMinor){t=document.createTextNode("0");var i=document.createElement("DIV");i.className="text minor measure",i.appendChild(t),this.frame.appendChild(i),e.measureCharMinor=i}if(!e.measureCharMajor){t=document.createTextNode("0");var n=document.createElement("DIV");n.className="text major measure",n.appendChild(t),this.frame.appendChild(n),e.measureCharMajor=n}},TimeAxis.prototype.reflow=function(){var t=0,e=util.updateProperty,i=this.frame,n=this.range;if(!n)throw new Error("Cannot repaint time axis: no range configured");if(i){t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft);var s=this.props,o=this.getOption("showMinorLabels"),r=this.getOption("showMajorLabels"),a=this.dom.measureCharMinor,h=this.dom.measureCharMajor;a&&(s.minorCharHeight=a.clientHeight,s.minorCharWidth=a.clientWidth),h&&(s.majorCharHeight=h.clientHeight,s.majorCharWidth=h.clientWidth);var l=i.parentNode?i.parentNode.offsetHeight:0;switch(l!=s.parentHeight&&(s.parentHeight=l,t+=1),this.getOption("orientation")){case"bottom":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.minorLabelTop=0,s.majorLabelTop=s.minorLabelTop+s.minorLabelHeight,s.minorLineTop=-this.top,s.minorLineHeight=Math.max(this.top+s.majorLabelHeight,0),s.minorLineWidth=1,s.majorLineTop=-this.top,s.majorLineHeight=Math.max(this.top+s.minorLabelHeight+s.majorLabelHeight,0),s.majorLineWidth=1,s.lineTop=0;break;case"top":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.majorLabelTop=0,s.minorLabelTop=s.majorLabelTop+s.majorLabelHeight,s.minorLineTop=s.minorLabelTop,s.minorLineHeight=Math.max(l-s.majorLabelHeight-this.top),s.minorLineWidth=1,s.majorLineTop=0,s.majorLineHeight=Math.max(l-this.top),s.majorLineWidth=1,s.lineTop=s.majorLabelHeight+s.minorLabelHeight;break;default:throw new Error('Unkown orientation "'+this.getOption("orientation")+'"')}var c=s.minorLabelHeight+s.majorLabelHeight;t+=e(this,"width",i.offsetWidth),t+=e(this,"height",c),this._updateConversion();var d=util.convert(n.start,"Number"),u=util.convert(n.end,"Number"),p=this.toTime(5*(s.minorCharWidth||10)).valueOf()-this.toTime(0).valueOf();this.step=new TimeStep(new Date(d),new Date(u),p),t+=e(s.range,"start",d),t+=e(s.range,"end",u),t+=e(s.range,"minimumStep",p.valueOf())}return t>0},TimeAxis.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):Range.conversion(t.start,t.end,this.width)},CurrentTime.prototype=new Component,CurrentTime.prototype.setOptions=Component.prototype.setOptions,CurrentTime.prototype.getContainer=function(){return this.frame},CurrentTime.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCurrentTime"))return void(t&&(i.removeChild(t),delete this.frame));t||(t=document.createElement("div"),t.className="currenttime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t),this.frame=t),e.conversion||e._updateConversion();var n=new Date,s=e.toScreen(n);t.style.left=s+"px",t.title="Current time: "+n,void 0!==this.currentTimeTimer&&(clearTimeout(this.currentTimeTimer),delete this.currentTimeTimer);var o=this,r=1/e.conversion.scale/2;return 30>r&&(r=30),this.currentTimeTimer=setTimeout(function(){o.repaint()},r),!1},CustomTime.prototype=new Component,CustomTime.prototype.setOptions=Component.prototype.setOptions,CustomTime.prototype.getContainer=function(){return this.frame},CustomTime.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCustomTime"))return void(t&&(i.removeChild(t),delete this.frame));if(!t){t=document.createElement("div"),t.className="customtime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t);var n=document.createElement("div");n.style.position="relative",n.style.top="0px",n.style.left="-10px",n.style.height="100%",n.style.width="20px",t.appendChild(n),this.frame=t,this.subscribe(this,"movetime")}e.conversion||e._updateConversion();var s=e.toScreen(this.customTime);return t.style.left=s+"px",t.title="Time: "+this.customTime,!1},CustomTime.prototype._setCustomTime=function(t){this.customTime=new Date(t.valueOf()),this.repaint()},CustomTime.prototype._getCustomTime=function(){return new Date(this.customTime.valueOf())},CustomTime.prototype.subscribe=function(t,e){var i=this,n={component:t,event:e,callback:function(t){i._onMouseDown(t,n)},params:{}};t.on("mousedown",n.callback),i.listeners.push(n)},CustomTime.prototype.on=function(t,e){var i=this.frame;if(!i)throw new Error("Cannot add event listener: no parent attached");events.addListener(this,t,e),util.addEventListener(i,t,e)},CustomTime.prototype._onMouseDown=function(t,e){t=t||window.event;var i=e.params,n=t.which?1==t.which:1==t.button;if(n){i.mouseX=util.getPageX(t),i.moved=!1,i.customTime=this.customTime;var s=this;i.onMouseMove||(i.onMouseMove=function(t){s._onMouseMove(t,e)},util.addEventListener(document,"mousemove",i.onMouseMove)),i.onMouseUp||(i.onMouseUp=function(t){s._onMouseUp(t,e)},util.addEventListener(document,"mouseup",i.onMouseUp)),util.stopPropagation(t),util.preventDefault(t)}},CustomTime.prototype._onMouseMove=function(t,e){t=t||window.event;var i=e.params,n=this.parent,s=util.getPageX(t);void 0===i.mouseX&&(i.mouseX=s);var o=s-i.mouseX;Math.abs(o)>=1&&(i.moved=!0);var r=n.toScreen(i.customTime),a=r+o,h=n.toTime(a);this._setCustomTime(h),events.trigger(this,"timechange",{customTime:this.customTime}),util.preventDefault(t)},CustomTime.prototype._onMouseUp=function(t,e){t=t||window.event;var i=e.params;i.onMouseMove&&(util.removeEventListener(document,"mousemove",i.onMouseMove),i.onMouseMove=null),i.onMouseUp&&(util.removeEventListener(document,"mouseup",i.onMouseUp),i.onMouseUp=null),i.moved&&events.trigger(this,"timechanged",{customTime:this.customTime}) },ItemSet.prototype=new Panel,ItemSet.types={box:ItemBox,range:ItemRange,rangeoverflow:ItemRangeOverflow,point:ItemPoint},ItemSet.prototype.setOptions=Component.prototype.setOptions,ItemSet.prototype.setRange=function(t){if(!(t instanceof Range||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},ItemSet.prototype.setSelection=function(t){var e,i,n,s,o;if(t){if(!Array.isArray(t))throw new TypeError("Array expected");for(e=0,i=this.selection.length;i>e;e++)n=this.selection[e],s=this.items[n],s&&s.unselect();for(this.selection=[],e=0,i=t.length;i>e;e++)n=t[e],s=this.items[n],s&&(this.selection.push(n),s.select());o=this.selection.concat([]),events.trigger(this,"select",{ids:o}),this.controller&&this.requestRepaint()}},ItemSet.prototype.getSelection=function(){return this.selection.concat([])},ItemSet.prototype._deselect=function(t){for(var e=this.selection,i=0,n=e.length;n>i;i++)if(e[i]==t){e.splice(i,1);break}},ItemSet.prototype.repaint=function(){var t=0,e=util.updateProperty,i=util.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.defaultOptions,r=this.frame;if(!r){r=document.createElement("div"),r.className="itemset";var a=n.className;a&&util.addClassName(r,util.option.asString(a));var h=document.createElement("div");h.className="background",r.appendChild(h),this.dom.background=h;var l=document.createElement("div");l.className="foreground",r.appendChild(l),this.dom.foreground=l;var c=document.createElement("div");c.className="itemset-axis",this.dom.axis=c,this.frame=r,t+=1}if(!this.parent)throw new Error("Cannot repaint itemset: no parent attached");var d=this.parent.getContainer();if(!d)throw new Error("Cannot repaint itemset: parent has no container element");r.parentNode||(d.appendChild(r),t+=1),this.dom.axis.parentNode||(d.appendChild(this.dom.axis),t+=1),t+=e(r.style,"left",i(n.left,"0px")),t+=e(r.style,"top",i(n.top,"0px")),t+=e(r.style,"width",i(n.width,"100%")),t+=e(r.style,"height",i(n.height,this.height+"px")),t+=e(this.dom.axis.style,"left",i(n.left,"0px")),t+=e(this.dom.axis.style,"width",i(n.width,"100%")),t+="bottom"==s?e(this.dom.axis.style,"top",this.height+this.top+"px"):e(this.dom.axis.style,"top",this.top+"px"),this._updateConversion();var u=this,p=this.queue,f=this.itemsData,g=this.items,m={};for(var v in p)if(p.hasOwnProperty(v)){var y=p[v],_=g[v],b=y.action;switch(b){case"add":case"update":var w=f&&f.get(v,m);if(w){var S=w.type||w.start&&w.end&&"range"||n.type||"box",T=ItemSet.types[S];if(_&&(T&&_ instanceof T?(_.data=w,t++):(t+=_.hide(),_=null)),!_){if(!T)throw new TypeError('Unknown item type "'+S+'"');_=new T(u,w,n,o),_.id=y.id,t++}_.repaint(),g[v]=_}delete p[v];break;case"remove":_&&(_.selected&&u._deselect(v),t+=_.hide()),delete g[v],delete p[v];break;default:console.log('Error: unknown action "'+b+'"')}}return util.forEach(this.items,function(e){e.visible?(t+=e.show(),e.reposition()):t+=e.hide()}),t>0},ItemSet.prototype.getForeground=function(){return this.dom.foreground},ItemSet.prototype.getBackground=function(){return this.dom.background},ItemSet.prototype.getAxis=function(){return this.dom.axis},ItemSet.prototype.reflow=function(){var t=0,e=this.options,i=e.margin&&e.margin.axis||this.defaultOptions.margin.axis,n=e.margin&&e.margin.item||this.defaultOptions.margin.item,s=util.updateProperty,o=util.option.asNumber,r=util.option.asSize,a=this.frame;if(a){this._updateConversion(),util.forEach(this.items,function(e){t+=e.reflow()}),this.stack.update();var h,l=o(e.maxHeight),c=null!=r(e.height);if(c)h=a.offsetHeight;else{var d=this.stack.ordered;if(d.length){var u=d[0].top,p=d[0].top+d[0].height;util.forEach(d,function(t){u=Math.min(u,t.top),p=Math.max(p,t.top+t.height)}),h=p-u+i+n}else h=i+n}null!=l&&(h=Math.min(h,l)),t+=s(this,"height",h),t+=s(this,"top",a.offsetTop),t+=s(this,"left",a.offsetLeft),t+=s(this,"width",a.offsetWidth)}else t+=1;return t>0},ItemSet.prototype.hide=function(){var t=!1;return this.frame&&this.frame.parentNode&&(this.frame.parentNode.removeChild(this.frame),t=!0),this.dom.axis&&this.dom.axis.parentNode&&(this.dom.axis.parentNode.removeChild(this.dom.axis),t=!0),t},ItemSet.prototype.setItems=function(t){var e,i=this,n=this.itemsData;if(t){if(!(t instanceof DataSet||t instanceof DataView))throw new TypeError("Data must be an instance of DataSet");this.itemsData=t}else this.itemsData=null;if(n&&(util.forEach(this.listeners,function(t,e){n.unsubscribe(e,t)}),e=n.getIds(),this._onRemove(e)),this.itemsData){var s=this.id;util.forEach(this.listeners,function(t,e){i.itemsData.subscribe(e,t,s)}),e=this.itemsData.getIds(),this._onAdd(e)}},ItemSet.prototype.getItems=function(){return this.itemsData},ItemSet.prototype._onUpdate=function(t){this._toQueue("update",t)},ItemSet.prototype._onAdd=function(t){this._toQueue("add",t)},ItemSet.prototype._onRemove=function(t){this._toQueue("remove",t)},ItemSet.prototype._toQueue=function(t,e){var i=this.queue;e.forEach(function(e){i[e]={id:e,action:t}}),this.controller&&this.requestRepaint()},ItemSet.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):Range.conversion(t.start,t.end,this.width)},ItemSet.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},ItemSet.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},Item.prototype.select=function(){this.selected=!0,this.visible&&this.repaint()},Item.prototype.unselect=function(){this.selected=!1,this.visible&&this.repaint()},Item.prototype.show=function(){return!1},Item.prototype.hide=function(){return!1},Item.prototype.repaint=function(){return!1},Item.prototype.reflow=function(){return!1},Item.prototype.getWidth=function(){return this.width},ItemBox.prototype=new Item(null,null),ItemBox.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");if(!e.box.parentNode){var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");i.appendChild(e.box),t=!0}if(!e.line.parentNode){var n=this.parent.getBackground();if(!n)throw new Error("Cannot repaint time axis: parent has no background container element");n.appendChild(e.line),t=!0}if(!e.dot.parentNode){var s=this.parent.getAxis();if(!n)throw new Error("Cannot repaint time axis: parent has no axis container element");s.appendChild(e.dot),t=!0}if(this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var o=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=o&&(this.className=o,e.box.className="item box"+o,e.line.className="item line"+o,e.dot.className="item dot"+o,t=!0)}return t},ItemBox.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},ItemBox.prototype.hide=function(){var t=!1,e=this.dom;return e&&(e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),e.line.parentNode&&e.line.parentNode.removeChild(e.line),e.dot.parentNode&&e.dot.parentNode.removeChild(e.dot)),t},ItemBox.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,l,c,d,u=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(c=this.data,d=this.parent&&this.parent.range,c&&d){var p=d.end-d.start;this.visible=c.start>d.start-p&&c.start0},ItemBox.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("DIV"),t.content=document.createElement("DIV"),t.content.className="content",t.box.appendChild(t.content),t.line=document.createElement("DIV"),t.line.className="line",t.dot=document.createElement("DIV"),t.dot.className="dot",t.box["timeline-item"]=this)},ItemBox.prototype.reposition=function(){var t=this.dom,e=this.props,i=this.options.orientation||this.defaultOptions.orientation;if(t){var n=t.box,s=t.line,o=t.dot;n.style.left=this.left+"px",n.style.top=this.top+"px",s.style.left=e.line.left+"px","top"==i?(s.style.top="0px",s.style.height=this.top+"px"):(s.style.top=this.top+this.height+"px",s.style.height=Math.max(this.parent.height-this.top-this.height+this.props.dot.height/2,0)+"px"),o.style.left=e.dot.left+"px",o.style.top=e.dot.top+"px"}},ItemPoint.prototype=new Item(null,null),ItemPoint.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.point.parentNode||(i.appendChild(e.point),i.appendChild(e.point),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.point.className="item point"+n,t=!0)}return t},ItemPoint.prototype.show=function(){return this.dom&&this.dom.point.parentNode?!1:this.repaint()},ItemPoint.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.point.parentNode&&(e.point.parentNode.removeChild(e.point),t=!0),t},ItemPoint.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,l,c=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(h=this.data,l=this.parent&&this.parent.range,h&&l){var d=l.end-l.start;this.visible=h.start>l.start-d&&h.start0},ItemPoint.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.point=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.point.appendChild(t.content),t.dot=document.createElement("div"),t.dot.className="dot",t.point.appendChild(t.dot),t.point["timeline-item"]=this)},ItemPoint.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.point.style.top=this.top+"px",t.point.style.left=this.left+"px",t.content.style.marginLeft=e.content.marginLeft+"px",t.dot.style.top=e.dot.top+"px")},ItemRange.prototype=new Item(null,null),ItemRange.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.box.className="item range"+n,t=!0)}return t},ItemRange.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},ItemRange.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),t},ItemRange.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,l,c,d,u,p,f,g,m=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(void 0==this.data.end)throw new Error('Property "end" missing in item '+this.data.id);return h=this.data,l=this.parent&&this.parent.range,this.visible=h&&l?h.startl.start:!1,this.visible&&(t=this.dom,t?(e=this.props,i=this.options,o=this.parent,r=o.toScreen(this.data.start),a=o.toScreen(this.data.end),c=util.updateProperty,d=t.box,u=o.width,f=i.orientation||this.defaultOptions.orientation,n=i.margin&&i.margin.axis||this.defaultOptions.margin.axis,s=i.padding||this.defaultOptions.padding,m+=c(e.content,"width",t.content.offsetWidth),m+=c(this,"height",d.offsetHeight),-u>r&&(r=-u),a>2*u&&(a=2*u),p=0>r?Math.min(-r,a-r-e.content.width-2*s):0,m+=c(e.content,"left",p),"top"==f?(g=n,m+=c(this,"top",g)):(g=o.height-this.height-n,m+=c(this,"top",g)),m+=c(this,"left",r),m+=c(this,"width",Math.max(a-r,1))):m+=1),m>0},ItemRange.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content),t.box["timeline-item"]=this)},ItemRange.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.box.style.top=this.top+"px",t.box.style.left=this.left+"px",t.box.style.width=this.width+"px",t.content.style.left=e.content.left+"px")},ItemRangeOverflow.prototype=new ItemRange(null,null),ItemRangeOverflow.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=this.data.className?" "+this.data.className:"";this.className!=n&&(this.className=n,e.box.className="item rangeoverflow"+n,t=!0)}return t},ItemRangeOverflow.prototype.getWidth=function(){return void 0!==this.props.content&&this.width0},GroupSet.prototype=new Panel,GroupSet.prototype.setOptions=Component.prototype.setOptions,GroupSet.prototype.setRange=function(){},GroupSet.prototype.setItems=function(t){this.itemsData=t;for(var e in this.groups)if(this.groups.hasOwnProperty(e)){var i=this.groups[e];i.setItems(t)}},GroupSet.prototype.getItems=function(){return this.itemsData},GroupSet.prototype.setRange=function(t){this.range=t},GroupSet.prototype.setGroups=function(t){var e,i=this;if(this.groupsData&&(util.forEach(this.listeners,function(t,e){i.groupsData.unsubscribe(e,t)}),e=this.groupsData.getIds(),this._onRemove(e)),t?t instanceof DataSet?this.groupsData=t:(this.groupsData=new DataSet({convert:{start:"Date",end:"Date"}}),this.groupsData.add(t)):this.groupsData=null,this.groupsData){var n=this.id;util.forEach(this.listeners,function(t,e){i.groupsData.subscribe(e,t,n)}),e=this.groupsData.getIds(),this._onAdd(e)}},GroupSet.prototype.getGroups=function(){return this.groupsData},GroupSet.prototype.setSelection=function(t){var e=[],i=this.groups;for(var n in i)if(i.hasOwnProperty(n)){var s=i[n];s.setSelection(t)}return e},GroupSet.prototype.getSelection=function(){var t=[],e=this.groups;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];t=t.concat(n.getSelection())}return t},GroupSet.prototype.repaint=function(){var t,e,i,n,s=0,o=util.updateProperty,r=util.option.asSize,a=util.option.asElement,h=this.options,l=this.dom.frame,c=this.dom.labels,d=this.dom.labelSet;if(!this.parent)throw new Error("Cannot repaint groupset: no parent attached");var u=this.parent.getContainer();if(!u)throw new Error("Cannot repaint groupset: parent has no container element");if(!l){l=document.createElement("div"),l.className="groupset",this.dom.frame=l;var p=h.className;p&&util.addClassName(l,util.option.asString(p)),s+=1}l.parentNode||(u.appendChild(l),s+=1);var f=a(h.labelContainer);if(!f)throw new Error('Cannot repaint groupset: option "labelContainer" not defined');c||(c=document.createElement("div"),c.className="labels",this.dom.labels=c),d||(d=document.createElement("div"),d.className="label-set",c.appendChild(d),this.dom.labelSet=d),c.parentNode&&c.parentNode==f||(c.parentNode&&c.parentNode.removeChild(c.parentNode),f.appendChild(c)),s+=o(l.style,"height",r(h.height,this.height+"px")),s+=o(l.style,"top",r(h.top,"0px")),s+=o(l.style,"left",r(h.left,"0px")),s+=o(l.style,"width",r(h.width,"100%")),s+=o(d.style,"top",r(h.top,"0px")),s+=o(d.style,"height",r(h.height,this.height+"px"));var g=this,m=this.queue,v=this.groups,y=this.groupsData,_=Object.keys(m);if(_.length){_.forEach(function(t){var e=m[t],i=v[t];switch(e){case"add":case"update":if(!i){var n=Object.create(g.options);util.extend(n,{height:null,maxHeight:null}),i=new Group(g,t,n),i.setItems(g.itemsData),v[t]=i,g.controller.add(i)}i.data=y.get(t),delete m[t];break;case"remove":i&&(i.setItems(),delete v[t],g.controller.remove(i)),delete m[t];break;default:console.log('Error: unknown action "'+e+'"')}});var b=this.groupsData.getIds({order:this.options.groupOrder});for(t=0;t0},GroupSet.prototype._createLabel=function(t){var e=this.groups[t],i=document.createElement("div");i.className="label";var n=document.createElement("div");n.className="inner",i.appendChild(n);var s=e.data&&e.data.content;s instanceof Element?n.appendChild(s):void 0!=s&&(n.innerHTML=s);var o=e.data&&e.data.className;return o&&util.addClassName(i,o),e.label=i,i},GroupSet.prototype.getContainer=function(){return this.dom.frame},GroupSet.prototype.getLabelsWidth=function(){return this.props.labels.width},GroupSet.prototype.reflow=function(){var t,e,i=0,n=this.options,s=util.updateProperty,o=util.option.asNumber,r=util.option.asSize,a=this.dom.frame;if(a){var h,l=o(n.maxHeight),c=null!=r(n.height);if(c)h=a.offsetHeight;else{h=0;for(t in this.groups)this.groups.hasOwnProperty(t)&&(e=this.groups[t],h+=e.height)}null!=l&&(h=Math.min(h,l)),i+=s(this,"height",h),i+=s(this,"top",a.offsetTop),i+=s(this,"left",a.offsetLeft),i+=s(this,"width",a.offsetWidth)}var d=0;for(t in this.groups)if(this.groups.hasOwnProperty(t)){e=this.groups[t];var u=e.props&&e.props.label&&e.props.label.width||0;d=Math.max(d,u)}return i+=s(this.props.labels,"width",d),i>0},GroupSet.prototype.hide=function(){return this.dom.frame&&this.dom.frame.parentNode?(this.dom.frame.parentNode.removeChild(this.dom.frame),!0):!1},GroupSet.prototype.show=function(){return this.dom.frame&&this.dom.frame.parentNode?!1:this.repaint()},GroupSet.prototype._onUpdate=function(t){this._toQueue(t,"update")},GroupSet.prototype._onAdd=function(t){this._toQueue(t,"add")},GroupSet.prototype._onRemove=function(t){this._toQueue(t,"remove")},GroupSet.prototype._toQueue=function(t,e){var i=this.queue;t.forEach(function(t){i[t]=e}),this.controller&&this.requestRepaint()},Timeline.prototype.setOptions=function(t){util.extend(this.options,t),this.range.setRange(t.start,t.end),this.controller.reflow(),this.controller.repaint()},Timeline.prototype.setCustomTime=function(t){this.customtime._setCustomTime(t)},Timeline.prototype.getCustomTime=function(){return new Date(this.customtime.customTime.valueOf())},Timeline.prototype.setItems=function(t){var e,i=null==this.itemsData;if(t?t instanceof DataSet&&(e=t):e=null,t instanceof DataSet||(e=new DataSet({convert:{start:"Date",end:"Date"}}),e.add(t)),this.itemsData=e,this.content.setItems(e),i&&(void 0==this.options.start||void 0==this.options.end)){var n=this.getItemRange(),s=n.min,o=n.max;if(null!=s&&null!=o){var r=o.valueOf()-s.valueOf();0>=r&&(r=864e5),s=new Date(s.valueOf()-.05*r),o=new Date(o.valueOf()+.05*r)}void 0!=this.options.start&&(s=util.convert(this.options.start,"Date")),void 0!=this.options.end&&(o=util.convert(this.options.end,"Date")),(null!=s||null!=o)&&this.range.setRange(s,o)}},Timeline.prototype.setGroups=function(t){var e=this;this.groupsData=t;var i=this.groupsData?GroupSet:ItemSet;if(!(this.content instanceof i)){this.content&&(this.content.hide(),this.content.setItems&&this.content.setItems(),this.content.setGroups&&this.content.setGroups(),this.controller.remove(this.content));var n=Object.create(this.options);util.extend(n,{top:function(){return"top"==e.options.orientation?e.timeaxis.height:e.itemPanel.height-e.timeaxis.height-e.content.height},left:null,width:"100%",height:function(){return e.options.height?e.itemPanel.height-e.timeaxis.height:null},maxHeight:function(){if(e.options.maxHeight){if(!util.isNumber(e.options.maxHeight))throw new TypeError("Number expected for property maxHeight");return e.options.maxHeight-e.timeaxis.height}return null},labelContainer:function(){return e.labelPanel.getContainer()}}),this.content=new i(this.itemPanel,[this.timeaxis],n),this.content.setRange&&this.content.setRange(this.range),this.content.setItems&&this.content.setItems(this.itemsData),this.content.setGroups&&this.content.setGroups(this.groupsData),this.controller.add(this.content)}},Timeline.prototype.getItemRange=function(){var t=this.itemsData,e=null,i=null;if(t){var n=t.min("start");e=n?n.start.valueOf():null;var s=t.max("start");s&&(i=s.start.valueOf());var o=t.max("end");o&&(i=null==i?o.end.valueOf():Math.max(i,o.end.valueOf()))}return{min:null!=e?new Date(e):null,max:null!=i?new Date(i):null}},Timeline.prototype.setSelection=function(t){this.content&&this.content.setSelection(t)},Timeline.prototype.getSelection=function(){return this.content?this.content.getSelection():[]},Timeline.prototype.on=function(t,e){var i=["rangechange","rangechanged","select"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());events.addListener(this,t,e)},Timeline.prototype.off=function(t,e){events.removeListener(this,t,e)},Timeline.prototype._trigger=function(t,e){events.trigger(this,t,e||{})},Timeline.prototype._onSelectItem=function(t){var e=this._itemFromTarget(t),i=e?[e.id]:[];this.setSelection(i),this._trigger("select",{items:this.getSelection()}),t.stopPropagation()},Timeline.prototype._onMultiSelectItem=function(t){var e,i=this._itemFromTarget(t);if(i){e=this.getSelection();var n=e.indexOf(i.id);-1==n?e.push(i.id):e.splice(n,1),this.setSelection(e),this._trigger("select",{items:this.getSelection()}),t.stopPropagation()}},Timeline.prototype._itemFromTarget=function(t){for(var e=t.target;e;){if(e.hasOwnProperty("timeline-item"))return e["timeline-item"];e=e.parentNode}return null},function(t){function e(t){return C=t,u()}function i(){M=0,D=C.charAt(0)}function n(){M++,D=C.charAt(M)}function s(){return C.charAt(M+1)}function o(t){return O.test(t)}function r(t,e){if(t||(t={}),e)for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function a(t,e,i){for(var n=e.split("."),s=t;n.length;){var o=n.shift();n.length?(s[o]||(s[o]={}),s=s[o]):s[o]=i}}function h(t,e){for(var i,n,s=null,o=[t],a=t;a.parent;)o.push(a.parent),a=a.parent;if(a.nodes)for(i=0,n=a.nodes.length;n>i;i++)if(e.id===a.nodes[i].id){s=a.nodes[i];break}for(s||(s={id:e.id},t.node&&(s.attr=r(s.attr,t.node))),i=o.length-1;i>=0;i--){var h=o[i];h.nodes||(h.nodes=[]),-1==h.nodes.indexOf(s)&&h.nodes.push(s)}e.attr&&(s.attr=r(s.attr,e.attr))}function l(t,e){if(t.edges||(t.edges=[]),t.edges.push(e),t.edge){var i=r({},t.edge);e.attr=r(i,e.attr)}}function c(t,e,i,n,s){var o={from:e,to:i,type:n};return t.edge&&(o.attr=r({},t.edge)),o.attr=r(o.attr||{},s),o}function d(){for(N=E.NULL,I="";" "==D||" "==D||"\n"==D||"\r"==D;)n();do{var t=!1;if("#"==D){for(var e=M-1;" "==C.charAt(e)||" "==C.charAt(e);)e--;if("\n"==C.charAt(e)||""==C.charAt(e)){for(;""!=D&&"\n"!=D;)n();t=!0}}if("/"==D&&"/"==s()){for(;""!=D&&"\n"!=D;)n();t=!0}if("/"==D&&"*"==s()){for(;""!=D;){if("*"==D&&"/"==s()){n(),n();break}n()}t=!0}for(;" "==D||" "==D||"\n"==D||"\r"==D;)n()}while(t);if(""==D)return void(N=E.DELIMITER);var i=D+s();if(x[i])return N=E.DELIMITER,I=i,n(),void n();if(x[D])return N=E.DELIMITER,I=D,void n();if(o(D)||"-"==D){for(I+=D,n();o(D);)I+=D,n();return"false"==I?I=!1:"true"==I?I=!0:isNaN(Number(I))||(I=Number(I)),void(N=E.IDENTIFIER)}if('"'==D){for(n();""!=D&&('"'!=D||'"'==D&&'"'==s());)I+=D,'"'==D&&n(),n();if('"'!=D)throw b('End of string " expected');return n(),void(N=E.IDENTIFIER)}for(N=E.UNKNOWN;""!=D;)I+=D,n();throw new SyntaxError('Syntax error in part "'+w(I,30)+'"')}function u(){var t={};if(i(),d(),"strict"==I&&(t.strict=!0,d()),("graph"==I||"digraph"==I)&&(t.type=I,d()),N==E.IDENTIFIER&&(t.id=I,d()),"{"!=I)throw b("Angle bracket { expected");if(d(),p(t),"}"!=I)throw b("Angle bracket } expected");if(d(),""!==I)throw b("End of file expected");return d(),delete t.node,delete t.edge,delete t.graph,t}function p(t){for(;""!==I&&"}"!=I;)f(t),";"==I&&d()}function f(t){var e=g(t);if(e)return void y(t,e);var i=m(t);if(!i){if(N!=E.IDENTIFIER)throw b("Identifier expected");var n=I;if(d(),"="==I){if(d(),N!=E.IDENTIFIER)throw b("Identifier expected");t[n]=I,d()}else v(t,n)}}function g(t){var e=null;if("subgraph"==I&&(e={},e.type="subgraph",d(),N==E.IDENTIFIER&&(e.id=I,d())),"{"==I){if(d(),e||(e={}),e.parent=t,e.node=t.node,e.edge=t.edge,e.graph=t.graph,p(e),"}"!=I)throw b("Angle bracket } expected");d(),delete e.node,delete e.edge,delete e.graph,delete e.parent,t.subgraphs||(t.subgraphs=[]),t.subgraphs.push(e)}return e}function m(t){return"node"==I?(d(),t.node=_(),"node"):"edge"==I?(d(),t.edge=_(),"edge"):"graph"==I?(d(),t.graph=_(),"graph"):null}function v(t,e){var i={id:e},n=_();n&&(i.attr=n),h(t,i),y(t,e)}function y(t,e){for(;"->"==I||"--"==I;){var i,n=I;d();var s=g(t);if(s)i=s;else{if(N!=E.IDENTIFIER)throw b("Identifier or subgraph expected");i=I,h(t,{id:i}),d()}var o=_(),r=c(t,e,i,n,o);l(t,r),e=i}}function _(){for(var t=null;"["==I;){for(d(),t={};""!==I&&"]"!=I;){if(N!=E.IDENTIFIER)throw b("Attribute name expected");var e=I;if(d(),"="!=I)throw b("Equal sign = expected");if(d(),N!=E.IDENTIFIER)throw b("Attribute value expected");var i=I;a(t,e,i),d(),","==I&&d()}if("]"!=I)throw b("Bracket ] expected");d()}return t}function b(t){return new SyntaxError(t+', got "'+w(I,30)+'" (char '+M+")")}function w(t,e){return t.length<=e?t:t.substr(0,27)+"..."}function S(t,e,i){t instanceof Array?t.forEach(function(t){e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}):e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}function T(t){function i(t){var e={from:t.from,to:t.to};return r(e,t.attr),e.style="->"==t.type?"arrow":"line",e}var n=e(t),s={nodes:[],edges:[],options:{}};return n.nodes&&n.nodes.forEach(function(t){var e={id:t.id,label:String(t.label||t.id)};r(e,t.attr),e.image&&(e.shape="image"),s.nodes.push(e)}),n.edges&&n.edges.forEach(function(t){var e,n;e=t.from instanceof Object?t.from.nodes:{id:t.from},n=t.to instanceof Object?t.to.nodes:{id:t.to},t.from instanceof Object&&t.from.edges&&t.from.edges.forEach(function(t){var e=i(t);s.edges.push(e)}),S(e,n,function(e,n){var o=c(s,e.id,n.id,t.type,t.attr),r=i(o);s.edges.push(r)}),t.to instanceof Object&&t.to.edges&&t.to.edges.forEach(function(t){var e=i(t);s.edges.push(e)})}),n.attr&&(s.options=n.attr),s}var E={NULL:0,DELIMITER:1,IDENTIFIER:2,UNKNOWN:3},x={"{":!0,"}":!0,"[":!0,"]":!0,";":!0,"=":!0,",":!0,"->":!0,"--":!0},C="",M=0,D="",I="",N=E.NULL,O=/[a-zA-Z_0-9.:#]/;t.parseDOT=e,t.DOTToGraph=T}("undefined"!=typeof util?util:exports),"undefined"!=typeof CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.circle=function(t,e,i){this.beginPath(),this.arc(t,e,i,0,2*Math.PI,!1)},CanvasRenderingContext2D.prototype.square=function(t,e,i){this.beginPath(),this.rect(t-i,e-i,2*i,2*i)},CanvasRenderingContext2D.prototype.triangle=function(t,e,i){this.beginPath();var n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e-(r-o)),this.lineTo(t+s,e+o),this.lineTo(t-s,e+o),this.lineTo(t,e-(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.triangleDown=function(t,e,i){this.beginPath();var n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e+(r-o)),this.lineTo(t+s,e-o),this.lineTo(t-s,e-o),this.lineTo(t,e+(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.star=function(t,e,i){this.beginPath();for(var n=0;10>n;n++){var s=n%2===0?1.3*i:.5*i;this.lineTo(t+s*Math.sin(2*n*Math.PI/10),e-s*Math.cos(2*n*Math.PI/10))}this.closePath()},CanvasRenderingContext2D.prototype.roundRect=function(t,e,i,n,s){var o=Math.PI/180;0>i-2*s&&(s=i/2),0>n-2*s&&(s=n/2),this.beginPath(),this.moveTo(t+s,e),this.lineTo(t+i-s,e),this.arc(t+i-s,e+s,s,270*o,360*o,!1),this.lineTo(t+i,e+n-s),this.arc(t+i-s,e+n-s,s,0,90*o,!1),this.lineTo(t+s,e+n),this.arc(t+s,e+n-s,s,90*o,180*o,!1),this.lineTo(t,e+s),this.arc(t+s,e+s,s,180*o,270*o,!1)},CanvasRenderingContext2D.prototype.ellipse=function(t,e,i,n){var s=.5522848,o=i/2*s,r=n/2*s,a=t+i,h=e+n,l=t+i/2,c=e+n/2;this.beginPath(),this.moveTo(t,c),this.bezierCurveTo(t,c-r,l-o,e,l,e),this.bezierCurveTo(l+o,e,a,c-r,a,c),this.bezierCurveTo(a,c+r,l+o,h,l,h),this.bezierCurveTo(l-o,h,t,c+r,t,c)},CanvasRenderingContext2D.prototype.database=function(t,e,i,n){var s=1/3,o=i,r=n*s,a=.5522848,h=o/2*a,l=r/2*a,c=t+o,d=e+r,u=t+o/2,p=e+r/2,f=e+(n-r/2),g=e+n; -this.beginPath(),this.moveTo(c,p),this.bezierCurveTo(c,p+l,u+h,d,u,d),this.bezierCurveTo(u-h,d,t,p+l,t,p),this.bezierCurveTo(t,p-l,u-h,e,u,e),this.bezierCurveTo(u+h,e,c,p-l,c,p),this.lineTo(c,f),this.bezierCurveTo(c,f+l,u+h,g,u,g),this.bezierCurveTo(u-h,g,t,f+l,t,f),this.lineTo(t,p)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,n){var s=t-n*Math.cos(i),o=e-n*Math.sin(i),r=t-.9*n*Math.cos(i),a=e-.9*n*Math.sin(i),h=s+n/3*Math.cos(i+.5*Math.PI),l=o+n/3*Math.sin(i+.5*Math.PI),c=s+n/3*Math.cos(i-.5*Math.PI),d=o+n/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,l),this.lineTo(r,a),this.lineTo(c,d),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,n,s){s||(s=[10,5]),0==u&&(u=.001);var o=s.length;this.moveTo(t,e);for(var r=i-t,a=n-e,h=a/r,l=Math.sqrt(r*r+a*a),c=0,d=!0;l>=.1;){var u=s[c++%o];u>l&&(u=l);var p=Math.sqrt(u*u/(1+h*h));0>r&&(p=-p),t+=p,e+=h*p,this[d?"lineTo":"moveTo"](t,e),l-=u,d=!d}}),Node.prototype.resetCluster=function(){this.formationScale=void 0,this.clusterSize=1,this.containedNodes={},this.containedEdges={},this.clusterSessions=[]},Node.prototype.attachEdge=function(t){-1==this.edges.indexOf(t)&&this.edges.push(t),-1==this.dynamicEdges.indexOf(t)&&this.dynamicEdges.push(t),this.dynamicEdgesLength=this.dynamicEdges.length,this._updateMass()},Node.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&(this.edges.splice(e,1),this.dynamicEdges.splice(e,1)),this.dynamicEdgesLength=this.dynamicEdges.length,this._updateMass()},Node.prototype._updateMass=function(){this.mass=1},Node.prototype.setProperties=function(t,e){if(t){if(this.originalLabel=void 0,void 0!==t.id&&(this.id=t.id),void 0!==t.label&&(this.label=t.label,this.originalLabel=t.label),void 0!==t.title&&(this.title=t.title),void 0!==t.group&&(this.group=t.group),void 0!==t.x&&(this.x=t.x),void 0!==t.y&&(this.y=t.y),void 0!==t.value&&(this.value=t.value),void 0!==t.horizontalAlignLeft&&(this.horizontalAlignLeft=t.horizontalAlignLeft),void 0!==t.verticalAlignTop&&(this.verticalAlignTop=t.verticalAlignTop),void 0!==t.triggerFunction&&(this.triggerFunction=t.triggerFunction),void 0===this.id)throw"Node must have an id";if(this.group){var i=this.grouplist.get(this.group);for(var n in i)i.hasOwnProperty(n)&&(this[n]=i[n])}if(void 0!==t.shape&&(this.shape=t.shape),void 0!==t.image&&(this.image=t.image),void 0!==t.radius&&(this.radius=t.radius),void 0!==t.color&&(this.color=Node.parseColor(t.color)),void 0!==t.fontColor&&(this.fontColor=t.fontColor),void 0!==t.fontSize&&(this.fontSize=t.fontSize),void 0!==t.fontFace&&(this.fontFace=t.fontFace),void 0!==this.image){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.image)}switch(this.xFixed=this.xFixed||void 0!==t.x&&t.fixed,this.yFixed=this.yFixed||void 0!==t.y&&t.fixed,this.radiusFixed=this.radiusFixed||void 0!==t.radius,"image"==this.shape&&(this.radiusMin=e.nodes.widthMin,this.radiusMax=e.nodes.widthMax),this.shape){case"database":this.draw=this._drawDatabase,this.resize=this._resizeDatabase;break;case"box":this.draw=this._drawBox,this.resize=this._resizeBox;break;case"circle":this.draw=this._drawCircle,this.resize=this._resizeCircle;break;case"ellipse":this.draw=this._drawEllipse,this.resize=this._resizeEllipse;break;case"image":this.draw=this._drawImage,this.resize=this._resizeImage;break;case"text":this.draw=this._drawText,this.resize=this._resizeText;break;case"dot":this.draw=this._drawDot,this.resize=this._resizeShape;break;case"square":this.draw=this._drawSquare,this.resize=this._resizeShape;break;case"triangle":this.draw=this._drawTriangle,this.resize=this._resizeShape;break;case"triangleDown":this.draw=this._drawTriangleDown,this.resize=this._resizeShape;break;case"star":this.draw=this._drawStar,this.resize=this._resizeShape;break;default:this.draw=this._drawEllipse,this.resize=this._resizeEllipse}this._reset()}},Node.parseColor=function(t){var e;return util.isString(t)?e={border:t,background:t,highlight:{border:t,background:t}}:(e={},e.background=t.background||"white",e.border=t.border||e.background,util.isString(t.highlight)?e.highlight={border:t.highlight,background:t.highlight}:(e.highlight={},e.highlight.background=t.highlight&&t.highlight.background||e.background,e.highlight.border=t.highlight&&t.highlight.border||e.border)),e},Node.prototype.select=function(){this.selected=!0,this._reset()},Node.prototype.unselect=function(){this.selected=!1,this._reset()},Node.prototype.clearSizeCache=function(){this._reset()},Node.prototype._reset=function(){this.width=void 0,this.height=void 0},Node.prototype.getTitle=function(){return this.title},Node.prototype.distanceToBorder=function(t,e){var i=1;switch(this.width||this.resize(t),this.shape){case"circle":case"dot":return this.radius+i;case"ellipse":var n=this.width/2,s=this.height/2,o=Math.sin(e)*n,r=Math.cos(e)*s;return n*s/Math.sqrt(o*o+r*r);case"box":case"image":case"text":default:return this.width?Math.min(Math.abs(this.width/2/Math.cos(e)),Math.abs(this.height/2/Math.sin(e)))+i:0}},Node.prototype._setForce=function(t,e){this.fx=t,this.fy=e},Node.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},Node.prototype.discreteStep=function(t){if(!this.xFixed){var e=-this.damping*this.vx,i=(this.fx+e)/this.mass;this.vx+=i*t,this.x+=this.vx*t}if(!this.yFixed){var n=-this.damping*this.vy,s=(this.fy+n)/this.mass;this.vy+=s*t,this.y+=this.vy*t}},Node.prototype.isFixed=function(){return this.xFixed&&this.yFixed},Node.prototype.isMoving=function(t){return Math.abs(this.vx)>t||Math.abs(this.vy)>t?!0:(this.vx=0,this.vy=0,!1)},Node.prototype.isSelected=function(){return this.selected},Node.prototype.getValue=function(){return this.value},Node.prototype.getDistance=function(t,e){var i=this.x-t,n=this.y-e;return Math.sqrt(i*i+n*n)},Node.prototype.setValueRange=function(t,e){if(!this.radiusFixed&&void 0!==this.value)if(e==t)this.radius=(this.radiusMin+this.radiusMax)/2;else{var i=(this.radiusMax-this.radiusMin)/(e-t);this.radius=(this.value-t)*i+this.radiusMin}this.baseRadiusValue=this.radius},Node.prototype.draw=function(){throw"Draw method not initialized for node"},Node.prototype.resize=function(){throw"Resize method not initialized for node"},Node.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},Node.prototype._resizeImage=function(){if(!this.width||!this.height){var t,e;if(this.value){this.radius=this.baseRadiusValue;var i=this.imageObj.height/this.imageObj.width;void 0!==i?(t=this.radius||this.imageObj.width,e=this.radius*i||this.imageObj.height):(t=0,e=0)}else t=this.imageObj.width,e=this.imageObj.height;this.width=t,this.height=e,this.width>0&&this.height>0&&(this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor)}},Node.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e;if(0!=this.imageObj.width){if(this.clusterSize>1){var i=this.clusterSize>1?10:0;i*=this.graphScaleInv,i=Math.min(.2*this.width,i),t.globalAlpha=.5,t.drawImage(this.imageObj,this.left-i,this.top-i,this.width+2*i,this.height+2*i)}t.globalAlpha=1,t.drawImage(this.imageObj,this.left,this.top,this.width,this.height),e=this.y+this.height/2}else e=this.y;this._label(t,this.label,this.x,e,void 0,"top")},Node.prototype._resizeBox=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=.5*(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=.5*(this.clusterSize-1)*this.clusterSizeHeightFactor}},Node.prototype._drawBox=function(t){this._resizeBox(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.roundRect(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth,this.radius),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.roundRect(this.left,this.top,this.width,this.height,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.prototype._resizeDatabase=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=i.width+2*e;this.width=n,this.height=n,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor}},Node.prototype._drawDatabase=function(t){this._resizeDatabase(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.database(this.x-this.width/2-2*t.lineWidth,this.y-.5*this.height-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.database(this.x-this.width/2,this.y-.5*this.height,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=Math.max(i.width,i.height)+2*e;this.radius=n/2,this.width=n,this.height=n,this.radius+=.5*(this.clusterSize-1)*this.clusterSizeRadiusFactor}},Node.prototype._drawCircle=function(){},Node.prototype._resizeEllipse=function(t){if(!this.width){var e=this.getTextSize(t);this.width=1.5*e.width,this.height=2*e.height,this.width1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.ellipse(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.ellipse(this.left,this.top,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.prototype._drawDot=function(t){this._drawShape(t,"circle")},Node.prototype._drawTriangle=function(t){this._drawShape(t,"triangle")},Node.prototype._drawTriangleDown=function(t){this._drawShape(t,"triangleDown")},Node.prototype._drawSquare=function(t){this._drawShape(t,"square")},Node.prototype._drawStar=function(t){this._drawShape(t,"star")},Node.prototype._resizeShape=function(){if(!this.width){this.radius=this.baseRadiusValue;var t=2*this.radius;this.width=t,this.height=t,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=.5*(this.clusterSize-1)*this.clusterSizeRadiusFactor}},Node.prototype._drawShape=function(t,e){this._resizeShape(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var i=2.5,n=2,s=2;switch(e){case"dot":s=2;break;case"square":s=2;break;case"triangle":s=3;break;case"triangleDown":s=3;break;case"star":s=4}t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?n:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t[e](this.x,this.y,this.radius+s*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?n:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t[e](this.x,this.y,this.radius),t.fill(),t.stroke(),this.label&&this._label(t,this.label,this.x,this.y+this.height/2,void 0,"top")},Node.prototype._resizeText=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor}},Node.prototype._drawText=function(t){this._resizeText(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,this._label(t,this.label,this.x,this.y)},Node.prototype._label=function(t,e,i,n,s,o){if(e){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle=this.fontColor||"black",t.textAlign=s||"center",t.textBaseline=o||"middle";for(var r=e.split("\n"),a=r.length,h=this.fontSize+4,l=n+(1-a)/2*h,c=0;a>c;c++)t.fillText(r[c],i,l),l+=h}},Node.prototype.getTextSize=function(t){if(void 0!==this.label){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace;for(var e=this.label.split("\n"),i=(this.fontSize+4)*e.length,n=0,s=0,o=e.length;o>s;s++)n=Math.max(n,t.measureText(e[s]).width);return{width:n,height:i}}return{width:0,height:0}},Node.prototype.inArea=function(){return void 0!==this.width?this.x+this.width*this.graphScaleInv>=this.canvasTopLeft.x&&this.x-this.width*this.graphScaleInv=this.canvasTopLeft.y&&this.y-this.height*this.graphScaleInv=this.canvasTopLeft.x&&this.x=this.canvasTopLeft.y&&this.yh},Edge.prototype._drawLine=function(t){t.strokeStyle=this.color,t.lineWidth=this._getLineWidth();var e;if(this.from!=this.to)this._line(t),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y));else{var i,n,s=this.length/4,o=this.from;o.width||o.resize(t),o.width>o.height?(i=o.x+o.width/2,n=o.y-s):(i=o.x+s,n=o.y-o.height/2),this._circle(t,i,n,s),e=this._pointOnCircle(i,n,s,.5),this._label(t,this.label,e.x,e.y)}},Edge.prototype._getLineWidth=function(){return 1==this.selected?Math.min(2*this.width,this.widthMax)*this.graphScaleInv:this.width*this.graphScaleInv},Edge.prototype._line=function(t){t.beginPath(),t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y),t.stroke()},Edge.prototype._circle=function(t,e,i,n){t.beginPath(),t.arc(e,i,n,0,2*Math.PI,!1),t.stroke()},Edge.prototype._label=function(t,e,i,n){if(e){t.font=(this.from.selected||this.to.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle="white";var s=t.measureText(e).width,o=this.fontSize,r=i-s/2,a=n-o/2;t.fillRect(r,a,s,o),t.fillStyle=this.fontColor||"black",t.textAlign="left",t.textBaseline="top",t.fillText(e,r,a)}},Edge.prototype._drawDashLine=function(t){if(t.strokeStyle=this.color,t.lineWidth=this._getLineWidth(),t.beginPath(),t.lineCap="round",void 0!==this.dash.altLength?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]):void 0!==this.dash.length&&void 0!==this.dash.gap?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap]):(t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y)),t.stroke(),this.label){var e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}},Edge.prototype._pointOnLine=function(t){return{x:(1-t)*this.from.x+t*this.to.x,y:(1-t)*this.from.y+t*this.to.y}},Edge.prototype._pointOnCircle=function(t,e,i,n){var s=2*(n-3/8)*Math.PI;return{x:t+i*Math.cos(s),y:e-i*Math.sin(s)}},Edge.prototype._drawArrowCenter=function(t){var e;if(t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth(),this.from!=this.to){this._line(t);var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),n=10+5*this.width;e=this._pointOnLine(.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y))}else{var s,o,r=this.length/4,a=this.from;a.width||a.resize(t),a.width>a.height?(s=a.x+a.width/2,o=a.y-r):(s=a.x+r,o=a.y-a.height/2),this._circle(t,s,o,r);var i=.2*Math.PI,n=10+5*this.width;e=this._pointOnCircle(s,o,r,.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(s,o,r,.5),this._label(t,this.label,e.x,e.y))}},Edge.prototype._drawArrow=function(t){t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth();var e,i;if(this.from!=this.to){e=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x);var n=this.to.x-this.from.x,s=this.to.y-this.from.y,o=Math.sqrt(n*n+s*s),r=this.from.distanceToBorder(t,e+Math.PI),a=(o-r)/o,h=a*this.from.x+(1-a)*this.to.x,l=a*this.from.y+(1-a)*this.to.y,c=this.to.distanceToBorder(t,e),d=(o-c)/o,u=(1-d)*this.from.x+d*this.to.x,p=(1-d)*this.from.y+d*this.to.y;if(t.beginPath(),t.moveTo(h,l),t.lineTo(u,p),t.stroke(),i=10+5*this.width,t.arrow(u,p,e,i),t.fill(),t.stroke(),this.label){var f=this._pointOnLine(.5);this._label(t,this.label,f.x,f.y)}}else{var g,m,v,y=this.from,_=this.length/4;y.width||y.resize(t),y.width>y.height?(g=y.x+y.width/2,m=y.y-_,v={x:g,y:y.y,angle:.9*Math.PI}):(g=y.x+_,m=y.y-y.height/2,v={x:y.x,y:m,angle:.6*Math.PI}),t.beginPath(),t.arc(g,m,_,0,2*Math.PI,!1),t.stroke(),i=10+5*this.width,t.arrow(v.x,v.y,v.angle,i),t.fill(),t.stroke(),this.label&&(f=this._pointOnCircle(g,m,_,.5),this._label(t,this.label,f.x,f.y))}},Edge._dist=function(t,e,i,n,s,o){var r=i-t,a=n-e,h=r*r+a*a,l=((s-t)*r+(o-e)*a)/h;l>1?l=1:0>l&&(l=0);var c=t+l*r,d=e+l*a,u=c-s,p=d-o;return Math.sqrt(u*u+p*p)},Edge.prototype.setScale=function(t){this.graphScaleInv=1/t},Edge.prototype.select=function(){this.selected=!0},Edge.prototype.unselect=function(){this.selected=!1},Popup.prototype.setPosition=function(t,e){this.x=parseInt(t),this.y=parseInt(e)},Popup.prototype.setText=function(t){this.frame.innerHTML=t},Popup.prototype.show=function(t){if(void 0===t&&(t=!0),t){var e=this.frame.clientHeight,i=this.frame.clientWidth,n=this.frame.parentNode.clientHeight,s=this.frame.parentNode.clientWidth,o=this.y-e;o+e+this.padding>n&&(o=n-e-this.padding),os&&(r=s-i-this.padding),rthis.constants.clustering.clusterThreshold&&1==this.constants.clustering.enabled&&this.clusterToFit(this.constants.clustering.reduceToNodes,!1),this._calculateForcesBarnesHut())},_calculateForcesOriginal:function(){var t=Date.now();this._calculateGravitationalForces(1);var e=Date.now();this._calculateRepulsionForces();var i=Date.now(),n=Date.now();echo("Time repulsion part:",i-e),echo("Time total force calc:",n-t)},_calculateForcesBarnesHut:function(){var t=Date.now();this._clearForces();var e=Date.now();this._calculateBarnesHutForces();var i=Date.now();this._calculateSpringForces(1);var n=Date.now();echo("Time repulsion part:",i-e),echo("Time total force calc:",n-t)},_clearForces:function(){for(var t,e=this.nodes,i=0;in&&(i=Math.atan2(e,t),a=.5*g>n?1:m*n+f,a*=0==r?1:1+r*this.constants.clustering.forceAmplification,s=Math.cos(i)*a,o=Math.sin(i)*a,h._addForce(-s,-o),l._addForce(s,o))}},_calculateSpringForces:function(t){var e,i,n,s,o,r,a,h,l,c,d,u=this.edges;for(c in u)u.hasOwnProperty(c)&&(l=u[c],l.connected&&this.nodes.hasOwnProperty(l.toId)&&this.nodes.hasOwnProperty(l.fromId)&&(d=l.to.clusterSize+l.from.clusterSize-2,e=l.to.x-l.from.x,i=l.to.y-l.from.y,h=l.length,h+=d*this.constants.clustering.edgeGrowth,a=Math.sqrt(e*e+i*i),n=Math.atan2(i,e),r=l.stiffness*(h-a)*t,s=Math.cos(n)*r,o=Math.sin(n)*r,l.from._addForce(-s,-o),l.to._addForce(s,o)))},_calculateBarnesHutForces:function(){this._formBarnesHutTree();var t,e=this.nodes,i=this.nodeIndices,n=i.length,s=this.barnesHutTree;this.maxAllowedForce=100,this.theta=.8,this.graviationalConstant=-1e4;for(var o=0;n>o;o++)t=e[i[o]],this._getForceContribution(s.root.children.NW,t),this._getForceContribution(s.root.children.NE,t),this._getForceContribution(s.root.children.SW,t),this._getForceContribution(s.root.children.SE,t);for(o=0;n>o;o++)t=e[i[o]],t.fx=Math.abs(t.fx)>this.maxAllowedForce?t.fx<0?-this.maxAllowedForce:this.maxAllowedForce:t.fx,t.fy=Math.abs(t.fy)>this.maxAllowedForce?t.fy<0?-this.maxAllowedForce:this.maxAllowedForce:t.fy},_getForceContribution:function(t,e){if(t.childrenCount>0){var i,n,s;if(i=t.CenterOfMass.x-e.x,n=t.CenterOfMass.y-e.y,s=Math.sqrt(i*i+n*n),s>0){var o=1/s;t.size*o>this.theta?4==t.childrenCount?(this._getForceContribution(t.children.NW,e),this._getForceContribution(t.children.NE,e),this._getForceContribution(t.children.SW,e),this._getForceContribution(t.children.SE,e)):this._getForceOnNode(t,e,i,n,o):this._getForceOnNode(t,e,i,n,o)}}},_getForceOnNode:function(t,e,i,n,s){var o=this.graviationalConstant*t.mass*e.mass*s*s,r=Math.atan2(n,i),a=Math.cos(r)*o,h=Math.sin(r)*o;e._addForce(a,h)},_formBarnesHutTree:function(){for(var t,e=this.nodes,i=this.nodeIndices,n=i.length,s=Number.MAX_VALUE,o=Number.MAX_VALUE,r=-Number.MAX_VALUE,a=-Number.MAX_VALUE,h=0;n>h;h++){var l=e[i[h]].x,c=e[i[h]].y;s>l&&(s=l),l>r&&(r=l),o>c&&(o=c),c>a&&(a=c)}var d=Math.abs(r-s)-Math.abs(a-o);d>0?(o-=.5*d,a+=.5*d):(s+=.5*d,a-=.5*d);var u={root:{CenterOfMass:{x:0,y:0},mass:0,range:{minX:s,maxX:r,minY:o,maxY:a},size:Math.abs(r-s),children:{data:null},childrenCount:4}};for(this._splitBranch(u.root),h=0;n>h;h++)t=e[i[h]],this._placeInTree(u.root,t);this.barnesHutTree=u},_updateBranchMass:function(t,e){var i=t.mass+e.mass,n=1/i;t.CenterOfMass.x=t.CenterOfMass.x*t.mass+e.x*e.mass,t.CenterOfMass.x*=n,t.CenterOfMass.y=t.CenterOfMass.y*t.mass+e.y*e.mass,t.CenterOfMass.y*=n,t.mass=i},_placeInTree:function(t,e){this._updateBranchMass(t,e),t.children.NW.range.maxX>e.x?t.children.NW.range.maxY>e.y?this._placeInRegion(t,e,"NW"):this._placeInRegion(t,e,"SW"):t.children.NE.range.maxY>e.y?this._placeInRegion(t,e,"NE"):this._placeInRegion(t,e,"SE")},_placeInRegion:function(t,e,i){switch(t.children[i].childrenCount){case 0:t.children[i].children.data=e,t.children[i].childrenCount=1,this._updateBranchMass(t.children[i],e);break;case 1:this._splitBranch(t.children[i]),this._placeInTree(t.children[i],e);break;case 4:this._placeInTree(t.children[i],e)}},_splitBranch:function(t){var e=null;1==t.childrenCount&&(e=t.children.data,t.mass=0,t.CenterOfMass.x=0,t.CenterOfMass.y=0),t.childrenCount=4,t.children.data=null,this._insertRegion(t,"NW"),this._insertRegion(t,"NE"),this._insertRegion(t,"SW"),this._insertRegion(t,"SE"),null!=e&&this._placeInTree(t,e)},_insertRegion:function(t,e){var i,n,s,o;switch(e){case"NW":i=t.range.minX,n=t.range.minX+t.size,s=t.range.minY,o=t.range.minY+t.size;break;case"NE":i=t.range.minX+t.size,n=t.range.maxX,s=t.range.minY,o=t.range.minY+t.size;break;case"SW":i=t.range.minX,n=t.range.minX+t.size,s=t.range.minY+t.size,o=t.range.maxY;break;case"SE":i=t.range.minX+t.size,n=t.range.maxX,s=t.range.minY+t.size,o=t.range.maxY}t.children[e]={CenterOfMass:{x:0,y:0},mass:0,range:{minX:i,maxX:n,minY:s,maxY:o},size:.5*t.size,children:{data:null},childrenCount:0}},_drawTree:function(t,e){void 0!==this.barnesHutTree&&(t.lineWidth=2,this._drawBranch(this.barnesHutTree.root,t,e))},_drawBranch:function(t,e,i){void 0===i&&(i="#FF0000"),4==t.childrenCount&&(this._drawBranch(t.children.NW,e),this._drawBranch(t.children.NE,e),this._drawBranch(t.children.SE,e),this._drawBranch(t.children.SW,e)),e.strokeStyle=i,e.beginPath(),e.moveTo(t.range.minX,t.range.minY),e.lineTo(t.range.maxX,t.range.minY),e.stroke(),e.beginPath(),e.moveTo(t.range.maxX,t.range.minY),e.lineTo(t.range.maxX,t.range.maxY),e.stroke(),e.beginPath(),e.moveTo(t.range.maxX,t.range.maxY),e.lineTo(t.range.minX,t.range.maxY),e.stroke(),e.beginPath(),e.moveTo(t.range.minX,t.range.maxY),e.lineTo(t.range.minX,t.range.minY),e.stroke()}},manipulationMixin={_clearManipulatorBar:function(){for(;this.manipulationDiv.hasChildNodes();)this.manipulationDiv.removeChild(this.manipulationDiv.firstChild)},_createManipulatorBar:function(){for(this.off("select",this.boundFunction),this.blockConnectingEdgeSelection=!1,this.forceAppendSelection=!1;this.manipulationDiv.hasChildNodes();)this.manipulationDiv.removeChild(this.manipulationDiv.firstChild);this.manipulationDiv.innerHTML="Add Node
    Edit Selected
    Connect Node
    Delete selected";var t=document.getElementById("manipulate-addNode");t.onclick=this._createAddToolbar.bind(this);var e=document.getElementById("manipulate-editNode");e.onclick=this._createEditToolbar.bind(this);var i=document.getElementById("manipulate-connectNode");i.onclick=this._createConnectToolbar.bind(this);var n=document.getElementById("manipulate-delete");n.onclick=this._createDeletionToolbar.bind(this)},_createAddToolbar:function(){this._clearManipulatorBar(),this.off("select",this.boundFunction),this.manipulationDiv.innerHTML="Back
    Click in an empty space to place a new node";var t=document.getElementById("manipulate-back"); -t.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._addNode.bind(this),this.on("select",this.boundFunction)},_createEditToolbar:function(){this.blockConnectingEdgeSelection=!1,this._clearManipulatorBar(),this.off("select",this.boundFunction);var t="";if(this._selectionIsEmpty()?t="Select a node or edge to edit.":this._getSelectedObjectCount()>1?(t="Select a single node or edge to edit.",this._unselectAll(!0)):this._clusterInSelection()?(t="You cannot edit a cluster.",this._unselectAll(!0)):this._getSelectedNodeCount()>0?this._createEditNodeToolbar():this._createEditEdgeToolbar(),""!=t){this.blockConnectingEdgeSelection=!0,this.manipulationDiv.innerHTML="Back
    "+t+"";var e=document.getElementById("manipulate-back");e.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._createEditToolbar.bind(this),this.on("select",this.boundFunction)}},_createEditNodeToolbar:function(){this.blockConnectingEdgeSelection=!1,this._clearManipulatorBar(),this.off("select",this.boundFunction);var t=this._getEditObject();this.manipulationDiv.innerHTML="Cancel
    label:
    color:
    ";var e=document.getElementById("manipulate-back");e.onclick=this._createManipulatorBar.bind(this);var i=document.getElementById("manipulator-obj-save");i.onclick=this._saveNodeData.bind(this),this.boundFunction=this._createManipulatorBar.bind(this),this.on("select",this.boundFunction)},_saveNodeData:function(){var t=this._getEditObject().id,e=document.getElementById("manipulator-obj-label").value,i=document.getElementById("manipulator-obj-color").value,n=util.hexToHSV(i),s={h:n.h,s:.45*n.s,v:Math.min(1,1.05*n.v)},o={h:n.h,s:Math.min(1,1.25*n.v),v:.6*n.v},r=util.HSVToHex(o.h,o.h,o.v),a=util.HSVToHex(s.h,s.s,s.v),h={id:t,label:e,color:{background:i,border:r,highlight:{background:a,border:r}}};this.nodesData.update(h),this._createManipulatorBar()},_createEditEdgeToolbar:function(){this.blockConnectingEdgeSelection=!1,this._clearManipulatorBar(),this.off("select",this.boundFunction),this.manipulationDiv.innerHTML="Back
    Currently only nodes can be edited.";var t=document.getElementById("manipulate-back");t.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._createManipulatorBar.bind(this),this.on("select",this.boundFunction)},_createConnectToolbar:function(){this._clearManipulatorBar(),this.off("select",this.boundFunction),this._unselectAll(),this.forceAppendSelection=!1,this.blockConnectingEdgeSelection=!0,this.manipulationDiv.innerHTML="Back
    Select the node you want to connect to other nodes.";var t=document.getElementById("manipulate-back");t.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._handleConnect.bind(this),this.on("select",this.boundFunction)},_createDeletionToolbar:function(){if(this._clearManipulatorBar(),this.off("select",this.boundFunction),this._selectionIsEmpty()){this.manipulationDiv.innerHTML="Cannot delete an empty selection.";var t=this;window.setTimeout(function(){t._createManipulatorBar()},1500)}else{this.manipulationDiv.innerHTML="Back
    Are you sure? This cannot be undone.
    Yes.";var e=document.getElementById("manipulate-back");e.onclick=this._createManipulatorBar.bind(this);var i=document.getElementById("manipulate-acceptDelete");i.onclick=this._deleteSelected.bind(this),this.boundFunction=this._createManipulatorBar.bind(this),this.on("select",this.boundFunction)}},_handleConnect:function(){this.forceAppendSelection=!1,this._clusterInSelection()?(this._unselectClusters(!0),this._selectionIsEmpty()?this._setManipulationMessage("You cannot connect anything to a cluster."):(this._setManipulationMessage("You cannot connect a node to a cluster."),this.forceAppendSelection=!0)):this._selectionIsEmpty()?this._setManipulationMessage("Select the node you want to connect to other nodes."):2==this._getSelectedNodeCount()?(this._connectNodes(),this._restoreSourceNode(),this._setManipulationMessage("Click on another node you want to connect this node to or go back.")):(this._setManipulationMessage("Click on the node you want to connect this node."),this._setSourceNode(),this.forceAppendSelection=!0)},_getEditObject:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t))return this.selectionObj[t];return null},_setSourceNode:function(){for(var t in this.selectionObj)this.selectionObj.hasOwnProperty(t)&&this.selectionObj[t]instanceof Node&&(this.manipulationSourceNode=this.selectionObj[t])},_getTargetNode:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t)&&this.selectionObj[t]instanceof Node&&this.manipulationSourceNode.id!=this.selectionObj[t].id)return this.selectionObj[t];return null},_restoreSourceNode:function(){this._unselectAll(!0),this._selectObject(this.manipulationSourceNode)},_setManipulationMessage:function(t){var e=document.getElementById("manipulatorLabel");e.innerHTML=t},_addNode:function(){if(this._selectionIsEmpty()){var t=this._pointerToPositionObject(this.pointerPosition);this.createNodeOnClick=!0,this.nodesData.add({id:util.randomUUID(),x:t.left,y:t.top,label:"new",fixed:!1}),this.createNodeOnClick=!1,this.moving=!0,this.start()}},_connectNodes:function(){var t=this._getTargetNode(),e=this.manipulationSourceNode;this.edgesData.add({from:e.id,to:t.id}),this.moving=!0,this.start()},_deleteSelected:function(){if(this._clusterInSelection())alert("Clusters cannot be deleted.");else{var t=this.getSelectedNodes(),e=this.getSelectedEdges();this._removeEdges(e),this._removeNodes(t),this.moving=!0,this.start()}}},SectorMixin={_putDataInSector:function(){this.sectors.active[this._sector()].nodes=this.nodes,this.sectors.active[this._sector()].edges=this.edges,this.sectors.active[this._sector()].nodeIndices=this.nodeIndices},_switchToSector:function(t,e){void 0===e||"active"==e?this._switchToActiveSector(t):this._switchToFrozenSector(t)},_switchToActiveSector:function(t){this.nodeIndices=this.sectors.active[t].nodeIndices,this.nodes=this.sectors.active[t].nodes,this.edges=this.sectors.active[t].edges},_switchToFrozenSector:function(t){this.nodeIndices=this.sectors.frozen[t].nodeIndices,this.nodes=this.sectors.frozen[t].nodes,this.edges=this.sectors.frozen[t].edges},_switchToNavigationSector:function(){this.nodeIndices=this.sectors.navigation.nodeIndices,this.nodes=this.sectors.navigation.nodes,this.edges=this.sectors.navigation.edges},_loadLatestSector:function(){this._switchToSector(this._sector())},_sector:function(){return this.activeSector[this.activeSector.length-1]},_previousSector:function(){if(this.activeSector.length>1)return this.activeSector[this.activeSector.length-2];throw new TypeError("there are not enough sectors in the this.activeSector array.")},_setActiveSector:function(t){this.activeSector.push(t)},_forgetLastSector:function(){this.activeSector.pop()},_createNewSector:function(t){this.sectors.active[t]={nodes:{},edges:{},nodeIndices:[],formationScale:this.scale,drawingNode:void 0},this.sectors.active[t].drawingNode=new Node({id:t,color:{background:"#eaefef",border:"495c5e"}},{},{},this.constants),this.sectors.active[t].drawingNode.clusterSize=2},_deleteActiveSector:function(t){delete this.sectors.active[t]},_deleteFrozenSector:function(t){delete this.sectors.frozen[t]},_freezeSector:function(t){this.sectors.frozen[t]=this.sectors.active[t],this._deleteActiveSector(t)},_activateSector:function(t){this.sectors.active[t]=this.sectors.frozen[t],this._deleteFrozenSector(t)},_mergeThisWithFrozen:function(t){for(var e in this.nodes)this.nodes.hasOwnProperty(e)&&(this.sectors.frozen[t].nodes[e]=this.nodes[e]);for(var i in this.edges)this.edges.hasOwnProperty(i)&&(this.sectors.frozen[t].edges[i]=this.edges[i]);for(var n=0;n1?this[t](n[0],n[1]):this[t](e)}this._loadLatestSector()},_doInAllFrozenSectors:function(t,e){if(void 0===e)for(var i in this.sectors.frozen)this.sectors.frozen.hasOwnProperty(i)&&(this._switchToFrozenSector(i),this[t]());else for(var i in this.sectors.frozen)if(this.sectors.frozen.hasOwnProperty(i)){this._switchToFrozenSector(i);var n=Array.prototype.splice.call(arguments,1);n.length>1?this[t](n[0],n[1]):this[t](e)}this._loadLatestSector()},_doInNavigationSector:function(t,e){if(this._switchToNavigationSector(),void 0===e)this[t]();else{var i=Array.prototype.splice.call(arguments,1);i.length>1?this[t](i[0],i[1]):this[t](e)}this._loadLatestSector()},_doInAllSectors:function(t,e){var i=Array.prototype.splice.call(arguments,1);void 0===e?(this._doInAllActiveSectors(t),this._doInAllFrozenSectors(t)):i.length>1?(this._doInAllActiveSectors(t,i[0],i[1]),this._doInAllFrozenSectors(t,i[0],i[1])):(this._doInAllActiveSectors(t,e),this._doInAllFrozenSectors(t,e))},_clearNodeIndexList:function(){var t=this._sector();this.sectors.active[t].nodeIndices=[],this.nodeIndices=this.sectors.active[t].nodeIndices},_drawSectorNodes:function(t,e){var i,n=1e9,s=-1e9,o=1e9,r=-1e9;for(var a in this.sectors[e])if(this.sectors[e].hasOwnProperty(a)&&void 0!==this.sectors[e][a].drawingNode){this._switchToSector(a,e),n=1e9,s=-1e9,o=1e9,r=-1e9;for(var h in this.nodes)this.nodes.hasOwnProperty(h)&&(i=this.nodes[h],i.resize(t),o>i.x-.5*i.width&&(o=i.x-.5*i.width),ri.y-.5*i.height&&(n=i.y-.5*i.height),st&&n>s;)s%3==0?this.forceAggregateHubs():this.increaseClusterLevel(),i=this.nodeIndices.length,s+=1;s>1&&1==e&&this.repositionNodes()},openCluster:function(t){var e=this.moving;if(t.clusterSize>this.constants.clustering.sectorThreshold&&this._nodeInActiveArea(t)&&("default"!=this._sector()||1!=this.nodeIndices.length)){this._addSector(t);for(var i=0;this.nodeIndices.lengthi;)this.decreaseClusterLevel(),i+=1}else this._expandClusterNode(t,!1,!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels();this.moving!=e&&this.start()},updateClustersDefault:function(){1==this.constants.clustering.enabled&&this.updateClusters(0,!1,!1)},increaseClusterLevel:function(){this.updateClusters(-1,!1,!0)},decreaseClusterLevel:function(){this.updateClusters(1,!1,!0)},updateClusters:function(t,e,i){var n=this.moving,s=this.nodeIndices.length;this.previousScale>this.scale&&0==t&&this._collapseSector(),this.previousScale>this.scale||-1==t?this._formClusters(i):(this.previousScalethis.scale||-1==t)&&(this._aggregateHubs(i),this._updateNodeIndexList()),(this.previousScale>this.scale||-1==t)&&(this.handleChains(),this._updateNodeIndexList()),this.previousScale=this.scale,this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.lengththis.constants.clustering.chainThreshold&&this._reduceAmountOfChains(1-this.constants.clustering.chainThreshold/t)},_aggregateHubs:function(t){this._getHubSize(),this._formClustersByHub(t,!1)},forceAggregateHubs:function(){var t=this.moving,e=this.nodeIndices.length;this._aggregateHubs(!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.length!=e&&(this.clusterSession+=1),this.moving!=t&&this.start()},_openClustersBySize:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];1==e.inView()&&(e.width*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientWidth||e.height*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientHeight)&&this.openCluster(e)}},_openClusters:function(t,e){for(var i=0;i1&&(t.clusterSizei)){var r=o.from,a=o.to;o.to.mass>o.from.mass&&(r=o.to,a=o.from),1==a.dynamicEdgesLength?this._addToCluster(r,a,!1):1==r.dynamicEdgesLength&&this._addToCluster(a,r,!1)}}},_forceClustersByZoom:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];if(1==e.dynamicEdgesLength&&0!=e.dynamicEdges.length){var i=e.dynamicEdges[0],n=i.toId==e.id?this.nodes[i.fromId]:this.nodes[i.toId];e.id!=n.id&&(n.mass>e.mass?this._addToCluster(n,e,!0):this._addToCluster(e,n,!0))}}},_formClustersByHub:function(t,e){for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&this._formClusterFromHub(this.nodes[i],t,e)},_formClusterFromHub:function(t,e,i,n){if(void 0===n&&(n=0),t.dynamicEdgesLength>=this.hubThreshold&&0==i||t.dynamicEdgesLength==this.hubThreshold&&1==i){for(var s,o,r,a=this.constants.clustering.clusterEdgeThreshold/this.scale,h=!1,l=[],c=t.dynamicEdges.length,d=0;c>d;d++)l.push(t.dynamicEdges[d].id);if(0==e)for(h=!1,d=0;c>d;d++){var u=this.edges[l[d]];if(void 0!==u&&u.connected&&u.toId!=u.fromId&&(s=u.to.x-u.from.x,o=u.to.y-u.from.y,r=Math.sqrt(s*s+o*o),a>r)){h=!0;break}}if(!e&&h||e)for(d=0;c>d;d++)if(u=this.edges[l[d]],void 0!==u){var p=this.nodes[u.fromId==t.id?u.toId:u.fromId];p.dynamicEdges.length<=this.hubThreshold+n&&p.id!=t.id&&this._addToCluster(t,p,e)}}},_addToCluster:function(t,e,i){t.containedNodes[e.id]=e;for(var n=0;n1)for(var n=0;n1&&(e.label="[".concat(String(e.clusterSize),"]"))}for(t in this.nodes)this.nodes.hasOwnProperty(t)&&(e=this.nodes[t],1==e.clusterSize&&(e.label=void 0!==e.originalLabel?e.originalLabel:String(e.id)))},_nodeInActiveArea:function(t){return Math.abs(t.x-this.areaCenter.x)<=this.constants.clustering.activeAreaBoxSize/this.scale&&Math.abs(t.y-this.areaCenter.y)<=this.constants.clustering.activeAreaBoxSize/this.scale},repositionNodes:function(){for(var t=0;tn&&(n=o.dynamicEdgesLength),t+=o.dynamicEdgesLength,e+=Math.pow(o.dynamicEdgesLength,2),i+=1}t/=i,e/=i;var r=e-Math.pow(t,2),a=Math.sqrt(r);this.hubThreshold=Math.floor(t+2*a),this.hubThreshold>n&&(this.hubThreshold=n)},_reduceAmountOfChains:function(t){this.hubThreshold=2;var e=Math.floor(this.nodeIndices.length*t);for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&e>0&&(this._formClusterFromHub(this.nodes[i],!0,!0,1),e-=1)},_getChainFraction:function(){var t=0,e=0;for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&(2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&(t+=1),e+=1);return t/e}},SelectionMixin={_getNodesOverlappingWith:function(t,e){var i=this.nodes;for(var n in i)i.hasOwnProperty(n)&&i[n].isOverlappingWith(t)&&e.push(n)},_getAllNodesOverlappingWith:function(t){var e=[];return this._doInAllActiveSectors("_getNodesOverlappingWith",t,e),e},_getAllNavigationNodesOverlappingWith:function(t){var e=[];return this._doInNavigationSector("_getNodesOverlappingWith",t,e),e},_pointerToPositionObject:function(t){var e=this._canvasToX(t.x),i=this._canvasToY(t.y);return{left:e,top:i,right:e,bottom:i}},_pointerToScreenPositionObject:function(t){var e=t.x,i=t.y;return{left:e,top:i,right:e,bottom:i}},_getNavigationNodeAt:function(t){var e=this._pointerToScreenPositionObject(t),i=this._getAllNavigationNodesOverlappingWith(e);return i.length>0?this.sectors.navigation.nodes[i[i.length-1]]:null},_getNodeAt:function(t){var e=this._pointerToPositionObject(t),i=this._getAllNodesOverlappingWith(e);return i.length>0?this.nodes[i[i.length-1]]:null},_getEdgesOverlappingWith:function(t,e){var i=this.edges;for(var n in i)i.hasOwnProperty(n)&&i[n].isOverlappingWith(t)&&e.push(n)},_getAllEdgesOverlappingWith:function(t){var e=[];return this._doInAllActiveSectors("_getEdgesOverlappingWith",t,e),e},_getEdgeAt:function(t){var e=this._pointerToPositionObject(t),i=this._getAllEdgesOverlappingWith(e);return i.length>0?this.edges[i[i.length-1]]:null},_addToSelection:function(t){this.selectionObj[t.id]=t},_removeFromSelection:function(t){delete this.selectionObj[t.id]},_unselectAll:function(t){void 0===t&&(t=!1);for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e].unselect();this.selectionObj={},0==t&&this._trigger("select",this.getSelection())},_unselectClusters:function(t){void 0===t&&(t=!1);for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e]instanceof Node&&this.selectionObj[e].clusterSize>1&&(this.selectionObj[e].unselect(),this._removeFromSelection(this.selectionObj[e]));0==t&&this._trigger("select",this.getSelection())},_getSelectedNodeCount:function(){var t=0;for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e]instanceof Node&&(t+=1);return t},_getSelectedEdgeCount:function(){var t=0;for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e]instanceof Edge&&(t+=1);return t},_getSelectedObjectCount:function(){var t=0;for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&(t+=1);return t},_selectionIsEmpty:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t))return!1;return!0},_clusterInSelection:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t)&&this.selectionObj[t]instanceof Node&&this.selectionObj[t].clusterSize>1)return!0;return!1},_selectConnectedEdges:function(t){for(var e=0;ee;e++){n=t[e];var s=this.nodes[n];if(!s)throw new RangeError('Node with id "'+n+'" not found');this._selectObject(s,!0,!0)}this.redraw()},_updateSelection:function(){for(var t in this.selectionObj)this.selectionObj.hasOwnProperty(t)&&(this.selectionObj[t]instanceof Node?this.nodes.hasOwnProperty(t)||delete this.selectionObj[t]:this.edges.hasOwnProperty(t)||delete this.selectionObj[t])}},NavigationMixin={_relocateNavigation:function(){if(void 0!==this.sectors){var t=this.navigationClientWidth-this.frame.canvas.clientWidth,e=this.navigationClientHeight-this.frame.canvas.clientHeight;this.navigationClientWidth=this.frame.canvas.clientWidth,this.navigationClientHeight=this.frame.canvas.clientHeight;var i=null;for(var n in this.sectors.navigation.nodes)this.sectors.navigation.nodes.hasOwnProperty(n)&&(i=this.sectors.navigation.nodes[n],i.horizontalAlignLeft||(i.x-=t),i.verticalAlignTop||(i.y-=e))}},_loadNavigationElements:function(){var t=this.constants.navigation.iconPath;this.navigationClientWidth=this.frame.canvas.clientWidth,this.navigationClientHeight=this.frame.canvas.clientHeight,void 0===this.navigationClientWidth&&(this.navigationClientWidth=0,this.navigationClientHeight=0);for(var e=15,i=7,n=[{id:"navigation_up",shape:"image",image:t+"/uparrow.png",triggerFunction:"_moveUp",verticalAlignTop:!1,x:45+e+i,y:this.navigationClientHeight-45-e-i},{id:"navigation_down",shape:"image",image:t+"/downarrow.png",triggerFunction:"_moveDown",verticalAlignTop:!1,x:45+e+i,y:this.navigationClientHeight-15-e},{id:"navigation_left",shape:"image",image:t+"/leftarrow.png",triggerFunction:"_moveLeft",verticalAlignTop:!1,x:15+e,y:this.navigationClientHeight-15-e},{id:"navigation_right",shape:"image",image:t+"/rightarrow.png",triggerFunction:"_moveRight",verticalAlignTop:!1,x:75+e+2*i,y:this.navigationClientHeight-15-e},{id:"navigation_plus",shape:"image",image:t+"/plus.png",triggerFunction:"_zoomIn",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-45-e-i,y:this.navigationClientHeight-15-e},{id:"navigation_min",shape:"image",image:t+"/minus.png",triggerFunction:"_zoomOut",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-15-e,y:this.navigationClientHeight-15-e},{id:"navigation_zoomExtends",shape:"image",image:t+"/zoomExtends.png",triggerFunction:"zoomToFit",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-15-e,y:this.navigationClientHeight-45-e-i}],s=null,o=0;ot.x-t.width&&(n=t.x-t.width),st.y-t.height&&(e=t.y-t.height),i=this.constants.clustering.initialMaxNodes)var n=38.8467/(e-14.50184)+.0116;else var n=42.54117319/(e+39.31966387)+.1944405;else{var s=1.1*(Math.abs(i.minX)+Math.abs(i.maxX)),o=1.1*(Math.abs(i.minY)+Math.abs(i.maxY)),r=this.frame.canvas.clientWidth/s,a=this.frame.canvas.clientHeight/o;n=a>=r?r:a}n>1&&(n=1),this.pinch.mousewheelScale=n,this._setScale(n),this._centerGraph(i),this.start()},Graph.prototype._updateNodeIndexList=function(){this._clearNodeIndexList();for(var t in this.nodes)this.nodes.hasOwnProperty(t)&&this.nodeIndices.push(t)},Graph.prototype.setData=function(t,e){if(void 0===e&&(e=!1),t&&t.dot&&(t.nodes||t.edges))throw new SyntaxError('Data must contain either parameter "dot" or parameter pair "nodes" and "edges", but not both.');if(this.setOptions(t&&t.options),t&&t.dot){if(t&&t.dot){var i=vis.util.DOTToGraph(t.dot);return void this.setData(i)}}else this._setNodes(t&&t.nodes),this._setEdges(t&&t.edges);this._putDataInSector(),e||(this.stabilize&&this._doStabilize(),this.moving=!0,this.start())},Graph.prototype.setOptions=function(t){if(t){if(void 0!==t.width&&(this.width=t.width),void 0!==t.height&&(this.height=t.height),void 0!==t.stabilize&&(this.stabilize=t.stabilize),void 0!==t.selectable&&(this.selectable=t.selectable),t.clustering){this.constants.clustering.enabled=!0;for(var e in t.clustering)t.clustering.hasOwnProperty(e)&&(this.constants.clustering[e]=t.clustering[e])}else void 0!==t.clustering&&(this.constants.clustering.enabled=!1);if(t.navigation){this.constants.navigation.enabled=!0;for(var e in t.navigation)t.navigation.hasOwnProperty(e)&&(this.constants.navigation[e]=t.navigation[e])}else void 0!==t.navigation&&(this.constants.navigation.enabled=!1);if(t.keyboard){this.constants.keyboard.enabled=!0;for(var e in t.keyboard)t.keyboard.hasOwnProperty(e)&&(this.constants.keyboard[e]=t.keyboard[e])}else void 0!==t.keyboard&&(this.constants.keyboard.enabled=!1);if(t.dataManipulationToolbar){this.constants.dataManipulationToolbar.enabled=!0;for(var e in t.dataManipulationToolbar)t.dataManipulationToolbar.hasOwnProperty(e)&&(this.constants.dataManipulationToolbar[e]=t.dataManipulationToolbar[e])}else void 0!==t.dataManipulationToolbar&&(this.constants.dataManipulationToolbar.enabled=!1);if(t.edges){for(e in t.edges)t.edges.hasOwnProperty(e)&&(this.constants.edges[e]=t.edges[e]);void 0!==t.edges.length&&t.nodes&&void 0===t.nodes.distance&&(this.constants.edges.length=t.edges.length,this.constants.nodes.distance=1.25*t.edges.length),t.edges.fontColor||(this.constants.edges.fontColor=t.edges.color),t.edges.dash&&(void 0!==t.edges.dash.length&&(this.constants.edges.dash.length=t.edges.dash.length),void 0!==t.edges.dash.gap&&(this.constants.edges.dash.gap=t.edges.dash.gap),void 0!==t.edges.dash.altLength&&(this.constants.edges.dash.altLength=t.edges.dash.altLength))}if(t.nodes){for(e in t.nodes)t.nodes.hasOwnProperty(e)&&(this.constants.nodes[e]=t.nodes[e]);t.nodes.color&&(this.constants.nodes.color=Node.parseColor(t.nodes.color))}if(t.groups)for(var i in t.groups)if(t.groups.hasOwnProperty(i)){var n=t.groups[i];this.groups.add(i,n)}}this._loadNavigationControls(),this._loadManipulationSystem(),this._createKeyBinds(),this.setSize(this.width,this.height),this._setTranslation(this.frame.clientWidth/2,this.frame.clientHeight/2),this._setScale(1),this._redraw()},Graph.prototype.on=function(t,e){var i=["select"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());events.addListener(this,t,e)},Graph.prototype.off=function(t,e){events.removeListener(this,t,e)},Graph.prototype._trigger=function(t,e){events.trigger(this,t,e)},Graph.prototype._create=function(){for(;this.containerElement.hasChildNodes();)this.containerElement.removeChild(this.containerElement.firstChild);if(this.frame=document.createElement("div"),this.frame.className="graph-frame",this.frame.style.position="relative",this.frame.style.overflow="hidden",this.frame.style.zIndex="1",this.frame.canvas=document.createElement("canvas"),this.frame.canvas.style.position="relative",this.frame.appendChild(this.frame.canvas),!this.frame.canvas.getContext){var t=document.createElement("DIV");t.style.color="red",t.style.fontWeight="bold",t.style.padding="10px",t.innerHTML="Error: your browser does not support HTML canvas",this.frame.canvas.appendChild(t)}var e=this;this.drag={},this.pinch={},this.hammer=Hammer(this.frame.canvas,{prevent_default:!0}),this.hammer.on("tap",e._onTap.bind(e)),this.hammer.on("doubletap",e._onDoubleTap.bind(e)),this.hammer.on("hold",e._onHold.bind(e)),this.hammer.on("pinch",e._onPinch.bind(e)),this.hammer.on("touch",e._onTouch.bind(e)),this.hammer.on("dragstart",e._onDragStart.bind(e)),this.hammer.on("drag",e._onDrag.bind(e)),this.hammer.on("dragend",e._onDragEnd.bind(e)),this.hammer.on("release",e._onRelease.bind(e)),this.hammer.on("mousewheel",e._onMouseWheel.bind(e)),this.hammer.on("DOMMouseScroll",e._onMouseWheel.bind(e)),this.hammer.on("mousemove",e._onMouseMoveTitle.bind(e)),this.containerElement.appendChild(this.frame)},Graph.prototype._createKeyBinds=function(){var t=this;this.mousetrap=mousetrap,this.mousetrap.reset(),1==this.constants.keyboard.enabled&&(this.mousetrap.bind("up",this._moveUp.bind(t),"keydown"),this.mousetrap.bind("up",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("down",this._moveDown.bind(t),"keydown"),this.mousetrap.bind("down",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("left",this._moveLeft.bind(t),"keydown"),this.mousetrap.bind("left",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("right",this._moveRight.bind(t),"keydown"),this.mousetrap.bind("right",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("=",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("=",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("-",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("-",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("[",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("[",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("]",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("]",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pageup",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("pageup",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pagedown",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("pagedown",this._stopZoom.bind(t),"keyup")),this.mousetrap.bind("b",this._formBarnesHutTree.bind(t)),1==this.constants.dataManipulationToolbar.enabled&&this.mousetrap.bind("escape",this._createManipulatorBar.bind(t))},Graph.prototype._getPointer=function(t){return{x:t.pageX-vis.util.getAbsoluteLeft(this.frame.canvas),y:t.pageY-vis.util.getAbsoluteTop(this.frame.canvas)}},Graph.prototype._onTouch=function(t){this.drag.pointer=this._getPointer(t.gesture.touches[0]),this.drag.pinched=!1,this.pinch.scale=this._getScale(),this._handleTouch(this.drag.pointer)},Graph.prototype._onDragStart=function(){var t=this.drag,e=this._getNodeAt(t.pointer);if(t.dragging=!0,t.selection=[],t.translation=this._getTranslation(),t.nodeId=null,null!=e){t.nodeId=e.id,e.isSelected()||this._selectObject(e,!1);for(var i in this.selectionObj)if(this.selectionObj.hasOwnProperty(i)){var n=this.selectionObj[i];if(n instanceof Node){var s={id:n.id,node:n,x:n.x,y:n.y,xFixed:n.xFixed,yFixed:n.yFixed};n.xFixed=!0,n.yFixed=!0,t.selection.push(s)}}}},Graph.prototype._onDrag=function(t){if(!this.drag.pinched){var e=this._getPointer(t.gesture.touches[0]),i=this,n=this.drag,s=n.selection;if(s&&s.length){var o=e.x-n.pointer.x,r=e.y-n.pointer.y;s.forEach(function(t){var e=t.node;t.xFixed||(e.x=i._canvasToX(i._xToCanvas(t.x)+o)),t.yFixed||(e.y=i._canvasToY(i._yToCanvas(t.y)+r))}),this.moving||(this.moving=!0,this.start())}else{var a=e.x-this.drag.pointer.x,h=e.y-this.drag.pointer.y;this._setTranslation(this.drag.translation.x+a,this.drag.translation.y+h),this._redraw(),this.moved=!0}}},Graph.prototype._onDragEnd=function(){this.drag.dragging=!1;var t=this.drag.selection;t&&t.forEach(function(t){t.node.xFixed=t.xFixed,t.node.yFixed=t.yFixed})},Graph.prototype._onTap=function(t){var e=this._getPointer(t.gesture.touches[0]);this.pointerPosition=e,this._handleTap(e)},Graph.prototype._onDoubleTap=function(t){var e=this._getPointer(t.gesture.touches[0]);this._handleDoubleTap(e)},Graph.prototype._onHold=function(t){var e=this._getPointer(t.gesture.touches[0]);this.pointerPosition=e,this._handleOnHold(e)},Graph.prototype._onRelease=function(){this._handleOnRelease()},Graph.prototype._onPinch=function(t){var e=this._getPointer(t.gesture.center);this.drag.pinched=!0,"scale"in this.pinch||(this.pinch.scale=1);var i=this.pinch.scale*t.gesture.scale;this._zoom(i,e)},Graph.prototype._zoom=function(t,e){var i=this._getScale();1e-5>t&&(t=1e-5),t>10&&(t=10);var n=this._getTranslation(),s=t/i,o=(1-s)*e.x+n.x*s,r=(1-s)*e.y+n.y*s;return this.areaCenter={x:this._canvasToX(e.x),y:this._canvasToY(e.y)},this.pinch.mousewheelScale=t,this._setScale(t),this._setTranslation(o,r),this.updateClustersDefault(),this._redraw(),t},Graph.prototype._onMouseWheel=function(t){var e=0;if(t.wheelDelta?e=t.wheelDelta/120:t.detail&&(e=-t.detail/3),e){"mousewheelScale"in this.pinch||(this.pinch.mousewheelScale=1);var i=this.pinch.mousewheelScale,n=e/10;0>e&&(n/=1-n),i*=1+n;var s=util.fakeGesture(this,t),o=this._getPointer(s.center);i=this._zoom(i,o)}t.preventDefault()},Graph.prototype._onMouseMoveTitle=function(t){var e=util.fakeGesture(this,t),i=this._getPointer(e.center);this.popupNode&&this._checkHidePopup(i);var n=this,s=function(){n._checkShowPopup(i)};this.popupTimer&&clearInterval(this.popupTimer),this.drag.dragging||(this.popupTimer=setTimeout(s,300))},Graph.prototype._checkShowPopup=function(t){var e,i={left:this._canvasToX(t.x),top:this._canvasToY(t.y),right:this._canvasToX(t.x),bottom:this._canvasToY(t.y)},n=this.popupNode;if(void 0==this.popupNode){var s=this.nodes;for(e in s)if(s.hasOwnProperty(e)){var o=s[e];if(void 0!==o.getTitle()&&o.isOverlappingWith(i)){this.popupNode=o;break}}}if(void 0===this.popupNode){var r=this.edges;for(e in r)if(r.hasOwnProperty(e)){var a=r[e];if(a.connected&&void 0!==a.getTitle()&&a.isOverlappingWith(i)){this.popupNode=a;break}}}if(this.popupNode){if(this.popupNode!=n){var h=this;h.popup||(h.popup=new Popup(h.frame)),h.popup.setPosition(t.x-3,t.y-3),h.popup.setText(h.popupNode.getTitle()),h.popup.show()}}else this.popup&&this.popup.hide()},Graph.prototype._checkHidePopup=function(t){this.popupNode&&this._getNodeAt(t)||(this.popupNode=void 0,this.popup&&this.popup.hide())},Graph.prototype._getConnectionCount=function(t){function e(t){for(var e=[],i=0,n=t.length;n>i;i++)for(var s=t[i],o=s.edges,r=0,a=o.length;a>r;r++){var h=o[r],l=null;h.from==s?l=h.to:h.to==s&&(l=h.from);var c,d;if(l)for(c=0,d=t.length;d>c;c++)if(t[c]==l){l=null;break}if(l)for(c=0,d=e.length;d>c;c++)if(e[c]==l){l=null;break}l&&e.push(l)}return e}void 0==t&&(t=1);var i=[],n=this.nodes;for(var s in n)if(n.hasOwnProperty(s)){for(var o=[n[s]],r=0;t>r;r++)o=o.concat(e(o));i.push(o)}for(var a=[],h=0,l=i.length;l>h;h++)a.push(i[h].length);return a},Graph.prototype.setSize=function(t,e){this.frame.style.width=t,this.frame.style.height=e,this.frame.canvas.style.width="100%",this.frame.canvas.style.height="100%",this.frame.canvas.width=this.frame.canvas.clientWidth,this.frame.canvas.height=this.frame.canvas.clientHeight,void 0!==this.manipulationDiv&&(this.manipulationDiv.style.width=this.frame.canvas.clientWidth),1==this.constants.navigation.enabled&&this._relocateNavigation()},Graph.prototype._setNodes=function(t){var e=this.nodesData;if(t instanceof DataSet||t instanceof DataView)this.nodesData=t;else if(t instanceof Array)this.nodesData=new DataSet,this.nodesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.nodesData=new DataSet}if(e&&util.forEach(this.nodesListeners,function(t,i){e.unsubscribe(i,t)}),this.nodes={},this.nodesData){var i=this;util.forEach(this.nodesListeners,function(t,e){i.nodesData.subscribe(e,t)});var n=this.nodesData.getIds();this._addNodes(n)}this._updateSelection()},Graph.prototype._addNodes=function(t){for(var e,i=0,n=t.length;n>i;i++){e=t[i];var s=this.nodesData.get(e),o=new Node(s,this.images,this.groups,this.constants);if(this.nodes[e]=o,!o.isFixed()&&1!=this.createNodeOnClick){var r=20*this.constants.edges.length,a=t.length,h=2*Math.PI*(i/a);o.x=r*Math.cos(h),o.y=r*Math.sin(h),this.moving=!0}}this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(this.nodes),this.updateLabels()},Graph.prototype._updateNodes=function(t){for(var e=this.nodes,i=this.nodesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o],a=i.get(o);r?r.setProperties(a,this.constants):(r=new Node(properties,this.images,this.groups,this.constants),e[o]=r,r.isFixed()||(this.moving=!0))}this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(e)},Graph.prototype._removeNodes=function(t){for(var e=this.nodes,i=0,n=t.length;n>i;i++){var s=t[i];delete e[s]}this._updateNodeIndexList(),this._reconnectEdges(),this._updateSelection(),this._updateValueRange(e)},Graph.prototype._setEdges=function(t){var e=this.edgesData;if(t instanceof DataSet||t instanceof DataView)this.edgesData=t;else if(t instanceof Array)this.edgesData=new DataSet,this.edgesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.edgesData=new DataSet}if(e&&util.forEach(this.edgesListeners,function(t,i){e.unsubscribe(i,t)}),this.edges={},this.edgesData){var i=this;util.forEach(this.edgesListeners,function(t,e){i.edgesData.subscribe(e,t)});var n=this.edgesData.getIds();this._addEdges(n)}this._reconnectEdges()},Graph.prototype._addEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o];r&&r.disconnect();var a=i.get(o,{showInternalIds:!0});e[o]=new Edge(a,this,this.constants)}this.moving=!0,this._updateValueRange(e)},Graph.prototype._updateEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=i.get(o),a=e[o];a?(a.disconnect(),a.setProperties(r,this.constants),a.connect()):(a=new Edge(r,this,this.constants),this.edges[o]=a)}this.moving=!0,this._updateValueRange(e)},Graph.prototype._removeEdges=function(t){for(var e=this.edges,i=0,n=t.length;n>i;i++){var s=t[i],o=e[s];o&&(o.disconnect(),delete e[s])}this.moving=!0,this._updateValueRange(e)},Graph.prototype._reconnectEdges=function(){var t,e=this.nodes,i=this.edges;for(t in e)e.hasOwnProperty(t)&&(e[t].edges=[]);for(t in i)if(i.hasOwnProperty(t)){var n=i[t];n.from=null,n.to=null,n.connect()}},Graph.prototype._updateValueRange=function(t){var e,i=void 0,n=void 0;for(e in t)if(t.hasOwnProperty(e)){var s=t[e].getValue();void 0!==s&&(i=void 0===i?s:Math.min(s,i),n=void 0===n?s:Math.max(s,n))}if(void 0!==i&&void 0!==n)for(e in t)t.hasOwnProperty(e)&&t[e].setValueRange(i,n)},Graph.prototype.redraw=function(){this.setSize(this.width,this.height),this._redraw()},Graph.prototype._redraw=function(){var t=this.frame.canvas.getContext("2d"),e=this.frame.canvas.width,i=this.frame.canvas.height;t.clearRect(0,0,e,i),t.save(),t.translate(this.translation.x,this.translation.y),t.scale(this.scale,this.scale),this.canvasTopLeft={x:this._canvasToX(0),y:this._canvasToY(0)},this.canvasBottomRight={x:this._canvasToX(this.frame.canvas.clientWidth),y:this._canvasToY(this.frame.canvas.clientHeight)},this._doInAllSectors("_drawAllSectorNodes",t),this._doInAllSectors("_drawEdges",t),this._doInAllSectors("_drawNodes",t,!0),this._drawTree(t,"#F00F0F"),t.restore(),1==this.constants.navigation.enabled&&this._doInNavigationSector("_drawNodes",t,!0)},Graph.prototype._setTranslation=function(t,e){void 0===this.translation&&(this.translation={x:0,y:0}),void 0!==t&&(this.translation.x=t),void 0!==e&&(this.translation.y=e)},Graph.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},Graph.prototype._setScale=function(t){this.scale=t},Graph.prototype._getScale=function(){return this.scale},Graph.prototype._canvasToX=function(t){return(t-this.translation.x)/this.scale},Graph.prototype._xToCanvas=function(t){return t*this.scale+this.translation.x},Graph.prototype._canvasToY=function(t){return(t-this.translation.y)/this.scale},Graph.prototype._yToCanvas=function(t){return t*this.scale+this.translation.y},Graph.prototype._drawNodes=function(t,e){void 0===e&&(e=!1);var i=this.nodes,n=[];for(var s in i)i.hasOwnProperty(s)&&(i[s].setScaleAndPos(this.scale,this.canvasTopLeft,this.canvasBottomRight),i[s].isSelected()?n.push(s):(i[s].inArea()||e)&&i[s].draw(t));for(var o=0,r=n.length;r>o;o++)(i[n[o]].inArea()||e)&&i[n[o]].draw(t)},Graph.prototype._drawEdges=function(t){var e=this.edges;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];n.setScale(this.scale),n.connected&&e[i].draw(t)}},Graph.prototype._doStabilize=function(){for(var t=0,e=this.constants.minVelocity,i=!1;!i&&t0&&e==s.EVENT_END?e=s.EVENT_MOVE:c||(e=s.EVENT_END),c||null===o?o=h:h=o,i.call(s.detection,n.collectEventData(t,e,h)),s.HAS_POINTEREVENTS&&e==s.EVENT_END&&(c=s.PointerEvent.updatePointer(e,h))),c||(o=null,r=!1,a=!1,s.PointerEvent.reset())}})},determineEventTypes:function(){var t;t=s.HAS_POINTEREVENTS?s.PointerEvent.getEvents():s.NO_MOUSEEVENTS?["touchstart","touchmove","touchend touchcancel"]:["touchstart mousedown","touchmove mousemove","touchend touchcancel mouseup"],s.EVENT_TYPES[s.EVENT_START]=t[0],s.EVENT_TYPES[s.EVENT_MOVE]=t[1],s.EVENT_TYPES[s.EVENT_END]=t[2]},getTouchList:function(t){return s.HAS_POINTEREVENTS?s.PointerEvent.getTouchList():t.touches?t.touches:[{identifier:1,pageX:t.pageX,pageY:t.pageY,target:t.target}]},collectEventData:function(t,e,i){var n=this.getTouchList(i,e),o=s.POINTER_TOUCH;return(i.type.match(/mouse/)||s.PointerEvent.matchType(s.POINTER_MOUSE,i))&&(o=s.POINTER_MOUSE),{center:s.utils.getCenter(n),timeStamp:(new Date).getTime(),target:i.target,touches:n,eventType:e,pointerType:o,srcEvent:i,preventDefault:function(){this.srcEvent.preventManipulation&&this.srcEvent.preventManipulation(),this.srcEvent.preventDefault&&this.srcEvent.preventDefault()},stopPropagation:function(){this.srcEvent.stopPropagation()},stopDetect:function(){return s.detection.stopDetect()}}}},s.PointerEvent={pointers:{},getTouchList:function(){var t=this,e=[];return Object.keys(t.pointers).sort().forEach(function(i){e.push(t.pointers[i])}),e},updatePointer:function(t,e){return t==s.EVENT_END?this.pointers={}:(e.identifier=e.pointerId,this.pointers[e.pointerId]=e),Object.keys(this.pointers).length},matchType:function(t,e){if(!e.pointerType)return!1;var i={};return i[s.POINTER_MOUSE]=e.pointerType==e.MSPOINTER_TYPE_MOUSE||e.pointerType==s.POINTER_MOUSE,i[s.POINTER_TOUCH]=e.pointerType==e.MSPOINTER_TYPE_TOUCH||e.pointerType==s.POINTER_TOUCH,i[s.POINTER_PEN]=e.pointerType==e.MSPOINTER_TYPE_PEN||e.pointerType==s.POINTER_PEN,i[t]},getEvents:function(){return["pointerdown MSPointerDown","pointermove MSPointerMove","pointerup pointercancel MSPointerUp MSPointerCancel"]},reset:function(){this.pointers={}}},s.utils={extend:function(t,e,n){for(var s in e)t[s]!==i&&n||(t[s]=e[s]);return t},hasParent:function(t,e){for(;t;){if(t==e)return!0;t=t.parentNode}return!1},getCenter:function(t){for(var e=[],i=[],n=0,s=t.length;s>n;n++)e.push(t[n].pageX),i.push(t[n].pageY);return{pageX:(Math.min.apply(Math,e)+Math.max.apply(Math,e))/2,pageY:(Math.min.apply(Math,i)+Math.max.apply(Math,i))/2}},getVelocity:function(t,e,i){return{x:Math.abs(e/t)||0,y:Math.abs(i/t)||0}},getAngle:function(t,e){var i=e.pageY-t.pageY,n=e.pageX-t.pageX;return 180*Math.atan2(i,n)/Math.PI},getDirection:function(t,e){var i=Math.abs(t.pageX-e.pageX),n=Math.abs(t.pageY-e.pageY);return i>=n?t.pageX-e.pageX>0?s.DIRECTION_LEFT:s.DIRECTION_RIGHT:t.pageY-e.pageY>0?s.DIRECTION_UP:s.DIRECTION_DOWN},getDistance:function(t,e){var i=e.pageX-t.pageX,n=e.pageY-t.pageY;return Math.sqrt(i*i+n*n)},getScale:function(t,e){return t.length>=2&&e.length>=2?this.getDistance(e[0],e[1])/this.getDistance(t[0],t[1]):1},getRotation:function(t,e){return t.length>=2&&e.length>=2?this.getAngle(e[1],e[0])-this.getAngle(t[1],t[0]):0},isVertical:function(t){return t==s.DIRECTION_UP||t==s.DIRECTION_DOWN},stopDefaultBrowserBehavior:function(t,e){var i,n=["webkit","khtml","moz","ms","o",""];if(e&&t.style){for(var s=0;si;i++){var o=this.gestures[i];if(!this.stopped&&e[o.name]!==!1&&o.handler.call(o,t,this.current.inst)===!1){this.stopDetect();break}}return this.current&&(this.current.lastEvent=t),t.eventType==s.EVENT_END&&!t.touches.length-1&&this.stopDetect(),t}},stopDetect:function(){this.previous=s.utils.extend({},this.current),this.current=null,this.stopped=!0},extendEventData:function(t){var e=this.current.startEvent;if(e&&(t.touches.length!=e.touches.length||t.touches===e.touches)){e.touches=[];for(var i=0,n=t.touches.length;n>i;i++)e.touches.push(s.utils.extend({},t.touches[i]))}var o=t.timeStamp-e.timeStamp,r=t.center.pageX-e.center.pageX,a=t.center.pageY-e.center.pageY,h=s.utils.getVelocity(o,r,a);return s.utils.extend(t,{deltaTime:o,deltaX:r,deltaY:a,velocityX:h.x,velocityY:h.y,distance:s.utils.getDistance(e.center,t.center),angle:s.utils.getAngle(e.center,t.center),direction:s.utils.getDirection(e.center,t.center),scale:s.utils.getScale(e.touches,t.touches),rotation:s.utils.getRotation(e.touches,t.touches),startEvent:e}),t},register:function(t){var e=t.defaults||{};return e[t.name]===i&&(e[t.name]=!0),s.utils.extend(s.defaults,e,!0),t.index=t.index||1e3,this.gestures.push(t),this.gestures.sort(function(t,e){return t.indexe.index?1:0}),this.gestures}},s.gestures=s.gestures||{},s.gestures.Hold={name:"hold",index:10,defaults:{hold_timeout:500,hold_threshold:1},timer:null,handler:function(t,e){switch(t.eventType){case s.EVENT_START:clearTimeout(this.timer),s.detection.current.name=this.name,this.timer=setTimeout(function(){"hold"==s.detection.current.name&&e.trigger("hold",t)},e.options.hold_timeout);break;case s.EVENT_MOVE:t.distance>e.options.hold_threshold&&clearTimeout(this.timer);break;case s.EVENT_END:clearTimeout(this.timer)}}},s.gestures.Tap={name:"tap",index:100,defaults:{tap_max_touchtime:250,tap_max_distance:10,tap_always:!0,doubletap_distance:20,doubletap_interval:300},handler:function(t,e){if(t.eventType==s.EVENT_END){var i=s.detection.previous,n=!1;if(t.deltaTime>e.options.tap_max_touchtime||t.distance>e.options.tap_max_distance)return;i&&"tap"==i.name&&t.timeStamp-i.lastEvent.timeStamp0&&t.touches.length>e.options.swipe_max_touches)return;(t.velocityX>e.options.swipe_velocity||t.velocityY>e.options.swipe_velocity)&&(e.trigger(this.name,t),e.trigger(this.name+t.direction,t))}}},s.gestures.Drag={name:"drag",index:50,defaults:{drag_min_distance:10,drag_max_touches:1,drag_block_horizontal:!1,drag_block_vertical:!1,drag_lock_to_axis:!1,drag_lock_min_distance:25},triggered:!1,handler:function(t,e){if(s.detection.current.name!=this.name&&this.triggered)return e.trigger(this.name+"end",t),void(this.triggered=!1);if(!(e.options.drag_max_touches>0&&t.touches.length>e.options.drag_max_touches))switch(t.eventType){case s.EVENT_START:this.triggered=!1;break;case s.EVENT_MOVE:if(t.distancee.options.transform_min_rotation&&e.trigger("rotate",t),i>e.options.transform_min_scale&&(e.trigger("pinch",t),e.trigger("pinch"+(t.scale<1?"in":"out"),t));break;case s.EVENT_END:this.triggered&&e.trigger(this.name+"end",t),this.triggered=!1}}},s.gestures.Touch={name:"touch",index:-1/0,defaults:{prevent_default:!1,prevent_mouseevents:!1},handler:function(t,e){return e.options.prevent_mouseevents&&t.pointerType==s.POINTER_MOUSE?void t.stopDetect():(e.options.prevent_default&&t.preventDefault(),void(t.eventType==s.EVENT_START&&e.trigger(this.name,t)))}},s.gestures.Release={name:"release",index:1/0,handler:function(t,e){t.eventType==s.EVENT_END&&e.trigger(this.name,t)}},"object"==typeof e&&"object"==typeof e.exports?e.exports=s:(t.Hammer=s,"function"==typeof t.define&&t.define.amd&&t.define("hammer",[],function(){return s}))}(this)},{}],3:[function(t,e){(function(i){function n(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function s(t,e){return function(i){return u(t.call(this,i),e)}}function o(t,e){return function(i){return this.lang().ordinal(t.call(this,i),e)}}function r(){}function a(t){E(t),l(this,t)}function h(t){var e=y(t),i=e.year||0,n=e.month||0,s=e.week||0,o=e.day||0,r=e.hour||0,a=e.minute||0,h=e.second||0,l=e.millisecond||0;this._milliseconds=+l+1e3*h+6e4*a+36e5*r,this._days=+o+7*s,this._months=+n+12*i,this._data={},this._bubble()}function l(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return e.hasOwnProperty("toString")&&(t.toString=e.toString),e.hasOwnProperty("valueOf")&&(t.valueOf=e.valueOf),t}function c(t){var e,i={};for(e in t)t.hasOwnProperty(e)&&ye.hasOwnProperty(e)&&(i[e]=t[e]);return i}function d(t){return 0>t?Math.ceil(t):Math.floor(t)}function u(t,e,i){for(var n=""+Math.abs(t),s=t>=0;n.lengthn;n++)(i&&t[n]!==e[n]||!i&&b(t[n])!==b(e[n]))&&r++;return r+o}function v(t){if(t){var e=t.toLowerCase().replace(/(.)s$/,"$1");t=Xe[t]||qe[e]||e}return t}function y(t){var e,i,n={};for(i in t)t.hasOwnProperty(i)&&(e=v(i),e&&(n[e]=t[i]));return n}function _(t){var e,n;if(0===t.indexOf("week"))e=7,n="day";else{if(0!==t.indexOf("month"))return;e=12,n="month"}oe[t]=function(s,o){var r,a,h=oe.fn._lang[t],l=[];if("number"==typeof s&&(o=s,s=i),a=function(t){var e=oe().utc().set(n,t);return h.call(oe.fn._lang,e,s||"")},null!=o)return a(o);for(r=0;e>r;r++)l.push(a(r));return l}}function b(t){var e=+t,i=0;return 0!==e&&isFinite(e)&&(i=e>=0?Math.floor(e):Math.ceil(e)),i}function w(t,e){return new Date(Date.UTC(t,e+1,0)).getUTCDate()}function S(t){return T(t)?366:365}function T(t){return t%4===0&&t%100!==0||t%400===0}function E(t){var e;t._a&&-2===t._pf.overflow&&(e=t._a[de]<0||t._a[de]>11?de:t._a[ue]<1||t._a[ue]>w(t._a[ce],t._a[de])?ue:t._a[pe]<0||t._a[pe]>23?pe:t._a[fe]<0||t._a[fe]>59?fe:t._a[ge]<0||t._a[ge]>59?ge:t._a[me]<0||t._a[me]>999?me:-1,t._pf._overflowDayOfYear&&(ce>e||e>ue)&&(e=ue),t._pf.overflow=e)}function x(t){return null==t._isValid&&(t._isValid=!isNaN(t._d.getTime())&&t._pf.overflow<0&&!t._pf.empty&&!t._pf.invalidMonth&&!t._pf.nullInput&&!t._pf.invalidFormat&&!t._pf.userInvalidated,t._strict&&(t._isValid=t._isValid&&0===t._pf.charsLeftOver&&0===t._pf.unusedTokens.length)),t._isValid}function C(t){return t?t.toLowerCase().replace("_","-"):t}function M(t,e){return e._isUTC?oe(t).zone(e._offset||0):oe(t).local()}function D(t,e){return e.abbr=t,ve[t]||(ve[t]=new r),ve[t].set(e),ve[t]}function I(t){delete ve[t]}function N(e){var i,n,s,o,r=0,a=function(e){if(!ve[e]&&_e)try{t("./lang/"+e)}catch(i){}return ve[e]};if(!e)return oe.fn._lang;if(!f(e)){if(n=a(e))return n;e=[e]}for(;r0;){if(n=a(o.slice(0,i).join("-")))return n;if(s&&s.length>=i&&m(o,s,!0)>=i-1)break;i--}r++}return oe.fn._lang}function O(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function L(t){var e,i,n=t.match(Te);for(e=0,i=n.length;i>e;e++)n[e]=Qe[n[e]]?Qe[n[e]]:O(n[e]);return function(s){var o="";for(e=0;i>e;e++)o+=n[e]instanceof Function?n[e].call(s,t):n[e];return o}}function k(t,e){return t.isValid()?(e=A(e,t.lang()),Ze[e]||(Ze[e]=L(e)),Ze[e](t)):t.lang().invalidDate()}function A(t,e){function i(t){return e.longDateFormat(t)||t}var n=5;for(Ee.lastIndex=0;n>=0&&Ee.test(t);)t=t.replace(Ee,i),Ee.lastIndex=0,n-=1;return t}function P(t,e){var i,n=e._strict;switch(t){case"DDDD":return ze;case"YYYY":case"GGGG":case"gggg":return n?Fe:Me;case"Y":case"G":case"g":return Ye;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return n?Re:De;case"S":if(n)return Ae;case"SS":if(n)return Pe;case"SSS":if(n)return ze;case"DDD":return Ce;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Ne;case"a":case"A":return N(e._l)._meridiemParse;case"X":return ke;case"Z":case"ZZ":return Oe;case"T":return Le;case"SSSS":return Ie;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return n?Pe:xe;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return xe;default:return i=new RegExp(G(j(t.replace("\\","")),"i"))}}function z(t){t=t||"";var e=t.match(Oe)||[],i=e[e.length-1]||[],n=(i+"").match(Ue)||["-",0,0],s=+(60*n[1])+b(n[2]);return"+"===n[0]?-s:s}function F(t,e,i){var n,s=i._a;switch(t){case"M":case"MM":null!=e&&(s[de]=b(e)-1);break;case"MMM":case"MMMM":n=N(i._l).monthsParse(e),null!=n?s[de]=n:i._pf.invalidMonth=e;break;case"D":case"DD":null!=e&&(s[ue]=b(e));break;case"DDD":case"DDDD":null!=e&&(i._dayOfYear=b(e));break;case"YY":s[ce]=b(e)+(b(e)>68?1900:2e3);break;case"YYYY":case"YYYYY":case"YYYYYY":s[ce]=b(e);break;case"a":case"A":i._isPm=N(i._l).isPM(e);break;case"H":case"HH":case"h":case"hh":s[pe]=b(e);break;case"m":case"mm":s[fe]=b(e);break;case"s":case"ss":s[ge]=b(e);break;case"S":case"SS":case"SSS":case"SSSS":s[me]=b(1e3*("0."+e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,i._tzm=z(e);break;case"w":case"ww":case"W":case"WW":case"d":case"dd":case"ddd":case"dddd":case"e":case"E":t=t.substr(0,1);case"gg":case"gggg":case"GG":case"GGGG":case"GGGGG":t=t.substr(0,2),e&&(i._w=i._w||{},i._w[t]=e)}}function R(t){var e,i,n,s,o,r,a,h,l,c,d=[];if(!t._d){for(n=H(t),t._w&&null==t._a[ue]&&null==t._a[de]&&(o=function(e){var i=parseInt(e,10);return e?e.length<3?i>68?1900+i:2e3+i:i:null==t._a[ce]?oe().weekYear():t._a[ce]},r=t._w,null!=r.GG||null!=r.W||null!=r.E?a=J(o(r.GG),r.W||1,r.E,4,1):(h=N(t._l),l=null!=r.d?Z(r.d,h):null!=r.e?parseInt(r.e,10)+h._week.dow:0,c=parseInt(r.w,10)||1,null!=r.d&&lS(s)&&(t._pf._overflowDayOfYear=!0),i=q(s,0,t._dayOfYear),t._a[de]=i.getUTCMonth(),t._a[ue]=i.getUTCDate()),e=0;3>e&&null==t._a[e];++e)t._a[e]=d[e]=n[e];for(;7>e;e++)t._a[e]=d[e]=null==t._a[e]?2===e?1:0:t._a[e];d[pe]+=b((t._tzm||0)/60),d[fe]+=b((t._tzm||0)%60),t._d=(t._useUTC?q:X).apply(null,d)}}function Y(t){var e;t._d||(e=y(t._i),t._a=[e.year,e.month,e.day,e.hour,e.minute,e.second,e.millisecond],R(t))}function H(t){var e=new Date;return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function W(t){t._a=[],t._pf.empty=!0;var e,i,n,s,o,r=N(t._l),a=""+t._i,h=a.length,l=0;for(n=A(t._f,r).match(Te)||[],e=0;e0&&t._pf.unusedInput.push(o),a=a.slice(a.indexOf(i)+i.length),l+=i.length),Qe[s]?(i?t._pf.empty=!1:t._pf.unusedTokens.push(s),F(s,i,t)):t._strict&&!i&&t._pf.unusedTokens.push(s);t._pf.charsLeftOver=h-l,a.length>0&&t._pf.unusedInput.push(a),t._isPm&&t._a[pe]<12&&(t._a[pe]+=12),t._isPm===!1&&12===t._a[pe]&&(t._a[pe]=0),R(t),E(t)}function j(t){return t.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,i,n,s){return e||i||n||s})}function G(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function U(t){var e,i,s,o,r;if(0===t._f.length)return t._pf.invalidFormat=!0,void(t._d=new Date(0/0));for(o=0;or)&&(s=r,i=e));l(t,i||e)}function B(t){var e,i,n=t._i,s=He.exec(n);if(s){for(t._pf.iso=!0,e=0,i=je.length;i>e;e++)if(je[e][1].exec(n)){t._f=je[e][0]+(s[6]||" ");break}for(e=0,i=Ge.length;i>e;e++)if(Ge[e][1].exec(n)){t._f+=Ge[e][0];break}n.match(Oe)&&(t._f+="Z"),W(t)}else t._d=new Date(n)}function V(t){var e=t._i,n=be.exec(e);e===i?t._d=new Date:n?t._d=new Date(+n[1]):"string"==typeof e?B(t):f(e)?(t._a=e.slice(0),R(t)):g(e)?t._d=new Date(+e):"object"==typeof e?Y(t):t._d=new Date(e)}function X(t,e,i,n,s,o,r){var a=new Date(t,e,i,n,s,o,r);return 1970>t&&a.setFullYear(t),a}function q(t){var e=new Date(Date.UTC.apply(null,arguments));return 1970>t&&e.setUTCFullYear(t),e}function Z(t,e){if("string"==typeof t)if(isNaN(t)){if(t=e.weekdaysParse(t),"number"!=typeof t)return null}else t=parseInt(t,10);return t}function K(t,e,i,n,s){return s.relativeTime(e||1,!!i,t,n)}function $(t,e,i){var n=le(Math.abs(t)/1e3),s=le(n/60),o=le(s/60),r=le(o/24),a=le(r/365),h=45>n&&["s",n]||1===s&&["m"]||45>s&&["mm",s]||1===o&&["h"]||22>o&&["hh",o]||1===r&&["d"]||25>=r&&["dd",r]||45>=r&&["M"]||345>r&&["MM",le(r/30)]||1===a&&["y"]||["yy",a];return h[2]=e,h[3]=t>0,h[4]=i,K.apply({},h)}function Q(t,e,i){var n,s=i-e,o=i-t.day();return o>s&&(o-=7),s-7>o&&(o+=7),n=oe(t).add("d",o),{week:Math.ceil(n.dayOfYear()/7),year:n.year()}}function J(t,e,i,n,s){var o,r,a=q(t,0,1).getUTCDay();return i=null!=i?i:s,o=s-a+(a>n?7:0)-(s>a?7:0),r=7*(e-1)+(i-s)+o+1,{year:r>0?t:t-1,dayOfYear:r>0?r:S(t-1)+r}}function te(t){var e=t._i,i=t._f;return null===e?oe.invalid({nullInput:!0}):("string"==typeof e&&(t._i=e=N().preparse(e)),oe.isMoment(e)?(t=c(e),t._d=new Date(+e._d)):i?f(i)?U(t):W(t):V(t),new a(t))}function ee(t,e){oe.fn[t]=oe.fn[t+"s"]=function(t){var i=this._isUTC?"UTC":"";return null!=t?(this._d["set"+i+e](t),oe.updateOffset(this),this):this._d["get"+i+e]()}}function ie(t){oe.duration.fn[t]=function(){return this._data[t]}}function ne(t,e){oe.duration.fn["as"+t]=function(){return+this/e}}function se(t){var e=!1,i=oe;"undefined"==typeof ender&&(t?(he.moment=function(){return!e&&console&&console.warn&&(e=!0,console.warn("Accessing Moment through the global scope is deprecated, and will be removed in an upcoming release.")),i.apply(null,arguments)},l(he.moment,i)):he.moment=oe)}for(var oe,re,ae="2.5.1",he=this,le=Math.round,ce=0,de=1,ue=2,pe=3,fe=4,ge=5,me=6,ve={},ye={_isAMomentObject:null,_i:null,_f:null,_l:null,_strict:null,_isUTC:null,_offset:null,_pf:null,_lang:null},_e="undefined"!=typeof e&&e.exports&&"undefined"!=typeof t,be=/^\/?Date\((\-?\d+)/i,we=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,Se=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,Te=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g,Ee=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,xe=/\d\d?/,Ce=/\d{1,3}/,Me=/\d{1,4}/,De=/[+\-]?\d{1,6}/,Ie=/\d+/,Ne=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Oe=/Z|[\+\-]\d\d:?\d\d/gi,Le=/T/i,ke=/[\+\-]?\d+(\.\d{1,3})?/,Ae=/\d/,Pe=/\d\d/,ze=/\d{3}/,Fe=/\d{4}/,Re=/[+-]?\d{6}/,Ye=/[+-]?\d+/,He=/^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,We="YYYY-MM-DDTHH:mm:ssZ",je=[["YYYYYY-MM-DD",/[+-]\d{6}-\d{2}-\d{2}/],["YYYY-MM-DD",/\d{4}-\d{2}-\d{2}/],["GGGG-[W]WW-E",/\d{4}-W\d{2}-\d/],["GGGG-[W]WW",/\d{4}-W\d{2}/],["YYYY-DDD",/\d{4}-\d{3}/]],Ge=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d{1,3}/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],Ue=/([\+\-]|\d\d)/gi,Be="Date|Hours|Minutes|Seconds|Milliseconds".split("|"),Ve={Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6},Xe={ms:"millisecond",s:"second",m:"minute",h:"hour",d:"day",D:"date",w:"week",W:"isoWeek",M:"month",y:"year",DDD:"dayOfYear",e:"weekday",E:"isoWeekday",gg:"weekYear",GG:"isoWeekYear"},qe={dayofyear:"dayOfYear",isoweekday:"isoWeekday",isoweek:"isoWeek",weekyear:"weekYear",isoweekyear:"isoWeekYear"},Ze={},Ke="DDD w W M D d".split(" "),$e="M D H h m s w W".split(" "),Qe={M:function(){return this.month()+1},MMM:function(t){return this.lang().monthsShort(this,t)},MMMM:function(t){return this.lang().months(this,t)},D:function(){return this.date()},DDD:function(){return this.dayOfYear()},d:function(){return this.day()},dd:function(t){return this.lang().weekdaysMin(this,t)},ddd:function(t){return this.lang().weekdaysShort(this,t)},dddd:function(t){return this.lang().weekdays(this,t)},w:function(){return this.week()},W:function(){return this.isoWeek()},YY:function(){return u(this.year()%100,2)},YYYY:function(){return u(this.year(),4)},YYYYY:function(){return u(this.year(),5)},YYYYYY:function(){var t=this.year(),e=t>=0?"+":"-";return e+u(Math.abs(t),6)},gg:function(){return u(this.weekYear()%100,2)},gggg:function(){return u(this.weekYear(),4)},ggggg:function(){return u(this.weekYear(),5)},GG:function(){return u(this.isoWeekYear()%100,2)},GGGG:function(){return u(this.isoWeekYear(),4)},GGGGG:function(){return u(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.lang().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.lang().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return b(this.milliseconds()/100)},SS:function(){return u(b(this.milliseconds()/10),2)},SSS:function(){return u(this.milliseconds(),3)},SSSS:function(){return u(this.milliseconds(),3)},Z:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+u(b(t/60),2)+":"+u(b(t)%60,2)},ZZ:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+u(b(t/60),2)+u(b(t)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},X:function(){return this.unix()},Q:function(){return this.quarter()}},Je=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"];Ke.length;)re=Ke.pop(),Qe[re+"o"]=o(Qe[re],re);for(;$e.length;)re=$e.pop(),Qe[re+re]=s(Qe[re],2);for(Qe.DDDD=s(Qe.DDD,3),l(r.prototype,{set:function(t){var e,i;for(i in t)e=t[i],"function"==typeof e?this[i]=e:this["_"+i]=e},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(t){return this._months[t.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(t){return this._monthsShort[t.month()]},monthsParse:function(t){var e,i,n;for(this._monthsParse||(this._monthsParse=[]),e=0;12>e;e++)if(this._monthsParse[e]||(i=oe.utc([2e3,e]),n="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[e]=new RegExp(n.replace(".",""),"i")),this._monthsParse[e].test(t))return e},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(t){return this._weekdays[t.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(t){return this._weekdaysShort[t.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(t){return this._weekdaysMin[t.day()]},weekdaysParse:function(t){var e,i,n;for(this._weekdaysParse||(this._weekdaysParse=[]),e=0;7>e;e++)if(this._weekdaysParse[e]||(i=oe([2e3,1]).day(e),n="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[e]=new RegExp(n.replace(".",""),"i")),this._weekdaysParse[e].test(t))return e},_longDateFormat:{LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D YYYY",LLL:"MMMM D YYYY LT",LLLL:"dddd, MMMM D YYYY LT"},longDateFormat:function(t){var e=this._longDateFormat[t];return!e&&this._longDateFormat[t.toUpperCase()]&&(e=this._longDateFormat[t.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t]=e),e},isPM:function(t){return"p"===(t+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(t,e,i){return t>11?i?"pm":"PM":i?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(t,e){var i=this._calendar[t];return"function"==typeof i?i.apply(e):i},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(t,e,i,n){var s=this._relativeTime[i];return"function"==typeof s?s(t,e,i,n):s.replace(/%d/i,t)},pastFuture:function(t,e){var i=this._relativeTime[t>0?"future":"past"];return"function"==typeof i?i(e):i.replace(/%s/i,e)},ordinal:function(t){return this._ordinal.replace("%d",t)},_ordinal:"%d",preparse:function(t){return t},postformat:function(t){return t},week:function(t){return Q(t,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),oe=function(t,e,s,o){var r;return"boolean"==typeof s&&(o=s,s=i),r={},r._isAMomentObject=!0,r._i=t,r._f=e,r._l=s,r._strict=o,r._isUTC=!1,r._pf=n(),te(r)},oe.utc=function(t,e,s,o){var r;return"boolean"==typeof s&&(o=s,s=i),r={},r._isAMomentObject=!0,r._useUTC=!0,r._isUTC=!0,r._l=s,r._i=t,r._f=e,r._strict=o,r._pf=n(),te(r).utc()},oe.unix=function(t){return oe(1e3*t)},oe.duration=function(t,e){var i,n,s,o=t,r=null;return oe.isDuration(t)?o={ms:t._milliseconds,d:t._days,M:t._months}:"number"==typeof t?(o={},e?o[e]=t:o.milliseconds=t):(r=we.exec(t))?(i="-"===r[1]?-1:1,o={y:0,d:b(r[ue])*i,h:b(r[pe])*i,m:b(r[fe])*i,s:b(r[ge])*i,ms:b(r[me])*i}):(r=Se.exec(t))&&(i="-"===r[1]?-1:1,s=function(t){var e=t&&parseFloat(t.replace(",","."));return(isNaN(e)?0:e)*i},o={y:s(r[2]),M:s(r[3]),d:s(r[4]),h:s(r[5]),m:s(r[6]),s:s(r[7]),w:s(r[8])}),n=new h(o),oe.isDuration(t)&&t.hasOwnProperty("_lang")&&(n._lang=t._lang),n},oe.version=ae,oe.defaultFormat=We,oe.updateOffset=function(){},oe.lang=function(t,e){var i;return t?(e?D(C(t),e):null===e?(I(t),t="en"):ve[t]||N(t),i=oe.duration.fn._lang=oe.fn._lang=N(t),i._abbr):oe.fn._lang._abbr},oe.langData=function(t){return t&&t._lang&&t._lang._abbr&&(t=t._lang._abbr),N(t)},oe.isMoment=function(t){return t instanceof a||null!=t&&t.hasOwnProperty("_isAMomentObject")},oe.isDuration=function(t){return t instanceof h},re=Je.length-1;re>=0;--re)_(Je[re]);for(oe.normalizeUnits=function(t){return v(t)},oe.invalid=function(t){var e=oe.utc(0/0);return null!=t?l(e._pf,t):e._pf.userInvalidated=!0,e},oe.parseZone=function(t){return oe(t).parseZone()},l(oe.fn=a.prototype,{clone:function(){return oe(this)},valueOf:function(){return+this._d+6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().lang("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){var t=oe(this).utc();return 00:!1},parsingFlags:function(){return l({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(){return this.zone(0)},local:function(){return this.zone(0),this._isUTC=!1,this},format:function(t){var e=k(this,t||oe.defaultFormat);return this.lang().postformat(e)},add:function(t,e){var i;return i="string"==typeof t?oe.duration(+e,t):oe.duration(t,e),p(this,i,1),this},subtract:function(t,e){var i;return i="string"==typeof t?oe.duration(+e,t):oe.duration(t,e),p(this,i,-1),this},diff:function(t,e,i){var n,s,o=M(t,this),r=6e4*(this.zone()-o.zone());return e=v(e),"year"===e||"month"===e?(n=432e5*(this.daysInMonth()+o.daysInMonth()),s=12*(this.year()-o.year())+(this.month()-o.month()),s+=(this-oe(this).startOf("month")-(o-oe(o).startOf("month")))/n,s-=6e4*(this.zone()-oe(this).startOf("month").zone()-(o.zone()-oe(o).startOf("month").zone()))/n,"year"===e&&(s/=12)):(n=this-o,s="second"===e?n/1e3:"minute"===e?n/6e4:"hour"===e?n/36e5:"day"===e?(n-r)/864e5:"week"===e?(n-r)/6048e5:n),i?s:d(s)},from:function(t,e){return oe.duration(this.diff(t)).lang(this.lang()._abbr).humanize(!e)},fromNow:function(t){return this.from(oe(),t)},calendar:function(){var t=M(oe(),this).startOf("day"),e=this.diff(t,"days",!0),i=-6>e?"sameElse":-1>e?"lastWeek":0>e?"lastDay":1>e?"sameDay":2>e?"nextDay":7>e?"nextWeek":"sameElse";return this.format(this.lang().calendar(i,this))},isLeapYear:function(){return T(this.year())},isDST:function(){return this.zone()+oe(t).startOf(e)},isBefore:function(t,e){return e="undefined"!=typeof e?e:"millisecond",+this.clone().startOf(e)<+oe(t).startOf(e)},isSame:function(t,e){return e=e||"ms",+this.clone().startOf(e)===+M(t,this).startOf(e)},min:function(t){return t=oe.apply(null,arguments),this>t?this:t},max:function(t){return t=oe.apply(null,arguments),t>this?this:t},zone:function(t){var e=this._offset||0;return null==t?this._isUTC?e:this._d.getTimezoneOffset():("string"==typeof t&&(t=z(t)),Math.abs(t)<16&&(t=60*t),this._offset=t,this._isUTC=!0,e!==t&&p(this,oe.duration(e-t,"m"),1,!0),this)},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.zone(this._tzm):"string"==typeof this._i&&this.zone(this._i),this},hasAlignedHourOffset:function(t){return t=t?oe(t).zone():0,(this.zone()-t)%60===0},daysInMonth:function(){return w(this.year(),this.month())},dayOfYear:function(t){var e=le((oe(this).startOf("day")-oe(this).startOf("year"))/864e5)+1;return null==t?e:this.add("d",t-e)},quarter:function(){return Math.ceil((this.month()+1)/3)},weekYear:function(t){var e=Q(this,this.lang()._week.dow,this.lang()._week.doy).year;return null==t?e:this.add("y",t-e)},isoWeekYear:function(t){var e=Q(this,1,4).year;return null==t?e:this.add("y",t-e)},week:function(t){var e=this.lang().week(this);return null==t?e:this.add("d",7*(t-e))},isoWeek:function(t){var e=Q(this,1,4).week;return null==t?e:this.add("d",7*(t-e))},weekday:function(t){var e=(this.day()+7-this.lang()._week.dow)%7;return null==t?e:this.add("d",t-e)},isoWeekday:function(t){return null==t?this.day()||7:this.day(this.day()%7?t:t-7)},get:function(t){return t=v(t),this[t]()},set:function(t,e){return t=v(t),"function"==typeof this[t]&&this[t](e),this},lang:function(t){return t===i?this._lang:(this._lang=N(t),this)}}),re=0;re-1?!1:"INPUT"==i||"SELECT"==i||"TEXTAREA"==i||e.contentEditable&&"true"==e.contentEditable}function o(t,e){return t.sort().join(",")===e.sort().join(",")}function r(t){t=t||{};var e,i=!1;for(e in M)t[e]?i=!0:M[e]=0;i||(I=!1)}function a(t,e,i,n,s){var r,a,h=[];if(!x[t])return[];for("keyup"==i&&u(t)&&(e=[t]),r=0;r95&&112>t||w.hasOwnProperty(t)&&(_[w[t]]=t)}return _}function g(t,e,i){return i||(i=f()[t]?"keydown":"keypress"),"keypress"==i&&e.length&&(i="keydown"),i}function m(t,e,i,s){M[t]=0,s||(s=g(e[0],[]));var o,a=function(){I=s,++M[t],p()},h=function(t){l(i,t),"keyup"!==s&&(D=n(t)),setTimeout(r,10)};for(o=0;o1)return m(t,l,e,i);for(h="+"===t?["+"]:t.split("+"),o=0;o":".","?":"/","|":"\\"},E={option:"alt",command:"meta","return":"enter",escape:"esc"},x={},C={},M={},D=!1,I=!1,N=1;20>N;++N)w[111+N]="f"+N;for(N=0;9>=N;++N)w[N+96]=N;i(document,"keypress",d),i(document,"keydown",d),i(document,"keyup",d);var O={bind:function(t,e,i){return y(t instanceof Array?t:[t],e,i),C[t+":"+i]=e,this},unbind:function(t,e){return C[t+":"+e]&&(delete C[t+":"+e],this.bind(t,function(){},e)),this},trigger:function(t,e){return C[t+":"+e](),this},reset:function(){return x={},C={},this}};e.exports=O},{}]},{},[1])(1)}); \ No newline at end of file +this.beginPath(),this.moveTo(c,p),this.bezierCurveTo(c,p+l,u+h,d,u,d),this.bezierCurveTo(u-h,d,t,p+l,t,p),this.bezierCurveTo(t,p-l,u-h,e,u,e),this.bezierCurveTo(u+h,e,c,p-l,c,p),this.lineTo(c,f),this.bezierCurveTo(c,f+l,u+h,g,u,g),this.bezierCurveTo(u-h,g,t,f+l,t,f),this.lineTo(t,p)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,n){var s=t-n*Math.cos(i),o=e-n*Math.sin(i),r=t-.9*n*Math.cos(i),a=e-.9*n*Math.sin(i),h=s+n/3*Math.cos(i+.5*Math.PI),l=o+n/3*Math.sin(i+.5*Math.PI),c=s+n/3*Math.cos(i-.5*Math.PI),d=o+n/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,l),this.lineTo(r,a),this.lineTo(c,d),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,n,s){s||(s=[10,5]),0==u&&(u=.001);var o=s.length;this.moveTo(t,e);for(var r=i-t,a=n-e,h=a/r,l=Math.sqrt(r*r+a*a),c=0,d=!0;l>=.1;){var u=s[c++%o];u>l&&(u=l);var p=Math.sqrt(u*u/(1+h*h));0>r&&(p=-p),t+=p,e+=h*p,this[d?"lineTo":"moveTo"](t,e),l-=u,d=!d}}),Node.prototype.resetCluster=function(){this.formationScale=void 0,this.clusterSize=1,this.containedNodes={},this.containedEdges={},this.clusterSessions=[]},Node.prototype.attachEdge=function(t){-1==this.edges.indexOf(t)&&this.edges.push(t),-1==this.dynamicEdges.indexOf(t)&&this.dynamicEdges.push(t),this.dynamicEdgesLength=this.dynamicEdges.length,this._updateMass()},Node.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&(this.edges.splice(e,1),this.dynamicEdges.splice(e,1)),this.dynamicEdgesLength=this.dynamicEdges.length,this._updateMass()},Node.prototype._updateMass=function(){this.mass=1},Node.prototype.setProperties=function(t,e){if(t){if(this.originalLabel=void 0,void 0!==t.id&&(this.id=t.id),void 0!==t.label&&(this.label=t.label,this.originalLabel=t.label),void 0!==t.title&&(this.title=t.title),void 0!==t.group&&(this.group=t.group),void 0!==t.x&&(this.x=t.x),void 0!==t.y&&(this.y=t.y),void 0!==t.value&&(this.value=t.value),void 0!==t.horizontalAlignLeft&&(this.horizontalAlignLeft=t.horizontalAlignLeft),void 0!==t.verticalAlignTop&&(this.verticalAlignTop=t.verticalAlignTop),void 0!==t.triggerFunction&&(this.triggerFunction=t.triggerFunction),void 0===this.id)throw"Node must have an id";if(this.group){var i=this.grouplist.get(this.group);for(var n in i)i.hasOwnProperty(n)&&(this[n]=i[n])}if(void 0!==t.shape&&(this.shape=t.shape),void 0!==t.image&&(this.image=t.image),void 0!==t.radius&&(this.radius=t.radius),void 0!==t.color&&(this.color=Node.parseColor(t.color)),void 0!==t.fontColor&&(this.fontColor=t.fontColor),void 0!==t.fontSize&&(this.fontSize=t.fontSize),void 0!==t.fontFace&&(this.fontFace=t.fontFace),void 0!==this.image){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.image)}switch(this.xFixed=this.xFixed||void 0!==t.x&&t.fixed,this.yFixed=this.yFixed||void 0!==t.y&&t.fixed,this.radiusFixed=this.radiusFixed||void 0!==t.radius,"image"==this.shape&&(this.radiusMin=e.nodes.widthMin,this.radiusMax=e.nodes.widthMax),this.shape){case"database":this.draw=this._drawDatabase,this.resize=this._resizeDatabase;break;case"box":this.draw=this._drawBox,this.resize=this._resizeBox;break;case"circle":this.draw=this._drawCircle,this.resize=this._resizeCircle;break;case"ellipse":this.draw=this._drawEllipse,this.resize=this._resizeEllipse;break;case"image":this.draw=this._drawImage,this.resize=this._resizeImage;break;case"text":this.draw=this._drawText,this.resize=this._resizeText;break;case"dot":this.draw=this._drawDot,this.resize=this._resizeShape;break;case"square":this.draw=this._drawSquare,this.resize=this._resizeShape;break;case"triangle":this.draw=this._drawTriangle,this.resize=this._resizeShape;break;case"triangleDown":this.draw=this._drawTriangleDown,this.resize=this._resizeShape;break;case"star":this.draw=this._drawStar,this.resize=this._resizeShape;break;default:this.draw=this._drawEllipse,this.resize=this._resizeEllipse}this._reset()}},Node.parseColor=function(t){var e;return util.isString(t)?e={border:t,background:t,highlight:{border:t,background:t}}:(e={},e.background=t.background||"white",e.border=t.border||e.background,util.isString(t.highlight)?e.highlight={border:t.highlight,background:t.highlight}:(e.highlight={},e.highlight.background=t.highlight&&t.highlight.background||e.background,e.highlight.border=t.highlight&&t.highlight.border||e.border)),e},Node.prototype.select=function(){this.selected=!0,this._reset()},Node.prototype.unselect=function(){this.selected=!1,this._reset()},Node.prototype.clearSizeCache=function(){this._reset()},Node.prototype._reset=function(){this.width=void 0,this.height=void 0},Node.prototype.getTitle=function(){return this.title},Node.prototype.distanceToBorder=function(t,e){var i=1;switch(this.width||this.resize(t),this.shape){case"circle":case"dot":return this.radius+i;case"ellipse":var n=this.width/2,s=this.height/2,o=Math.sin(e)*n,r=Math.cos(e)*s;return n*s/Math.sqrt(o*o+r*r);case"box":case"image":case"text":default:return this.width?Math.min(Math.abs(this.width/2/Math.cos(e)),Math.abs(this.height/2/Math.sin(e)))+i:0}},Node.prototype._setForce=function(t,e){this.fx=t,this.fy=e},Node.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},Node.prototype.discreteStep=function(t){if(!this.xFixed){var e=-this.damping*this.vx,i=(this.fx+e)/this.mass;this.vx+=i*t,this.x+=this.vx*t}if(!this.yFixed){var n=-this.damping*this.vy,s=(this.fy+n)/this.mass;this.vy+=s*t,this.y+=this.vy*t}},Node.prototype.discreteStepLimited=function(t,e){if(!this.xFixed){var i=-this.damping*this.vx,n=(this.fx+i)/this.mass;this.vx+=n*t,this.vx=Math.abs(this.vx)>e?this.vx>0?e:-e:this.vx,this.x+=this.vx*t}if(!this.yFixed){var s=-this.damping*this.vy,o=(this.fy+s)/this.mass;this.vy+=o*t,this.vy=Math.abs(this.vy)>e?this.vy>0?e:-e:this.vy,this.y+=this.vy*t}},Node.prototype.isFixed=function(){return this.xFixed&&this.yFixed},Node.prototype.isMoving=function(t){return Math.abs(this.vx)>t||Math.abs(this.vy)>t?!0:(this.vx=0,this.vy=0,!1)},Node.prototype.isSelected=function(){return this.selected},Node.prototype.getValue=function(){return this.value},Node.prototype.getDistance=function(t,e){var i=this.x-t,n=this.y-e;return Math.sqrt(i*i+n*n)},Node.prototype.setValueRange=function(t,e){if(!this.radiusFixed&&void 0!==this.value)if(e==t)this.radius=(this.radiusMin+this.radiusMax)/2;else{var i=(this.radiusMax-this.radiusMin)/(e-t);this.radius=(this.value-t)*i+this.radiusMin}this.baseRadiusValue=this.radius},Node.prototype.draw=function(){throw"Draw method not initialized for node"},Node.prototype.resize=function(){throw"Resize method not initialized for node"},Node.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},Node.prototype._resizeImage=function(){if(!this.width||!this.height){var t,e;if(this.value){this.radius=this.baseRadiusValue;var i=this.imageObj.height/this.imageObj.width;void 0!==i?(t=this.radius||this.imageObj.width,e=this.radius*i||this.imageObj.height):(t=0,e=0)}else t=this.imageObj.width,e=this.imageObj.height;this.width=t,this.height=e,this.width>0&&this.height>0&&(this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor)}},Node.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e;if(0!=this.imageObj.width){if(this.clusterSize>1){var i=this.clusterSize>1?10:0;i*=this.graphScaleInv,i=Math.min(.2*this.width,i),t.globalAlpha=.5,t.drawImage(this.imageObj,this.left-i,this.top-i,this.width+2*i,this.height+2*i)}t.globalAlpha=1,t.drawImage(this.imageObj,this.left,this.top,this.width,this.height),e=this.y+this.height/2}else e=this.y;this._label(t,this.label,this.x,e,void 0,"top")},Node.prototype._resizeBox=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=.5*(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=.5*(this.clusterSize-1)*this.clusterSizeHeightFactor}},Node.prototype._drawBox=function(t){this._resizeBox(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.roundRect(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth,this.radius),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.roundRect(this.left,this.top,this.width,this.height,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.prototype._resizeDatabase=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=i.width+2*e;this.width=n,this.height=n,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor}},Node.prototype._drawDatabase=function(t){this._resizeDatabase(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.database(this.x-this.width/2-2*t.lineWidth,this.y-.5*this.height-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.database(this.x-this.width/2,this.y-.5*this.height,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=Math.max(i.width,i.height)+2*e;this.radius=n/2,this.width=n,this.height=n,this.radius+=.5*(this.clusterSize-1)*this.clusterSizeRadiusFactor}},Node.prototype._drawCircle=function(t){this._resizeCircle(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.circle(this.x,this.y,this.radius+2*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.circle(this.x,this.y,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.prototype._resizeEllipse=function(t){if(!this.width){var e=this.getTextSize(t);this.width=1.5*e.width,this.height=2*e.height,this.width1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.ellipse(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.ellipse(this.left,this.top,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.prototype._drawDot=function(t){this._drawShape(t,"circle")},Node.prototype._drawTriangle=function(t){this._drawShape(t,"triangle")},Node.prototype._drawTriangleDown=function(t){this._drawShape(t,"triangleDown")},Node.prototype._drawSquare=function(t){this._drawShape(t,"square")},Node.prototype._drawStar=function(t){this._drawShape(t,"star")},Node.prototype._resizeShape=function(){if(!this.width){this.radius=this.baseRadiusValue;var t=2*this.radius;this.width=t,this.height=t,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=.5*(this.clusterSize-1)*this.clusterSizeRadiusFactor}},Node.prototype._drawShape=function(t,e){this._resizeShape(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var i=2.5,n=2,s=2;switch(e){case"dot":s=2;break;case"square":s=2;break;case"triangle":s=3;break;case"triangleDown":s=3;break;case"star":s=4}t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?n:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t[e](this.x,this.y,this.radius+s*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?n:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t[e](this.x,this.y,this.radius),t.fill(),t.stroke(),this.label&&this._label(t,this.label,this.x,this.y+this.height/2,void 0,"top")},Node.prototype._resizeText=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor}},Node.prototype._drawText=function(t){this._resizeText(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,this._label(t,this.label,this.x,this.y)},Node.prototype._label=function(t,e,i,n,s,o){if(e){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle=this.fontColor||"black",t.textAlign=s||"center",t.textBaseline=o||"middle";for(var r=e.split("\n"),a=r.length,h=this.fontSize+4,l=n+(1-a)/2*h,c=0;a>c;c++)t.fillText(r[c],i,l),l+=h}},Node.prototype.getTextSize=function(t){if(void 0!==this.label){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace;for(var e=this.label.split("\n"),i=(this.fontSize+4)*e.length,n=0,s=0,o=e.length;o>s;s++)n=Math.max(n,t.measureText(e[s]).width);return{width:n,height:i}}return{width:0,height:0}},Node.prototype.inArea=function(){return void 0!==this.width?this.x+this.width*this.graphScaleInv>=this.canvasTopLeft.x&&this.x-this.width*this.graphScaleInv=this.canvasTopLeft.y&&this.y-this.height*this.graphScaleInv=this.canvasTopLeft.x&&this.x=this.canvasTopLeft.y&&this.yh},Edge.prototype._drawLine=function(t){t.strokeStyle=this.color,t.lineWidth=this._getLineWidth();var e;if(this.from!=this.to)this._line(t),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y));else{var i,n,s=this.length/4,o=this.from;o.width||o.resize(t),o.width>o.height?(i=o.x+o.width/2,n=o.y-s):(i=o.x+s,n=o.y-o.height/2),this._circle(t,i,n,s),e=this._pointOnCircle(i,n,s,.5),this._label(t,this.label,e.x,e.y)}},Edge.prototype._getLineWidth=function(){return 1==this.selected?Math.min(2*this.width,this.widthMax)*this.graphScaleInv:this.width*this.graphScaleInv},Edge.prototype._line=function(t){t.beginPath(),t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y),t.stroke()},Edge.prototype._circle=function(t,e,i,n){t.beginPath(),t.arc(e,i,n,0,2*Math.PI,!1),t.stroke()},Edge.prototype._label=function(t,e,i,n){if(e){t.font=(this.from.selected||this.to.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle="white";var s=t.measureText(e).width,o=this.fontSize,r=i-s/2,a=n-o/2;t.fillRect(r,a,s,o),t.fillStyle=this.fontColor||"black",t.textAlign="left",t.textBaseline="top",t.fillText(e,r,a)}},Edge.prototype._drawDashLine=function(t){if(t.strokeStyle=this.color,t.lineWidth=this._getLineWidth(),t.beginPath(),t.lineCap="round",void 0!==this.dash.altLength?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]):void 0!==this.dash.length&&void 0!==this.dash.gap?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap]):(t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y)),t.stroke(),this.label){var e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}},Edge.prototype._pointOnLine=function(t){return{x:(1-t)*this.from.x+t*this.to.x,y:(1-t)*this.from.y+t*this.to.y}},Edge.prototype._pointOnCircle=function(t,e,i,n){var s=2*(n-3/8)*Math.PI;return{x:t+i*Math.cos(s),y:e-i*Math.sin(s)}},Edge.prototype._drawArrowCenter=function(t){var e;if(t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth(),this.from!=this.to){this._line(t);var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),n=10+5*this.width;e=this._pointOnLine(.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y))}else{var s,o,r=this.length/4,a=this.from;a.width||a.resize(t),a.width>a.height?(s=a.x+a.width/2,o=a.y-r):(s=a.x+r,o=a.y-a.height/2),this._circle(t,s,o,r);var i=.2*Math.PI,n=10+5*this.width;e=this._pointOnCircle(s,o,r,.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(s,o,r,.5),this._label(t,this.label,e.x,e.y))}},Edge.prototype._drawArrow=function(t){t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth();var e,i;if(this.from!=this.to){e=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x);var n=this.to.x-this.from.x,s=this.to.y-this.from.y,o=Math.sqrt(n*n+s*s),r=this.from.distanceToBorder(t,e+Math.PI),a=(o-r)/o,h=a*this.from.x+(1-a)*this.to.x,l=a*this.from.y+(1-a)*this.to.y,c=this.to.distanceToBorder(t,e),d=(o-c)/o,u=(1-d)*this.from.x+d*this.to.x,p=(1-d)*this.from.y+d*this.to.y;if(t.beginPath(),t.moveTo(h,l),t.lineTo(u,p),t.stroke(),i=10+5*this.width,t.arrow(u,p,e,i),t.fill(),t.stroke(),this.label){var f=this._pointOnLine(.5);this._label(t,this.label,f.x,f.y)}}else{var g,m,v,y=this.from,_=this.length/4;y.width||y.resize(t),y.width>y.height?(g=y.x+y.width/2,m=y.y-_,v={x:g,y:y.y,angle:.9*Math.PI}):(g=y.x+_,m=y.y-y.height/2,v={x:y.x,y:m,angle:.6*Math.PI}),t.beginPath(),t.arc(g,m,_,0,2*Math.PI,!1),t.stroke(),i=10+5*this.width,t.arrow(v.x,v.y,v.angle,i),t.fill(),t.stroke(),this.label&&(f=this._pointOnCircle(g,m,_,.5),this._label(t,this.label,f.x,f.y))}},Edge._dist=function(t,e,i,n,s,o){var r=i-t,a=n-e,h=r*r+a*a,l=((s-t)*r+(o-e)*a)/h;l>1?l=1:0>l&&(l=0);var c=t+l*r,d=e+l*a,u=c-s,p=d-o;return Math.sqrt(u*u+p*p)},Edge.prototype.setScale=function(t){this.graphScaleInv=1/t},Edge.prototype.select=function(){this.selected=!0},Edge.prototype.unselect=function(){this.selected=!1},Popup.prototype.setPosition=function(t,e){this.x=parseInt(t),this.y=parseInt(e)},Popup.prototype.setText=function(t){this.frame.innerHTML=t},Popup.prototype.show=function(t){if(void 0===t&&(t=!0),t){var e=this.frame.clientHeight,i=this.frame.clientWidth,n=this.frame.parentNode.clientHeight,s=this.frame.parentNode.clientWidth,o=this.y-e;o+e+this.padding>n&&(o=n-e-this.padding),os&&(r=s-i-this.padding),rthis.constants.clustering.clusterThreshold&&1==this.constants.clustering.enabled&&this.clusterToFit(this.constants.clustering.reduceToNodes,!1),this._calculateForcesBarnesHut())},_calculateForcesOriginal:function(){this._calculateGravitationalForces(1),this._calculateRepulsionForces(),this._calculateSpringForces(1)},_calculateForcesBarnesHut:function(){this._clearForces(),this._calculateBarnesHutForces(),this._calculateSpringForces(1)},_clearForces:function(){for(var t,e=this.nodes,i=0;in&&(i=Math.atan2(e,t),a=.5*g>n?1:m*n+f,a*=0==r?1:1+r*this.constants.clustering.forceAmplification,s=Math.cos(i)*a,o=Math.sin(i)*a,h._addForce(-s,-o),l._addForce(s,o))}},_calculateSpringForces:function(t){var e,i,n,s,o,r,a,h,l,c,d,u=this.edges;for(c in u)u.hasOwnProperty(c)&&(l=u[c],l.connected&&this.nodes.hasOwnProperty(l.toId)&&this.nodes.hasOwnProperty(l.fromId)&&(d=l.to.clusterSize+l.from.clusterSize-2,e=l.to.x-l.from.x,i=l.to.y-l.from.y,h=l.length,h+=d*this.constants.clustering.edgeGrowth,a=Math.sqrt(e*e+i*i),n=Math.atan2(i,e),r=.02*(h-a)*t,s=Math.cos(n)*r,o=Math.sin(n)*r,l.from._addForce(-s,-o),l.to._addForce(s,o)))},_calculateBarnesHutForces:function(){this._formBarnesHutTree();var t,e=this.nodes,i=this.nodeIndices,n=i.length,s=this.barnesHutTree;this.theta=.2,this.graviationalConstant=-1e4;for(var o=0;n>o;o++)t=e[i[o]],this._getForceContribution(s.root.children.NW,t),this._getForceContribution(s.root.children.NE,t),this._getForceContribution(s.root.children.SW,t),this._getForceContribution(s.root.children.SE,t)},_getForceContribution:function(t,e){if(t.childrenCount>0){var i,n,s;if(i=t.CenterOfMass.x-e.x,n=t.CenterOfMass.y-e.y,s=Math.sqrt(i*i+n*n),s>0){var o=1/s;t.size*o>this.theta?4==t.childrenCount?(this._getForceContribution(t.children.NW,e),this._getForceContribution(t.children.NE,e),this._getForceContribution(t.children.SW,e),this._getForceContribution(t.children.SE,e)):this._getForceOnNode(t,e,i,n,o):this._getForceOnNode(t,e,i,n,o)}}},_getForceOnNode:function(t,e,i,n,s){var o=this.graviationalConstant*t.mass*e.mass*s*s,r=Math.atan2(n,i),a=Math.cos(r)*o,h=Math.sin(r)*o;e._addForce(a,h)},_formBarnesHutTree:function(){for(var t,e=this.nodes,i=this.nodeIndices,n=i.length,s=Number.MAX_VALUE,o=Number.MAX_VALUE,r=-Number.MAX_VALUE,a=-Number.MAX_VALUE,h=0;n>h;h++){var l=e[i[h]].x,c=e[i[h]].y;s>l&&(s=l),l>r&&(r=l),o>c&&(o=c),c>a&&(a=c)}var d=Math.abs(r-s)-Math.abs(a-o);d>0?(o-=.5*d,a+=.5*d):(s+=.5*d,a-=.5*d);var u={root:{CenterOfMass:{x:0,y:0},mass:0,range:{minX:s,maxX:r,minY:o,maxY:a},size:Math.abs(r-s),children:{data:null},childrenCount:4}};for(this._splitBranch(u.root),h=0;n>h;h++)t=e[i[h]],this._placeInTree(u.root,t);this.barnesHutTree=u},_updateBranchMass:function(t,e){var i=t.mass+e.mass,n=1/i;t.CenterOfMass.x=t.CenterOfMass.x*t.mass+e.x*e.mass,t.CenterOfMass.x*=n,t.CenterOfMass.y=t.CenterOfMass.y*t.mass+e.y*e.mass,t.CenterOfMass.y*=n,t.mass=i},_placeInTree:function(t,e){this._updateBranchMass(t,e),t.children.NW.range.maxX>e.x?t.children.NW.range.maxY>e.y?this._placeInRegion(t,e,"NW"):this._placeInRegion(t,e,"SW"):t.children.NE.range.maxY>e.y?this._placeInRegion(t,e,"NE"):this._placeInRegion(t,e,"SE")},_placeInRegion:function(t,e,i){switch(t.children[i].childrenCount){case 0:t.children[i].children.data=e,t.children[i].childrenCount=1,this._updateBranchMass(t.children[i],e);break;case 1:this._splitBranch(t.children[i]),this._placeInTree(t.children[i],e);break;case 4:this._placeInTree(t.children[i],e)}},_splitBranch:function(t){var e=null;1==t.childrenCount&&(e=t.children.data,t.mass=0,t.CenterOfMass.x=0,t.CenterOfMass.y=0),t.childrenCount=4,t.children.data=null,this._insertRegion(t,"NW"),this._insertRegion(t,"NE"),this._insertRegion(t,"SW"),this._insertRegion(t,"SE"),null!=e&&this._placeInTree(t,e)},_insertRegion:function(t,e){var i,n,s,o;switch(e){case"NW":i=t.range.minX,n=t.range.minX+t.size,s=t.range.minY,o=t.range.minY+t.size;break;case"NE":i=t.range.minX+t.size,n=t.range.maxX,s=t.range.minY,o=t.range.minY+t.size;break;case"SW":i=t.range.minX,n=t.range.minX+t.size,s=t.range.minY+t.size,o=t.range.maxY;break;case"SE":i=t.range.minX+t.size,n=t.range.maxX,s=t.range.minY+t.size,o=t.range.maxY}t.children[e]={CenterOfMass:{x:0,y:0},mass:0,range:{minX:i,maxX:n,minY:s,maxY:o},size:.5*t.size,children:{data:null},childrenCount:0}},_drawTree:function(t,e){void 0!==this.barnesHutTree&&(t.lineWidth=2,this._drawBranch(this.barnesHutTree.root,t,e))},_drawBranch:function(t,e,i){void 0===i&&(i="#FF0000"),4==t.childrenCount&&(this._drawBranch(t.children.NW,e),this._drawBranch(t.children.NE,e),this._drawBranch(t.children.SE,e),this._drawBranch(t.children.SW,e)),e.strokeStyle=i,e.beginPath(),e.moveTo(t.range.minX,t.range.minY),e.lineTo(t.range.maxX,t.range.minY),e.stroke(),e.beginPath(),e.moveTo(t.range.maxX,t.range.minY),e.lineTo(t.range.maxX,t.range.maxY),e.stroke(),e.beginPath(),e.moveTo(t.range.maxX,t.range.maxY),e.lineTo(t.range.minX,t.range.maxY),e.stroke(),e.beginPath(),e.moveTo(t.range.minX,t.range.maxY),e.lineTo(t.range.minX,t.range.minY),e.stroke()}},manipulationMixin={_clearManipulatorBar:function(){for(;this.manipulationDiv.hasChildNodes();)this.manipulationDiv.removeChild(this.manipulationDiv.firstChild)},_createManipulatorBar:function(){for(this.off("select",this.boundFunction),this.blockConnectingEdgeSelection=!1,this.forceAppendSelection=!1;this.manipulationDiv.hasChildNodes();)this.manipulationDiv.removeChild(this.manipulationDiv.firstChild);this.manipulationDiv.innerHTML="Add Node
    Edit Selected
    Connect Node
    Delete selected";var t=document.getElementById("manipulate-addNode");t.onclick=this._createAddToolbar.bind(this);var e=document.getElementById("manipulate-editNode");e.onclick=this._createEditToolbar.bind(this);var i=document.getElementById("manipulate-connectNode");i.onclick=this._createConnectToolbar.bind(this); +var n=document.getElementById("manipulate-delete");n.onclick=this._createDeletionToolbar.bind(this)},_createAddToolbar:function(){this._clearManipulatorBar(),this.off("select",this.boundFunction),this.manipulationDiv.innerHTML="Back
    Click in an empty space to place a new node";var t=document.getElementById("manipulate-back");t.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._addNode.bind(this),this.on("select",this.boundFunction)},_createEditToolbar:function(){this.blockConnectingEdgeSelection=!1,this._clearManipulatorBar(),this.off("select",this.boundFunction);var t="";if(this._selectionIsEmpty()?t="Select a node or edge to edit.":this._getSelectedObjectCount()>1?(t="Select a single node or edge to edit.",this._unselectAll(!0)):this._clusterInSelection()?(t="You cannot edit a cluster.",this._unselectAll(!0)):this._getSelectedNodeCount()>0?this._createEditNodeToolbar():this._createEditEdgeToolbar(),""!=t){this.blockConnectingEdgeSelection=!0,this.manipulationDiv.innerHTML="Back
    "+t+"";var e=document.getElementById("manipulate-back");e.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._createEditToolbar.bind(this),this.on("select",this.boundFunction)}},_createEditNodeToolbar:function(){this.blockConnectingEdgeSelection=!1,this._clearManipulatorBar(),this.off("select",this.boundFunction);var t=this._getEditObject();this.manipulationDiv.innerHTML="Cancel
    label:
    color:
    ";var e=document.getElementById("manipulate-back");e.onclick=this._createManipulatorBar.bind(this);var i=document.getElementById("manipulator-obj-save");i.onclick=this._saveNodeData.bind(this),this.boundFunction=this._createManipulatorBar.bind(this),this.on("select",this.boundFunction)},_saveNodeData:function(){var t=this._getEditObject().id,e=document.getElementById("manipulator-obj-label").value,i=document.getElementById("manipulator-obj-color").value,n=util.hexToHSV(i),s={h:n.h,s:.45*n.s,v:Math.min(1,1.05*n.v)},o={h:n.h,s:Math.min(1,1.25*n.v),v:.6*n.v},r=util.HSVToHex(o.h,o.h,o.v),a=util.HSVToHex(s.h,s.s,s.v),h={id:t,label:e,color:{background:i,border:r,highlight:{background:a,border:r}}};this.nodesData.update(h),this._createManipulatorBar()},_createEditEdgeToolbar:function(){this.blockConnectingEdgeSelection=!1,this._clearManipulatorBar(),this.off("select",this.boundFunction),this.manipulationDiv.innerHTML="Back
    Currently only nodes can be edited.";var t=document.getElementById("manipulate-back");t.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._createManipulatorBar.bind(this),this.on("select",this.boundFunction)},_createConnectToolbar:function(){this._clearManipulatorBar(),this.off("select",this.boundFunction),this._unselectAll(),this.forceAppendSelection=!1,this.blockConnectingEdgeSelection=!0,this.manipulationDiv.innerHTML="Back
    Select the node you want to connect to other nodes.";var t=document.getElementById("manipulate-back");t.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._handleConnect.bind(this),this.on("select",this.boundFunction)},_createDeletionToolbar:function(){if(this._clearManipulatorBar(),this.off("select",this.boundFunction),this._selectionIsEmpty()){this.manipulationDiv.innerHTML="Cannot delete an empty selection.";var t=this;window.setTimeout(function(){t._createManipulatorBar()},1500)}else{this.manipulationDiv.innerHTML="Back
    Are you sure? This cannot be undone.
    Yes.";var e=document.getElementById("manipulate-back");e.onclick=this._createManipulatorBar.bind(this);var i=document.getElementById("manipulate-acceptDelete");i.onclick=this._deleteSelected.bind(this),this.boundFunction=this._createManipulatorBar.bind(this),this.on("select",this.boundFunction)}},_handleConnect:function(){this.forceAppendSelection=!1,this._clusterInSelection()?(this._unselectClusters(!0),this._selectionIsEmpty()?this._setManipulationMessage("You cannot connect anything to a cluster."):(this._setManipulationMessage("You cannot connect a node to a cluster."),this.forceAppendSelection=!0)):this._selectionIsEmpty()?this._setManipulationMessage("Select the node you want to connect to other nodes."):2==this._getSelectedNodeCount()?(this._connectNodes(),this._restoreSourceNode(),this._setManipulationMessage("Click on another node you want to connect this node to or go back.")):(this._setManipulationMessage("Click on the node you want to connect this node."),this._setSourceNode(),this.forceAppendSelection=!0)},_getEditObject:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t))return this.selectionObj[t];return null},_setSourceNode:function(){for(var t in this.selectionObj)this.selectionObj.hasOwnProperty(t)&&this.selectionObj[t]instanceof Node&&(this.manipulationSourceNode=this.selectionObj[t])},_getTargetNode:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t)&&this.selectionObj[t]instanceof Node&&this.manipulationSourceNode.id!=this.selectionObj[t].id)return this.selectionObj[t];return null},_restoreSourceNode:function(){this._unselectAll(!0),this._selectObject(this.manipulationSourceNode)},_setManipulationMessage:function(t){var e=document.getElementById("manipulatorLabel");e.innerHTML=t},_addNode:function(){if(this._selectionIsEmpty()){var t=this._pointerToPositionObject(this.pointerPosition);this.createNodeOnClick=!0,this.nodesData.add({id:util.randomUUID(),x:t.left,y:t.top,label:"new",fixed:!1}),this.createNodeOnClick=!1,this.moving=!0,this.start()}},_connectNodes:function(){var t=this._getTargetNode(),e=this.manipulationSourceNode;this.edgesData.add({from:e.id,to:t.id}),this.moving=!0,this.start()},_deleteSelected:function(){if(this._clusterInSelection())alert("Clusters cannot be deleted.");else{var t=this.getSelectedNodes(),e=this.getSelectedEdges();this._removeEdges(e),this._removeNodes(t),this.moving=!0,this.start()}}},SectorMixin={_putDataInSector:function(){this.sectors.active[this._sector()].nodes=this.nodes,this.sectors.active[this._sector()].edges=this.edges,this.sectors.active[this._sector()].nodeIndices=this.nodeIndices},_switchToSector:function(t,e){void 0===e||"active"==e?this._switchToActiveSector(t):this._switchToFrozenSector(t)},_switchToActiveSector:function(t){this.nodeIndices=this.sectors.active[t].nodeIndices,this.nodes=this.sectors.active[t].nodes,this.edges=this.sectors.active[t].edges},_switchToFrozenSector:function(t){this.nodeIndices=this.sectors.frozen[t].nodeIndices,this.nodes=this.sectors.frozen[t].nodes,this.edges=this.sectors.frozen[t].edges},_switchToNavigationSector:function(){this.nodeIndices=this.sectors.navigation.nodeIndices,this.nodes=this.sectors.navigation.nodes,this.edges=this.sectors.navigation.edges},_loadLatestSector:function(){this._switchToSector(this._sector())},_sector:function(){return this.activeSector[this.activeSector.length-1]},_previousSector:function(){if(this.activeSector.length>1)return this.activeSector[this.activeSector.length-2];throw new TypeError("there are not enough sectors in the this.activeSector array.")},_setActiveSector:function(t){this.activeSector.push(t)},_forgetLastSector:function(){this.activeSector.pop()},_createNewSector:function(t){this.sectors.active[t]={nodes:{},edges:{},nodeIndices:[],formationScale:this.scale,drawingNode:void 0},this.sectors.active[t].drawingNode=new Node({id:t,color:{background:"#eaefef",border:"495c5e"}},{},{},this.constants),this.sectors.active[t].drawingNode.clusterSize=2},_deleteActiveSector:function(t){delete this.sectors.active[t]},_deleteFrozenSector:function(t){delete this.sectors.frozen[t]},_freezeSector:function(t){this.sectors.frozen[t]=this.sectors.active[t],this._deleteActiveSector(t)},_activateSector:function(t){this.sectors.active[t]=this.sectors.frozen[t],this._deleteFrozenSector(t)},_mergeThisWithFrozen:function(t){for(var e in this.nodes)this.nodes.hasOwnProperty(e)&&(this.sectors.frozen[t].nodes[e]=this.nodes[e]);for(var i in this.edges)this.edges.hasOwnProperty(i)&&(this.sectors.frozen[t].edges[i]=this.edges[i]);for(var n=0;n1?this[t](n[0],n[1]):this[t](e)}this._loadLatestSector()},_doInAllFrozenSectors:function(t,e){if(void 0===e)for(var i in this.sectors.frozen)this.sectors.frozen.hasOwnProperty(i)&&(this._switchToFrozenSector(i),this[t]());else for(var i in this.sectors.frozen)if(this.sectors.frozen.hasOwnProperty(i)){this._switchToFrozenSector(i);var n=Array.prototype.splice.call(arguments,1);n.length>1?this[t](n[0],n[1]):this[t](e)}this._loadLatestSector()},_doInNavigationSector:function(t,e){if(this._switchToNavigationSector(),void 0===e)this[t]();else{var i=Array.prototype.splice.call(arguments,1);i.length>1?this[t](i[0],i[1]):this[t](e)}this._loadLatestSector()},_doInAllSectors:function(t,e){var i=Array.prototype.splice.call(arguments,1);void 0===e?(this._doInAllActiveSectors(t),this._doInAllFrozenSectors(t)):i.length>1?(this._doInAllActiveSectors(t,i[0],i[1]),this._doInAllFrozenSectors(t,i[0],i[1])):(this._doInAllActiveSectors(t,e),this._doInAllFrozenSectors(t,e))},_clearNodeIndexList:function(){var t=this._sector();this.sectors.active[t].nodeIndices=[],this.nodeIndices=this.sectors.active[t].nodeIndices},_drawSectorNodes:function(t,e){var i,n=1e9,s=-1e9,o=1e9,r=-1e9;for(var a in this.sectors[e])if(this.sectors[e].hasOwnProperty(a)&&void 0!==this.sectors[e][a].drawingNode){this._switchToSector(a,e),n=1e9,s=-1e9,o=1e9,r=-1e9;for(var h in this.nodes)this.nodes.hasOwnProperty(h)&&(i=this.nodes[h],i.resize(t),o>i.x-.5*i.width&&(o=i.x-.5*i.width),ri.y-.5*i.height&&(n=i.y-.5*i.height),st&&n>s;)s%3==0?this.forceAggregateHubs():this.increaseClusterLevel(),i=this.nodeIndices.length,s+=1;s>1&&1==e&&this.repositionNodes()},openCluster:function(t){var e=this.moving;if(t.clusterSize>this.constants.clustering.sectorThreshold&&this._nodeInActiveArea(t)&&("default"!=this._sector()||1!=this.nodeIndices.length)){this._addSector(t);for(var i=0;this.nodeIndices.lengthi;)this.decreaseClusterLevel(),i+=1}else this._expandClusterNode(t,!1,!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels();this.moving!=e&&this.start()},updateClustersDefault:function(){1==this.constants.clustering.enabled&&this.updateClusters(0,!1,!1)},increaseClusterLevel:function(){this.updateClusters(-1,!1,!0)},decreaseClusterLevel:function(){this.updateClusters(1,!1,!0)},updateClusters:function(t,e,i){var n=this.moving,s=this.nodeIndices.length;this.previousScale>this.scale&&0==t&&this._collapseSector(),this.previousScale>this.scale||-1==t?this._formClusters(i):(this.previousScalethis.scale||-1==t)&&(this._aggregateHubs(i),this._updateNodeIndexList()),(this.previousScale>this.scale||-1==t)&&(this.handleChains(),this._updateNodeIndexList()),this.previousScale=this.scale,this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.lengththis.constants.clustering.chainThreshold&&this._reduceAmountOfChains(1-this.constants.clustering.chainThreshold/t)},_aggregateHubs:function(t){this._getHubSize(),this._formClustersByHub(t,!1)},forceAggregateHubs:function(){var t=this.moving,e=this.nodeIndices.length;this._aggregateHubs(!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.length!=e&&(this.clusterSession+=1),this.moving!=t&&this.start()},_openClustersBySize:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];1==e.inView()&&(e.width*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientWidth||e.height*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientHeight)&&this.openCluster(e)}},_openClusters:function(t,e){for(var i=0;i1&&(t.clusterSizei)){var r=o.from,a=o.to;o.to.mass>o.from.mass&&(r=o.to,a=o.from),1==a.dynamicEdgesLength?this._addToCluster(r,a,!1):1==r.dynamicEdgesLength&&this._addToCluster(a,r,!1)}}},_forceClustersByZoom:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];if(1==e.dynamicEdgesLength&&0!=e.dynamicEdges.length){var i=e.dynamicEdges[0],n=i.toId==e.id?this.nodes[i.fromId]:this.nodes[i.toId];e.id!=n.id&&(n.mass>e.mass?this._addToCluster(n,e,!0):this._addToCluster(e,n,!0))}}},_formClustersByHub:function(t,e){for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&this._formClusterFromHub(this.nodes[i],t,e)},_formClusterFromHub:function(t,e,i,n){if(void 0===n&&(n=0),t.dynamicEdgesLength>=this.hubThreshold&&0==i||t.dynamicEdgesLength==this.hubThreshold&&1==i){for(var s,o,r,a=this.constants.clustering.clusterEdgeThreshold/this.scale,h=!1,l=[],c=t.dynamicEdges.length,d=0;c>d;d++)l.push(t.dynamicEdges[d].id);if(0==e)for(h=!1,d=0;c>d;d++){var u=this.edges[l[d]];if(void 0!==u&&u.connected&&u.toId!=u.fromId&&(s=u.to.x-u.from.x,o=u.to.y-u.from.y,r=Math.sqrt(s*s+o*o),a>r)){h=!0;break}}if(!e&&h||e)for(d=0;c>d;d++)if(u=this.edges[l[d]],void 0!==u){var p=this.nodes[u.fromId==t.id?u.toId:u.fromId];p.dynamicEdges.length<=this.hubThreshold+n&&p.id!=t.id&&this._addToCluster(t,p,e)}}},_addToCluster:function(t,e,i){t.containedNodes[e.id]=e;for(var n=0;n1)for(var n=0;n1&&(e.label="[".concat(String(e.clusterSize),"]"))}for(t in this.nodes)this.nodes.hasOwnProperty(t)&&(e=this.nodes[t],1==e.clusterSize&&(e.label=void 0!==e.originalLabel?e.originalLabel:String(e.id)))},_nodeInActiveArea:function(t){return Math.abs(t.x-this.areaCenter.x)<=this.constants.clustering.activeAreaBoxSize/this.scale&&Math.abs(t.y-this.areaCenter.y)<=this.constants.clustering.activeAreaBoxSize/this.scale},repositionNodes:function(){for(var t=0;tn&&(n=o.dynamicEdgesLength),t+=o.dynamicEdgesLength,e+=Math.pow(o.dynamicEdgesLength,2),i+=1}t/=i,e/=i;var r=e-Math.pow(t,2),a=Math.sqrt(r);this.hubThreshold=Math.floor(t+2*a),this.hubThreshold>n&&(this.hubThreshold=n)},_reduceAmountOfChains:function(t){this.hubThreshold=2;var e=Math.floor(this.nodeIndices.length*t);for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&e>0&&(this._formClusterFromHub(this.nodes[i],!0,!0,1),e-=1)},_getChainFraction:function(){var t=0,e=0;for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&(2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&(t+=1),e+=1);return t/e}},SelectionMixin={_getNodesOverlappingWith:function(t,e){var i=this.nodes;for(var n in i)i.hasOwnProperty(n)&&i[n].isOverlappingWith(t)&&e.push(n)},_getAllNodesOverlappingWith:function(t){var e=[];return this._doInAllActiveSectors("_getNodesOverlappingWith",t,e),e},_getAllNavigationNodesOverlappingWith:function(t){var e=[];return this._doInNavigationSector("_getNodesOverlappingWith",t,e),e},_pointerToPositionObject:function(t){var e=this._canvasToX(t.x),i=this._canvasToY(t.y);return{left:e,top:i,right:e,bottom:i}},_pointerToScreenPositionObject:function(t){var e=t.x,i=t.y;return{left:e,top:i,right:e,bottom:i}},_getNavigationNodeAt:function(t){var e=this._pointerToScreenPositionObject(t),i=this._getAllNavigationNodesOverlappingWith(e);return i.length>0?this.sectors.navigation.nodes[i[i.length-1]]:null},_getNodeAt:function(t){var e=this._pointerToPositionObject(t),i=this._getAllNodesOverlappingWith(e);return i.length>0?this.nodes[i[i.length-1]]:null},_getEdgesOverlappingWith:function(t,e){var i=this.edges;for(var n in i)i.hasOwnProperty(n)&&i[n].isOverlappingWith(t)&&e.push(n)},_getAllEdgesOverlappingWith:function(t){var e=[];return this._doInAllActiveSectors("_getEdgesOverlappingWith",t,e),e},_getEdgeAt:function(t){var e=this._pointerToPositionObject(t),i=this._getAllEdgesOverlappingWith(e);return i.length>0?this.edges[i[i.length-1]]:null},_addToSelection:function(t){this.selectionObj[t.id]=t},_removeFromSelection:function(t){delete this.selectionObj[t.id]},_unselectAll:function(t){void 0===t&&(t=!1);for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e].unselect();this.selectionObj={},0==t&&this._trigger("select",this.getSelection())},_unselectClusters:function(t){void 0===t&&(t=!1);for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e]instanceof Node&&this.selectionObj[e].clusterSize>1&&(this.selectionObj[e].unselect(),this._removeFromSelection(this.selectionObj[e]));0==t&&this._trigger("select",this.getSelection())},_getSelectedNodeCount:function(){var t=0;for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e]instanceof Node&&(t+=1);return t},_getSelectedEdgeCount:function(){var t=0;for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e]instanceof Edge&&(t+=1);return t},_getSelectedObjectCount:function(){var t=0;for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&(t+=1);return t},_selectionIsEmpty:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t))return!1;return!0},_clusterInSelection:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t)&&this.selectionObj[t]instanceof Node&&this.selectionObj[t].clusterSize>1)return!0;return!1},_selectConnectedEdges:function(t){for(var e=0;ee;e++){n=t[e];var s=this.nodes[n];if(!s)throw new RangeError('Node with id "'+n+'" not found');this._selectObject(s,!0,!0)}this.redraw()},_updateSelection:function(){for(var t in this.selectionObj)this.selectionObj.hasOwnProperty(t)&&(this.selectionObj[t]instanceof Node?this.nodes.hasOwnProperty(t)||delete this.selectionObj[t]:this.edges.hasOwnProperty(t)||delete this.selectionObj[t])}},NavigationMixin={_relocateNavigation:function(){if(void 0!==this.sectors){var t=this.navigationClientWidth-this.frame.canvas.clientWidth,e=this.navigationClientHeight-this.frame.canvas.clientHeight;this.navigationClientWidth=this.frame.canvas.clientWidth,this.navigationClientHeight=this.frame.canvas.clientHeight;var i=null;for(var n in this.sectors.navigation.nodes)this.sectors.navigation.nodes.hasOwnProperty(n)&&(i=this.sectors.navigation.nodes[n],i.horizontalAlignLeft||(i.x-=t),i.verticalAlignTop||(i.y-=e))}},_loadNavigationElements:function(){var t=this.constants.navigation.iconPath;this.navigationClientWidth=this.frame.canvas.clientWidth,this.navigationClientHeight=this.frame.canvas.clientHeight,void 0===this.navigationClientWidth&&(this.navigationClientWidth=0,this.navigationClientHeight=0);for(var e=15,i=7,n=[{id:"navigation_up",shape:"image",image:t+"/uparrow.png",triggerFunction:"_moveUp",verticalAlignTop:!1,x:45+e+i,y:this.navigationClientHeight-45-e-i},{id:"navigation_down",shape:"image",image:t+"/downarrow.png",triggerFunction:"_moveDown",verticalAlignTop:!1,x:45+e+i,y:this.navigationClientHeight-15-e},{id:"navigation_left",shape:"image",image:t+"/leftarrow.png",triggerFunction:"_moveLeft",verticalAlignTop:!1,x:15+e,y:this.navigationClientHeight-15-e},{id:"navigation_right",shape:"image",image:t+"/rightarrow.png",triggerFunction:"_moveRight",verticalAlignTop:!1,x:75+e+2*i,y:this.navigationClientHeight-15-e},{id:"navigation_plus",shape:"image",image:t+"/plus.png",triggerFunction:"_zoomIn",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-45-e-i,y:this.navigationClientHeight-15-e},{id:"navigation_min",shape:"image",image:t+"/minus.png",triggerFunction:"_zoomOut",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-15-e,y:this.navigationClientHeight-15-e},{id:"navigation_zoomExtends",shape:"image",image:t+"/zoomExtends.png",triggerFunction:"zoomToFit",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-15-e,y:this.navigationClientHeight-45-e-i}],s=null,o=0;ot.x-t.width&&(n=t.x-t.width),st.y-t.height&&(e=t.y-t.height),i=this.constants.clustering.initialMaxNodes)var n=38.8467/(e-14.50184)+.0116;else var n=42.54117319/(e+39.31966387)+.1944405;else{var s=1.1*(Math.abs(i.minX)+Math.abs(i.maxX)),o=1.1*(Math.abs(i.minY)+Math.abs(i.maxY)),r=this.frame.canvas.clientWidth/s,a=this.frame.canvas.clientHeight/o;n=a>=r?r:a}n>1&&(n=1),this.pinch.mousewheelScale=n,this._setScale(n),this._centerGraph(i),this.start()},Graph.prototype._updateNodeIndexList=function(){this._clearNodeIndexList();for(var t in this.nodes)this.nodes.hasOwnProperty(t)&&this.nodeIndices.push(t)},Graph.prototype.setData=function(t,e){if(void 0===e&&(e=!1),t&&t.dot&&(t.nodes||t.edges))throw new SyntaxError('Data must contain either parameter "dot" or parameter pair "nodes" and "edges", but not both.');if(this.setOptions(t&&t.options),t&&t.dot){if(t&&t.dot){var i=vis.util.DOTToGraph(t.dot);return void this.setData(i)}}else this._setNodes(t&&t.nodes),this._setEdges(t&&t.edges);this._putDataInSector(),e||(this.stabilize&&this._doStabilize(),this.moving=!0,this.start())},Graph.prototype.setOptions=function(t){if(t){if(void 0!==t.width&&(this.width=t.width),void 0!==t.height&&(this.height=t.height),void 0!==t.stabilize&&(this.stabilize=t.stabilize),void 0!==t.selectable&&(this.selectable=t.selectable),t.clustering){this.constants.clustering.enabled=!0;for(var e in t.clustering)t.clustering.hasOwnProperty(e)&&(this.constants.clustering[e]=t.clustering[e])}else void 0!==t.clustering&&(this.constants.clustering.enabled=!1);if(t.navigation){this.constants.navigation.enabled=!0;for(var e in t.navigation)t.navigation.hasOwnProperty(e)&&(this.constants.navigation[e]=t.navigation[e])}else void 0!==t.navigation&&(this.constants.navigation.enabled=!1);if(t.keyboard){this.constants.keyboard.enabled=!0;for(var e in t.keyboard)t.keyboard.hasOwnProperty(e)&&(this.constants.keyboard[e]=t.keyboard[e])}else void 0!==t.keyboard&&(this.constants.keyboard.enabled=!1);if(t.dataManipulationToolbar){this.constants.dataManipulationToolbar.enabled=!0;for(var e in t.dataManipulationToolbar)t.dataManipulationToolbar.hasOwnProperty(e)&&(this.constants.dataManipulationToolbar[e]=t.dataManipulationToolbar[e])}else void 0!==t.dataManipulationToolbar&&(this.constants.dataManipulationToolbar.enabled=!1);if(t.edges){for(e in t.edges)t.edges.hasOwnProperty(e)&&(this.constants.edges[e]=t.edges[e]);void 0!==t.edges.length&&t.nodes&&void 0===t.nodes.distance&&(this.constants.edges.length=t.edges.length,this.constants.nodes.distance=1.25*t.edges.length),t.edges.fontColor||(this.constants.edges.fontColor=t.edges.color),t.edges.dash&&(void 0!==t.edges.dash.length&&(this.constants.edges.dash.length=t.edges.dash.length),void 0!==t.edges.dash.gap&&(this.constants.edges.dash.gap=t.edges.dash.gap),void 0!==t.edges.dash.altLength&&(this.constants.edges.dash.altLength=t.edges.dash.altLength))}if(t.nodes){for(e in t.nodes)t.nodes.hasOwnProperty(e)&&(this.constants.nodes[e]=t.nodes[e]);t.nodes.color&&(this.constants.nodes.color=Node.parseColor(t.nodes.color))}if(t.groups)for(var i in t.groups)if(t.groups.hasOwnProperty(i)){var n=t.groups[i];this.groups.add(i,n)}}this._loadNavigationControls(),this._loadManipulationSystem(),this._createKeyBinds(),this.setSize(this.width,this.height),this._setTranslation(this.frame.clientWidth/2,this.frame.clientHeight/2),this._setScale(1),this._redraw()},Graph.prototype.on=function(t,e){var i=["select"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());events.addListener(this,t,e)},Graph.prototype.off=function(t,e){events.removeListener(this,t,e)},Graph.prototype._trigger=function(t,e){events.trigger(this,t,e)},Graph.prototype._create=function(){for(;this.containerElement.hasChildNodes();)this.containerElement.removeChild(this.containerElement.firstChild);if(this.frame=document.createElement("div"),this.frame.className="graph-frame",this.frame.style.position="relative",this.frame.style.overflow="hidden",this.frame.style.zIndex="1",this.frame.canvas=document.createElement("canvas"),this.frame.canvas.style.position="relative",this.frame.appendChild(this.frame.canvas),!this.frame.canvas.getContext){var t=document.createElement("DIV");t.style.color="red",t.style.fontWeight="bold",t.style.padding="10px",t.innerHTML="Error: your browser does not support HTML canvas",this.frame.canvas.appendChild(t)}var e=this;this.drag={},this.pinch={},this.hammer=Hammer(this.frame.canvas,{prevent_default:!0}),this.hammer.on("tap",e._onTap.bind(e)),this.hammer.on("doubletap",e._onDoubleTap.bind(e)),this.hammer.on("hold",e._onHold.bind(e)),this.hammer.on("pinch",e._onPinch.bind(e)),this.hammer.on("touch",e._onTouch.bind(e)),this.hammer.on("dragstart",e._onDragStart.bind(e)),this.hammer.on("drag",e._onDrag.bind(e)),this.hammer.on("dragend",e._onDragEnd.bind(e)),this.hammer.on("release",e._onRelease.bind(e)),this.hammer.on("mousewheel",e._onMouseWheel.bind(e)),this.hammer.on("DOMMouseScroll",e._onMouseWheel.bind(e)),this.hammer.on("mousemove",e._onMouseMoveTitle.bind(e)),this.containerElement.appendChild(this.frame)},Graph.prototype._createKeyBinds=function(){var t=this;this.mousetrap=mousetrap,this.mousetrap.reset(),1==this.constants.keyboard.enabled&&(this.mousetrap.bind("up",this._moveUp.bind(t),"keydown"),this.mousetrap.bind("up",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("down",this._moveDown.bind(t),"keydown"),this.mousetrap.bind("down",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("left",this._moveLeft.bind(t),"keydown"),this.mousetrap.bind("left",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("right",this._moveRight.bind(t),"keydown"),this.mousetrap.bind("right",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("=",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("=",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("-",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("-",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("[",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("[",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("]",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("]",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pageup",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("pageup",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pagedown",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("pagedown",this._stopZoom.bind(t),"keyup")),this.mousetrap.bind("b",this._formBarnesHutTree.bind(t)),1==this.constants.dataManipulationToolbar.enabled&&this.mousetrap.bind("escape",this._createManipulatorBar.bind(t))},Graph.prototype._getPointer=function(t){return{x:t.pageX-vis.util.getAbsoluteLeft(this.frame.canvas),y:t.pageY-vis.util.getAbsoluteTop(this.frame.canvas)}},Graph.prototype._onTouch=function(t){this.drag.pointer=this._getPointer(t.gesture.touches[0]),this.drag.pinched=!1,this.pinch.scale=this._getScale(),this._handleTouch(this.drag.pointer)},Graph.prototype._onDragStart=function(){var t=this.drag,e=this._getNodeAt(t.pointer);if(t.dragging=!0,t.selection=[],t.translation=this._getTranslation(),t.nodeId=null,null!=e){t.nodeId=e.id,e.isSelected()||this._selectObject(e,!1);for(var i in this.selectionObj)if(this.selectionObj.hasOwnProperty(i)){var n=this.selectionObj[i];if(n instanceof Node){var s={id:n.id,node:n,x:n.x,y:n.y,xFixed:n.xFixed,yFixed:n.yFixed};n.xFixed=!0,n.yFixed=!0,t.selection.push(s)}}}},Graph.prototype._onDrag=function(t){if(!this.drag.pinched){var e=this._getPointer(t.gesture.touches[0]),i=this,n=this.drag,s=n.selection;if(s&&s.length){var o=e.x-n.pointer.x,r=e.y-n.pointer.y;s.forEach(function(t){var e=t.node;t.xFixed||(e.x=i._canvasToX(i._xToCanvas(t.x)+o)),t.yFixed||(e.y=i._canvasToY(i._yToCanvas(t.y)+r))}),this.moving||(this.moving=!0,this.start())}else{var a=e.x-this.drag.pointer.x,h=e.y-this.drag.pointer.y;this._setTranslation(this.drag.translation.x+a,this.drag.translation.y+h),this._redraw(),this.moved=!0}}},Graph.prototype._onDragEnd=function(){this.drag.dragging=!1;var t=this.drag.selection;t&&t.forEach(function(t){t.node.xFixed=t.xFixed,t.node.yFixed=t.yFixed})},Graph.prototype._onTap=function(t){var e=this._getPointer(t.gesture.touches[0]);this.pointerPosition=e,this._handleTap(e)},Graph.prototype._onDoubleTap=function(t){var e=this._getPointer(t.gesture.touches[0]);this._handleDoubleTap(e)},Graph.prototype._onHold=function(t){var e=this._getPointer(t.gesture.touches[0]);this.pointerPosition=e,this._handleOnHold(e)},Graph.prototype._onRelease=function(){this._handleOnRelease()},Graph.prototype._onPinch=function(t){var e=this._getPointer(t.gesture.center);this.drag.pinched=!0,"scale"in this.pinch||(this.pinch.scale=1);var i=this.pinch.scale*t.gesture.scale;this._zoom(i,e)},Graph.prototype._zoom=function(t,e){var i=this._getScale();1e-5>t&&(t=1e-5),t>10&&(t=10);var n=this._getTranslation(),s=t/i,o=(1-s)*e.x+n.x*s,r=(1-s)*e.y+n.y*s;return this.areaCenter={x:this._canvasToX(e.x),y:this._canvasToY(e.y)},this.pinch.mousewheelScale=t,this._setScale(t),this._setTranslation(o,r),this.updateClustersDefault(),this._redraw(),t},Graph.prototype._onMouseWheel=function(t){var e=0;if(t.wheelDelta?e=t.wheelDelta/120:t.detail&&(e=-t.detail/3),e){"mousewheelScale"in this.pinch||(this.pinch.mousewheelScale=1);var i=this.pinch.mousewheelScale,n=e/10;0>e&&(n/=1-n),i*=1+n;var s=util.fakeGesture(this,t),o=this._getPointer(s.center);i=this._zoom(i,o)}t.preventDefault()},Graph.prototype._onMouseMoveTitle=function(t){var e=util.fakeGesture(this,t),i=this._getPointer(e.center);this.popupNode&&this._checkHidePopup(i);var n=this,s=function(){n._checkShowPopup(i)};this.popupTimer&&clearInterval(this.popupTimer),this.drag.dragging||(this.popupTimer=setTimeout(s,300))},Graph.prototype._checkShowPopup=function(t){var e,i={left:this._canvasToX(t.x),top:this._canvasToY(t.y),right:this._canvasToX(t.x),bottom:this._canvasToY(t.y)},n=this.popupNode;if(void 0==this.popupNode){var s=this.nodes;for(e in s)if(s.hasOwnProperty(e)){var o=s[e];if(void 0!==o.getTitle()&&o.isOverlappingWith(i)){this.popupNode=o;break}}}if(void 0===this.popupNode){var r=this.edges;for(e in r)if(r.hasOwnProperty(e)){var a=r[e];if(a.connected&&void 0!==a.getTitle()&&a.isOverlappingWith(i)){this.popupNode=a;break}}}if(this.popupNode){if(this.popupNode!=n){var h=this;h.popup||(h.popup=new Popup(h.frame)),h.popup.setPosition(t.x-3,t.y-3),h.popup.setText(h.popupNode.getTitle()),h.popup.show()}}else this.popup&&this.popup.hide()},Graph.prototype._checkHidePopup=function(t){this.popupNode&&this._getNodeAt(t)||(this.popupNode=void 0,this.popup&&this.popup.hide())},Graph.prototype._getConnectionCount=function(t){function e(t){for(var e=[],i=0,n=t.length;n>i;i++)for(var s=t[i],o=s.edges,r=0,a=o.length;a>r;r++){var h=o[r],l=null;h.from==s?l=h.to:h.to==s&&(l=h.from);var c,d;if(l)for(c=0,d=t.length;d>c;c++)if(t[c]==l){l=null;break}if(l)for(c=0,d=e.length;d>c;c++)if(e[c]==l){l=null;break}l&&e.push(l)}return e}void 0==t&&(t=1);var i=[],n=this.nodes;for(var s in n)if(n.hasOwnProperty(s)){for(var o=[n[s]],r=0;t>r;r++)o=o.concat(e(o));i.push(o)}for(var a=[],h=0,l=i.length;l>h;h++)a.push(i[h].length);return a},Graph.prototype.setSize=function(t,e){this.frame.style.width=t,this.frame.style.height=e,this.frame.canvas.style.width="100%",this.frame.canvas.style.height="100%",this.frame.canvas.width=this.frame.canvas.clientWidth,this.frame.canvas.height=this.frame.canvas.clientHeight,void 0!==this.manipulationDiv&&(this.manipulationDiv.style.width=this.frame.canvas.clientWidth),1==this.constants.navigation.enabled&&this._relocateNavigation()},Graph.prototype._setNodes=function(t){var e=this.nodesData;if(t instanceof DataSet||t instanceof DataView)this.nodesData=t;else if(t instanceof Array)this.nodesData=new DataSet,this.nodesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.nodesData=new DataSet}if(e&&util.forEach(this.nodesListeners,function(t,i){e.unsubscribe(i,t)}),this.nodes={},this.nodesData){var i=this;util.forEach(this.nodesListeners,function(t,e){i.nodesData.subscribe(e,t)});var n=this.nodesData.getIds();this._addNodes(n)}this._updateSelection()},Graph.prototype._addNodes=function(t){for(var e,i=0,n=t.length;n>i;i++){e=t[i];var s=this.nodesData.get(e),o=new Node(s,this.images,this.groups,this.constants);if(this.nodes[e]=o,!o.isFixed()&&1!=this.createNodeOnClick){var r=this.constants.edges.length,a=t.length,h=2*Math.PI*(i/a);o.x=r*Math.cos(h),o.y=r*Math.sin(h),this.moving=!0}}this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(this.nodes),this.updateLabels()},Graph.prototype._updateNodes=function(t){for(var e=this.nodes,i=this.nodesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o],a=i.get(o);r?r.setProperties(a,this.constants):(r=new Node(properties,this.images,this.groups,this.constants),e[o]=r,r.isFixed()||(this.moving=!0))}this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(e)},Graph.prototype._removeNodes=function(t){for(var e=this.nodes,i=0,n=t.length;n>i;i++){var s=t[i];delete e[s]}this._updateNodeIndexList(),this._reconnectEdges(),this._updateSelection(),this._updateValueRange(e)},Graph.prototype._setEdges=function(t){var e=this.edgesData;if(t instanceof DataSet||t instanceof DataView)this.edgesData=t;else if(t instanceof Array)this.edgesData=new DataSet,this.edgesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.edgesData=new DataSet}if(e&&util.forEach(this.edgesListeners,function(t,i){e.unsubscribe(i,t)}),this.edges={},this.edgesData){var i=this;util.forEach(this.edgesListeners,function(t,e){i.edgesData.subscribe(e,t)});var n=this.edgesData.getIds();this._addEdges(n)}this._reconnectEdges()},Graph.prototype._addEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o];r&&r.disconnect();var a=i.get(o,{showInternalIds:!0});e[o]=new Edge(a,this,this.constants)}this.moving=!0,this._updateValueRange(e)},Graph.prototype._updateEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=i.get(o),a=e[o];a?(a.disconnect(),a.setProperties(r,this.constants),a.connect()):(a=new Edge(r,this,this.constants),this.edges[o]=a)}this.moving=!0,this._updateValueRange(e)},Graph.prototype._removeEdges=function(t){for(var e=this.edges,i=0,n=t.length;n>i;i++){var s=t[i],o=e[s];o&&(o.disconnect(),delete e[s])}this.moving=!0,this._updateValueRange(e)},Graph.prototype._reconnectEdges=function(){var t,e=this.nodes,i=this.edges;for(t in e)e.hasOwnProperty(t)&&(e[t].edges=[]);for(t in i)if(i.hasOwnProperty(t)){var n=i[t];n.from=null,n.to=null,n.connect()}},Graph.prototype._updateValueRange=function(t){var e,i=void 0,n=void 0;for(e in t)if(t.hasOwnProperty(e)){var s=t[e].getValue();void 0!==s&&(i=void 0===i?s:Math.min(s,i),n=void 0===n?s:Math.max(s,n))}if(void 0!==i&&void 0!==n)for(e in t)t.hasOwnProperty(e)&&t[e].setValueRange(i,n)},Graph.prototype.redraw=function(){this.setSize(this.width,this.height),this._redraw()},Graph.prototype._redraw=function(){var t=this.frame.canvas.getContext("2d"),e=this.frame.canvas.width,i=this.frame.canvas.height;t.clearRect(0,0,e,i),t.save(),t.translate(this.translation.x,this.translation.y),t.scale(this.scale,this.scale),this.canvasTopLeft={x:this._canvasToX(0),y:this._canvasToY(0)},this.canvasBottomRight={x:this._canvasToX(this.frame.canvas.clientWidth),y:this._canvasToY(this.frame.canvas.clientHeight)},this._doInAllSectors("_drawAllSectorNodes",t),this._doInAllSectors("_drawEdges",t),this._doInAllSectors("_drawNodes",t,!0),t.restore(),1==this.constants.navigation.enabled&&this._doInNavigationSector("_drawNodes",t,!0)},Graph.prototype._setTranslation=function(t,e){void 0===this.translation&&(this.translation={x:0,y:0}),void 0!==t&&(this.translation.x=t),void 0!==e&&(this.translation.y=e)},Graph.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},Graph.prototype._setScale=function(t){this.scale=t},Graph.prototype._getScale=function(){return this.scale},Graph.prototype._canvasToX=function(t){return(t-this.translation.x)/this.scale},Graph.prototype._xToCanvas=function(t){return t*this.scale+this.translation.x},Graph.prototype._canvasToY=function(t){return(t-this.translation.y)/this.scale},Graph.prototype._yToCanvas=function(t){return t*this.scale+this.translation.y},Graph.prototype._drawNodes=function(t,e){void 0===e&&(e=!1);var i=this.nodes,n=[];for(var s in i)i.hasOwnProperty(s)&&(i[s].setScaleAndPos(this.scale,this.canvasTopLeft,this.canvasBottomRight),i[s].isSelected()?n.push(s):(i[s].inArea()||e)&&i[s].draw(t));for(var o=0,r=n.length;r>o;o++)(i[n[o]].inArea()||e)&&i[n[o]].draw(t)},Graph.prototype._drawEdges=function(t){var e=this.edges;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];n.setScale(this.scale),n.connected&&e[i].draw(t)}},Graph.prototype._doStabilize=function(){for(var t=0,e=this.constants.minVelocity,i=!1;!i&&t0)for(var i in e)e.hasOwnProperty(i)&&e[i].discreteStepLimited(t,this.constants.maxVelocity);else for(var i in e)e.hasOwnProperty(i)&&e[i].discreteStep(t);var n=this.constants.minVelocity;this.moving=this._isMoving(n)},Graph.prototype.start=function(){if(!this.freezeSimulation)if(this.moving&&(this._doInAllActiveSectors("_initializeForceCalculation"),this._doInAllActiveSectors("_discreteStepNodes"),this._findCenter(this._getRange())),this.moving||0!=this.xIncrement||0!=this.yIncrement||0!=this.zoomIncrement){if(!this.timer){var t=this;this.timer=window.setTimeout(function(){if(t.timer=void 0,0!=t.xIncrement||0!=t.yIncrement){var e=t._getTranslation();t._setTranslation(e.x+t.xIncrement,e.y+t.yIncrement)}if(0!=t.zoomIncrement){var i={x:t.frame.canvas.clientWidth/2,y:t.frame.canvas.clientHeight/2};t._zoom(t.scale*(1+t.zoomIncrement),i)}t.start(),t.start(),t._redraw()},this.renderTimestep)}}else this._redraw()},Graph.prototype.singleStep=function(){if(this.moving){this._initializeForceCalculation(),this._discreteStepNodes();var t=this.constants.minVelocity;this.moving=this._isMoving(t),this._redraw()}},Graph.prototype.toggleFreeze=function(){0==this.freezeSimulation?this.freezeSimulation=!0:(this.freezeSimulation=!1,this.start())},Graph.prototype._loadPhysicsSystem=function(){for(var t in physicsMixin)physicsMixin.hasOwnProperty(t)&&(Graph.prototype[t]=physicsMixin[t])},Graph.prototype._loadClusterSystem=function(){this.clusterSession=0,this.hubThreshold=5;for(var t in ClusterMixin)ClusterMixin.hasOwnProperty(t)&&(Graph.prototype[t]=ClusterMixin[t])},Graph.prototype._loadSectorSystem=function(){this.sectors={},this.activeSector=["default"],this.sectors.active={},this.sectors.active["default"]={nodes:{},edges:{},nodeIndices:[],formationScale:1,drawingNode:void 0},this.sectors.frozen={},this.sectors.navigation={nodes:{},edges:{},nodeIndices:[],formationScale:1,drawingNode:void 0},this.nodeIndices=this.sectors.active["default"].nodeIndices;for(var t in SectorMixin)SectorMixin.hasOwnProperty(t)&&(Graph.prototype[t]=SectorMixin[t])},Graph.prototype._loadSelectionSystem=function(){this.selectionObj={};for(var t in SelectionMixin)SelectionMixin.hasOwnProperty(t)&&(Graph.prototype[t]=SelectionMixin[t])},Graph.prototype._loadManipulationSystem=function(){if(this.blockConnectingEdgeSelection=!1,this.forceAppendSelection=!1,1==this.constants.dataManipulationToolbar.enabled){void 0===this.manipulationDiv&&(this.manipulationDiv=document.createElement("div"),this.manipulationDiv.className="graph-manipulationDiv",this.containerElement.insertBefore(this.manipulationDiv,this.frame));for(var t in manipulationMixin)manipulationMixin.hasOwnProperty(t)&&(Graph.prototype[t]=manipulationMixin[t]);this._createManipulatorBar()}},Graph.prototype._loadNavigationControls=function(){for(var t in NavigationMixin)NavigationMixin.hasOwnProperty(t)&&(Graph.prototype[t]=NavigationMixin[t]);1==this.constants.navigation.enabled&&this._loadNavigationElements()},Graph.prototype._relocateNavigation=function(){},Graph.prototype._unHighlightAll=function(){};var vis={util:util,events:events,Controller:Controller,DataSet:DataSet,DataView:DataView,Range:Range,Stack:Stack,TimeStep:TimeStep,EventBus:EventBus,components:{items:{Item:Item,ItemBox:ItemBox,ItemPoint:ItemPoint,ItemRange:ItemRange},Component:Component,Panel:Panel,RootPanel:RootPanel,ItemSet:ItemSet,TimeAxis:TimeAxis},graph:{Node:Node,Edge:Edge,Popup:Popup,Groups:Groups,Images:Images},Timeline:Timeline,Graph:Graph};"undefined"!=typeof exports&&(exports=vis),"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=vis),"function"==typeof define&&define(function(){return vis}),"undefined"!=typeof window&&(window.vis=vis)},{hammerjs:2,moment:3,mousetrap:4}],2:[function(t,e){!function(t,i){"use strict";function n(){if(!s.READY){s.event.determineEventTypes();for(var t in s.gestures)s.gestures.hasOwnProperty(t)&&s.detection.register(s.gestures[t]);s.event.onTouch(s.DOCUMENT,s.EVENT_MOVE,s.detection.detect),s.event.onTouch(s.DOCUMENT,s.EVENT_END,s.detection.detect),s.READY=!0}}var s=function(t,e){return new s.Instance(t,e||{})};s.defaults={stop_browser_behavior:{userSelect:"none",touchAction:"none",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}},s.HAS_POINTEREVENTS=navigator.pointerEnabled||navigator.msPointerEnabled,s.HAS_TOUCHEVENTS="ontouchstart"in t,s.MOBILE_REGEX=/mobile|tablet|ip(ad|hone|od)|android/i,s.NO_MOUSEEVENTS=s.HAS_TOUCHEVENTS&&navigator.userAgent.match(s.MOBILE_REGEX),s.EVENT_TYPES={},s.DIRECTION_DOWN="down",s.DIRECTION_LEFT="left",s.DIRECTION_UP="up",s.DIRECTION_RIGHT="right",s.POINTER_MOUSE="mouse",s.POINTER_TOUCH="touch",s.POINTER_PEN="pen",s.EVENT_START="start",s.EVENT_MOVE="move",s.EVENT_END="end",s.DOCUMENT=document,s.plugins={},s.READY=!1,s.Instance=function(t,e){var i=this;return n(),this.element=t,this.enabled=!0,this.options=s.utils.extend(s.utils.extend({},s.defaults),e||{}),this.options.stop_browser_behavior&&s.utils.stopDefaultBrowserBehavior(this.element,this.options.stop_browser_behavior),s.event.onTouch(t,s.EVENT_START,function(t){i.enabled&&s.detection.startDetect(i,t)}),this},s.Instance.prototype={on:function(t,e){for(var i=t.split(" "),n=0;n0&&e==s.EVENT_END?e=s.EVENT_MOVE:c||(e=s.EVENT_END),c||null===o?o=h:h=o,i.call(s.detection,n.collectEventData(t,e,h)),s.HAS_POINTEREVENTS&&e==s.EVENT_END&&(c=s.PointerEvent.updatePointer(e,h))),c||(o=null,r=!1,a=!1,s.PointerEvent.reset())}})},determineEventTypes:function(){var t;t=s.HAS_POINTEREVENTS?s.PointerEvent.getEvents():s.NO_MOUSEEVENTS?["touchstart","touchmove","touchend touchcancel"]:["touchstart mousedown","touchmove mousemove","touchend touchcancel mouseup"],s.EVENT_TYPES[s.EVENT_START]=t[0],s.EVENT_TYPES[s.EVENT_MOVE]=t[1],s.EVENT_TYPES[s.EVENT_END]=t[2]},getTouchList:function(t){return s.HAS_POINTEREVENTS?s.PointerEvent.getTouchList():t.touches?t.touches:[{identifier:1,pageX:t.pageX,pageY:t.pageY,target:t.target}]},collectEventData:function(t,e,i){var n=this.getTouchList(i,e),o=s.POINTER_TOUCH;return(i.type.match(/mouse/)||s.PointerEvent.matchType(s.POINTER_MOUSE,i))&&(o=s.POINTER_MOUSE),{center:s.utils.getCenter(n),timeStamp:(new Date).getTime(),target:i.target,touches:n,eventType:e,pointerType:o,srcEvent:i,preventDefault:function(){this.srcEvent.preventManipulation&&this.srcEvent.preventManipulation(),this.srcEvent.preventDefault&&this.srcEvent.preventDefault()},stopPropagation:function(){this.srcEvent.stopPropagation()},stopDetect:function(){return s.detection.stopDetect()}}}},s.PointerEvent={pointers:{},getTouchList:function(){var t=this,e=[];return Object.keys(t.pointers).sort().forEach(function(i){e.push(t.pointers[i])}),e},updatePointer:function(t,e){return t==s.EVENT_END?this.pointers={}:(e.identifier=e.pointerId,this.pointers[e.pointerId]=e),Object.keys(this.pointers).length},matchType:function(t,e){if(!e.pointerType)return!1;var i={};return i[s.POINTER_MOUSE]=e.pointerType==e.MSPOINTER_TYPE_MOUSE||e.pointerType==s.POINTER_MOUSE,i[s.POINTER_TOUCH]=e.pointerType==e.MSPOINTER_TYPE_TOUCH||e.pointerType==s.POINTER_TOUCH,i[s.POINTER_PEN]=e.pointerType==e.MSPOINTER_TYPE_PEN||e.pointerType==s.POINTER_PEN,i[t]},getEvents:function(){return["pointerdown MSPointerDown","pointermove MSPointerMove","pointerup pointercancel MSPointerUp MSPointerCancel"]},reset:function(){this.pointers={}}},s.utils={extend:function(t,e,n){for(var s in e)t[s]!==i&&n||(t[s]=e[s]);return t},hasParent:function(t,e){for(;t;){if(t==e)return!0;t=t.parentNode}return!1},getCenter:function(t){for(var e=[],i=[],n=0,s=t.length;s>n;n++)e.push(t[n].pageX),i.push(t[n].pageY);return{pageX:(Math.min.apply(Math,e)+Math.max.apply(Math,e))/2,pageY:(Math.min.apply(Math,i)+Math.max.apply(Math,i))/2}},getVelocity:function(t,e,i){return{x:Math.abs(e/t)||0,y:Math.abs(i/t)||0}},getAngle:function(t,e){var i=e.pageY-t.pageY,n=e.pageX-t.pageX;return 180*Math.atan2(i,n)/Math.PI},getDirection:function(t,e){var i=Math.abs(t.pageX-e.pageX),n=Math.abs(t.pageY-e.pageY);return i>=n?t.pageX-e.pageX>0?s.DIRECTION_LEFT:s.DIRECTION_RIGHT:t.pageY-e.pageY>0?s.DIRECTION_UP:s.DIRECTION_DOWN},getDistance:function(t,e){var i=e.pageX-t.pageX,n=e.pageY-t.pageY;return Math.sqrt(i*i+n*n)},getScale:function(t,e){return t.length>=2&&e.length>=2?this.getDistance(e[0],e[1])/this.getDistance(t[0],t[1]):1},getRotation:function(t,e){return t.length>=2&&e.length>=2?this.getAngle(e[1],e[0])-this.getAngle(t[1],t[0]):0},isVertical:function(t){return t==s.DIRECTION_UP||t==s.DIRECTION_DOWN},stopDefaultBrowserBehavior:function(t,e){var i,n=["webkit","khtml","moz","ms","o",""];if(e&&t.style){for(var s=0;si;i++){var o=this.gestures[i];if(!this.stopped&&e[o.name]!==!1&&o.handler.call(o,t,this.current.inst)===!1){this.stopDetect();break}}return this.current&&(this.current.lastEvent=t),t.eventType==s.EVENT_END&&!t.touches.length-1&&this.stopDetect(),t}},stopDetect:function(){this.previous=s.utils.extend({},this.current),this.current=null,this.stopped=!0},extendEventData:function(t){var e=this.current.startEvent;if(e&&(t.touches.length!=e.touches.length||t.touches===e.touches)){e.touches=[];for(var i=0,n=t.touches.length;n>i;i++)e.touches.push(s.utils.extend({},t.touches[i]))}var o=t.timeStamp-e.timeStamp,r=t.center.pageX-e.center.pageX,a=t.center.pageY-e.center.pageY,h=s.utils.getVelocity(o,r,a);return s.utils.extend(t,{deltaTime:o,deltaX:r,deltaY:a,velocityX:h.x,velocityY:h.y,distance:s.utils.getDistance(e.center,t.center),angle:s.utils.getAngle(e.center,t.center),direction:s.utils.getDirection(e.center,t.center),scale:s.utils.getScale(e.touches,t.touches),rotation:s.utils.getRotation(e.touches,t.touches),startEvent:e}),t},register:function(t){var e=t.defaults||{};return e[t.name]===i&&(e[t.name]=!0),s.utils.extend(s.defaults,e,!0),t.index=t.index||1e3,this.gestures.push(t),this.gestures.sort(function(t,e){return t.indexe.index?1:0}),this.gestures}},s.gestures=s.gestures||{},s.gestures.Hold={name:"hold",index:10,defaults:{hold_timeout:500,hold_threshold:1},timer:null,handler:function(t,e){switch(t.eventType){case s.EVENT_START:clearTimeout(this.timer),s.detection.current.name=this.name,this.timer=setTimeout(function(){"hold"==s.detection.current.name&&e.trigger("hold",t)},e.options.hold_timeout);break;case s.EVENT_MOVE:t.distance>e.options.hold_threshold&&clearTimeout(this.timer);break;case s.EVENT_END:clearTimeout(this.timer)}}},s.gestures.Tap={name:"tap",index:100,defaults:{tap_max_touchtime:250,tap_max_distance:10,tap_always:!0,doubletap_distance:20,doubletap_interval:300},handler:function(t,e){if(t.eventType==s.EVENT_END){var i=s.detection.previous,n=!1;if(t.deltaTime>e.options.tap_max_touchtime||t.distance>e.options.tap_max_distance)return;i&&"tap"==i.name&&t.timeStamp-i.lastEvent.timeStamp0&&t.touches.length>e.options.swipe_max_touches)return;(t.velocityX>e.options.swipe_velocity||t.velocityY>e.options.swipe_velocity)&&(e.trigger(this.name,t),e.trigger(this.name+t.direction,t))}}},s.gestures.Drag={name:"drag",index:50,defaults:{drag_min_distance:10,drag_max_touches:1,drag_block_horizontal:!1,drag_block_vertical:!1,drag_lock_to_axis:!1,drag_lock_min_distance:25},triggered:!1,handler:function(t,e){if(s.detection.current.name!=this.name&&this.triggered)return e.trigger(this.name+"end",t),void(this.triggered=!1); +if(!(e.options.drag_max_touches>0&&t.touches.length>e.options.drag_max_touches))switch(t.eventType){case s.EVENT_START:this.triggered=!1;break;case s.EVENT_MOVE:if(t.distancee.options.transform_min_rotation&&e.trigger("rotate",t),i>e.options.transform_min_scale&&(e.trigger("pinch",t),e.trigger("pinch"+(t.scale<1?"in":"out"),t));break;case s.EVENT_END:this.triggered&&e.trigger(this.name+"end",t),this.triggered=!1}}},s.gestures.Touch={name:"touch",index:-1/0,defaults:{prevent_default:!1,prevent_mouseevents:!1},handler:function(t,e){return e.options.prevent_mouseevents&&t.pointerType==s.POINTER_MOUSE?void t.stopDetect():(e.options.prevent_default&&t.preventDefault(),void(t.eventType==s.EVENT_START&&e.trigger(this.name,t)))}},s.gestures.Release={name:"release",index:1/0,handler:function(t,e){t.eventType==s.EVENT_END&&e.trigger(this.name,t)}},"object"==typeof e&&"object"==typeof e.exports?e.exports=s:(t.Hammer=s,"function"==typeof t.define&&t.define.amd&&t.define("hammer",[],function(){return s}))}(this)},{}],3:[function(t,e){(function(i){function n(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function s(t,e){return function(i){return u(t.call(this,i),e)}}function o(t,e){return function(i){return this.lang().ordinal(t.call(this,i),e)}}function r(){}function a(t){E(t),l(this,t)}function h(t){var e=y(t),i=e.year||0,n=e.month||0,s=e.week||0,o=e.day||0,r=e.hour||0,a=e.minute||0,h=e.second||0,l=e.millisecond||0;this._milliseconds=+l+1e3*h+6e4*a+36e5*r,this._days=+o+7*s,this._months=+n+12*i,this._data={},this._bubble()}function l(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return e.hasOwnProperty("toString")&&(t.toString=e.toString),e.hasOwnProperty("valueOf")&&(t.valueOf=e.valueOf),t}function c(t){var e,i={};for(e in t)t.hasOwnProperty(e)&&ye.hasOwnProperty(e)&&(i[e]=t[e]);return i}function d(t){return 0>t?Math.ceil(t):Math.floor(t)}function u(t,e,i){for(var n=""+Math.abs(t),s=t>=0;n.lengthn;n++)(i&&t[n]!==e[n]||!i&&b(t[n])!==b(e[n]))&&r++;return r+o}function v(t){if(t){var e=t.toLowerCase().replace(/(.)s$/,"$1");t=Xe[t]||qe[e]||e}return t}function y(t){var e,i,n={};for(i in t)t.hasOwnProperty(i)&&(e=v(i),e&&(n[e]=t[i]));return n}function _(t){var e,n;if(0===t.indexOf("week"))e=7,n="day";else{if(0!==t.indexOf("month"))return;e=12,n="month"}oe[t]=function(s,o){var r,a,h=oe.fn._lang[t],l=[];if("number"==typeof s&&(o=s,s=i),a=function(t){var e=oe().utc().set(n,t);return h.call(oe.fn._lang,e,s||"")},null!=o)return a(o);for(r=0;e>r;r++)l.push(a(r));return l}}function b(t){var e=+t,i=0;return 0!==e&&isFinite(e)&&(i=e>=0?Math.floor(e):Math.ceil(e)),i}function w(t,e){return new Date(Date.UTC(t,e+1,0)).getUTCDate()}function S(t){return T(t)?366:365}function T(t){return t%4===0&&t%100!==0||t%400===0}function E(t){var e;t._a&&-2===t._pf.overflow&&(e=t._a[de]<0||t._a[de]>11?de:t._a[ue]<1||t._a[ue]>w(t._a[ce],t._a[de])?ue:t._a[pe]<0||t._a[pe]>23?pe:t._a[fe]<0||t._a[fe]>59?fe:t._a[ge]<0||t._a[ge]>59?ge:t._a[me]<0||t._a[me]>999?me:-1,t._pf._overflowDayOfYear&&(ce>e||e>ue)&&(e=ue),t._pf.overflow=e)}function x(t){return null==t._isValid&&(t._isValid=!isNaN(t._d.getTime())&&t._pf.overflow<0&&!t._pf.empty&&!t._pf.invalidMonth&&!t._pf.nullInput&&!t._pf.invalidFormat&&!t._pf.userInvalidated,t._strict&&(t._isValid=t._isValid&&0===t._pf.charsLeftOver&&0===t._pf.unusedTokens.length)),t._isValid}function C(t){return t?t.toLowerCase().replace("_","-"):t}function M(t,e){return e._isUTC?oe(t).zone(e._offset||0):oe(t).local()}function D(t,e){return e.abbr=t,ve[t]||(ve[t]=new r),ve[t].set(e),ve[t]}function I(t){delete ve[t]}function N(e){var i,n,s,o,r=0,a=function(e){if(!ve[e]&&_e)try{t("./lang/"+e)}catch(i){}return ve[e]};if(!e)return oe.fn._lang;if(!f(e)){if(n=a(e))return n;e=[e]}for(;r0;){if(n=a(o.slice(0,i).join("-")))return n;if(s&&s.length>=i&&m(o,s,!0)>=i-1)break;i--}r++}return oe.fn._lang}function O(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function L(t){var e,i,n=t.match(Te);for(e=0,i=n.length;i>e;e++)n[e]=Qe[n[e]]?Qe[n[e]]:O(n[e]);return function(s){var o="";for(e=0;i>e;e++)o+=n[e]instanceof Function?n[e].call(s,t):n[e];return o}}function k(t,e){return t.isValid()?(e=A(e,t.lang()),Ze[e]||(Ze[e]=L(e)),Ze[e](t)):t.lang().invalidDate()}function A(t,e){function i(t){return e.longDateFormat(t)||t}var n=5;for(Ee.lastIndex=0;n>=0&&Ee.test(t);)t=t.replace(Ee,i),Ee.lastIndex=0,n-=1;return t}function P(t,e){var i,n=e._strict;switch(t){case"DDDD":return ze;case"YYYY":case"GGGG":case"gggg":return n?Fe:Me;case"Y":case"G":case"g":return Ye;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return n?Re:De;case"S":if(n)return Ae;case"SS":if(n)return Pe;case"SSS":if(n)return ze;case"DDD":return Ce;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Ne;case"a":case"A":return N(e._l)._meridiemParse;case"X":return ke;case"Z":case"ZZ":return Oe;case"T":return Le;case"SSSS":return Ie;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return n?Pe:xe;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return xe;default:return i=new RegExp(G(j(t.replace("\\","")),"i"))}}function z(t){t=t||"";var e=t.match(Oe)||[],i=e[e.length-1]||[],n=(i+"").match(Ue)||["-",0,0],s=+(60*n[1])+b(n[2]);return"+"===n[0]?-s:s}function F(t,e,i){var n,s=i._a;switch(t){case"M":case"MM":null!=e&&(s[de]=b(e)-1);break;case"MMM":case"MMMM":n=N(i._l).monthsParse(e),null!=n?s[de]=n:i._pf.invalidMonth=e;break;case"D":case"DD":null!=e&&(s[ue]=b(e));break;case"DDD":case"DDDD":null!=e&&(i._dayOfYear=b(e));break;case"YY":s[ce]=b(e)+(b(e)>68?1900:2e3);break;case"YYYY":case"YYYYY":case"YYYYYY":s[ce]=b(e);break;case"a":case"A":i._isPm=N(i._l).isPM(e);break;case"H":case"HH":case"h":case"hh":s[pe]=b(e);break;case"m":case"mm":s[fe]=b(e);break;case"s":case"ss":s[ge]=b(e);break;case"S":case"SS":case"SSS":case"SSSS":s[me]=b(1e3*("0."+e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,i._tzm=z(e);break;case"w":case"ww":case"W":case"WW":case"d":case"dd":case"ddd":case"dddd":case"e":case"E":t=t.substr(0,1);case"gg":case"gggg":case"GG":case"GGGG":case"GGGGG":t=t.substr(0,2),e&&(i._w=i._w||{},i._w[t]=e)}}function R(t){var e,i,n,s,o,r,a,h,l,c,d=[];if(!t._d){for(n=H(t),t._w&&null==t._a[ue]&&null==t._a[de]&&(o=function(e){var i=parseInt(e,10);return e?e.length<3?i>68?1900+i:2e3+i:i:null==t._a[ce]?oe().weekYear():t._a[ce]},r=t._w,null!=r.GG||null!=r.W||null!=r.E?a=J(o(r.GG),r.W||1,r.E,4,1):(h=N(t._l),l=null!=r.d?Z(r.d,h):null!=r.e?parseInt(r.e,10)+h._week.dow:0,c=parseInt(r.w,10)||1,null!=r.d&&lS(s)&&(t._pf._overflowDayOfYear=!0),i=q(s,0,t._dayOfYear),t._a[de]=i.getUTCMonth(),t._a[ue]=i.getUTCDate()),e=0;3>e&&null==t._a[e];++e)t._a[e]=d[e]=n[e];for(;7>e;e++)t._a[e]=d[e]=null==t._a[e]?2===e?1:0:t._a[e];d[pe]+=b((t._tzm||0)/60),d[fe]+=b((t._tzm||0)%60),t._d=(t._useUTC?q:X).apply(null,d)}}function Y(t){var e;t._d||(e=y(t._i),t._a=[e.year,e.month,e.day,e.hour,e.minute,e.second,e.millisecond],R(t))}function H(t){var e=new Date;return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function W(t){t._a=[],t._pf.empty=!0;var e,i,n,s,o,r=N(t._l),a=""+t._i,h=a.length,l=0;for(n=A(t._f,r).match(Te)||[],e=0;e0&&t._pf.unusedInput.push(o),a=a.slice(a.indexOf(i)+i.length),l+=i.length),Qe[s]?(i?t._pf.empty=!1:t._pf.unusedTokens.push(s),F(s,i,t)):t._strict&&!i&&t._pf.unusedTokens.push(s);t._pf.charsLeftOver=h-l,a.length>0&&t._pf.unusedInput.push(a),t._isPm&&t._a[pe]<12&&(t._a[pe]+=12),t._isPm===!1&&12===t._a[pe]&&(t._a[pe]=0),R(t),E(t)}function j(t){return t.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,i,n,s){return e||i||n||s})}function G(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function U(t){var e,i,s,o,r;if(0===t._f.length)return t._pf.invalidFormat=!0,void(t._d=new Date(0/0));for(o=0;or)&&(s=r,i=e));l(t,i||e)}function B(t){var e,i,n=t._i,s=He.exec(n);if(s){for(t._pf.iso=!0,e=0,i=je.length;i>e;e++)if(je[e][1].exec(n)){t._f=je[e][0]+(s[6]||" ");break}for(e=0,i=Ge.length;i>e;e++)if(Ge[e][1].exec(n)){t._f+=Ge[e][0];break}n.match(Oe)&&(t._f+="Z"),W(t)}else t._d=new Date(n)}function V(t){var e=t._i,n=be.exec(e);e===i?t._d=new Date:n?t._d=new Date(+n[1]):"string"==typeof e?B(t):f(e)?(t._a=e.slice(0),R(t)):g(e)?t._d=new Date(+e):"object"==typeof e?Y(t):t._d=new Date(e)}function X(t,e,i,n,s,o,r){var a=new Date(t,e,i,n,s,o,r);return 1970>t&&a.setFullYear(t),a}function q(t){var e=new Date(Date.UTC.apply(null,arguments));return 1970>t&&e.setUTCFullYear(t),e}function Z(t,e){if("string"==typeof t)if(isNaN(t)){if(t=e.weekdaysParse(t),"number"!=typeof t)return null}else t=parseInt(t,10);return t}function K(t,e,i,n,s){return s.relativeTime(e||1,!!i,t,n)}function $(t,e,i){var n=le(Math.abs(t)/1e3),s=le(n/60),o=le(s/60),r=le(o/24),a=le(r/365),h=45>n&&["s",n]||1===s&&["m"]||45>s&&["mm",s]||1===o&&["h"]||22>o&&["hh",o]||1===r&&["d"]||25>=r&&["dd",r]||45>=r&&["M"]||345>r&&["MM",le(r/30)]||1===a&&["y"]||["yy",a];return h[2]=e,h[3]=t>0,h[4]=i,K.apply({},h)}function Q(t,e,i){var n,s=i-e,o=i-t.day();return o>s&&(o-=7),s-7>o&&(o+=7),n=oe(t).add("d",o),{week:Math.ceil(n.dayOfYear()/7),year:n.year()}}function J(t,e,i,n,s){var o,r,a=q(t,0,1).getUTCDay();return i=null!=i?i:s,o=s-a+(a>n?7:0)-(s>a?7:0),r=7*(e-1)+(i-s)+o+1,{year:r>0?t:t-1,dayOfYear:r>0?r:S(t-1)+r}}function te(t){var e=t._i,i=t._f;return null===e?oe.invalid({nullInput:!0}):("string"==typeof e&&(t._i=e=N().preparse(e)),oe.isMoment(e)?(t=c(e),t._d=new Date(+e._d)):i?f(i)?U(t):W(t):V(t),new a(t))}function ee(t,e){oe.fn[t]=oe.fn[t+"s"]=function(t){var i=this._isUTC?"UTC":"";return null!=t?(this._d["set"+i+e](t),oe.updateOffset(this),this):this._d["get"+i+e]()}}function ie(t){oe.duration.fn[t]=function(){return this._data[t]}}function ne(t,e){oe.duration.fn["as"+t]=function(){return+this/e}}function se(t){var e=!1,i=oe;"undefined"==typeof ender&&(t?(he.moment=function(){return!e&&console&&console.warn&&(e=!0,console.warn("Accessing Moment through the global scope is deprecated, and will be removed in an upcoming release.")),i.apply(null,arguments)},l(he.moment,i)):he.moment=oe)}for(var oe,re,ae="2.5.1",he=this,le=Math.round,ce=0,de=1,ue=2,pe=3,fe=4,ge=5,me=6,ve={},ye={_isAMomentObject:null,_i:null,_f:null,_l:null,_strict:null,_isUTC:null,_offset:null,_pf:null,_lang:null},_e="undefined"!=typeof e&&e.exports&&"undefined"!=typeof t,be=/^\/?Date\((\-?\d+)/i,we=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,Se=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,Te=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g,Ee=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,xe=/\d\d?/,Ce=/\d{1,3}/,Me=/\d{1,4}/,De=/[+\-]?\d{1,6}/,Ie=/\d+/,Ne=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Oe=/Z|[\+\-]\d\d:?\d\d/gi,Le=/T/i,ke=/[\+\-]?\d+(\.\d{1,3})?/,Ae=/\d/,Pe=/\d\d/,ze=/\d{3}/,Fe=/\d{4}/,Re=/[+-]?\d{6}/,Ye=/[+-]?\d+/,He=/^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,We="YYYY-MM-DDTHH:mm:ssZ",je=[["YYYYYY-MM-DD",/[+-]\d{6}-\d{2}-\d{2}/],["YYYY-MM-DD",/\d{4}-\d{2}-\d{2}/],["GGGG-[W]WW-E",/\d{4}-W\d{2}-\d/],["GGGG-[W]WW",/\d{4}-W\d{2}/],["YYYY-DDD",/\d{4}-\d{3}/]],Ge=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d{1,3}/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],Ue=/([\+\-]|\d\d)/gi,Be="Date|Hours|Minutes|Seconds|Milliseconds".split("|"),Ve={Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6},Xe={ms:"millisecond",s:"second",m:"minute",h:"hour",d:"day",D:"date",w:"week",W:"isoWeek",M:"month",y:"year",DDD:"dayOfYear",e:"weekday",E:"isoWeekday",gg:"weekYear",GG:"isoWeekYear"},qe={dayofyear:"dayOfYear",isoweekday:"isoWeekday",isoweek:"isoWeek",weekyear:"weekYear",isoweekyear:"isoWeekYear"},Ze={},Ke="DDD w W M D d".split(" "),$e="M D H h m s w W".split(" "),Qe={M:function(){return this.month()+1},MMM:function(t){return this.lang().monthsShort(this,t)},MMMM:function(t){return this.lang().months(this,t)},D:function(){return this.date()},DDD:function(){return this.dayOfYear()},d:function(){return this.day()},dd:function(t){return this.lang().weekdaysMin(this,t)},ddd:function(t){return this.lang().weekdaysShort(this,t)},dddd:function(t){return this.lang().weekdays(this,t)},w:function(){return this.week()},W:function(){return this.isoWeek()},YY:function(){return u(this.year()%100,2)},YYYY:function(){return u(this.year(),4)},YYYYY:function(){return u(this.year(),5)},YYYYYY:function(){var t=this.year(),e=t>=0?"+":"-";return e+u(Math.abs(t),6)},gg:function(){return u(this.weekYear()%100,2)},gggg:function(){return u(this.weekYear(),4)},ggggg:function(){return u(this.weekYear(),5)},GG:function(){return u(this.isoWeekYear()%100,2)},GGGG:function(){return u(this.isoWeekYear(),4)},GGGGG:function(){return u(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.lang().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.lang().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return b(this.milliseconds()/100)},SS:function(){return u(b(this.milliseconds()/10),2)},SSS:function(){return u(this.milliseconds(),3)},SSSS:function(){return u(this.milliseconds(),3)},Z:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+u(b(t/60),2)+":"+u(b(t)%60,2)},ZZ:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+u(b(t/60),2)+u(b(t)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},X:function(){return this.unix()},Q:function(){return this.quarter()}},Je=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"];Ke.length;)re=Ke.pop(),Qe[re+"o"]=o(Qe[re],re);for(;$e.length;)re=$e.pop(),Qe[re+re]=s(Qe[re],2);for(Qe.DDDD=s(Qe.DDD,3),l(r.prototype,{set:function(t){var e,i;for(i in t)e=t[i],"function"==typeof e?this[i]=e:this["_"+i]=e},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(t){return this._months[t.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(t){return this._monthsShort[t.month()]},monthsParse:function(t){var e,i,n;for(this._monthsParse||(this._monthsParse=[]),e=0;12>e;e++)if(this._monthsParse[e]||(i=oe.utc([2e3,e]),n="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[e]=new RegExp(n.replace(".",""),"i")),this._monthsParse[e].test(t))return e},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(t){return this._weekdays[t.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(t){return this._weekdaysShort[t.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(t){return this._weekdaysMin[t.day()]},weekdaysParse:function(t){var e,i,n;for(this._weekdaysParse||(this._weekdaysParse=[]),e=0;7>e;e++)if(this._weekdaysParse[e]||(i=oe([2e3,1]).day(e),n="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[e]=new RegExp(n.replace(".",""),"i")),this._weekdaysParse[e].test(t))return e},_longDateFormat:{LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D YYYY",LLL:"MMMM D YYYY LT",LLLL:"dddd, MMMM D YYYY LT"},longDateFormat:function(t){var e=this._longDateFormat[t];return!e&&this._longDateFormat[t.toUpperCase()]&&(e=this._longDateFormat[t.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t]=e),e},isPM:function(t){return"p"===(t+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(t,e,i){return t>11?i?"pm":"PM":i?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(t,e){var i=this._calendar[t];return"function"==typeof i?i.apply(e):i},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(t,e,i,n){var s=this._relativeTime[i];return"function"==typeof s?s(t,e,i,n):s.replace(/%d/i,t)},pastFuture:function(t,e){var i=this._relativeTime[t>0?"future":"past"];return"function"==typeof i?i(e):i.replace(/%s/i,e)},ordinal:function(t){return this._ordinal.replace("%d",t)},_ordinal:"%d",preparse:function(t){return t},postformat:function(t){return t},week:function(t){return Q(t,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),oe=function(t,e,s,o){var r;return"boolean"==typeof s&&(o=s,s=i),r={},r._isAMomentObject=!0,r._i=t,r._f=e,r._l=s,r._strict=o,r._isUTC=!1,r._pf=n(),te(r)},oe.utc=function(t,e,s,o){var r;return"boolean"==typeof s&&(o=s,s=i),r={},r._isAMomentObject=!0,r._useUTC=!0,r._isUTC=!0,r._l=s,r._i=t,r._f=e,r._strict=o,r._pf=n(),te(r).utc()},oe.unix=function(t){return oe(1e3*t)},oe.duration=function(t,e){var i,n,s,o=t,r=null;return oe.isDuration(t)?o={ms:t._milliseconds,d:t._days,M:t._months}:"number"==typeof t?(o={},e?o[e]=t:o.milliseconds=t):(r=we.exec(t))?(i="-"===r[1]?-1:1,o={y:0,d:b(r[ue])*i,h:b(r[pe])*i,m:b(r[fe])*i,s:b(r[ge])*i,ms:b(r[me])*i}):(r=Se.exec(t))&&(i="-"===r[1]?-1:1,s=function(t){var e=t&&parseFloat(t.replace(",","."));return(isNaN(e)?0:e)*i},o={y:s(r[2]),M:s(r[3]),d:s(r[4]),h:s(r[5]),m:s(r[6]),s:s(r[7]),w:s(r[8])}),n=new h(o),oe.isDuration(t)&&t.hasOwnProperty("_lang")&&(n._lang=t._lang),n},oe.version=ae,oe.defaultFormat=We,oe.updateOffset=function(){},oe.lang=function(t,e){var i;return t?(e?D(C(t),e):null===e?(I(t),t="en"):ve[t]||N(t),i=oe.duration.fn._lang=oe.fn._lang=N(t),i._abbr):oe.fn._lang._abbr},oe.langData=function(t){return t&&t._lang&&t._lang._abbr&&(t=t._lang._abbr),N(t)},oe.isMoment=function(t){return t instanceof a||null!=t&&t.hasOwnProperty("_isAMomentObject")},oe.isDuration=function(t){return t instanceof h},re=Je.length-1;re>=0;--re)_(Je[re]);for(oe.normalizeUnits=function(t){return v(t)},oe.invalid=function(t){var e=oe.utc(0/0);return null!=t?l(e._pf,t):e._pf.userInvalidated=!0,e},oe.parseZone=function(t){return oe(t).parseZone()},l(oe.fn=a.prototype,{clone:function(){return oe(this)},valueOf:function(){return+this._d+6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().lang("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){var t=oe(this).utc();return 00:!1},parsingFlags:function(){return l({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(){return this.zone(0)},local:function(){return this.zone(0),this._isUTC=!1,this},format:function(t){var e=k(this,t||oe.defaultFormat);return this.lang().postformat(e)},add:function(t,e){var i;return i="string"==typeof t?oe.duration(+e,t):oe.duration(t,e),p(this,i,1),this},subtract:function(t,e){var i;return i="string"==typeof t?oe.duration(+e,t):oe.duration(t,e),p(this,i,-1),this},diff:function(t,e,i){var n,s,o=M(t,this),r=6e4*(this.zone()-o.zone());return e=v(e),"year"===e||"month"===e?(n=432e5*(this.daysInMonth()+o.daysInMonth()),s=12*(this.year()-o.year())+(this.month()-o.month()),s+=(this-oe(this).startOf("month")-(o-oe(o).startOf("month")))/n,s-=6e4*(this.zone()-oe(this).startOf("month").zone()-(o.zone()-oe(o).startOf("month").zone()))/n,"year"===e&&(s/=12)):(n=this-o,s="second"===e?n/1e3:"minute"===e?n/6e4:"hour"===e?n/36e5:"day"===e?(n-r)/864e5:"week"===e?(n-r)/6048e5:n),i?s:d(s)},from:function(t,e){return oe.duration(this.diff(t)).lang(this.lang()._abbr).humanize(!e)},fromNow:function(t){return this.from(oe(),t)},calendar:function(){var t=M(oe(),this).startOf("day"),e=this.diff(t,"days",!0),i=-6>e?"sameElse":-1>e?"lastWeek":0>e?"lastDay":1>e?"sameDay":2>e?"nextDay":7>e?"nextWeek":"sameElse";return this.format(this.lang().calendar(i,this))},isLeapYear:function(){return T(this.year())},isDST:function(){return this.zone()+oe(t).startOf(e)},isBefore:function(t,e){return e="undefined"!=typeof e?e:"millisecond",+this.clone().startOf(e)<+oe(t).startOf(e)},isSame:function(t,e){return e=e||"ms",+this.clone().startOf(e)===+M(t,this).startOf(e)},min:function(t){return t=oe.apply(null,arguments),this>t?this:t},max:function(t){return t=oe.apply(null,arguments),t>this?this:t},zone:function(t){var e=this._offset||0;return null==t?this._isUTC?e:this._d.getTimezoneOffset():("string"==typeof t&&(t=z(t)),Math.abs(t)<16&&(t=60*t),this._offset=t,this._isUTC=!0,e!==t&&p(this,oe.duration(e-t,"m"),1,!0),this)},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.zone(this._tzm):"string"==typeof this._i&&this.zone(this._i),this},hasAlignedHourOffset:function(t){return t=t?oe(t).zone():0,(this.zone()-t)%60===0},daysInMonth:function(){return w(this.year(),this.month())},dayOfYear:function(t){var e=le((oe(this).startOf("day")-oe(this).startOf("year"))/864e5)+1;return null==t?e:this.add("d",t-e)},quarter:function(){return Math.ceil((this.month()+1)/3)},weekYear:function(t){var e=Q(this,this.lang()._week.dow,this.lang()._week.doy).year;return null==t?e:this.add("y",t-e)},isoWeekYear:function(t){var e=Q(this,1,4).year;return null==t?e:this.add("y",t-e)},week:function(t){var e=this.lang().week(this);return null==t?e:this.add("d",7*(t-e))},isoWeek:function(t){var e=Q(this,1,4).week;return null==t?e:this.add("d",7*(t-e))},weekday:function(t){var e=(this.day()+7-this.lang()._week.dow)%7;return null==t?e:this.add("d",t-e)},isoWeekday:function(t){return null==t?this.day()||7:this.day(this.day()%7?t:t-7)},get:function(t){return t=v(t),this[t]()},set:function(t,e){return t=v(t),"function"==typeof this[t]&&this[t](e),this},lang:function(t){return t===i?this._lang:(this._lang=N(t),this)}}),re=0;re-1?!1:"INPUT"==i||"SELECT"==i||"TEXTAREA"==i||e.contentEditable&&"true"==e.contentEditable}function o(t,e){return t.sort().join(",")===e.sort().join(",")}function r(t){t=t||{};var e,i=!1;for(e in M)t[e]?i=!0:M[e]=0;i||(I=!1)}function a(t,e,i,n,s){var r,a,h=[];if(!x[t])return[];for("keyup"==i&&u(t)&&(e=[t]),r=0;r95&&112>t||w.hasOwnProperty(t)&&(_[w[t]]=t)}return _}function g(t,e,i){return i||(i=f()[t]?"keydown":"keypress"),"keypress"==i&&e.length&&(i="keydown"),i}function m(t,e,i,s){M[t]=0,s||(s=g(e[0],[]));var o,a=function(){I=s,++M[t],p()},h=function(t){l(i,t),"keyup"!==s&&(D=n(t)),setTimeout(r,10)};for(o=0;o1)return m(t,l,e,i);for(h="+"===t?["+"]:t.split("+"),o=0;o":".","?":"/","|":"\\"},E={option:"alt",command:"meta","return":"enter",escape:"esc"},x={},C={},M={},D=!1,I=!1,N=1;20>N;++N)w[111+N]="f"+N;for(N=0;9>=N;++N)w[N+96]=N;i(document,"keypress",d),i(document,"keydown",d),i(document,"keyup",d);var O={bind:function(t,e,i){return y(t instanceof Array?t:[t],e,i),C[t+":"+i]=e,this},unbind:function(t,e){return C[t+":"+e]&&(delete C[t+":"+e],this.bind(t,function(){},e)),this},trigger:function(t,e){return C[t+":"+e](),this},reset:function(){return x={},C={},this}};e.exports=O},{}]},{},[1])(1)}); \ No newline at end of file diff --git a/examples/graph/22_les_miserables.html b/examples/graph/22_les_miserables.html index d6919f3f..8200e051 100644 --- a/examples/graph/22_les_miserables.html +++ b/examples/graph/22_les_miserables.html @@ -361,7 +361,7 @@ edges: edges }; - var options = {stabilize: false}; + var options = {nodes: {shape:'circle'},stabilize: false}; var graph = new vis.Graph(container, data, options); } diff --git a/src/graph/Node.js b/src/graph/Node.js index 1225369b..4b24cea3 100644 --- a/src/graph/Node.js +++ b/src/graph/Node.js @@ -68,13 +68,13 @@ function Node(properties, imagelist, grouplist, constants) { this.clusterSizeRadiusFactor = constants.clustering.nodeScaling.radius; // mass, force, velocity - this.mass = 1; // kg (mass is adjusted for the number of connected edges) + this.mass = 1; // kg this.fx = 0.0; // external force x this.fy = 0.0; // external force y this.vx = 0.0; // velocity x this.vy = 0.0; // velocity y this.minForce = constants.minForce; - this.damping = 0.9; // this is manipulated in the updateDaming function + this.damping = 0.9; // this is manipulated in the updateDamping function this.graphScaleInv = 1; this.canvasTopLeft = {"x": -300, "y": -300}; @@ -105,7 +105,7 @@ Node.prototype.attachEdge = function(edge) { this.dynamicEdges.push(edge); } this.dynamicEdgesLength = this.dynamicEdges.length; - this._updateMass(); +// this._updateMass(); }; /** @@ -119,7 +119,7 @@ Node.prototype.detachEdge = function(edge) { this.dynamicEdges.splice(index, 1); } this.dynamicEdgesLength = this.dynamicEdges.length; - this._updateMass(); +// this._updateMass(); }; /** @@ -127,9 +127,9 @@ Node.prototype.detachEdge = function(edge) { * to it (more edges -> heavier node). * @private */ -Node.prototype._updateMass = function() { - this.mass = 1;// + 0.6 * this.edges.length; // kg -}; +//Node.prototype._updateMass = function() { +// this.mass = 1;// + 0.6 * this.edges.length; // kg +//}; /** * Set or overwrite properties for the node @@ -973,7 +973,7 @@ Node.prototype.setScale = function(scale) { * @param {Number} numberOfNodes */ Node.prototype.updateDamping = function(numberOfNodes) { - this.damping = (1 + 0.1*this.clusterSize * (1 + Math.pow(numberOfNodes,-2))); + this.damping = (0.9 + 0.1*this.clusterSize * (1 + Math.pow(numberOfNodes,-2))); }; From 45692d868150f4b20dc26b08869547392379b6a8 Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Sat, 8 Feb 2014 15:59:59 +0100 Subject: [PATCH 36/52] Modified code structure, fixed barnes Hut bugs --- dist/vis.js | 122 ++++++++++++++------------------------ src/graph/ClusterMixin.js | 8 +-- src/graph/Edge.js | 6 +- src/graph/Graph.js | 17 ++++-- src/graph/Node.js | 4 +- src/graph/physicsMixin.js | 87 +++++++-------------------- src/util.js | 3 +- 7 files changed, 87 insertions(+), 160 deletions(-) diff --git a/dist/vis.js b/dist/vis.js index 96804d48..279127f1 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -1136,6 +1136,8 @@ util.hexToHSV = function hexToHSV(hex) { var rgb = util.hexToRGB(hex); return util.RGBToHSV(rgb.r,rgb.g,rgb.b); } + + /** * Event listener (singleton) */ @@ -10075,9 +10077,9 @@ Node.prototype.clearVelocity = function() { */ Node.prototype.updateVelocity = function(massBeforeClustering) { var energyBefore = this.vx * this.vx * massBeforeClustering; - this.vx = Math.sqrt(energyBefore/this.mass); + this.vx = (this.vx < 0) ? -Math.sqrt(energyBefore/this.mass) : Math.sqrt(energyBefore/this.mass); energyBefore = this.vy * this.vy * massBeforeClustering; - this.vy = Math.sqrt(energyBefore/this.mass); + this.vy = (this.vy < 0) ? -Math.sqrt(energyBefore/this.mass) : Math.sqrt(energyBefore/this.mass); }; @@ -10114,7 +10116,7 @@ function Edge (properties, graph, constants) { this.title = undefined; this.width = constants.edges.width; this.value = undefined; - this.length = constants.edges.length; + this.length = constants.physics.springLength; this.selected = false; this.from = null; // a node @@ -10132,13 +10134,12 @@ function Edge (properties, graph, constants) { // 2012-08-08 this.dash = util.extend({}, constants.edges.dash); // contains properties length, gap, altLength - this.stiffness = undefined; // depends on the length of the edge + this.springConstant = constants.physics.springConstant; this.color = constants.edges.color; this.widthFixed = false; this.lengthFixed = false; this.setProperties(properties, constants); - } /** @@ -10186,7 +10187,6 @@ Edge.prototype.setProperties = function(properties, constants) { this.widthFixed = this.widthFixed || (properties.width !== undefined); this.lengthFixed = this.lengthFixed || (properties.length !== undefined); - this.stiffness = 1 / this.length; // set draw method based on style switch (this.style) { @@ -10966,7 +10966,7 @@ var physicsMixin = { // we now start the force calculation this._calculateForcesBarnesHut(); -// this._calculateForcesOriginal(); +// this._calculateForcesRepulsion(); } }, @@ -10976,23 +10976,23 @@ var physicsMixin = { * Forces are caused by: edges, repulsing forces between nodes, gravity * @private */ - _calculateForcesOriginal : function() { + _calculateForcesRepulsion : function() { // Gravity is required to keep separated groups from floating off // the forces are reset to zero in this loop by using _setForce instead // of _addForce // var startTimeAll = Date.now(); - this._calculateGravitationalForces(1); + this._applyCentralGravity(); // var startTimeRepulsion = Date.now(); // All nodes repel eachother. - this._calculateRepulsionForces(); + this._applyNodeRepulsion(); // var endTimeRepulsion = Date.now(); // the edges are strings - this._calculateSpringForces(1); + this._applySpringForces(); // var endTimeAll = Date.now(); @@ -11012,7 +11012,7 @@ var physicsMixin = { // var startTimeAll = Date.now(); - this._clearForces(); + this._applyCentralGravity(); // var startTimeRepulsion = Date.now(); // All nodes repel eachother. @@ -11021,7 +11021,7 @@ var physicsMixin = { // var endTimeRepulsion = Date.now(); // the edges are strings - this._calculateSpringForces(1); + this._applySpringForces(); // var endTimeAll = Date.now(); @@ -11041,10 +11041,10 @@ var physicsMixin = { } }, - _calculateGravitationalForces : function(boost) { + _applyCentralGravity : function() { var dx, dy, angle, fx, fy, node, i; var nodes = this.nodes; - var gravity = 0.08 * boost; + var gravity = this.constants.physics.centralGravity; for (i = 0; i < this.nodeIndices.length; i++) { node = nodes[this.nodeIndices[i]]; @@ -11066,13 +11066,13 @@ var physicsMixin = { } }, - _calculateRepulsionForces : function() { + _applyNodeRepulsion : function() { var dx, dy, angle, distance, fx, fy, clusterSize, repulsingForce, node1, node2, i, j; var nodes = this.nodes; // approximation constants - var a_base = (-2/3); + var a_base = -2/3; var b = 4/3; // repulsing forces between nodes @@ -11116,7 +11116,7 @@ var physicsMixin = { } }, - _calculateSpringForces : function(boost) { + _applySpringForces : function() { var dx, dy, angle, fx, fy, springForce, length, edgeLength, edge, edgeId, clusterSize; var edges = this.edges; @@ -11138,7 +11138,7 @@ var physicsMixin = { length = Math.sqrt(dx * dx + dy * dy); angle = Math.atan2(dy, dx); - springForce = 0.02 * (edgeLength - length) * boost; + springForce = edge.springConstant * (edgeLength - length); fx = Math.cos(angle) * springForce; fy = Math.sin(angle) * springForce; @@ -11161,10 +11161,6 @@ var physicsMixin = { var barnesHutTree = this.barnesHutTree; - this.theta = 0.2; - this.graviationalConstant = -10000; - - // place the nodes one by one recursively for (var i = 0; i < nodeCount; i++) { node = nodes[nodeIndices[i]]; @@ -11189,8 +11185,9 @@ var physicsMixin = { if (distance > 0) { // distance is 0 if it looks to apply a force on itself. // we invert it here because we need the inverted distance for the force calculation too. var distanceInv = 1/distance; + // BarnesHut condition - if (parentBranch.size * distanceInv > this.theta) { + if (parentBranch.size * distanceInv > this.constants.physics.barnesHutTheta) { // Did not pass the condition, go into children if available if (parentBranch.childrenCount == 4) { this._getForceContribution(parentBranch.children.NW,node); @@ -11199,7 +11196,9 @@ var physicsMixin = { this._getForceContribution(parentBranch.children.SE,node); } else { // parentBranch must have only one node, if it was empty we wouldnt be here - this._getForceOnNode(parentBranch, node, dx ,dy, distanceInv); + if (parentBranch.children.data.id != node.id) { // if it is not self + this._getForceOnNode(parentBranch, node, dx ,dy, distanceInv); + } } } else { @@ -11211,7 +11210,7 @@ var physicsMixin = { _getForceOnNode : function(parentBranch, node, dx ,dy, distanceInv) { // even if the parentBranch only has one node, its Center of Mass is at the right place (the node in this case). - var gravityForce = this.graviationalConstant * parentBranch.mass * node.mass * distanceInv * distanceInv; + var gravityForce = this.constants.physics.nodeGravityConstant * parentBranch.mass * node.mass * distanceInv * distanceInv; var angle = Math.atan2(dy, dx); var fx = Math.cos(angle) * gravityForce; var fy = Math.sin(angle) * gravityForce; @@ -11242,7 +11241,7 @@ var physicsMixin = { // make the range a square var sizeDiff = Math.abs(maxX - minX) - Math.abs(maxY - minY); // difference between X and Y if (sizeDiff > 0) {minY -= 0.5 * sizeDiff; maxY += 0.5 * sizeDiff;} // xSize > ySize - else {minX += 0.5 * sizeDiff; maxY -= 0.5 * sizeDiff;} // xSize < ySize + else {minX += 0.5 * sizeDiff; maxX -= 0.5 * sizeDiff;} // xSize < ySize // construct the barnesHutTree @@ -11388,11 +11387,10 @@ var physicsMixin = { }; }, - _drawTree : function(ctx,color) { if (this.barnesHutTree !== undefined) { - ctx.lineWidth = 2; + ctx.lineWidth = 1; this._drawBranch(this.barnesHutTree.root,ctx,color); } @@ -11437,48 +11435,7 @@ var physicsMixin = { } */ } - - - - - - - - - - - - - - - - - - }; - -function echo() { - switch (arguments.length) { - case 1: - echoN1(arguments[0]); break; - case 2: - echoN2(arguments[0],arguments[1]); break; - case 3: - echoN3(arguments[0],arguments[1],arguments[2]); break; - } -} - -function echoN1(message) { - console.log(message); -} - -function echoN2(message1,message2) { - console.log(message1,message2); -} - -function echoN3(message1,message2,message3) { - console.log(message1,message2,message3); -} /** * Created by Alex on 2/4/14. */ @@ -12851,8 +12808,8 @@ var ClusterMixin = { parentNode.dynamicEdgesLength = parentNode.dynamicEdges.length; // place the child node near the parent, not at the exact same location to avoid chaos in the system - childNode.x = parentNode.x + this.constants.edges.length * 0.3 * (0.5 - Math.random()) * parentNode.clusterSize; - childNode.y = parentNode.y + this.constants.edges.length * 0.3 * (0.5 - Math.random()) * parentNode.clusterSize; + childNode.x = parentNode.x + this.constants.edges.length * (0.1 + 0.3 * (0.5 - Math.random()) * parentNode.clusterSize); + childNode.y = parentNode.y + this.constants.edges.length * (0.1 + 0.3 * (0.5 - Math.random()) * parentNode.clusterSize); // remove node from the list delete parentNode.containedNodes[containedNodeId]; @@ -13110,7 +13067,7 @@ var ClusterMixin = { // update the properties of the child and parent var massBefore = parentNode.mass; childNode.clusterSession = this.clusterSession; - parentNode.mass += this.constants.clustering.massTransferCoefficient * childNode.mass; + parentNode.mass += childNode.mass; parentNode.clusterSize += childNode.clusterSize; parentNode.fontSize += this.constants.clustering.fontSizeMultiplier * childNode.clusterSize; @@ -13423,7 +13380,7 @@ var ClusterMixin = { for (var i = 0; i < this.nodeIndices.length; i++) { var node = this.nodes[this.nodeIndices[i]]; if (!node.isFixed()) { - var radius = this.constants.edges.length * (1 + 0.6*node.clusterSize); + var radius = this.constants.physics.springLength * (1 + 0.6*node.clusterSize); var angle = 2 * Math.PI * Math.random(); node.x = radius * Math.cos(angle); node.y = radius * Math.sin(angle); @@ -14474,6 +14431,13 @@ function Graph (container, data, options) { altLength: undefined } }, + physics: { + springConstant:0.05, + springLength: 100, + centralGravity: 0.1, + nodeGravityConstant: -10000, + barnesHutTheta: 0.2 + }, clustering: { // Per Node in Cluster = PNiC enabled: false, // (Boolean) | global on/off switch for clustering. initialMaxNodes: 100, // (# nodes) | if the initial amount of nodes is larger than this, we cluster until the total number is less than this threshold. @@ -14490,8 +14454,7 @@ function Graph (container, data, options) { nodeScaling: {width: 10, // (px PNiC) | growth of the width per node in cluster. height: 10, // (px PNiC) | growth of the height per node in cluster. radius: 10}, // (px PNiC) | growth of the radius per node in cluster. - activeAreaBoxSize: 100, // (px) | box area around the curser where clusters are popped open. - massTransferCoefficient: 1 // (multiplier) | parent.mass += massTransferCoefficient * child.mass + activeAreaBoxSize: 100 // (px) | box area around the curser where clusters are popped open. }, navigation: { enabled: false, @@ -14853,7 +14816,7 @@ Graph.prototype.setOptions = function (options) { if (options.edges.length !== undefined && options.nodes && options.nodes.distance === undefined) { - this.constants.edges.length = options.edges.length; + this.constants.physics.springLength = options.edges.length; this.constants.nodes.distance = options.edges.length * 1.25; } @@ -15905,7 +15868,7 @@ Graph.prototype._redraw = function() { this._doInAllSectors("_drawEdges",ctx); this._doInAllSectors("_drawNodes",ctx,true); - //this._drawTree(ctx,"#F00F0F"); + this._drawTree(ctx,"#F00F0F"); // restore original scaling and translation ctx.restore(); @@ -16113,7 +16076,7 @@ Graph.prototype._isMoving = function(vmin) { * @private */ Graph.prototype._discreteStepNodes = function() { - var interval = 1.0; + var interval = 0.5; var nodes = this.nodes; this.constants.maxVelocity = 30; @@ -16172,6 +16135,7 @@ Graph.prototype.start = function() { graph._zoom(graph.scale*(1 + graph.zoomIncrement), center); } + graph.start(); graph.start(); graph._redraw(); diff --git a/src/graph/ClusterMixin.js b/src/graph/ClusterMixin.js index f63c404f..8045ccee 100644 --- a/src/graph/ClusterMixin.js +++ b/src/graph/ClusterMixin.js @@ -358,8 +358,8 @@ var ClusterMixin = { parentNode.dynamicEdgesLength = parentNode.dynamicEdges.length; // place the child node near the parent, not at the exact same location to avoid chaos in the system - childNode.x = parentNode.x + this.constants.edges.length * 0.3 * (0.5 - Math.random()) * parentNode.clusterSize; - childNode.y = parentNode.y + this.constants.edges.length * 0.3 * (0.5 - Math.random()) * parentNode.clusterSize; + childNode.x = parentNode.x + this.constants.edges.length * (0.1 + 0.3 * (0.5 - Math.random()) * parentNode.clusterSize); + childNode.y = parentNode.y + this.constants.edges.length * (0.1 + 0.3 * (0.5 - Math.random()) * parentNode.clusterSize); // remove node from the list delete parentNode.containedNodes[containedNodeId]; @@ -617,7 +617,7 @@ var ClusterMixin = { // update the properties of the child and parent var massBefore = parentNode.mass; childNode.clusterSession = this.clusterSession; - parentNode.mass += this.constants.clustering.massTransferCoefficient * childNode.mass; + parentNode.mass += childNode.mass; parentNode.clusterSize += childNode.clusterSize; parentNode.fontSize += this.constants.clustering.fontSizeMultiplier * childNode.clusterSize; @@ -930,7 +930,7 @@ var ClusterMixin = { for (var i = 0; i < this.nodeIndices.length; i++) { var node = this.nodes[this.nodeIndices[i]]; if (!node.isFixed()) { - var radius = this.constants.edges.length * (1 + 0.6*node.clusterSize); + var radius = this.constants.physics.springLength * (1 + 0.6*node.clusterSize); var angle = 2 * Math.PI * Math.random(); node.x = radius * Math.cos(angle); node.y = radius * Math.sin(angle); diff --git a/src/graph/Edge.js b/src/graph/Edge.js index e61b9083..c74a5bdc 100644 --- a/src/graph/Edge.js +++ b/src/graph/Edge.js @@ -31,7 +31,7 @@ function Edge (properties, graph, constants) { this.title = undefined; this.width = constants.edges.width; this.value = undefined; - this.length = constants.edges.length; + this.length = constants.physics.springLength; this.selected = false; this.from = null; // a node @@ -49,13 +49,12 @@ function Edge (properties, graph, constants) { // 2012-08-08 this.dash = util.extend({}, constants.edges.dash); // contains properties length, gap, altLength - this.stiffness = undefined; // depends on the length of the edge + this.springConstant = constants.physics.springConstant; this.color = constants.edges.color; this.widthFixed = false; this.lengthFixed = false; this.setProperties(properties, constants); - } /** @@ -103,7 +102,6 @@ Edge.prototype.setProperties = function(properties, constants) { this.widthFixed = this.widthFixed || (properties.width !== undefined); this.lengthFixed = this.lengthFixed || (properties.length !== undefined); - this.stiffness = 1 / this.length; // set draw method based on style switch (this.style) { diff --git a/src/graph/Graph.js b/src/graph/Graph.js index 25367a32..2e238baa 100644 --- a/src/graph/Graph.js +++ b/src/graph/Graph.js @@ -65,6 +65,13 @@ function Graph (container, data, options) { altLength: undefined } }, + physics: { + springConstant:0.05, + springLength: 100, + centralGravity: 0.1, + nodeGravityConstant: -10000, + barnesHutTheta: 0.2 + }, clustering: { // Per Node in Cluster = PNiC enabled: false, // (Boolean) | global on/off switch for clustering. initialMaxNodes: 100, // (# nodes) | if the initial amount of nodes is larger than this, we cluster until the total number is less than this threshold. @@ -81,8 +88,7 @@ function Graph (container, data, options) { nodeScaling: {width: 10, // (px PNiC) | growth of the width per node in cluster. height: 10, // (px PNiC) | growth of the height per node in cluster. radius: 10}, // (px PNiC) | growth of the radius per node in cluster. - activeAreaBoxSize: 100, // (px) | box area around the curser where clusters are popped open. - massTransferCoefficient: 1 // (multiplier) | parent.mass += massTransferCoefficient * child.mass + activeAreaBoxSize: 100 // (px) | box area around the curser where clusters are popped open. }, navigation: { enabled: false, @@ -444,7 +450,7 @@ Graph.prototype.setOptions = function (options) { if (options.edges.length !== undefined && options.nodes && options.nodes.distance === undefined) { - this.constants.edges.length = options.edges.length; + this.constants.physics.springLength = options.edges.length; this.constants.nodes.distance = options.edges.length * 1.25; } @@ -1496,7 +1502,7 @@ Graph.prototype._redraw = function() { this._doInAllSectors("_drawEdges",ctx); this._doInAllSectors("_drawNodes",ctx,true); - //this._drawTree(ctx,"#F00F0F"); + this._drawTree(ctx,"#F00F0F"); // restore original scaling and translation ctx.restore(); @@ -1704,7 +1710,7 @@ Graph.prototype._isMoving = function(vmin) { * @private */ Graph.prototype._discreteStepNodes = function() { - var interval = 1.0; + var interval = 0.5; var nodes = this.nodes; this.constants.maxVelocity = 30; @@ -1763,6 +1769,7 @@ Graph.prototype.start = function() { graph._zoom(graph.scale*(1 + graph.zoomIncrement), center); } + graph.start(); graph.start(); graph._redraw(); diff --git a/src/graph/Node.js b/src/graph/Node.js index 4b24cea3..044eed67 100644 --- a/src/graph/Node.js +++ b/src/graph/Node.js @@ -993,8 +993,8 @@ Node.prototype.clearVelocity = function() { */ Node.prototype.updateVelocity = function(massBeforeClustering) { var energyBefore = this.vx * this.vx * massBeforeClustering; - this.vx = Math.sqrt(energyBefore/this.mass); + this.vx = (this.vx < 0) ? -Math.sqrt(energyBefore/this.mass) : Math.sqrt(energyBefore/this.mass); energyBefore = this.vy * this.vy * massBeforeClustering; - this.vy = Math.sqrt(energyBefore/this.mass); + this.vy = (this.vy < 0) ? -Math.sqrt(energyBefore/this.mass) : Math.sqrt(energyBefore/this.mass); }; diff --git a/src/graph/physicsMixin.js b/src/graph/physicsMixin.js index c8edbd1c..b49e86dd 100644 --- a/src/graph/physicsMixin.js +++ b/src/graph/physicsMixin.js @@ -24,7 +24,7 @@ var physicsMixin = { // we now start the force calculation this._calculateForcesBarnesHut(); -// this._calculateForcesOriginal(); +// this._calculateForcesRepulsion(); } }, @@ -34,23 +34,23 @@ var physicsMixin = { * Forces are caused by: edges, repulsing forces between nodes, gravity * @private */ - _calculateForcesOriginal : function() { + _calculateForcesRepulsion : function() { // Gravity is required to keep separated groups from floating off // the forces are reset to zero in this loop by using _setForce instead // of _addForce // var startTimeAll = Date.now(); - this._calculateGravitationalForces(1); + this._applyCentralGravity(); // var startTimeRepulsion = Date.now(); // All nodes repel eachother. - this._calculateRepulsionForces(); + this._applyNodeRepulsion(); // var endTimeRepulsion = Date.now(); // the edges are strings - this._calculateSpringForces(1); + this._applySpringForces(); // var endTimeAll = Date.now(); @@ -70,7 +70,7 @@ var physicsMixin = { // var startTimeAll = Date.now(); - this._clearForces(); + this._applyCentralGravity(); // var startTimeRepulsion = Date.now(); // All nodes repel eachother. @@ -79,7 +79,7 @@ var physicsMixin = { // var endTimeRepulsion = Date.now(); // the edges are strings - this._calculateSpringForces(1); + this._applySpringForces(); // var endTimeAll = Date.now(); @@ -99,10 +99,10 @@ var physicsMixin = { } }, - _calculateGravitationalForces : function(boost) { + _applyCentralGravity : function() { var dx, dy, angle, fx, fy, node, i; var nodes = this.nodes; - var gravity = 0.08 * boost; + var gravity = this.constants.physics.centralGravity; for (i = 0; i < this.nodeIndices.length; i++) { node = nodes[this.nodeIndices[i]]; @@ -124,13 +124,13 @@ var physicsMixin = { } }, - _calculateRepulsionForces : function() { + _applyNodeRepulsion : function() { var dx, dy, angle, distance, fx, fy, clusterSize, repulsingForce, node1, node2, i, j; var nodes = this.nodes; // approximation constants - var a_base = (-2/3); + var a_base = -2/3; var b = 4/3; // repulsing forces between nodes @@ -174,7 +174,7 @@ var physicsMixin = { } }, - _calculateSpringForces : function(boost) { + _applySpringForces : function() { var dx, dy, angle, fx, fy, springForce, length, edgeLength, edge, edgeId, clusterSize; var edges = this.edges; @@ -196,7 +196,7 @@ var physicsMixin = { length = Math.sqrt(dx * dx + dy * dy); angle = Math.atan2(dy, dx); - springForce = 0.02 * (edgeLength - length) * boost; + springForce = edge.springConstant * (edgeLength - length); fx = Math.cos(angle) * springForce; fy = Math.sin(angle) * springForce; @@ -219,10 +219,6 @@ var physicsMixin = { var barnesHutTree = this.barnesHutTree; - this.theta = 0.2; - this.graviationalConstant = -10000; - - // place the nodes one by one recursively for (var i = 0; i < nodeCount; i++) { node = nodes[nodeIndices[i]]; @@ -247,8 +243,9 @@ var physicsMixin = { if (distance > 0) { // distance is 0 if it looks to apply a force on itself. // we invert it here because we need the inverted distance for the force calculation too. var distanceInv = 1/distance; + // BarnesHut condition - if (parentBranch.size * distanceInv > this.theta) { + if (parentBranch.size * distanceInv > this.constants.physics.barnesHutTheta) { // Did not pass the condition, go into children if available if (parentBranch.childrenCount == 4) { this._getForceContribution(parentBranch.children.NW,node); @@ -257,7 +254,9 @@ var physicsMixin = { this._getForceContribution(parentBranch.children.SE,node); } else { // parentBranch must have only one node, if it was empty we wouldnt be here - this._getForceOnNode(parentBranch, node, dx ,dy, distanceInv); + if (parentBranch.children.data.id != node.id) { // if it is not self + this._getForceOnNode(parentBranch, node, dx ,dy, distanceInv); + } } } else { @@ -269,7 +268,7 @@ var physicsMixin = { _getForceOnNode : function(parentBranch, node, dx ,dy, distanceInv) { // even if the parentBranch only has one node, its Center of Mass is at the right place (the node in this case). - var gravityForce = this.graviationalConstant * parentBranch.mass * node.mass * distanceInv * distanceInv; + var gravityForce = this.constants.physics.nodeGravityConstant * parentBranch.mass * node.mass * distanceInv * distanceInv; var angle = Math.atan2(dy, dx); var fx = Math.cos(angle) * gravityForce; var fy = Math.sin(angle) * gravityForce; @@ -300,7 +299,7 @@ var physicsMixin = { // make the range a square var sizeDiff = Math.abs(maxX - minX) - Math.abs(maxY - minY); // difference between X and Y if (sizeDiff > 0) {minY -= 0.5 * sizeDiff; maxY += 0.5 * sizeDiff;} // xSize > ySize - else {minX += 0.5 * sizeDiff; maxY -= 0.5 * sizeDiff;} // xSize < ySize + else {minX += 0.5 * sizeDiff; maxX -= 0.5 * sizeDiff;} // xSize < ySize // construct the barnesHutTree @@ -446,11 +445,10 @@ var physicsMixin = { }; }, - _drawTree : function(ctx,color) { if (this.barnesHutTree !== undefined) { - ctx.lineWidth = 2; + ctx.lineWidth = 1; this._drawBranch(this.barnesHutTree.root,ctx,color); } @@ -495,45 +493,4 @@ var physicsMixin = { } */ } - - - - - - - - - - - - - - - - - - -}; - -function echo() { - switch (arguments.length) { - case 1: - echoN1(arguments[0]); break; - case 2: - echoN2(arguments[0],arguments[1]); break; - case 3: - echoN3(arguments[0],arguments[1],arguments[2]); break; - } -} - -function echoN1(message) { - console.log(message); -} - -function echoN2(message1,message2) { - console.log(message1,message2); -} - -function echoN3(message1,message2,message3) { - console.log(message1,message2,message3); -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/util.js b/src/util.js index 8495d68c..6b49996c 100644 --- a/src/util.js +++ b/src/util.js @@ -824,4 +824,5 @@ util.HSVToHex = function HSVToHex(h,s,v) { util.hexToHSV = function hexToHSV(hex) { var rgb = util.hexToRGB(hex); return util.RGBToHSV(rgb.r,rgb.g,rgb.b); -} \ No newline at end of file +} + From 9c1e96a492905a52e9d6fc701c228f93ac46ff8d Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Sat, 8 Feb 2014 16:36:01 +0100 Subject: [PATCH 37/52] hunting bug... --- dist/vis.js | 30 +++++++++++++++++++---------- examples/graph/02_random_nodes.html | 3 ++- src/graph/ClusterMixin.js | 7 ++++--- src/graph/Graph.js | 3 ++- src/graph/physicsMixin.js | 20 +++++++++++++------ 5 files changed, 42 insertions(+), 21 deletions(-) diff --git a/dist/vis.js b/dist/vis.js index 279127f1..b1a268b6 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -10953,7 +10953,7 @@ var physicsMixin = { * * @private */ - _initializeForceCalculation : function() { + _initializeForceCalculation : function(useBarnesHut) { // stop calculation if there is only one node if (this.nodeIndices.length == 1) { this.nodes[this.nodeIndices[0]]._setForce(0,0); @@ -10964,9 +10964,15 @@ var physicsMixin = { this.clusterToFit(this.constants.clustering.reduceToNodes, false); } - // we now start the force calculation - this._calculateForcesBarnesHut(); -// this._calculateForcesRepulsion(); + this._calculateForcesRepulsion(); + +// // we now start the force calculation +// if (useBarnesHut == true) { +// this._calculateForcesBarnesHut(); +// } +// else { +// this._calculateForcesRepulsion(); +// } } }, @@ -11142,7 +11148,7 @@ var physicsMixin = { fx = Math.cos(angle) * springForce; fy = Math.sin(angle) * springForce; - + //console.log(edge.length,dx,dy,edge.springConstant,angle) edge.from._addForce(-fx, -fy); edge.to._addForce(fx, fy); } @@ -11251,6 +11257,7 @@ var physicsMixin = { range:{minX:minX,maxX:maxX,minY:minY,maxY:maxY}, size: Math.abs(maxX - minX), children: {data:null}, + level: 0, childrenCount: 4 }}; this._splitBranch(barnesHutTree.root); @@ -11265,7 +11272,6 @@ var physicsMixin = { this.barnesHutTree = barnesHutTree }, - _updateBranchMass : function(parentBranch, node) { var totalMass = parentBranch.mass + node.mass; var totalMassInv = 1/totalMass; @@ -11377,12 +11383,14 @@ var physicsMixin = { break; } + parentBranch.children[region] = { CenterOfMass:{x:0,y:0}, mass:0, range:{minX:minX,maxX:maxX,minY:minY,maxY:maxY}, size: 0.5 * parentBranch.size, children: {data:null}, + level: parentBranch.level +1, childrenCount: 0 }; }, @@ -12763,6 +12771,7 @@ var ClusterMixin = { } } } + }, /** @@ -12808,9 +12817,9 @@ var ClusterMixin = { parentNode.dynamicEdgesLength = parentNode.dynamicEdges.length; // place the child node near the parent, not at the exact same location to avoid chaos in the system - childNode.x = parentNode.x + this.constants.edges.length * (0.1 + 0.3 * (0.5 - Math.random()) * parentNode.clusterSize); - childNode.y = parentNode.y + this.constants.edges.length * (0.1 + 0.3 * (0.5 - Math.random()) * parentNode.clusterSize); - + childNode.x = parentNode.x + this.constants.physics.springLength * (0.1 * (0.5 - Math.random()) * parentNode.clusterSize); + childNode.y = parentNode.y + this.constants.physics.springLength * (0.1 * (0.5 - Math.random()) * parentNode.clusterSize); + console.log(childNode.x,childNode.y,parentNode.x,parentNode.y); // remove node from the list delete parentNode.containedNodes[containedNodeId]; @@ -16135,6 +16144,7 @@ Graph.prototype.start = function() { graph._zoom(graph.scale*(1 + graph.zoomIncrement), center); } + graph.start(); graph.start(); graph._redraw(); @@ -16157,7 +16167,7 @@ Graph.prototype.start = function() { */ Graph.prototype.singleStep = function() { if (this.moving) { - this._initializeForceCalculation(); + this._initializeForceCalculation(true); this._discreteStepNodes(); var vmin = this.constants.minVelocity; diff --git a/examples/graph/02_random_nodes.html b/examples/graph/02_random_nodes.html index a900ccbd..57ea0714 100755 --- a/examples/graph/02_random_nodes.html +++ b/examples/graph/02_random_nodes.html @@ -90,7 +90,8 @@ edges: { length: 50 }, - stabilize: false + stabilize: false, + clustering : true }; graph = new vis.Graph(container, data, options); diff --git a/src/graph/ClusterMixin.js b/src/graph/ClusterMixin.js index 8045ccee..740f618f 100644 --- a/src/graph/ClusterMixin.js +++ b/src/graph/ClusterMixin.js @@ -313,6 +313,7 @@ var ClusterMixin = { } } } + }, /** @@ -358,9 +359,9 @@ var ClusterMixin = { parentNode.dynamicEdgesLength = parentNode.dynamicEdges.length; // place the child node near the parent, not at the exact same location to avoid chaos in the system - childNode.x = parentNode.x + this.constants.edges.length * (0.1 + 0.3 * (0.5 - Math.random()) * parentNode.clusterSize); - childNode.y = parentNode.y + this.constants.edges.length * (0.1 + 0.3 * (0.5 - Math.random()) * parentNode.clusterSize); - + childNode.x = parentNode.x + this.constants.physics.springLength * (0.1 * (0.5 - Math.random()) * parentNode.clusterSize); + childNode.y = parentNode.y + this.constants.physics.springLength * (0.1 * (0.5 - Math.random()) * parentNode.clusterSize); + console.log(childNode.x,childNode.y,parentNode.x,parentNode.y); // remove node from the list delete parentNode.containedNodes[containedNodeId]; diff --git a/src/graph/Graph.js b/src/graph/Graph.js index 2e238baa..0dbc111a 100644 --- a/src/graph/Graph.js +++ b/src/graph/Graph.js @@ -1769,6 +1769,7 @@ Graph.prototype.start = function() { graph._zoom(graph.scale*(1 + graph.zoomIncrement), center); } + graph.start(); graph.start(); graph._redraw(); @@ -1791,7 +1792,7 @@ Graph.prototype.start = function() { */ Graph.prototype.singleStep = function() { if (this.moving) { - this._initializeForceCalculation(); + this._initializeForceCalculation(true); this._discreteStepNodes(); var vmin = this.constants.minVelocity; diff --git a/src/graph/physicsMixin.js b/src/graph/physicsMixin.js index b49e86dd..b52d32c7 100644 --- a/src/graph/physicsMixin.js +++ b/src/graph/physicsMixin.js @@ -11,7 +11,7 @@ var physicsMixin = { * * @private */ - _initializeForceCalculation : function() { + _initializeForceCalculation : function(useBarnesHut) { // stop calculation if there is only one node if (this.nodeIndices.length == 1) { this.nodes[this.nodeIndices[0]]._setForce(0,0); @@ -22,9 +22,15 @@ var physicsMixin = { this.clusterToFit(this.constants.clustering.reduceToNodes, false); } - // we now start the force calculation - this._calculateForcesBarnesHut(); -// this._calculateForcesRepulsion(); + this._calculateForcesRepulsion(); + +// // we now start the force calculation +// if (useBarnesHut == true) { +// this._calculateForcesBarnesHut(); +// } +// else { +// this._calculateForcesRepulsion(); +// } } }, @@ -200,7 +206,7 @@ var physicsMixin = { fx = Math.cos(angle) * springForce; fy = Math.sin(angle) * springForce; - + //console.log(edge.length,dx,dy,edge.springConstant,angle) edge.from._addForce(-fx, -fy); edge.to._addForce(fx, fy); } @@ -309,6 +315,7 @@ var physicsMixin = { range:{minX:minX,maxX:maxX,minY:minY,maxY:maxY}, size: Math.abs(maxX - minX), children: {data:null}, + level: 0, childrenCount: 4 }}; this._splitBranch(barnesHutTree.root); @@ -323,7 +330,6 @@ var physicsMixin = { this.barnesHutTree = barnesHutTree }, - _updateBranchMass : function(parentBranch, node) { var totalMass = parentBranch.mass + node.mass; var totalMassInv = 1/totalMass; @@ -435,12 +441,14 @@ var physicsMixin = { break; } + parentBranch.children[region] = { CenterOfMass:{x:0,y:0}, mass:0, range:{minX:minX,maxX:maxX,minY:minY,maxY:maxY}, size: 0.5 * parentBranch.size, children: {data:null}, + level: parentBranch.level +1, childrenCount: 0 }; }, From 1e6bb102af209f93ba9465585a591aedc91cde83 Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Sat, 8 Feb 2014 17:27:20 +0100 Subject: [PATCH 38/52] alter git --- .gitignore | 1 + dist/vis.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index b6a487c8..ec01a71f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .idea node_modules .project +dist .settings/.jsdtscope .settings/org.eclipse.wst.jsdt.ui.superType.container .settings/org.eclipse.wst.jsdt.ui.superType.name diff --git a/dist/vis.js b/dist/vis.js index b1a268b6..194426c9 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -4,8 +4,8 @@ * * A dynamic, browser-based visualization library. * - * @version @@version - * @date @@date + * @version 0.5.0-SNAPSHOT + * @date 2014-02-08 * * @license * Copyright (C) 2011-2014 Almende B.V, http://almende.com From c34d9697b2bc8b7cce798c92d25602ff34334266 Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Sat, 8 Feb 2014 17:34:14 +0100 Subject: [PATCH 39/52] bughunt 4, going back commits --- dist/vis.js | 21055 ------------------------------------ src/graph/ClusterMixin.js | 6 +- src/graph/Edge.js | 4 +- src/graph/Graph.js | 5 +- src/graph/physicsMixin.js | 34 +- 5 files changed, 22 insertions(+), 21082 deletions(-) delete mode 100644 dist/vis.js diff --git a/dist/vis.js b/dist/vis.js deleted file mode 100644 index 194426c9..00000000 --- a/dist/vis.js +++ /dev/null @@ -1,21055 +0,0 @@ -/** - * vis.js - * https://github.com/almende/vis - * - * A dynamic, browser-based visualization library. - * - * @version 0.5.0-SNAPSHOT - * @date 2014-02-08 - * - * @license - * Copyright (C) 2011-2014 Almende B.V, http://almende.com - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -!function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.vis=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o>> 0; - - // 4. If IsCallable(callback) is false, throw a TypeError exception. - // See: http://es5.github.com/#x9.11 - if (typeof callback !== "function") { - throw new TypeError(callback + " is not a function"); - } - - // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. - if (thisArg) { - T = thisArg; - } - - // 6. Let A be a new array created as if by the expression new Array(len) where Array is - // the standard built-in constructor with that name and len is the value of len. - A = new Array(len); - - // 7. Let k be 0 - k = 0; - - // 8. Repeat, while k < len - while(k < len) { - - var kValue, mappedValue; - - // a. Let Pk be ToString(k). - // This is implicit for LHS operands of the in operator - // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk. - // This step can be combined with c - // c. If kPresent is true, then - if (k in O) { - - // i. Let kValue be the result of calling the Get internal method of O with argument Pk. - kValue = O[ k ]; - - // ii. Let mappedValue be the result of calling the Call internal method of callback - // with T as the this value and argument list containing kValue, k, and O. - mappedValue = callback.call(T, kValue, k, O); - - // iii. Call the DefineOwnProperty internal method of A with arguments - // Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true}, - // and false. - - // In browsers that support Object.defineProperty, use the following: - // Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true }); - - // For best browser support, use the following: - A[ k ] = mappedValue; - } - // d. Increase k by 1. - k++; - } - - // 9. return A - return A; - }; -} - -// Internet Explorer 8 and older does not support Array.filter, so we define it -// here in that case. -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/filter -if (!Array.prototype.filter) { - Array.prototype.filter = function(fun /*, thisp */) { - "use strict"; - - if (this == null) { - throw new TypeError(); - } - - var t = Object(this); - var len = t.length >>> 0; - if (typeof fun != "function") { - throw new TypeError(); - } - - var res = []; - var thisp = arguments[1]; - for (var i = 0; i < len; i++) { - if (i in t) { - var val = t[i]; // in case fun mutates this - if (fun.call(thisp, val, i, t)) - res.push(val); - } - } - - return res; - }; -} - - -// Internet Explorer 8 and older does not support Object.keys, so we define it -// here in that case. -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys -if (!Object.keys) { - Object.keys = (function () { - var hasOwnProperty = Object.prototype.hasOwnProperty, - hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), - dontEnums = [ - 'toString', - 'toLocaleString', - 'valueOf', - 'hasOwnProperty', - 'isPrototypeOf', - 'propertyIsEnumerable', - 'constructor' - ], - dontEnumsLength = dontEnums.length; - - return function (obj) { - if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) { - throw new TypeError('Object.keys called on non-object'); - } - - var result = []; - - for (var prop in obj) { - if (hasOwnProperty.call(obj, prop)) result.push(prop); - } - - if (hasDontEnumBug) { - for (var i=0; i < dontEnumsLength; i++) { - if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]); - } - } - return result; - } - })() -} - -// Internet Explorer 8 and older does not support Array.isArray, -// so we define it here in that case. -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/isArray -if(!Array.isArray) { - Array.isArray = function (vArg) { - return Object.prototype.toString.call(vArg) === "[object Array]"; - }; -} - -// Internet Explorer 8 and older does not support Function.bind, -// so we define it here in that case. -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind -if (!Function.prototype.bind) { - Function.prototype.bind = function (oThis) { - if (typeof this !== "function") { - // closest thing possible to the ECMAScript 5 internal IsCallable function - throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); - } - - var aArgs = Array.prototype.slice.call(arguments, 1), - fToBind = this, - fNOP = function () {}, - fBound = function () { - return fToBind.apply(this instanceof fNOP && oThis - ? this - : oThis, - aArgs.concat(Array.prototype.slice.call(arguments))); - }; - - fNOP.prototype = this.prototype; - fBound.prototype = new fNOP(); - - return fBound; - }; -} - -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create -if (!Object.create) { - Object.create = function (o) { - if (arguments.length > 1) { - throw new Error('Object.create implementation only accepts the first parameter.'); - } - function F() {} - F.prototype = o; - return new F(); - }; -} - -// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind -if (!Function.prototype.bind) { - Function.prototype.bind = function (oThis) { - if (typeof this !== "function") { - // closest thing possible to the ECMAScript 5 internal IsCallable function - throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); - } - - var aArgs = Array.prototype.slice.call(arguments, 1), - fToBind = this, - fNOP = function () {}, - fBound = function () { - return fToBind.apply(this instanceof fNOP && oThis - ? this - : oThis, - aArgs.concat(Array.prototype.slice.call(arguments))); - }; - - fNOP.prototype = this.prototype; - fBound.prototype = new fNOP(); - - return fBound; - }; -} - -/** - * utility functions - */ -var util = {}; - -/** - * Test whether given object is a number - * @param {*} object - * @return {Boolean} isNumber - */ -util.isNumber = function isNumber(object) { - return (object instanceof Number || typeof object == 'number'); -}; - -/** - * Test whether given object is a string - * @param {*} object - * @return {Boolean} isString - */ -util.isString = function isString(object) { - return (object instanceof String || typeof object == 'string'); -}; - -/** - * Test whether given object is a Date, or a String containing a Date - * @param {Date | String} object - * @return {Boolean} isDate - */ -util.isDate = function isDate(object) { - if (object instanceof Date) { - return true; - } - else if (util.isString(object)) { - // test whether this string contains a date - var match = ASPDateRegex.exec(object); - if (match) { - return true; - } - else if (!isNaN(Date.parse(object))) { - return true; - } - } - - return false; -}; - -/** - * Test whether given object is an instance of google.visualization.DataTable - * @param {*} object - * @return {Boolean} isDataTable - */ -util.isDataTable = function isDataTable(object) { - return (typeof (google) !== 'undefined') && - (google.visualization) && - (google.visualization.DataTable) && - (object instanceof google.visualization.DataTable); -}; - -/** - * Create a semi UUID - * source: http://stackoverflow.com/a/105074/1262753 - * @return {String} uuid - */ -util.randomUUID = function randomUUID () { - var S4 = function () { - return Math.floor( - Math.random() * 0x10000 /* 65536 */ - ).toString(16); - }; - - return ( - S4() + S4() + '-' + - S4() + '-' + - S4() + '-' + - S4() + '-' + - S4() + S4() + S4() - ); -}; - -/** - * Extend object a with the properties of object b or a series of objects - * Only properties with defined values are copied - * @param {Object} a - * @param {... Object} b - * @return {Object} a - */ -util.extend = function (a, b) { - for (var i = 1, len = arguments.length; i < len; i++) { - var other = arguments[i]; - for (var prop in other) { - if (other.hasOwnProperty(prop) && other[prop] !== undefined) { - a[prop] = other[prop]; - } - } - } - - return a; -}; - -/** - * Convert an object to another type - * @param {Boolean | Number | String | Date | Moment | Null | undefined} object - * @param {String | undefined} type Name of the type. Available types: - * 'Boolean', 'Number', 'String', - * 'Date', 'Moment', ISODate', 'ASPDate'. - * @return {*} object - * @throws Error - */ -util.convert = function convert(object, type) { - var match; - - if (object === undefined) { - return undefined; - } - if (object === null) { - return null; - } - - if (!type) { - return object; - } - if (!(typeof type === 'string') && !(type instanceof String)) { - throw new Error('Type must be a string'); - } - - //noinspection FallthroughInSwitchStatementJS - switch (type) { - case 'boolean': - case 'Boolean': - return Boolean(object); - - case 'number': - case 'Number': - return Number(object.valueOf()); - - case 'string': - case 'String': - return String(object); - - case 'Date': - if (util.isNumber(object)) { - return new Date(object); - } - if (object instanceof Date) { - return new Date(object.valueOf()); - } - else if (moment.isMoment(object)) { - return new Date(object.valueOf()); - } - if (util.isString(object)) { - match = ASPDateRegex.exec(object); - if (match) { - // object is an ASP date - return new Date(Number(match[1])); // parse number - } - else { - return moment(object).toDate(); // parse string - } - } - else { - throw new Error( - 'Cannot convert object of type ' + util.getType(object) + - ' to type Date'); - } - - case 'Moment': - if (util.isNumber(object)) { - return moment(object); - } - if (object instanceof Date) { - return moment(object.valueOf()); - } - else if (moment.isMoment(object)) { - return moment(object); - } - if (util.isString(object)) { - match = ASPDateRegex.exec(object); - if (match) { - // object is an ASP date - return moment(Number(match[1])); // parse number - } - else { - return moment(object); // parse string - } - } - else { - throw new Error( - 'Cannot convert object of type ' + util.getType(object) + - ' to type Date'); - } - - case 'ISODate': - if (util.isNumber(object)) { - return new Date(object); - } - else if (object instanceof Date) { - return object.toISOString(); - } - else if (moment.isMoment(object)) { - return object.toDate().toISOString(); - } - else if (util.isString(object)) { - match = ASPDateRegex.exec(object); - if (match) { - // object is an ASP date - return new Date(Number(match[1])).toISOString(); // parse number - } - else { - return new Date(object).toISOString(); // parse string - } - } - else { - throw new Error( - 'Cannot convert object of type ' + util.getType(object) + - ' to type ISODate'); - } - - case 'ASPDate': - if (util.isNumber(object)) { - return '/Date(' + object + ')/'; - } - else if (object instanceof Date) { - return '/Date(' + object.valueOf() + ')/'; - } - else if (util.isString(object)) { - match = ASPDateRegex.exec(object); - var value; - if (match) { - // object is an ASP date - value = new Date(Number(match[1])).valueOf(); // parse number - } - else { - value = new Date(object).valueOf(); // parse string - } - return '/Date(' + value + ')/'; - } - else { - throw new Error( - 'Cannot convert object of type ' + util.getType(object) + - ' to type ASPDate'); - } - - default: - throw new Error('Cannot convert object of type ' + util.getType(object) + - ' to type "' + type + '"'); - } -}; - -// parse ASP.Net Date pattern, -// for example '/Date(1198908717056)/' or '/Date(1198908717056-0700)/' -// code from http://momentjs.com/ -var ASPDateRegex = /^\/?Date\((\-?\d+)/i; - -/** - * Get the type of an object, for example util.getType([]) returns 'Array' - * @param {*} object - * @return {String} type - */ -util.getType = function getType(object) { - var type = typeof object; - - if (type == 'object') { - if (object == null) { - return 'null'; - } - if (object instanceof Boolean) { - return 'Boolean'; - } - if (object instanceof Number) { - return 'Number'; - } - if (object instanceof String) { - return 'String'; - } - if (object instanceof Array) { - return 'Array'; - } - if (object instanceof Date) { - return 'Date'; - } - return 'Object'; - } - else if (type == 'number') { - return 'Number'; - } - else if (type == 'boolean') { - return 'Boolean'; - } - else if (type == 'string') { - return 'String'; - } - - return type; -}; - -/** - * Retrieve the absolute left value of a DOM element - * @param {Element} elem A dom element, for example a div - * @return {number} left The absolute left position of this element - * in the browser page. - */ -util.getAbsoluteLeft = function getAbsoluteLeft (elem) { - var doc = document.documentElement; - var body = document.body; - - var left = elem.offsetLeft; - var e = elem.offsetParent; - while (e != null && e != body && e != doc) { - left += e.offsetLeft; - left -= e.scrollLeft; - e = e.offsetParent; - } - return left; -}; - -/** - * Retrieve the absolute top value of a DOM element - * @param {Element} elem A dom element, for example a div - * @return {number} top The absolute top position of this element - * in the browser page. - */ -util.getAbsoluteTop = function getAbsoluteTop (elem) { - var doc = document.documentElement; - var body = document.body; - - var top = elem.offsetTop; - var e = elem.offsetParent; - while (e != null && e != body && e != doc) { - top += e.offsetTop; - top -= e.scrollTop; - e = e.offsetParent; - } - return top; -}; - -/** - * Get the absolute, vertical mouse position from an event. - * @param {Event} event - * @return {Number} pageY - */ -util.getPageY = function getPageY (event) { - if ('pageY' in event) { - return event.pageY; - } - else { - var clientY; - if (('targetTouches' in event) && event.targetTouches.length) { - clientY = event.targetTouches[0].clientY; - } - else { - clientY = event.clientY; - } - - var doc = document.documentElement; - var body = document.body; - return clientY + - ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - - ( doc && doc.clientTop || body && body.clientTop || 0 ); - } -}; - -/** - * Get the absolute, horizontal mouse position from an event. - * @param {Event} event - * @return {Number} pageX - */ -util.getPageX = function getPageX (event) { - if ('pageY' in event) { - return event.pageX; - } - else { - var clientX; - if (('targetTouches' in event) && event.targetTouches.length) { - clientX = event.targetTouches[0].clientX; - } - else { - clientX = event.clientX; - } - - var doc = document.documentElement; - var body = document.body; - return clientX + - ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); - } -}; - -/** - * add a className to the given elements style - * @param {Element} elem - * @param {String} className - */ -util.addClassName = function addClassName(elem, className) { - var classes = elem.className.split(' '); - if (classes.indexOf(className) == -1) { - classes.push(className); // add the class to the array - elem.className = classes.join(' '); - } -}; - -/** - * add a className to the given elements style - * @param {Element} elem - * @param {String} className - */ -util.removeClassName = function removeClassname(elem, className) { - var classes = elem.className.split(' '); - var index = classes.indexOf(className); - if (index != -1) { - classes.splice(index, 1); // remove the class from the array - elem.className = classes.join(' '); - } -}; - -/** - * For each method for both arrays and objects. - * In case of an array, the built-in Array.forEach() is applied. - * In case of an Object, the method loops over all properties of the object. - * @param {Object | Array} object An Object or Array - * @param {function} callback Callback method, called for each item in - * the object or array with three parameters: - * callback(value, index, object) - */ -util.forEach = function forEach (object, callback) { - var i, - len; - if (object instanceof Array) { - // array - for (i = 0, len = object.length; i < len; i++) { - callback(object[i], i, object); - } - } - else { - // object - for (i in object) { - if (object.hasOwnProperty(i)) { - callback(object[i], i, object); - } - } - } -}; - -/** - * Update a property in an object - * @param {Object} object - * @param {String} key - * @param {*} value - * @return {Boolean} changed - */ -util.updateProperty = function updateProp (object, key, value) { - if (object[key] !== value) { - object[key] = value; - return true; - } - else { - return false; - } -}; - -/** - * Add and event listener. Works for all browsers - * @param {Element} element An html element - * @param {string} action The action, for example "click", - * without the prefix "on" - * @param {function} listener The callback function to be executed - * @param {boolean} [useCapture] - */ -util.addEventListener = function addEventListener(element, action, listener, useCapture) { - if (element.addEventListener) { - if (useCapture === undefined) - useCapture = false; - - if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) { - action = "DOMMouseScroll"; // For Firefox - } - - element.addEventListener(action, listener, useCapture); - } else { - element.attachEvent("on" + action, listener); // IE browsers - } -}; - -/** - * Remove an event listener from an element - * @param {Element} element An html dom element - * @param {string} action The name of the event, for example "mousedown" - * @param {function} listener The listener function - * @param {boolean} [useCapture] - */ -util.removeEventListener = function removeEventListener(element, action, listener, useCapture) { - if (element.removeEventListener) { - // non-IE browsers - if (useCapture === undefined) - useCapture = false; - - if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) { - action = "DOMMouseScroll"; // For Firefox - } - - element.removeEventListener(action, listener, useCapture); - } else { - // IE browsers - element.detachEvent("on" + action, listener); - } -}; - - -/** - * Get HTML element which is the target of the event - * @param {Event} event - * @return {Element} target element - */ -util.getTarget = function getTarget(event) { - // code from http://www.quirksmode.org/js/events_properties.html - if (!event) { - event = window.event; - } - - var target; - - if (event.target) { - target = event.target; - } - else if (event.srcElement) { - target = event.srcElement; - } - - if (target.nodeType != undefined && target.nodeType == 3) { - // defeat Safari bug - target = target.parentNode; - } - - return target; -}; - -/** - * Stop event propagation - */ -util.stopPropagation = function stopPropagation(event) { - if (!event) - event = window.event; - - if (event.stopPropagation) { - event.stopPropagation(); // non-IE browsers - } - else { - event.cancelBubble = true; // IE browsers - } -}; - -/** - * Fake a hammer.js gesture. Event can be a ScrollEvent or MouseMoveEvent - * @param {Element} element - * @param {Event} event - */ -util.fakeGesture = function fakeGesture (element, event) { - var eventType = null; - - // for hammer.js 1.0.5 - return Hammer.event.collectEventData(this, eventType, event); - - // for hammer.js 1.0.6 - //var touches = Hammer.event.getTouchList(event, eventType); - //return Hammer.event.collectEventData(this, eventType, touches, event); -}; - -/** - * Cancels the event if it is cancelable, without stopping further propagation of the event. - */ -util.preventDefault = function preventDefault (event) { - if (!event) - event = window.event; - - if (event.preventDefault) { - event.preventDefault(); // non-IE browsers - } - else { - event.returnValue = false; // IE browsers - } -}; - - -util.option = {}; - -/** - * Convert a value into a boolean - * @param {Boolean | function | undefined} value - * @param {Boolean} [defaultValue] - * @returns {Boolean} bool - */ -util.option.asBoolean = function (value, defaultValue) { - if (typeof value == 'function') { - value = value(); - } - - if (value != null) { - return (value != false); - } - - return defaultValue || null; -}; - -/** - * Convert a value into a number - * @param {Boolean | function | undefined} value - * @param {Number} [defaultValue] - * @returns {Number} number - */ -util.option.asNumber = function (value, defaultValue) { - if (typeof value == 'function') { - value = value(); - } - - if (value != null) { - return Number(value) || defaultValue || null; - } - - return defaultValue || null; -}; - -/** - * Convert a value into a string - * @param {String | function | undefined} value - * @param {String} [defaultValue] - * @returns {String} str - */ -util.option.asString = function (value, defaultValue) { - if (typeof value == 'function') { - value = value(); - } - - if (value != null) { - return String(value); - } - - return defaultValue || null; -}; - -/** - * Convert a size or location into a string with pixels or a percentage - * @param {String | Number | function | undefined} value - * @param {String} [defaultValue] - * @returns {String} size - */ -util.option.asSize = function (value, defaultValue) { - if (typeof value == 'function') { - value = value(); - } - - if (util.isString(value)) { - return value; - } - else if (util.isNumber(value)) { - return value + 'px'; - } - else { - return defaultValue || null; - } -}; - -/** - * Convert a value into a DOM element - * @param {HTMLElement | function | undefined} value - * @param {HTMLElement} [defaultValue] - * @returns {HTMLElement | null} dom - */ -util.option.asElement = function (value, defaultValue) { - if (typeof value == 'function') { - value = value(); - } - - return value || defaultValue || null; -}; - - - -util.GiveDec = function GiveDec(Hex) -{ - if(Hex == "A") - Value = 10; - else - if(Hex == "B") - Value = 11; - else - if(Hex == "C") - Value = 12; - else - if(Hex == "D") - Value = 13; - else - if(Hex == "E") - Value = 14; - else - if(Hex == "F") - Value = 15; - else - Value = eval(Hex) - return Value; -} - -util.GiveHex = function GiveHex(Dec) -{ - if(Dec == 10) - Value = "A"; - else - if(Dec == 11) - Value = "B"; - else - if(Dec == 12) - Value = "C"; - else - if(Dec == 13) - Value = "D"; - else - if(Dec == 14) - Value = "E"; - else - if(Dec == 15) - Value = "F"; - else - Value = "" + Dec; - return Value; -} - -/** - * http://www.yellowpipe.com/yis/tools/hex-to-rgb/color-converter.php - * - * @param {String} hex - * @returns {{r: *, g: *, b: *}} - */ -util.hexToRGB = function hexToRGB(hex) { - hex = hex.replace("#","").toUpperCase(); - - var a = util.GiveDec(hex.substring(0, 1)); - var b = util.GiveDec(hex.substring(1, 2)); - var c = util.GiveDec(hex.substring(2, 3)); - var d = util.GiveDec(hex.substring(3, 4)); - var e = util.GiveDec(hex.substring(4, 5)); - var f = util.GiveDec(hex.substring(5, 6)); - - var r = (a * 16) + b; - var g = (c * 16) + d; - var b = (e * 16) + f; - - return {r:r,g:g,b:b}; -}; - -util.RGBToHex = function RGBToHex(red,green,blue) { - var a = util.GiveHex(Math.floor(red / 16)); - var b = util.GiveHex(red % 16); - var c = util.GiveHex(Math.floor(green / 16)); - var d = util.GiveHex(green % 16); - var e = util.GiveHex(Math.floor(blue / 16)); - var f = util.GiveHex(blue % 16); - - var hex = a + b + c + d + e + f; - return "#" + hex; -}; - - -/** - * http://www.javascripter.net/faq/rgb2hsv.htm - * - * @param red - * @param green - * @param blue - * @returns {*} - * @constructor - */ -util.RGBToHSV = function RGBToHSV (red,green,blue) { - red=red/255; green=green/255; blue=blue/255; - var minRGB = Math.min(red,Math.min(green,blue)); - var maxRGB = Math.max(red,Math.max(green,blue)); - - // Black-gray-white - if (minRGB == maxRGB) { - return {h:0,s:0,v:minRGB}; - } - - // Colors other than black-gray-white: - var d = (red==minRGB) ? green-blue : ((blue==minRGB) ? red-green : blue-red); - var h = (red==minRGB) ? 3 : ((blue==minRGB) ? 1 : 5); - var hue = 60*(h - d/(maxRGB - minRGB))/360; - var saturation = (maxRGB - minRGB)/maxRGB; - var value = maxRGB; - return {h:hue,s:saturation,v:value}; -}; - - -/** - * https://gist.github.com/mjijackson/5311256 - * @param hue - * @param saturation - * @param value - * @returns {{r: number, g: number, b: number}} - * @constructor - */ -util.HSVToRGB = function HSVToRGB(h, s, v) { - var r, g, b; - - var i = Math.floor(h * 6); - var f = h * 6 - i; - var p = v * (1 - s); - var q = v * (1 - f * s); - var t = v * (1 - (1 - f) * s); - - switch (i % 6) { - case 0: r = v, g = t, b = p; break; - case 1: r = q, g = v, b = p; break; - case 2: r = p, g = v, b = t; break; - case 3: r = p, g = q, b = v; break; - case 4: r = t, g = p, b = v; break; - case 5: r = v, g = p, b = q; break; - } - - return {r:Math.floor(r * 255), g:Math.floor(g * 255), b:Math.floor(b * 255) }; -}; - -util.HSVToHex = function HSVToHex(h,s,v) { - var rgb = util.HSVToRGB(h,s,v); - return util.RGBToHex(rgb.r,rgb.g,rgb.b); -} - -util.hexToHSV = function hexToHSV(hex) { - var rgb = util.hexToRGB(hex); - return util.RGBToHSV(rgb.r,rgb.g,rgb.b); -} - - -/** - * Event listener (singleton) - */ -// TODO: replace usage of the event listener for the EventBus -var events = { - 'listeners': [], - - /** - * Find a single listener by its object - * @param {Object} object - * @return {Number} index -1 when not found - */ - 'indexOf': function (object) { - var listeners = this.listeners; - for (var i = 0, iMax = this.listeners.length; i < iMax; i++) { - var listener = listeners[i]; - if (listener && listener.object == object) { - return i; - } - } - return -1; - }, - - /** - * Add an event listener - * @param {Object} object - * @param {String} event The name of an event, for example 'select' - * @param {function} callback The callback method, called when the - * event takes place - */ - 'addListener': function (object, event, callback) { - var index = this.indexOf(object); - var listener = this.listeners[index]; - if (!listener) { - listener = { - 'object': object, - 'events': {} - }; - this.listeners.push(listener); - } - - var callbacks = listener.events[event]; - if (!callbacks) { - callbacks = []; - listener.events[event] = callbacks; - } - - // add the callback if it does not yet exist - if (callbacks.indexOf(callback) == -1) { - callbacks.push(callback); - } - }, - - /** - * Remove an event listener - * @param {Object} object - * @param {String} event The name of an event, for example 'select' - * @param {function} callback The registered callback method - */ - 'removeListener': function (object, event, callback) { - var index = this.indexOf(object); - var listener = this.listeners[index]; - if (listener) { - var callbacks = listener.events[event]; - if (callbacks) { - index = callbacks.indexOf(callback); - if (index != -1) { - callbacks.splice(index, 1); - } - - // remove the array when empty - if (callbacks.length == 0) { - delete listener.events[event]; - } - } - - // count the number of registered events. remove listener when empty - var count = 0; - var events = listener.events; - for (var e in events) { - if (events.hasOwnProperty(e)) { - count++; - } - } - if (count == 0) { - delete this.listeners[index]; - } - } - }, - - /** - * Remove all registered event listeners - */ - 'removeAllListeners': function () { - this.listeners = []; - }, - - /** - * Trigger an event. All registered event handlers will be called - * @param {Object} object - * @param {String} event - * @param {Object} properties (optional) - */ - 'trigger': function (object, event, properties) { - var index = this.indexOf(object); - var listener = this.listeners[index]; - if (listener) { - var callbacks = listener.events[event]; - if (callbacks) { - for (var i = 0, iMax = callbacks.length; i < iMax; i++) { - callbacks[i](properties); - } - } - } - } -}; - -/** - * An event bus can be used to emit events, and to subscribe to events - * @constructor EventBus - */ -function EventBus() { - this.subscriptions = []; -} - -/** - * Subscribe to an event - * @param {String | RegExp} event The event can be a regular expression, or - * a string with wildcards, like 'server.*'. - * @param {function} callback. Callback are called with three parameters: - * {String} event, {*} [data], {*} [source] - * @param {*} [target] - * @returns {String} id A subscription id - */ -EventBus.prototype.on = function (event, callback, target) { - var regexp = (event instanceof RegExp) ? - event : - new RegExp(event.replace('*', '\\w+')); - - var subscription = { - id: util.randomUUID(), - event: event, - regexp: regexp, - callback: (typeof callback === 'function') ? callback : null, - target: target - }; - - this.subscriptions.push(subscription); - - return subscription.id; -}; - -/** - * Unsubscribe from an event - * @param {String | Object} filter Filter for subscriptions to be removed - * Filter can be a string containing a - * subscription id, or an object containing - * one or more of the fields id, event, - * callback, and target. - */ -EventBus.prototype.off = function (filter) { - var i = 0; - while (i < this.subscriptions.length) { - var subscription = this.subscriptions[i]; - - var match = true; - if (filter instanceof Object) { - // filter is an object. All fields must match - for (var prop in filter) { - if (filter.hasOwnProperty(prop)) { - if (filter[prop] !== subscription[prop]) { - match = false; - } - } - } - } - else { - // filter is a string, filter on id - match = (subscription.id == filter); - } - - if (match) { - this.subscriptions.splice(i, 1); - } - else { - i++; - } - } -}; - -/** - * Emit an event - * @param {String} event - * @param {*} [data] - * @param {*} [source] - */ -EventBus.prototype.emit = function (event, data, source) { - for (var i =0; i < this.subscriptions.length; i++) { - var subscription = this.subscriptions[i]; - if (subscription.regexp.test(event)) { - if (subscription.callback) { - subscription.callback(event, data, source); - } - } - } -}; - -/** - * DataSet - * - * Usage: - * var dataSet = new DataSet({ - * fieldId: '_id', - * convert: { - * // ... - * } - * }); - * - * dataSet.add(item); - * dataSet.add(data); - * dataSet.update(item); - * dataSet.update(data); - * dataSet.remove(id); - * dataSet.remove(ids); - * var data = dataSet.get(); - * var data = dataSet.get(id); - * var data = dataSet.get(ids); - * var data = dataSet.get(ids, options, data); - * dataSet.clear(); - * - * A data set can: - * - add/remove/update data - * - gives triggers upon changes in the data - * - can import/export data in various data formats - * - * @param {Object} [options] Available options: - * {String} fieldId Field name of the id in the - * items, 'id' by default. - * {Object.} [convert] - * {String[]} [fields] field names to be returned - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * {Array | DataTable} [data] If provided, items will be appended to this - * array or table. Required in case of Google - * DataTable. - * - * @throws Error - */ -DataSet.prototype.get = function (args) { - var me = this; - var globalShowInternalIds = this.showInternalIds; - - // parse the arguments - var id, ids, options, data; - var firstType = util.getType(arguments[0]); - if (firstType == 'String' || firstType == 'Number') { - // get(id [, options] [, data]) - id = arguments[0]; - options = arguments[1]; - data = arguments[2]; - } - else if (firstType == 'Array') { - // get(ids [, options] [, data]) - ids = arguments[0]; - options = arguments[1]; - data = arguments[2]; - } - else { - // get([, options] [, data]) - options = arguments[0]; - data = arguments[1]; - } - - // determine the return type - var type; - if (options && options.type) { - type = (options.type == 'DataTable') ? 'DataTable' : 'Array'; - - if (data && (type != util.getType(data))) { - throw new Error('Type of parameter "data" (' + util.getType(data) + ') ' + - 'does not correspond with specified options.type (' + options.type + ')'); - } - if (type == 'DataTable' && !util.isDataTable(data)) { - throw new Error('Parameter "data" must be a DataTable ' + - 'when options.type is "DataTable"'); - } - } - else if (data) { - type = (util.getType(data) == 'DataTable') ? 'DataTable' : 'Array'; - } - else { - type = 'Array'; - } - - // we allow the setting of this value for a single get request. - if (options != undefined) { - if (options.showInternalIds != undefined) { - this.showInternalIds = options.showInternalIds; - } - } - - // build options - var convert = options && options.convert || this.options.convert; - var filter = options && options.filter; - var items = [], item, itemId, i, len; - - // convert items - if (id != undefined) { - // return a single item - item = me._getItem(id, convert); - if (filter && !filter(item)) { - item = null; - } - } - else if (ids != undefined) { - // return a subset of items - for (i = 0, len = ids.length; i < len; i++) { - item = me._getItem(ids[i], convert); - if (!filter || filter(item)) { - items.push(item); - } - } - } - else { - // return all items - for (itemId in this.data) { - if (this.data.hasOwnProperty(itemId)) { - item = me._getItem(itemId, convert); - if (!filter || filter(item)) { - items.push(item); - } - } - } - } - - // restore the global value of showInternalIds - this.showInternalIds = globalShowInternalIds; - - // order the results - if (options && options.order && id == undefined) { - this._sort(items, options.order); - } - - // filter fields of the items - if (options && options.fields) { - var fields = options.fields; - if (id != undefined) { - item = this._filterFields(item, fields); - } - else { - for (i = 0, len = items.length; i < len; i++) { - items[i] = this._filterFields(items[i], fields); - } - } - } - - // return the results - if (type == 'DataTable') { - var columns = this._getColumnNames(data); - if (id != undefined) { - // append a single item to the data table - me._appendRow(data, columns, item); - } - else { - // copy the items to the provided data table - for (i = 0, len = items.length; i < len; i++) { - me._appendRow(data, columns, items[i]); - } - } - return data; - } - else { - // return an array - if (id != undefined) { - // a single item - return item; - } - else { - // multiple items - if (data) { - // copy the items to the provided array - for (i = 0, len = items.length; i < len; i++) { - data.push(items[i]); - } - return data; - } - else { - // just return our array - return items; - } - } - } -}; - -/** - * Get ids of all items or from a filtered set of items. - * @param {Object} [options] An Object with options. Available options: - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * @return {Array} ids - */ -DataSet.prototype.getIds = function (options) { - var data = this.data, - filter = options && options.filter, - order = options && options.order, - convert = options && options.convert || this.options.convert, - i, - len, - id, - item, - items, - ids = []; - - if (filter) { - // get filtered items - if (order) { - // create ordered list - items = []; - for (id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, convert); - if (filter(item)) { - items.push(item); - } - } - } - - this._sort(items, order); - - for (i = 0, len = items.length; i < len; i++) { - ids[i] = items[i][this.fieldId]; - } - } - else { - // create unordered list - for (id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, convert); - if (filter(item)) { - ids.push(item[this.fieldId]); - } - } - } - } - } - else { - // get all items - if (order) { - // create an ordered list - items = []; - for (id in data) { - if (data.hasOwnProperty(id)) { - items.push(data[id]); - } - } - - this._sort(items, order); - - for (i = 0, len = items.length; i < len; i++) { - ids[i] = items[i][this.fieldId]; - } - } - else { - // create unordered list - for (id in data) { - if (data.hasOwnProperty(id)) { - item = data[id]; - ids.push(item[this.fieldId]); - } - } - } - } - - return ids; -}; - -/** - * Execute a callback function for every item in the dataset. - * The order of the items is not determined. - * @param {function} callback - * @param {Object} [options] Available options: - * {Object.} [convert] - * {String[]} [fields] filter fields - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - */ -DataSet.prototype.forEach = function (callback, options) { - var filter = options && options.filter, - convert = options && options.convert || this.options.convert, - data = this.data, - item, - id; - - if (options && options.order) { - // execute forEach on ordered list - var items = this.get(options); - - for (var i = 0, len = items.length; i < len; i++) { - item = items[i]; - id = item[this.fieldId]; - callback(item, id); - } - } - else { - // unordered - for (id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, convert); - if (!filter || filter(item)) { - callback(item, id); - } - } - } - } -}; - -/** - * Map every item in the dataset. - * @param {function} callback - * @param {Object} [options] Available options: - * {Object.} [convert] - * {String[]} [fields] filter fields - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * @return {Object[]} mappedItems - */ -DataSet.prototype.map = function (callback, options) { - var filter = options && options.filter, - convert = options && options.convert || this.options.convert, - mappedItems = [], - data = this.data, - item; - - // convert and filter items - for (var id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, convert); - if (!filter || filter(item)) { - mappedItems.push(callback(item, id)); - } - } - } - - // order items - if (options && options.order) { - this._sort(mappedItems, options.order); - } - - return mappedItems; -}; - -/** - * Filter the fields of an item - * @param {Object} item - * @param {String[]} fields Field names - * @return {Object} filteredItem - * @private - */ -DataSet.prototype._filterFields = function (item, fields) { - var filteredItem = {}; - - for (var field in item) { - if (item.hasOwnProperty(field) && (fields.indexOf(field) != -1)) { - filteredItem[field] = item[field]; - } - } - - return filteredItem; -}; - -/** - * Sort the provided array with items - * @param {Object[]} items - * @param {String | function} order A field name or custom sort function. - * @private - */ -DataSet.prototype._sort = function (items, order) { - if (util.isString(order)) { - // order by provided field name - var name = order; // field name - items.sort(function (a, b) { - var av = a[name]; - var bv = b[name]; - return (av > bv) ? 1 : ((av < bv) ? -1 : 0); - }); - } - else if (typeof order === 'function') { - // order by sort function - items.sort(order); - } - // TODO: extend order by an Object {field:String, direction:String} - // where direction can be 'asc' or 'desc' - else { - throw new TypeError('Order must be a function or a string'); - } -}; - -/** - * Remove an object by pointer or by id - * @param {String | Number | Object | Array} id Object or id, or an array with - * objects or ids to be removed - * @param {String} [senderId] Optional sender id - * @return {Array} removedIds - */ -DataSet.prototype.remove = function (id, senderId) { - var removedIds = [], - i, len, removedId; - - if (id instanceof Array) { - for (i = 0, len = id.length; i < len; i++) { - removedId = this._remove(id[i]); - if (removedId != null) { - removedIds.push(removedId); - } - } - } - else { - removedId = this._remove(id); - if (removedId != null) { - removedIds.push(removedId); - } - } - - if (removedIds.length) { - this._trigger('remove', {items: removedIds}, senderId); - } - - return removedIds; -}; - -/** - * Remove an item by its id - * @param {Number | String | Object} id id or item - * @returns {Number | String | null} id - * @private - */ -DataSet.prototype._remove = function (id) { - if (util.isNumber(id) || util.isString(id)) { - if (this.data[id]) { - delete this.data[id]; - delete this.internalIds[id]; - return id; - } - } - else if (id instanceof Object) { - var itemId = id[this.fieldId]; - if (itemId && this.data[itemId]) { - delete this.data[itemId]; - delete this.internalIds[itemId]; - return itemId; - } - } - return null; -}; - -/** - * Clear the data - * @param {String} [senderId] Optional sender id - * @return {Array} removedIds The ids of all removed items - */ -DataSet.prototype.clear = function (senderId) { - var ids = Object.keys(this.data); - - this.data = {}; - this.internalIds = {}; - - this._trigger('remove', {items: ids}, senderId); - - return ids; -}; - -/** - * Find the item with maximum value of a specified field - * @param {String} field - * @return {Object | null} item Item containing max value, or null if no items - */ -DataSet.prototype.max = function (field) { - var data = this.data, - max = null, - maxField = null; - - for (var id in data) { - if (data.hasOwnProperty(id)) { - var item = data[id]; - var itemField = item[field]; - if (itemField != null && (!max || itemField > maxField)) { - max = item; - maxField = itemField; - } - } - } - - return max; -}; - -/** - * Find the item with minimum value of a specified field - * @param {String} field - * @return {Object | null} item Item containing max value, or null if no items - */ -DataSet.prototype.min = function (field) { - var data = this.data, - min = null, - minField = null; - - for (var id in data) { - if (data.hasOwnProperty(id)) { - var item = data[id]; - var itemField = item[field]; - if (itemField != null && (!min || itemField < minField)) { - min = item; - minField = itemField; - } - } - } - - return min; -}; - -/** - * Find all distinct values of a specified field - * @param {String} field - * @return {Array} values Array containing all distinct values. If the data - * items do not contain the specified field, an array - * containing a single value undefined is returned. - * The returned array is unordered. - */ -DataSet.prototype.distinct = function (field) { - var data = this.data, - values = [], - fieldType = this.options.convert[field], - count = 0; - - for (var prop in data) { - if (data.hasOwnProperty(prop)) { - var item = data[prop]; - var value = util.convert(item[field], fieldType); - var exists = false; - for (var i = 0; i < count; i++) { - if (values[i] == value) { - exists = true; - break; - } - } - if (!exists) { - values[count] = value; - count++; - } - } - } - - return values; -}; - -/** - * Add a single item. Will fail when an item with the same id already exists. - * @param {Object} item - * @return {String} id - * @private - */ -DataSet.prototype._addItem = function (item) { - var id = item[this.fieldId]; - - if (id != undefined) { - // check whether this id is already taken - if (this.data[id]) { - // item already exists - throw new Error('Cannot add item: item with id ' + id + ' already exists'); - } - } - else { - // generate an id - id = util.randomUUID(); - item[this.fieldId] = id; - this.internalIds[id] = item; - } - - var d = {}; - for (var field in item) { - if (item.hasOwnProperty(field)) { - var fieldType = this.convert[field]; // type may be undefined - d[field] = util.convert(item[field], fieldType); - } - } - this.data[id] = d; - - return id; -}; - -/** - * Get an item. Fields can be converted to a specific type - * @param {String} id - * @param {Object.} [convert] field types to convert - * @return {Object | null} item - * @private - */ -DataSet.prototype._getItem = function (id, convert) { - var field, value; - - // get the item from the dataset - var raw = this.data[id]; - if (!raw) { - return null; - } - - // convert the items field types - var converted = {}, - fieldId = this.fieldId, - internalIds = this.internalIds; - if (convert) { - for (field in raw) { - if (raw.hasOwnProperty(field)) { - value = raw[field]; - // output all fields, except internal ids - if ((field != fieldId) || (!(value in internalIds) || this.showInternalIds)) { - converted[field] = util.convert(value, convert[field]); - } - } - } - } - else { - // no field types specified, no converting needed - for (field in raw) { - if (raw.hasOwnProperty(field)) { - value = raw[field]; - // output all fields, except internal ids - if ((field != fieldId) || (!(value in internalIds) || this.showInternalIds)) { - converted[field] = value; - } - } - } - } - return converted; -}; - -/** - * Update a single item: merge with existing item. - * Will fail when the item has no id, or when there does not exist an item - * with the same id. - * @param {Object} item - * @return {String} id - * @private - */ -DataSet.prototype._updateItem = function (item) { - var id = item[this.fieldId]; - if (id == undefined) { - throw new Error('Cannot update item: item has no id (item: ' + JSON.stringify(item) + ')'); - } - var d = this.data[id]; - if (!d) { - // item doesn't exist - throw new Error('Cannot update item: no item with id ' + id + ' found'); - } - - // merge with current item - for (var field in item) { - if (item.hasOwnProperty(field)) { - var fieldType = this.convert[field]; // type may be undefined - d[field] = util.convert(item[field], fieldType); - } - } - - return id; -}; - -/** - * check if an id is an internal or external id - * @param id - * @returns {boolean} - * @private - */ -DataSet.prototype.isInternalId = function(id) { - return (id in this.internalIds); -}; - - -/** - * Get an array with the column names of a Google DataTable - * @param {DataTable} dataTable - * @return {String[]} columnNames - * @private - */ -DataSet.prototype._getColumnNames = function (dataTable) { - var columns = []; - for (var col = 0, cols = dataTable.getNumberOfColumns(); col < cols; col++) { - columns[col] = dataTable.getColumnId(col) || dataTable.getColumnLabel(col); - } - return columns; -}; - -/** - * Append an item as a row to the dataTable - * @param dataTable - * @param columns - * @param item - * @private - */ -DataSet.prototype._appendRow = function (dataTable, columns, item) { - var row = dataTable.addRow(); - - for (var col = 0, cols = columns.length; col < cols; col++) { - var field = columns[col]; - dataTable.setValue(row, col, item[field]); - } -}; - -/** - * DataView - * - * a dataview offers a filtered view on a dataset or an other dataview. - * - * @param {DataSet | DataView} data - * @param {Object} [options] Available options: see method get - * - * @constructor DataView - */ -function DataView (data, options) { - this.id = util.randomUUID(); - - this.data = null; - this.ids = {}; // ids of the items currently in memory (just contains a boolean true) - this.options = options || {}; - this.fieldId = 'id'; // name of the field containing id - this.subscribers = {}; // event subscribers - - var me = this; - this.listener = function () { - me._onEvent.apply(me, arguments); - }; - - this.setData(data); -} - -// TODO: implement a function .config() to dynamically update things like configured filter -// and trigger changes accordingly - -/** - * Set a data source for the view - * @param {DataSet | DataView} data - */ -DataView.prototype.setData = function (data) { - var ids, dataItems, i, len; - - if (this.data) { - // unsubscribe from current dataset - if (this.data.unsubscribe) { - this.data.unsubscribe('*', this.listener); - } - - // trigger a remove of all items in memory - ids = []; - for (var id in this.ids) { - if (this.ids.hasOwnProperty(id)) { - ids.push(id); - } - } - this.ids = {}; - this._trigger('remove', {items: ids}); - } - - this.data = data; - - if (this.data) { - // update fieldId - this.fieldId = this.options.fieldId || - (this.data && this.data.options && this.data.options.fieldId) || - 'id'; - - // trigger an add of all added items - ids = this.data.getIds({filter: this.options && this.options.filter}); - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - this.ids[id] = true; - } - this._trigger('add', {items: ids}); - - // subscribe to new dataset - if (this.data.subscribe) { - this.data.subscribe('*', this.listener); - } - } -}; - -/** - * Get data from the data view - * - * Usage: - * - * get() - * get(options: Object) - * get(options: Object, data: Array | DataTable) - * - * get(id: Number) - * get(id: Number, options: Object) - * get(id: Number, options: Object, data: Array | DataTable) - * - * get(ids: Number[]) - * get(ids: Number[], options: Object) - * get(ids: Number[], options: Object, data: Array | DataTable) - * - * Where: - * - * {Number | String} id The id of an item - * {Number[] | String{}} ids An array with ids of items - * {Object} options An Object with options. Available options: - * {String} [type] Type of data to be returned. Can - * be 'DataTable' or 'Array' (default) - * {Object.} [convert] - * {String[]} [fields] field names to be returned - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * {Array | DataTable} [data] If provided, items will be appended to this - * array or table. Required in case of Google - * DataTable. - * @param args - */ -DataView.prototype.get = function (args) { - var me = this; - - // parse the arguments - var ids, options, data; - var firstType = util.getType(arguments[0]); - if (firstType == 'String' || firstType == 'Number' || firstType == 'Array') { - // get(id(s) [, options] [, data]) - ids = arguments[0]; // can be a single id or an array with ids - options = arguments[1]; - data = arguments[2]; - } - else { - // get([, options] [, data]) - options = arguments[0]; - data = arguments[1]; - } - - // extend the options with the default options and provided options - var viewOptions = util.extend({}, this.options, options); - - // create a combined filter method when needed - if (this.options.filter && options && options.filter) { - viewOptions.filter = function (item) { - return me.options.filter(item) && options.filter(item); - } - } - - // build up the call to the linked data set - var getArguments = []; - if (ids != undefined) { - getArguments.push(ids); - } - getArguments.push(viewOptions); - getArguments.push(data); - - return this.data && this.data.get.apply(this.data, getArguments); -}; - -/** - * Get ids of all items or from a filtered set of items. - * @param {Object} [options] An Object with options. Available options: - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * @return {Array} ids - */ -DataView.prototype.getIds = function (options) { - var ids; - - if (this.data) { - var defaultFilter = this.options.filter; - var filter; - - if (options && options.filter) { - if (defaultFilter) { - filter = function (item) { - return defaultFilter(item) && options.filter(item); - } - } - else { - filter = options.filter; - } - } - else { - filter = defaultFilter; - } - - ids = this.data.getIds({ - filter: filter, - order: options && options.order - }); - } - else { - ids = []; - } - - return ids; -}; - -/** - * Event listener. Will propagate all events from the connected data set to - * the subscribers of the DataView, but will filter the items and only trigger - * when there are changes in the filtered data set. - * @param {String} event - * @param {Object | null} params - * @param {String} senderId - * @private - */ -DataView.prototype._onEvent = function (event, params, senderId) { - var i, len, id, item, - ids = params && params.items, - data = this.data, - added = [], - updated = [], - removed = []; - - if (ids && data) { - switch (event) { - case 'add': - // filter the ids of the added items - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - item = this.get(id); - if (item) { - this.ids[id] = true; - added.push(id); - } - } - - break; - - case 'update': - // determine the event from the views viewpoint: an updated - // item can be added, updated, or removed from this view. - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - item = this.get(id); - - if (item) { - if (this.ids[id]) { - updated.push(id); - } - else { - this.ids[id] = true; - added.push(id); - } - } - else { - if (this.ids[id]) { - delete this.ids[id]; - removed.push(id); - } - else { - // nothing interesting for me :-( - } - } - } - - break; - - case 'remove': - // filter the ids of the removed items - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - if (this.ids[id]) { - delete this.ids[id]; - removed.push(id); - } - } - - break; - } - - if (added.length) { - this._trigger('add', {items: added}, senderId); - } - if (updated.length) { - this._trigger('update', {items: updated}, senderId); - } - if (removed.length) { - this._trigger('remove', {items: removed}, senderId); - } - } -}; - -// copy subscription functionality from DataSet -DataView.prototype.subscribe = DataSet.prototype.subscribe; -DataView.prototype.unsubscribe = DataSet.prototype.unsubscribe; -DataView.prototype._trigger = DataSet.prototype._trigger; - -/** - * @constructor TimeStep - * The class TimeStep is an iterator for dates. You provide a start date and an - * end date. The class itself determines the best scale (step size) based on the - * provided start Date, end Date, and minimumStep. - * - * If minimumStep is provided, the step size is chosen as close as possible - * to the minimumStep but larger than minimumStep. If minimumStep is not - * provided, the scale is set to 1 DAY. - * The minimumStep should correspond with the onscreen size of about 6 characters - * - * Alternatively, you can set a scale by hand. - * After creation, you can initialize the class by executing first(). Then you - * can iterate from the start date to the end date via next(). You can check if - * the end date is reached with the function hasNext(). After each step, you can - * retrieve the current date via getCurrent(). - * The TimeStep has scales ranging from milliseconds, seconds, minutes, hours, - * days, to years. - * - * Version: 1.2 - * - * @param {Date} [start] The start date, for example new Date(2010, 9, 21) - * or new Date(2010, 9, 21, 23, 45, 00) - * @param {Date} [end] The end date - * @param {Number} [minimumStep] Optional. Minimum step size in milliseconds - */ -TimeStep = function(start, end, minimumStep) { - // variables - this.current = new Date(); - this._start = new Date(); - this._end = new Date(); - - this.autoScale = true; - this.scale = TimeStep.SCALE.DAY; - this.step = 1; - - // initialize the range - this.setRange(start, end, minimumStep); -}; - -/// enum scale -TimeStep.SCALE = { - MILLISECOND: 1, - SECOND: 2, - MINUTE: 3, - HOUR: 4, - DAY: 5, - WEEKDAY: 6, - MONTH: 7, - YEAR: 8 -}; - - -/** - * Set a new range - * If minimumStep is provided, the step size is chosen as close as possible - * to the minimumStep but larger than minimumStep. If minimumStep is not - * provided, the scale is set to 1 DAY. - * The minimumStep should correspond with the onscreen size of about 6 characters - * @param {Date} [start] The start date and time. - * @param {Date} [end] The end date and time. - * @param {int} [minimumStep] Optional. Minimum step size in milliseconds - */ -TimeStep.prototype.setRange = function(start, end, minimumStep) { - if (!(start instanceof Date) || !(end instanceof Date)) { - throw "No legal start or end date in method setRange"; - } - - this._start = (start != undefined) ? new Date(start.valueOf()) : new Date(); - this._end = (end != undefined) ? new Date(end.valueOf()) : new Date(); - - if (this.autoScale) { - this.setMinimumStep(minimumStep); - } -}; - -/** - * Set the range iterator to the start date. - */ -TimeStep.prototype.first = function() { - this.current = new Date(this._start.valueOf()); - this.roundToMinor(); -}; - -/** - * Round the current date to the first minor date value - * This must be executed once when the current date is set to start Date - */ -TimeStep.prototype.roundToMinor = function() { - // round to floor - // IMPORTANT: we have no breaks in this switch! (this is no bug) - //noinspection FallthroughInSwitchStatementJS - switch (this.scale) { - case TimeStep.SCALE.YEAR: - this.current.setFullYear(this.step * Math.floor(this.current.getFullYear() / this.step)); - this.current.setMonth(0); - case TimeStep.SCALE.MONTH: this.current.setDate(1); - case TimeStep.SCALE.DAY: // intentional fall through - case TimeStep.SCALE.WEEKDAY: this.current.setHours(0); - case TimeStep.SCALE.HOUR: this.current.setMinutes(0); - case TimeStep.SCALE.MINUTE: this.current.setSeconds(0); - case TimeStep.SCALE.SECOND: this.current.setMilliseconds(0); - //case TimeStep.SCALE.MILLISECOND: // nothing to do for milliseconds - } - - if (this.step != 1) { - // round down to the first minor value that is a multiple of the current step size - switch (this.scale) { - case TimeStep.SCALE.MILLISECOND: this.current.setMilliseconds(this.current.getMilliseconds() - this.current.getMilliseconds() % this.step); break; - case TimeStep.SCALE.SECOND: this.current.setSeconds(this.current.getSeconds() - this.current.getSeconds() % this.step); break; - case TimeStep.SCALE.MINUTE: this.current.setMinutes(this.current.getMinutes() - this.current.getMinutes() % this.step); break; - case TimeStep.SCALE.HOUR: this.current.setHours(this.current.getHours() - this.current.getHours() % this.step); break; - case TimeStep.SCALE.WEEKDAY: // intentional fall through - case TimeStep.SCALE.DAY: this.current.setDate((this.current.getDate()-1) - (this.current.getDate()-1) % this.step + 1); break; - case TimeStep.SCALE.MONTH: this.current.setMonth(this.current.getMonth() - this.current.getMonth() % this.step); break; - case TimeStep.SCALE.YEAR: this.current.setFullYear(this.current.getFullYear() - this.current.getFullYear() % this.step); break; - default: break; - } - } -}; - -/** - * Check if the there is a next step - * @return {boolean} true if the current date has not passed the end date - */ -TimeStep.prototype.hasNext = function () { - return (this.current.valueOf() <= this._end.valueOf()); -}; - -/** - * Do the next step - */ -TimeStep.prototype.next = function() { - var prev = this.current.valueOf(); - - // Two cases, needed to prevent issues with switching daylight savings - // (end of March and end of October) - if (this.current.getMonth() < 6) { - switch (this.scale) { - case TimeStep.SCALE.MILLISECOND: - - this.current = new Date(this.current.valueOf() + this.step); break; - case TimeStep.SCALE.SECOND: this.current = new Date(this.current.valueOf() + this.step * 1000); break; - case TimeStep.SCALE.MINUTE: this.current = new Date(this.current.valueOf() + this.step * 1000 * 60); break; - case TimeStep.SCALE.HOUR: - this.current = new Date(this.current.valueOf() + this.step * 1000 * 60 * 60); - // in case of skipping an hour for daylight savings, adjust the hour again (else you get: 0h 5h 9h ... instead of 0h 4h 8h ...) - var h = this.current.getHours(); - this.current.setHours(h - (h % this.step)); - break; - case TimeStep.SCALE.WEEKDAY: // intentional fall through - case TimeStep.SCALE.DAY: this.current.setDate(this.current.getDate() + this.step); break; - case TimeStep.SCALE.MONTH: this.current.setMonth(this.current.getMonth() + this.step); break; - case TimeStep.SCALE.YEAR: this.current.setFullYear(this.current.getFullYear() + this.step); break; - default: break; - } - } - else { - switch (this.scale) { - case TimeStep.SCALE.MILLISECOND: this.current = new Date(this.current.valueOf() + this.step); break; - case TimeStep.SCALE.SECOND: this.current.setSeconds(this.current.getSeconds() + this.step); break; - case TimeStep.SCALE.MINUTE: this.current.setMinutes(this.current.getMinutes() + this.step); break; - case TimeStep.SCALE.HOUR: this.current.setHours(this.current.getHours() + this.step); break; - case TimeStep.SCALE.WEEKDAY: // intentional fall through - case TimeStep.SCALE.DAY: this.current.setDate(this.current.getDate() + this.step); break; - case TimeStep.SCALE.MONTH: this.current.setMonth(this.current.getMonth() + this.step); break; - case TimeStep.SCALE.YEAR: this.current.setFullYear(this.current.getFullYear() + this.step); break; - default: break; - } - } - - if (this.step != 1) { - // round down to the correct major value - switch (this.scale) { - case TimeStep.SCALE.MILLISECOND: if(this.current.getMilliseconds() < this.step) this.current.setMilliseconds(0); break; - case TimeStep.SCALE.SECOND: if(this.current.getSeconds() < this.step) this.current.setSeconds(0); break; - case TimeStep.SCALE.MINUTE: if(this.current.getMinutes() < this.step) this.current.setMinutes(0); break; - case TimeStep.SCALE.HOUR: if(this.current.getHours() < this.step) this.current.setHours(0); break; - case TimeStep.SCALE.WEEKDAY: // intentional fall through - case TimeStep.SCALE.DAY: if(this.current.getDate() < this.step+1) this.current.setDate(1); break; - case TimeStep.SCALE.MONTH: if(this.current.getMonth() < this.step) this.current.setMonth(0); break; - case TimeStep.SCALE.YEAR: break; // nothing to do for year - default: break; - } - } - - // safety mechanism: if current time is still unchanged, move to the end - if (this.current.valueOf() == prev) { - this.current = new Date(this._end.valueOf()); - } -}; - - -/** - * Get the current datetime - * @return {Date} current The current date - */ -TimeStep.prototype.getCurrent = function() { - return this.current; -}; - -/** - * Set a custom scale. Autoscaling will be disabled. - * For example setScale(SCALE.MINUTES, 5) will result - * in minor steps of 5 minutes, and major steps of an hour. - * - * @param {TimeStep.SCALE} newScale - * A scale. Choose from SCALE.MILLISECOND, - * SCALE.SECOND, SCALE.MINUTE, SCALE.HOUR, - * SCALE.WEEKDAY, SCALE.DAY, SCALE.MONTH, - * SCALE.YEAR. - * @param {Number} newStep A step size, by default 1. Choose for - * example 1, 2, 5, or 10. - */ -TimeStep.prototype.setScale = function(newScale, newStep) { - this.scale = newScale; - - if (newStep > 0) { - this.step = newStep; - } - - this.autoScale = false; -}; - -/** - * Enable or disable autoscaling - * @param {boolean} enable If true, autoascaling is set true - */ -TimeStep.prototype.setAutoScale = function (enable) { - this.autoScale = enable; -}; - - -/** - * Automatically determine the scale that bests fits the provided minimum step - * @param {Number} [minimumStep] The minimum step size in milliseconds - */ -TimeStep.prototype.setMinimumStep = function(minimumStep) { - if (minimumStep == undefined) { - return; - } - - var stepYear = (1000 * 60 * 60 * 24 * 30 * 12); - var stepMonth = (1000 * 60 * 60 * 24 * 30); - var stepDay = (1000 * 60 * 60 * 24); - var stepHour = (1000 * 60 * 60); - var stepMinute = (1000 * 60); - var stepSecond = (1000); - var stepMillisecond= (1); - - // find the smallest step that is larger than the provided minimumStep - if (stepYear*1000 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 1000;} - if (stepYear*500 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 500;} - if (stepYear*100 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 100;} - if (stepYear*50 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 50;} - if (stepYear*10 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 10;} - if (stepYear*5 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 5;} - if (stepYear > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 1;} - if (stepMonth*3 > minimumStep) {this.scale = TimeStep.SCALE.MONTH; this.step = 3;} - if (stepMonth > minimumStep) {this.scale = TimeStep.SCALE.MONTH; this.step = 1;} - if (stepDay*5 > minimumStep) {this.scale = TimeStep.SCALE.DAY; this.step = 5;} - if (stepDay*2 > minimumStep) {this.scale = TimeStep.SCALE.DAY; this.step = 2;} - if (stepDay > minimumStep) {this.scale = TimeStep.SCALE.DAY; this.step = 1;} - if (stepDay/2 > minimumStep) {this.scale = TimeStep.SCALE.WEEKDAY; this.step = 1;} - if (stepHour*4 > minimumStep) {this.scale = TimeStep.SCALE.HOUR; this.step = 4;} - if (stepHour > minimumStep) {this.scale = TimeStep.SCALE.HOUR; this.step = 1;} - if (stepMinute*15 > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 15;} - if (stepMinute*10 > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 10;} - if (stepMinute*5 > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 5;} - if (stepMinute > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 1;} - if (stepSecond*15 > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 15;} - if (stepSecond*10 > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 10;} - if (stepSecond*5 > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 5;} - if (stepSecond > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 1;} - if (stepMillisecond*200 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 200;} - if (stepMillisecond*100 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 100;} - if (stepMillisecond*50 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 50;} - if (stepMillisecond*10 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 10;} - if (stepMillisecond*5 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 5;} - if (stepMillisecond > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 1;} -}; - -/** - * Snap a date to a rounded value. The snap intervals are dependent on the - * current scale and step. - * @param {Date} date the date to be snapped - */ -TimeStep.prototype.snap = function(date) { - if (this.scale == TimeStep.SCALE.YEAR) { - var year = date.getFullYear() + Math.round(date.getMonth() / 12); - date.setFullYear(Math.round(year / this.step) * this.step); - date.setMonth(0); - date.setDate(0); - date.setHours(0); - date.setMinutes(0); - date.setSeconds(0); - date.setMilliseconds(0); - } - else if (this.scale == TimeStep.SCALE.MONTH) { - if (date.getDate() > 15) { - date.setDate(1); - date.setMonth(date.getMonth() + 1); - // important: first set Date to 1, after that change the month. - } - else { - date.setDate(1); - } - - date.setHours(0); - date.setMinutes(0); - date.setSeconds(0); - date.setMilliseconds(0); - } - else if (this.scale == TimeStep.SCALE.DAY || - this.scale == TimeStep.SCALE.WEEKDAY) { - //noinspection FallthroughInSwitchStatementJS - switch (this.step) { - case 5: - case 2: - date.setHours(Math.round(date.getHours() / 24) * 24); break; - default: - date.setHours(Math.round(date.getHours() / 12) * 12); break; - } - date.setMinutes(0); - date.setSeconds(0); - date.setMilliseconds(0); - } - else if (this.scale == TimeStep.SCALE.HOUR) { - switch (this.step) { - case 4: - date.setMinutes(Math.round(date.getMinutes() / 60) * 60); break; - default: - date.setMinutes(Math.round(date.getMinutes() / 30) * 30); break; - } - date.setSeconds(0); - date.setMilliseconds(0); - } else if (this.scale == TimeStep.SCALE.MINUTE) { - //noinspection FallthroughInSwitchStatementJS - switch (this.step) { - case 15: - case 10: - date.setMinutes(Math.round(date.getMinutes() / 5) * 5); - date.setSeconds(0); - break; - case 5: - date.setSeconds(Math.round(date.getSeconds() / 60) * 60); break; - default: - date.setSeconds(Math.round(date.getSeconds() / 30) * 30); break; - } - date.setMilliseconds(0); - } - else if (this.scale == TimeStep.SCALE.SECOND) { - //noinspection FallthroughInSwitchStatementJS - switch (this.step) { - case 15: - case 10: - date.setSeconds(Math.round(date.getSeconds() / 5) * 5); - date.setMilliseconds(0); - break; - case 5: - date.setMilliseconds(Math.round(date.getMilliseconds() / 1000) * 1000); break; - default: - date.setMilliseconds(Math.round(date.getMilliseconds() / 500) * 500); break; - } - } - else if (this.scale == TimeStep.SCALE.MILLISECOND) { - var step = this.step > 5 ? this.step / 2 : 1; - date.setMilliseconds(Math.round(date.getMilliseconds() / step) * step); - } -}; - -/** - * Check if the current value is a major value (for example when the step - * is DAY, a major value is each first day of the MONTH) - * @return {boolean} true if current date is major, else false. - */ -TimeStep.prototype.isMajor = function() { - switch (this.scale) { - case TimeStep.SCALE.MILLISECOND: - return (this.current.getMilliseconds() == 0); - case TimeStep.SCALE.SECOND: - return (this.current.getSeconds() == 0); - case TimeStep.SCALE.MINUTE: - return (this.current.getHours() == 0) && (this.current.getMinutes() == 0); - // Note: this is no bug. Major label is equal for both minute and hour scale - case TimeStep.SCALE.HOUR: - return (this.current.getHours() == 0); - case TimeStep.SCALE.WEEKDAY: // intentional fall through - case TimeStep.SCALE.DAY: - return (this.current.getDate() == 1); - case TimeStep.SCALE.MONTH: - return (this.current.getMonth() == 0); - case TimeStep.SCALE.YEAR: - return false; - default: - return false; - } -}; - - -/** - * Returns formatted text for the minor axislabel, depending on the current - * date and the scale. For example when scale is MINUTE, the current time is - * formatted as "hh:mm". - * @param {Date} [date] custom date. if not provided, current date is taken - */ -TimeStep.prototype.getLabelMinor = function(date) { - if (date == undefined) { - date = this.current; - } - - switch (this.scale) { - case TimeStep.SCALE.MILLISECOND: return moment(date).format('SSS'); - case TimeStep.SCALE.SECOND: return moment(date).format('s'); - case TimeStep.SCALE.MINUTE: return moment(date).format('HH:mm'); - case TimeStep.SCALE.HOUR: return moment(date).format('HH:mm'); - case TimeStep.SCALE.WEEKDAY: return moment(date).format('ddd D'); - case TimeStep.SCALE.DAY: return moment(date).format('D'); - case TimeStep.SCALE.MONTH: return moment(date).format('MMM'); - case TimeStep.SCALE.YEAR: return moment(date).format('YYYY'); - default: return ''; - } -}; - - -/** - * Returns formatted text for the major axis label, depending on the current - * date and the scale. For example when scale is MINUTE, the major scale is - * hours, and the hour will be formatted as "hh". - * @param {Date} [date] custom date. if not provided, current date is taken - */ -TimeStep.prototype.getLabelMajor = function(date) { - if (date == undefined) { - date = this.current; - } - - //noinspection FallthroughInSwitchStatementJS - switch (this.scale) { - case TimeStep.SCALE.MILLISECOND:return moment(date).format('HH:mm:ss'); - case TimeStep.SCALE.SECOND: return moment(date).format('D MMMM HH:mm'); - case TimeStep.SCALE.MINUTE: - case TimeStep.SCALE.HOUR: return moment(date).format('ddd D MMMM'); - case TimeStep.SCALE.WEEKDAY: - case TimeStep.SCALE.DAY: return moment(date).format('MMMM YYYY'); - case TimeStep.SCALE.MONTH: return moment(date).format('YYYY'); - case TimeStep.SCALE.YEAR: return ''; - default: return ''; - } -}; - -/** - * @constructor Stack - * Stacks items on top of each other. - * @param {ItemSet} parent - * @param {Object} [options] - */ -function Stack (parent, options) { - this.parent = parent; - - this.options = options || {}; - this.defaultOptions = { - order: function (a, b) { - //return (b.width - a.width) || (a.left - b.left); // TODO: cleanup - // Order: ranges over non-ranges, ranged ordered by width, and - // lastly ordered by start. - if (a instanceof ItemRange) { - if (b instanceof ItemRange) { - var aInt = (a.data.end - a.data.start); - var bInt = (b.data.end - b.data.start); - return (aInt - bInt) || (a.data.start - b.data.start); - } - else { - return -1; - } - } - else { - if (b instanceof ItemRange) { - return 1; - } - else { - return (a.data.start - b.data.start); - } - } - }, - margin: { - item: 10 - } - }; - - this.ordered = []; // ordered items -} - -/** - * Set options for the stack - * @param {Object} options Available options: - * {ItemSet} parent - * {Number} margin - * {function} order Stacking order - */ -Stack.prototype.setOptions = function setOptions (options) { - util.extend(this.options, options); - - // TODO: register on data changes at the connected parent itemset, and update the changed part only and immediately -}; - -/** - * Stack the items such that they don't overlap. The items will have a minimal - * distance equal to options.margin.item. - */ -Stack.prototype.update = function update() { - this._order(); - this._stack(); -}; - -/** - * Order the items. The items are ordered by width first, and by left position - * second. - * If a custom order function has been provided via the options, then this will - * be used. - * @private - */ -Stack.prototype._order = function _order () { - var items = this.parent.items; - if (!items) { - throw new Error('Cannot stack items: parent does not contain items'); - } - - // TODO: store the sorted items, to have less work later on - var ordered = []; - var index = 0; - // items is a map (no array) - util.forEach(items, function (item) { - if (item.visible) { - ordered[index] = item; - index++; - } - }); - - //if a customer stack order function exists, use it. - var order = this.options.order || this.defaultOptions.order; - if (!(typeof order === 'function')) { - throw new Error('Option order must be a function'); - } - - ordered.sort(order); - - this.ordered = ordered; -}; - -/** - * Adjust vertical positions of the events such that they don't overlap each - * other. - * @private - */ -Stack.prototype._stack = function _stack () { - var i, - iMax, - ordered = this.ordered, - options = this.options, - orientation = options.orientation || this.defaultOptions.orientation, - axisOnTop = (orientation == 'top'), - margin; - - if (options.margin && options.margin.item !== undefined) { - margin = options.margin.item; - } - else { - margin = this.defaultOptions.margin.item - } - - // calculate new, non-overlapping positions - for (i = 0, iMax = ordered.length; i < iMax; i++) { - var item = ordered[i]; - var collidingItem = null; - do { - // TODO: optimize checking for overlap. when there is a gap without items, - // you only need to check for items from the next item on, not from zero - collidingItem = this.checkOverlap(ordered, i, 0, i - 1, margin); - if (collidingItem != null) { - // There is a collision. Reposition the event above the colliding element - if (axisOnTop) { - item.top = collidingItem.top + collidingItem.height + margin; - } - else { - item.top = collidingItem.top - item.height - margin; - } - } - } while (collidingItem); - } -}; - -/** - * Check if the destiny position of given item overlaps with any - * of the other items from index itemStart to itemEnd. - * @param {Array} items Array with items - * @param {int} itemIndex Number of the item to be checked for overlap - * @param {int} itemStart First item to be checked. - * @param {int} itemEnd Last item to be checked. - * @return {Object | null} colliding item, or undefined when no collisions - * @param {Number} margin A minimum required margin. - * If margin is provided, the two items will be - * marked colliding when they overlap or - * when the margin between the two is smaller than - * the requested margin. - */ -Stack.prototype.checkOverlap = function checkOverlap (items, itemIndex, - itemStart, itemEnd, margin) { - var collision = this.collision; - - // we loop from end to start, as we suppose that the chance of a - // collision is larger for items at the end, so check these first. - var a = items[itemIndex]; - for (var i = itemEnd; i >= itemStart; i--) { - var b = items[i]; - if (collision(a, b, margin)) { - if (i != itemIndex) { - return b; - } - } - } - - return null; -}; - -/** - * Test if the two provided items collide - * The items must have parameters left, width, top, and height. - * @param {Component} a The first item - * @param {Component} b The second item - * @param {Number} margin A minimum required margin. - * If margin is provided, the two items will be - * marked colliding when they overlap or - * when the margin between the two is smaller than - * the requested margin. - * @return {boolean} true if a and b collide, else false - */ -Stack.prototype.collision = function collision (a, b, margin) { - return ((a.left - margin) < (b.left + b.getWidth()) && - (a.left + a.getWidth() + margin) > b.left && - (a.top - margin) < (b.top + b.height) && - (a.top + a.height + margin) > b.top); -}; - -/** - * @constructor Range - * A Range controls a numeric range with a start and end value. - * The Range adjusts the range based on mouse events or programmatic changes, - * and triggers events when the range is changing or has been changed. - * @param {Object} [options] See description at Range.setOptions - * @extends Controller - */ -function Range(options) { - this.id = util.randomUUID(); - this.start = null; // Number - this.end = null; // Number - - this.options = options || {}; - - this.setOptions(options); -} - -/** - * Set options for the range controller - * @param {Object} options Available options: - * {Number} min Minimum value for start - * {Number} max Maximum value for end - * {Number} zoomMin Set a minimum value for - * (end - start). - * {Number} zoomMax Set a maximum value for - * (end - start). - */ -Range.prototype.setOptions = function (options) { - util.extend(this.options, options); - - // re-apply range with new limitations - if (this.start !== null && this.end !== null) { - this.setRange(this.start, this.end); - } -}; - -/** - * Test whether direction has a valid value - * @param {String} direction 'horizontal' or 'vertical' - */ -function validateDirection (direction) { - if (direction != 'horizontal' && direction != 'vertical') { - throw new TypeError('Unknown direction "' + direction + '". ' + - 'Choose "horizontal" or "vertical".'); - } -} - -/** - * Add listeners for mouse and touch events to the component - * @param {Component} component - * @param {String} event Available events: 'move', 'zoom' - * @param {String} direction Available directions: 'horizontal', 'vertical' - */ -Range.prototype.subscribe = function (component, event, direction) { - var me = this; - - if (event == 'move') { - // drag start listener - component.on('dragstart', function (event) { - me._onDragStart(event, component); - }); - - // drag listener - component.on('drag', function (event) { - me._onDrag(event, component, direction); - }); - - // drag end listener - component.on('dragend', function (event) { - me._onDragEnd(event, component); - }); - } - else if (event == 'zoom') { - // mouse wheel - function mousewheel (event) { - me._onMouseWheel(event, component, direction); - } - component.on('mousewheel', mousewheel); - component.on('DOMMouseScroll', mousewheel); // For FF - - // pinch - component.on('touch', function (event) { - me._onTouch(); - }); - component.on('pinch', function (event) { - me._onPinch(event, component, direction); - }); - } - else { - throw new TypeError('Unknown event "' + event + '". ' + - 'Choose "move" or "zoom".'); - } -}; - -/** - * Add event listener - * @param {String} event Name of the event. - * Available events: 'rangechange', 'rangechanged' - * @param {function} callback Callback function, invoked as callback({start: Date, end: Date}) - */ -Range.prototype.on = function on (event, callback) { - var available = ['rangechange', 'rangechanged']; - - if (available.indexOf(event) == -1) { - throw new Error('Unknown event "' + event + '". Choose from ' + available.join()); - } - - events.addListener(this, event, callback); -}; - -/** - * Remove an event listener - * @param {String} event name of the event - * @param {function} callback callback handler - */ -Range.prototype.off = function off (event, callback) { - events.removeListener(this, event, callback); -}; - -/** - * Trigger an event - * @param {String} event name of the event, available events: 'rangechange', - * 'rangechanged' - * @private - */ -Range.prototype._trigger = function (event) { - events.trigger(this, event, { - start: this.start, - end: this.end - }); -}; - -/** - * Set a new start and end range - * @param {Number} [start] - * @param {Number} [end] - */ -Range.prototype.setRange = function(start, end) { - var changed = this._applyRange(start, end); - if (changed) { - this._trigger('rangechange'); - this._trigger('rangechanged'); - } -}; - -/** - * Set a new start and end range. This method is the same as setRange, but - * does not trigger a range change and range changed event, and it returns - * true when the range is changed - * @param {Number} [start] - * @param {Number} [end] - * @return {Boolean} changed - * @private - */ -Range.prototype._applyRange = function(start, end) { - var newStart = (start != null) ? util.convert(start, 'Date').valueOf() : this.start, - newEnd = (end != null) ? util.convert(end, 'Date').valueOf() : this.end, - max = (this.options.max != null) ? util.convert(this.options.max, 'Date').valueOf() : null, - min = (this.options.min != null) ? util.convert(this.options.min, 'Date').valueOf() : null, - diff; - - // check for valid number - if (isNaN(newStart) || newStart === null) { - throw new Error('Invalid start "' + start + '"'); - } - if (isNaN(newEnd) || newEnd === null) { - throw new Error('Invalid end "' + end + '"'); - } - - // prevent start < end - if (newEnd < newStart) { - newEnd = newStart; - } - - // prevent start < min - if (min !== null) { - if (newStart < min) { - diff = (min - newStart); - newStart += diff; - newEnd += diff; - - // prevent end > max - if (max != null) { - if (newEnd > max) { - newEnd = max; - } - } - } - } - - // prevent end > max - if (max !== null) { - if (newEnd > max) { - diff = (newEnd - max); - newStart -= diff; - newEnd -= diff; - - // prevent start < min - if (min != null) { - if (newStart < min) { - newStart = min; - } - } - } - } - - // prevent (end-start) < zoomMin - if (this.options.zoomMin !== null) { - var zoomMin = parseFloat(this.options.zoomMin); - if (zoomMin < 0) { - zoomMin = 0; - } - if ((newEnd - newStart) < zoomMin) { - if ((this.end - this.start) === zoomMin) { - // ignore this action, we are already zoomed to the minimum - newStart = this.start; - newEnd = this.end; - } - else { - // zoom to the minimum - diff = (zoomMin - (newEnd - newStart)); - newStart -= diff / 2; - newEnd += diff / 2; - } - } - } - - // prevent (end-start) > zoomMax - if (this.options.zoomMax !== null) { - var zoomMax = parseFloat(this.options.zoomMax); - if (zoomMax < 0) { - zoomMax = 0; - } - if ((newEnd - newStart) > zoomMax) { - if ((this.end - this.start) === zoomMax) { - // ignore this action, we are already zoomed to the maximum - newStart = this.start; - newEnd = this.end; - } - else { - // zoom to the maximum - diff = ((newEnd - newStart) - zoomMax); - newStart += diff / 2; - newEnd -= diff / 2; - } - } - } - - var changed = (this.start != newStart || this.end != newEnd); - - this.start = newStart; - this.end = newEnd; - - return changed; -}; - -/** - * Retrieve the current range. - * @return {Object} An object with start and end properties - */ -Range.prototype.getRange = function() { - return { - start: this.start, - end: this.end - }; -}; - -/** - * Calculate the conversion offset and scale for current range, based on - * the provided width - * @param {Number} width - * @returns {{offset: number, scale: number}} conversion - */ -Range.prototype.conversion = function (width) { - return Range.conversion(this.start, this.end, width); -}; - -/** - * Static method to calculate the conversion offset and scale for a range, - * based on the provided start, end, and width - * @param {Number} start - * @param {Number} end - * @param {Number} width - * @returns {{offset: number, scale: number}} conversion - */ -Range.conversion = function (start, end, width) { - if (width != 0 && (end - start != 0)) { - return { - offset: start, - scale: width / (end - start) - } - } - else { - return { - offset: 0, - scale: 1 - }; - } -}; - -// global (private) object to store drag params -var touchParams = {}; - -/** - * Start dragging horizontally or vertically - * @param {Event} event - * @param {Object} component - * @private - */ -Range.prototype._onDragStart = function(event, component) { - // refuse to drag when we where pinching to prevent the timeline make a jump - // when releasing the fingers in opposite order from the touch screen - if (touchParams.pinching) return; - - touchParams.start = this.start; - touchParams.end = this.end; - - var frame = component.frame; - if (frame) { - frame.style.cursor = 'move'; - } -}; - -/** - * Perform dragging operating. - * @param {Event} event - * @param {Component} component - * @param {String} direction 'horizontal' or 'vertical' - * @private - */ -Range.prototype._onDrag = function (event, component, direction) { - validateDirection(direction); - - // refuse to drag when we where pinching to prevent the timeline make a jump - // when releasing the fingers in opposite order from the touch screen - if (touchParams.pinching) return; - - var delta = (direction == 'horizontal') ? event.gesture.deltaX : event.gesture.deltaY, - interval = (touchParams.end - touchParams.start), - width = (direction == 'horizontal') ? component.width : component.height, - diffRange = -delta / width * interval; - - this._applyRange(touchParams.start + diffRange, touchParams.end + diffRange); - - // fire a rangechange event - this._trigger('rangechange'); -}; - -/** - * Stop dragging operating. - * @param {event} event - * @param {Component} component - * @private - */ -Range.prototype._onDragEnd = function (event, component) { - // refuse to drag when we where pinching to prevent the timeline make a jump - // when releasing the fingers in opposite order from the touch screen - if (touchParams.pinching) return; - - if (component.frame) { - component.frame.style.cursor = 'auto'; - } - - // fire a rangechanged event - this._trigger('rangechanged'); -}; - -/** - * Event handler for mouse wheel event, used to zoom - * Code from http://adomas.org/javascript-mouse-wheel/ - * @param {Event} event - * @param {Component} component - * @param {String} direction 'horizontal' or 'vertical' - * @private - */ -Range.prototype._onMouseWheel = function(event, component, direction) { - validateDirection(direction); - - // retrieve delta - var delta = 0; - if (event.wheelDelta) { /* IE/Opera. */ - delta = event.wheelDelta / 120; - } else if (event.detail) { /* Mozilla case. */ - // In Mozilla, sign of delta is different than in IE. - // Also, delta is multiple of 3. - delta = -event.detail / 3; - } - - // If delta is nonzero, handle it. - // Basically, delta is now positive if wheel was scrolled up, - // and negative, if wheel was scrolled down. - if (delta) { - // perform the zoom action. Delta is normally 1 or -1 - - // adjust a negative delta such that zooming in with delta 0.1 - // equals zooming out with a delta -0.1 - var scale; - if (delta < 0) { - scale = 1 - (delta / 5); - } - else { - scale = 1 / (1 + (delta / 5)) ; - } - - // calculate center, the date to zoom around - var gesture = util.fakeGesture(this, event), - pointer = getPointer(gesture.touches[0], component.frame), - pointerDate = this._pointerToDate(component, direction, pointer); - - this.zoom(scale, pointerDate); - } - - // Prevent default actions caused by mouse wheel - // (else the page and timeline both zoom and scroll) - util.preventDefault(event); -}; - -/** - * On start of a touch gesture, initialize scale to 1 - * @private - */ -Range.prototype._onTouch = function () { - touchParams.start = this.start; - touchParams.end = this.end; - touchParams.pinching = false; - touchParams.center = null; -}; - -/** - * Handle pinch event - * @param {Event} event - * @param {Component} component - * @param {String} direction 'horizontal' or 'vertical' - * @private - */ -Range.prototype._onPinch = function (event, component, direction) { - touchParams.pinching = true; - - if (event.gesture.touches.length > 1) { - if (!touchParams.center) { - touchParams.center = getPointer(event.gesture.center, component.frame); - } - - var scale = 1 / event.gesture.scale, - initDate = this._pointerToDate(component, direction, touchParams.center), - center = getPointer(event.gesture.center, component.frame), - date = this._pointerToDate(component, direction, center), - delta = date - initDate; // TODO: utilize delta - - // calculate new start and end - var newStart = parseInt(initDate + (touchParams.start - initDate) * scale); - var newEnd = parseInt(initDate + (touchParams.end - initDate) * scale); - - // apply new range - this.setRange(newStart, newEnd); - } -}; - -/** - * Helper function to calculate the center date for zooming - * @param {Component} component - * @param {{x: Number, y: Number}} pointer - * @param {String} direction 'horizontal' or 'vertical' - * @return {number} date - * @private - */ -Range.prototype._pointerToDate = function (component, direction, pointer) { - var conversion; - if (direction == 'horizontal') { - var width = component.width; - conversion = this.conversion(width); - return pointer.x / conversion.scale + conversion.offset; - } - else { - var height = component.height; - conversion = this.conversion(height); - return pointer.y / conversion.scale + conversion.offset; - } -}; - -/** - * Get the pointer location relative to the location of the dom element - * @param {{pageX: Number, pageY: Number}} touch - * @param {Element} element HTML DOM element - * @return {{x: Number, y: Number}} pointer - * @private - */ -function getPointer (touch, element) { - return { - x: touch.pageX - vis.util.getAbsoluteLeft(element), - y: touch.pageY - vis.util.getAbsoluteTop(element) - }; -} - -/** - * Zoom the range the given scale in or out. Start and end date will - * be adjusted, and the timeline will be redrawn. You can optionally give a - * date around which to zoom. - * For example, try scale = 0.9 or 1.1 - * @param {Number} scale Scaling factor. Values above 1 will zoom out, - * values below 1 will zoom in. - * @param {Number} [center] Value representing a date around which will - * be zoomed. - */ -Range.prototype.zoom = function(scale, center) { - // if centerDate is not provided, take it half between start Date and end Date - if (center == null) { - center = (this.start + this.end) / 2; - } - - // calculate new start and end - var newStart = center + (this.start - center) * scale; - var newEnd = center + (this.end - center) * scale; - - this.setRange(newStart, newEnd); -}; - -/** - * Move the range with a given delta to the left or right. Start and end - * value will be adjusted. For example, try delta = 0.1 or -0.1 - * @param {Number} delta Moving amount. Positive value will move right, - * negative value will move left - */ -Range.prototype.move = function(delta) { - // zoom start Date and end Date relative to the centerDate - var diff = (this.end - this.start); - - // apply new values - var newStart = this.start + diff * delta; - var newEnd = this.end + diff * delta; - - // TODO: reckon with min and max range - - this.start = newStart; - this.end = newEnd; -}; - -/** - * Move the range to a new center point - * @param {Number} moveTo New center point of the range - */ -Range.prototype.moveTo = function(moveTo) { - var center = (this.start + this.end) / 2; - - var diff = center - moveTo; - - // calculate new start and end - var newStart = this.start - diff; - var newEnd = this.end - diff; - - this.setRange(newStart, newEnd); -}; - -/** - * @constructor Controller - * - * A Controller controls the reflows and repaints of all visual components - */ -function Controller () { - this.id = util.randomUUID(); - this.components = {}; - - this.repaintTimer = undefined; - this.reflowTimer = undefined; -} - -/** - * Add a component to the controller - * @param {Component} component - */ -Controller.prototype.add = function add(component) { - // validate the component - if (component.id == undefined) { - throw new Error('Component has no field id'); - } - if (!(component instanceof Component) && !(component instanceof Controller)) { - throw new TypeError('Component must be an instance of ' + - 'prototype Component or Controller'); - } - - // add the component - component.controller = this; - this.components[component.id] = component; -}; - -/** - * Remove a component from the controller - * @param {Component | String} component - */ -Controller.prototype.remove = function remove(component) { - var id; - for (id in this.components) { - if (this.components.hasOwnProperty(id)) { - if (id == component || this.components[id] == component) { - break; - } - } - } - - if (id) { - delete this.components[id]; - } -}; - -/** - * Request a reflow. The controller will schedule a reflow - * @param {Boolean} [force] If true, an immediate reflow is forced. Default - * is false. - */ -Controller.prototype.requestReflow = function requestReflow(force) { - if (force) { - this.reflow(); - } - else { - if (!this.reflowTimer) { - var me = this; - this.reflowTimer = setTimeout(function () { - me.reflowTimer = undefined; - me.reflow(); - }, 0); - } - } -}; - -/** - * Request a repaint. The controller will schedule a repaint - * @param {Boolean} [force] If true, an immediate repaint is forced. Default - * is false. - */ -Controller.prototype.requestRepaint = function requestRepaint(force) { - if (force) { - this.repaint(); - } - else { - if (!this.repaintTimer) { - var me = this; - this.repaintTimer = setTimeout(function () { - me.repaintTimer = undefined; - me.repaint(); - }, 0); - } - } -}; - -/** - * Repaint all components - */ -Controller.prototype.repaint = function repaint() { - var changed = false; - - // cancel any running repaint request - if (this.repaintTimer) { - clearTimeout(this.repaintTimer); - this.repaintTimer = undefined; - } - - var done = {}; - - function repaint(component, id) { - if (!(id in done)) { - // first repaint the components on which this component is dependent - if (component.depends) { - component.depends.forEach(function (dep) { - repaint(dep, dep.id); - }); - } - if (component.parent) { - repaint(component.parent, component.parent.id); - } - - // repaint the component itself and mark as done - changed = component.repaint() || changed; - done[id] = true; - } - } - - util.forEach(this.components, repaint); - - // immediately reflow when needed - if (changed) { - this.reflow(); - } - // TODO: limit the number of nested reflows/repaints, prevent loop -}; - -/** - * Reflow all components - */ -Controller.prototype.reflow = function reflow() { - var resized = false; - - // cancel any running repaint request - if (this.reflowTimer) { - clearTimeout(this.reflowTimer); - this.reflowTimer = undefined; - } - - var done = {}; - - function reflow(component, id) { - if (!(id in done)) { - // first reflow the components on which this component is dependent - if (component.depends) { - component.depends.forEach(function (dep) { - reflow(dep, dep.id); - }); - } - if (component.parent) { - reflow(component.parent, component.parent.id); - } - - // reflow the component itself and mark as done - resized = component.reflow() || resized; - done[id] = true; - } - } - - util.forEach(this.components, reflow); - - // immediately repaint when needed - if (resized) { - this.repaint(); - } - // TODO: limit the number of nested reflows/repaints, prevent loop -}; - -/** - * Prototype for visual components - */ -function Component () { - this.id = null; - this.parent = null; - this.depends = null; - this.controller = null; - this.options = null; - - this.frame = null; // main DOM element - this.top = 0; - this.left = 0; - this.width = 0; - this.height = 0; -} - -/** - * Set parameters for the frame. Parameters will be merged in current parameter - * set. - * @param {Object} options Available parameters: - * {String | function} [className] - * {EventBus} [eventBus] - * {String | Number | function} [left] - * {String | Number | function} [top] - * {String | Number | function} [width] - * {String | Number | function} [height] - */ -Component.prototype.setOptions = function setOptions(options) { - if (options) { - util.extend(this.options, options); - - if (this.controller) { - this.requestRepaint(); - this.requestReflow(); - } - } -}; - -/** - * Get an option value by name - * The function will first check this.options object, and else will check - * this.defaultOptions. - * @param {String} name - * @return {*} value - */ -Component.prototype.getOption = function getOption(name) { - var value; - if (this.options) { - value = this.options[name]; - } - if (value === undefined && this.defaultOptions) { - value = this.defaultOptions[name]; - } - return value; -}; - -/** - * Get the container element of the component, which can be used by a child to - * add its own widgets. Not all components do have a container for childs, in - * that case null is returned. - * @returns {HTMLElement | null} container - */ -// TODO: get rid of the getContainer and getFrame methods, provide these via the options -Component.prototype.getContainer = function getContainer() { - // should be implemented by the component - return null; -}; - -/** - * Get the frame element of the component, the outer HTML DOM element. - * @returns {HTMLElement | null} frame - */ -Component.prototype.getFrame = function getFrame() { - return this.frame; -}; - -/** - * Repaint the component - * @return {Boolean} changed - */ -Component.prototype.repaint = function repaint() { - // should be implemented by the component - return false; -}; - -/** - * Reflow the component - * @return {Boolean} resized - */ -Component.prototype.reflow = function reflow() { - // should be implemented by the component - return false; -}; - -/** - * Hide the component from the DOM - * @return {Boolean} changed - */ -Component.prototype.hide = function hide() { - if (this.frame && this.frame.parentNode) { - this.frame.parentNode.removeChild(this.frame); - return true; - } - else { - return false; - } -}; - -/** - * Show the component in the DOM (when not already visible). - * A repaint will be executed when the component is not visible - * @return {Boolean} changed - */ -Component.prototype.show = function show() { - if (!this.frame || !this.frame.parentNode) { - return this.repaint(); - } - else { - return false; - } -}; - -/** - * Request a repaint. The controller will schedule a repaint - */ -Component.prototype.requestRepaint = function requestRepaint() { - if (this.controller) { - this.controller.requestRepaint(); - } - else { - throw new Error('Cannot request a repaint: no controller configured'); - // TODO: just do a repaint when no parent is configured? - } -}; - -/** - * Request a reflow. The controller will schedule a reflow - */ -Component.prototype.requestReflow = function requestReflow() { - if (this.controller) { - this.controller.requestReflow(); - } - else { - throw new Error('Cannot request a reflow: no controller configured'); - // TODO: just do a reflow when no parent is configured? - } -}; - -/** - * A panel can contain components - * @param {Component} [parent] - * @param {Component[]} [depends] Components on which this components depends - * (except for the parent) - * @param {Object} [options] Available parameters: - * {String | Number | function} [left] - * {String | Number | function} [top] - * {String | Number | function} [width] - * {String | Number | function} [height] - * {String | function} [className] - * @constructor Panel - * @extends Component - */ -function Panel(parent, depends, options) { - this.id = util.randomUUID(); - this.parent = parent; - this.depends = depends; - - this.options = options || {}; -} - -Panel.prototype = new Component(); - -/** - * Set options. Will extend the current options. - * @param {Object} [options] Available parameters: - * {String | function} [className] - * {String | Number | function} [left] - * {String | Number | function} [top] - * {String | Number | function} [width] - * {String | Number | function} [height] - */ -Panel.prototype.setOptions = Component.prototype.setOptions; - -/** - * Get the container element of the panel, which can be used by a child to - * add its own widgets. - * @returns {HTMLElement} container - */ -Panel.prototype.getContainer = function () { - return this.frame; -}; - -/** - * Repaint the component - * @return {Boolean} changed - */ -Panel.prototype.repaint = function () { - var changed = 0, - update = util.updateProperty, - asSize = util.option.asSize, - options = this.options, - frame = this.frame; - if (!frame) { - frame = document.createElement('div'); - frame.className = 'panel'; - - var className = options.className; - if (className) { - if (typeof className == 'function') { - util.addClassName(frame, String(className())); - } - else { - util.addClassName(frame, String(className)); - } - } - - this.frame = frame; - changed += 1; - } - if (!frame.parentNode) { - if (!this.parent) { - throw new Error('Cannot repaint panel: no parent attached'); - } - var parentContainer = this.parent.getContainer(); - if (!parentContainer) { - throw new Error('Cannot repaint panel: parent has no container element'); - } - parentContainer.appendChild(frame); - changed += 1; - } - - changed += update(frame.style, 'top', asSize(options.top, '0px')); - changed += update(frame.style, 'left', asSize(options.left, '0px')); - changed += update(frame.style, 'width', asSize(options.width, '100%')); - changed += update(frame.style, 'height', asSize(options.height, '100%')); - - return (changed > 0); -}; - -/** - * Reflow the component - * @return {Boolean} resized - */ -Panel.prototype.reflow = function () { - var changed = 0, - update = util.updateProperty, - frame = this.frame; - - if (frame) { - changed += update(this, 'top', frame.offsetTop); - changed += update(this, 'left', frame.offsetLeft); - changed += update(this, 'width', frame.offsetWidth); - changed += update(this, 'height', frame.offsetHeight); - } - else { - changed += 1; - } - - return (changed > 0); -}; - -/** - * A root panel can hold components. The root panel must be initialized with - * a DOM element as container. - * @param {HTMLElement} container - * @param {Object} [options] Available parameters: see RootPanel.setOptions. - * @constructor RootPanel - * @extends Panel - */ -function RootPanel(container, options) { - this.id = util.randomUUID(); - this.container = container; - - this.options = options || {}; - this.defaultOptions = { - autoResize: true - }; - - this.listeners = {}; // event listeners -} - -RootPanel.prototype = new Panel(); - -/** - * Set options. Will extend the current options. - * @param {Object} [options] Available parameters: - * {String | function} [className] - * {String | Number | function} [left] - * {String | Number | function} [top] - * {String | Number | function} [width] - * {String | Number | function} [height] - * {Boolean | function} [autoResize] - */ -RootPanel.prototype.setOptions = Component.prototype.setOptions; - -/** - * Repaint the component - * @return {Boolean} changed - */ -RootPanel.prototype.repaint = function () { - var changed = 0, - update = util.updateProperty, - asSize = util.option.asSize, - options = this.options, - frame = this.frame; - - if (!frame) { - frame = document.createElement('div'); - - this.frame = frame; - - changed += 1; - } - if (!frame.parentNode) { - if (!this.container) { - throw new Error('Cannot repaint root panel: no container attached'); - } - this.container.appendChild(frame); - changed += 1; - } - - frame.className = 'vis timeline rootpanel ' + options.orientation; - var className = options.className; - if (className) { - util.addClassName(frame, util.option.asString(className)); - } - - changed += update(frame.style, 'top', asSize(options.top, '0px')); - changed += update(frame.style, 'left', asSize(options.left, '0px')); - changed += update(frame.style, 'width', asSize(options.width, '100%')); - changed += update(frame.style, 'height', asSize(options.height, '100%')); - - this._updateEventEmitters(); - this._updateWatch(); - - return (changed > 0); -}; - -/** - * Reflow the component - * @return {Boolean} resized - */ -RootPanel.prototype.reflow = function () { - var changed = 0, - update = util.updateProperty, - frame = this.frame; - - if (frame) { - changed += update(this, 'top', frame.offsetTop); - changed += update(this, 'left', frame.offsetLeft); - changed += update(this, 'width', frame.offsetWidth); - changed += update(this, 'height', frame.offsetHeight); - } - else { - changed += 1; - } - - return (changed > 0); -}; - -/** - * Update watching for resize, depending on the current option - * @private - */ -RootPanel.prototype._updateWatch = function () { - var autoResize = this.getOption('autoResize'); - if (autoResize) { - this._watch(); - } - else { - this._unwatch(); - } -}; - -/** - * Watch for changes in the size of the frame. On resize, the Panel will - * automatically redraw itself. - * @private - */ -RootPanel.prototype._watch = function () { - var me = this; - - this._unwatch(); - - var checkSize = function () { - var autoResize = me.getOption('autoResize'); - if (!autoResize) { - // stop watching when the option autoResize is changed to false - me._unwatch(); - return; - } - - if (me.frame) { - // check whether the frame is resized - if ((me.frame.clientWidth != me.width) || - (me.frame.clientHeight != me.height)) { - me.requestReflow(); - } - } - }; - - // TODO: automatically cleanup the event listener when the frame is deleted - util.addEventListener(window, 'resize', checkSize); - - this.watchTimer = setInterval(checkSize, 1000); -}; - -/** - * Stop watching for a resize of the frame. - * @private - */ -RootPanel.prototype._unwatch = function () { - if (this.watchTimer) { - clearInterval(this.watchTimer); - this.watchTimer = undefined; - } - - // TODO: remove event listener on window.resize -}; - -/** - * Event handler - * @param {String} event name of the event, for example 'click', 'mousemove' - * @param {function} callback callback handler, invoked with the raw HTML Event - * as parameter. - */ -RootPanel.prototype.on = function (event, callback) { - // register the listener at this component - var arr = this.listeners[event]; - if (!arr) { - arr = []; - this.listeners[event] = arr; - } - arr.push(callback); - - this._updateEventEmitters(); -}; - -/** - * Update the event listeners for all event emitters - * @private - */ -RootPanel.prototype._updateEventEmitters = function () { - if (this.listeners) { - var me = this; - util.forEach(this.listeners, function (listeners, event) { - if (!me.emitters) { - me.emitters = {}; - } - if (!(event in me.emitters)) { - // create event - var frame = me.frame; - if (frame) { - //console.log('Created a listener for event ' + event + ' on component ' + me.id); // TODO: cleanup logging - var callback = function(event) { - listeners.forEach(function (listener) { - // TODO: filter on event target! - listener(event); - }); - }; - me.emitters[event] = callback; - - if (!me.hammer) { - me.hammer = Hammer(frame, { - prevent_default: true - }); - } - me.hammer.on(event, callback); - } - } - }); - - // TODO: be able to delete event listeners - // TODO: be able to move event listeners to a parent when available - } -}; - -/** - * A horizontal time axis - * @param {Component} parent - * @param {Component[]} [depends] Components on which this components depends - * (except for the parent) - * @param {Object} [options] See TimeAxis.setOptions for the available - * options. - * @constructor TimeAxis - * @extends Component - */ -function TimeAxis (parent, depends, options) { - this.id = util.randomUUID(); - this.parent = parent; - this.depends = depends; - - this.dom = { - majorLines: [], - majorTexts: [], - minorLines: [], - minorTexts: [], - redundant: { - majorLines: [], - majorTexts: [], - minorLines: [], - minorTexts: [] - } - }; - this.props = { - range: { - start: 0, - end: 0, - minimumStep: 0 - }, - lineTop: 0 - }; - - this.options = options || {}; - this.defaultOptions = { - orientation: 'bottom', // supported: 'top', 'bottom' - // TODO: implement timeaxis orientations 'left' and 'right' - showMinorLabels: true, - showMajorLabels: true - }; - - this.conversion = null; - this.range = null; -} - -TimeAxis.prototype = new Component(); - -// TODO: comment options -TimeAxis.prototype.setOptions = Component.prototype.setOptions; - -/** - * Set a range (start and end) - * @param {Range | Object} range A Range or an object containing start and end. - */ -TimeAxis.prototype.setRange = function (range) { - if (!(range instanceof Range) && (!range || !range.start || !range.end)) { - throw new TypeError('Range must be an instance of Range, ' + - 'or an object containing start and end.'); - } - this.range = range; -}; - -/** - * Convert a position on screen (pixels) to a datetime - * @param {int} x Position on the screen in pixels - * @return {Date} time The datetime the corresponds with given position x - */ -TimeAxis.prototype.toTime = function(x) { - var conversion = this.conversion; - return new Date(x / conversion.scale + conversion.offset); -}; - -/** - * Convert a datetime (Date object) into a position on the screen - * @param {Date} time A date - * @return {int} x The position on the screen in pixels which corresponds - * with the given date. - * @private - */ -TimeAxis.prototype.toScreen = function(time) { - var conversion = this.conversion; - return (time.valueOf() - conversion.offset) * conversion.scale; -}; - -/** - * Repaint the component - * @return {Boolean} changed - */ -TimeAxis.prototype.repaint = function () { - var changed = 0, - update = util.updateProperty, - asSize = util.option.asSize, - options = this.options, - orientation = this.getOption('orientation'), - props = this.props, - step = this.step; - - var frame = this.frame; - if (!frame) { - frame = document.createElement('div'); - this.frame = frame; - changed += 1; - } - frame.className = 'axis'; - // TODO: custom className? - - if (!frame.parentNode) { - if (!this.parent) { - throw new Error('Cannot repaint time axis: no parent attached'); - } - var parentContainer = this.parent.getContainer(); - if (!parentContainer) { - throw new Error('Cannot repaint time axis: parent has no container element'); - } - parentContainer.appendChild(frame); - - changed += 1; - } - - var parent = frame.parentNode; - if (parent) { - var beforeChild = frame.nextSibling; - parent.removeChild(frame); // take frame offline while updating (is almost twice as fast) - - var defaultTop = (orientation == 'bottom' && this.props.parentHeight && this.height) ? - (this.props.parentHeight - this.height) + 'px' : - '0px'; - changed += update(frame.style, 'top', asSize(options.top, defaultTop)); - changed += update(frame.style, 'left', asSize(options.left, '0px')); - changed += update(frame.style, 'width', asSize(options.width, '100%')); - changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); - - // get characters width and height - this._repaintMeasureChars(); - - if (this.step) { - this._repaintStart(); - - step.first(); - var xFirstMajorLabel = undefined; - var max = 0; - while (step.hasNext() && max < 1000) { - max++; - var cur = step.getCurrent(), - x = this.toScreen(cur), - isMajor = step.isMajor(); - - // TODO: lines must have a width, such that we can create css backgrounds - - if (this.getOption('showMinorLabels')) { - this._repaintMinorText(x, step.getLabelMinor()); - } - - if (isMajor && this.getOption('showMajorLabels')) { - if (x > 0) { - if (xFirstMajorLabel == undefined) { - xFirstMajorLabel = x; - } - this._repaintMajorText(x, step.getLabelMajor()); - } - this._repaintMajorLine(x); - } - else { - this._repaintMinorLine(x); - } - - step.next(); - } - - // create a major label on the left when needed - if (this.getOption('showMajorLabels')) { - var leftTime = this.toTime(0), - leftText = step.getLabelMajor(leftTime), - widthText = leftText.length * (props.majorCharWidth || 10) + 10; // upper bound estimation - - if (xFirstMajorLabel == undefined || widthText < xFirstMajorLabel) { - this._repaintMajorText(0, leftText); - } - } - - this._repaintEnd(); - } - - this._repaintLine(); - - // put frame online again - if (beforeChild) { - parent.insertBefore(frame, beforeChild); - } - else { - parent.appendChild(frame) - } - } - - return (changed > 0); -}; - -/** - * Start a repaint. Move all DOM elements to a redundant list, where they - * can be picked for re-use, or can be cleaned up in the end - * @private - */ -TimeAxis.prototype._repaintStart = function () { - var dom = this.dom, - redundant = dom.redundant; - - redundant.majorLines = dom.majorLines; - redundant.majorTexts = dom.majorTexts; - redundant.minorLines = dom.minorLines; - redundant.minorTexts = dom.minorTexts; - - dom.majorLines = []; - dom.majorTexts = []; - dom.minorLines = []; - dom.minorTexts = []; -}; - -/** - * End a repaint. Cleanup leftover DOM elements in the redundant list - * @private - */ -TimeAxis.prototype._repaintEnd = function () { - util.forEach(this.dom.redundant, function (arr) { - while (arr.length) { - var elem = arr.pop(); - if (elem && elem.parentNode) { - elem.parentNode.removeChild(elem); - } - } - }); -}; - - -/** - * Create a minor label for the axis at position x - * @param {Number} x - * @param {String} text - * @private - */ -TimeAxis.prototype._repaintMinorText = function (x, text) { - // reuse redundant label - var label = this.dom.redundant.minorTexts.shift(); - - if (!label) { - // create new label - var content = document.createTextNode(''); - label = document.createElement('div'); - label.appendChild(content); - label.className = 'text minor'; - this.frame.appendChild(label); - } - this.dom.minorTexts.push(label); - - label.childNodes[0].nodeValue = text; - label.style.left = x + 'px'; - label.style.top = this.props.minorLabelTop + 'px'; - //label.title = title; // TODO: this is a heavy operation -}; - -/** - * Create a Major label for the axis at position x - * @param {Number} x - * @param {String} text - * @private - */ -TimeAxis.prototype._repaintMajorText = function (x, text) { - // reuse redundant label - var label = this.dom.redundant.majorTexts.shift(); - - if (!label) { - // create label - var content = document.createTextNode(text); - label = document.createElement('div'); - label.className = 'text major'; - label.appendChild(content); - this.frame.appendChild(label); - } - this.dom.majorTexts.push(label); - - label.childNodes[0].nodeValue = text; - label.style.top = this.props.majorLabelTop + 'px'; - label.style.left = x + 'px'; - //label.title = title; // TODO: this is a heavy operation -}; - -/** - * Create a minor line for the axis at position x - * @param {Number} x - * @private - */ -TimeAxis.prototype._repaintMinorLine = function (x) { - // reuse redundant line - var line = this.dom.redundant.minorLines.shift(); - - if (!line) { - // create vertical line - line = document.createElement('div'); - line.className = 'grid vertical minor'; - this.frame.appendChild(line); - } - this.dom.minorLines.push(line); - - var props = this.props; - line.style.top = props.minorLineTop + 'px'; - line.style.height = props.minorLineHeight + 'px'; - line.style.left = (x - props.minorLineWidth / 2) + 'px'; -}; - -/** - * Create a Major line for the axis at position x - * @param {Number} x - * @private - */ -TimeAxis.prototype._repaintMajorLine = function (x) { - // reuse redundant line - var line = this.dom.redundant.majorLines.shift(); - - if (!line) { - // create vertical line - line = document.createElement('DIV'); - line.className = 'grid vertical major'; - this.frame.appendChild(line); - } - this.dom.majorLines.push(line); - - var props = this.props; - line.style.top = props.majorLineTop + 'px'; - line.style.left = (x - props.majorLineWidth / 2) + 'px'; - line.style.height = props.majorLineHeight + 'px'; -}; - - -/** - * Repaint the horizontal line for the axis - * @private - */ -TimeAxis.prototype._repaintLine = function() { - var line = this.dom.line, - frame = this.frame, - options = this.options; - - // line before all axis elements - if (this.getOption('showMinorLabels') || this.getOption('showMajorLabels')) { - if (line) { - // put this line at the end of all childs - frame.removeChild(line); - frame.appendChild(line); - } - else { - // create the axis line - line = document.createElement('div'); - line.className = 'grid horizontal major'; - frame.appendChild(line); - this.dom.line = line; - } - - line.style.top = this.props.lineTop + 'px'; - } - else { - if (line && line.parentElement) { - frame.removeChild(line.line); - delete this.dom.line; - } - } -}; - -/** - * Create characters used to determine the size of text on the axis - * @private - */ -TimeAxis.prototype._repaintMeasureChars = function () { - // calculate the width and height of a single character - // this is used to calculate the step size, and also the positioning of the - // axis - var dom = this.dom, - text; - - if (!dom.measureCharMinor) { - text = document.createTextNode('0'); - var measureCharMinor = document.createElement('DIV'); - measureCharMinor.className = 'text minor measure'; - measureCharMinor.appendChild(text); - this.frame.appendChild(measureCharMinor); - - dom.measureCharMinor = measureCharMinor; - } - - if (!dom.measureCharMajor) { - text = document.createTextNode('0'); - var measureCharMajor = document.createElement('DIV'); - measureCharMajor.className = 'text major measure'; - measureCharMajor.appendChild(text); - this.frame.appendChild(measureCharMajor); - - dom.measureCharMajor = measureCharMajor; - } -}; - -/** - * Reflow the component - * @return {Boolean} resized - */ -TimeAxis.prototype.reflow = function () { - var changed = 0, - update = util.updateProperty, - frame = this.frame, - range = this.range; - - if (!range) { - throw new Error('Cannot repaint time axis: no range configured'); - } - - if (frame) { - changed += update(this, 'top', frame.offsetTop); - changed += update(this, 'left', frame.offsetLeft); - - // calculate size of a character - var props = this.props, - showMinorLabels = this.getOption('showMinorLabels'), - showMajorLabels = this.getOption('showMajorLabels'), - measureCharMinor = this.dom.measureCharMinor, - measureCharMajor = this.dom.measureCharMajor; - if (measureCharMinor) { - props.minorCharHeight = measureCharMinor.clientHeight; - props.minorCharWidth = measureCharMinor.clientWidth; - } - if (measureCharMajor) { - props.majorCharHeight = measureCharMajor.clientHeight; - props.majorCharWidth = measureCharMajor.clientWidth; - } - - var parentHeight = frame.parentNode ? frame.parentNode.offsetHeight : 0; - if (parentHeight != props.parentHeight) { - props.parentHeight = parentHeight; - changed += 1; - } - switch (this.getOption('orientation')) { - case 'bottom': - props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; - props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; - - props.minorLabelTop = 0; - props.majorLabelTop = props.minorLabelTop + props.minorLabelHeight; - - props.minorLineTop = -this.top; - props.minorLineHeight = Math.max(this.top + props.majorLabelHeight, 0); - props.minorLineWidth = 1; // TODO: really calculate width - - props.majorLineTop = -this.top; - props.majorLineHeight = Math.max(this.top + props.minorLabelHeight + props.majorLabelHeight, 0); - props.majorLineWidth = 1; // TODO: really calculate width - - props.lineTop = 0; - - break; - - case 'top': - props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; - props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; - - props.majorLabelTop = 0; - props.minorLabelTop = props.majorLabelTop + props.majorLabelHeight; - - props.minorLineTop = props.minorLabelTop; - props.minorLineHeight = Math.max(parentHeight - props.majorLabelHeight - this.top); - props.minorLineWidth = 1; // TODO: really calculate width - - props.majorLineTop = 0; - props.majorLineHeight = Math.max(parentHeight - this.top); - props.majorLineWidth = 1; // TODO: really calculate width - - props.lineTop = props.majorLabelHeight + props.minorLabelHeight; - - break; - - default: - throw new Error('Unkown orientation "' + this.getOption('orientation') + '"'); - } - - var height = props.minorLabelHeight + props.majorLabelHeight; - changed += update(this, 'width', frame.offsetWidth); - changed += update(this, 'height', height); - - // calculate range and step - this._updateConversion(); - - var start = util.convert(range.start, 'Number'), - end = util.convert(range.end, 'Number'), - minimumStep = this.toTime((props.minorCharWidth || 10) * 5).valueOf() - -this.toTime(0).valueOf(); - this.step = new TimeStep(new Date(start), new Date(end), minimumStep); - changed += update(props.range, 'start', start); - changed += update(props.range, 'end', end); - changed += update(props.range, 'minimumStep', minimumStep.valueOf()); - } - - return (changed > 0); -}; - -/** - * Calculate the scale and offset to convert a position on screen to the - * corresponding date and vice versa. - * After the method _updateConversion is executed once, the methods toTime - * and toScreen can be used. - * @private - */ -TimeAxis.prototype._updateConversion = function() { - var range = this.range; - if (!range) { - throw new Error('No range configured'); - } - - if (range.conversion) { - this.conversion = range.conversion(this.width); - } - else { - this.conversion = Range.conversion(range.start, range.end, this.width); - } -}; - -/** - * A current time bar - * @param {Component} parent - * @param {Component[]} [depends] Components on which this components depends - * (except for the parent) - * @param {Object} [options] Available parameters: - * {Boolean} [showCurrentTime] - * @constructor CurrentTime - * @extends Component - */ - -function CurrentTime (parent, depends, options) { - this.id = util.randomUUID(); - this.parent = parent; - this.depends = depends; - - this.options = options || {}; - this.defaultOptions = { - showCurrentTime: false - }; -} - -CurrentTime.prototype = new Component(); - -CurrentTime.prototype.setOptions = Component.prototype.setOptions; - -/** - * Get the container element of the bar, which can be used by a child to - * add its own widgets. - * @returns {HTMLElement} container - */ -CurrentTime.prototype.getContainer = function () { - return this.frame; -}; - -/** - * Repaint the component - * @return {Boolean} changed - */ -CurrentTime.prototype.repaint = function () { - var bar = this.frame, - parent = this.parent, - parentContainer = parent.parent.getContainer(); - - if (!parent) { - throw new Error('Cannot repaint bar: no parent attached'); - } - - if (!parentContainer) { - throw new Error('Cannot repaint bar: parent has no container element'); - } - - if (!this.getOption('showCurrentTime')) { - if (bar) { - parentContainer.removeChild(bar); - delete this.frame; - } - - return; - } - - if (!bar) { - bar = document.createElement('div'); - bar.className = 'currenttime'; - bar.style.position = 'absolute'; - bar.style.top = '0px'; - bar.style.height = '100%'; - - parentContainer.appendChild(bar); - this.frame = bar; - } - - if (!parent.conversion) { - parent._updateConversion(); - } - - var now = new Date(); - var x = parent.toScreen(now); - - bar.style.left = x + 'px'; - bar.title = 'Current time: ' + now; - - // start a timer to adjust for the new time - if (this.currentTimeTimer !== undefined) { - clearTimeout(this.currentTimeTimer); - delete this.currentTimeTimer; - } - - var timeline = this; - var interval = 1 / parent.conversion.scale / 2; - - if (interval < 30) { - interval = 30; - } - - this.currentTimeTimer = setTimeout(function() { - timeline.repaint(); - }, interval); - - return false; -}; - -/** - * A custom time bar - * @param {Component} parent - * @param {Component[]} [depends] Components on which this components depends - * (except for the parent) - * @param {Object} [options] Available parameters: - * {Boolean} [showCustomTime] - * @constructor CustomTime - * @extends Component - */ - -function CustomTime (parent, depends, options) { - this.id = util.randomUUID(); - this.parent = parent; - this.depends = depends; - - this.options = options || {}; - this.defaultOptions = { - showCustomTime: false - }; - - this.listeners = []; - this.customTime = new Date(); -} - -CustomTime.prototype = new Component(); - -CustomTime.prototype.setOptions = Component.prototype.setOptions; - -/** - * Get the container element of the bar, which can be used by a child to - * add its own widgets. - * @returns {HTMLElement} container - */ -CustomTime.prototype.getContainer = function () { - return this.frame; -}; - -/** - * Repaint the component - * @return {Boolean} changed - */ -CustomTime.prototype.repaint = function () { - var bar = this.frame, - parent = this.parent, - parentContainer = parent.parent.getContainer(); - - if (!parent) { - throw new Error('Cannot repaint bar: no parent attached'); - } - - if (!parentContainer) { - throw new Error('Cannot repaint bar: parent has no container element'); - } - - if (!this.getOption('showCustomTime')) { - if (bar) { - parentContainer.removeChild(bar); - delete this.frame; - } - - return; - } - - if (!bar) { - bar = document.createElement('div'); - bar.className = 'customtime'; - bar.style.position = 'absolute'; - bar.style.top = '0px'; - bar.style.height = '100%'; - - parentContainer.appendChild(bar); - - var drag = document.createElement('div'); - drag.style.position = 'relative'; - drag.style.top = '0px'; - drag.style.left = '-10px'; - drag.style.height = '100%'; - drag.style.width = '20px'; - bar.appendChild(drag); - - this.frame = bar; - - this.subscribe(this, 'movetime'); - } - - if (!parent.conversion) { - parent._updateConversion(); - } - - var x = parent.toScreen(this.customTime); - - bar.style.left = x + 'px'; - bar.title = 'Time: ' + this.customTime; - - return false; -}; - -/** - * Set custom time. - * @param {Date} time - */ -CustomTime.prototype._setCustomTime = function(time) { - this.customTime = new Date(time.valueOf()); - this.repaint(); -}; - -/** - * Retrieve the current custom time. - * @return {Date} customTime - */ -CustomTime.prototype._getCustomTime = function() { - return new Date(this.customTime.valueOf()); -}; - -/** - * Add listeners for mouse and touch events to the component - * @param {Component} component - */ -CustomTime.prototype.subscribe = function (component, event) { - var me = this; - var listener = { - component: component, - event: event, - callback: function (event) { - me._onMouseDown(event, listener); - }, - params: {} - }; - - component.on('mousedown', listener.callback); - me.listeners.push(listener); - -}; - -/** - * Event handler - * @param {String} event name of the event, for example 'click', 'mousemove' - * @param {function} callback callback handler, invoked with the raw HTML Event - * as parameter. - */ -CustomTime.prototype.on = function (event, callback) { - var bar = this.frame; - if (!bar) { - throw new Error('Cannot add event listener: no parent attached'); - } - - events.addListener(this, event, callback); - util.addEventListener(bar, event, callback); -}; - -/** - * Start moving horizontally - * @param {Event} event - * @param {Object} listener Listener containing the component and params - * @private - */ -CustomTime.prototype._onMouseDown = function(event, listener) { - event = event || window.event; - var params = listener.params; - - // only react on left mouse button down - var leftButtonDown = event.which ? (event.which == 1) : (event.button == 1); - if (!leftButtonDown) { - return; - } - - // get mouse position - params.mouseX = util.getPageX(event); - params.moved = false; - - params.customTime = this.customTime; - - // add event listeners to handle moving the custom time bar - var me = this; - if (!params.onMouseMove) { - params.onMouseMove = function (event) { - me._onMouseMove(event, listener); - }; - util.addEventListener(document, 'mousemove', params.onMouseMove); - } - if (!params.onMouseUp) { - params.onMouseUp = function (event) { - me._onMouseUp(event, listener); - }; - util.addEventListener(document, 'mouseup', params.onMouseUp); - } - - util.stopPropagation(event); - util.preventDefault(event); -}; - -/** - * Perform moving operating. - * This function activated from within the funcion CustomTime._onMouseDown(). - * @param {Event} event - * @param {Object} listener - * @private - */ -CustomTime.prototype._onMouseMove = function (event, listener) { - event = event || window.event; - var params = listener.params; - var parent = this.parent; - - // calculate change in mouse position - var mouseX = util.getPageX(event); - - if (params.mouseX === undefined) { - params.mouseX = mouseX; - } - - var diff = mouseX - params.mouseX; - - // if mouse movement is big enough, register it as a "moved" event - if (Math.abs(diff) >= 1) { - params.moved = true; - } - - var x = parent.toScreen(params.customTime); - var xnew = x + diff; - var time = parent.toTime(xnew); - this._setCustomTime(time); - - // fire a timechange event - events.trigger(this, 'timechange', {customTime: this.customTime}); - - util.preventDefault(event); -}; - -/** - * Stop moving operating. - * This function activated from within the function CustomTime._onMouseDown(). - * @param {event} event - * @param {Object} listener - * @private - */ -CustomTime.prototype._onMouseUp = function (event, listener) { - event = event || window.event; - var params = listener.params; - - // remove event listeners here, important for Safari - if (params.onMouseMove) { - util.removeEventListener(document, 'mousemove', params.onMouseMove); - params.onMouseMove = null; - } - if (params.onMouseUp) { - util.removeEventListener(document, 'mouseup', params.onMouseUp); - params.onMouseUp = null; - } - - if (params.moved) { - // fire a timechanged event - events.trigger(this, 'timechanged', {customTime: this.customTime}); - } -}; - -/** - * An ItemSet holds a set of items and ranges which can be displayed in a - * range. The width is determined by the parent of the ItemSet, and the height - * is determined by the size of the items. - * @param {Component} parent - * @param {Component[]} [depends] Components on which this components depends - * (except for the parent) - * @param {Object} [options] See ItemSet.setOptions for the available - * options. - * @constructor ItemSet - * @extends Panel - */ -// TODO: improve performance by replacing all Array.forEach with a for loop -function ItemSet(parent, depends, options) { - this.id = util.randomUUID(); - this.parent = parent; - this.depends = depends; - - // one options object is shared by this itemset and all its items - this.options = options || {}; - this.defaultOptions = { - type: 'box', - align: 'center', - orientation: 'bottom', - margin: { - axis: 20, - item: 10 - }, - padding: 5 - }; - - this.dom = {}; - - var me = this; - this.itemsData = null; // DataSet - this.range = null; // Range or Object {start: number, end: number} - - this.listeners = { - 'add': function (event, params, senderId) { - if (senderId != me.id) { - me._onAdd(params.items); - } - }, - 'update': function (event, params, senderId) { - if (senderId != me.id) { - me._onUpdate(params.items); - } - }, - 'remove': function (event, params, senderId) { - if (senderId != me.id) { - me._onRemove(params.items); - } - } - }; - - this.items = {}; // object with an Item for every data item - this.selection = []; // list with the ids of all selected nodes - this.queue = {}; // queue with id/actions: 'add', 'update', 'delete' - this.stack = new Stack(this, Object.create(this.options)); - this.conversion = null; - - // TODO: ItemSet should also attach event listeners for rangechange and rangechanged, like timeaxis -} - -ItemSet.prototype = new Panel(); - -// available item types will be registered here -ItemSet.types = { - box: ItemBox, - range: ItemRange, - rangeoverflow: ItemRangeOverflow, - point: ItemPoint -}; - -/** - * Set options for the ItemSet. Existing options will be extended/overwritten. - * @param {Object} [options] The following options are available: - * {String | function} [className] - * class name for the itemset - * {String} [type] - * Default type for the items. Choose from 'box' - * (default), 'point', or 'range'. The default - * Style can be overwritten by individual items. - * {String} align - * Alignment for the items, only applicable for - * ItemBox. Choose 'center' (default), 'left', or - * 'right'. - * {String} orientation - * Orientation of the item set. Choose 'top' or - * 'bottom' (default). - * {Number} margin.axis - * Margin between the axis and the items in pixels. - * Default is 20. - * {Number} margin.item - * Margin between items in pixels. Default is 10. - * {Number} padding - * Padding of the contents of an item in pixels. - * Must correspond with the items css. Default is 5. - */ -ItemSet.prototype.setOptions = Component.prototype.setOptions; - -/** - * Set range (start and end). - * @param {Range | Object} range A Range or an object containing start and end. - */ -ItemSet.prototype.setRange = function setRange(range) { - if (!(range instanceof Range) && (!range || !range.start || !range.end)) { - throw new TypeError('Range must be an instance of Range, ' + - 'or an object containing start and end.'); - } - this.range = range; -}; - -/** - * Set selected items by their id. Replaces the current selection - * Unknown id's are silently ignored. - * @param {Array} [ids] An array with zero or more id's of the items to be - * selected. If ids is an empty array, all items will be - * unselected. - */ -ItemSet.prototype.setSelection = function setSelection(ids) { - var i, ii, id, item, selection; - - if (ids) { - if (!Array.isArray(ids)) { - throw new TypeError('Array expected'); - } - - // unselect currently selected items - for (i = 0, ii = this.selection.length; i < ii; i++) { - id = this.selection[i]; - item = this.items[id]; - if (item) item.unselect(); - } - - // select items - this.selection = []; - for (i = 0, ii = ids.length; i < ii; i++) { - id = ids[i]; - item = this.items[id]; - if (item) { - this.selection.push(id); - item.select(); - } - } - - // trigger a select event - selection = this.selection.concat([]); - events.trigger(this, 'select', { - ids: selection - }); - - if (this.controller) { - this.requestRepaint(); - } - } -}; - -/** - * Get the selected items by their id - * @return {Array} ids The ids of the selected items - */ -ItemSet.prototype.getSelection = function getSelection() { - return this.selection.concat([]); -}; - -/** - * Deselect a selected item - * @param {String | Number} id - * @private - */ -ItemSet.prototype._deselect = function _deselect(id) { - var selection = this.selection; - for (var i = 0, ii = selection.length; i < ii; i++) { - if (selection[i] == id) { // non-strict comparison! - selection.splice(i, 1); - break; - } - } -}; - -/** - * Repaint the component - * @return {Boolean} changed - */ -ItemSet.prototype.repaint = function repaint() { - var changed = 0, - update = util.updateProperty, - asSize = util.option.asSize, - options = this.options, - orientation = this.getOption('orientation'), - defaultOptions = this.defaultOptions, - frame = this.frame; - - if (!frame) { - frame = document.createElement('div'); - frame.className = 'itemset'; - - var className = options.className; - if (className) { - util.addClassName(frame, util.option.asString(className)); - } - - // create background panel - var background = document.createElement('div'); - background.className = 'background'; - frame.appendChild(background); - this.dom.background = background; - - // create foreground panel - var foreground = document.createElement('div'); - foreground.className = 'foreground'; - frame.appendChild(foreground); - this.dom.foreground = foreground; - - // create axis panel - var axis = document.createElement('div'); - axis.className = 'itemset-axis'; - //frame.appendChild(axis); - this.dom.axis = axis; - - this.frame = frame; - changed += 1; - } - - if (!this.parent) { - throw new Error('Cannot repaint itemset: no parent attached'); - } - var parentContainer = this.parent.getContainer(); - if (!parentContainer) { - throw new Error('Cannot repaint itemset: parent has no container element'); - } - if (!frame.parentNode) { - parentContainer.appendChild(frame); - changed += 1; - } - if (!this.dom.axis.parentNode) { - parentContainer.appendChild(this.dom.axis); - changed += 1; - } - - // reposition frame - changed += update(frame.style, 'left', asSize(options.left, '0px')); - changed += update(frame.style, 'top', asSize(options.top, '0px')); - changed += update(frame.style, 'width', asSize(options.width, '100%')); - changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); - - // reposition axis - changed += update(this.dom.axis.style, 'left', asSize(options.left, '0px')); - changed += update(this.dom.axis.style, 'width', asSize(options.width, '100%')); - if (orientation == 'bottom') { - changed += update(this.dom.axis.style, 'top', (this.height + this.top) + 'px'); - } - else { // orientation == 'top' - changed += update(this.dom.axis.style, 'top', this.top + 'px'); - } - - this._updateConversion(); - - var me = this, - queue = this.queue, - itemsData = this.itemsData, - items = this.items, - dataOptions = { - // TODO: cleanup - // fields: [(itemsData && itemsData.fieldId || 'id'), 'start', 'end', 'content', 'type', 'className'] - }; - - // show/hide added/changed/removed items - for (var id in queue) { - if (queue.hasOwnProperty(id)) { - var entry = queue[id], - item = items[id], - action = entry.action; - - //noinspection FallthroughInSwitchStatementJS - switch (action) { - case 'add': - case 'update': - var itemData = itemsData && itemsData.get(id, dataOptions); - - if (itemData) { - var type = itemData.type || - (itemData.start && itemData.end && 'range') || - options.type || - 'box'; - var constructor = ItemSet.types[type]; - - // TODO: how to handle items with invalid data? hide them and give a warning? or throw an error? - if (item) { - // update item - if (!constructor || !(item instanceof constructor)) { - // item type has changed, hide and delete the item - changed += item.hide(); - item = null; - } - else { - item.data = itemData; // TODO: create a method item.setData ? - changed++; - } - } - - if (!item) { - // create item - if (constructor) { - item = new constructor(me, itemData, options, defaultOptions); - item.id = entry.id; // we take entry.id, as id itself is stringified - changed++; - } - else { - throw new TypeError('Unknown item type "' + type + '"'); - } - } - - // force a repaint (not only a reposition) - item.repaint(); - - items[id] = item; - } - - // update queue - delete queue[id]; - break; - - case 'remove': - if (item) { - // remove the item from the set selected items - if (item.selected) { - me._deselect(id); - } - - // remove DOM of the item - changed += item.hide(); - } - - // update lists - delete items[id]; - delete queue[id]; - break; - - default: - console.log('Error: unknown action "' + action + '"'); - } - } - } - - // reposition all items. Show items only when in the visible area - util.forEach(this.items, function (item) { - if (item.visible) { - changed += item.show(); - item.reposition(); - } - else { - changed += item.hide(); - } - }); - - return (changed > 0); -}; - -/** - * Get the foreground container element - * @return {HTMLElement} foreground - */ -ItemSet.prototype.getForeground = function getForeground() { - return this.dom.foreground; -}; - -/** - * Get the background container element - * @return {HTMLElement} background - */ -ItemSet.prototype.getBackground = function getBackground() { - return this.dom.background; -}; - -/** - * Get the axis container element - * @return {HTMLElement} axis - */ -ItemSet.prototype.getAxis = function getAxis() { - return this.dom.axis; -}; - -/** - * Reflow the component - * @return {Boolean} resized - */ -ItemSet.prototype.reflow = function reflow () { - var changed = 0, - options = this.options, - marginAxis = options.margin && options.margin.axis || this.defaultOptions.margin.axis, - marginItem = options.margin && options.margin.item || this.defaultOptions.margin.item, - update = util.updateProperty, - asNumber = util.option.asNumber, - asSize = util.option.asSize, - frame = this.frame; - - if (frame) { - this._updateConversion(); - - util.forEach(this.items, function (item) { - changed += item.reflow(); - }); - - // TODO: stack.update should be triggered via an event, in stack itself - // TODO: only update the stack when there are changed items - this.stack.update(); - - var maxHeight = asNumber(options.maxHeight); - var fixedHeight = (asSize(options.height) != null); - var height; - if (fixedHeight) { - height = frame.offsetHeight; - } - else { - // height is not specified, determine the height from the height and positioned items - var visibleItems = this.stack.ordered; // TODO: not so nice way to get the filtered items - if (visibleItems.length) { - var min = visibleItems[0].top; - var max = visibleItems[0].top + visibleItems[0].height; - util.forEach(visibleItems, function (item) { - min = Math.min(min, item.top); - max = Math.max(max, (item.top + item.height)); - }); - height = (max - min) + marginAxis + marginItem; - } - else { - height = marginAxis + marginItem; - } - } - if (maxHeight != null) { - height = Math.min(height, maxHeight); - } - changed += update(this, 'height', height); - - // calculate height from items - changed += update(this, 'top', frame.offsetTop); - changed += update(this, 'left', frame.offsetLeft); - changed += update(this, 'width', frame.offsetWidth); - } - else { - changed += 1; - } - - return (changed > 0); -}; - -/** - * Hide this component from the DOM - * @return {Boolean} changed - */ -ItemSet.prototype.hide = function hide() { - var changed = false; - - // remove the DOM - if (this.frame && this.frame.parentNode) { - this.frame.parentNode.removeChild(this.frame); - changed = true; - } - if (this.dom.axis && this.dom.axis.parentNode) { - this.dom.axis.parentNode.removeChild(this.dom.axis); - changed = true; - } - - return changed; -}; - -/** - * Set items - * @param {vis.DataSet | null} items - */ -ItemSet.prototype.setItems = function setItems(items) { - var me = this, - ids, - oldItemsData = this.itemsData; - - // replace the dataset - if (!items) { - this.itemsData = null; - } - else if (items instanceof DataSet || items instanceof DataView) { - this.itemsData = items; - } - else { - throw new TypeError('Data must be an instance of DataSet'); - } - - if (oldItemsData) { - // unsubscribe from old dataset - util.forEach(this.listeners, function (callback, event) { - oldItemsData.unsubscribe(event, callback); - }); - - // remove all drawn items - ids = oldItemsData.getIds(); - this._onRemove(ids); - } - - if (this.itemsData) { - // subscribe to new dataset - var id = this.id; - util.forEach(this.listeners, function (callback, event) { - me.itemsData.subscribe(event, callback, id); - }); - - // draw all new items - ids = this.itemsData.getIds(); - this._onAdd(ids); - } -}; - -/** - * Get the current items items - * @returns {vis.DataSet | null} - */ -ItemSet.prototype.getItems = function getItems() { - return this.itemsData; -}; - -/** - * Handle updated items - * @param {Number[]} ids - * @private - */ -ItemSet.prototype._onUpdate = function _onUpdate(ids) { - this._toQueue('update', ids); -}; - -/** - * Handle changed items - * @param {Number[]} ids - * @private - */ -ItemSet.prototype._onAdd = function _onAdd(ids) { - this._toQueue('add', ids); -}; - -/** - * Handle removed items - * @param {Number[]} ids - * @private - */ -ItemSet.prototype._onRemove = function _onRemove(ids) { - this._toQueue('remove', ids); -}; - -/** - * Put items in the queue to be added/updated/remove - * @param {String} action can be 'add', 'update', 'remove' - * @param {Number[]} ids - */ -ItemSet.prototype._toQueue = function _toQueue(action, ids) { - var queue = this.queue; - ids.forEach(function (id) { - queue[id] = { - id: id, - action: action - }; - }); - - if (this.controller) { - //this.requestReflow(); - this.requestRepaint(); - } -}; - -/** - * Calculate the scale and offset to convert a position on screen to the - * corresponding date and vice versa. - * After the method _updateConversion is executed once, the methods toTime - * and toScreen can be used. - * @private - */ -ItemSet.prototype._updateConversion = function _updateConversion() { - var range = this.range; - if (!range) { - throw new Error('No range configured'); - } - - if (range.conversion) { - this.conversion = range.conversion(this.width); - } - else { - this.conversion = Range.conversion(range.start, range.end, this.width); - } -}; - -/** - * Convert a position on screen (pixels) to a datetime - * Before this method can be used, the method _updateConversion must be - * executed once. - * @param {int} x Position on the screen in pixels - * @return {Date} time The datetime the corresponds with given position x - */ -ItemSet.prototype.toTime = function toTime(x) { - var conversion = this.conversion; - return new Date(x / conversion.scale + conversion.offset); -}; - -/** - * Convert a datetime (Date object) into a position on the screen - * Before this method can be used, the method _updateConversion must be - * executed once. - * @param {Date} time A date - * @return {int} x The position on the screen in pixels which corresponds - * with the given date. - */ -ItemSet.prototype.toScreen = function toScreen(time) { - var conversion = this.conversion; - return (time.valueOf() - conversion.offset) * conversion.scale; -}; - -/** - * @constructor Item - * @param {ItemSet} parent - * @param {Object} data Object containing (optional) parameters type, - * start, end, content, group, className. - * @param {Object} [options] Options to set initial property values - * @param {Object} [defaultOptions] default options - * // TODO: describe available options - */ -function Item (parent, data, options, defaultOptions) { - this.parent = parent; - this.data = data; - this.dom = null; - this.options = options || {}; - this.defaultOptions = defaultOptions || {}; - - this.selected = false; - this.visible = false; - this.top = 0; - this.left = 0; - this.width = 0; - this.height = 0; -} - -/** - * Select current item - */ -Item.prototype.select = function select() { - this.selected = true; - if (this.visible) this.repaint(); -}; - -/** - * Unselect current item - */ -Item.prototype.unselect = function unselect() { - this.selected = false; - if (this.visible) this.repaint(); -}; - -/** - * Show the Item in the DOM (when not already visible) - * @return {Boolean} changed - */ -Item.prototype.show = function show() { - return false; -}; - -/** - * Hide the Item from the DOM (when visible) - * @return {Boolean} changed - */ -Item.prototype.hide = function hide() { - return false; -}; - -/** - * Repaint the item - * @return {Boolean} changed - */ -Item.prototype.repaint = function repaint() { - // should be implemented by the item - return false; -}; - -/** - * Reflow the item - * @return {Boolean} resized - */ -Item.prototype.reflow = function reflow() { - // should be implemented by the item - return false; -}; - -/** - * Return the items width - * @return {Integer} width - */ -Item.prototype.getWidth = function getWidth() { - return this.width; -} - -/** - * @constructor ItemBox - * @extends Item - * @param {ItemSet} parent - * @param {Object} data Object containing parameters start - * content, className. - * @param {Object} [options] Options to set initial property values - * @param {Object} [defaultOptions] default options - * // TODO: describe available options - */ -function ItemBox (parent, data, options, defaultOptions) { - this.props = { - dot: { - left: 0, - top: 0, - width: 0, - height: 0 - }, - line: { - top: 0, - left: 0, - width: 0, - height: 0 - } - }; - - Item.call(this, parent, data, options, defaultOptions); -} - -ItemBox.prototype = new Item (null, null); - -/** - * Repaint the item - * @return {Boolean} changed - */ -ItemBox.prototype.repaint = function repaint() { - // TODO: make an efficient repaint - var changed = false; - var dom = this.dom; - - if (!dom) { - this._create(); - dom = this.dom; - changed = true; - } - - if (dom) { - if (!this.parent) { - throw new Error('Cannot repaint item: no parent attached'); - } - - if (!dom.box.parentNode) { - var foreground = this.parent.getForeground(); - if (!foreground) { - throw new Error('Cannot repaint time axis: ' + - 'parent has no foreground container element'); - } - foreground.appendChild(dom.box); - changed = true; - } - - if (!dom.line.parentNode) { - var background = this.parent.getBackground(); - if (!background) { - throw new Error('Cannot repaint time axis: ' + - 'parent has no background container element'); - } - background.appendChild(dom.line); - changed = true; - } - - if (!dom.dot.parentNode) { - var axis = this.parent.getAxis(); - if (!background) { - throw new Error('Cannot repaint time axis: ' + - 'parent has no axis container element'); - } - axis.appendChild(dom.dot); - changed = true; - } - - // update contents - if (this.data.content != this.content) { - this.content = this.data.content; - if (this.content instanceof Element) { - dom.content.innerHTML = ''; - dom.content.appendChild(this.content); - } - else if (this.data.content != undefined) { - dom.content.innerHTML = this.content; - } - else { - throw new Error('Property "content" missing in item ' + this.data.id); - } - changed = true; - } - - // update class - var className = (this.data.className? ' ' + this.data.className : '') + - (this.selected ? ' selected' : ''); - if (this.className != className) { - this.className = className; - dom.box.className = 'item box' + className; - dom.line.className = 'item line' + className; - dom.dot.className = 'item dot' + className; - changed = true; - } - } - - return changed; -}; - -/** - * Show the item in the DOM (when not already visible). The items DOM will - * be created when needed. - * @return {Boolean} changed - */ -ItemBox.prototype.show = function show() { - if (!this.dom || !this.dom.box.parentNode) { - return this.repaint(); - } - else { - return false; - } -}; - -/** - * Hide the item from the DOM (when visible) - * @return {Boolean} changed - */ -ItemBox.prototype.hide = function hide() { - var changed = false, - dom = this.dom; - if (dom) { - if (dom.box.parentNode) { - dom.box.parentNode.removeChild(dom.box); - changed = true; - } - if (dom.line.parentNode) { - dom.line.parentNode.removeChild(dom.line); - } - if (dom.dot.parentNode) { - dom.dot.parentNode.removeChild(dom.dot); - } - } - return changed; -}; - -/** - * Reflow the item: calculate its actual size and position from the DOM - * @return {boolean} resized returns true if the axis is resized - * @override - */ -ItemBox.prototype.reflow = function reflow() { - var changed = 0, - update, - dom, - props, - options, - margin, - start, - align, - orientation, - top, - left, - data, - range; - - if (this.data.start == undefined) { - throw new Error('Property "start" missing in item ' + this.data.id); - } - - data = this.data; - range = this.parent && this.parent.range; - if (data && range) { - // TODO: account for the width of the item - var interval = (range.end - range.start); - this.visible = (data.start > range.start - interval) && (data.start < range.end + interval); - } - else { - this.visible = false; - } - - if (this.visible) { - dom = this.dom; - if (dom) { - update = util.updateProperty; - props = this.props; - options = this.options; - start = this.parent.toScreen(this.data.start); - align = options.align || this.defaultOptions.align; - margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; - orientation = options.orientation || this.defaultOptions.orientation; - - changed += update(props.dot, 'height', dom.dot.offsetHeight); - changed += update(props.dot, 'width', dom.dot.offsetWidth); - changed += update(props.line, 'width', dom.line.offsetWidth); - changed += update(props.line, 'height', dom.line.offsetHeight); - changed += update(props.line, 'top', dom.line.offsetTop); - changed += update(this, 'width', dom.box.offsetWidth); - changed += update(this, 'height', dom.box.offsetHeight); - if (align == 'right') { - left = start - this.width; - } - else if (align == 'left') { - left = start; - } - else { - // default or 'center' - left = start - this.width / 2; - } - changed += update(this, 'left', left); - - changed += update(props.line, 'left', start - props.line.width / 2); - changed += update(props.dot, 'left', start - props.dot.width / 2); - changed += update(props.dot, 'top', -props.dot.height / 2); - if (orientation == 'top') { - top = margin; - - changed += update(this, 'top', top); - } - else { - // default or 'bottom' - var parentHeight = this.parent.height; - top = parentHeight - this.height - margin; - - changed += update(this, 'top', top); - } - } - else { - changed += 1; - } - } - - return (changed > 0); -}; - -/** - * Create an items DOM - * @private - */ -ItemBox.prototype._create = function _create() { - var dom = this.dom; - if (!dom) { - this.dom = dom = {}; - - // create the box - dom.box = document.createElement('DIV'); - // className is updated in repaint() - - // contents box (inside the background box). used for making margins - dom.content = document.createElement('DIV'); - dom.content.className = 'content'; - dom.box.appendChild(dom.content); - - // line to axis - dom.line = document.createElement('DIV'); - dom.line.className = 'line'; - - // dot on axis - dom.dot = document.createElement('DIV'); - dom.dot.className = 'dot'; - - // attach this item as attribute - dom.box['timeline-item'] = this; - } -}; - -/** - * Reposition the item, recalculate its left, top, and width, using the current - * range and size of the items itemset - * @override - */ -ItemBox.prototype.reposition = function reposition() { - var dom = this.dom, - props = this.props, - orientation = this.options.orientation || this.defaultOptions.orientation; - - if (dom) { - var box = dom.box, - line = dom.line, - dot = dom.dot; - - box.style.left = this.left + 'px'; - box.style.top = this.top + 'px'; - - line.style.left = props.line.left + 'px'; - if (orientation == 'top') { - line.style.top = 0 + 'px'; - line.style.height = this.top + 'px'; - } - else { - // orientation 'bottom' - line.style.top = (this.top + this.height) + 'px'; - line.style.height = Math.max(this.parent.height - this.top - this.height + - this.props.dot.height / 2, 0) + 'px'; - } - - dot.style.left = props.dot.left + 'px'; - dot.style.top = props.dot.top + 'px'; - } -}; - -/** - * @constructor ItemPoint - * @extends Item - * @param {ItemSet} parent - * @param {Object} data Object containing parameters start - * content, className. - * @param {Object} [options] Options to set initial property values - * @param {Object} [defaultOptions] default options - * // TODO: describe available options - */ -function ItemPoint (parent, data, options, defaultOptions) { - this.props = { - dot: { - top: 0, - width: 0, - height: 0 - }, - content: { - height: 0, - marginLeft: 0 - } - }; - - Item.call(this, parent, data, options, defaultOptions); -} - -ItemPoint.prototype = new Item (null, null); - -/** - * Repaint the item - * @return {Boolean} changed - */ -ItemPoint.prototype.repaint = function repaint() { - // TODO: make an efficient repaint - var changed = false; - var dom = this.dom; - - if (!dom) { - this._create(); - dom = this.dom; - changed = true; - } - - if (dom) { - if (!this.parent) { - throw new Error('Cannot repaint item: no parent attached'); - } - var foreground = this.parent.getForeground(); - if (!foreground) { - throw new Error('Cannot repaint time axis: ' + - 'parent has no foreground container element'); - } - - if (!dom.point.parentNode) { - foreground.appendChild(dom.point); - foreground.appendChild(dom.point); - changed = true; - } - - // update contents - if (this.data.content != this.content) { - this.content = this.data.content; - if (this.content instanceof Element) { - dom.content.innerHTML = ''; - dom.content.appendChild(this.content); - } - else if (this.data.content != undefined) { - dom.content.innerHTML = this.content; - } - else { - throw new Error('Property "content" missing in item ' + this.data.id); - } - changed = true; - } - - // update class - var className = (this.data.className? ' ' + this.data.className : '') + - (this.selected ? ' selected' : ''); - if (this.className != className) { - this.className = className; - dom.point.className = 'item point' + className; - changed = true; - } - } - - return changed; -}; - -/** - * Show the item in the DOM (when not already visible). The items DOM will - * be created when needed. - * @return {Boolean} changed - */ -ItemPoint.prototype.show = function show() { - if (!this.dom || !this.dom.point.parentNode) { - return this.repaint(); - } - else { - return false; - } -}; - -/** - * Hide the item from the DOM (when visible) - * @return {Boolean} changed - */ -ItemPoint.prototype.hide = function hide() { - var changed = false, - dom = this.dom; - if (dom) { - if (dom.point.parentNode) { - dom.point.parentNode.removeChild(dom.point); - changed = true; - } - } - return changed; -}; - -/** - * Reflow the item: calculate its actual size from the DOM - * @return {boolean} resized returns true if the axis is resized - * @override - */ -ItemPoint.prototype.reflow = function reflow() { - var changed = 0, - update, - dom, - props, - options, - margin, - orientation, - start, - top, - data, - range; - - if (this.data.start == undefined) { - throw new Error('Property "start" missing in item ' + this.data.id); - } - - data = this.data; - range = this.parent && this.parent.range; - if (data && range) { - // TODO: account for the width of the item - var interval = (range.end - range.start); - this.visible = (data.start > range.start - interval) && (data.start < range.end); - } - else { - this.visible = false; - } - - if (this.visible) { - dom = this.dom; - if (dom) { - update = util.updateProperty; - props = this.props; - options = this.options; - orientation = options.orientation || this.defaultOptions.orientation; - margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; - start = this.parent.toScreen(this.data.start); - - changed += update(this, 'width', dom.point.offsetWidth); - changed += update(this, 'height', dom.point.offsetHeight); - changed += update(props.dot, 'width', dom.dot.offsetWidth); - changed += update(props.dot, 'height', dom.dot.offsetHeight); - changed += update(props.content, 'height', dom.content.offsetHeight); - - if (orientation == 'top') { - top = margin; - } - else { - // default or 'bottom' - var parentHeight = this.parent.height; - top = Math.max(parentHeight - this.height - margin, 0); - } - changed += update(this, 'top', top); - changed += update(this, 'left', start - props.dot.width / 2); - changed += update(props.content, 'marginLeft', 1.5 * props.dot.width); - //changed += update(props.content, 'marginRight', 0.5 * props.dot.width); // TODO - - changed += update(props.dot, 'top', (this.height - props.dot.height) / 2); - } - else { - changed += 1; - } - } - - return (changed > 0); -}; - -/** - * Create an items DOM - * @private - */ -ItemPoint.prototype._create = function _create() { - var dom = this.dom; - if (!dom) { - this.dom = dom = {}; - - // background box - dom.point = document.createElement('div'); - // className is updated in repaint() - - // contents box, right from the dot - dom.content = document.createElement('div'); - dom.content.className = 'content'; - dom.point.appendChild(dom.content); - - // dot at start - dom.dot = document.createElement('div'); - dom.dot.className = 'dot'; - dom.point.appendChild(dom.dot); - - // attach this item as attribute - dom.point['timeline-item'] = this; - } -}; - -/** - * Reposition the item, recalculate its left, top, and width, using the current - * range and size of the items itemset - * @override - */ -ItemPoint.prototype.reposition = function reposition() { - var dom = this.dom, - props = this.props; - - if (dom) { - dom.point.style.top = this.top + 'px'; - dom.point.style.left = this.left + 'px'; - - dom.content.style.marginLeft = props.content.marginLeft + 'px'; - //dom.content.style.marginRight = props.content.marginRight + 'px'; // TODO - - dom.dot.style.top = props.dot.top + 'px'; - } -}; - -/** - * @constructor ItemRange - * @extends Item - * @param {ItemSet} parent - * @param {Object} data Object containing parameters start, end - * content, className. - * @param {Object} [options] Options to set initial property values - * @param {Object} [defaultOptions] default options - * // TODO: describe available options - */ -function ItemRange (parent, data, options, defaultOptions) { - this.props = { - content: { - left: 0, - width: 0 - } - }; - - Item.call(this, parent, data, options, defaultOptions); -} - -ItemRange.prototype = new Item (null, null); - -/** - * Repaint the item - * @return {Boolean} changed - */ -ItemRange.prototype.repaint = function repaint() { - // TODO: make an efficient repaint - var changed = false; - var dom = this.dom; - - if (!dom) { - this._create(); - dom = this.dom; - changed = true; - } - - if (dom) { - if (!this.parent) { - throw new Error('Cannot repaint item: no parent attached'); - } - var foreground = this.parent.getForeground(); - if (!foreground) { - throw new Error('Cannot repaint time axis: ' + - 'parent has no foreground container element'); - } - - if (!dom.box.parentNode) { - foreground.appendChild(dom.box); - changed = true; - } - - // update content - if (this.data.content != this.content) { - this.content = this.data.content; - if (this.content instanceof Element) { - dom.content.innerHTML = ''; - dom.content.appendChild(this.content); - } - else if (this.data.content != undefined) { - dom.content.innerHTML = this.content; - } - else { - throw new Error('Property "content" missing in item ' + this.data.id); - } - changed = true; - } - - // update class - var className = (this.data.className? ' ' + this.data.className : '') + - (this.selected ? ' selected' : ''); - if (this.className != className) { - this.className = className; - dom.box.className = 'item range' + className; - changed = true; - } - } - - return changed; -}; - -/** - * Show the item in the DOM (when not already visible). The items DOM will - * be created when needed. - * @return {Boolean} changed - */ -ItemRange.prototype.show = function show() { - if (!this.dom || !this.dom.box.parentNode) { - return this.repaint(); - } - else { - return false; - } -}; - -/** - * Hide the item from the DOM (when visible) - * @return {Boolean} changed - */ -ItemRange.prototype.hide = function hide() { - var changed = false, - dom = this.dom; - if (dom) { - if (dom.box.parentNode) { - dom.box.parentNode.removeChild(dom.box); - changed = true; - } - } - return changed; -}; - -/** - * Reflow the item: calculate its actual size from the DOM - * @return {boolean} resized returns true if the axis is resized - * @override - */ -ItemRange.prototype.reflow = function reflow() { - var changed = 0, - dom, - props, - options, - margin, - padding, - parent, - start, - end, - data, - range, - update, - box, - parentWidth, - contentLeft, - orientation, - top; - - if (this.data.start == undefined) { - throw new Error('Property "start" missing in item ' + this.data.id); - } - if (this.data.end == undefined) { - throw new Error('Property "end" missing in item ' + this.data.id); - } - - data = this.data; - range = this.parent && this.parent.range; - if (data && range) { - // TODO: account for the width of the item. Take some margin - this.visible = (data.start < range.end) && (data.end > range.start); - } - else { - this.visible = false; - } - - if (this.visible) { - dom = this.dom; - if (dom) { - props = this.props; - options = this.options; - parent = this.parent; - start = parent.toScreen(this.data.start); - end = parent.toScreen(this.data.end); - update = util.updateProperty; - box = dom.box; - parentWidth = parent.width; - orientation = options.orientation || this.defaultOptions.orientation; - margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; - padding = options.padding || this.defaultOptions.padding; - - changed += update(props.content, 'width', dom.content.offsetWidth); - - changed += update(this, 'height', box.offsetHeight); - - // limit the width of the this, as browsers cannot draw very wide divs - if (start < -parentWidth) { - start = -parentWidth; - } - if (end > 2 * parentWidth) { - end = 2 * parentWidth; - } - - // when range exceeds left of the window, position the contents at the left of the visible area - if (start < 0) { - contentLeft = Math.min(-start, - (end - start - props.content.width - 2 * padding)); - // TODO: remove the need for options.padding. it's terrible. - } - else { - contentLeft = 0; - } - changed += update(props.content, 'left', contentLeft); - - if (orientation == 'top') { - top = margin; - changed += update(this, 'top', top); - } - else { - // default or 'bottom' - top = parent.height - this.height - margin; - changed += update(this, 'top', top); - } - - changed += update(this, 'left', start); - changed += update(this, 'width', Math.max(end - start, 1)); // TODO: reckon with border width; - } - else { - changed += 1; - } - } - - return (changed > 0); -}; - -/** - * Create an items DOM - * @private - */ -ItemRange.prototype._create = function _create() { - var dom = this.dom; - if (!dom) { - this.dom = dom = {}; - // background box - dom.box = document.createElement('div'); - // className is updated in repaint() - - // contents box - dom.content = document.createElement('div'); - dom.content.className = 'content'; - dom.box.appendChild(dom.content); - - // attach this item as attribute - dom.box['timeline-item'] = this; - } -}; - -/** - * Reposition the item, recalculate its left, top, and width, using the current - * range and size of the items itemset - * @override - */ -ItemRange.prototype.reposition = function reposition() { - var dom = this.dom, - props = this.props; - - if (dom) { - dom.box.style.top = this.top + 'px'; - dom.box.style.left = this.left + 'px'; - dom.box.style.width = this.width + 'px'; - - dom.content.style.left = props.content.left + 'px'; - } -}; - -/** - * @constructor ItemRangeOverflow - * @extends ItemRange - * @param {ItemSet} parent - * @param {Object} data Object containing parameters start, end - * content, className. - * @param {Object} [options] Options to set initial property values - * @param {Object} [defaultOptions] default options - * // TODO: describe available options - */ -function ItemRangeOverflow (parent, data, options, defaultOptions) { - this.props = { - content: { - left: 0, - width: 0 - } - }; - - ItemRange.call(this, parent, data, options, defaultOptions); -} - -ItemRangeOverflow.prototype = new ItemRange (null, null); - -/** - * Repaint the item - * @return {Boolean} changed - */ -ItemRangeOverflow.prototype.repaint = function repaint() { - // TODO: make an efficient repaint - var changed = false; - var dom = this.dom; - - if (!dom) { - this._create(); - dom = this.dom; - changed = true; - } - - if (dom) { - if (!this.parent) { - throw new Error('Cannot repaint item: no parent attached'); - } - var foreground = this.parent.getForeground(); - if (!foreground) { - throw new Error('Cannot repaint time axis: ' + - 'parent has no foreground container element'); - } - - if (!dom.box.parentNode) { - foreground.appendChild(dom.box); - changed = true; - } - - // update content - if (this.data.content != this.content) { - this.content = this.data.content; - if (this.content instanceof Element) { - dom.content.innerHTML = ''; - dom.content.appendChild(this.content); - } - else if (this.data.content != undefined) { - dom.content.innerHTML = this.content; - } - else { - throw new Error('Property "content" missing in item ' + this.data.id); - } - changed = true; - } - - // update class - var className = this.data.className ? (' ' + this.data.className) : ''; - if (this.className != className) { - this.className = className; - dom.box.className = 'item rangeoverflow' + className; - changed = true; - } - } - - return changed; -}; - -/** - * Return the items width - * @return {Number} width - */ -ItemRangeOverflow.prototype.getWidth = function getWidth() { - if (this.props.content !== undefined && this.width < this.props.content.width) - return this.props.content.width; - else - return this.width; -}; - -/** - * @constructor Group - * @param {GroupSet} parent - * @param {Number | String} groupId - * @param {Object} [options] Options to set initial property values - * // TODO: describe available options - * @extends Component - */ -function Group (parent, groupId, options) { - this.id = util.randomUUID(); - this.parent = parent; - - this.groupId = groupId; - this.itemset = null; // ItemSet - this.options = options || {}; - this.options.top = 0; - - this.props = { - label: { - width: 0, - height: 0 - } - }; - - this.top = 0; - this.left = 0; - this.width = 0; - this.height = 0; -} - -Group.prototype = new Component(); - -// TODO: comment -Group.prototype.setOptions = Component.prototype.setOptions; - -/** - * Get the container element of the panel, which can be used by a child to - * add its own widgets. - * @returns {HTMLElement} container - */ -Group.prototype.getContainer = function () { - return this.parent.getContainer(); -}; - -/** - * Set item set for the group. The group will create a view on the itemset, - * filtered by the groups id. - * @param {DataSet | DataView} items - */ -Group.prototype.setItems = function setItems(items) { - if (this.itemset) { - // remove current item set - this.itemset.hide(); - this.itemset.setItems(); - - this.parent.controller.remove(this.itemset); - this.itemset = null; - } - - if (items) { - var groupId = this.groupId; - - var itemsetOptions = Object.create(this.options); - this.itemset = new ItemSet(this, null, itemsetOptions); - this.itemset.setRange(this.parent.range); - - this.view = new DataView(items, { - filter: function (item) { - return item.group == groupId; - } - }); - this.itemset.setItems(this.view); - - this.parent.controller.add(this.itemset); - } -}; - -/** - * Set selected items by their id. Replaces the current selection. - * Unknown id's are silently ignored. - * @param {Array} [ids] An array with zero or more id's of the items to be - * selected. If ids is an empty array, all items will be - * unselected. - */ -Group.prototype.setSelection = function setSelection(ids) { - if (this.itemset) this.itemset.setSelection(ids); -}; - -/** - * Get the selected items by their id - * @return {Array} ids The ids of the selected items - */ -Group.prototype.getSelection = function getSelection() { - return this.itemset ? this.itemset.getSelection() : []; -}; - -/** - * Repaint the item - * @return {Boolean} changed - */ -Group.prototype.repaint = function repaint() { - return false; -}; - -/** - * Reflow the item - * @return {Boolean} resized - */ -Group.prototype.reflow = function reflow() { - var changed = 0, - update = util.updateProperty; - - changed += update(this, 'top', this.itemset ? this.itemset.top : 0); - changed += update(this, 'height', this.itemset ? this.itemset.height : 0); - - // TODO: reckon with the height of the group label - - if (this.label) { - var inner = this.label.firstChild; - changed += update(this.props.label, 'width', inner.clientWidth); - changed += update(this.props.label, 'height', inner.clientHeight); - } - else { - changed += update(this.props.label, 'width', 0); - changed += update(this.props.label, 'height', 0); - } - - return (changed > 0); -}; - -/** - * An GroupSet holds a set of groups - * @param {Component} parent - * @param {Component[]} [depends] Components on which this components depends - * (except for the parent) - * @param {Object} [options] See GroupSet.setOptions for the available - * options. - * @constructor GroupSet - * @extends Panel - */ -function GroupSet(parent, depends, options) { - this.id = util.randomUUID(); - this.parent = parent; - this.depends = depends; - - this.options = options || {}; - - this.range = null; // Range or Object {start: number, end: number} - this.itemsData = null; // DataSet with items - this.groupsData = null; // DataSet with groups - - this.groups = {}; // map with groups - - this.dom = {}; - this.props = { - labels: { - width: 0 - } - }; - - // TODO: implement right orientation of the labels - - // changes in groups are queued key/value map containing id/action - this.queue = {}; - - var me = this; - this.listeners = { - 'add': function (event, params) { - me._onAdd(params.items); - }, - 'update': function (event, params) { - me._onUpdate(params.items); - }, - 'remove': function (event, params) { - me._onRemove(params.items); - } - }; -} - -GroupSet.prototype = new Panel(); - -/** - * Set options for the GroupSet. Existing options will be extended/overwritten. - * @param {Object} [options] The following options are available: - * {String | function} groupsOrder - * TODO: describe options - */ -GroupSet.prototype.setOptions = Component.prototype.setOptions; - -GroupSet.prototype.setRange = function (range) { - // TODO: implement setRange -}; - -/** - * Set items - * @param {vis.DataSet | null} items - */ -GroupSet.prototype.setItems = function setItems(items) { - this.itemsData = items; - - for (var id in this.groups) { - if (this.groups.hasOwnProperty(id)) { - var group = this.groups[id]; - group.setItems(items); - } - } -}; - -/** - * Get items - * @return {vis.DataSet | null} items - */ -GroupSet.prototype.getItems = function getItems() { - return this.itemsData; -}; - -/** - * Set range (start and end). - * @param {Range | Object} range A Range or an object containing start and end. - */ -GroupSet.prototype.setRange = function setRange(range) { - this.range = range; -}; - -/** - * Set groups - * @param {vis.DataSet} groups - */ -GroupSet.prototype.setGroups = function setGroups(groups) { - var me = this, - ids; - - // unsubscribe from current dataset - if (this.groupsData) { - util.forEach(this.listeners, function (callback, event) { - me.groupsData.unsubscribe(event, callback); - }); - - // remove all drawn groups - ids = this.groupsData.getIds(); - this._onRemove(ids); - } - - // replace the dataset - if (!groups) { - this.groupsData = null; - } - else if (groups instanceof DataSet) { - this.groupsData = groups; - } - else { - this.groupsData = new DataSet({ - convert: { - start: 'Date', - end: 'Date' - } - }); - this.groupsData.add(groups); - } - - if (this.groupsData) { - // subscribe to new dataset - var id = this.id; - util.forEach(this.listeners, function (callback, event) { - me.groupsData.subscribe(event, callback, id); - }); - - // draw all new groups - ids = this.groupsData.getIds(); - this._onAdd(ids); - } -}; - -/** - * Get groups - * @return {vis.DataSet | null} groups - */ -GroupSet.prototype.getGroups = function getGroups() { - return this.groupsData; -}; - -/** - * Set selected items by their id. Replaces the current selection. - * Unknown id's are silently ignored. - * @param {Array} [ids] An array with zero or more id's of the items to be - * selected. If ids is an empty array, all items will be - * unselected. - */ -GroupSet.prototype.setSelection = function setSelection(ids) { - var selection = [], - groups = this.groups; - - // iterate over each of the groups - for (var id in groups) { - if (groups.hasOwnProperty(id)) { - var group = groups[id]; - group.setSelection(ids); - } - } - - return selection; -}; - -/** - * Get the selected items by their id - * @return {Array} ids The ids of the selected items - */ -GroupSet.prototype.getSelection = function getSelection() { - var selection = [], - groups = this.groups; - - // iterate over each of the groups - for (var id in groups) { - if (groups.hasOwnProperty(id)) { - var group = groups[id]; - selection = selection.concat(group.getSelection()); - } - } - - return selection; -}; - -/** - * Repaint the component - * @return {Boolean} changed - */ -GroupSet.prototype.repaint = function repaint() { - var changed = 0, - i, id, group, label, - update = util.updateProperty, - asSize = util.option.asSize, - asElement = util.option.asElement, - options = this.options, - frame = this.dom.frame, - labels = this.dom.labels, - labelSet = this.dom.labelSet; - - // create frame - if (!this.parent) { - throw new Error('Cannot repaint groupset: no parent attached'); - } - var parentContainer = this.parent.getContainer(); - if (!parentContainer) { - throw new Error('Cannot repaint groupset: parent has no container element'); - } - if (!frame) { - frame = document.createElement('div'); - frame.className = 'groupset'; - this.dom.frame = frame; - - var className = options.className; - if (className) { - util.addClassName(frame, util.option.asString(className)); - } - - changed += 1; - } - if (!frame.parentNode) { - parentContainer.appendChild(frame); - changed += 1; - } - - // create labels - var labelContainer = asElement(options.labelContainer); - if (!labelContainer) { - throw new Error('Cannot repaint groupset: option "labelContainer" not defined'); - } - if (!labels) { - labels = document.createElement('div'); - labels.className = 'labels'; - this.dom.labels = labels; - } - if (!labelSet) { - labelSet = document.createElement('div'); - labelSet.className = 'label-set'; - labels.appendChild(labelSet); - this.dom.labelSet = labelSet; - } - if (!labels.parentNode || labels.parentNode != labelContainer) { - if (labels.parentNode) { - labels.parentNode.removeChild(labels.parentNode); - } - labelContainer.appendChild(labels); - } - - // reposition frame - changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); - changed += update(frame.style, 'top', asSize(options.top, '0px')); - changed += update(frame.style, 'left', asSize(options.left, '0px')); - changed += update(frame.style, 'width', asSize(options.width, '100%')); - - // reposition labels - changed += update(labelSet.style, 'top', asSize(options.top, '0px')); - changed += update(labelSet.style, 'height', asSize(options.height, this.height + 'px')); - - var me = this, - queue = this.queue, - groups = this.groups, - groupsData = this.groupsData; - - // show/hide added/changed/removed groups - var ids = Object.keys(queue); - if (ids.length) { - ids.forEach(function (id) { - var action = queue[id]; - var group = groups[id]; - - //noinspection FallthroughInSwitchStatementJS - switch (action) { - case 'add': - case 'update': - if (!group) { - var groupOptions = Object.create(me.options); - util.extend(groupOptions, { - height: null, - maxHeight: null - }); - - group = new Group(me, id, groupOptions); - group.setItems(me.itemsData); // attach items data - groups[id] = group; - - me.controller.add(group); - } - - // TODO: update group data - group.data = groupsData.get(id); - - delete queue[id]; - break; - - case 'remove': - if (group) { - group.setItems(); // detach items data - delete groups[id]; - - me.controller.remove(group); - } - - // update lists - delete queue[id]; - break; - - default: - console.log('Error: unknown action "' + action + '"'); - } - }); - - // the groupset depends on each of the groups - //this.depends = this.groups; // TODO: gives a circular reference through the parent - - // TODO: apply dependencies of the groupset - - // update the top positions of the groups in the correct order - var orderedGroups = this.groupsData.getIds({ - order: this.options.groupOrder - }); - for (i = 0; i < orderedGroups.length; i++) { - (function (group, prevGroup) { - var top = 0; - if (prevGroup) { - top = function () { - // TODO: top must reckon with options.maxHeight - return prevGroup.top + prevGroup.height; - } - } - group.setOptions({ - top: top - }); - })(groups[orderedGroups[i]], groups[orderedGroups[i - 1]]); - } - - // (re)create the labels - while (labelSet.firstChild) { - labelSet.removeChild(labelSet.firstChild); - } - for (i = 0; i < orderedGroups.length; i++) { - id = orderedGroups[i]; - label = this._createLabel(id); - labelSet.appendChild(label); - } - - changed++; - } - - // reposition the labels - // TODO: labels are not displayed correctly when orientation=='top' - // TODO: width of labelPanel is not immediately updated on a change in groups - for (id in groups) { - if (groups.hasOwnProperty(id)) { - group = groups[id]; - label = group.label; - if (label) { - label.style.top = group.top + 'px'; - label.style.height = group.height + 'px'; - } - } - } - - return (changed > 0); -}; - -/** - * Create a label for group with given id - * @param {Number} id - * @return {Element} label - * @private - */ -GroupSet.prototype._createLabel = function(id) { - var group = this.groups[id]; - var label = document.createElement('div'); - label.className = 'label'; - var inner = document.createElement('div'); - inner.className = 'inner'; - label.appendChild(inner); - - var content = group.data && group.data.content; - if (content instanceof Element) { - inner.appendChild(content); - } - else if (content != undefined) { - inner.innerHTML = content; - } - - var className = group.data && group.data.className; - if (className) { - util.addClassName(label, className); - } - - group.label = label; // TODO: not so nice, parking labels in the group this way!!! - - return label; -}; - -/** - * Get container element - * @return {HTMLElement} container - */ -GroupSet.prototype.getContainer = function getContainer() { - return this.dom.frame; -}; - -/** - * Get the width of the group labels - * @return {Number} width - */ -GroupSet.prototype.getLabelsWidth = function getContainer() { - return this.props.labels.width; -}; - -/** - * Reflow the component - * @return {Boolean} resized - */ -GroupSet.prototype.reflow = function reflow() { - var changed = 0, - id, group, - options = this.options, - update = util.updateProperty, - asNumber = util.option.asNumber, - asSize = util.option.asSize, - frame = this.dom.frame; - - if (frame) { - var maxHeight = asNumber(options.maxHeight); - var fixedHeight = (asSize(options.height) != null); - var height; - if (fixedHeight) { - height = frame.offsetHeight; - } - else { - // height is not specified, calculate the sum of the height of all groups - height = 0; - - for (id in this.groups) { - if (this.groups.hasOwnProperty(id)) { - group = this.groups[id]; - height += group.height; - } - } - } - if (maxHeight != null) { - height = Math.min(height, maxHeight); - } - changed += update(this, 'height', height); - - changed += update(this, 'top', frame.offsetTop); - changed += update(this, 'left', frame.offsetLeft); - changed += update(this, 'width', frame.offsetWidth); - } - - // calculate the maximum width of the labels - var width = 0; - for (id in this.groups) { - if (this.groups.hasOwnProperty(id)) { - group = this.groups[id]; - var labelWidth = group.props && group.props.label && group.props.label.width || 0; - width = Math.max(width, labelWidth); - } - } - changed += update(this.props.labels, 'width', width); - - return (changed > 0); -}; - -/** - * Hide the component from the DOM - * @return {Boolean} changed - */ -GroupSet.prototype.hide = function hide() { - if (this.dom.frame && this.dom.frame.parentNode) { - this.dom.frame.parentNode.removeChild(this.dom.frame); - return true; - } - else { - return false; - } -}; - -/** - * Show the component in the DOM (when not already visible). - * A repaint will be executed when the component is not visible - * @return {Boolean} changed - */ -GroupSet.prototype.show = function show() { - if (!this.dom.frame || !this.dom.frame.parentNode) { - return this.repaint(); - } - else { - return false; - } -}; - -/** - * Handle updated groups - * @param {Number[]} ids - * @private - */ -GroupSet.prototype._onUpdate = function _onUpdate(ids) { - this._toQueue(ids, 'update'); -}; - -/** - * Handle changed groups - * @param {Number[]} ids - * @private - */ -GroupSet.prototype._onAdd = function _onAdd(ids) { - this._toQueue(ids, 'add'); -}; - -/** - * Handle removed groups - * @param {Number[]} ids - * @private - */ -GroupSet.prototype._onRemove = function _onRemove(ids) { - this._toQueue(ids, 'remove'); -}; - -/** - * Put groups in the queue to be added/updated/remove - * @param {Number[]} ids - * @param {String} action can be 'add', 'update', 'remove' - */ -GroupSet.prototype._toQueue = function _toQueue(ids, action) { - var queue = this.queue; - ids.forEach(function (id) { - queue[id] = action; - }); - - if (this.controller) { - //this.requestReflow(); - this.requestRepaint(); - } -}; - -/** - * Create a timeline visualization - * @param {HTMLElement} container - * @param {vis.DataSet | Array | DataTable} [items] - * @param {Object} [options] See Timeline.setOptions for the available options. - * @constructor - */ -function Timeline (container, items, options) { - var me = this; - var now = moment().hours(0).minutes(0).seconds(0).milliseconds(0); - this.options = { - orientation: 'bottom', - min: null, - max: null, - zoomMin: 10, // milliseconds - zoomMax: 1000 * 60 * 60 * 24 * 365 * 10000, // milliseconds - // moveable: true, // TODO: option moveable - // zoomable: true, // TODO: option zoomable - showMinorLabels: true, - showMajorLabels: true, - showCurrentTime: false, - showCustomTime: false, - autoResize: false - }; - - // controller - this.controller = new Controller(); - - // root panel - if (!container) { - throw new Error('No container element provided'); - } - var rootOptions = Object.create(this.options); - rootOptions.height = function () { - // TODO: change to height - if (me.options.height) { - // fixed height - return me.options.height; - } - else { - // auto height - return (me.timeaxis.height + me.content.height) + 'px'; - } - }; - this.rootPanel = new RootPanel(container, rootOptions); - this.controller.add(this.rootPanel); - - // item panel - var itemOptions = Object.create(this.options); - itemOptions.left = function () { - return me.labelPanel.width; - }; - itemOptions.width = function () { - return me.rootPanel.width - me.labelPanel.width; - }; - itemOptions.top = null; - itemOptions.height = null; - this.itemPanel = new Panel(this.rootPanel, [], itemOptions); - this.controller.add(this.itemPanel); - - // label panel - var labelOptions = Object.create(this.options); - labelOptions.top = null; - labelOptions.left = null; - labelOptions.height = null; - labelOptions.width = function () { - if (me.content && typeof me.content.getLabelsWidth === 'function') { - return me.content.getLabelsWidth(); - } - else { - return 0; - } - }; - this.labelPanel = new Panel(this.rootPanel, [], labelOptions); - this.controller.add(this.labelPanel); - - // range - var rangeOptions = Object.create(this.options); - this.range = new Range(rangeOptions); - this.range.setRange( - now.clone().add('days', -3).valueOf(), - now.clone().add('days', 4).valueOf() - ); - - // TODO: reckon with options moveable and zoomable - // TODO: put the listeners in setOptions, be able to dynamically change with options moveable and zoomable - this.range.subscribe(this.rootPanel, 'move', 'horizontal'); - this.range.subscribe(this.rootPanel, 'zoom', 'horizontal'); - this.range.on('rangechange', function (properties) { - var force = true; - me.controller.requestReflow(force); - me._trigger('rangechange', properties); - }); - this.range.on('rangechanged', function (properties) { - var force = true; - me.controller.requestReflow(force); - me._trigger('rangechanged', properties); - }); - - // single select (or unselect) when tapping an item - // TODO: implement ctrl+click - this.rootPanel.on('tap', this._onSelectItem.bind(this)); - - // multi select when holding mouse/touch, or on ctrl+click - this.rootPanel.on('hold', this._onMultiSelectItem.bind(this)); - - // time axis - var timeaxisOptions = Object.create(rootOptions); - timeaxisOptions.range = this.range; - timeaxisOptions.left = null; - timeaxisOptions.top = null; - timeaxisOptions.width = '100%'; - timeaxisOptions.height = null; - this.timeaxis = new TimeAxis(this.itemPanel, [], timeaxisOptions); - this.timeaxis.setRange(this.range); - this.controller.add(this.timeaxis); - - // current time bar - this.currenttime = new CurrentTime(this.timeaxis, [], rootOptions); - this.controller.add(this.currenttime); - - // custom time bar - this.customtime = new CustomTime(this.timeaxis, [], rootOptions); - this.controller.add(this.customtime); - - // create groupset - this.setGroups(null); - - this.itemsData = null; // DataSet - this.groupsData = null; // DataSet - - // apply options - if (options) { - this.setOptions(options); - } - - // create itemset and groupset - if (items) { - this.setItems(items); - } -} - -/** - * Set options - * @param {Object} options TODO: describe the available options - */ -Timeline.prototype.setOptions = function (options) { - util.extend(this.options, options); - - // force update of range (apply new min/max etc.) - // both start and end are optional - this.range.setRange(options.start, options.end); - - this.controller.reflow(); - this.controller.repaint(); -}; - -/** - * Set a custom time bar - * @param {Date} time - */ -Timeline.prototype.setCustomTime = function (time) { - this.customtime._setCustomTime(time); -}; - -/** - * Retrieve the current custom time. - * @return {Date} customTime - */ -Timeline.prototype.getCustomTime = function() { - return new Date(this.customtime.customTime.valueOf()); -}; - -/** - * Set items - * @param {vis.DataSet | Array | DataTable | null} items - */ -Timeline.prototype.setItems = function(items) { - var initialLoad = (this.itemsData == null); - - // convert to type DataSet when needed - var newItemSet; - if (!items) { - newItemSet = null; - } - else if (items instanceof DataSet) { - newItemSet = items; - } - if (!(items instanceof DataSet)) { - newItemSet = new DataSet({ - convert: { - start: 'Date', - end: 'Date' - } - }); - newItemSet.add(items); - } - - // set items - this.itemsData = newItemSet; - this.content.setItems(newItemSet); - - if (initialLoad && (this.options.start == undefined || this.options.end == undefined)) { - // apply the data range as range - var dataRange = this.getItemRange(); - - // add 5% space on both sides - var start = dataRange.min; - var end = dataRange.max; - if (start != null && end != null) { - var interval = (end.valueOf() - start.valueOf()); - if (interval <= 0) { - // prevent an empty interval - interval = 24 * 60 * 60 * 1000; // 1 day - } - start = new Date(start.valueOf() - interval * 0.05); - end = new Date(end.valueOf() + interval * 0.05); - } - - // override specified start and/or end date - if (this.options.start != undefined) { - start = util.convert(this.options.start, 'Date'); - } - if (this.options.end != undefined) { - end = util.convert(this.options.end, 'Date'); - } - - // apply range if there is a min or max available - if (start != null || end != null) { - this.range.setRange(start, end); - } - } -}; - -/** - * Set groups - * @param {vis.DataSet | Array | DataTable} groups - */ -Timeline.prototype.setGroups = function(groups) { - var me = this; - this.groupsData = groups; - - // switch content type between ItemSet or GroupSet when needed - var Type = this.groupsData ? GroupSet : ItemSet; - if (!(this.content instanceof Type)) { - // remove old content set - if (this.content) { - this.content.hide(); - if (this.content.setItems) { - this.content.setItems(); // disconnect from items - } - if (this.content.setGroups) { - this.content.setGroups(); // disconnect from groups - } - this.controller.remove(this.content); - } - - // create new content set - var options = Object.create(this.options); - util.extend(options, { - top: function () { - if (me.options.orientation == 'top') { - return me.timeaxis.height; - } - else { - return me.itemPanel.height - me.timeaxis.height - me.content.height; - } - }, - left: null, - width: '100%', - height: function () { - if (me.options.height) { - // fixed height - return me.itemPanel.height - me.timeaxis.height; - } - else { - // auto height - return null; - } - }, - maxHeight: function () { - // TODO: change maxHeight to be a css string like '100%' or '300px' - if (me.options.maxHeight) { - if (!util.isNumber(me.options.maxHeight)) { - throw new TypeError('Number expected for property maxHeight'); - } - return me.options.maxHeight - me.timeaxis.height; - } - else { - return null; - } - }, - labelContainer: function () { - return me.labelPanel.getContainer(); - } - }); - - this.content = new Type(this.itemPanel, [this.timeaxis], options); - if (this.content.setRange) { - this.content.setRange(this.range); - } - if (this.content.setItems) { - this.content.setItems(this.itemsData); - } - if (this.content.setGroups) { - this.content.setGroups(this.groupsData); - } - this.controller.add(this.content); - } -}; - -/** - * Get the data range of the item set. - * @returns {{min: Date, max: Date}} range A range with a start and end Date. - * When no minimum is found, min==null - * When no maximum is found, max==null - */ -Timeline.prototype.getItemRange = function getItemRange() { - // calculate min from start filed - var itemsData = this.itemsData, - min = null, - max = null; - - if (itemsData) { - // calculate the minimum value of the field 'start' - var minItem = itemsData.min('start'); - min = minItem ? minItem.start.valueOf() : null; - - // calculate maximum value of fields 'start' and 'end' - var maxStartItem = itemsData.max('start'); - if (maxStartItem) { - max = maxStartItem.start.valueOf(); - } - var maxEndItem = itemsData.max('end'); - if (maxEndItem) { - if (max == null) { - max = maxEndItem.end.valueOf(); - } - else { - max = Math.max(max, maxEndItem.end.valueOf()); - } - } - } - - return { - min: (min != null) ? new Date(min) : null, - max: (max != null) ? new Date(max) : null - }; -}; - -/** - * Set selected items by their id. Replaces the current selection - * Unknown id's are silently ignored. - * @param {Array} [ids] An array with zero or more id's of the items to be - * selected. If ids is an empty array, all items will be - * unselected. - */ -Timeline.prototype.setSelection = function setSelection (ids) { - if (this.content) this.content.setSelection(ids); -}; - -/** - * Get the selected items by their id - * @return {Array} ids The ids of the selected items - */ -Timeline.prototype.getSelection = function getSelection() { - return this.content ? this.content.getSelection() : []; -}; - -/** - * Add event listener - * @param {String} event Event name. Available events: - * 'rangechange', 'rangechanged', 'select' - * @param {function} callback Callback function, invoked as callback(properties) - * where properties is an optional object containing - * event specific properties. - */ -Timeline.prototype.on = function on (event, callback) { - var available = ['rangechange', 'rangechanged', 'select']; - - if (available.indexOf(event) == -1) { - throw new Error('Unknown event "' + event + '". Choose from ' + available.join()); - } - - events.addListener(this, event, callback); -}; - -/** - * Remove an event listener - * @param {String} event Event name - * @param {function} callback Callback function - */ -Timeline.prototype.off = function off (event, callback) { - events.removeListener(this, event, callback); -}; - -/** - * Trigger an event - * @param {String} event Event name, available events: 'rangechange', - * 'rangechanged', 'select' - * @param {Object} [properties] Event specific properties - * @private - */ -Timeline.prototype._trigger = function _trigger(event, properties) { - events.trigger(this, event, properties || {}); -}; - -/** - * Handle selecting/deselecting an item when tapping it - * @param {Event} event - * @private - */ -Timeline.prototype._onSelectItem = function (event) { - var item = this._itemFromTarget(event); - - var selection = item ? [item.id] : []; - this.setSelection(selection); - - this._trigger('select', { - items: this.getSelection() - }); - - event.stopPropagation(); -}; - -/** - * Handle selecting/deselecting multiple items when holding an item - * @param {Event} event - * @private - */ -Timeline.prototype._onMultiSelectItem = function (event) { - var selection, - item = this._itemFromTarget(event); - - if (!item) { - // do nothing... - return; - } - - selection = this.getSelection(); // current selection - var index = selection.indexOf(item.id); - if (index == -1) { - // item is not yet selected -> select it - selection.push(item.id); - } - else { - // item is already selected -> deselect it - selection.splice(index, 1); - } - this.setSelection(selection); - - this._trigger('select', { - items: this.getSelection() - }); - - event.stopPropagation(); -}; - -/** - * Find an item from an event target: - * searches for the attribute 'timeline-item' in the event target's element tree - * @param {Event} event - * @return {Item | null| item - * @private - */ -Timeline.prototype._itemFromTarget = function _itemFromTarget (event) { - var target = event.target; - while (target) { - if (target.hasOwnProperty('timeline-item')) { - return target['timeline-item']; - } - target = target.parentNode; - } - - return null; -}; -(function(exports) { - /** - * Parse a text source containing data in DOT language into a JSON object. - * The object contains two lists: one with nodes and one with edges. - * - * DOT language reference: http://www.graphviz.org/doc/info/lang.html - * - * @param {String} data Text containing a graph in DOT-notation - * @return {Object} graph An object containing two parameters: - * {Object[]} nodes - * {Object[]} edges - */ - function parseDOT (data) { - dot = data; - return parseGraph(); - } - - // token types enumeration - var TOKENTYPE = { - NULL : 0, - DELIMITER : 1, - IDENTIFIER: 2, - UNKNOWN : 3 - }; - - // map with all delimiters - var DELIMITERS = { - '{': true, - '}': true, - '[': true, - ']': true, - ';': true, - '=': true, - ',': true, - - '->': true, - '--': true - }; - - var dot = ''; // current dot file - var index = 0; // current index in dot file - var c = ''; // current token character in expr - var token = ''; // current token - var tokenType = TOKENTYPE.NULL; // type of the token - - /** - * Get the first character from the dot file. - * The character is stored into the char c. If the end of the dot file is - * reached, the function puts an empty string in c. - */ - function first() { - index = 0; - c = dot.charAt(0); - } - - /** - * Get the next character from the dot file. - * The character is stored into the char c. If the end of the dot file is - * reached, the function puts an empty string in c. - */ - function next() { - index++; - c = dot.charAt(index); - } - - /** - * Preview the next character from the dot file. - * @return {String} cNext - */ - function nextPreview() { - return dot.charAt(index + 1); - } - - /** - * Test whether given character is alphabetic or numeric - * @param {String} c - * @return {Boolean} isAlphaNumeric - */ - var regexAlphaNumeric = /[a-zA-Z_0-9.:#]/; - function isAlphaNumeric(c) { - return regexAlphaNumeric.test(c); - } - - /** - * Merge all properties of object b into object b - * @param {Object} a - * @param {Object} b - * @return {Object} a - */ - function merge (a, b) { - if (!a) { - a = {}; - } - - if (b) { - for (var name in b) { - if (b.hasOwnProperty(name)) { - a[name] = b[name]; - } - } - } - return a; - } - - /** - * Set a value in an object, where the provided parameter name can be a - * path with nested parameters. For example: - * - * var obj = {a: 2}; - * setValue(obj, 'b.c', 3); // obj = {a: 2, b: {c: 3}} - * - * @param {Object} obj - * @param {String} path A parameter name or dot-separated parameter path, - * like "color.highlight.border". - * @param {*} value - */ - function setValue(obj, path, value) { - var keys = path.split('.'); - var o = obj; - while (keys.length) { - var key = keys.shift(); - if (keys.length) { - // this isn't the end point - if (!o[key]) { - o[key] = {}; - } - o = o[key]; - } - else { - // this is the end point - o[key] = value; - } - } - } - - /** - * Add a node to a graph object. If there is already a node with - * the same id, their attributes will be merged. - * @param {Object} graph - * @param {Object} node - */ - function addNode(graph, node) { - var i, len; - var current = null; - - // find root graph (in case of subgraph) - var graphs = [graph]; // list with all graphs from current graph to root graph - var root = graph; - while (root.parent) { - graphs.push(root.parent); - root = root.parent; - } - - // find existing node (at root level) by its id - if (root.nodes) { - for (i = 0, len = root.nodes.length; i < len; i++) { - if (node.id === root.nodes[i].id) { - current = root.nodes[i]; - break; - } - } - } - - if (!current) { - // this is a new node - current = { - id: node.id - }; - if (graph.node) { - // clone default attributes - current.attr = merge(current.attr, graph.node); - } - } - - // add node to this (sub)graph and all its parent graphs - for (i = graphs.length - 1; i >= 0; i--) { - var g = graphs[i]; - - if (!g.nodes) { - g.nodes = []; - } - if (g.nodes.indexOf(current) == -1) { - g.nodes.push(current); - } - } - - // merge attributes - if (node.attr) { - current.attr = merge(current.attr, node.attr); - } - } - - /** - * Add an edge to a graph object - * @param {Object} graph - * @param {Object} edge - */ - function addEdge(graph, edge) { - if (!graph.edges) { - graph.edges = []; - } - graph.edges.push(edge); - if (graph.edge) { - var attr = merge({}, graph.edge); // clone default attributes - edge.attr = merge(attr, edge.attr); // merge attributes - } - } - - /** - * Create an edge to a graph object - * @param {Object} graph - * @param {String | Number | Object} from - * @param {String | Number | Object} to - * @param {String} type - * @param {Object | null} attr - * @return {Object} edge - */ - function createEdge(graph, from, to, type, attr) { - var edge = { - from: from, - to: to, - type: type - }; - - if (graph.edge) { - edge.attr = merge({}, graph.edge); // clone default attributes - } - edge.attr = merge(edge.attr || {}, attr); // merge attributes - - return edge; - } - - /** - * Get next token in the current dot file. - * The token and token type are available as token and tokenType - */ - function getToken() { - tokenType = TOKENTYPE.NULL; - token = ''; - - // skip over whitespaces - while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter - next(); - } - - do { - var isComment = false; - - // skip comment - if (c == '#') { - // find the previous non-space character - var i = index - 1; - while (dot.charAt(i) == ' ' || dot.charAt(i) == '\t') { - i--; - } - if (dot.charAt(i) == '\n' || dot.charAt(i) == '') { - // the # is at the start of a line, this is indeed a line comment - while (c != '' && c != '\n') { - next(); - } - isComment = true; - } - } - if (c == '/' && nextPreview() == '/') { - // skip line comment - while (c != '' && c != '\n') { - next(); - } - isComment = true; - } - if (c == '/' && nextPreview() == '*') { - // skip block comment - while (c != '') { - if (c == '*' && nextPreview() == '/') { - // end of block comment found. skip these last two characters - next(); - next(); - break; - } - else { - next(); - } - } - isComment = true; - } - - // skip over whitespaces - while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter - next(); - } - } - while (isComment); - - // check for end of dot file - if (c == '') { - // token is still empty - tokenType = TOKENTYPE.DELIMITER; - return; - } - - // check for delimiters consisting of 2 characters - var c2 = c + nextPreview(); - if (DELIMITERS[c2]) { - tokenType = TOKENTYPE.DELIMITER; - token = c2; - next(); - next(); - return; - } - - // check for delimiters consisting of 1 character - if (DELIMITERS[c]) { - tokenType = TOKENTYPE.DELIMITER; - token = c; - next(); - return; - } - - // check for an identifier (number or string) - // TODO: more precise parsing of numbers/strings (and the port separator ':') - if (isAlphaNumeric(c) || c == '-') { - token += c; - next(); - - while (isAlphaNumeric(c)) { - token += c; - next(); - } - if (token == 'false') { - token = false; // convert to boolean - } - else if (token == 'true') { - token = true; // convert to boolean - } - else if (!isNaN(Number(token))) { - token = Number(token); // convert to number - } - tokenType = TOKENTYPE.IDENTIFIER; - return; - } - - // check for a string enclosed by double quotes - if (c == '"') { - next(); - while (c != '' && (c != '"' || (c == '"' && nextPreview() == '"'))) { - token += c; - if (c == '"') { // skip the escape character - next(); - } - next(); - } - if (c != '"') { - throw newSyntaxError('End of string " expected'); - } - next(); - tokenType = TOKENTYPE.IDENTIFIER; - return; - } - - // something unknown is found, wrong characters, a syntax error - tokenType = TOKENTYPE.UNKNOWN; - while (c != '') { - token += c; - next(); - } - throw new SyntaxError('Syntax error in part "' + chop(token, 30) + '"'); - } - - /** - * Parse a graph. - * @returns {Object} graph - */ - function parseGraph() { - var graph = {}; - - first(); - getToken(); - - // optional strict keyword - if (token == 'strict') { - graph.strict = true; - getToken(); - } - - // graph or digraph keyword - if (token == 'graph' || token == 'digraph') { - graph.type = token; - getToken(); - } - - // optional graph id - if (tokenType == TOKENTYPE.IDENTIFIER) { - graph.id = token; - getToken(); - } - - // open angle bracket - if (token != '{') { - throw newSyntaxError('Angle bracket { expected'); - } - getToken(); - - // statements - parseStatements(graph); - - // close angle bracket - if (token != '}') { - throw newSyntaxError('Angle bracket } expected'); - } - getToken(); - - // end of file - if (token !== '') { - throw newSyntaxError('End of file expected'); - } - getToken(); - - // remove temporary default properties - delete graph.node; - delete graph.edge; - delete graph.graph; - - return graph; - } - - /** - * Parse a list with statements. - * @param {Object} graph - */ - function parseStatements (graph) { - while (token !== '' && token != '}') { - parseStatement(graph); - if (token == ';') { - getToken(); - } - } - } - - /** - * Parse a single statement. Can be a an attribute statement, node - * statement, a series of node statements and edge statements, or a - * parameter. - * @param {Object} graph - */ - function parseStatement(graph) { - // parse subgraph - var subgraph = parseSubgraph(graph); - if (subgraph) { - // edge statements - parseEdge(graph, subgraph); - - return; - } - - // parse an attribute statement - var attr = parseAttributeStatement(graph); - if (attr) { - return; - } - - // parse node - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Identifier expected'); - } - var id = token; // id can be a string or a number - getToken(); - - if (token == '=') { - // id statement - getToken(); - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Identifier expected'); - } - graph[id] = token; - getToken(); - // TODO: implement comma separated list with "a_list: ID=ID [','] [a_list] " - } - else { - parseNodeStatement(graph, id); - } - } - - /** - * Parse a subgraph - * @param {Object} graph parent graph object - * @return {Object | null} subgraph - */ - function parseSubgraph (graph) { - var subgraph = null; - - // optional subgraph keyword - if (token == 'subgraph') { - subgraph = {}; - subgraph.type = 'subgraph'; - getToken(); - - // optional graph id - if (tokenType == TOKENTYPE.IDENTIFIER) { - subgraph.id = token; - getToken(); - } - } - - // open angle bracket - if (token == '{') { - getToken(); - - if (!subgraph) { - subgraph = {}; - } - subgraph.parent = graph; - subgraph.node = graph.node; - subgraph.edge = graph.edge; - subgraph.graph = graph.graph; - - // statements - parseStatements(subgraph); - - // close angle bracket - if (token != '}') { - throw newSyntaxError('Angle bracket } expected'); - } - getToken(); - - // remove temporary default properties - delete subgraph.node; - delete subgraph.edge; - delete subgraph.graph; - delete subgraph.parent; - - // register at the parent graph - if (!graph.subgraphs) { - graph.subgraphs = []; - } - graph.subgraphs.push(subgraph); - } - - return subgraph; - } - - /** - * parse an attribute statement like "node [shape=circle fontSize=16]". - * Available keywords are 'node', 'edge', 'graph'. - * The previous list with default attributes will be replaced - * @param {Object} graph - * @returns {String | null} keyword Returns the name of the parsed attribute - * (node, edge, graph), or null if nothing - * is parsed. - */ - function parseAttributeStatement (graph) { - // attribute statements - if (token == 'node') { - getToken(); - - // node attributes - graph.node = parseAttributeList(); - return 'node'; - } - else if (token == 'edge') { - getToken(); - - // edge attributes - graph.edge = parseAttributeList(); - return 'edge'; - } - else if (token == 'graph') { - getToken(); - - // graph attributes - graph.graph = parseAttributeList(); - return 'graph'; - } - - return null; - } - - /** - * parse a node statement - * @param {Object} graph - * @param {String | Number} id - */ - function parseNodeStatement(graph, id) { - // node statement - var node = { - id: id - }; - var attr = parseAttributeList(); - if (attr) { - node.attr = attr; - } - addNode(graph, node); - - // edge statements - parseEdge(graph, id); - } - - /** - * Parse an edge or a series of edges - * @param {Object} graph - * @param {String | Number} from Id of the from node - */ - function parseEdge(graph, from) { - while (token == '->' || token == '--') { - var to; - var type = token; - getToken(); - - var subgraph = parseSubgraph(graph); - if (subgraph) { - to = subgraph; - } - else { - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Identifier or subgraph expected'); - } - to = token; - addNode(graph, { - id: to - }); - getToken(); - } - - // parse edge attributes - var attr = parseAttributeList(); - - // create edge - var edge = createEdge(graph, from, to, type, attr); - addEdge(graph, edge); - - from = to; - } - } - - /** - * Parse a set with attributes, - * for example [label="1.000", shape=solid] - * @return {Object | null} attr - */ - function parseAttributeList() { - var attr = null; - - while (token == '[') { - getToken(); - attr = {}; - while (token !== '' && token != ']') { - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Attribute name expected'); - } - var name = token; - - getToken(); - if (token != '=') { - throw newSyntaxError('Equal sign = expected'); - } - getToken(); - - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Attribute value expected'); - } - var value = token; - setValue(attr, name, value); // name can be a path - - getToken(); - if (token ==',') { - getToken(); - } - } - - if (token != ']') { - throw newSyntaxError('Bracket ] expected'); - } - getToken(); - } - - return attr; - } - - /** - * Create a syntax error with extra information on current token and index. - * @param {String} message - * @returns {SyntaxError} err - */ - function newSyntaxError(message) { - return new SyntaxError(message + ', got "' + chop(token, 30) + '" (char ' + index + ')'); - } - - /** - * Chop off text after a maximum length - * @param {String} text - * @param {Number} maxLength - * @returns {String} - */ - function chop (text, maxLength) { - return (text.length <= maxLength) ? text : (text.substr(0, 27) + '...'); - } - - /** - * Execute a function fn for each pair of elements in two arrays - * @param {Array | *} array1 - * @param {Array | *} array2 - * @param {function} fn - */ - function forEach2(array1, array2, fn) { - if (array1 instanceof Array) { - array1.forEach(function (elem1) { - if (array2 instanceof Array) { - array2.forEach(function (elem2) { - fn(elem1, elem2); - }); - } - else { - fn(elem1, array2); - } - }); - } - else { - if (array2 instanceof Array) { - array2.forEach(function (elem2) { - fn(array1, elem2); - }); - } - else { - fn(array1, array2); - } - } - } - - /** - * Convert a string containing a graph in DOT language into a map containing - * with nodes and edges in the format of graph. - * @param {String} data Text containing a graph in DOT-notation - * @return {Object} graphData - */ - function DOTToGraph (data) { - // parse the DOT file - var dotData = parseDOT(data); - var graphData = { - nodes: [], - edges: [], - options: {} - }; - - // copy the nodes - if (dotData.nodes) { - dotData.nodes.forEach(function (dotNode) { - var graphNode = { - id: dotNode.id, - label: String(dotNode.label || dotNode.id) - }; - merge(graphNode, dotNode.attr); - if (graphNode.image) { - graphNode.shape = 'image'; - } - graphData.nodes.push(graphNode); - }); - } - - // copy the edges - if (dotData.edges) { - /** - * Convert an edge in DOT format to an edge with VisGraph format - * @param {Object} dotEdge - * @returns {Object} graphEdge - */ - function convertEdge(dotEdge) { - var graphEdge = { - from: dotEdge.from, - to: dotEdge.to - }; - merge(graphEdge, dotEdge.attr); - graphEdge.style = (dotEdge.type == '->') ? 'arrow' : 'line'; - return graphEdge; - } - - dotData.edges.forEach(function (dotEdge) { - var from, to; - if (dotEdge.from instanceof Object) { - from = dotEdge.from.nodes; - } - else { - from = { - id: dotEdge.from - } - } - - if (dotEdge.to instanceof Object) { - to = dotEdge.to.nodes; - } - else { - to = { - id: dotEdge.to - } - } - - if (dotEdge.from instanceof Object && dotEdge.from.edges) { - dotEdge.from.edges.forEach(function (subEdge) { - var graphEdge = convertEdge(subEdge); - graphData.edges.push(graphEdge); - }); - } - - forEach2(from, to, function (from, to) { - var subEdge = createEdge(graphData, from.id, to.id, dotEdge.type, dotEdge.attr); - var graphEdge = convertEdge(subEdge); - graphData.edges.push(graphEdge); - }); - - if (dotEdge.to instanceof Object && dotEdge.to.edges) { - dotEdge.to.edges.forEach(function (subEdge) { - var graphEdge = convertEdge(subEdge); - graphData.edges.push(graphEdge); - }); - } - }); - } - - // copy the options - if (dotData.attr) { - graphData.options = dotData.attr; - } - - return graphData; - } - - // exports - exports.parseDOT = parseDOT; - exports.DOTToGraph = DOTToGraph; - -})(typeof util !== 'undefined' ? util : exports); - -/** - * Canvas shapes used by the Graph - */ -if (typeof CanvasRenderingContext2D !== 'undefined') { - - /** - * Draw a circle shape - */ - CanvasRenderingContext2D.prototype.circle = function(x, y, r) { - this.beginPath(); - this.arc(x, y, r, 0, 2*Math.PI, false); - }; - - /** - * Draw a square shape - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r size, width and height of the square - */ - CanvasRenderingContext2D.prototype.square = function(x, y, r) { - this.beginPath(); - this.rect(x - r, y - r, r * 2, r * 2); - }; - - /** - * Draw a triangle shape - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r radius, half the length of the sides of the triangle - */ - CanvasRenderingContext2D.prototype.triangle = function(x, y, r) { - // http://en.wikipedia.org/wiki/Equilateral_triangle - this.beginPath(); - - var s = r * 2; - var s2 = s / 2; - var ir = Math.sqrt(3) / 6 * s; // radius of inner circle - var h = Math.sqrt(s * s - s2 * s2); // height - - this.moveTo(x, y - (h - ir)); - this.lineTo(x + s2, y + ir); - this.lineTo(x - s2, y + ir); - this.lineTo(x, y - (h - ir)); - this.closePath(); - }; - - /** - * Draw a triangle shape in downward orientation - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r radius - */ - CanvasRenderingContext2D.prototype.triangleDown = function(x, y, r) { - // http://en.wikipedia.org/wiki/Equilateral_triangle - this.beginPath(); - - var s = r * 2; - var s2 = s / 2; - var ir = Math.sqrt(3) / 6 * s; // radius of inner circle - var h = Math.sqrt(s * s - s2 * s2); // height - - this.moveTo(x, y + (h - ir)); - this.lineTo(x + s2, y - ir); - this.lineTo(x - s2, y - ir); - this.lineTo(x, y + (h - ir)); - this.closePath(); - }; - - /** - * Draw a star shape, a star with 5 points - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r radius, half the length of the sides of the triangle - */ - CanvasRenderingContext2D.prototype.star = function(x, y, r) { - // http://www.html5canvastutorials.com/labs/html5-canvas-star-spinner/ - this.beginPath(); - - for (var n = 0; n < 10; n++) { - var radius = (n % 2 === 0) ? r * 1.3 : r * 0.5; - this.lineTo( - x + radius * Math.sin(n * 2 * Math.PI / 10), - y - radius * Math.cos(n * 2 * Math.PI / 10) - ); - } - - this.closePath(); - }; - - /** - * http://stackoverflow.com/questions/1255512/how-to-draw-a-rounded-rectangle-on-html-canvas - */ - CanvasRenderingContext2D.prototype.roundRect = function(x, y, w, h, r) { - var r2d = Math.PI/180; - if( w - ( 2 * r ) < 0 ) { r = ( w / 2 ); } //ensure that the radius isn't too large for x - if( h - ( 2 * r ) < 0 ) { r = ( h / 2 ); } //ensure that the radius isn't too large for y - this.beginPath(); - this.moveTo(x+r,y); - this.lineTo(x+w-r,y); - this.arc(x+w-r,y+r,r,r2d*270,r2d*360,false); - this.lineTo(x+w,y+h-r); - this.arc(x+w-r,y+h-r,r,0,r2d*90,false); - this.lineTo(x+r,y+h); - this.arc(x+r,y+h-r,r,r2d*90,r2d*180,false); - this.lineTo(x,y+r); - this.arc(x+r,y+r,r,r2d*180,r2d*270,false); - }; - - /** - * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - */ - CanvasRenderingContext2D.prototype.ellipse = function(x, y, w, h) { - var kappa = .5522848, - ox = (w / 2) * kappa, // control point offset horizontal - oy = (h / 2) * kappa, // control point offset vertical - xe = x + w, // x-end - ye = y + h, // y-end - xm = x + w / 2, // x-middle - ym = y + h / 2; // y-middle - - this.beginPath(); - this.moveTo(x, ym); - this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); - this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); - this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); - this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - }; - - - - /** - * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - */ - CanvasRenderingContext2D.prototype.database = function(x, y, w, h) { - var f = 1/3; - var wEllipse = w; - var hEllipse = h * f; - - var kappa = .5522848, - ox = (wEllipse / 2) * kappa, // control point offset horizontal - oy = (hEllipse / 2) * kappa, // control point offset vertical - xe = x + wEllipse, // x-end - ye = y + hEllipse, // y-end - xm = x + wEllipse / 2, // x-middle - ym = y + hEllipse / 2, // y-middle - ymb = y + (h - hEllipse/2), // y-midlle, bottom ellipse - yeb = y + h; // y-end, bottom ellipse - - this.beginPath(); - this.moveTo(xe, ym); - - this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); - this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - - this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); - this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); - - this.lineTo(xe, ymb); - - this.bezierCurveTo(xe, ymb + oy, xm + ox, yeb, xm, yeb); - this.bezierCurveTo(xm - ox, yeb, x, ymb + oy, x, ymb); - - this.lineTo(x, ym); - }; - - - /** - * Draw an arrow point (no line) - */ - CanvasRenderingContext2D.prototype.arrow = function(x, y, angle, length) { - // tail - var xt = x - length * Math.cos(angle); - var yt = y - length * Math.sin(angle); - - // inner tail - // TODO: allow to customize different shapes - var xi = x - length * 0.9 * Math.cos(angle); - var yi = y - length * 0.9 * Math.sin(angle); - - // left - var xl = xt + length / 3 * Math.cos(angle + 0.5 * Math.PI); - var yl = yt + length / 3 * Math.sin(angle + 0.5 * Math.PI); - - // right - var xr = xt + length / 3 * Math.cos(angle - 0.5 * Math.PI); - var yr = yt + length / 3 * Math.sin(angle - 0.5 * Math.PI); - - this.beginPath(); - this.moveTo(x, y); - this.lineTo(xl, yl); - this.lineTo(xi, yi); - this.lineTo(xr, yr); - this.closePath(); - }; - - /** - * Sets up the dashedLine functionality for drawing - * Original code came from http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas - * @author David Jordan - * @date 2012-08-08 - */ - CanvasRenderingContext2D.prototype.dashedLine = function(x,y,x2,y2,dashArray){ - if (!dashArray) dashArray=[10,5]; - if (dashLength==0) dashLength = 0.001; // Hack for Safari - var dashCount = dashArray.length; - this.moveTo(x, y); - var dx = (x2-x), dy = (y2-y); - var slope = dy/dx; - var distRemaining = Math.sqrt( dx*dx + dy*dy ); - var dashIndex=0, draw=true; - while (distRemaining>=0.1){ - var dashLength = dashArray[dashIndex++%dashCount]; - if (dashLength > distRemaining) dashLength = distRemaining; - var xStep = Math.sqrt( dashLength*dashLength / (1 + slope*slope) ); - if (dx<0) xStep = -xStep; - x += xStep; - y += slope*xStep; - this[draw ? 'lineTo' : 'moveTo'](x,y); - distRemaining -= dashLength; - draw = !draw; - } - }; - - // TODO: add diamond shape -} - -/** - * @class Node - * A node. A node can be connected to other nodes via one or multiple edges. - * @param {object} properties An object containing properties for the node. All - * properties are optional, except for the id. - * {number} id Id of the node. Required - * {string} label Text label for the node - * {number} x Horizontal position of the node - * {number} y Vertical position of the node - * {string} shape Node shape, available: - * "database", "circle", "ellipse", - * "box", "image", "text", "dot", - * "star", "triangle", "triangleDown", - * "square" - * {string} image An image url - * {string} title An title text, can be HTML - * {anytype} group A group name or number - * @param {Graph.Images} imagelist A list with images. Only needed - * when the node has an image - * @param {Graph.Groups} grouplist A list with groups. Needed for - * retrieving group properties - * @param {Object} constants An object with default values for - * example for the color - * - */ -function Node(properties, imagelist, grouplist, constants) { - this.selected = false; - - this.edges = []; // all edges connected to this node - this.dynamicEdges = []; - this.reroutedEdges = {}; - this.group = constants.nodes.group; - - this.fontSize = constants.nodes.fontSize; - this.fontFace = constants.nodes.fontFace; - this.fontColor = constants.nodes.fontColor; - - this.color = constants.nodes.color; - - // set defaults for the properties - this.id = undefined; - this.shape = constants.nodes.shape; - this.image = constants.nodes.image; - this.x = 0; - this.y = 0; - this.xFixed = false; - this.yFixed = false; - this.horizontalAlignLeft = true; // these are for the navigation controls - this.verticalAlignTop = true; // these are for the navigation controls - this.radius = constants.nodes.radius; - this.baseRadiusValue = constants.nodes.radius; - this.radiusFixed = false; - this.radiusMin = constants.nodes.radiusMin; - this.radiusMax = constants.nodes.radiusMax; - - this.imagelist = imagelist; - - this.grouplist = grouplist; - - this.setProperties(properties, constants); - - // creating the variables for clustering - this.resetCluster(); - this.dynamicEdgesLength = 0; - this.clusterSession = 0; - this.clusterSizeWidthFactor = constants.clustering.nodeScaling.width; - this.clusterSizeHeightFactor = constants.clustering.nodeScaling.height; - this.clusterSizeRadiusFactor = constants.clustering.nodeScaling.radius; - - // mass, force, velocity - this.mass = 1; // kg - this.fx = 0.0; // external force x - this.fy = 0.0; // external force y - this.vx = 0.0; // velocity x - this.vy = 0.0; // velocity y - this.minForce = constants.minForce; - this.damping = 0.9; // this is manipulated in the updateDamping function - - this.graphScaleInv = 1; - this.canvasTopLeft = {"x": -300, "y": -300}; - this.canvasBottomRight = {"x": 300, "y": 300}; -} - -/** - * (re)setting the clustering variables and objects - */ -Node.prototype.resetCluster = function() { - // clustering variables - this.formationScale = undefined; // this is used to determine when to open the cluster - this.clusterSize = 1; // this signifies the total amount of nodes in this cluster - this.containedNodes = {}; - this.containedEdges = {}; - this.clusterSessions = []; -}; - -/** - * Attach a edge to the node - * @param {Edge} edge - */ -Node.prototype.attachEdge = function(edge) { - if (this.edges.indexOf(edge) == -1) { - this.edges.push(edge); - } - if (this.dynamicEdges.indexOf(edge) == -1) { - this.dynamicEdges.push(edge); - } - this.dynamicEdgesLength = this.dynamicEdges.length; -// this._updateMass(); -}; - -/** - * Detach a edge from the node - * @param {Edge} edge - */ -Node.prototype.detachEdge = function(edge) { - var index = this.edges.indexOf(edge); - if (index != -1) { - this.edges.splice(index, 1); - this.dynamicEdges.splice(index, 1); - } - this.dynamicEdgesLength = this.dynamicEdges.length; -// this._updateMass(); -}; - -/** - * Update the nodes mass, which is determined by the number of edges connecting - * to it (more edges -> heavier node). - * @private - */ -//Node.prototype._updateMass = function() { -// this.mass = 1;// + 0.6 * this.edges.length; // kg -//}; - -/** - * Set or overwrite properties for the node - * @param {Object} properties an object with properties - * @param {Object} constants and object with default, global properties - */ -Node.prototype.setProperties = function(properties, constants) { - if (!properties) { - return; - } - this.originalLabel = undefined; - // basic properties - if (properties.id !== undefined) {this.id = properties.id;} - if (properties.label !== undefined) {this.label = properties.label; this.originalLabel = properties.label;} - if (properties.title !== undefined) {this.title = properties.title;} - if (properties.group !== undefined) {this.group = properties.group;} - if (properties.x !== undefined) {this.x = properties.x;} - if (properties.y !== undefined) {this.y = properties.y;} - if (properties.value !== undefined) {this.value = properties.value;} - - // navigation controls properties - if (properties.horizontalAlignLeft !== undefined) {this.horizontalAlignLeft = properties.horizontalAlignLeft;} - if (properties.verticalAlignTop !== undefined) {this.verticalAlignTop = properties.verticalAlignTop;} - if (properties.triggerFunction !== undefined) {this.triggerFunction = properties.triggerFunction;} - - if (this.id === undefined) { - throw "Node must have an id"; - } - - // copy group properties - if (this.group) { - var groupObj = this.grouplist.get(this.group); - for (var prop in groupObj) { - if (groupObj.hasOwnProperty(prop)) { - this[prop] = groupObj[prop]; - } - } - } - - // individual shape properties - if (properties.shape !== undefined) {this.shape = properties.shape;} - if (properties.image !== undefined) {this.image = properties.image;} - if (properties.radius !== undefined) {this.radius = properties.radius;} - if (properties.color !== undefined) {this.color = Node.parseColor(properties.color);} - - if (properties.fontColor !== undefined) {this.fontColor = properties.fontColor;} - if (properties.fontSize !== undefined) {this.fontSize = properties.fontSize;} - if (properties.fontFace !== undefined) {this.fontFace = properties.fontFace;} - - if (this.image !== undefined) { - if (this.imagelist) { - this.imageObj = this.imagelist.load(this.image); - } - else { - throw "No imagelist provided"; - } - } - - this.xFixed = this.xFixed || (properties.x !== undefined && properties.fixed); - this.yFixed = this.yFixed || (properties.y !== undefined && properties.fixed); - this.radiusFixed = this.radiusFixed || (properties.radius !== undefined); - - if (this.shape == 'image') { - this.radiusMin = constants.nodes.widthMin; - this.radiusMax = constants.nodes.widthMax; - } - - // choose draw method depending on the shape - switch (this.shape) { - case 'database': this.draw = this._drawDatabase; this.resize = this._resizeDatabase; break; - case 'box': this.draw = this._drawBox; this.resize = this._resizeBox; break; - case 'circle': this.draw = this._drawCircle; this.resize = this._resizeCircle; break; - case 'ellipse': this.draw = this._drawEllipse; this.resize = this._resizeEllipse; break; - // TODO: add diamond shape - case 'image': this.draw = this._drawImage; this.resize = this._resizeImage; break; - case 'text': this.draw = this._drawText; this.resize = this._resizeText; break; - case 'dot': this.draw = this._drawDot; this.resize = this._resizeShape; break; - case 'square': this.draw = this._drawSquare; this.resize = this._resizeShape; break; - case 'triangle': this.draw = this._drawTriangle; this.resize = this._resizeShape; break; - case 'triangleDown': this.draw = this._drawTriangleDown; this.resize = this._resizeShape; break; - case 'star': this.draw = this._drawStar; this.resize = this._resizeShape; break; - default: this.draw = this._drawEllipse; this.resize = this._resizeEllipse; break; - } - // reset the size of the node, this can be changed - this._reset(); -}; - -/** - * Parse a color property into an object with border, background, and - * hightlight colors - * @param {Object | String} color - * @return {Object} colorObject - */ -Node.parseColor = function(color) { - var c; - if (util.isString(color)) { - c = { - border: color, - background: color, - highlight: { - border: color, - background: color - } - }; - // TODO: automatically generate a nice highlight color - } - else { - c = {}; - c.background = color.background || 'white'; - c.border = color.border || c.background; - - if (util.isString(color.highlight)) { - c.highlight = { - border: color.highlight, - background: color.highlight - } - } - else { - c.highlight = {}; - c.highlight.background = color.highlight && color.highlight.background || c.background; - c.highlight.border = color.highlight && color.highlight.border || c.border; - } - } - - return c; -}; - -/** - * select this node - */ -Node.prototype.select = function() { - this.selected = true; - this._reset(); -}; - -/** - * unselect this node - */ -Node.prototype.unselect = function() { - this.selected = false; - this._reset(); -}; - - -/** - * Reset the calculated size of the node, forces it to recalculate its size - */ -Node.prototype.clearSizeCache = function() { - this._reset(); -}; - -/** - * Reset the calculated size of the node, forces it to recalculate its size - * @private - */ -Node.prototype._reset = function() { - this.width = undefined; - this.height = undefined; -}; - -/** - * get the title of this node. - * @return {string} title The title of the node, or undefined when no title - * has been set. - */ -Node.prototype.getTitle = function() { - return this.title; -}; - -/** - * Calculate the distance to the border of the Node - * @param {CanvasRenderingContext2D} ctx - * @param {Number} angle Angle in radians - * @returns {number} distance Distance to the border in pixels - */ -Node.prototype.distanceToBorder = function (ctx, angle) { - var borderWidth = 1; - - if (!this.width) { - this.resize(ctx); - } - - //noinspection FallthroughInSwitchStatementJS - switch (this.shape) { - case 'circle': - case 'dot': - return this.radius + borderWidth; - - case 'ellipse': - var a = this.width / 2; - var b = this.height / 2; - var w = (Math.sin(angle) * a); - var h = (Math.cos(angle) * b); - return a * b / Math.sqrt(w * w + h * h); - - // TODO: implement distanceToBorder for database - // TODO: implement distanceToBorder for triangle - // TODO: implement distanceToBorder for triangleDown - - case 'box': - case 'image': - case 'text': - default: - if (this.width) { - return Math.min( - Math.abs(this.width / 2 / Math.cos(angle)), - Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth; - // TODO: reckon with border radius too in case of box - } - else { - return 0; - } - - } - - // TODO: implement calculation of distance to border for all shapes -}; - -/** - * Set forces acting on the node - * @param {number} fx Force in horizontal direction - * @param {number} fy Force in vertical direction - */ -Node.prototype._setForce = function(fx, fy) { - this.fx = fx; - this.fy = fy; -}; - -/** - * Add forces acting on the node - * @param {number} fx Force in horizontal direction - * @param {number} fy Force in vertical direction - * @private - */ -Node.prototype._addForce = function(fx, fy) { - this.fx += fx; - this.fy += fy; -}; - -/** - * Perform one discrete step for the node - * @param {number} interval Time interval in seconds - */ -Node.prototype.discreteStep = function(interval) { - if (!this.xFixed) { - var dx = -this.damping * this.vx; // damping force - var ax = (this.fx + dx) / this.mass; // acceleration - this.vx += ax * interval; // velocity - this.x += this.vx * interval; // position - } - - if (!this.yFixed) { - var dy = -this.damping * this.vy; // damping force - var ay = (this.fy + dy) / this.mass; // acceleration - this.vy += ay * interval; // velocity - this.y += this.vy * interval; // position - } -}; - - - -/** - * Perform one discrete step for the node - * @param {number} interval Time interval in seconds - */ -Node.prototype.discreteStepLimited = function(interval, maxVelocity) { - if (!this.xFixed) { - var dx = -this.damping * this.vx; // damping force - var ax = (this.fx + dx) / this.mass; // acceleration - this.vx += ax * interval; // velocity - this.vx = (Math.abs(this.vx) > maxVelocity) ? ((this.vx > 0) ? maxVelocity : -maxVelocity) : this.vx; - this.x += this.vx * interval; // position - } - - if (!this.yFixed) { - var dy = -this.damping * this.vy; // damping force - var ay = (this.fy + dy) / this.mass; // acceleration - this.vy += ay * interval; // velocity - this.vy = (Math.abs(this.vy) > maxVelocity) ? ((this.vy > 0) ? maxVelocity : -maxVelocity) : this.vy; - this.y += this.vy * interval; // position - } -}; - -/** - * Check if this node has a fixed x and y position - * @return {boolean} true if fixed, false if not - */ -Node.prototype.isFixed = function() { - return (this.xFixed && this.yFixed); -}; - -/** - * Check if this node is moving - * @param {number} vmin the minimum velocity considered as "moving" - * @return {boolean} true if moving, false if it has no velocity - */ -// TODO: replace this method with calculating the kinetic energy -Node.prototype.isMoving = function(vmin) { - - if (Math.abs(this.vx) > vmin || Math.abs(this.vy) > vmin) { -// console.log(vmin,this.vx,this.vy); - return true; - } - else { - this.vx = 0; this.vy = 0; - return false; - } - //return (Math.abs(this.vx) > vmin || Math.abs(this.vy) > vmin); -}; - -/** - * check if this node is selecte - * @return {boolean} selected True if node is selected, else false - */ -Node.prototype.isSelected = function() { - return this.selected; -}; - -/** - * Retrieve the value of the node. Can be undefined - * @return {Number} value - */ -Node.prototype.getValue = function() { - return this.value; -}; - -/** - * Calculate the distance from the nodes location to the given location (x,y) - * @param {Number} x - * @param {Number} y - * @return {Number} value - */ -Node.prototype.getDistance = function(x, y) { - var dx = this.x - x, - dy = this.y - y; - return Math.sqrt(dx * dx + dy * dy); -}; - - -/** - * Adjust the value range of the node. The node will adjust it's radius - * based on its value. - * @param {Number} min - * @param {Number} max - */ -Node.prototype.setValueRange = function(min, max) { - if (!this.radiusFixed && this.value !== undefined) { - if (max == min) { - this.radius = (this.radiusMin + this.radiusMax) / 2; - } - else { - var scale = (this.radiusMax - this.radiusMin) / (max - min); - this.radius = (this.value - min) * scale + this.radiusMin; - } - } - this.baseRadiusValue = this.radius; -}; - -/** - * Draw this node in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - */ -Node.prototype.draw = function(ctx) { - throw "Draw method not initialized for node"; -}; - -/** - * Recalculate the size of this node in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - */ -Node.prototype.resize = function(ctx) { - throw "Resize method not initialized for node"; -}; - -/** - * Check if this object is overlapping with the provided object - * @param {Object} obj an object with parameters left, top, right, bottom - * @return {boolean} True if location is located on node - */ -Node.prototype.isOverlappingWith = function(obj) { - return (this.left < obj.right && - this.left + this.width > obj.left && - this.top < obj.bottom && - this.top + this.height > obj.top); -}; - -Node.prototype._resizeImage = function (ctx) { - // TODO: pre calculate the image size - - if (!this.width || !this.height) { // undefined or 0 - var width, height; - if (this.value) { - this.radius = this.baseRadiusValue; - var scale = this.imageObj.height / this.imageObj.width; - if (scale !== undefined) { - width = this.radius || this.imageObj.width; - height = this.radius * scale || this.imageObj.height; - } - else { - width = 0; - height = 0; - } - } - else { - width = this.imageObj.width; - height = this.imageObj.height; - } - this.width = width; - this.height = height; - - if (this.width > 0 && this.height > 0) { - this.width += (this.clusterSize - 1) * this.clusterSizeWidthFactor; - this.height += (this.clusterSize - 1) * this.clusterSizeHeightFactor; - this.radius += (this.clusterSize - 1) * this.clusterSizeRadiusFactor; - } - } - -}; - -Node.prototype._drawImage = function (ctx) { - this._resizeImage(ctx); - - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - var yLabel; - if (this.imageObj.width != 0 ) { - // draw the shade - if (this.clusterSize > 1) { - var lineWidth = ((this.clusterSize > 1) ? 10 : 0.0); - lineWidth *= this.graphScaleInv; - lineWidth = Math.min(0.2 * this.width,lineWidth); - - ctx.globalAlpha = 0.5; - ctx.drawImage(this.imageObj, this.left - lineWidth, this.top - lineWidth, this.width + 2*lineWidth, this.height + 2*lineWidth); - } - - // draw the image - ctx.globalAlpha = 1.0; - ctx.drawImage(this.imageObj, this.left, this.top, this.width, this.height); - yLabel = this.y + this.height / 2; - } - else { - // image still loading... just draw the label for now - yLabel = this.y; - } - - this._label(ctx, this.label, this.x, yLabel, undefined, "top"); -}; - - -Node.prototype._resizeBox = function (ctx) { - if (!this.width) { - var margin = 5; - var textSize = this.getTextSize(ctx); - this.width = textSize.width + 2 * margin; - this.height = textSize.height + 2 * margin; - - this.width += (this.clusterSize - 1) * 0.5 * this.clusterSizeWidthFactor; - this.height += (this.clusterSize - 1) * 0.5 * this.clusterSizeHeightFactor; -// this.radius += (this.clusterSize - 1) * 0.5 * this.clusterSizeRadiusFactor; - } -}; - -Node.prototype._drawBox = function (ctx) { - this._resizeBox(ctx); - - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - var clusterLineWidth = 2.5; - var selectionLineWidth = 2; - - ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; - - // draw the outer border - if (this.clusterSize > 1) { - ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.graphScaleInv; - ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth); - - ctx.roundRect(this.left-2*ctx.lineWidth, this.top-2*ctx.lineWidth, this.width+4*ctx.lineWidth, this.height+4*ctx.lineWidth, this.radius); - ctx.stroke(); - } - ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.graphScaleInv; - ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth); - - ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; - - ctx.roundRect(this.left, this.top, this.width, this.height, this.radius); - ctx.fill(); - ctx.stroke(); - - this._label(ctx, this.label, this.x, this.y); -}; - - -Node.prototype._resizeDatabase = function (ctx) { - if (!this.width) { - var margin = 5; - var textSize = this.getTextSize(ctx); - var size = textSize.width + 2 * margin; - this.width = size; - this.height = size; - - // scaling used for clustering - this.width += (this.clusterSize - 1) * this.clusterSizeWidthFactor; - this.height += (this.clusterSize - 1) * this.clusterSizeHeightFactor; - this.radius += (this.clusterSize - 1) * this.clusterSizeRadiusFactor; - } -}; - -Node.prototype._drawDatabase = function (ctx) { - this._resizeDatabase(ctx); - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - var clusterLineWidth = 2.5; - var selectionLineWidth = 2; - - ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; - - // draw the outer border - if (this.clusterSize > 1) { - ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.graphScaleInv; - ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth); - - ctx.database(this.x - this.width/2 - 2*ctx.lineWidth, this.y - this.height*0.5 - 2*ctx.lineWidth, this.width + 4*ctx.lineWidth, this.height + 4*ctx.lineWidth); - ctx.stroke(); - } - ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.graphScaleInv; - ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth); - - ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; - ctx.database(this.x - this.width/2, this.y - this.height*0.5, this.width, this.height); - ctx.fill(); - ctx.stroke(); - - this._label(ctx, this.label, this.x, this.y); -}; - - -Node.prototype._resizeCircle = function (ctx) { - if (!this.width) { - var margin = 5; - var textSize = this.getTextSize(ctx); - var diameter = Math.max(textSize.width, textSize.height) + 2 * margin; - this.radius = diameter / 2; - - this.width = diameter; - this.height = diameter; - - // scaling used for clustering -// this.width += (this.clusterSize - 1) * 0.5 * this.clusterSizeWidthFactor; -// this.height += (this.clusterSize - 1) * 0.5 * this.clusterSizeHeightFactor; - this.radius += (this.clusterSize - 1) * 0.5 * this.clusterSizeRadiusFactor; - } -}; - -Node.prototype._drawCircle = function (ctx) { - this._resizeCircle(ctx); - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - var clusterLineWidth = 2.5; - var selectionLineWidth = 2; - - ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; - - // draw the outer border - if (this.clusterSize > 1) { - ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.graphScaleInv; - ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth); - - ctx.circle(this.x, this.y, this.radius+2*ctx.lineWidth); - ctx.stroke(); - } - ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.graphScaleInv; - ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth); - - ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; - ctx.circle(this.x, this.y, this.radius); - ctx.fill(); - ctx.stroke(); - - this._label(ctx, this.label, this.x, this.y); -}; - -Node.prototype._resizeEllipse = function (ctx) { - if (!this.width) { - var textSize = this.getTextSize(ctx); - - this.width = textSize.width * 1.5; - this.height = textSize.height * 2; - if (this.width < this.height) { - this.width = this.height; - } - - // scaling used for clustering - this.width += (this.clusterSize - 1) * this.clusterSizeWidthFactor; - this.height += (this.clusterSize - 1) * this.clusterSizeHeightFactor; - this.radius += (this.clusterSize - 1) * this.clusterSizeRadiusFactor; - } -}; - -Node.prototype._drawEllipse = function (ctx) { - this._resizeEllipse(ctx); - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - var clusterLineWidth = 2.5; - var selectionLineWidth = 2; - - ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; - - // draw the outer border - if (this.clusterSize > 1) { - ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.graphScaleInv; - ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth); - - ctx.ellipse(this.left-2*ctx.lineWidth, this.top-2*ctx.lineWidth, this.width+4*ctx.lineWidth, this.height+4*ctx.lineWidth); - ctx.stroke(); - } - ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.graphScaleInv; - ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth); - - ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; - - ctx.ellipse(this.left, this.top, this.width, this.height); - ctx.fill(); - ctx.stroke(); - this._label(ctx, this.label, this.x, this.y); -}; - -Node.prototype._drawDot = function (ctx) { - this._drawShape(ctx, 'circle'); -}; - -Node.prototype._drawTriangle = function (ctx) { - this._drawShape(ctx, 'triangle'); -}; - -Node.prototype._drawTriangleDown = function (ctx) { - this._drawShape(ctx, 'triangleDown'); -}; - -Node.prototype._drawSquare = function (ctx) { - this._drawShape(ctx, 'square'); -}; - -Node.prototype._drawStar = function (ctx) { - this._drawShape(ctx, 'star'); -}; - -Node.prototype._resizeShape = function (ctx) { - if (!this.width) { - this.radius = this.baseRadiusValue; - var size = 2 * this.radius; - this.width = size; - this.height = size; - - // scaling used for clustering - this.width += (this.clusterSize - 1) * this.clusterSizeWidthFactor; - this.height += (this.clusterSize - 1) * this.clusterSizeHeightFactor; - this.radius += (this.clusterSize - 1) * 0.5 * this.clusterSizeRadiusFactor; - } -}; - -Node.prototype._drawShape = function (ctx, shape) { - this._resizeShape(ctx); - - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - var clusterLineWidth = 2.5; - var selectionLineWidth = 2; - var radiusMultiplier = 2; - - // choose draw method depending on the shape - switch (shape) { - case 'dot': radiusMultiplier = 2; break; - case 'square': radiusMultiplier = 2; break; - case 'triangle': radiusMultiplier = 3; break; - case 'triangleDown': radiusMultiplier = 3; break; - case 'star': radiusMultiplier = 4; break; - } - - ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; - - // draw the outer border - if (this.clusterSize > 1) { - ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.graphScaleInv; - ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth); - - ctx[shape](this.x, this.y, this.radius + radiusMultiplier * ctx.lineWidth); - ctx.stroke(); - } - ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.graphScaleInv; - ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth); - - ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; - - ctx[shape](this.x, this.y, this.radius); - ctx.fill(); - ctx.stroke(); - - if (this.label) { - this._label(ctx, this.label, this.x, this.y + this.height / 2, undefined, 'top'); - } -}; - -Node.prototype._resizeText = function (ctx) { - if (!this.width) { - var margin = 5; - var textSize = this.getTextSize(ctx); - this.width = textSize.width + 2 * margin; - this.height = textSize.height + 2 * margin; - - // scaling used for clustering - this.width += (this.clusterSize - 1) * this.clusterSizeWidthFactor; - this.height += (this.clusterSize - 1) * this.clusterSizeHeightFactor; - this.radius += (this.clusterSize - 1) * this.clusterSizeRadiusFactor; - } -}; - -Node.prototype._drawText = function (ctx) { - this._resizeText(ctx); - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - this._label(ctx, this.label, this.x, this.y); -}; - - -Node.prototype._label = function (ctx, text, x, y, align, baseline) { - if (text) { - ctx.font = (this.selected ? "bold " : "") + this.fontSize + "px " + this.fontFace; - ctx.fillStyle = this.fontColor || "black"; - ctx.textAlign = align || "center"; - ctx.textBaseline = baseline || "middle"; - - var lines = text.split('\n'), - lineCount = lines.length, - fontSize = (this.fontSize + 4), - yLine = y + (1 - lineCount) / 2 * fontSize; - - for (var i = 0; i < lineCount; i++) { - ctx.fillText(lines[i], x, yLine); - yLine += fontSize; - } - } -}; - - -Node.prototype.getTextSize = function(ctx) { - if (this.label !== undefined) { - ctx.font = (this.selected ? "bold " : "") + this.fontSize + "px " + this.fontFace; - - var lines = this.label.split('\n'), - height = (this.fontSize + 4) * lines.length, - width = 0; - - for (var i = 0, iMax = lines.length; i < iMax; i++) { - width = Math.max(width, ctx.measureText(lines[i]).width); - } - - return {"width": width, "height": height}; - } - else { - return {"width": 0, "height": 0}; - } -}; - -/** - * this is used to determine if a node is visible at all. this is used to determine when it needs to be drawn. - * there is a safety margin of 0.3 * width; - * - * @returns {boolean} - */ -Node.prototype.inArea = function() { - if (this.width !== undefined) { - return (this.x + this.width*this.graphScaleInv >= this.canvasTopLeft.x && - this.x - this.width*this.graphScaleInv < this.canvasBottomRight.x && - this.y + this.height*this.graphScaleInv >= this.canvasTopLeft.y && - this.y - this.height*this.graphScaleInv < this.canvasBottomRight.y); - } - else { - return true; - } -} - -/** - * checks if the core of the node is in the display area, this is used for opening clusters around zoom - * @returns {boolean} - */ -Node.prototype.inView = function() { - return (this.x >= this.canvasTopLeft.x && - this.x < this.canvasBottomRight.x && - this.y >= this.canvasTopLeft.y && - this.y < this.canvasBottomRight.y); -} - -/** - * This allows the zoom level of the graph to influence the rendering - * We store the inverted scale and the coordinates of the top left, and bottom right points of the canvas - * - * @param scale - * @param canvasTopLeft - * @param canvasBottomRight - */ -Node.prototype.setScaleAndPos = function(scale,canvasTopLeft,canvasBottomRight) { - this.graphScaleInv = 1.0/scale; - this.canvasTopLeft = canvasTopLeft; - this.canvasBottomRight = canvasBottomRight; -}; - - -/** - * This allows the zoom level of the graph to influence the rendering - * - * @param scale - */ -Node.prototype.setScale = function(scale) { - this.graphScaleInv = 1.0/scale; -}; - -/** - * This function updates the damping parameter for clusters, based ont he - * - * @param {Number} numberOfNodes - */ -Node.prototype.updateDamping = function(numberOfNodes) { - this.damping = (0.9 + 0.1*this.clusterSize * (1 + Math.pow(numberOfNodes,-2))); -}; - - -/** - * set the velocity at 0. Is called when this node is contained in another during clustering - */ -Node.prototype.clearVelocity = function() { - this.vx = 0; - this.vy = 0; -}; - - -/** - * Basic preservation of (kinectic) energy - * - * @param massBeforeClustering - */ -Node.prototype.updateVelocity = function(massBeforeClustering) { - var energyBefore = this.vx * this.vx * massBeforeClustering; - this.vx = (this.vx < 0) ? -Math.sqrt(energyBefore/this.mass) : Math.sqrt(energyBefore/this.mass); - energyBefore = this.vy * this.vy * massBeforeClustering; - this.vy = (this.vy < 0) ? -Math.sqrt(energyBefore/this.mass) : Math.sqrt(energyBefore/this.mass); -}; - - -/** - * @class Edge - * - * A edge connects two nodes - * @param {Object} properties Object with properties. Must contain - * At least properties from and to. - * Available properties: from (number), - * to (number), label (string, color (string), - * width (number), style (string), - * length (number), title (string) - * @param {Graph} graph A graph object, used to find and edge to - * nodes. - * @param {Object} constants An object with default values for - * example for the color - */ -function Edge (properties, graph, constants) { - if (!graph) { - throw "No graph provided"; - } - this.graph = graph; - - // initialize constants - this.widthMin = constants.edges.widthMin; - this.widthMax = constants.edges.widthMax; - - // initialize variables - this.id = undefined; - this.fromId = undefined; - this.toId = undefined; - this.style = constants.edges.style; - this.title = undefined; - this.width = constants.edges.width; - this.value = undefined; - this.length = constants.physics.springLength; - this.selected = false; - - this.from = null; // a node - this.to = null; // a node - - // we use this to be able to reconnect the edge to a cluster if its node is put into a cluster - // by storing the original information we can revert to the original connection when the cluser is opened. - this.originalFromId = []; - this.originalToId = []; - - this.connected = false; - - // Added to support dashed lines - // David Jordan - // 2012-08-08 - this.dash = util.extend({}, constants.edges.dash); // contains properties length, gap, altLength - - this.springConstant = constants.physics.springConstant; - this.color = constants.edges.color; - this.widthFixed = false; - this.lengthFixed = false; - - this.setProperties(properties, constants); -} - -/** - * Set or overwrite properties for the edge - * @param {Object} properties an object with properties - * @param {Object} constants and object with default, global properties - */ -Edge.prototype.setProperties = function(properties, constants) { - if (!properties) { - return; - } - - if (properties.from !== undefined) {this.fromId = properties.from;} - if (properties.to !== undefined) {this.toId = properties.to;} - - if (properties.id !== undefined) {this.id = properties.id;} - if (properties.style !== undefined) {this.style = properties.style;} - if (properties.label !== undefined) {this.label = properties.label;} - if (this.label) { - this.fontSize = constants.edges.fontSize; - this.fontFace = constants.edges.fontFace; - this.fontColor = constants.edges.fontColor; - if (properties.fontColor !== undefined) {this.fontColor = properties.fontColor;} - if (properties.fontSize !== undefined) {this.fontSize = properties.fontSize;} - if (properties.fontFace !== undefined) {this.fontFace = properties.fontFace;} - } - if (properties.title !== undefined) {this.title = properties.title;} - if (properties.width !== undefined) {this.width = properties.width;} - if (properties.value !== undefined) {this.value = properties.value;} - if (properties.length !== undefined) {this.length = properties.length;} - - // Added to support dashed lines - // David Jordan - // 2012-08-08 - if (properties.dash) { - if (properties.dash.length !== undefined) {this.dash.length = properties.dash.length;} - if (properties.dash.gap !== undefined) {this.dash.gap = properties.dash.gap;} - if (properties.dash.altLength !== undefined) {this.dash.altLength = properties.dash.altLength;} - } - - if (properties.color !== undefined) {this.color = properties.color;} - - // A node is connected when it has a from and to node. - this.connect(); - - this.widthFixed = this.widthFixed || (properties.width !== undefined); - this.lengthFixed = this.lengthFixed || (properties.length !== undefined); - - // set draw method based on style - switch (this.style) { - case 'line': this.draw = this._drawLine; break; - case 'arrow': this.draw = this._drawArrow; break; - case 'arrow-center': this.draw = this._drawArrowCenter; break; - case 'dash-line': this.draw = this._drawDashLine; break; - default: this.draw = this._drawLine; break; - } -}; - -/** - * Connect an edge to its nodes - */ -Edge.prototype.connect = function () { - this.disconnect(); - - this.from = this.graph.nodes[this.fromId] || null; - this.to = this.graph.nodes[this.toId] || null; - this.connected = (this.from && this.to); - - if (this.connected) { - this.from.attachEdge(this); - this.to.attachEdge(this); - } - else { - if (this.from) { - this.from.detachEdge(this); - } - if (this.to) { - this.to.detachEdge(this); - } - } -}; - -/** - * Disconnect an edge from its nodes - */ -Edge.prototype.disconnect = function () { - if (this.from) { - this.from.detachEdge(this); - this.from = null; - } - if (this.to) { - this.to.detachEdge(this); - this.to = null; - } - - this.connected = false; -}; - -/** - * get the title of this edge. - * @return {string} title The title of the edge, or undefined when no title - * has been set. - */ -Edge.prototype.getTitle = function() { - return this.title; -}; - - -/** - * Retrieve the value of the edge. Can be undefined - * @return {Number} value - */ -Edge.prototype.getValue = function() { - return this.value; -}; - -/** - * Adjust the value range of the edge. The edge will adjust it's width - * based on its value. - * @param {Number} min - * @param {Number} max - */ -Edge.prototype.setValueRange = function(min, max) { - if (!this.widthFixed && this.value !== undefined) { - var scale = (this.widthMax - this.widthMin) / (max - min); - this.width = (this.value - min) * scale + this.widthMin; - } -}; - -/** - * Redraw a edge - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - */ -Edge.prototype.draw = function(ctx) { - throw "Method draw not initialized in edge"; -}; - -/** - * Check if this object is overlapping with the provided object - * @param {Object} obj an object with parameters left, top - * @return {boolean} True if location is located on the edge - */ -Edge.prototype.isOverlappingWith = function(obj) { - var distMax = 10; - - var xFrom = this.from.x; - var yFrom = this.from.y; - var xTo = this.to.x; - var yTo = this.to.y; - var xObj = obj.left; - var yObj = obj.top; - - - var dist = Edge._dist(xFrom, yFrom, xTo, yTo, xObj, yObj); - - return (dist < distMax); -}; - - -/** - * Redraw a edge as a line - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Edge.prototype._drawLine = function(ctx) { - // set style - ctx.strokeStyle = this.color; - ctx.lineWidth = this._getLineWidth(); - - var point; - if (this.from != this.to) { - // draw line - this._line(ctx); - - // draw label - if (this.label) { - point = this._pointOnLine(0.5); - this._label(ctx, this.label, point.x, point.y); - } - } - else { - var x, y; - var radius = this.length / 4; - var node = this.from; - if (!node.width) { - node.resize(ctx); - } - if (node.width > node.height) { - x = node.x + node.width / 2; - y = node.y - radius; - } - else { - x = node.x + radius; - y = node.y - node.height / 2; - } - this._circle(ctx, x, y, radius); - point = this._pointOnCircle(x, y, radius, 0.5); - this._label(ctx, this.label, point.x, point.y); - } -}; - -/** - * Get the line width of the edge. Depends on width and whether one of the - * connected nodes is selected. - * @return {Number} width - * @private - */ -Edge.prototype._getLineWidth = function() { - if (this.selected == true) { - return Math.min(this.width * 2, this.widthMax)*this.graphScaleInv; - } - else { - return this.width*this.graphScaleInv; - } -}; - -/** - * Draw a line between two nodes - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Edge.prototype._line = function (ctx) { - // draw a straight line - ctx.beginPath(); - ctx.moveTo(this.from.x, this.from.y); - ctx.lineTo(this.to.x, this.to.y); - ctx.stroke(); -}; - -/** - * Draw a line from a node to itself, a circle - * @param {CanvasRenderingContext2D} ctx - * @param {Number} x - * @param {Number} y - * @param {Number} radius - * @private - */ -Edge.prototype._circle = function (ctx, x, y, radius) { - // draw a circle - ctx.beginPath(); - ctx.arc(x, y, radius, 0, 2 * Math.PI, false); - ctx.stroke(); -}; - -/** - * Draw label with white background and with the middle at (x, y) - * @param {CanvasRenderingContext2D} ctx - * @param {String} text - * @param {Number} x - * @param {Number} y - * @private - */ -Edge.prototype._label = function (ctx, text, x, y) { - if (text) { - // TODO: cache the calculated size - ctx.font = ((this.from.selected || this.to.selected) ? "bold " : "") + - this.fontSize + "px " + this.fontFace; - ctx.fillStyle = 'white'; - var width = ctx.measureText(text).width; - var height = this.fontSize; - var left = x - width / 2; - var top = y - height / 2; - - ctx.fillRect(left, top, width, height); - - // draw text - ctx.fillStyle = this.fontColor || "black"; - ctx.textAlign = "left"; - ctx.textBaseline = "top"; - ctx.fillText(text, left, top); - } -}; - -/** - * Redraw a edge as a dashed line - * Draw this edge in the given canvas - * @author David Jordan - * @date 2012-08-08 - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Edge.prototype._drawDashLine = function(ctx) { - // set style - ctx.strokeStyle = this.color; - ctx.lineWidth = this._getLineWidth(); - - // draw dashed line - ctx.beginPath(); - ctx.lineCap = 'round'; - if (this.dash.altLength !== undefined) //If an alt dash value has been set add to the array this value - { - ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, - [this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]); - } - else if (this.dash.length !== undefined && this.dash.gap !== undefined) //If a dash and gap value has been set add to the array this value - { - ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, - [this.dash.length,this.dash.gap]); - } - else //If all else fails draw a line - { - ctx.moveTo(this.from.x, this.from.y); - ctx.lineTo(this.to.x, this.to.y); - } - ctx.stroke(); - - // draw label - if (this.label) { - var point = this._pointOnLine(0.5); - this._label(ctx, this.label, point.x, point.y); - } -}; - -/** - * Get a point on a line - * @param {Number} percentage. Value between 0 (line start) and 1 (line end) - * @return {Object} point - * @private - */ -Edge.prototype._pointOnLine = function (percentage) { - return { - x: (1 - percentage) * this.from.x + percentage * this.to.x, - y: (1 - percentage) * this.from.y + percentage * this.to.y - } -}; - -/** - * Get a point on a circle - * @param {Number} x - * @param {Number} y - * @param {Number} radius - * @param {Number} percentage. Value between 0 (line start) and 1 (line end) - * @return {Object} point - * @private - */ -Edge.prototype._pointOnCircle = function (x, y, radius, percentage) { - var angle = (percentage - 3/8) * 2 * Math.PI; - return { - x: x + radius * Math.cos(angle), - y: y - radius * Math.sin(angle) - } -}; - -/** - * Redraw a edge as a line with an arrow halfway the line - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Edge.prototype._drawArrowCenter = function(ctx) { - var point; - // set style - ctx.strokeStyle = this.color; - ctx.fillStyle = this.color; - ctx.lineWidth = this._getLineWidth(); - - if (this.from != this.to) { - // draw line - this._line(ctx); - - // draw an arrow halfway the line - var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); - var length = 10 + 5 * this.width; // TODO: make customizable? - point = this._pointOnLine(0.5); - ctx.arrow(point.x, point.y, angle, length); - ctx.fill(); - ctx.stroke(); - - // draw label - if (this.label) { - point = this._pointOnLine(0.5); - this._label(ctx, this.label, point.x, point.y); - } - } - else { - // draw circle - var x, y; - var radius = this.length / 4; - var node = this.from; - if (!node.width) { - node.resize(ctx); - } - if (node.width > node.height) { - x = node.x + node.width / 2; - y = node.y - radius; - } - else { - x = node.x + radius; - y = node.y - node.height / 2; - } - this._circle(ctx, x, y, radius); - - // draw all arrows - var angle = 0.2 * Math.PI; - var length = 10 + 5 * this.width; // TODO: make customizable? - point = this._pointOnCircle(x, y, radius, 0.5); - ctx.arrow(point.x, point.y, angle, length); - ctx.fill(); - ctx.stroke(); - - // draw label - if (this.label) { - point = this._pointOnCircle(x, y, radius, 0.5); - this._label(ctx, this.label, point.x, point.y); - } - } -}; - - - -/** - * Redraw a edge as a line with an arrow - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Edge.prototype._drawArrow = function(ctx) { - // set style - ctx.strokeStyle = this.color; - ctx.fillStyle = this.color; - ctx.lineWidth = this._getLineWidth(); - - // draw line - var angle, length; - if (this.from != this.to) { - // calculate length and angle of the line - angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); - var dx = (this.to.x - this.from.x); - var dy = (this.to.y - this.from.y); - var lEdge = Math.sqrt(dx * dx + dy * dy); - - var lFrom = this.from.distanceToBorder(ctx, angle + Math.PI); - var pFrom = (lEdge - lFrom) / lEdge; - var xFrom = (pFrom) * this.from.x + (1 - pFrom) * this.to.x; - var yFrom = (pFrom) * this.from.y + (1 - pFrom) * this.to.y; - - var lTo = this.to.distanceToBorder(ctx, angle); - var pTo = (lEdge - lTo) / lEdge; - var xTo = (1 - pTo) * this.from.x + pTo * this.to.x; - var yTo = (1 - pTo) * this.from.y + pTo * this.to.y; - - ctx.beginPath(); - ctx.moveTo(xFrom, yFrom); - ctx.lineTo(xTo, yTo); - ctx.stroke(); - - // draw arrow at the end of the line - length = 10 + 5 * this.width; // TODO: make customizable? - ctx.arrow(xTo, yTo, angle, length); - ctx.fill(); - ctx.stroke(); - - // draw label - if (this.label) { - var point = this._pointOnLine(0.5); - this._label(ctx, this.label, point.x, point.y); - } - } - else { - // draw circle - var node = this.from; - var x, y, arrow; - var radius = this.length / 4; - if (!node.width) { - node.resize(ctx); - } - if (node.width > node.height) { - x = node.x + node.width / 2; - y = node.y - radius; - arrow = { - x: x, - y: node.y, - angle: 0.9 * Math.PI - }; - } - else { - x = node.x + radius; - y = node.y - node.height / 2; - arrow = { - x: node.x, - y: y, - angle: 0.6 * Math.PI - }; - } - ctx.beginPath(); - // TODO: do not draw a circle, but an arc - // TODO: similarly, for a line without arrows, draw to the border of the nodes instead of the center - ctx.arc(x, y, radius, 0, 2 * Math.PI, false); - ctx.stroke(); - - // draw all arrows - length = 10 + 5 * this.width; // TODO: make customizable? - ctx.arrow(arrow.x, arrow.y, arrow.angle, length); - ctx.fill(); - ctx.stroke(); - - // draw label - if (this.label) { - point = this._pointOnCircle(x, y, radius, 0.5); - this._label(ctx, this.label, point.x, point.y); - } - } -}; - - - -/** - * Calculate the distance between a point (x3,y3) and a line segment from - * (x1,y1) to (x2,y2). - * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment - * @param {number} x1 - * @param {number} y1 - * @param {number} x2 - * @param {number} y2 - * @param {number} x3 - * @param {number} y3 - * @private - */ -Edge._dist = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point - var px = x2-x1, - py = y2-y1, - something = px*px + py*py, - u = ((x3 - x1) * px + (y3 - y1) * py) / something; - - if (u > 1) { - u = 1; - } - else if (u < 0) { - u = 0; - } - - var x = x1 + u * px, - y = y1 + u * py, - dx = x - x3, - dy = y - y3; - - //# Note: If the actual distance does not matter, - //# if you only want to compare what this function - //# returns to other results of this function, you - //# can just return the squared distance instead - //# (i.e. remove the sqrt) to gain a little performance - - return Math.sqrt(dx*dx + dy*dy); -}; - - - -/** - * This allows the zoom level of the graph to influence the rendering - * - * @param scale - */ -Edge.prototype.setScale = function(scale) { - this.graphScaleInv = 1.0/scale; -}; - - -Edge.prototype.select = function() { - this.selected = true; -} - -Edge.prototype.unselect = function() { - this.selected = false; -} -/** - * Popup is a class to create a popup window with some text - * @param {Element} container The container object. - * @param {Number} [x] - * @param {Number} [y] - * @param {String} [text] - */ -function Popup(container, x, y, text) { - if (container) { - this.container = container; - } - else { - this.container = document.body; - } - this.x = 0; - this.y = 0; - this.padding = 5; - - if (x !== undefined && y !== undefined ) { - this.setPosition(x, y); - } - if (text !== undefined) { - this.setText(text); - } - - // create the frame - this.frame = document.createElement("div"); - var style = this.frame.style; - style.position = "absolute"; - style.visibility = "hidden"; - style.border = "1px solid #666"; - style.color = "black"; - style.padding = this.padding + "px"; - style.backgroundColor = "#FFFFC6"; - style.borderRadius = "3px"; - style.MozBorderRadius = "3px"; - style.WebkitBorderRadius = "3px"; - style.boxShadow = "3px 3px 10px rgba(128, 128, 128, 0.5)"; - style.whiteSpace = "nowrap"; - this.container.appendChild(this.frame); -} - -/** - * @param {number} x Horizontal position of the popup window - * @param {number} y Vertical position of the popup window - */ -Popup.prototype.setPosition = function(x, y) { - this.x = parseInt(x); - this.y = parseInt(y); -}; - -/** - * Set the text for the popup window. This can be HTML code - * @param {string} text - */ -Popup.prototype.setText = function(text) { - this.frame.innerHTML = text; -}; - -/** - * Show the popup window - * @param {boolean} show Optional. Show or hide the window - */ -Popup.prototype.show = function (show) { - if (show === undefined) { - show = true; - } - - if (show) { - var height = this.frame.clientHeight; - var width = this.frame.clientWidth; - var maxHeight = this.frame.parentNode.clientHeight; - var maxWidth = this.frame.parentNode.clientWidth; - - var top = (this.y - height); - if (top + height + this.padding > maxHeight) { - top = maxHeight - height - this.padding; - } - if (top < this.padding) { - top = this.padding; - } - - var left = this.x; - if (left + width + this.padding > maxWidth) { - left = maxWidth - width - this.padding; - } - if (left < this.padding) { - left = this.padding; - } - - this.frame.style.left = left + "px"; - this.frame.style.top = top + "px"; - this.frame.style.visibility = "visible"; - } - else { - this.hide(); - } -}; - -/** - * Hide the popup window - */ -Popup.prototype.hide = function () { - this.frame.style.visibility = "hidden"; -}; - -/** - * @class Groups - * This class can store groups and properties specific for groups. - */ -Groups = function () { - this.clear(); - this.defaultIndex = 0; -}; - - -/** - * default constants for group colors - */ -Groups.DEFAULT = [ - {border: "#2B7CE9", background: "#97C2FC", highlight: {border: "#2B7CE9", background: "#D2E5FF"}}, // blue - {border: "#FFA500", background: "#FFFF00", highlight: {border: "#FFA500", background: "#FFFFA3"}}, // yellow - {border: "#FA0A10", background: "#FB7E81", highlight: {border: "#FA0A10", background: "#FFAFB1"}}, // red - {border: "#41A906", background: "#7BE141", highlight: {border: "#41A906", background: "#A1EC76"}}, // green - {border: "#E129F0", background: "#EB7DF4", highlight: {border: "#E129F0", background: "#F0B3F5"}}, // magenta - {border: "#7C29F0", background: "#AD85E4", highlight: {border: "#7C29F0", background: "#D3BDF0"}}, // purple - {border: "#C37F00", background: "#FFA807", highlight: {border: "#C37F00", background: "#FFCA66"}}, // orange - {border: "#4220FB", background: "#6E6EFD", highlight: {border: "#4220FB", background: "#9B9BFD"}}, // darkblue - {border: "#FD5A77", background: "#FFC0CB", highlight: {border: "#FD5A77", background: "#FFD1D9"}}, // pink - {border: "#4AD63A", background: "#C2FABC", highlight: {border: "#4AD63A", background: "#E6FFE3"}} // mint -]; - - -/** - * Clear all groups - */ -Groups.prototype.clear = function () { - this.groups = {}; - this.groups.length = function() - { - var i = 0; - for ( var p in this ) { - if (this.hasOwnProperty(p)) { - i++; - } - } - return i; - } -}; - - -/** - * get group properties of a groupname. If groupname is not found, a new group - * is added. - * @param {*} groupname Can be a number, string, Date, etc. - * @return {Object} group The created group, containing all group properties - */ -Groups.prototype.get = function (groupname) { - var group = this.groups[groupname]; - - if (group == undefined) { - // create new group - var index = this.defaultIndex % Groups.DEFAULT.length; - this.defaultIndex++; - group = {}; - group.color = Groups.DEFAULT[index]; - this.groups[groupname] = group; - } - - return group; -}; - -/** - * Add a custom group style - * @param {String} groupname - * @param {Object} style An object containing borderColor, - * backgroundColor, etc. - * @return {Object} group The created group object - */ -Groups.prototype.add = function (groupname, style) { - this.groups[groupname] = style; - if (style.color) { - style.color = Node.parseColor(style.color); - } - return style; -}; - -/** - * @class Images - * This class loads images and keeps them stored. - */ -Images = function () { - this.images = {}; - - this.callback = undefined; -}; - -/** - * Set an onload callback function. This will be called each time an image - * is loaded - * @param {function} callback - */ -Images.prototype.setOnloadCallback = function(callback) { - this.callback = callback; -}; - -/** - * - * @param {string} url Url of the image - * @return {Image} img The image object - */ -Images.prototype.load = function(url) { - var img = this.images[url]; - if (img == undefined) { - // create the image - var images = this; - img = new Image(); - this.images[url] = img; - img.onload = function() { - if (images.callback) { - images.callback(this); - } - }; - img.src = url; - } - - return img; -}; - -/** - * Created by Alex on 2/6/14. - */ - - -var physicsMixin = { - - /** - * Before calculating the forces, we check if we need to cluster to keep up performance and we check - * if there is more than one node. If it is just one node, we dont calculate anything. - * - * @private - */ - _initializeForceCalculation : function(useBarnesHut) { - // stop calculation if there is only one node - if (this.nodeIndices.length == 1) { - this.nodes[this.nodeIndices[0]]._setForce(0,0); - } - else { - // if there are too many nodes on screen, we cluster without repositioning - if (this.nodeIndices.length > this.constants.clustering.clusterThreshold && this.constants.clustering.enabled == true) { - this.clusterToFit(this.constants.clustering.reduceToNodes, false); - } - - this._calculateForcesRepulsion(); - -// // we now start the force calculation -// if (useBarnesHut == true) { -// this._calculateForcesBarnesHut(); -// } -// else { -// this._calculateForcesRepulsion(); -// } - } - }, - - - /** - * Calculate the external forces acting on the nodes - * Forces are caused by: edges, repulsing forces between nodes, gravity - * @private - */ - _calculateForcesRepulsion : function() { - // Gravity is required to keep separated groups from floating off - // the forces are reset to zero in this loop by using _setForce instead - // of _addForce - -// var startTimeAll = Date.now(); - - this._applyCentralGravity(); - -// var startTimeRepulsion = Date.now(); - // All nodes repel eachother. - this._applyNodeRepulsion(); - -// var endTimeRepulsion = Date.now(); - - // the edges are strings - this._applySpringForces(); - -// var endTimeAll = Date.now(); - -// echo("Time repulsion part:", endTimeRepulsion - startTimeRepulsion); -// echo("Time total force calc:", endTimeAll - startTimeAll); - }, - - /** - * Calculate the external forces acting on the nodes - * Forces are caused by: edges, repulsing forces between nodes, gravity - * @private - */ - _calculateForcesBarnesHut : function() { - // Gravity is required to keep separated groups from floating off - // the forces are reset to zero in this loop by using _setForce instead - // of _addForce - -// var startTimeAll = Date.now(); - - this._applyCentralGravity(); - -// var startTimeRepulsion = Date.now(); - // All nodes repel eachother. - this._calculateBarnesHutForces(); - -// var endTimeRepulsion = Date.now(); - - // the edges are strings - this._applySpringForces(); - -// var endTimeAll = Date.now(); - -// echo("Time repulsion part:", endTimeRepulsion - startTimeRepulsion); -// echo("Time total force calc:", endTimeAll - startTimeAll); - }, - - - _clearForces : function() { - var node; - var nodes = this.nodes; - - for (var i = 0; i < this.nodeIndices.length; i++) { - node = nodes[this.nodeIndices[i]]; - node._setForce(0, 0); - node.updateDamping(this.nodeIndices.length); - } - }, - - _applyCentralGravity : function() { - var dx, dy, angle, fx, fy, node, i; - var nodes = this.nodes; - var gravity = this.constants.physics.centralGravity; - - for (i = 0; i < this.nodeIndices.length; i++) { - node = nodes[this.nodeIndices[i]]; - // gravity does not apply when we are in a pocket sector - if (this._sector() == "default") { - dx = -node.x;// + screenCenterPos.x; - dy = -node.y;// + screenCenterPos.y; - - angle = Math.atan2(dy, dx); - fx = Math.cos(angle) * gravity; - fy = Math.sin(angle) * gravity; - } - else { - fx = 0; - fy = 0; - } - node._setForce(fx, fy); - node.updateDamping(this.nodeIndices.length); - } - }, - - _applyNodeRepulsion : function() { - var dx, dy, angle, distance, fx, fy, clusterSize, - repulsingForce, node1, node2, i, j; - var nodes = this.nodes; - - // approximation constants - var a_base = -2/3; - var b = 4/3; - - // repulsing forces between nodes - var minimumDistance = this.constants.nodes.distance; - //var steepness = 10; - - // we loop from i over all but the last entree in the array - // j loops from i+1 to the last. This way we do not double count any of the indices, nor i == j - for (i = 0; i < this.nodeIndices.length-1; i++) { - node1 = nodes[this.nodeIndices[i]]; - for (j = i+1; j < this.nodeIndices.length; j++) { - node2 = nodes[this.nodeIndices[j]]; - clusterSize = (node1.clusterSize + node2.clusterSize - 2); - dx = node2.x - node1.x; - dy = node2.y - node1.y; - distance = Math.sqrt(dx * dx + dy * dy); - - - // clusters have a larger region of influence - minimumDistance = (clusterSize == 0) ? this.constants.nodes.distance : (this.constants.nodes.distance * (1 + clusterSize * this.constants.clustering.distanceAmplification)); - var a = a_base / minimumDistance; - if (distance < 2*minimumDistance) { // at 2.0 * the minimum distance, the force is 0.000045 - angle = Math.atan2(dy, dx); - - if (distance < 0.5*minimumDistance) { // at 0.5 * the minimum distance, the force is 0.993307 - repulsingForce = 1.0; - } - else { - repulsingForce = a * distance + b; // linear approx of 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)) - } - // amplify the repulsion for clusters. - repulsingForce *= (clusterSize == 0) ? 1 : 1 + clusterSize * this.constants.clustering.forceAmplification; - - fx = Math.cos(angle) * repulsingForce; - fy = Math.sin(angle) * repulsingForce ; - - node1._addForce(-fx, -fy); - node2._addForce(fx, fy); - } - } - } - }, - - _applySpringForces : function() { - var dx, dy, angle, fx, fy, springForce, length, edgeLength, edge, edgeId, clusterSize; - var edges = this.edges; - - // forces caused by the edges, modelled as springs - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.connected) { - // only calculate forces if nodes are in the same sector - if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { - clusterSize = (edge.to.clusterSize + edge.from.clusterSize - 2); - dx = (edge.to.x - edge.from.x); - dy = (edge.to.y - edge.from.y); - - edgeLength = edge.length; - - // this implies that the edges between big clusters are longer - edgeLength += clusterSize * this.constants.clustering.edgeGrowth; - length = Math.sqrt(dx * dx + dy * dy); - angle = Math.atan2(dy, dx); - - springForce = edge.springConstant * (edgeLength - length); - - fx = Math.cos(angle) * springForce; - fy = Math.sin(angle) * springForce; - //console.log(edge.length,dx,dy,edge.springConstant,angle) - edge.from._addForce(-fx, -fy); - edge.to._addForce(fx, fy); - } - } - } - } - }, - - _calculateBarnesHutForces : function() { - this._formBarnesHutTree(); - - var nodes = this.nodes; - var nodeIndices = this.nodeIndices; - var node; - var nodeCount = nodeIndices.length; - - var barnesHutTree = this.barnesHutTree; - - // place the nodes one by one recursively - for (var i = 0; i < nodeCount; i++) { - node = nodes[nodeIndices[i]]; - // starting with root is irrelevant, it never passes the BarnesHut condition - this._getForceContribution(barnesHutTree.root.children.NW,node); - this._getForceContribution(barnesHutTree.root.children.NE,node); - this._getForceContribution(barnesHutTree.root.children.SW,node); - this._getForceContribution(barnesHutTree.root.children.SE,node); - } - }, - - _getForceContribution : function(parentBranch,node) { - // we get no force contribution from an empty region - if (parentBranch.childrenCount > 0) { - var dx,dy,distance; - - // get the distance from the center of mass to the node. - dx = parentBranch.CenterOfMass.x - node.x; - dy = parentBranch.CenterOfMass.y - node.y; - distance = Math.sqrt(dx * dx + dy * dy); - - if (distance > 0) { // distance is 0 if it looks to apply a force on itself. - // we invert it here because we need the inverted distance for the force calculation too. - var distanceInv = 1/distance; - - // BarnesHut condition - if (parentBranch.size * distanceInv > this.constants.physics.barnesHutTheta) { - // Did not pass the condition, go into children if available - if (parentBranch.childrenCount == 4) { - this._getForceContribution(parentBranch.children.NW,node); - this._getForceContribution(parentBranch.children.NE,node); - this._getForceContribution(parentBranch.children.SW,node); - this._getForceContribution(parentBranch.children.SE,node); - } - else { // parentBranch must have only one node, if it was empty we wouldnt be here - if (parentBranch.children.data.id != node.id) { // if it is not self - this._getForceOnNode(parentBranch, node, dx ,dy, distanceInv); - } - } - } - else { - this._getForceOnNode(parentBranch, node, dx ,dy, distanceInv); - } - } - } - }, - - _getForceOnNode : function(parentBranch, node, dx ,dy, distanceInv) { - // even if the parentBranch only has one node, its Center of Mass is at the right place (the node in this case). - var gravityForce = this.constants.physics.nodeGravityConstant * parentBranch.mass * node.mass * distanceInv * distanceInv; - var angle = Math.atan2(dy, dx); - var fx = Math.cos(angle) * gravityForce; - var fy = Math.sin(angle) * gravityForce; - node._addForce(fx, fy); - }, - - - _formBarnesHutTree : function() { - var nodes = this.nodes; - var nodeIndices = this.nodeIndices; - var node; - var nodeCount = nodeIndices.length; - - var minX = Number.MAX_VALUE, - minY = Number.MAX_VALUE, - maxX =-Number.MAX_VALUE, - maxY =-Number.MAX_VALUE; - - // get the range of the nodes - for (var i = 0; i < nodeCount; i++) { - var x = nodes[nodeIndices[i]].x; - var y = nodes[nodeIndices[i]].y; - if (x < minX) { minX = x; } - if (x > maxX) { maxX = x; } - if (y < minY) { minY = y; } - if (y > maxY) { maxY = y; } - } - // make the range a square - var sizeDiff = Math.abs(maxX - minX) - Math.abs(maxY - minY); // difference between X and Y - if (sizeDiff > 0) {minY -= 0.5 * sizeDiff; maxY += 0.5 * sizeDiff;} // xSize > ySize - else {minX += 0.5 * sizeDiff; maxX -= 0.5 * sizeDiff;} // xSize < ySize - - - // construct the barnesHutTree - var barnesHutTree = {root:{ - CenterOfMass:{x:0,y:0}, // Center of Mass - mass:0, - range:{minX:minX,maxX:maxX,minY:minY,maxY:maxY}, - size: Math.abs(maxX - minX), - children: {data:null}, - level: 0, - childrenCount: 4 - }}; - this._splitBranch(barnesHutTree.root); - - // place the nodes one by one recursively - for (i = 0; i < nodeCount; i++) { - node = nodes[nodeIndices[i]]; - this._placeInTree(barnesHutTree.root,node); - } - - // make global - this.barnesHutTree = barnesHutTree - }, - - _updateBranchMass : function(parentBranch, node) { - var totalMass = parentBranch.mass + node.mass; - var totalMassInv = 1/totalMass; - - parentBranch.CenterOfMass.x = parentBranch.CenterOfMass.x * parentBranch.mass + node.x * node.mass; - parentBranch.CenterOfMass.x *= totalMassInv; - - parentBranch.CenterOfMass.y = parentBranch.CenterOfMass.y * parentBranch.mass + node.y * node.mass; - parentBranch.CenterOfMass.y *= totalMassInv; - - parentBranch.mass = totalMass; - }, - - _placeInTree : function(parentBranch,node) { - // update the mass of the branch. - this._updateBranchMass(parentBranch,node); - - if (parentBranch.children.NW.range.maxX > node.x) { // in NW or SW - if (parentBranch.children.NW.range.maxY > node.y) { // in NW - this._placeInRegion(parentBranch,node,"NW"); - } - else { // in SW - this._placeInRegion(parentBranch,node,"SW"); - } - } - else { // in NE or SE - if (parentBranch.children.NE.range.maxY > node.y) { // in NE - this._placeInRegion(parentBranch,node,"NE"); - } - else { // in SE - this._placeInRegion(parentBranch,node,"SE"); - } - } - }, - - _placeInRegion : function(parentBranch,node,region) { - switch (parentBranch.children[region].childrenCount) { - case 0: // place node here - parentBranch.children[region].children.data = node; - parentBranch.children[region].childrenCount = 1; - this._updateBranchMass(parentBranch.children[region],node); - break; - case 1: // convert into children - this._splitBranch(parentBranch.children[region]); - this._placeInTree(parentBranch.children[region],node); - break; - case 4: // place in branch - this._placeInTree(parentBranch.children[region],node); - break; - } - }, - - _splitBranch : function(parentBranch) { - // if the branch is filled with a node, replace the node in the new subset. - var containedNode = null; - if (parentBranch.childrenCount == 1) { - containedNode = parentBranch.children.data; - parentBranch.mass = 0; parentBranch.CenterOfMass.x = 0; parentBranch.CenterOfMass.y = 0; - } - parentBranch.childrenCount = 4; - parentBranch.children.data = null; - this._insertRegion(parentBranch,"NW"); - this._insertRegion(parentBranch,"NE"); - this._insertRegion(parentBranch,"SW"); - this._insertRegion(parentBranch,"SE"); - - if (containedNode != null) { - this._placeInTree(parentBranch,containedNode); - } - }, - - - /** - * This function subdivides the region into four new segments. - * Specifically, this inserts a single new segment. - * It fills the children section of the parentBranch - * - * @param parentBranch - * @param region - * @param parentRange - * @private - */ - _insertRegion : function(parentBranch, region) { - var minX,maxX,minY,maxY; - switch (region) { - case "NW": - minX = parentBranch.range.minX; - maxX = parentBranch.range.minX + parentBranch.size; - minY = parentBranch.range.minY; - maxY = parentBranch.range.minY + parentBranch.size; - break; - case "NE": - minX = parentBranch.range.minX + parentBranch.size; - maxX = parentBranch.range.maxX; - minY = parentBranch.range.minY; - maxY = parentBranch.range.minY + parentBranch.size; - break; - case "SW": - minX = parentBranch.range.minX; - maxX = parentBranch.range.minX + parentBranch.size; - minY = parentBranch.range.minY + parentBranch.size; - maxY = parentBranch.range.maxY; - break; - case "SE": - minX = parentBranch.range.minX + parentBranch.size; - maxX = parentBranch.range.maxX; - minY = parentBranch.range.minY + parentBranch.size; - maxY = parentBranch.range.maxY; - break; - } - - - parentBranch.children[region] = { - CenterOfMass:{x:0,y:0}, - mass:0, - range:{minX:minX,maxX:maxX,minY:minY,maxY:maxY}, - size: 0.5 * parentBranch.size, - children: {data:null}, - level: parentBranch.level +1, - childrenCount: 0 - }; - }, - - _drawTree : function(ctx,color) { - if (this.barnesHutTree !== undefined) { - - ctx.lineWidth = 1; - - this._drawBranch(this.barnesHutTree.root,ctx,color); - } - }, - - _drawBranch : function(branch,ctx,color) { - if (color === undefined) { - color = "#FF0000"; - } - - if (branch.childrenCount == 4) { - this._drawBranch(branch.children.NW,ctx); - this._drawBranch(branch.children.NE,ctx); - this._drawBranch(branch.children.SE,ctx); - this._drawBranch(branch.children.SW,ctx); - } - ctx.strokeStyle = color; - ctx.beginPath(); - ctx.moveTo(branch.range.minX,branch.range.minY); - ctx.lineTo(branch.range.maxX,branch.range.minY); - ctx.stroke(); - - ctx.beginPath(); - ctx.moveTo(branch.range.maxX,branch.range.minY); - ctx.lineTo(branch.range.maxX,branch.range.maxY); - ctx.stroke(); - - ctx.beginPath(); - ctx.moveTo(branch.range.maxX,branch.range.maxY); - ctx.lineTo(branch.range.minX,branch.range.maxY); - ctx.stroke(); - - ctx.beginPath(); - ctx.moveTo(branch.range.minX,branch.range.maxY); - ctx.lineTo(branch.range.minX,branch.range.minY); - ctx.stroke(); - - /* - if (branch.mass > 0) { - ctx.circle(branch.CenterOfMass.x, branch.CenterOfMass.y, 3*branch.mass); - ctx.stroke(); - } - */ - } -}; -/** - * Created by Alex on 2/4/14. - */ - -var manipulationMixin = { - - /** - * clears the toolbar div element of children - * - * @private - */ - _clearManipulatorBar : function() { - while (this.manipulationDiv.hasChildNodes()) { - this.manipulationDiv.removeChild(this.manipulationDiv.firstChild); - } - }, - - - /** - * main function, creates the main toolbar. Removes functions bound to the select event. Binds all the buttons of the toolbar. - * - * @private - */ - _createManipulatorBar : function() { - // remove bound functions - this.off('select', this.boundFunction); - - // reset global variables - this.blockConnectingEdgeSelection = false; - this.forceAppendSelection = false - - while (this.manipulationDiv.hasChildNodes()) { - this.manipulationDiv.removeChild(this.manipulationDiv.firstChild); - } - // add the icons to the manipulator div - this.manipulationDiv.innerHTML = "" + - "Add Node" + - "
    " + - "Edit Selected" + - "
    " + - "Connect Node" + - "
    " + - "Delete selected"; - - // bind the icons - var addButton = document.getElementById("manipulate-addNode"); - addButton.onclick = this._createAddToolbar.bind(this); - var editButton = document.getElementById("manipulate-editNode"); - editButton.onclick = this._createEditToolbar.bind(this); - var connectButton = document.getElementById("manipulate-connectNode"); - connectButton.onclick = this._createConnectToolbar.bind(this); - var deleteButton = document.getElementById("manipulate-delete"); - deleteButton.onclick = this._createDeletionToolbar.bind(this); - }, - - - /** - * Create the toolbar for adding Nodes - * - * @private - */ - _createAddToolbar : function() { - // clear the toolbar - this._clearManipulatorBar(); - this.off('select', this.boundFunction); - - // create the toolbar contents - this.manipulationDiv.innerHTML = "" + - "Back" + - "
    " + - "Click in an empty space to place a new node"; - - // bind the icon - var backButton = document.getElementById("manipulate-back"); - backButton.onclick = this._createManipulatorBar.bind(this); - - // we use the boundFunction so we can reference it when we unbind it from the "select" event. - this.boundFunction = this._addNode.bind(this); - this.on('select', this.boundFunction); - }, - - - /** - * Create the toolbar to edit nodes or edges. - * TODO: edges not implemented yet, unsure what to edit. - * - * @private - */ - _createEditToolbar : function() { - // clear the toolbar - this.blockConnectingEdgeSelection = false; - this._clearManipulatorBar(); - this.off('select', this.boundFunction); - - - var message = ""; - if (this._selectionIsEmpty()) { - message = "Select a node or edge to edit."; - } - else { - if (this._getSelectedObjectCount() > 1) { - message = "Select a single node or edge to edit." - this._unselectAll(true); - } - else { - if (this._clusterInSelection()) { - message = "You cannot edit a cluster." - this._unselectAll(true); - } - else { - if (this._getSelectedNodeCount() > 0) { // the selected item is a node - this._createEditNodeToolbar(); - } - else { // the selected item is an edge - this._createEditEdgeToolbar(); - } - } - } - } - - if (message != "") { - this.blockConnectingEdgeSelection = true; - // create the toolbar contents - this.manipulationDiv.innerHTML = "" + - "Back" + - "
    " + - ""+message+""; - - // bind the icon - var backButton = document.getElementById("manipulate-back"); - backButton.onclick = this._createManipulatorBar.bind(this); - - // we use the boundFunction so we can reference it when we unbind it from the "select" event. - this.boundFunction = this._createEditToolbar.bind(this); - this.on('select', this.boundFunction); - } - }, - - - /** - * Create the toolbar to edit the selected node. The label and the color can be changed. Other colors are derived from the chosen color. - * TODO: change shape or group? - * - * @private - */ - _createEditNodeToolbar : function() { - // clear the toolbar - this.blockConnectingEdgeSelection = false; - this._clearManipulatorBar(); - this.off('select', this.boundFunction); - - var editObject = this._getEditObject(); - - // create the toolbar contents - this.manipulationDiv.innerHTML = "" + - "Cancel" + - "
    " + - "label: " + - "
    " + - "color: " + - "
    " + - "" - - // bind the icon - var backButton = document.getElementById("manipulate-back"); - backButton.onclick = this._createManipulatorBar.bind(this); - var saveButton = document.getElementById("manipulator-obj-save"); - saveButton.onclick = this._saveNodeData.bind(this); - - // we use the boundFunction so we can reference it when we unbind it from the "select" event. - this.boundFunction = this._createManipulatorBar.bind(this); - this.on('select', this.boundFunction); - }, - - - /** - * save the changes in the node data - * - * @private - */ - _saveNodeData : function() { - var editObjectId = this._getEditObject().id; - var label = document.getElementById('manipulator-obj-label').value; - - var definedColor = document.getElementById('manipulator-obj-color').value; - var hsv = util.hexToHSV(definedColor); - - var lighterColorHSV = {h:hsv.h,s:hsv.s * 0.45,v:Math.min(1,hsv.v * 1.05)}; - var darkerColorHSV = {h:hsv.h,s:Math.min(1,hsv.v * 1.25),v:hsv.v*0.6}; - var darkerColorHex = util.HSVToHex(darkerColorHSV.h ,darkerColorHSV.h ,darkerColorHSV.v); - var lighterColorHex = util.HSVToHex(lighterColorHSV.h,lighterColorHSV.s,lighterColorHSV.v); - - var updatedSettings = {id:editObjectId, - label: label, - color: { - background:definedColor, - border:darkerColorHex, - highlight: { - background:lighterColorHex, - border:darkerColorHex - } - }}; - this.nodesData.update(updatedSettings); - this._createManipulatorBar(); - }, - - - /** - * creating the toolbar to edit edges. - * - * @private - */ - _createEditEdgeToolbar : function() { - // clear the toolbar - this.blockConnectingEdgeSelection = false; - this._clearManipulatorBar(); - this.off('select', this.boundFunction); - - // create the toolbar contents - this.manipulationDiv.innerHTML = "" + - "Back" + - "
    " + - "Currently only nodes can be edited."; - - // bind the icon - var backButton = document.getElementById("manipulate-back"); - backButton.onclick = this._createManipulatorBar.bind(this); - - // we use the boundFunction so we can reference it when we unbind it from the "select" event. - this.boundFunction = this._createManipulatorBar.bind(this); - this.on('select', this.boundFunction); - }, - - - /** - * create the toolbar to connect nodes - * - * @private - */ - _createConnectToolbar : function() { - // clear the toolbar - this._clearManipulatorBar(); - this.off('select', this.boundFunction); - - this._unselectAll(); - this.forceAppendSelection = false; - this.blockConnectingEdgeSelection = true; - - this.manipulationDiv.innerHTML = "" + - "Back" + - "
    " + - "Select the node you want to connect to other nodes."; - - // bind the icon - var backButton = document.getElementById("manipulate-back"); - backButton.onclick = this._createManipulatorBar.bind(this); - - // we use the boundFunction so we can reference it when we unbind it from the "select" event. - this.boundFunction = this._handleConnect.bind(this); - this.on('select', this.boundFunction); - }, - - - /** - * create the toolbar for deleting selected objects. User has to be sure. - * - * @private - */ - _createDeletionToolbar : function() { - // clear the toolbar - this._clearManipulatorBar(); - this.off('select', this.boundFunction); - - if (this._selectionIsEmpty()) { - this.manipulationDiv.innerHTML = "" + - "Cannot delete an empty selection."; - var graph = this; - window.setTimeout (function() {graph._createManipulatorBar()},1500); - } - else { - this.manipulationDiv.innerHTML = "" + - "Back" + - "
    " + - "Are you sure? This cannot be undone." + - "
    " + - "Yes."; - - // bind the buttons - var backButton = document.getElementById("manipulate-back"); - backButton.onclick = this._createManipulatorBar.bind(this); - var acceptDeleteButton = document.getElementById("manipulate-acceptDelete"); - acceptDeleteButton.onclick = this._deleteSelected.bind(this); - - // we use the boundFunction so we can reference it when we unbind it from the "select" event. - this.boundFunction = this._createManipulatorBar.bind(this); - this.on('select', this.boundFunction); - } - }, - - - /** - * the function bound to the selection event. It checks if you want to connect a cluster and changes the description - * to walk the user through the process. - * - * @private - */ - _handleConnect : function() { - this.forceAppendSelection = false; - if (this._clusterInSelection()) { - this._unselectClusters(true); - if (!this._selectionIsEmpty()) { - this._setManipulationMessage("You cannot connect a node to a cluster."); - this.forceAppendSelection = true; - } - else { - this._setManipulationMessage("You cannot connect anything to a cluster."); - } - } - else if (!this._selectionIsEmpty()) { - if (this._getSelectedNodeCount() == 2) { - this._connectNodes(); - this._restoreSourceNode(); - this._setManipulationMessage("Click on another node you want to connect this node to or go back."); - } - else { - this._setManipulationMessage("Click on the node you want to connect this node."); - this._setSourceNode(); - this.forceAppendSelection = true; - } - } - else { - this._setManipulationMessage("Select the node you want to connect to other nodes."); - } - }, - - - /** - * returns the object that is selected - * - * @returns {*} - * @private - */ - _getEditObject : function() { - for(var objectId in this.selectionObj) { - if(this.selectionObj.hasOwnProperty(objectId)) { - return this.selectionObj[objectId]; - } - } - return null; - }, - - - /** - * stores the first selected node for the connecting process as the source node. This allows us to remember the direction - * - * @private - */ - _setSourceNode : function() { - for(var objectId in this.selectionObj) { - if(this.selectionObj.hasOwnProperty(objectId)) { - if (this.selectionObj[objectId] instanceof Node) { - this.manipulationSourceNode = this.selectionObj[objectId]; - } - } - } - }, - - - /** - * gets the node the source connects to. - * - * @returns {*} - * @private - */ - _getTargetNode : function() { - for(var objectId in this.selectionObj) { - if(this.selectionObj.hasOwnProperty(objectId)) { - if (this.selectionObj[objectId] instanceof Node) { - if (this.manipulationSourceNode.id != this.selectionObj[objectId].id) { - return this.selectionObj[objectId]; - } - } - } - } - return null; - }, - - - /** - * restore the selection back to only the sourcenode - * - * @private - */ - _restoreSourceNode : function() { - this._unselectAll(true); - this._selectObject(this.manipulationSourceNode); - }, - - - /** - * change the description message on the toolbar - * - * @param message - * @private - */ - _setManipulationMessage : function(message) { - var messageSpan = document.getElementById('manipulatorLabel'); - messageSpan.innerHTML = message; - }, - - - /** - * Adds a node on the specified location - * - * @param {Object} pointer - */ - _addNode : function() { - if (this._selectionIsEmpty()) { - var positionObject = this._pointerToPositionObject(this.pointerPosition); - this.createNodeOnClick = true; - this.nodesData.add({id:util.randomUUID(),x:positionObject.left,y:positionObject.top,label:"new",fixed:false}); - this.createNodeOnClick = false; - this.moving = true; - this.start(); - } - }, - - - /** - * connect two nodes with a new edge. - * - * @private - */ - _connectNodes : function() { - var targetNode = this._getTargetNode(); - var sourceNode = this.manipulationSourceNode; - this.edgesData.add({from:sourceNode.id, to:targetNode.id}) - this.moving = true; - this.start(); - }, - - - /** - * delete everything in the selection - * TODO : place the alert in the gui. - * - * - * @private - */ - _deleteSelected : function() { - if (!this._clusterInSelection()) { - var selectedNodes = this.getSelectedNodes(); - var selectedEdges = this.getSelectedEdges(); - this._removeEdges(selectedEdges); - this._removeNodes(selectedNodes); - this.moving = true; - this.start(); - } - else { - alert("Clusters cannot be deleted.") - } - } - - -}; -/** - * Creation of the SectorMixin var. - * - * This contains all the functions the Graph object can use to employ the sector system. - * The sector system is always used by Graph, though the benefits only apply to the use of clustering. - * If clustering is not used, there is no overhead except for a duplicate object with references to nodes and edges. - * - * Alex de Mulder - * 21-01-2013 - */ -var SectorMixin = { - - /** - * This function is only called by the setData function of the Graph object. - * This loads the global references into the active sector. This initializes the sector. - * - * @private - */ - _putDataInSector : function() { - this.sectors["active"][this._sector()].nodes = this.nodes; - this.sectors["active"][this._sector()].edges = this.edges; - this.sectors["active"][this._sector()].nodeIndices = this.nodeIndices; - }, - - - /** - * /** - * This function sets the global references to nodes, edges and nodeIndices back to - * those of the supplied (active) sector. If a type is defined, do the specific type - * - * @param {String} sectorId - * @param {String} [sectorType] | "active" or "frozen" - * @private - */ - _switchToSector : function(sectorId, sectorType) { - if (sectorType === undefined || sectorType == "active") { - this._switchToActiveSector(sectorId); - } - else { - this._switchToFrozenSector(sectorId); - } - }, - - - /** - * This function sets the global references to nodes, edges and nodeIndices back to - * those of the supplied active sector. - * - * @param sectorId - * @private - */ - _switchToActiveSector : function(sectorId) { - this.nodeIndices = this.sectors["active"][sectorId]["nodeIndices"]; - this.nodes = this.sectors["active"][sectorId]["nodes"]; - this.edges = this.sectors["active"][sectorId]["edges"]; - }, - - - /** - * This function sets the global references to nodes, edges and nodeIndices back to - * those of the supplied frozen sector. - * - * @param sectorId - * @private - */ - _switchToFrozenSector : function(sectorId) { - this.nodeIndices = this.sectors["frozen"][sectorId]["nodeIndices"]; - this.nodes = this.sectors["frozen"][sectorId]["nodes"]; - this.edges = this.sectors["frozen"][sectorId]["edges"]; - }, - - - /** - * This function sets the global references to nodes, edges and nodeIndices to - * those of the navigation controls sector. - * - * @private - */ - _switchToNavigationSector : function() { - this.nodeIndices = this.sectors["navigation"]["nodeIndices"]; - this.nodes = this.sectors["navigation"]["nodes"]; - this.edges = this.sectors["navigation"]["edges"]; - }, - - - /** - * This function sets the global references to nodes, edges and nodeIndices back to - * those of the currently active sector. - * - * @private - */ - _loadLatestSector : function() { - this._switchToSector(this._sector()); - }, - - - /** - * This function returns the currently active sector Id - * - * @returns {String} - * @private - */ - _sector : function() { - return this.activeSector[this.activeSector.length-1]; - }, - - - /** - * This function returns the previously active sector Id - * - * @returns {String} - * @private - */ - _previousSector : function() { - if (this.activeSector.length > 1) { - return this.activeSector[this.activeSector.length-2]; - } - else { - throw new TypeError('there are not enough sectors in the this.activeSector array.'); - } - }, - - - /** - * We add the active sector at the end of the this.activeSector array - * This ensures it is the currently active sector returned by _sector() and it reaches the top - * of the activeSector stack. When we reverse our steps we move from the end to the beginning of this stack. - * - * @param newId - * @private - */ - _setActiveSector : function(newId) { - this.activeSector.push(newId); - }, - - - /** - * We remove the currently active sector id from the active sector stack. This happens when - * we reactivate the previously active sector - * - * @private - */ - _forgetLastSector : function() { - this.activeSector.pop(); - }, - - - /** - * This function creates a new active sector with the supplied newId. This newId - * is the expanding node id. - * - * @param {String} newId | Id of the new active sector - * @private - */ - _createNewSector : function(newId) { - // create the new sector - this.sectors["active"][newId] = {"nodes":{}, - "edges":{}, - "nodeIndices":[], - "formationScale": this.scale, - "drawingNode": undefined}; - - // create the new sector render node. This gives visual feedback that you are in a new sector. - this.sectors["active"][newId]['drawingNode'] = new Node( - {id:newId, - color: { - background: "#eaefef", - border: "495c5e" - } - },{},{},this.constants); - this.sectors["active"][newId]['drawingNode'].clusterSize = 2; - }, - - - /** - * This function removes the currently active sector. This is called when we create a new - * active sector. - * - * @param {String} sectorId | Id of the active sector that will be removed - * @private - */ - _deleteActiveSector : function(sectorId) { - delete this.sectors["active"][sectorId]; - }, - - - /** - * This function removes the currently active sector. This is called when we reactivate - * the previously active sector. - * - * @param {String} sectorId | Id of the active sector that will be removed - * @private - */ - _deleteFrozenSector : function(sectorId) { - delete this.sectors["frozen"][sectorId]; - }, - - - /** - * Freezing an active sector means moving it from the "active" object to the "frozen" object. - * We copy the references, then delete the active entree. - * - * @param sectorId - * @private - */ - _freezeSector : function(sectorId) { - // we move the set references from the active to the frozen stack. - this.sectors["frozen"][sectorId] = this.sectors["active"][sectorId]; - - // we have moved the sector data into the frozen set, we now remove it from the active set - this._deleteActiveSector(sectorId); - }, - - - /** - * This is the reverse operation of _freezeSector. Activating means moving the sector from the "frozen" - * object to the "active" object. - * - * @param sectorId - * @private - */ - _activateSector : function(sectorId) { - // we move the set references from the frozen to the active stack. - this.sectors["active"][sectorId] = this.sectors["frozen"][sectorId]; - - // we have moved the sector data into the active set, we now remove it from the frozen stack - this._deleteFrozenSector(sectorId); - }, - - - /** - * This function merges the data from the currently active sector with a frozen sector. This is used - * in the process of reverting back to the previously active sector. - * The data that is placed in the frozen (the previously active) sector is the node that has been removed from it - * upon the creation of a new active sector. - * - * @param sectorId - * @private - */ - _mergeThisWithFrozen : function(sectorId) { - // copy all nodes - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - this.sectors["frozen"][sectorId]["nodes"][nodeId] = this.nodes[nodeId]; - } - } - - // copy all edges (if not fully clustered, else there are no edges) - for (var edgeId in this.edges) { - if (this.edges.hasOwnProperty(edgeId)) { - this.sectors["frozen"][sectorId]["edges"][edgeId] = this.edges[edgeId]; - } - } - - // merge the nodeIndices - for (var i = 0; i < this.nodeIndices.length; i++) { - this.sectors["frozen"][sectorId]["nodeIndices"].push(this.nodeIndices[i]); - } - }, - - - /** - * This clusters the sector to one cluster. It was a single cluster before this process started so - * we revert to that state. The clusterToFit function with a maximum size of 1 node does this. - * - * @private - */ - _collapseThisToSingleCluster : function() { - this.clusterToFit(1,false); - }, - - - /** - * We create a new active sector from the node that we want to open. - * - * @param node - * @private - */ - _addSector : function(node) { - // this is the currently active sector - var sector = this._sector(); - -// // this should allow me to select nodes from a frozen set. -// if (this.sectors['active'][sector]["nodes"].hasOwnProperty(node.id)) { -// console.log("the node is part of the active sector"); -// } -// else { -// console.log("I dont know what the fuck happened!!"); -// } - - // when we switch to a new sector, we remove the node that will be expanded from the current nodes list. - delete this.nodes[node.id]; - - var unqiueIdentifier = util.randomUUID(); - - // we fully freeze the currently active sector - this._freezeSector(sector); - - // we create a new active sector. This sector has the Id of the node to ensure uniqueness - this._createNewSector(unqiueIdentifier); - - // we add the active sector to the sectors array to be able to revert these steps later on - this._setActiveSector(unqiueIdentifier); - - // we redirect the global references to the new sector's references. this._sector() now returns unqiueIdentifier - this._switchToSector(this._sector()); - - // finally we add the node we removed from our previous active sector to the new active sector - this.nodes[node.id] = node; - }, - - - /** - * We close the sector that is currently open and revert back to the one before. - * If the active sector is the "default" sector, nothing happens. - * - * @private - */ - _collapseSector : function() { - // the currently active sector - var sector = this._sector(); - - // we cannot collapse the default sector - if (sector != "default") { - if ((this.nodeIndices.length == 1) || - (this.sectors["active"][sector]["drawingNode"].width*this.scale < this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientWidth) || - (this.sectors["active"][sector]["drawingNode"].height*this.scale < this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientHeight)) { - var previousSector = this._previousSector(); - - // we collapse the sector back to a single cluster - this._collapseThisToSingleCluster(); - - // we move the remaining nodes, edges and nodeIndices to the previous sector. - // This previous sector is the one we will reactivate - this._mergeThisWithFrozen(previousSector); - - // the previously active (frozen) sector now has all the data from the currently active sector. - // we can now delete the active sector. - this._deleteActiveSector(sector); - - // we activate the previously active (and currently frozen) sector. - this._activateSector(previousSector); - - // we load the references from the newly active sector into the global references - this._switchToSector(previousSector); - - // we forget the previously active sector because we reverted to the one before - this._forgetLastSector(); - - // finally, we update the node index list. - this._updateNodeIndexList(); - } - } - }, - - - /** - * This runs a function in all active sectors. This is used in _redraw() and the _initializeForceCalculation(). - * - * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors - * | we dont pass the function itself because then the "this" is the window object - * | instead of the Graph object - * @param {*} [argument] | Optional: arguments to pass to the runFunction - * @private - */ - _doInAllActiveSectors : function(runFunction,argument) { - if (argument === undefined) { - for (var sector in this.sectors["active"]) { - if (this.sectors["active"].hasOwnProperty(sector)) { - // switch the global references to those of this sector - this._switchToActiveSector(sector); - this[runFunction](); - } - } - } - else { - for (var sector in this.sectors["active"]) { - if (this.sectors["active"].hasOwnProperty(sector)) { - // switch the global references to those of this sector - this._switchToActiveSector(sector); - var args = Array.prototype.splice.call(arguments, 1); - if (args.length > 1) { - this[runFunction](args[0],args[1]); - } - else { - this[runFunction](argument); - } - } - } - } - // we revert the global references back to our active sector - this._loadLatestSector(); - }, - - - /** - * This runs a function in all frozen sectors. This is used in the _redraw(). - * - * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors - * | we don't pass the function itself because then the "this" is the window object - * | instead of the Graph object - * @param {*} [argument] | Optional: arguments to pass to the runFunction - * @private - */ - _doInAllFrozenSectors : function(runFunction,argument) { - if (argument === undefined) { - for (var sector in this.sectors["frozen"]) { - if (this.sectors["frozen"].hasOwnProperty(sector)) { - // switch the global references to those of this sector - this._switchToFrozenSector(sector); - this[runFunction](); - } - } - } - else { - for (var sector in this.sectors["frozen"]) { - if (this.sectors["frozen"].hasOwnProperty(sector)) { - // switch the global references to those of this sector - this._switchToFrozenSector(sector); - var args = Array.prototype.splice.call(arguments, 1); - if (args.length > 1) { - this[runFunction](args[0],args[1]); - } - else { - this[runFunction](argument); - } - } - } - } - this._loadLatestSector(); - }, - - - /** - * This runs a function in the navigation controls sector. - * - * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors - * | we don't pass the function itself because then the "this" is the window object - * | instead of the Graph object - * @param {*} [argument] | Optional: arguments to pass to the runFunction - * @private - */ - _doInNavigationSector : function(runFunction,argument) { - this._switchToNavigationSector(); - if (argument === undefined) { - this[runFunction](); - } - else { - var args = Array.prototype.splice.call(arguments, 1); - if (args.length > 1) { - this[runFunction](args[0],args[1]); - } - else { - this[runFunction](argument); - } - } - this._loadLatestSector(); - }, - - - /** - * This runs a function in all sectors. This is used in the _redraw(). - * - * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors - * | we don't pass the function itself because then the "this" is the window object - * | instead of the Graph object - * @param {*} [argument] | Optional: arguments to pass to the runFunction - * @private - */ - _doInAllSectors : function(runFunction,argument) { - var args = Array.prototype.splice.call(arguments, 1); - if (argument === undefined) { - this._doInAllActiveSectors(runFunction); - this._doInAllFrozenSectors(runFunction); - } - else { - if (args.length > 1) { - this._doInAllActiveSectors(runFunction,args[0],args[1]); - this._doInAllFrozenSectors(runFunction,args[0],args[1]); - } - else { - this._doInAllActiveSectors(runFunction,argument); - this._doInAllFrozenSectors(runFunction,argument); - } - } - - }, - - - /** - * This clears the nodeIndices list. We cannot use this.nodeIndices = [] because we would break the link with the - * active sector. Thus we clear the nodeIndices in the active sector, then reconnect the this.nodeIndices to it. - * - * @private - */ - _clearNodeIndexList : function() { - var sector = this._sector(); - this.sectors["active"][sector]["nodeIndices"] = []; - this.nodeIndices = this.sectors["active"][sector]["nodeIndices"]; - }, - - - /** - * Draw the encompassing sector node - * - * @param ctx - * @param sectorType - * @private - */ - _drawSectorNodes : function(ctx,sectorType) { - var minY = 1e9, maxY = -1e9, minX = 1e9, maxX = -1e9, node; - for (var sector in this.sectors[sectorType]) { - if (this.sectors[sectorType].hasOwnProperty(sector)) { - if (this.sectors[sectorType][sector]["drawingNode"] !== undefined) { - - this._switchToSector(sector,sectorType); - - minY = 1e9; maxY = -1e9; minX = 1e9; maxX = -1e9; - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - node = this.nodes[nodeId]; - node.resize(ctx); - if (minX > node.x - 0.5 * node.width) {minX = node.x - 0.5 * node.width;} - if (maxX < node.x + 0.5 * node.width) {maxX = node.x + 0.5 * node.width;} - if (minY > node.y - 0.5 * node.height) {minY = node.y - 0.5 * node.height;} - if (maxY < node.y + 0.5 * node.height) {maxY = node.y + 0.5 * node.height;} - } - } - node = this.sectors[sectorType][sector]["drawingNode"]; - node.x = 0.5 * (maxX + minX); - node.y = 0.5 * (maxY + minY); - node.width = 2 * (node.x - minX); - node.height = 2 * (node.y - minY); - node.radius = Math.sqrt(Math.pow(0.5*node.width,2) + Math.pow(0.5*node.height,2)); - node.setScale(this.scale); - node._drawCircle(ctx); - } - } - } - }, - - _drawAllSectorNodes : function(ctx) { - this._drawSectorNodes(ctx,"frozen"); - this._drawSectorNodes(ctx,"active"); - this._loadLatestSector(); - } -}; -/** - * Creation of the ClusterMixin var. - * - * This contains all the functions the Graph object can use to employ clustering - * - * Alex de Mulder - * 21-01-2013 - */ -var ClusterMixin = { - -/** - * This is only called in the constructor of the graph object - * */ - startWithClustering : function() { - // cluster if the data set is big - this.clusterToFit(this.constants.clustering.initialMaxNodes, true); - - // updates the lables after clustering - this.updateLabels(); - - // this is called here because if clusterin is disabled, the start and stabilize are called in - // the setData function. - if (this.stabilize) { - this._doStabilize(); - } - this.start(); - }, - - /** - * This function clusters until the initialMaxNodes has been reached - * - * @param {Number} maxNumberOfNodes - * @param {Boolean} reposition - */ - clusterToFit : function(maxNumberOfNodes, reposition) { - var numberOfNodes = this.nodeIndices.length; - - var maxLevels = 50; - var level = 0; - - // we first cluster the hubs, then we pull in the outliers, repeat - while (numberOfNodes > maxNumberOfNodes && level < maxLevels) { - if (level % 3 == 0) { - this.forceAggregateHubs(); - } - else { - this.increaseClusterLevel(); - } - numberOfNodes = this.nodeIndices.length; - level += 1; - } - - // after the clustering we reposition the nodes to reduce the initial chaos - if (level > 1 && reposition == true) { - this.repositionNodes(); - } - }, - - /** - * This function can be called to open up a specific cluster. It is only called by - * It will unpack the cluster back one level. - * - * @param node | Node object: cluster to open. - */ - openCluster : function(node) { - var isMovingBeforeClustering = this.moving; - if (node.clusterSize > this.constants.clustering.sectorThreshold && this._nodeInActiveArea(node) && - !(this._sector() == "default" && this.nodeIndices.length == 1)) { - this._addSector(node); - var level = 0; - while ((this.nodeIndices.length < this.constants.clustering.initialMaxNodes) && (level < 10)) { - this.decreaseClusterLevel(); - level += 1; - } - } - else { - this._expandClusterNode(node,false,true); - - // update the index list, dynamic edges and labels - this._updateNodeIndexList(); - this._updateDynamicEdges(); - this.updateLabels(); - } - - // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded - if (this.moving != isMovingBeforeClustering) { - this.start(); - } - }, - - /** - * This calls the updateClustes with default arguments - */ - updateClustersDefault : function() { - if (this.constants.clustering.enabled == true) { - this.updateClusters(0,false,false); - } - }, - - /** - * This function can be called to increase the cluster level. This means that the nodes with only one edge connection will - * be clustered with their connected node. This can be repeated as many times as needed. - * This can be called externally (by a keybind for instance) to reduce the complexity of big datasets. - */ - increaseClusterLevel : function() { - this.updateClusters(-1,false,true); - }, - - - - /** - * This function can be called to decrease the cluster level. This means that the nodes with only one edge connection will - * be unpacked if they are a cluster. This can be repeated as many times as needed. - * This can be called externally (by a key-bind for instance) to look into clusters without zooming. - */ - decreaseClusterLevel : function() { - this.updateClusters(1,false,true); - }, - - - /** - * This is the main clustering function. It clusters and declusters on zoom or forced - * This function clusters on zoom, it can be called with a predefined zoom direction - * If out, check if we can form clusters, if in, check if we can open clusters. - * This function is only called from _zoom() - * - * @param {Number} zoomDirection | -1 / 0 / +1 for zoomOut / determineByZoom / zoomIn - * @param {Boolean} recursive | enabled or disable recursive calling of the opening of clusters - * @param {Boolean} force | enabled or disable forcing - * - */ - updateClusters : function(zoomDirection,recursive,force) { - var isMovingBeforeClustering = this.moving; - var amountOfNodes = this.nodeIndices.length; - - // on zoom out collapse the sector if the scale is at the level the sector was made - if (this.previousScale > this.scale && zoomDirection == 0) { - this._collapseSector(); - } - - // check if we zoom in or out - if (this.previousScale > this.scale || zoomDirection == -1) { // zoom out - // forming clusters when forced pulls outliers in. When not forced, the edge length of the - // outer nodes determines if it is being clustered - this._formClusters(force); - } - else if (this.previousScale < this.scale || zoomDirection == 1) { // zoom in - if (force == true) { - // _openClusters checks for each node if the formationScale of the cluster is smaller than - // the current scale and if so, declusters. When forced, all clusters are reduced by one step - this._openClusters(recursive,force); - } - else { - // if a cluster takes up a set percentage of the active window - this._openClustersBySize(); - } - } - this._updateNodeIndexList(); - - // if a cluster was NOT formed and the user zoomed out, we try clustering by hubs - if (this.nodeIndices.length == amountOfNodes && (this.previousScale > this.scale || zoomDirection == -1)) { - this._aggregateHubs(force); - this._updateNodeIndexList(); - } - - // we now reduce chains. - if (this.previousScale > this.scale || zoomDirection == -1) { // zoom out - this.handleChains(); - this._updateNodeIndexList(); - } - - this.previousScale = this.scale; - - // rest of the update the index list, dynamic edges and labels - this._updateDynamicEdges(); - this.updateLabels(); - - // if a cluster was formed, we increase the clusterSession - if (this.nodeIndices.length < amountOfNodes) { // this means a clustering operation has taken place - this.clusterSession += 1; - } - - // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded - if (this.moving != isMovingBeforeClustering) { - this.start(); - } - }, - - /** - * This function handles the chains. It is called on every updateClusters(). - */ - handleChains : function() { - // after clustering we check how many chains there are - var chainPercentage = this._getChainFraction(); - if (chainPercentage > this.constants.clustering.chainThreshold) { - this._reduceAmountOfChains(1 - this.constants.clustering.chainThreshold / chainPercentage) - - } - }, - - /** - * this functions starts clustering by hubs - * The minimum hub threshold is set globally - * - * @private - */ - _aggregateHubs : function(force) { - this._getHubSize(); - this._formClustersByHub(force,false); - }, - - - /** - * This function is fired by keypress. It forces hubs to form. - * - */ - forceAggregateHubs : function() { - var isMovingBeforeClustering = this.moving; - var amountOfNodes = this.nodeIndices.length; - - this._aggregateHubs(true); - - // update the index list, dynamic edges and labels - this._updateNodeIndexList(); - this._updateDynamicEdges(); - this.updateLabels(); - - // if a cluster was formed, we increase the clusterSession - if (this.nodeIndices.length != amountOfNodes) { - this.clusterSession += 1; - } - - // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded - if (this.moving != isMovingBeforeClustering) { - this.start(); - } - }, - - /** - * If a cluster takes up more than a set percentage of the screen, open the cluster - * - * @private - */ - _openClustersBySize : function() { - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - var node = this.nodes[nodeId]; - if (node.inView() == true) { - if ((node.width*this.scale > this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientWidth) || - (node.height*this.scale > this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientHeight)) { - this.openCluster(node); - } - } - } - } - }, - - - /** - * This function loops over all nodes in the nodeIndices list. For each node it checks if it is a cluster and if it - * has to be opened based on the current zoom level. - * - * @private - */ - _openClusters : function(recursive,force) { - for (var i = 0; i < this.nodeIndices.length; i++) { - var node = this.nodes[this.nodeIndices[i]]; - this._expandClusterNode(node,recursive,force); - } - }, - - /** - * This function checks if a node has to be opened. This is done by checking the zoom level. - * If the node contains child nodes, this function is recursively called on the child nodes as well. - * This recursive behaviour is optional and can be set by the recursive argument. - * - * @param {Node} parentNode | to check for cluster and expand - * @param {Boolean} recursive | enabled or disable recursive calling - * @param {Boolean} force | enabled or disable forcing - * @param {Boolean} [openAll] | This will recursively force all nodes in the parent to be released - * @private - */ - _expandClusterNode : function(parentNode, recursive, force, openAll) { - // first check if node is a cluster - if (parentNode.clusterSize > 1) { - // this means that on a double tap event or a zoom event, the cluster fully unpacks if it is smaller than 20 - if (parentNode.clusterSize < this.constants.clustering.sectorThreshold) { - openAll = true; - } - recursive = openAll ? true : recursive; - - // if the last child has been added on a smaller scale than current scale decluster - if (parentNode.formationScale < this.scale || force == true) { - // we will check if any of the contained child nodes should be removed from the cluster - for (var containedNodeId in parentNode.containedNodes) { - if (parentNode.containedNodes.hasOwnProperty(containedNodeId)) { - var childNode = parentNode.containedNodes[containedNodeId]; - - // force expand will expand the largest cluster size clusters. Since we cluster from outside in, we assume that - // the largest cluster is the one that comes from outside - if (force == true) { - if (childNode.clusterSession == parentNode.clusterSessions[parentNode.clusterSessions.length-1] - || openAll) { - this._expelChildFromParent(parentNode,containedNodeId,recursive,force,openAll); - } - } - else { - if (this._nodeInActiveArea(parentNode)) { - this._expelChildFromParent(parentNode,containedNodeId,recursive,force,openAll); - } - } - } - } - } - } - - }, - - /** - * ONLY CALLED FROM _expandClusterNode - * - * This function will expel a child_node from a parent_node. This is to de-cluster the node. This function will remove - * the child node from the parent contained_node object and put it back into the global nodes object. - * The same holds for the edge that was connected to the child node. It is moved back into the global edges object. - * - * @param {Node} parentNode | the parent node - * @param {String} containedNodeId | child_node id as it is contained in the containedNodes object of the parent node - * @param {Boolean} recursive | This will also check if the child needs to be expanded. - * With force and recursive both true, the entire cluster is unpacked - * @param {Boolean} force | This will disregard the zoom level and will expel this child from the parent - * @param {Boolean} openAll | This will recursively force all nodes in the parent to be released - * @private - */ - _expelChildFromParent : function(parentNode, containedNodeId, recursive, force, openAll) { - var childNode = parentNode.containedNodes[containedNodeId]; - - // if child node has been added on smaller scale than current, kick out - if (childNode.formationScale < this.scale || force == true) { - // remove the selection, first remove the selection from the connected edges - this._unselectConnectedEdges(parentNode); - parentNode.unselect(); - - // put the child node back in the global nodes object - this.nodes[containedNodeId] = childNode; - - // release the contained edges from this childNode back into the global edges - this._releaseContainedEdges(parentNode,childNode); - - // reconnect rerouted edges to the childNode - this._connectEdgeBackToChild(parentNode,childNode); - - // validate all edges in dynamicEdges - this._validateEdges(parentNode); - - // undo the changes from the clustering operation on the parent node - parentNode.mass -= this.constants.clustering.massTransferCoefficient * childNode.mass; - parentNode.fontSize -= this.constants.clustering.fontSizeMultiplier * childNode.clusterSize; - parentNode.clusterSize -= childNode.clusterSize; - parentNode.dynamicEdgesLength = parentNode.dynamicEdges.length; - - // place the child node near the parent, not at the exact same location to avoid chaos in the system - childNode.x = parentNode.x + this.constants.physics.springLength * (0.1 * (0.5 - Math.random()) * parentNode.clusterSize); - childNode.y = parentNode.y + this.constants.physics.springLength * (0.1 * (0.5 - Math.random()) * parentNode.clusterSize); - console.log(childNode.x,childNode.y,parentNode.x,parentNode.y); - // remove node from the list - delete parentNode.containedNodes[containedNodeId]; - - // check if there are other childs with this clusterSession in the parent. - var othersPresent = false; - for (var childNodeId in parentNode.containedNodes) { - if (parentNode.containedNodes.hasOwnProperty(childNodeId)) { - if (parentNode.containedNodes[childNodeId].clusterSession == childNode.clusterSession) { - othersPresent = true; - break; - } - } - } - // if there are no others, remove the cluster session from the list - if (othersPresent == false) { - parentNode.clusterSessions.pop(); - } - - // remove the clusterSession from the child node - childNode.clusterSession = 0; - - // restart the simulation to reorganise all nodes - this.moving = true; - - // recalculate the size of the node on the next time the node is rendered - parentNode.clearSizeCache(); - - // this unselects the rest of the edges - this._unselectConnectedEdges(parentNode); - } - - // check if a further expansion step is possible if recursivity is enabled - if (recursive == true) { - this._expandClusterNode(childNode,recursive,force,openAll); - } - }, - - - /** - * This function checks if any nodes at the end of their trees have edges below a threshold length - * This function is called only from updateClusters() - * forceLevelCollapse ignores the length of the edge and collapses one level - * This means that a node with only one edge will be clustered with its connected node - * - * @private - * @param {Boolean} force - */ - _formClusters : function(force) { - if (force == false) { - this._formClustersByZoom(); - } - else { - this._forceClustersByZoom(); - } - }, - - /** - * This function handles the clustering by zooming out, this is based on a minimum edge distance - * - * @private - */ - _formClustersByZoom : function() { - var dx,dy,length, - minLength = this.constants.clustering.clusterEdgeThreshold/this.scale; - - // check if any edges are shorter than minLength and start the clustering - // the clustering favours the node with the larger mass - for (var edgeId in this.edges) { - if (this.edges.hasOwnProperty(edgeId)) { - var edge = this.edges[edgeId]; - if (edge.connected) { - if (edge.toId != edge.fromId) { - dx = (edge.to.x - edge.from.x); - dy = (edge.to.y - edge.from.y); - length = Math.sqrt(dx * dx + dy * dy); - - - if (length < minLength) { - // first check which node is larger - var parentNode = edge.from; - var childNode = edge.to; - if (edge.to.mass > edge.from.mass) { - parentNode = edge.to; - childNode = edge.from; - } - - if (childNode.dynamicEdgesLength == 1) { - this._addToCluster(parentNode,childNode,false); - } - else if (parentNode.dynamicEdgesLength == 1) { - this._addToCluster(childNode,parentNode,false); - } - } - } - } - } - } - }, - - /** - * This function forces the graph to cluster all nodes with only one connecting edge to their - * connected node. - * - * @private - */ - _forceClustersByZoom : function() { - for (var nodeId in this.nodes) { - // another node could have absorbed this child. - if (this.nodes.hasOwnProperty(nodeId)) { - var childNode = this.nodes[nodeId]; - - // the edges can be swallowed by another decrease - if (childNode.dynamicEdgesLength == 1 && childNode.dynamicEdges.length != 0) { - var edge = childNode.dynamicEdges[0]; - var parentNode = (edge.toId == childNode.id) ? this.nodes[edge.fromId] : this.nodes[edge.toId]; - - // group to the largest node - if (childNode.id != parentNode.id) { - if (parentNode.mass > childNode.mass) { - this._addToCluster(parentNode,childNode,true); - } - else { - this._addToCluster(childNode,parentNode,true); - } - } - } - } - } - }, - - - - /** - * This function forms clusters from hubs, it loops over all nodes - * - * @param {Boolean} force | Disregard zoom level - * @param {Boolean} onlyEqual | This only clusters a hub with a specific number of edges - * @private - */ - _formClustersByHub : function(force, onlyEqual) { - // we loop over all nodes in the list - for (var nodeId in this.nodes) { - // we check if it is still available since it can be used by the clustering in this loop - if (this.nodes.hasOwnProperty(nodeId)) { - this._formClusterFromHub(this.nodes[nodeId],force,onlyEqual); - } - } - }, - - /** - * This function forms a cluster from a specific preselected hub node - * - * @param {Node} hubNode | the node we will cluster as a hub - * @param {Boolean} force | Disregard zoom level - * @param {Boolean} onlyEqual | This only clusters a hub with a specific number of edges - * @param {Number} [absorptionSizeOffset] | - * @private - */ - _formClusterFromHub : function(hubNode, force, onlyEqual, absorptionSizeOffset) { - if (absorptionSizeOffset === undefined) { - absorptionSizeOffset = 0; - } - // we decide if the node is a hub - if ((hubNode.dynamicEdgesLength >= this.hubThreshold && onlyEqual == false) || - (hubNode.dynamicEdgesLength == this.hubThreshold && onlyEqual == true)) { - // initialize variables - var dx,dy,length; - var minLength = this.constants.clustering.clusterEdgeThreshold/this.scale; - var allowCluster = false; - - // we create a list of edges because the dynamicEdges change over the course of this loop - var edgesIdarray = []; - var amountOfInitialEdges = hubNode.dynamicEdges.length; - for (var j = 0; j < amountOfInitialEdges; j++) { - edgesIdarray.push(hubNode.dynamicEdges[j].id); - } - - // if the hub clustering is not forces, we check if one of the edges connected - // to a cluster is small enough based on the constants.clustering.clusterEdgeThreshold - if (force == false) { - allowCluster = false; - for (j = 0; j < amountOfInitialEdges; j++) { - var edge = this.edges[edgesIdarray[j]]; - if (edge !== undefined) { - if (edge.connected) { - if (edge.toId != edge.fromId) { - dx = (edge.to.x - edge.from.x); - dy = (edge.to.y - edge.from.y); - length = Math.sqrt(dx * dx + dy * dy); - - if (length < minLength) { - allowCluster = true; - break; - } - } - } - } - } - } - - // start the clustering if allowed - if ((!force && allowCluster) || force) { - // we loop over all edges INITIALLY connected to this hub - for (j = 0; j < amountOfInitialEdges; j++) { - edge = this.edges[edgesIdarray[j]]; - // the edge can be clustered by this function in a previous loop - if (edge !== undefined) { - var childNode = this.nodes[(edge.fromId == hubNode.id) ? edge.toId : edge.fromId]; - // we do not want hubs to merge with other hubs nor do we want to cluster itself. - if ((childNode.dynamicEdges.length <= (this.hubThreshold + absorptionSizeOffset)) && - (childNode.id != hubNode.id)) { - this._addToCluster(hubNode,childNode,force); - } - } - } - } - } - }, - - - - /** - * This function adds the child node to the parent node, creating a cluster if it is not already. - * - * @param {Node} parentNode | this is the node that will house the child node - * @param {Node} childNode | this node will be deleted from the global this.nodes and stored in the parent node - * @param {Boolean} force | true will only update the remainingEdges at the very end of the clustering, ensuring single level collapse - * @private - */ - _addToCluster : function(parentNode, childNode, force) { - // join child node in the parent node - parentNode.containedNodes[childNode.id] = childNode; - - // manage all the edges connected to the child and parent nodes - for (var i = 0; i < childNode.dynamicEdges.length; i++) { - var edge = childNode.dynamicEdges[i]; - if (edge.toId == parentNode.id || edge.fromId == parentNode.id) { // edge connected to parentNode - this._addToContainedEdges(parentNode,childNode,edge); - } - else { - this._connectEdgeToCluster(parentNode,childNode,edge); - } - } - // a contained node has no dynamic edges. - childNode.dynamicEdges = []; - - // remove circular edges from clusters - this._containCircularEdgesFromNode(parentNode,childNode); - - - // remove the childNode from the global nodes object - delete this.nodes[childNode.id]; - - // update the properties of the child and parent - var massBefore = parentNode.mass; - childNode.clusterSession = this.clusterSession; - parentNode.mass += childNode.mass; - parentNode.clusterSize += childNode.clusterSize; - parentNode.fontSize += this.constants.clustering.fontSizeMultiplier * childNode.clusterSize; - - // keep track of the clustersessions so we can open the cluster up as it has been formed. - if (parentNode.clusterSessions[parentNode.clusterSessions.length - 1] != this.clusterSession) { - parentNode.clusterSessions.push(this.clusterSession); - } - - // forced clusters only open from screen size and double tap - if (force == true) { - // parentNode.formationScale = Math.pow(1 - (1.0/11.0),this.clusterSession+3); - parentNode.formationScale = 0; - } - else { - parentNode.formationScale = this.scale; // The latest child has been added on this scale - } - - // recalculate the size of the node on the next time the node is rendered - parentNode.clearSizeCache(); - - // set the pop-out scale for the childnode - parentNode.containedNodes[childNode.id].formationScale = parentNode.formationScale; - - // nullify the movement velocity of the child, this is to avoid hectic behaviour - childNode.clearVelocity(); - - // the mass has altered, preservation of energy dictates the velocity to be updated - parentNode.updateVelocity(massBefore); - - // restart the simulation to reorganise all nodes - this.moving = true; - }, - - - /** - * This function will apply the changes made to the remainingEdges during the formation of the clusters. - * This is a seperate function to allow for level-wise collapsing of the node barnesHutTree. - * It has to be called if a level is collapsed. It is called by _formClusters(). - * @private - */ - _updateDynamicEdges : function() { - for (var i = 0; i < this.nodeIndices.length; i++) { - var node = this.nodes[this.nodeIndices[i]]; - node.dynamicEdgesLength = node.dynamicEdges.length; - - // this corrects for multiple edges pointing at the same other node - var correction = 0; - if (node.dynamicEdgesLength > 1) { - for (var j = 0; j < node.dynamicEdgesLength - 1; j++) { - var edgeToId = node.dynamicEdges[j].toId; - var edgeFromId = node.dynamicEdges[j].fromId; - for (var k = j+1; k < node.dynamicEdgesLength; k++) { - if ((node.dynamicEdges[k].toId == edgeToId && node.dynamicEdges[k].fromId == edgeFromId) || - (node.dynamicEdges[k].fromId == edgeToId && node.dynamicEdges[k].toId == edgeFromId)) { - correction += 1; - } - } - } - } - node.dynamicEdgesLength -= correction; - } - }, - - - /** - * This adds an edge from the childNode to the contained edges of the parent node - * - * @param parentNode | Node object - * @param childNode | Node object - * @param edge | Edge object - * @private - */ - _addToContainedEdges : function(parentNode, childNode, edge) { - // create an array object if it does not yet exist for this childNode - if (!(parentNode.containedEdges.hasOwnProperty(childNode.id))) { - parentNode.containedEdges[childNode.id] = [] - } - // add this edge to the list - parentNode.containedEdges[childNode.id].push(edge); - - // remove the edge from the global edges object - delete this.edges[edge.id]; - - // remove the edge from the parent object - for (var i = 0; i < parentNode.dynamicEdges.length; i++) { - if (parentNode.dynamicEdges[i].id == edge.id) { - parentNode.dynamicEdges.splice(i,1); - break; - } - } - }, - - /** - * This function connects an edge that was connected to a child node to the parent node. - * It keeps track of which nodes it has been connected to with the originalId array. - * - * @param {Node} parentNode | Node object - * @param {Node} childNode | Node object - * @param {Edge} edge | Edge object - * @private - */ - _connectEdgeToCluster : function(parentNode, childNode, edge) { - // handle circular edges - if (edge.toId == edge.fromId) { - this._addToContainedEdges(parentNode, childNode, edge); - } - else { - if (edge.toId == childNode.id) { // edge connected to other node on the "to" side - edge.originalToId.push(childNode.id); - edge.to = parentNode; - edge.toId = parentNode.id; - } - else { // edge connected to other node with the "from" side - - edge.originalFromId.push(childNode.id); - edge.from = parentNode; - edge.fromId = parentNode.id; - } - - this._addToReroutedEdges(parentNode,childNode,edge); - } - }, - - - _containCircularEdgesFromNode : function(parentNode, childNode) { - // manage all the edges connected to the child and parent nodes - for (var i = 0; i < parentNode.dynamicEdges.length; i++) { - var edge = parentNode.dynamicEdges[i]; - // handle circular edges - if (edge.toId == edge.fromId) { - this._addToContainedEdges(parentNode, childNode, edge); - } - } - }, - - - /** - * This adds an edge from the childNode to the rerouted edges of the parent node - * - * @param parentNode | Node object - * @param childNode | Node object - * @param edge | Edge object - * @private - */ - _addToReroutedEdges : function(parentNode, childNode, edge) { - // create an array object if it does not yet exist for this childNode - // we store the edge in the rerouted edges so we can restore it when the cluster pops open - if (!(parentNode.reroutedEdges.hasOwnProperty(childNode.id))) { - parentNode.reroutedEdges[childNode.id] = []; - } - parentNode.reroutedEdges[childNode.id].push(edge); - - // this edge becomes part of the dynamicEdges of the cluster node - parentNode.dynamicEdges.push(edge); - }, - - - - /** - * This function connects an edge that was connected to a cluster node back to the child node. - * - * @param parentNode | Node object - * @param childNode | Node object - * @private - */ - _connectEdgeBackToChild : function(parentNode, childNode) { - if (parentNode.reroutedEdges.hasOwnProperty(childNode.id)) { - for (var i = 0; i < parentNode.reroutedEdges[childNode.id].length; i++) { - var edge = parentNode.reroutedEdges[childNode.id][i]; - if (edge.originalFromId[edge.originalFromId.length-1] == childNode.id) { - edge.originalFromId.pop(); - edge.fromId = childNode.id; - edge.from = childNode; - } - else { - edge.originalToId.pop(); - edge.toId = childNode.id; - edge.to = childNode; - } - - // append this edge to the list of edges connecting to the childnode - childNode.dynamicEdges.push(edge); - - // remove the edge from the parent object - for (var j = 0; j < parentNode.dynamicEdges.length; j++) { - if (parentNode.dynamicEdges[j].id == edge.id) { - parentNode.dynamicEdges.splice(j,1); - break; - } - } - } - // remove the entry from the rerouted edges - delete parentNode.reroutedEdges[childNode.id]; - } - }, - - - /** - * When loops are clustered, an edge can be both in the rerouted array and the contained array. - * This function is called last to verify that all edges in dynamicEdges are in fact connected to the - * parentNode - * - * @param parentNode | Node object - * @private - */ - _validateEdges : function(parentNode) { - for (var i = 0; i < parentNode.dynamicEdges.length; i++) { - var edge = parentNode.dynamicEdges[i]; - if (parentNode.id != edge.toId && parentNode.id != edge.fromId) { - parentNode.dynamicEdges.splice(i,1); - } - } - }, - - - /** - * This function released the contained edges back into the global domain and puts them back into the - * dynamic edges of both parent and child. - * - * @param {Node} parentNode | - * @param {Node} childNode | - * @private - */ - _releaseContainedEdges : function(parentNode, childNode) { - for (var i = 0; i < parentNode.containedEdges[childNode.id].length; i++) { - var edge = parentNode.containedEdges[childNode.id][i]; - - // put the edge back in the global edges object - this.edges[edge.id] = edge; - - // put the edge back in the dynamic edges of the child and parent - childNode.dynamicEdges.push(edge); - parentNode.dynamicEdges.push(edge); - } - // remove the entry from the contained edges - delete parentNode.containedEdges[childNode.id]; - - }, - - - - - // ------------------- UTILITY FUNCTIONS ---------------------------- // - - - /** - * This updates the node labels for all nodes (for debugging purposes) - */ - updateLabels : function() { - var nodeId; - // update node labels - for (nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - var node = this.nodes[nodeId]; - if (node.clusterSize > 1) { - node.label = "[".concat(String(node.clusterSize),"]"); - } - } - } - - // update node labels - for (nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - node = this.nodes[nodeId]; - if (node.clusterSize == 1) { - if (node.originalLabel !== undefined) { - node.label = node.originalLabel; - } - else { - node.label = String(node.id); - } - } - } - } - - /* Debug Override */ - // for (nodeId in this.nodes) { - // if (this.nodes.hasOwnProperty(nodeId)) { - // node = this.nodes[nodeId]; - // node.label = String(Math.round(node.width)).concat(":",Math.round(node.width*this.scale)); - // } - // } - - }, - - - /** - * This function determines if the cluster we want to decluster is in the active area - * this means around the zoom center - * - * @param {Node} node - * @returns {boolean} - * @private - */ - _nodeInActiveArea : function(node) { - return ( - Math.abs(node.x - this.areaCenter.x) <= this.constants.clustering.activeAreaBoxSize/this.scale - && - Math.abs(node.y - this.areaCenter.y) <= this.constants.clustering.activeAreaBoxSize/this.scale - ) - }, - - - /** - * This is an adaptation of the original repositioning function. This is called if the system is clustered initially - * It puts large clusters away from the center and randomizes the order. - * - */ - repositionNodes : function() { - for (var i = 0; i < this.nodeIndices.length; i++) { - var node = this.nodes[this.nodeIndices[i]]; - if (!node.isFixed()) { - var radius = this.constants.physics.springLength * (1 + 0.6*node.clusterSize); - var angle = 2 * Math.PI * Math.random(); - node.x = radius * Math.cos(angle); - node.y = radius * Math.sin(angle); - } - } - }, - - - - - - /** - * We determine how many connections denote an important hub. - * We take the mean + 2*std as the important hub size. (Assuming a normal distribution of data, ~2.2%) - * - * @private - */ - _getHubSize : function() { - var average = 0; - var averageSquared = 0; - var hubCounter = 0; - var largestHub = 0; - - for (var i = 0; i < this.nodeIndices.length; i++) { - var node = this.nodes[this.nodeIndices[i]]; - if (node.dynamicEdgesLength > largestHub) { - largestHub = node.dynamicEdgesLength; - } - average += node.dynamicEdgesLength; - averageSquared += Math.pow(node.dynamicEdgesLength,2); - hubCounter += 1; - } - average = average / hubCounter; - averageSquared = averageSquared / hubCounter; - - var variance = averageSquared - Math.pow(average,2); - - var standardDeviation = Math.sqrt(variance); - - this.hubThreshold = Math.floor(average + 2*standardDeviation); - - // always have at least one to cluster - if (this.hubThreshold > largestHub) { - this.hubThreshold = largestHub; - } - - // console.log("average",average,"averageSQ",averageSquared,"var",variance,"std",standardDeviation); - // console.log("hubThreshold:",this.hubThreshold); - }, - - - /** - * We reduce the amount of "extension nodes" or chains. These are not quickly clustered with the outliers and hubs methods - * with this amount we can cluster specifically on these chains. - * - * @param {Number} fraction | between 0 and 1, the percentage of chains to reduce - * @private - */ - _reduceAmountOfChains : function(fraction) { - this.hubThreshold = 2; - var reduceAmount = Math.floor(this.nodeIndices.length * fraction); - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - if (this.nodes[nodeId].dynamicEdgesLength == 2 && this.nodes[nodeId].dynamicEdges.length >= 2) { - if (reduceAmount > 0) { - this._formClusterFromHub(this.nodes[nodeId],true,true,1); - reduceAmount -= 1; - } - } - } - } - }, - - /** - * We get the amount of "extension nodes" or chains. These are not quickly clustered with the outliers and hubs methods - * with this amount we can cluster specifically on these chains. - * - * @private - */ - _getChainFraction : function() { - var chains = 0; - var total = 0; - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - if (this.nodes[nodeId].dynamicEdgesLength == 2 && this.nodes[nodeId].dynamicEdges.length >= 2) { - chains += 1; - } - total += 1; - } - } - return chains/total; - } -}; - - -var SelectionMixin = { - - /** - * This function can be called from the _doInAllSectors function - * - * @param object - * @param overlappingNodes - * @private - */ - _getNodesOverlappingWith : function(object, overlappingNodes) { - var nodes = this.nodes; - for (var nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - if (nodes[nodeId].isOverlappingWith(object)) { - overlappingNodes.push(nodeId); - } - } - } - }, - - /** - * retrieve all nodes overlapping with given object - * @param {Object} object An object with parameters left, top, right, bottom - * @return {Number[]} An array with id's of the overlapping nodes - * @private - */ - _getAllNodesOverlappingWith : function (object) { - var overlappingNodes = []; - this._doInAllActiveSectors("_getNodesOverlappingWith",object,overlappingNodes); - return overlappingNodes; - }, - - - /** - * retrieve all nodes in the navigation controls overlapping with given object - * @param {Object} object An object with parameters left, top, right, bottom - * @return {Number[]} An array with id's of the overlapping nodes - * @private - */ - _getAllNavigationNodesOverlappingWith : function (object) { - var overlappingNodes = []; - this._doInNavigationSector("_getNodesOverlappingWith",object,overlappingNodes); - return overlappingNodes; - }, - - /** - * Return a position object in canvasspace from a single point in screenspace - * - * @param pointer - * @returns {{left: number, top: number, right: number, bottom: number}} - * @private - */ - _pointerToPositionObject : function(pointer) { - var x = this._canvasToX(pointer.x); - var y = this._canvasToY(pointer.y); - - return {left: x, - top: y, - right: x, - bottom: y}; - }, - - /** - * Return a position object in canvasspace from a single point in screenspace - * - * @param pointer - * @returns {{left: number, top: number, right: number, bottom: number}} - * @private - */ - _pointerToScreenPositionObject : function(pointer) { - var x = pointer.x; - var y = pointer.y; - - return {left: x, - top: y, - right: x, - bottom: y}; - }, - - - /** - * Get the top navigation controls node at the a specific point (like a click) - * - * @param {{x: Number, y: Number}} pointer - * @return {Node | null} node - * @private - */ - _getNavigationNodeAt : function (pointer) { - var screenPositionObject = this._pointerToScreenPositionObject(pointer); - var overlappingNodes = this._getAllNavigationNodesOverlappingWith(screenPositionObject); - if (overlappingNodes.length > 0) { - return this.sectors["navigation"]["nodes"][overlappingNodes[overlappingNodes.length - 1]]; - } - else { - return null; - } - }, - - - /** - * Get the top node at the a specific point (like a click) - * - * @param {{x: Number, y: Number}} pointer - * @return {Node | null} node - * @private - */ - _getNodeAt : function (pointer) { - // we first check if this is an navigation controls element - var positionObject = this._pointerToPositionObject(pointer); - var overlappingNodes = this._getAllNodesOverlappingWith(positionObject); - - // if there are overlapping nodes, select the last one, this is the - // one which is drawn on top of the others - if (overlappingNodes.length > 0) { - return this.nodes[overlappingNodes[overlappingNodes.length - 1]]; - } - else { - return null; - } - }, - - - /** - * retrieve all edges overlapping with given object, selector is around center - * @param {Object} object An object with parameters left, top, right, bottom - * @return {Number[]} An array with id's of the overlapping nodes - * @private - */ - _getEdgesOverlappingWith : function (object, overlappingEdges) { - var edges = this.edges; - for (var edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - if (edges[edgeId].isOverlappingWith(object)) { - overlappingEdges.push(edgeId); - } - } - } - }, - - - /** - * retrieve all nodes overlapping with given object - * @param {Object} object An object with parameters left, top, right, bottom - * @return {Number[]} An array with id's of the overlapping nodes - * @private - */ - _getAllEdgesOverlappingWith : function (object) { - var overlappingEdges = []; - this._doInAllActiveSectors("_getEdgesOverlappingWith",object,overlappingEdges); - return overlappingEdges; - }, - - /** - * Place holder. To implement change the _getNodeAt to a _getObjectAt. Have the _getObjectAt call - * _getNodeAt and _getEdgesAt, then priortize the selection to user preferences. - * - * @param pointer - * @returns {null} - * @private - */ - _getEdgeAt : function(pointer) { - var positionObject = this._pointerToPositionObject(pointer); - var overlappingEdges = this._getAllEdgesOverlappingWith(positionObject); - - if (overlappingEdges.length > 0) { - return this.edges[overlappingEdges[overlappingEdges.length - 1]]; - } - else { - return null; - } - }, - - - /** - * Add object to the selection array. - * - * @param obj - * @private - */ - _addToSelection : function(obj) { - this.selectionObj[obj.id] = obj; - }, - - - /** - * Remove a single option from selection. - * - * @param {Object} obj - * @private - */ - _removeFromSelection : function(obj) { - delete this.selectionObj[obj.id]; - }, - - - /** - * Unselect all. The selectionObj is useful for this. - * - * @param {Boolean} [doNotTrigger] | ignore trigger - * @private - */ - _unselectAll : function(doNotTrigger) { - if (doNotTrigger === undefined) { - doNotTrigger = false; - } - - for (var objectId in this.selectionObj) { - if (this.selectionObj.hasOwnProperty(objectId)) { - this.selectionObj[objectId].unselect(); - } - } - this.selectionObj = {}; - - if (doNotTrigger == false) { - this._trigger('select', this.getSelection()); - } - }, - - /** - * Unselect all clusters. The selectionObj is useful for this. - * - * @param {Boolean} [doNotTrigger] | ignore trigger - * @private - */ - _unselectClusters : function(doNotTrigger) { - if (doNotTrigger === undefined) { - doNotTrigger = false; - } - - for (var objectId in this.selectionObj) { - if (this.selectionObj.hasOwnProperty(objectId)) { - if (this.selectionObj[objectId] instanceof Node) { - if (this.selectionObj[objectId].clusterSize > 1) { - this.selectionObj[objectId].unselect(); - this._removeFromSelection(this.selectionObj[objectId]); - } - } - } - } - - if (doNotTrigger == false) { - this._trigger('select', this.getSelection()); - } - }, - - - /** - * return the number of selected nodes - * - * @returns {number} - * @private - */ - _getSelectedNodeCount : function() { - var count = 0; - for (var objectId in this.selectionObj) { - if (this.selectionObj.hasOwnProperty(objectId)) { - if (this.selectionObj[objectId] instanceof Node) { - count += 1; - } - } - } - return count; - }, - - - /** - * return the number of selected edges - * - * @returns {number} - * @private - */ - _getSelectedEdgeCount : function() { - var count = 0; - for (var objectId in this.selectionObj) { - if (this.selectionObj.hasOwnProperty(objectId)) { - if (this.selectionObj[objectId] instanceof Edge) { - count += 1; - } - } - } - return count; - }, - - - /** - * return the number of selected objects. - * - * @returns {number} - * @private - */ - _getSelectedObjectCount : function() { - var count = 0; - for (var objectId in this.selectionObj) { - if (this.selectionObj.hasOwnProperty(objectId)) { - count += 1; - } - } - return count; - }, - - /** - * Check if anything is selected - * - * @returns {boolean} - * @private - */ - _selectionIsEmpty : function() { - for(var objectId in this.selectionObj) { - if(this.selectionObj.hasOwnProperty(objectId)) { - return false; - } - } - return true; - }, - - - /** - * check if one of the selected nodes is a cluster. - * - * @returns {boolean} - * @private - */ - _clusterInSelection : function() { - for(var objectId in this.selectionObj) { - if(this.selectionObj.hasOwnProperty(objectId)) { - if (this.selectionObj[objectId] instanceof Node) { - if (this.selectionObj[objectId].clusterSize > 1) { - return true; - } - } - } - } - return false; - }, - - /** - * select the edges connected to the node that is being selected - * - * @param {Node} node - * @private - */ - _selectConnectedEdges : function(node) { - for (var i = 0; i < node.dynamicEdges.length; i++) { - var edge = node.dynamicEdges[i]; - edge.select(); - this._addToSelection(edge); - } - }, - - - /** - * unselect the edges connected to the node that is being selected - * - * @param {Node} node - * @private - */ - _unselectConnectedEdges : function(node) { - for (var i = 0; i < node.dynamicEdges.length; i++) { - var edge = node.dynamicEdges[i]; - edge.unselect(); - this._removeFromSelection(edge); - } - }, - - - - /** - * This is called when someone clicks on a node. either select or deselect it. - * If there is an existing selection and we don't want to append to it, clear the existing selection - * - * @param {Node || Edge} object - * @param {Boolean} append - * @param {Boolean} [doNotTrigger] | ignore trigger - * @private - */ - _selectObject : function(object, append, doNotTrigger) { - if (doNotTrigger === undefined) { - doNotTrigger = false; - } - - if (this._selectionIsEmpty() == false && append == false && this.forceAppendSelection == false) { - this._unselectAll(true); - } - - if (object.selected == false) { - object.select(); - this._addToSelection(object); - if (object instanceof Node && this.blockConnectingEdgeSelection == false) { - this._selectConnectedEdges(object); - } - } - else { - object.unselect(); - this._removeFromSelection(object); - } - if (doNotTrigger == false) { - this._trigger('select', this.getSelection()); - } - }, - - - /** - * handles the selection part of the touch, only for navigation controls elements; - * Touch is triggered before tap, also before hold. Hold triggers after a while. - * This is the most responsive solution - * - * @param {Object} pointer - * @private - */ - _handleTouch : function(pointer) { - if (this.constants.navigation.enabled == true) { - this.pointerPosition = pointer; - var node = this._getNavigationNodeAt(pointer); - if (node != null) { - if (this[node.triggerFunction] !== undefined) { - this[node.triggerFunction](); - } - } - } - }, - - - /** - * handles the selection part of the tap; - * - * @param {Object} pointer - * @private - */ - _handleTap : function(pointer) { - var node = this._getNodeAt(pointer); - if (node != null) { - this._selectObject(node,false); - } - else { - var edge = this._getEdgeAt(pointer); - if (edge != null) { - this._selectObject(edge,false); - } - else { - this._unselectAll(); - } - } - this._redraw(); - }, - - - /** - * handles the selection part of the double tap and opens a cluster if needed - * - * @param {Object} pointer - * @private - */ - _handleDoubleTap : function(pointer) { - var node = this._getNodeAt(pointer); - if (node != null && node !== undefined) { - // we reset the areaCenter here so the opening of the node will occur - this.areaCenter = {"x" : this._canvasToX(pointer.x), - "y" : this._canvasToY(pointer.y)}; - this.openCluster(node); - } - }, - - - /** - * Handle the onHold selection part - * - * @param pointer - * @private - */ - _handleOnHold : function(pointer) { - var node = this._getNodeAt(pointer); - if (node != null) { - this._selectObject(node,true); - } - else { - var edge = this._getEdgeAt(pointer); - if (edge != null) { - this._selectObject(edge,true); - } - } - this._redraw(); - }, - - - /** - * handle the onRelease event. These functions are here for the navigation controls module. - * - * @private - */ - _handleOnRelease : function() { - this.xIncrement = 0; - this.yIncrement = 0; - this.zoomIncrement = 0; - this._unHighlightAll(); - }, - - - - /** - * - * retrieve the currently selected objects - * @return {Number[] | String[]} selection An array with the ids of the - * selected nodes. - */ - getSelection : function() { - var nodeIds = this.getSelectedNodes(); - var edgeIds = this.getSelectedEdges(); - return {nodes:nodeIds, edges:edgeIds}; - }, - - /** - * - * retrieve the currently selected nodes - * @return {String} selection An array with the ids of the - * selected nodes. - */ - getSelectedNodes : function() { - var idArray = []; - for(var objectId in this.selectionObj) { - if(this.selectionObj.hasOwnProperty(objectId)) { - if (this.selectionObj[objectId] instanceof Node) { - idArray.push(objectId); - } - } - } - return idArray - }, - - /** - * - * retrieve the currently selected edges - * @return {Array} selection An array with the ids of the - * selected nodes. - */ - getSelectedEdges : function() { - var idArray = []; - for(var objectId in this.selectionObj) { - if(this.selectionObj.hasOwnProperty(objectId)) { - if (this.selectionObj[objectId] instanceof Edge) { - idArray.push(objectId); - } - } - } - return idArray - }, - - - /** - * select zero or more nodes - * @param {Number[] | String[]} selection An array with the ids of the - * selected nodes. - */ - setSelection : function(selection) { - var i, iMax, id; - - if (!selection || (selection.length == undefined)) - throw 'Selection must be an array with ids'; - - // first unselect any selected node - this._unselectAll(true); - - for (i = 0, iMax = selection.length; i < iMax; i++) { - id = selection[i]; - - var node = this.nodes[id]; - if (!node) { - throw new RangeError('Node with id "' + id + '" not found'); - } - this._selectObject(node,true,true); - } - this.redraw(); - }, - - - /** - * Validate the selection: remove ids of nodes which no longer exist - * @private - */ - _updateSelection : function () { - for(var objectId in this.selectionObj) { - if(this.selectionObj.hasOwnProperty(objectId)) { - if (this.selectionObj[objectId] instanceof Node) { - if (!this.nodes.hasOwnProperty(objectId)) { - delete this.selectionObj[objectId]; - } - } - else { // assuming only edges and nodes are selected - if (!this.edges.hasOwnProperty(objectId)) { - delete this.selectionObj[objectId]; - } - } - } - } - } - -} -/** - * select all nodes on given location x, y - * @param {Array} selection an array with node ids - * @param {boolean} append If true, the new selection will be appended to the - * current selection (except for duplicate entries) - * @return {Boolean} changed True if the selection is changed - * @private - */ -/* _selectNodes : function(selection, append) { - var changed = false; - var i, iMax; - - // TODO: the selectNodes method is a little messy, rework this - - // check if the current selection equals the desired selection - var selectionAlreadyThere = true; - if (selection.length != this.selection.length) { - selectionAlreadyThere = false; - } - else { - for (i = 0, iMax = Math.min(selection.length, this.selection.length); i < iMax; i++) { - if (selection[i] != this.selection[i]) { - selectionAlreadyThere = false; - break; ->>>>>>> develop - } - } - } - } - - -<<<<<<< HEAD -======= - if (changed) { - // fire the select event - this._trigger('select', { - nodes: this.getSelection() - }); - } ->>>>>>> develop - -}; - - - - -/** - * Created by Alex on 1/22/14. - */ - -var NavigationMixin = { - - /** - * This function moves the navigation controls if the canvas size has been changed. If the arugments - * verticaAlignTop and horizontalAlignLeft are false, the correction will be made - * - * @private - */ - _relocateNavigation : function() { - if (this.sectors !== undefined) { - var xOffset = this.navigationClientWidth - this.frame.canvas.clientWidth; - var yOffset = this.navigationClientHeight - this.frame.canvas.clientHeight; - this.navigationClientWidth = this.frame.canvas.clientWidth; - this.navigationClientHeight = this.frame.canvas.clientHeight; - var node = null; - - for (var nodeId in this.sectors["navigation"]["nodes"]) { - if (this.sectors["navigation"]["nodes"].hasOwnProperty(nodeId)) { - node = this.sectors["navigation"]["nodes"][nodeId]; - if (!node.horizontalAlignLeft) { - node.x -= xOffset; - } - if (!node.verticalAlignTop) { - node.y -= yOffset; - } - } - } - } - }, - - - /** - * Creation of the navigation controls nodes. They are drawn over the rest of the nodes and are not affected by scale and translation - * they have a triggerFunction which is called on click. If the position of the navigation controls is dependent - * on this.frame.canvas.clientWidth or this.frame.canvas.clientHeight, we flag horizontalAlignLeft and verticalAlignTop false. - * This means that the location will be corrected by the _relocateNavigation function on a size change of the canvas. - * - * @private - */ - _loadNavigationElements : function() { - var DIR = this.constants.navigation.iconPath; - this.navigationClientWidth = this.frame.canvas.clientWidth; - this.navigationClientHeight = this.frame.canvas.clientHeight; - if (this.navigationClientWidth === undefined) { - this.navigationClientWidth = 0; - this.navigationClientHeight = 0; - } - var offset = 15; - var intermediateOffset = 7; - var navigationNodes = [ - {id: 'navigation_up', shape: 'image', image: DIR + '/uparrow.png', triggerFunction: "_moveUp", - verticalAlignTop: false, x: 45 + offset + intermediateOffset, y: this.navigationClientHeight - 45 - offset - intermediateOffset}, - {id: 'navigation_down', shape: 'image', image: DIR + '/downarrow.png', triggerFunction: "_moveDown", - verticalAlignTop: false, x: 45 + offset + intermediateOffset, y: this.navigationClientHeight - 15 - offset}, - {id: 'navigation_left', shape: 'image', image: DIR + '/leftarrow.png', triggerFunction: "_moveLeft", - verticalAlignTop: false, x: 15 + offset, y: this.navigationClientHeight - 15 - offset}, - {id: 'navigation_right', shape: 'image', image: DIR + '/rightarrow.png',triggerFunction: "_moveRight", - verticalAlignTop: false, x: 75 + offset + 2 * intermediateOffset, y: this.navigationClientHeight - 15 - offset}, - - {id: 'navigation_plus', shape: 'image', image: DIR + '/plus.png', triggerFunction: "_zoomIn", - verticalAlignTop: false, horizontalAlignLeft: false, - x: this.navigationClientWidth - 45 - offset - intermediateOffset, y: this.navigationClientHeight - 15 - offset}, - {id: 'navigation_min', shape: 'image', image: DIR + '/minus.png', triggerFunction: "_zoomOut", - verticalAlignTop: false, horizontalAlignLeft: false, - x: this.navigationClientWidth - 15 - offset, y: this.navigationClientHeight - 15 - offset}, - {id: 'navigation_zoomExtends', shape: 'image', image: DIR + '/zoomExtends.png', triggerFunction: "zoomToFit", - verticalAlignTop: false, horizontalAlignLeft: false, - x: this.navigationClientWidth - 15 - offset, y: this.navigationClientHeight - 45 - offset - intermediateOffset} - ]; - - var nodeObj = null; - for (var i = 0; i < navigationNodes.length; i++) { - nodeObj = this.sectors["navigation"]['nodes']; - nodeObj[navigationNodes[i]['id']] = new Node(navigationNodes[i], this.images, this.groups, this.constants); - } - }, - - - /** - * By setting the clustersize to be larger than 1, we use the clustering drawing method - * to illustrate the buttons are presed. We call this highlighting. - * - * @param {String} elementId - * @private - */ - _highlightNavigationElement : function(elementId) { - if (this.sectors["navigation"]["nodes"].hasOwnProperty(elementId)) { - this.sectors["navigation"]["nodes"][elementId].clusterSize = 2; - } - }, - - - /** - * Reverting back to a normal button - * - * @param {String} elementId - * @private - */ - _unHighlightNavigationElement : function(elementId) { - if (this.sectors["navigation"]["nodes"].hasOwnProperty(elementId)) { - this.sectors["navigation"]["nodes"][elementId].clusterSize = 1; - } - }, - - /** - * un-highlight (for lack of a better term) all navigation controls elements - * @private - */ - _unHighlightAll : function() { - for (var nodeId in this.sectors['navigation']['nodes']) { - if (this.sectors['navigation']['nodes'].hasOwnProperty(nodeId)) { - this._unHighlightNavigationElement(nodeId); - } - } - }, - - - _preventDefault : function(event) { - if (event !== undefined) { - if (event.preventDefault) { - event.preventDefault(); - } else { - event.returnValue = false; - } - } - }, - - - /** - * move the screen up - * By using the increments, instead of adding a fixed number to the translation, we keep fluent and - * instant movement. The onKeypress event triggers immediately, then pauses, then triggers frequently - * To avoid this behaviour, we do the translation in the start loop. - * - * @private - */ - _moveUp : function(event) { - this._highlightNavigationElement("navigation_up"); - this.yIncrement = this.constants.keyboard.speed.y; - this.start(); // if there is no node movement, the calculation wont be done - this._preventDefault(event); - }, - - - /** - * move the screen down - * @private - */ - _moveDown : function(event) { - this._highlightNavigationElement("navigation_down"); - this.yIncrement = -this.constants.keyboard.speed.y; - this.start(); // if there is no node movement, the calculation wont be done - this._preventDefault(event); - }, - - - /** - * move the screen left - * @private - */ - _moveLeft : function(event) { - this._highlightNavigationElement("navigation_left"); - this.xIncrement = this.constants.keyboard.speed.x; - this.start(); // if there is no node movement, the calculation wont be done - this._preventDefault(event); - }, - - - /** - * move the screen right - * @private - */ - _moveRight : function(event) { - this._highlightNavigationElement("navigation_right"); - this.xIncrement = -this.constants.keyboard.speed.y; - this.start(); // if there is no node movement, the calculation wont be done - this._preventDefault(event); - }, - - - /** - * Zoom in, using the same method as the movement. - * @private - */ - _zoomIn : function(event) { - this._highlightNavigationElement("navigation_plus"); - this.zoomIncrement = this.constants.keyboard.speed.zoom; - this.start(); // if there is no node movement, the calculation wont be done - this._preventDefault(event); - }, - - - /** - * Zoom out - * @private - */ - _zoomOut : function() { - this._highlightNavigationElement("navigation_min"); - this.zoomIncrement = -this.constants.keyboard.speed.zoom; - this.start(); // if there is no node movement, the calculation wont be done - this._preventDefault(event); - }, - - - /** - * Stop zooming and unhighlight the zoom controls - * @private - */ - _stopZoom : function() { - this._unHighlightNavigationElement("navigation_plus"); - this._unHighlightNavigationElement("navigation_min"); - - this.zoomIncrement = 0; - }, - - - /** - * Stop moving in the Y direction and unHighlight the up and down - * @private - */ - _yStopMoving : function() { - this._unHighlightNavigationElement("navigation_up"); - this._unHighlightNavigationElement("navigation_down"); - - this.yIncrement = 0; - }, - - - /** - * Stop moving in the X direction and unHighlight left and right. - * @private - */ - _xStopMoving : function() { - this._unHighlightNavigationElement("navigation_left"); - this._unHighlightNavigationElement("navigation_right"); - - this.xIncrement = 0; - } - - -}; - -/** - * @constructor Graph - * Create a graph visualization, displaying nodes and edges. - * - * @param {Element} container The DOM element in which the Graph will - * be created. Normally a div element. - * @param {Object} data An object containing parameters - * {Array} nodes - * {Array} edges - * @param {Object} options Options - */ -function Graph (container, data, options) { - // create variables and set default values - this.containerElement = container; - this.width = '100%'; - this.height = '100%'; - // to give everything a nice fluidity, we seperate the rendering and calculating of the forces - this.renderRefreshRate = 60; // hz (fps) - this.renderTimestep = 1000 / this.renderRefreshRate; // ms -- saves calculation later on - this.stabilize = true; // stabilize before displaying the graph - this.selectable = true; - - // set constant values - this.constants = { - nodes: { - radiusMin: 5, - radiusMax: 20, - radius: 5, - distance: 100, // px - shape: 'ellipse', - image: undefined, - widthMin: 16, // px - widthMax: 64, // px - fontColor: 'black', - fontSize: 14, // px - //fontFace: verdana, - fontFace: 'arial', - color: { - border: '#2B7CE9', - background: '#97C2FC', - highlight: { - border: '#2B7CE9', - background: '#D2E5FF' - } - }, - borderColor: '#2B7CE9', - backgroundColor: '#97C2FC', - highlightColor: '#D2E5FF', - group: undefined - }, - edges: { - widthMin: 1, - widthMax: 15, - width: 1, - style: 'line', - color: '#343434', - fontColor: '#343434', - fontSize: 14, // px - fontFace: 'arial', - //distance: 100, //px - length: 100, // px - dash: { - length: 10, - gap: 5, - altLength: undefined - } - }, - physics: { - springConstant:0.05, - springLength: 100, - centralGravity: 0.1, - nodeGravityConstant: -10000, - barnesHutTheta: 0.2 - }, - clustering: { // Per Node in Cluster = PNiC - enabled: false, // (Boolean) | global on/off switch for clustering. - initialMaxNodes: 100, // (# nodes) | if the initial amount of nodes is larger than this, we cluster until the total number is less than this threshold. - clusterThreshold:500, // (# nodes) | during calculate forces, we check if the total number of nodes is larger than this. If it is, cluster until reduced to reduceToNodes - reduceToNodes:300, // (# nodes) | during calculate forces, we check if the total number of nodes is larger than clusterThreshold. If it is, cluster until reduced to this - chainThreshold: 0.4, // (% of all drawn nodes)| maximum percentage of allowed chainnodes (long strings of connected nodes) within all nodes. (lower means less chains). - clusterEdgeThreshold: 20, // (px) | edge length threshold. if smaller, this node is clustered. - sectorThreshold: 50, // (# nodes in cluster) | cluster size threshold. If larger, expanding in own sector. - screenSizeThreshold: 0.2, // (% of canvas) | relative size threshold. If the width or height of a clusternode takes up this much of the screen, decluster node. - fontSizeMultiplier: 4.0, // (px PNiC) | how much the cluster font size grows per node in cluster (in px). - forceAmplification: 0.6, // (multiplier PNiC) | factor of increase fo the repulsion force of a cluster (per node in cluster). - distanceAmplification: 0.2, // (multiplier PNiC) | factor how much the repulsion distance of a cluster increases (per node in cluster). - edgeGrowth: 11, // (px PNiC) | amount of clusterSize connected to the edge is multiplied with this and added to edgeLength. - nodeScaling: {width: 10, // (px PNiC) | growth of the width per node in cluster. - height: 10, // (px PNiC) | growth of the height per node in cluster. - radius: 10}, // (px PNiC) | growth of the radius per node in cluster. - activeAreaBoxSize: 100 // (px) | box area around the curser where clusters are popped open. - }, - navigation: { - enabled: false, - iconPath: this._getScriptPath() + '/img' - }, - keyboard: { - enabled: false, - speed: {x: 10, y: 10, zoom: 0.02} - }, - dataManipulationToolbar: { - enabled: false - }, - minVelocity: 0.2, // px/s - maxIterations: 1000 // maximum number of iteration to stabilize - }; - - // Node variables - this.groups = new Groups(); // object with groups - this.images = new Images(); // object with images - this.images.setOnloadCallback(function () { - graph._redraw(); - }); - - // navigation variables - this.xIncrement = 0; - this.yIncrement = 0; - this.zoomIncrement = 0; - - // load the force calculation functions, grouped under the physics system. - this._loadPhysicsSystem(); - - // create a frame and canvas - this._create(); - - // load the sector system. (mandatory, fully integrated with Graph) - this._loadSectorSystem(); - - // load the cluster system. (mandatory, even when not using the cluster system, there are function calls to it) - this._loadClusterSystem(); - - // load the selection system. (mandatory, required by Graph) - this._loadSelectionSystem(); - - // apply options - this.setOptions(options); - - // other vars - var graph = this; - this.freezeSimulation = false;// freeze the simulation - - this.nodeIndices = []; // array with all the indices of the nodes. Used to speed up forces calculation - this.nodes = {}; // object with Node objects - this.edges = {}; // object with Edge objects - - this.canvasTopLeft = {"x": 0,"y": 0}; // coordinates of the top left of the canvas. they will be set during _redraw. - this.canvasBottomRight = {"x": 0,"y": 0}; // coordinates of the bottom right of the canvas. they will be set during _redraw - this.pointerPosition = {"x": 0,"y": 0}; // coordinates of the bottom right of the canvas. they will be set during _redraw - - this.areaCenter = {}; // object with x and y elements used for determining the center of the zoom action - this.scale = 1; // defining the global scale variable in the constructor - this.previousScale = this.scale; // this is used to check if the zoom operation is zooming in or out - // TODO: create a counter to keep track on the number of nodes having values - // TODO: create a counter to keep track on the number of nodes currently moving - // TODO: create a counter to keep track on the number of edges having values - - this.nodesData = null; // A DataSet or DataView - this.edgesData = null; // A DataSet or DataView - - // create event listeners used to subscribe on the DataSets of the nodes and edges - var me = this; - this.nodesListeners = { - 'add': function (event, params) { - me._addNodes(params.items); - me.start(); - }, - 'update': function (event, params) { - me._updateNodes(params.items); - me.start(); - }, - 'remove': function (event, params) { - me._removeNodes(params.items); - me.start(); - } - }; - this.edgesListeners = { - 'add': function (event, params) { - me._addEdges(params.items); - me.start(); - }, - 'update': function (event, params) { - me._updateEdges(params.items); - me.start(); - }, - 'remove': function (event, params) { - me._removeEdges(params.items); - me.start(); - } - }; - - // properties of the data - this.moving = false; // True if any of the nodes have an undefined position - this.timer = undefined; - - // load data (the disable start variable will be the same as the enabled clustering) - this.setData(data,this.constants.clustering.enabled); - - // zoom so all data will fit on the screen - this.zoomToFit(true); - - // if clustering is disabled, the simulation will have started in the setData function - if (this.constants.clustering.enabled) { - this.startWithClustering(); - } -} - -/** - * Get the script path where the vis.js library is located - * - * @returns {string | null} path Path or null when not found. Path does not - * end with a slash. - * @private - */ -Graph.prototype._getScriptPath = function() { - var scripts = document.getElementsByTagName( 'script' ); - - // find script named vis.js or vis.min.js - for (var i = 0; i < scripts.length; i++) { - var src = scripts[i].src; - var match = src && /\/?vis(.min)?\.js$/.exec(src); - if (match) { - // return path without the script name - return src.substring(0, src.length - match[0].length); - } - } - - return null; -}; - - -/** - * Find the center position of the graph - * @private - */ -Graph.prototype._getRange = function() { - var minY = 1e9, maxY = -1e9, minX = 1e9, maxX = -1e9, node; - for (var i = 0; i < this.nodeIndices.length; i++) { - node = this.nodes[this.nodeIndices[i]]; - if (minX > (node.x - node.width)) {minX = node.x - node.width;} - if (maxX < (node.x + node.width)) {maxX = node.x + node.width;} - if (minY > (node.y - node.height)) {minY = node.y - node.height;} - if (maxY < (node.y + node.height)) {maxY = node.y + node.height;} - } - return {minX: minX, maxX: maxX, minY: minY, maxY: maxY}; -}; - - -/** - * @param {object} range = {minX: minX, maxX: maxX, minY: minY, maxY: maxY}; - * @returns {{x: number, y: number}} - * @private - */ -Graph.prototype._findCenter = function(range) { - var center = {x: (0.5 * (range.maxX + range.minX)), - y: (0.5 * (range.maxY + range.minY))}; - return center; -}; - - -/** - * center the graph - * - * @param {object} range = {minX: minX, maxX: maxX, minY: minY, maxY: maxY}; - */ -Graph.prototype._centerGraph = function(range) { - var center = this._findCenter(range); - - center.x *= this.scale; - center.y *= this.scale; - center.x -= 0.5 * this.frame.canvas.clientWidth; - center.y -= 0.5 * this.frame.canvas.clientHeight; - - this._setTranslation(-center.x,-center.y); // set at 0,0 -}; - - -/** - * This function zooms out to fit all data on screen based on amount of nodes - * - * @param {Boolean} [initialZoom] | zoom based on fitted formula or range, true = fitted, default = false; - */ -Graph.prototype.zoomToFit = function(initialZoom) { - if (initialZoom === undefined) { - initialZoom = false; - } - - var numberOfNodes = this.nodeIndices.length; - var range = this._getRange(); - - if (initialZoom == true) { - if (this.constants.clustering.enabled == true && - numberOfNodes >= this.constants.clustering.initialMaxNodes) { - var zoomLevel = 38.8467 / (numberOfNodes - 14.50184) + 0.0116; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. - } - else { - var zoomLevel = 42.54117319 / (numberOfNodes + 39.31966387) + 0.1944405; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. - } - } - else { - var xDistance = (Math.abs(range.minX) + Math.abs(range.maxX)) * 1.1; - var yDistance = (Math.abs(range.minY) + Math.abs(range.maxY)) * 1.1; - - var xZoomLevel = this.frame.canvas.clientWidth / xDistance; - var yZoomLevel = this.frame.canvas.clientHeight / yDistance; - - zoomLevel = (xZoomLevel <= yZoomLevel) ? xZoomLevel : yZoomLevel; - } - - if (zoomLevel > 1.0) { - zoomLevel = 1.0; - } - - this.pinch.mousewheelScale = zoomLevel; - this._setScale(zoomLevel); - this._centerGraph(range); - this.start(); -}; - - -/** - * Update the this.nodeIndices with the most recent node index list - * @private - */ -Graph.prototype._updateNodeIndexList = function() { - this._clearNodeIndexList(); - for (var idx in this.nodes) { - if (this.nodes.hasOwnProperty(idx)) { - this.nodeIndices.push(idx); - } - } -}; - - -/** - * Set nodes and edges, and optionally options as well. - * - * @param {Object} data Object containing parameters: - * {Array | DataSet | DataView} [nodes] Array with nodes - * {Array | DataSet | DataView} [edges] Array with edges - * {String} [dot] String containing data in DOT format - * {Options} [options] Object with options - * @param {Boolean} [disableStart] | optional: disable the calling of the start function. - */ -Graph.prototype.setData = function(data, disableStart) { - if (disableStart === undefined) { - disableStart = false; - } - - if (data && data.dot && (data.nodes || data.edges)) { - throw new SyntaxError('Data must contain either parameter "dot" or ' + - ' parameter pair "nodes" and "edges", but not both.'); - } - - // set options - this.setOptions(data && data.options); - - // set all data - if (data && data.dot) { - // parse DOT file - if(data && data.dot) { - var dotData = vis.util.DOTToGraph(data.dot); - this.setData(dotData); - return; - } - } - else { - this._setNodes(data && data.nodes); - this._setEdges(data && data.edges); - } - - this._putDataInSector(); - - if (!disableStart) { - // find a stable position or start animating to a stable position - if (this.stabilize) { - this._doStabilize(); - } - this.moving = true; - this.start(); - } -}; - -/** - * Set options - * @param {Object} options - */ -Graph.prototype.setOptions = function (options) { - if (options) { - // retrieve parameter values - if (options.width !== undefined) {this.width = options.width;} - if (options.height !== undefined) {this.height = options.height;} - if (options.stabilize !== undefined) {this.stabilize = options.stabilize;} - if (options.selectable !== undefined) {this.selectable = options.selectable;} - - if (options.clustering) { - this.constants.clustering.enabled = true; - for (var prop in options.clustering) { - if (options.clustering.hasOwnProperty(prop)) { - this.constants.clustering[prop] = options.clustering[prop]; - } - } - } - else if (options.clustering !== undefined) { - this.constants.clustering.enabled = false; - } - - if (options.navigation) { - this.constants.navigation.enabled = true; - for (var prop in options.navigation) { - if (options.navigation.hasOwnProperty(prop)) { - this.constants.navigation[prop] = options.navigation[prop]; - } - } - } - else if (options.navigation !== undefined) { - this.constants.navigation.enabled = false; - } - - if (options.keyboard) { - this.constants.keyboard.enabled = true; - for (var prop in options.keyboard) { - if (options.keyboard.hasOwnProperty(prop)) { - this.constants.keyboard[prop] = options.keyboard[prop]; - } - } - } - else if (options.keyboard !== undefined) { - this.constants.keyboard.enabled = false; - } - - if (options.dataManipulationToolbar) { - this.constants.dataManipulationToolbar.enabled = true; - for (var prop in options.dataManipulationToolbar) { - if (options.dataManipulationToolbar.hasOwnProperty(prop)) { - this.constants.dataManipulationToolbar[prop] = options.dataManipulationToolbar[prop]; - } - } - } - else if (options.dataManipulationToolbar !== undefined) { - this.constants.dataManipulationToolbar.enabled = false; - } - - // TODO: work out these options and document them - if (options.edges) { - for (prop in options.edges) { - if (options.edges.hasOwnProperty(prop)) { - this.constants.edges[prop] = options.edges[prop]; - } - } - - if (options.edges.length !== undefined && - options.nodes && options.nodes.distance === undefined) { - this.constants.physics.springLength = options.edges.length; - this.constants.nodes.distance = options.edges.length * 1.25; - } - - if (!options.edges.fontColor) { - this.constants.edges.fontColor = options.edges.color; - } - - // Added to support dashed lines - // David Jordan - // 2012-08-08 - if (options.edges.dash) { - if (options.edges.dash.length !== undefined) { - this.constants.edges.dash.length = options.edges.dash.length; - } - if (options.edges.dash.gap !== undefined) { - this.constants.edges.dash.gap = options.edges.dash.gap; - } - if (options.edges.dash.altLength !== undefined) { - this.constants.edges.dash.altLength = options.edges.dash.altLength; - } - } - } - - if (options.nodes) { - for (prop in options.nodes) { - if (options.nodes.hasOwnProperty(prop)) { - this.constants.nodes[prop] = options.nodes[prop]; - } - } - - if (options.nodes.color) { - this.constants.nodes.color = Node.parseColor(options.nodes.color); - } - - /* - if (options.nodes.widthMin) this.constants.nodes.radiusMin = options.nodes.widthMin; - if (options.nodes.widthMax) this.constants.nodes.radiusMax = options.nodes.widthMax; - */ - } - if (options.groups) { - for (var groupname in options.groups) { - if (options.groups.hasOwnProperty(groupname)) { - var group = options.groups[groupname]; - this.groups.add(groupname, group); - } - } - } - } - - // load the navigation system. - this._loadNavigationControls(); - - // load the data manipulation system - this._loadManipulationSystem(); - - // bind keys. If disabled, this will not do anything; - this._createKeyBinds(); - - this.setSize(this.width, this.height); - this._setTranslation(this.frame.clientWidth / 2, this.frame.clientHeight / 2); - this._setScale(1); - this._redraw(); -}; - -/** - * Add event listener - * @param {String} event Event name. Available events: - * 'select' - * @param {function} callback Callback function, invoked as callback(properties) - * where properties is an optional object containing - * event specific properties. - */ -Graph.prototype.on = function on (event, callback) { - var available = ['select']; - - if (available.indexOf(event) == -1) { - throw new Error('Unknown event "' + event + '". Choose from ' + available.join()); - } - - events.addListener(this, event, callback); -}; - -/** - * Remove an event listener - * @param {String} event Event name - * @param {function} callback Callback function - */ -Graph.prototype.off = function off (event, callback) { - events.removeListener(this, event, callback); -}; - -/** - * fire an event - * @param {String} event The name of an event, for example 'select' - * @param {Object} params Optional object with event parameters - * @private - */ -Graph.prototype._trigger = function (event, params) { - events.trigger(this, event, params); -}; - - -/** - * Create the main frame for the Graph. - * This function is executed once when a Graph object is created. The frame - * contains a canvas, and this canvas contains all objects like the axis and - * nodes. - * @private - */ -Graph.prototype._create = function () { - // remove all elements from the container element. - while (this.containerElement.hasChildNodes()) { - this.containerElement.removeChild(this.containerElement.firstChild); - } - - this.frame = document.createElement('div'); - this.frame.className = 'graph-frame'; - this.frame.style.position = 'relative'; - this.frame.style.overflow = 'hidden'; - this.frame.style.zIndex = "1"; - - // create the graph canvas (HTML canvas element) - this.frame.canvas = document.createElement( 'canvas' ); - this.frame.canvas.style.position = 'relative'; - this.frame.appendChild(this.frame.canvas); - if (!this.frame.canvas.getContext) { - var noCanvas = document.createElement( 'DIV' ); - noCanvas.style.color = 'red'; - noCanvas.style.fontWeight = 'bold' ; - noCanvas.style.padding = '10px'; - noCanvas.innerHTML = 'Error: your browser does not support HTML canvas'; - this.frame.canvas.appendChild(noCanvas); - } - - var me = this; - this.drag = {}; - this.pinch = {}; - this.hammer = Hammer(this.frame.canvas, { - prevent_default: true - }); - this.hammer.on('tap', me._onTap.bind(me) ); - this.hammer.on('doubletap', me._onDoubleTap.bind(me) ); - this.hammer.on('hold', me._onHold.bind(me) ); - this.hammer.on('pinch', me._onPinch.bind(me) ); - this.hammer.on('touch', me._onTouch.bind(me) ); - this.hammer.on('dragstart', me._onDragStart.bind(me) ); - this.hammer.on('drag', me._onDrag.bind(me) ); - this.hammer.on('dragend', me._onDragEnd.bind(me) ); - this.hammer.on('release', me._onRelease.bind(me) ); - this.hammer.on('mousewheel',me._onMouseWheel.bind(me) ); - this.hammer.on('DOMMouseScroll',me._onMouseWheel.bind(me) ); // for FF - this.hammer.on('mousemove', me._onMouseMoveTitle.bind(me) ); - - // add the frame to the container element - this.containerElement.appendChild(this.frame); - -}; - - -/** - * Binding the keys for keyboard navigation. These functions are defined in the NavigationMixin - * @private - */ -Graph.prototype._createKeyBinds = function() { - var me = this; - this.mousetrap = mousetrap; - - this.mousetrap.reset(); - - if (this.constants.keyboard.enabled == true) { - this.mousetrap.bind("up", this._moveUp.bind(me) , "keydown"); - this.mousetrap.bind("up", this._yStopMoving.bind(me), "keyup"); - this.mousetrap.bind("down", this._moveDown.bind(me) , "keydown"); - this.mousetrap.bind("down", this._yStopMoving.bind(me), "keyup"); - this.mousetrap.bind("left", this._moveLeft.bind(me) , "keydown"); - this.mousetrap.bind("left", this._xStopMoving.bind(me), "keyup"); - this.mousetrap.bind("right",this._moveRight.bind(me), "keydown"); - this.mousetrap.bind("right",this._xStopMoving.bind(me), "keyup"); - this.mousetrap.bind("=", this._zoomIn.bind(me), "keydown"); - this.mousetrap.bind("=", this._stopZoom.bind(me), "keyup"); - this.mousetrap.bind("-", this._zoomOut.bind(me), "keydown"); - this.mousetrap.bind("-", this._stopZoom.bind(me), "keyup"); - this.mousetrap.bind("[", this._zoomIn.bind(me), "keydown"); - this.mousetrap.bind("[", this._stopZoom.bind(me), "keyup"); - this.mousetrap.bind("]", this._zoomOut.bind(me), "keydown"); - this.mousetrap.bind("]", this._stopZoom.bind(me), "keyup"); - this.mousetrap.bind("pageup",this._zoomIn.bind(me), "keydown"); - this.mousetrap.bind("pageup",this._stopZoom.bind(me), "keyup"); - this.mousetrap.bind("pagedown",this._zoomOut.bind(me),"keydown"); - this.mousetrap.bind("pagedown",this._stopZoom.bind(me), "keyup"); - } - this.mousetrap.bind("b",this._formBarnesHutTree.bind(me)); - - if (this.constants.dataManipulationToolbar.enabled == true) { - this.mousetrap.bind("escape",this._createManipulatorBar.bind(me)); - } -} - -/** - * Get the pointer location from a touch location - * @param {{pageX: Number, pageY: Number}} touch - * @return {{x: Number, y: Number}} pointer - * @private - */ -Graph.prototype._getPointer = function (touch) { - return { - x: touch.pageX - vis.util.getAbsoluteLeft(this.frame.canvas), - y: touch.pageY - vis.util.getAbsoluteTop(this.frame.canvas) - }; -}; - -/** - * On start of a touch gesture, store the pointer - * @param event - * @private - */ -Graph.prototype._onTouch = function (event) { - this.drag.pointer = this._getPointer(event.gesture.touches[0]); - this.drag.pinched = false; - this.pinch.scale = this._getScale(); - - this._handleTouch(this.drag.pointer); -}; - -/** - * handle drag start event - * @private - */ -Graph.prototype._onDragStart = function () { - var drag = this.drag; - var node = this._getNodeAt(drag.pointer); - // note: drag.pointer is set in _onTouch to get the initial touch location - - drag.dragging = true; - drag.selection = []; - drag.translation = this._getTranslation(); - drag.nodeId = null; - - if (node != null) { - drag.nodeId = node.id; - // select the clicked node if not yet selected - if (!node.isSelected()) { - this._selectObject(node,false); - } - - // create an array with the selected nodes and their original location and status - for (var objectId in this.selectionObj) { - if (this.selectionObj.hasOwnProperty(objectId)) { - var object = this.selectionObj[objectId]; - if (object instanceof Node) { - var s = { - id: object.id, - node: object, - - // store original x, y, xFixed and yFixed, make the node temporarily Fixed - x: object.x, - y: object.y, - xFixed: object.xFixed, - yFixed: object.yFixed - }; - - object.xFixed = true; - object.yFixed = true; - - drag.selection.push(s); - } - } - } - } -}; - -/** - * handle drag event - * @private - */ -Graph.prototype._onDrag = function (event) { - if (this.drag.pinched) { - return; - } - - var pointer = this._getPointer(event.gesture.touches[0]); - - var me = this, - drag = this.drag, - selection = drag.selection; - if (selection && selection.length) { - // calculate delta's and new location - var deltaX = pointer.x - drag.pointer.x, - deltaY = pointer.y - drag.pointer.y; - - // update position of all selected nodes - selection.forEach(function (s) { - var node = s.node; - - if (!s.xFixed) { - node.x = me._canvasToX(me._xToCanvas(s.x) + deltaX); - } - - if (!s.yFixed) { - node.y = me._canvasToY(me._yToCanvas(s.y) + deltaY); - } - }); - - // start animation if not yet running - if (!this.moving) { - this.moving = true; - this.start(); - } - } - else { - // move the graph - var diffX = pointer.x - this.drag.pointer.x; - var diffY = pointer.y - this.drag.pointer.y; - - this._setTranslation( - this.drag.translation.x + diffX, - this.drag.translation.y + diffY); - this._redraw(); - this.moved = true; - } -}; - -/** - * handle drag start event - * @private - */ -Graph.prototype._onDragEnd = function () { - this.drag.dragging = false; - var selection = this.drag.selection; - if (selection) { - selection.forEach(function (s) { - // restore original xFixed and yFixed - s.node.xFixed = s.xFixed; - s.node.yFixed = s.yFixed; - }); - } -}; - -/** - * handle tap/click event: select/unselect a node - * @private - */ -Graph.prototype._onTap = function (event) { - var pointer = this._getPointer(event.gesture.touches[0]); - this.pointerPosition = pointer; - this._handleTap(pointer); - -}; - - -/** - * handle doubletap event - * @private - */ -Graph.prototype._onDoubleTap = function (event) { - var pointer = this._getPointer(event.gesture.touches[0]); - this._handleDoubleTap(pointer); - -}; - - -/** - * handle long tap event: multi select nodes - * @private - */ -Graph.prototype._onHold = function (event) { - var pointer = this._getPointer(event.gesture.touches[0]); - this.pointerPosition = pointer; - this._handleOnHold(pointer); -}; - -/** - * handle the release of the screen - * - * @param event - * @private - */ -Graph.prototype._onRelease = function (event) { - this._handleOnRelease(); -}; - -/** - * Handle pinch event - * @param event - * @private - */ -Graph.prototype._onPinch = function (event) { - var pointer = this._getPointer(event.gesture.center); - - this.drag.pinched = true; - if (!('scale' in this.pinch)) { - this.pinch.scale = 1; - } - - // TODO: enabled moving while pinching? - var scale = this.pinch.scale * event.gesture.scale; - this._zoom(scale, pointer) -}; - -/** - * Zoom the graph in or out - * @param {Number} scale a number around 1, and between 0.01 and 10 - * @param {{x: Number, y: Number}} pointer Position on screen - * @return {Number} appliedScale scale is limited within the boundaries - * @private - */ -Graph.prototype._zoom = function(scale, pointer) { - var scaleOld = this._getScale(); - if (scale < 0.00001) { - scale = 0.00001; - } - if (scale > 10) { - scale = 10; - } -// + this.frame.canvas.clientHeight / 2 - var translation = this._getTranslation(); - - var scaleFrac = scale / scaleOld; - var tx = (1 - scaleFrac) * pointer.x + translation.x * scaleFrac; - var ty = (1 - scaleFrac) * pointer.y + translation.y * scaleFrac; - - this.areaCenter = {"x" : this._canvasToX(pointer.x), - "y" : this._canvasToY(pointer.y)}; - - // this.areaCenter = {"x" : pointer.x,"y" : pointer.y }; -// console.log(translation.x,translation.y,pointer.x,pointer.y,scale); - this.pinch.mousewheelScale = scale; - this._setScale(scale); - this._setTranslation(tx, ty); - this.updateClustersDefault(); - this._redraw(); - - return scale; -}; - -/** - * Event handler for mouse wheel event, used to zoom the timeline - * See http://adomas.org/javascript-mouse-wheel/ - * https://github.com/EightMedia/hammer.js/issues/256 - * @param {MouseEvent} event - * @private - */ -Graph.prototype._onMouseWheel = function(event) { - // retrieve delta - var delta = 0; - if (event.wheelDelta) { /* IE/Opera. */ - delta = event.wheelDelta/120; - } else if (event.detail) { /* Mozilla case. */ - // In Mozilla, sign of delta is different than in IE. - // Also, delta is multiple of 3. - delta = -event.detail/3; - } - - // If delta is nonzero, handle it. - // Basically, delta is now positive if wheel was scrolled up, - // and negative, if wheel was scrolled down. - if (delta) { - if (!('mousewheelScale' in this.pinch)) { - this.pinch.mousewheelScale = 1; - } - - // calculate the new scale - var scale = this.pinch.mousewheelScale; - var zoom = delta / 10; - if (delta < 0) { - zoom = zoom / (1 - zoom); - } - scale *= (1 + zoom); - - // calculate the pointer location - var gesture = util.fakeGesture(this, event); - var pointer = this._getPointer(gesture.center); - - // apply the new scale - scale = this._zoom(scale, pointer); - - // store the new, applied scale -- this is now done in _zoom -// this.pinch.mousewheelScale = scale; - } - - // Prevent default actions caused by mouse wheel. - event.preventDefault(); -}; - - -/** - * Mouse move handler for checking whether the title moves over a node with a title. - * @param {Event} event - * @private - */ -Graph.prototype._onMouseMoveTitle = function (event) { - var gesture = util.fakeGesture(this, event); - var pointer = this._getPointer(gesture.center); - - // check if the previously selected node is still selected - if (this.popupNode) { - this._checkHidePopup(pointer); - } - - // start a timeout that will check if the mouse is positioned above - // an element - var me = this; - var checkShow = function() { - me._checkShowPopup(pointer); - }; - if (this.popupTimer) { - clearInterval(this.popupTimer); // stop any running calculationTimer - } - if (!this.drag.dragging) { - this.popupTimer = setTimeout(checkShow, 300); - } -}; - -/** - * Check if there is an element on the given position in the graph - * (a node or edge). If so, and if this element has a title, - * show a popup window with its title. - * - * @param {{x:Number, y:Number}} pointer - * @private - */ -Graph.prototype._checkShowPopup = function (pointer) { - var obj = { - left: this._canvasToX(pointer.x), - top: this._canvasToY(pointer.y), - right: this._canvasToX(pointer.x), - bottom: this._canvasToY(pointer.y) - }; - - var id; - var lastPopupNode = this.popupNode; - - if (this.popupNode == undefined) { - // search the nodes for overlap, select the top one in case of multiple nodes - var nodes = this.nodes; - for (id in nodes) { - if (nodes.hasOwnProperty(id)) { - var node = nodes[id]; - if (node.getTitle() !== undefined && node.isOverlappingWith(obj)) { - this.popupNode = node; - break; - } - } - } - } - - if (this.popupNode === undefined) { - // search the edges for overlap - var edges = this.edges; - for (id in edges) { - if (edges.hasOwnProperty(id)) { - var edge = edges[id]; - if (edge.connected && (edge.getTitle() !== undefined) && - edge.isOverlappingWith(obj)) { - this.popupNode = edge; - break; - } - } - } - } - - if (this.popupNode) { - // show popup message window - if (this.popupNode != lastPopupNode) { - var me = this; - if (!me.popup) { - me.popup = new Popup(me.frame); - } - - // adjust a small offset such that the mouse cursor is located in the - // bottom left location of the popup, and you can easily move over the - // popup area - me.popup.setPosition(pointer.x - 3, pointer.y - 3); - me.popup.setText(me.popupNode.getTitle()); - me.popup.show(); - } - } - else { - if (this.popup) { - this.popup.hide(); - } - } -}; - -/** - * Check if the popup must be hided, which is the case when the mouse is no - * longer hovering on the object - * @param {{x:Number, y:Number}} pointer - * @private - */ -Graph.prototype._checkHidePopup = function (pointer) { - if (!this.popupNode || !this._getNodeAt(pointer) ) { - this.popupNode = undefined; - if (this.popup) { - this.popup.hide(); - } - } -}; - - -/** - * Temporary method to test calculating a hub value for the nodes - * @param {number} level Maximum number edges between two nodes in order - * to call them connected. Optional, 1 by default - * @return {Number[]} connectioncount array with the connection count - * for each node - * @private - */ -Graph.prototype._getConnectionCount = function(level) { - if (level == undefined) { - level = 1; - } - - // get the nodes connected to given nodes - function getConnectedNodes(nodes) { - var connectedNodes = []; - - for (var j = 0, jMax = nodes.length; j < jMax; j++) { - var node = nodes[j]; - - // find all nodes connected to this node - var edges = node.edges; - for (var i = 0, iMax = edges.length; i < iMax; i++) { - var edge = edges[i]; - var other = null; - - // check if connected - if (edge.from == node) - other = edge.to; - else if (edge.to == node) - other = edge.from; - - // check if the other node is not already in the list with nodes - var k, kMax; - if (other) { - for (k = 0, kMax = nodes.length; k < kMax; k++) { - if (nodes[k] == other) { - other = null; - break; - } - } - } - if (other) { - for (k = 0, kMax = connectedNodes.length; k < kMax; k++) { - if (connectedNodes[k] == other) { - other = null; - break; - } - } - } - - if (other) - connectedNodes.push(other); - } - } - - return connectedNodes; - } - - var connections = []; - var nodes = this.nodes; - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - var c = [nodes[id]]; - for (var l = 0; l < level; l++) { - c = c.concat(getConnectedNodes(c)); - } - connections.push(c); - } - } - - var hubs = []; - for (var i = 0, len = connections.length; i < len; i++) { - hubs.push(connections[i].length); - } - - return hubs; -}; - -/** - * Set a new size for the graph - * @param {string} width Width in pixels or percentage (for example '800px' - * or '50%') - * @param {string} height Height in pixels or percentage (for example '400px' - * or '30%') - */ -Graph.prototype.setSize = function(width, height) { - this.frame.style.width = width; - this.frame.style.height = height; - - this.frame.canvas.style.width = '100%'; - this.frame.canvas.style.height = '100%'; - - this.frame.canvas.width = this.frame.canvas.clientWidth; - this.frame.canvas.height = this.frame.canvas.clientHeight; - - if (this.manipulationDiv !== undefined) { - this.manipulationDiv.style.width = this.frame.canvas.clientWidth; - } - - if (this.constants.navigation.enabled == true) { - this._relocateNavigation(); - } -}; - -/** - * Set a data set with nodes for the graph - * @param {Array | DataSet | DataView} nodes The data containing the nodes. - * @private - */ -Graph.prototype._setNodes = function(nodes) { - var oldNodesData = this.nodesData; - - if (nodes instanceof DataSet || nodes instanceof DataView) { - this.nodesData = nodes; - } - else if (nodes instanceof Array) { - this.nodesData = new DataSet(); - this.nodesData.add(nodes); - } - else if (!nodes) { - this.nodesData = new DataSet(); - } - else { - throw new TypeError('Array or DataSet expected'); - } - - if (oldNodesData) { - // unsubscribe from old dataset - util.forEach(this.nodesListeners, function (callback, event) { - oldNodesData.unsubscribe(event, callback); - }); - } - - // remove drawn nodes - this.nodes = {}; - - if (this.nodesData) { - // subscribe to new dataset - var me = this; - util.forEach(this.nodesListeners, function (callback, event) { - me.nodesData.subscribe(event, callback); - }); - - // draw all new nodes - var ids = this.nodesData.getIds(); - this._addNodes(ids); - } - this._updateSelection(); -}; - -/** - * Add nodes - * @param {Number[] | String[]} ids - * @private - */ -Graph.prototype._addNodes = function(ids) { - var id; - for (var i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - var data = this.nodesData.get(id); - var node = new Node(data, this.images, this.groups, this.constants); - this.nodes[id] = node; // note: this may replace an existing node - - if (!node.isFixed() && this.createNodeOnClick != true) { - // TODO: position new nodes in a smarter way! - var radius = this.constants.edges.length; - var count = ids.length; - var angle = 2 * Math.PI * (i / count); - node.x = radius * Math.cos(angle); - node.y = radius * Math.sin(angle); - - // note: no not use node.isMoving() here, as that gives the current - // velocity of the node, which is zero after creation of the node. - this.moving = true; - } - } - this._updateNodeIndexList(); - this._reconnectEdges(); - this._updateValueRange(this.nodes); - this.updateLabels(); -}; - -/** - * Update existing nodes, or create them when not yet existing - * @param {Number[] | String[]} ids - * @private - */ -Graph.prototype._updateNodes = function(ids) { - var nodes = this.nodes, - nodesData = this.nodesData; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - var node = nodes[id]; - var data = nodesData.get(id); - if (node) { - // update node - node.setProperties(data, this.constants); - } - else { - // create node - node = new Node(properties, this.images, this.groups, this.constants); - nodes[id] = node; - - if (!node.isFixed()) { - this.moving = true; - } - } - } - this._updateNodeIndexList(); - this._reconnectEdges(); - this._updateValueRange(nodes); -}; - -/** - * Remove existing nodes. If nodes do not exist, the method will just ignore it. - * @param {Number[] | String[]} ids - * @private - */ -Graph.prototype._removeNodes = function(ids) { - var nodes = this.nodes; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - delete nodes[id]; - } - this._updateNodeIndexList(); - this._reconnectEdges(); - this._updateSelection(); - this._updateValueRange(nodes); -}; - -/** - * Load edges by reading the data table - * @param {Array | DataSet | DataView} edges The data containing the edges. - * @private - * @private - */ -Graph.prototype._setEdges = function(edges) { - var oldEdgesData = this.edgesData; - - if (edges instanceof DataSet || edges instanceof DataView) { - this.edgesData = edges; - } - else if (edges instanceof Array) { - this.edgesData = new DataSet(); - this.edgesData.add(edges); - } - else if (!edges) { - this.edgesData = new DataSet(); - } - else { - throw new TypeError('Array or DataSet expected'); - } - - if (oldEdgesData) { - // unsubscribe from old dataset - util.forEach(this.edgesListeners, function (callback, event) { - oldEdgesData.unsubscribe(event, callback); - }); - } - - // remove drawn edges - this.edges = {}; - - if (this.edgesData) { - // subscribe to new dataset - var me = this; - util.forEach(this.edgesListeners, function (callback, event) { - me.edgesData.subscribe(event, callback); - }); - - // draw all new nodes - var ids = this.edgesData.getIds(); - this._addEdges(ids); - } - - this._reconnectEdges(); -}; - -/** - * Add edges - * @param {Number[] | String[]} ids - * @private - */ -Graph.prototype._addEdges = function (ids) { - var edges = this.edges, - edgesData = this.edgesData; - - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - - var oldEdge = edges[id]; - if (oldEdge) { - oldEdge.disconnect(); - } - - var data = edgesData.get(id, {"showInternalIds" : true}); - edges[id] = new Edge(data, this, this.constants); - } - - this.moving = true; - this._updateValueRange(edges); -}; - -/** - * Update existing edges, or create them when not yet existing - * @param {Number[] | String[]} ids - * @private - */ -Graph.prototype._updateEdges = function (ids) { - var edges = this.edges, - edgesData = this.edgesData; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - - var data = edgesData.get(id); - var edge = edges[id]; - if (edge) { - // update edge - edge.disconnect(); - edge.setProperties(data, this.constants); - edge.connect(); - } - else { - // create edge - edge = new Edge(data, this, this.constants); - this.edges[id] = edge; - } - } - - this.moving = true; - this._updateValueRange(edges); -}; - -/** - * Remove existing edges. Non existing ids will be ignored - * @param {Number[] | String[]} ids - * @private - */ -Graph.prototype._removeEdges = function (ids) { - var edges = this.edges; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - var edge = edges[id]; - if (edge) { - edge.disconnect(); - delete edges[id]; - } - } - - this.moving = true; - this._updateValueRange(edges); -}; - -/** - * Reconnect all edges - * @private - */ -Graph.prototype._reconnectEdges = function() { - var id, - nodes = this.nodes, - edges = this.edges; - for (id in nodes) { - if (nodes.hasOwnProperty(id)) { - nodes[id].edges = []; - } - } - - for (id in edges) { - if (edges.hasOwnProperty(id)) { - var edge = edges[id]; - edge.from = null; - edge.to = null; - edge.connect(); - } - } -}; - -/** - * Update the values of all object in the given array according to the current - * value range of the objects in the array. - * @param {Object} obj An object containing a set of Edges or Nodes - * The objects must have a method getValue() and - * setValueRange(min, max). - * @private - */ -Graph.prototype._updateValueRange = function(obj) { - var id; - - // determine the range of the objects - var valueMin = undefined; - var valueMax = undefined; - for (id in obj) { - if (obj.hasOwnProperty(id)) { - var value = obj[id].getValue(); - if (value !== undefined) { - valueMin = (valueMin === undefined) ? value : Math.min(value, valueMin); - valueMax = (valueMax === undefined) ? value : Math.max(value, valueMax); - } - } - } - - // adjust the range of all objects - if (valueMin !== undefined && valueMax !== undefined) { - for (id in obj) { - if (obj.hasOwnProperty(id)) { - obj[id].setValueRange(valueMin, valueMax); - } - } - } -}; - -/** - * Redraw the graph with the current data - * chart will be resized too. - */ -Graph.prototype.redraw = function() { - this.setSize(this.width, this.height); - - this._redraw(); -}; - -/** - * Redraw the graph with the current data - * @private - */ -Graph.prototype._redraw = function() { - var ctx = this.frame.canvas.getContext('2d'); - // clear the canvas - var w = this.frame.canvas.width; - var h = this.frame.canvas.height; - ctx.clearRect(0, 0, w, h); - - // set scaling and translation - ctx.save(); - ctx.translate(this.translation.x, this.translation.y); - ctx.scale(this.scale, this.scale); - - this.canvasTopLeft = { - "x": this._canvasToX(0), - "y": this._canvasToY(0) - }; - this.canvasBottomRight = { - "x": this._canvasToX(this.frame.canvas.clientWidth), - "y": this._canvasToY(this.frame.canvas.clientHeight) - }; - - this._doInAllSectors("_drawAllSectorNodes",ctx); - this._doInAllSectors("_drawEdges",ctx); - this._doInAllSectors("_drawNodes",ctx,true); - - this._drawTree(ctx,"#F00F0F"); - - // restore original scaling and translation - ctx.restore(); - - if (this.constants.navigation.enabled == true) { - this._doInNavigationSector("_drawNodes",ctx,true); - } -}; - -/** - * Set the translation of the graph - * @param {Number} offsetX Horizontal offset - * @param {Number} offsetY Vertical offset - * @private - */ -Graph.prototype._setTranslation = function(offsetX, offsetY) { - if (this.translation === undefined) { - this.translation = { - x: 0, - y: 0 - }; - } - - if (offsetX !== undefined) { - this.translation.x = offsetX; - } - if (offsetY !== undefined) { - this.translation.y = offsetY; - } -}; - -/** - * Get the translation of the graph - * @return {Object} translation An object with parameters x and y, both a number - * @private - */ -Graph.prototype._getTranslation = function() { - return { - x: this.translation.x, - y: this.translation.y - }; -}; - -/** - * Scale the graph - * @param {Number} scale Scaling factor 1.0 is unscaled - * @private - */ -Graph.prototype._setScale = function(scale) { - this.scale = scale; -}; - -/** - * Get the current scale of the graph - * @return {Number} scale Scaling factor 1.0 is unscaled - * @private - */ -Graph.prototype._getScale = function() { - return this.scale; -}; - -/** - * Convert a horizontal point on the HTML canvas to the x-value of the model - * @param {number} x - * @returns {number} - * @private - */ -Graph.prototype._canvasToX = function(x) { - return (x - this.translation.x) / this.scale; -}; - -/** - * Convert an x-value in the model to a horizontal point on the HTML canvas - * @param {number} x - * @returns {number} - * @private - */ -Graph.prototype._xToCanvas = function(x) { - return x * this.scale + this.translation.x; -}; - -/** - * Convert a vertical point on the HTML canvas to the y-value of the model - * @param {number} y - * @returns {number} - * @private - */ -Graph.prototype._canvasToY = function(y) { - return (y - this.translation.y) / this.scale; -}; - -/** - * Convert an y-value in the model to a vertical point on the HTML canvas - * @param {number} y - * @returns {number} - * @private - */ -Graph.prototype._yToCanvas = function(y) { - return y * this.scale + this.translation.y ; -}; - -/** - * Redraw all nodes - * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); - * @param {CanvasRenderingContext2D} ctx - * @param {Boolean} [alwaysShow] - * @private - */ -Graph.prototype._drawNodes = function(ctx,alwaysShow) { - if (alwaysShow === undefined) { - alwaysShow = false; - } - - // first draw the unselected nodes - var nodes = this.nodes; - var selected = []; - - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - nodes[id].setScaleAndPos(this.scale,this.canvasTopLeft,this.canvasBottomRight); - if (nodes[id].isSelected()) { - selected.push(id); - } - else { - if (nodes[id].inArea() || alwaysShow) { - nodes[id].draw(ctx); - } - } - } - } - - // draw the selected nodes on top - for (var s = 0, sMax = selected.length; s < sMax; s++) { - if (nodes[selected[s]].inArea() || alwaysShow) { - nodes[selected[s]].draw(ctx); - } - } -}; - -/** - * Redraw all edges - * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Graph.prototype._drawEdges = function(ctx) { - var edges = this.edges; - for (var id in edges) { - if (edges.hasOwnProperty(id)) { - var edge = edges[id]; - edge.setScale(this.scale); - if (edge.connected) { - edges[id].draw(ctx); - } - } - } -}; - -/** - * Find a stable position for all nodes - * @private - */ -Graph.prototype._doStabilize = function() { - //var start = new Date(); - - // find stable position - var count = 0; - var vmin = this.constants.minVelocity; - var stable = false; - while (!stable && count < this.constants.maxIterations) { - this._initializeForceCalculation(); - this._discreteStepNodes(); - stable = !this._isMoving(vmin); - count++; - } - this.zoomToFit(); -}; - - - - -/** - * Check if any of the nodes is still moving - * @param {number} vmin the minimum velocity considered as 'moving' - * @return {boolean} true if moving, false if non of the nodes is moving - * @private - */ -Graph.prototype._isMoving = function(vmin) { - var vminCorrected = vmin / this.scale; - var nodes = this.nodes; - for (var id in nodes) { - if (nodes.hasOwnProperty(id) && nodes[id].isMoving(vminCorrected)) { - return true; - } - } - return false; -}; - - -/** - * /** - * Perform one discrete step for all nodes - * - * @param interval - * @private - */ -Graph.prototype._discreteStepNodes = function() { - var interval = 0.5; - var nodes = this.nodes; - - this.constants.maxVelocity = 30; - - if (this.constants.maxVelocity > 0) { - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - nodes[id].discreteStepLimited(interval, this.constants.maxVelocity); - } - } - } - else { - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - nodes[id].discreteStep(interval); - } - } - } - var vmin = this.constants.minVelocity; - this.moving = this._isMoving(vmin); -}; - - - -/** - * Start animating nodes and edges - * - * @poram {Boolean} runCalculationStep - */ -Graph.prototype.start = function() { - if (!this.freezeSimulation) { - - if (this.moving) { - this._doInAllActiveSectors("_initializeForceCalculation"); - this._doInAllActiveSectors("_discreteStepNodes"); - this._findCenter(this._getRange()) - } - - if (this.moving || this.xIncrement != 0 || this.yIncrement != 0 || this.zoomIncrement != 0) { - // start animation. only start calculationTimer if it is not already running - if (!this.timer) { - var graph = this; - this.timer = window.setTimeout(function () { - graph.timer = undefined; - - // keyboad movement - if (graph.xIncrement != 0 || graph.yIncrement != 0) { - var translation = graph._getTranslation(); - graph._setTranslation(translation.x+graph.xIncrement, translation.y+graph.yIncrement); - } - if (graph.zoomIncrement != 0) { - var center = { - x: graph.frame.canvas.clientWidth / 2, - y: graph.frame.canvas.clientHeight / 2 - }; - graph._zoom(graph.scale*(1 + graph.zoomIncrement), center); - } - - - graph.start(); - graph.start(); - graph._redraw(); - - //this.end = window.performance.now(); - //this.time = this.end - this.startTime; - //console.log('refresh time: ' + this.time); - //this.startTime = window.performance.now(); - }, this.renderTimestep); - } - } - else { - this._redraw(); - } - } -}; - -/** - * Debug function, does one step of the graph - */ -Graph.prototype.singleStep = function() { - if (this.moving) { - this._initializeForceCalculation(true); - this._discreteStepNodes(); - - var vmin = this.constants.minVelocity; - this.moving = this._isMoving(vmin); - this._redraw(); - } -}; - - - -/** - * Freeze the animation - */ -Graph.prototype.toggleFreeze = function() { - if (this.freezeSimulation == false) { - this.freezeSimulation = true; - } - else { - this.freezeSimulation = false; - this.start(); - } -}; - - - -/** - * Mixin the physics system and initialize the parameters required. - * - * @private - */ -Graph.prototype._loadPhysicsSystem = function() { - for (var mixinFunction in physicsMixin) { - if (physicsMixin.hasOwnProperty(mixinFunction)) { - Graph.prototype[mixinFunction] = physicsMixin[mixinFunction]; - } - } -}; - - -/** - * Mixin the cluster system and initialize the parameters required. - * - * @private - */ -Graph.prototype._loadClusterSystem = function() { - this.clusterSession = 0; - this.hubThreshold = 5; - - for (var mixinFunction in ClusterMixin) { - if (ClusterMixin.hasOwnProperty(mixinFunction)) { - Graph.prototype[mixinFunction] = ClusterMixin[mixinFunction]; - } - } -} - -/** - * Mixin the sector system and initialize the parameters required - * - * @private - */ -Graph.prototype._loadSectorSystem = function() { - this.sectors = {}; - this.activeSector = ["default"]; - this.sectors["active"] = {}; - this.sectors["active"]["default"] = {"nodes":{}, - "edges":{}, - "nodeIndices":[], - "formationScale": 1.0, - "drawingNode": undefined}; - this.sectors["frozen"] = {}; - this.sectors["navigation"] = {"nodes":{}, - "edges":{}, - "nodeIndices":[], - "formationScale": 1.0, - "drawingNode": undefined}; - - this.nodeIndices = this.sectors["active"]["default"]["nodeIndices"]; // the node indices list is used to speed up the computation of the repulsion fields - for (var mixinFunction in SectorMixin) { - if (SectorMixin.hasOwnProperty(mixinFunction)) { - Graph.prototype[mixinFunction] = SectorMixin[mixinFunction]; - } - } -}; - - -/** - * Mixin the selection system and initialize the parameters required - * - * @private - */ -Graph.prototype._loadSelectionSystem = function() { - this.selectionObj = {}; - - for (var mixinFunction in SelectionMixin) { - if (SelectionMixin.hasOwnProperty(mixinFunction)) { - Graph.prototype[mixinFunction] = SelectionMixin[mixinFunction]; - } - } -} - - - -/** - * Mixin the navigationUI (User Interface) system and initialize the parameters required - * - * @private - */ -Graph.prototype._loadManipulationSystem = function() { - // reset global variables -- these are used by the selection of nodes and edges. - this.blockConnectingEdgeSelection = false; - this.forceAppendSelection = false - - - if (this.constants.dataManipulationToolbar.enabled == true) { - // load the manipulator HTML elements. All styling done in css. - if (this.manipulationDiv === undefined) { - this.manipulationDiv = document.createElement('div'); - this.manipulationDiv.className = 'graph-manipulationDiv'; - this.containerElement.insertBefore(this.manipulationDiv, this.frame); - } - // load the manipulation functions - for (var mixinFunction in manipulationMixin) { - if (manipulationMixin.hasOwnProperty(mixinFunction)) { - Graph.prototype[mixinFunction] = manipulationMixin[mixinFunction]; - } - } - - // create the manipulator toolbar - this._createManipulatorBar(); - } -} - -/** - * Mixin the navigation (User Interface) system and initialize the parameters required - * - * @private - */ -Graph.prototype._loadNavigationControls = function() { - for (var mixinFunction in NavigationMixin) { - if (NavigationMixin.hasOwnProperty(mixinFunction)) { - Graph.prototype[mixinFunction] = NavigationMixin[mixinFunction]; - } - } - - if (this.constants.navigation.enabled == true) { - this._loadNavigationElements(); - } -} - -/** - * this function exists to avoid errors when not loading the navigation system - */ -Graph.prototype._relocateNavigation = function() { - // empty, is overloaded by navigation system -} - -/** - * * this function exists to avoid errors when not loading the navigation system - */ -Graph.prototype._unHighlightAll = function() { - // empty, is overloaded by the navigation system -} - - - - - - - - - - - - - - - - - - - - - - - - - -/** - * vis.js module exports - */ -var vis = { - util: util, - events: events, - - Controller: Controller, - DataSet: DataSet, - DataView: DataView, - Range: Range, - Stack: Stack, - TimeStep: TimeStep, - EventBus: EventBus, - - components: { - items: { - Item: Item, - ItemBox: ItemBox, - ItemPoint: ItemPoint, - ItemRange: ItemRange - }, - - Component: Component, - Panel: Panel, - RootPanel: RootPanel, - ItemSet: ItemSet, - TimeAxis: TimeAxis - }, - - graph: { - Node: Node, - Edge: Edge, - Popup: Popup, - Groups: Groups, - Images: Images - }, - - Timeline: Timeline, - Graph: Graph -}; - -/** - * CommonJS module exports - */ -if (typeof exports !== 'undefined') { - exports = vis; -} -if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { - module.exports = vis; -} - -/** - * AMD module exports - */ -if (typeof(define) === 'function') { - define(function () { - return vis; - }); -} - -/** - * Window exports - */ -if (typeof window !== 'undefined') { - // attach the module to the window, load as a regular javascript file - window['vis'] = vis; -} - - -},{"hammerjs":2,"moment":3,"mousetrap":4}],2:[function(require,module,exports){ -/*! Hammer.JS - v1.0.5 - 2013-04-07 - * http://eightmedia.github.com/hammer.js - * - * Copyright (c) 2013 Jorik Tangelder ; - * Licensed under the MIT license */ - -(function(window, undefined) { - 'use strict'; - -/** - * Hammer - * use this to create instances - * @param {HTMLElement} element - * @param {Object} options - * @returns {Hammer.Instance} - * @constructor - */ -var Hammer = function(element, options) { - return new Hammer.Instance(element, options || {}); -}; - -// default settings -Hammer.defaults = { - // add styles and attributes to the element to prevent the browser from doing - // its native behavior. this doesnt prevent the scrolling, but cancels - // the contextmenu, tap highlighting etc - // set to false to disable this - stop_browser_behavior: { - // this also triggers onselectstart=false for IE - userSelect: 'none', - // this makes the element blocking in IE10 >, you could experiment with the value - // see for more options this issue; https://github.com/EightMedia/hammer.js/issues/241 - touchAction: 'none', - touchCallout: 'none', - contentZooming: 'none', - userDrag: 'none', - tapHighlightColor: 'rgba(0,0,0,0)' - } - - // more settings are defined per gesture at gestures.js -}; - -// detect touchevents -Hammer.HAS_POINTEREVENTS = navigator.pointerEnabled || navigator.msPointerEnabled; -Hammer.HAS_TOUCHEVENTS = ('ontouchstart' in window); - -// dont use mouseevents on mobile devices -Hammer.MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i; -Hammer.NO_MOUSEEVENTS = Hammer.HAS_TOUCHEVENTS && navigator.userAgent.match(Hammer.MOBILE_REGEX); - -// eventtypes per touchevent (start, move, end) -// are filled by Hammer.event.determineEventTypes on setup -Hammer.EVENT_TYPES = {}; - -// direction defines -Hammer.DIRECTION_DOWN = 'down'; -Hammer.DIRECTION_LEFT = 'left'; -Hammer.DIRECTION_UP = 'up'; -Hammer.DIRECTION_RIGHT = 'right'; - -// pointer type -Hammer.POINTER_MOUSE = 'mouse'; -Hammer.POINTER_TOUCH = 'touch'; -Hammer.POINTER_PEN = 'pen'; - -// touch event defines -Hammer.EVENT_START = 'start'; -Hammer.EVENT_MOVE = 'move'; -Hammer.EVENT_END = 'end'; - -// hammer document where the base events are added at -Hammer.DOCUMENT = document; - -// plugins namespace -Hammer.plugins = {}; - -// if the window events are set... -Hammer.READY = false; - -/** - * setup events to detect gestures on the document - */ -function setup() { - if(Hammer.READY) { - return; - } - - // find what eventtypes we add listeners to - Hammer.event.determineEventTypes(); - - // Register all gestures inside Hammer.gestures - for(var name in Hammer.gestures) { - if(Hammer.gestures.hasOwnProperty(name)) { - Hammer.detection.register(Hammer.gestures[name]); - } - } - - // Add touch events on the document - Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_MOVE, Hammer.detection.detect); - Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_END, Hammer.detection.detect); - - // Hammer is ready...! - Hammer.READY = true; -} - -/** - * create new hammer instance - * all methods should return the instance itself, so it is chainable. - * @param {HTMLElement} element - * @param {Object} [options={}] - * @returns {Hammer.Instance} - * @constructor - */ -Hammer.Instance = function(element, options) { - var self = this; - - // setup HammerJS window events and register all gestures - // this also sets up the default options - setup(); - - this.element = element; - - // start/stop detection option - this.enabled = true; - - // merge options - this.options = Hammer.utils.extend( - Hammer.utils.extend({}, Hammer.defaults), - options || {}); - - // add some css to the element to prevent the browser from doing its native behavoir - if(this.options.stop_browser_behavior) { - Hammer.utils.stopDefaultBrowserBehavior(this.element, this.options.stop_browser_behavior); - } - - // start detection on touchstart - Hammer.event.onTouch(element, Hammer.EVENT_START, function(ev) { - if(self.enabled) { - Hammer.detection.startDetect(self, ev); - } - }); - - // return instance - return this; -}; - - -Hammer.Instance.prototype = { - /** - * bind events to the instance - * @param {String} gesture - * @param {Function} handler - * @returns {Hammer.Instance} - */ - on: function onEvent(gesture, handler){ - var gestures = gesture.split(' '); - for(var t=0; t 0 && eventType == Hammer.EVENT_END) { - eventType = Hammer.EVENT_MOVE; - } - // no touches, force the end event - else if(!count_touches) { - eventType = Hammer.EVENT_END; - } - - // because touchend has no touches, and we often want to use these in our gestures, - // we send the last move event as our eventData in touchend - if(!count_touches && last_move_event !== null) { - ev = last_move_event; - } - // store the last move event - else { - last_move_event = ev; - } - - // trigger the handler - handler.call(Hammer.detection, self.collectEventData(element, eventType, ev)); - - // remove pointerevent from list - if(Hammer.HAS_POINTEREVENTS && eventType == Hammer.EVENT_END) { - count_touches = Hammer.PointerEvent.updatePointer(eventType, ev); - } - } - - //debug(sourceEventType +" "+ eventType); - - // on the end we reset everything - if(!count_touches) { - last_move_event = null; - enable_detect = false; - touch_triggered = false; - Hammer.PointerEvent.reset(); - } - }); - }, - - - /** - * we have different events for each device/browser - * determine what we need and set them in the Hammer.EVENT_TYPES constant - */ - determineEventTypes: function determineEventTypes() { - // determine the eventtype we want to set - var types; - - // pointerEvents magic - if(Hammer.HAS_POINTEREVENTS) { - types = Hammer.PointerEvent.getEvents(); - } - // on Android, iOS, blackberry, windows mobile we dont want any mouseevents - else if(Hammer.NO_MOUSEEVENTS) { - types = [ - 'touchstart', - 'touchmove', - 'touchend touchcancel']; - } - // for non pointer events browsers and mixed browsers, - // like chrome on windows8 touch laptop - else { - types = [ - 'touchstart mousedown', - 'touchmove mousemove', - 'touchend touchcancel mouseup']; - } - - Hammer.EVENT_TYPES[Hammer.EVENT_START] = types[0]; - Hammer.EVENT_TYPES[Hammer.EVENT_MOVE] = types[1]; - Hammer.EVENT_TYPES[Hammer.EVENT_END] = types[2]; - }, - - - /** - * create touchlist depending on the event - * @param {Object} ev - * @param {String} eventType used by the fakemultitouch plugin - */ - getTouchList: function getTouchList(ev/*, eventType*/) { - // get the fake pointerEvent touchlist - if(Hammer.HAS_POINTEREVENTS) { - return Hammer.PointerEvent.getTouchList(); - } - // get the touchlist - else if(ev.touches) { - return ev.touches; - } - // make fake touchlist from mouse position - else { - return [{ - identifier: 1, - pageX: ev.pageX, - pageY: ev.pageY, - target: ev.target - }]; - } - }, - - - /** - * collect event data for Hammer js - * @param {HTMLElement} element - * @param {String} eventType like Hammer.EVENT_MOVE - * @param {Object} eventData - */ - collectEventData: function collectEventData(element, eventType, ev) { - var touches = this.getTouchList(ev, eventType); - - // find out pointerType - var pointerType = Hammer.POINTER_TOUCH; - if(ev.type.match(/mouse/) || Hammer.PointerEvent.matchType(Hammer.POINTER_MOUSE, ev)) { - pointerType = Hammer.POINTER_MOUSE; - } - - return { - center : Hammer.utils.getCenter(touches), - timeStamp : new Date().getTime(), - target : ev.target, - touches : touches, - eventType : eventType, - pointerType : pointerType, - srcEvent : ev, - - /** - * prevent the browser default actions - * mostly used to disable scrolling of the browser - */ - preventDefault: function() { - if(this.srcEvent.preventManipulation) { - this.srcEvent.preventManipulation(); - } - - if(this.srcEvent.preventDefault) { - this.srcEvent.preventDefault(); - } - }, - - /** - * stop bubbling the event up to its parents - */ - stopPropagation: function() { - this.srcEvent.stopPropagation(); - }, - - /** - * immediately stop gesture detection - * might be useful after a swipe was detected - * @return {*} - */ - stopDetect: function() { - return Hammer.detection.stopDetect(); - } - }; - } -}; - -Hammer.PointerEvent = { - /** - * holds all pointers - * @type {Object} - */ - pointers: {}, - - /** - * get a list of pointers - * @returns {Array} touchlist - */ - getTouchList: function() { - var self = this; - var touchlist = []; - - // we can use forEach since pointerEvents only is in IE10 - Object.keys(self.pointers).sort().forEach(function(id) { - touchlist.push(self.pointers[id]); - }); - return touchlist; - }, - - /** - * update the position of a pointer - * @param {String} type Hammer.EVENT_END - * @param {Object} pointerEvent - */ - updatePointer: function(type, pointerEvent) { - if(type == Hammer.EVENT_END) { - this.pointers = {}; - } - else { - pointerEvent.identifier = pointerEvent.pointerId; - this.pointers[pointerEvent.pointerId] = pointerEvent; - } - - return Object.keys(this.pointers).length; - }, - - /** - * check if ev matches pointertype - * @param {String} pointerType Hammer.POINTER_MOUSE - * @param {PointerEvent} ev - */ - matchType: function(pointerType, ev) { - if(!ev.pointerType) { - return false; - } - - var types = {}; - types[Hammer.POINTER_MOUSE] = (ev.pointerType == ev.MSPOINTER_TYPE_MOUSE || ev.pointerType == Hammer.POINTER_MOUSE); - types[Hammer.POINTER_TOUCH] = (ev.pointerType == ev.MSPOINTER_TYPE_TOUCH || ev.pointerType == Hammer.POINTER_TOUCH); - types[Hammer.POINTER_PEN] = (ev.pointerType == ev.MSPOINTER_TYPE_PEN || ev.pointerType == Hammer.POINTER_PEN); - return types[pointerType]; - }, - - - /** - * get events - */ - getEvents: function() { - return [ - 'pointerdown MSPointerDown', - 'pointermove MSPointerMove', - 'pointerup pointercancel MSPointerUp MSPointerCancel' - ]; - }, - - /** - * reset the list - */ - reset: function() { - this.pointers = {}; - } -}; - - -Hammer.utils = { - /** - * extend method, - * also used for cloning when dest is an empty object - * @param {Object} dest - * @param {Object} src - * @parm {Boolean} merge do a merge - * @returns {Object} dest - */ - extend: function extend(dest, src, merge) { - for (var key in src) { - if(dest[key] !== undefined && merge) { - continue; - } - dest[key] = src[key]; - } - return dest; - }, - - - /** - * find if a node is in the given parent - * used for event delegation tricks - * @param {HTMLElement} node - * @param {HTMLElement} parent - * @returns {boolean} has_parent - */ - hasParent: function(node, parent) { - while(node){ - if(node == parent) { - return true; - } - node = node.parentNode; - } - return false; - }, - - - /** - * get the center of all the touches - * @param {Array} touches - * @returns {Object} center - */ - getCenter: function getCenter(touches) { - var valuesX = [], valuesY = []; - - for(var t= 0,len=touches.length; t= y) { - return touch1.pageX - touch2.pageX > 0 ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT; - } - else { - return touch1.pageY - touch2.pageY > 0 ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN; - } - }, - - - /** - * calculate the distance between two touches - * @param {Touch} touch1 - * @param {Touch} touch2 - * @returns {Number} distance - */ - getDistance: function getDistance(touch1, touch2) { - var x = touch2.pageX - touch1.pageX, - y = touch2.pageY - touch1.pageY; - return Math.sqrt((x*x) + (y*y)); - }, - - - /** - * calculate the scale factor between two touchLists (fingers) - * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out - * @param {Array} start - * @param {Array} end - * @returns {Number} scale - */ - getScale: function getScale(start, end) { - // need two fingers... - if(start.length >= 2 && end.length >= 2) { - return this.getDistance(end[0], end[1]) / - this.getDistance(start[0], start[1]); - } - return 1; - }, - - - /** - * calculate the rotation degrees between two touchLists (fingers) - * @param {Array} start - * @param {Array} end - * @returns {Number} rotation - */ - getRotation: function getRotation(start, end) { - // need two fingers - if(start.length >= 2 && end.length >= 2) { - return this.getAngle(end[1], end[0]) - - this.getAngle(start[1], start[0]); - } - return 0; - }, - - - /** - * boolean if the direction is vertical - * @param {String} direction - * @returns {Boolean} is_vertical - */ - isVertical: function isVertical(direction) { - return (direction == Hammer.DIRECTION_UP || direction == Hammer.DIRECTION_DOWN); - }, - - - /** - * stop browser default behavior with css props - * @param {HtmlElement} element - * @param {Object} css_props - */ - stopDefaultBrowserBehavior: function stopDefaultBrowserBehavior(element, css_props) { - var prop, - vendors = ['webkit','khtml','moz','ms','o','']; - - if(!css_props || !element.style) { - return; - } - - // with css properties for modern browsers - for(var i = 0; i < vendors.length; i++) { - for(var p in css_props) { - if(css_props.hasOwnProperty(p)) { - prop = p; - - // vender prefix at the property - if(vendors[i]) { - prop = vendors[i] + prop.substring(0, 1).toUpperCase() + prop.substring(1); - } - - // set the style - element.style[prop] = css_props[p]; - } - } - } - - // also the disable onselectstart - if(css_props.userSelect == 'none') { - element.onselectstart = function() { - return false; - }; - } - } -}; - -Hammer.detection = { - // contains all registred Hammer.gestures in the correct order - gestures: [], - - // data of the current Hammer.gesture detection session - current: null, - - // the previous Hammer.gesture session data - // is a full clone of the previous gesture.current object - previous: null, - - // when this becomes true, no gestures are fired - stopped: false, - - - /** - * start Hammer.gesture detection - * @param {Hammer.Instance} inst - * @param {Object} eventData - */ - startDetect: function startDetect(inst, eventData) { - // already busy with a Hammer.gesture detection on an element - if(this.current) { - return; - } - - this.stopped = false; - - this.current = { - inst : inst, // reference to HammerInstance we're working for - startEvent : Hammer.utils.extend({}, eventData), // start eventData for distances, timing etc - lastEvent : false, // last eventData - name : '' // current gesture we're in/detected, can be 'tap', 'hold' etc - }; - - this.detect(eventData); - }, - - - /** - * Hammer.gesture detection - * @param {Object} eventData - * @param {Object} eventData - */ - detect: function detect(eventData) { - if(!this.current || this.stopped) { - return; - } - - // extend event data with calculations about scale, distance etc - eventData = this.extendEventData(eventData); - - // instance options - var inst_options = this.current.inst.options; - - // call Hammer.gesture handlers - for(var g=0,len=this.gestures.length; g b.index) { - return 1; - } - return 0; - }); - - return this.gestures; - } -}; - - -Hammer.gestures = Hammer.gestures || {}; - -/** - * Custom gestures - * ============================== - * - * Gesture object - * -------------------- - * The object structure of a gesture: - * - * { name: 'mygesture', - * index: 1337, - * defaults: { - * mygesture_option: true - * } - * handler: function(type, ev, inst) { - * // trigger gesture event - * inst.trigger(this.name, ev); - * } - * } - - * @param {String} name - * this should be the name of the gesture, lowercase - * it is also being used to disable/enable the gesture per instance config. - * - * @param {Number} [index=1000] - * the index of the gesture, where it is going to be in the stack of gestures detection - * like when you build an gesture that depends on the drag gesture, it is a good - * idea to place it after the index of the drag gesture. - * - * @param {Object} [defaults={}] - * the default settings of the gesture. these are added to the instance settings, - * and can be overruled per instance. you can also add the name of the gesture, - * but this is also added by default (and set to true). - * - * @param {Function} handler - * this handles the gesture detection of your custom gesture and receives the - * following arguments: - * - * @param {Object} eventData - * event data containing the following properties: - * timeStamp {Number} time the event occurred - * target {HTMLElement} target element - * touches {Array} touches (fingers, pointers, mouse) on the screen - * pointerType {String} kind of pointer that was used. matches Hammer.POINTER_MOUSE|TOUCH - * center {Object} center position of the touches. contains pageX and pageY - * deltaTime {Number} the total time of the touches in the screen - * deltaX {Number} the delta on x axis we haved moved - * deltaY {Number} the delta on y axis we haved moved - * velocityX {Number} the velocity on the x - * velocityY {Number} the velocity on y - * angle {Number} the angle we are moving - * direction {String} the direction we are moving. matches Hammer.DIRECTION_UP|DOWN|LEFT|RIGHT - * distance {Number} the distance we haved moved - * scale {Number} scaling of the touches, needs 2 touches - * rotation {Number} rotation of the touches, needs 2 touches * - * eventType {String} matches Hammer.EVENT_START|MOVE|END - * srcEvent {Object} the source event, like TouchStart or MouseDown * - * startEvent {Object} contains the same properties as above, - * but from the first touch. this is used to calculate - * distances, deltaTime, scaling etc - * - * @param {Hammer.Instance} inst - * the instance we are doing the detection for. you can get the options from - * the inst.options object and trigger the gesture event by calling inst.trigger - * - * - * Handle gestures - * -------------------- - * inside the handler you can get/set Hammer.detection.current. This is the current - * detection session. It has the following properties - * @param {String} name - * contains the name of the gesture we have detected. it has not a real function, - * only to check in other gestures if something is detected. - * like in the drag gesture we set it to 'drag' and in the swipe gesture we can - * check if the current gesture is 'drag' by accessing Hammer.detection.current.name - * - * @readonly - * @param {Hammer.Instance} inst - * the instance we do the detection for - * - * @readonly - * @param {Object} startEvent - * contains the properties of the first gesture detection in this session. - * Used for calculations about timing, distance, etc. - * - * @readonly - * @param {Object} lastEvent - * contains all the properties of the last gesture detect in this session. - * - * after the gesture detection session has been completed (user has released the screen) - * the Hammer.detection.current object is copied into Hammer.detection.previous, - * this is usefull for gestures like doubletap, where you need to know if the - * previous gesture was a tap - * - * options that have been set by the instance can be received by calling inst.options - * - * You can trigger a gesture event by calling inst.trigger("mygesture", event). - * The first param is the name of your gesture, the second the event argument - * - * - * Register gestures - * -------------------- - * When an gesture is added to the Hammer.gestures object, it is auto registered - * at the setup of the first Hammer instance. You can also call Hammer.detection.register - * manually and pass your gesture object as a param - * - */ - -/** - * Hold - * Touch stays at the same place for x time - * @events hold - */ -Hammer.gestures.Hold = { - name: 'hold', - index: 10, - defaults: { - hold_timeout : 500, - hold_threshold : 1 - }, - timer: null, - handler: function holdGesture(ev, inst) { - switch(ev.eventType) { - case Hammer.EVENT_START: - // clear any running timers - clearTimeout(this.timer); - - // set the gesture so we can check in the timeout if it still is - Hammer.detection.current.name = this.name; - - // set timer and if after the timeout it still is hold, - // we trigger the hold event - this.timer = setTimeout(function() { - if(Hammer.detection.current.name == 'hold') { - inst.trigger('hold', ev); - } - }, inst.options.hold_timeout); - break; - - // when you move or end we clear the timer - case Hammer.EVENT_MOVE: - if(ev.distance > inst.options.hold_threshold) { - clearTimeout(this.timer); - } - break; - - case Hammer.EVENT_END: - clearTimeout(this.timer); - break; - } - } -}; - - -/** - * Tap/DoubleTap - * Quick touch at a place or double at the same place - * @events tap, doubletap - */ -Hammer.gestures.Tap = { - name: 'tap', - index: 100, - defaults: { - tap_max_touchtime : 250, - tap_max_distance : 10, - tap_always : true, - doubletap_distance : 20, - doubletap_interval : 300 - }, - handler: function tapGesture(ev, inst) { - if(ev.eventType == Hammer.EVENT_END) { - // previous gesture, for the double tap since these are two different gesture detections - var prev = Hammer.detection.previous, - did_doubletap = false; - - // when the touchtime is higher then the max touch time - // or when the moving distance is too much - if(ev.deltaTime > inst.options.tap_max_touchtime || - ev.distance > inst.options.tap_max_distance) { - return; - } - - // check if double tap - if(prev && prev.name == 'tap' && - (ev.timeStamp - prev.lastEvent.timeStamp) < inst.options.doubletap_interval && - ev.distance < inst.options.doubletap_distance) { - inst.trigger('doubletap', ev); - did_doubletap = true; - } - - // do a single tap - if(!did_doubletap || inst.options.tap_always) { - Hammer.detection.current.name = 'tap'; - inst.trigger(Hammer.detection.current.name, ev); - } - } - } -}; - - -/** - * Swipe - * triggers swipe events when the end velocity is above the threshold - * @events swipe, swipeleft, swiperight, swipeup, swipedown - */ -Hammer.gestures.Swipe = { - name: 'swipe', - index: 40, - defaults: { - // set 0 for unlimited, but this can conflict with transform - swipe_max_touches : 1, - swipe_velocity : 0.7 - }, - handler: function swipeGesture(ev, inst) { - if(ev.eventType == Hammer.EVENT_END) { - // max touches - if(inst.options.swipe_max_touches > 0 && - ev.touches.length > inst.options.swipe_max_touches) { - return; - } - - // when the distance we moved is too small we skip this gesture - // or we can be already in dragging - if(ev.velocityX > inst.options.swipe_velocity || - ev.velocityY > inst.options.swipe_velocity) { - // trigger swipe events - inst.trigger(this.name, ev); - inst.trigger(this.name + ev.direction, ev); - } - } - } -}; - - -/** - * Drag - * Move with x fingers (default 1) around on the page. Blocking the scrolling when - * moving left and right is a good practice. When all the drag events are blocking - * you disable scrolling on that area. - * @events drag, drapleft, dragright, dragup, dragdown - */ -Hammer.gestures.Drag = { - name: 'drag', - index: 50, - defaults: { - drag_min_distance : 10, - // set 0 for unlimited, but this can conflict with transform - drag_max_touches : 1, - // prevent default browser behavior when dragging occurs - // be careful with it, it makes the element a blocking element - // when you are using the drag gesture, it is a good practice to set this true - drag_block_horizontal : false, - drag_block_vertical : false, - // drag_lock_to_axis keeps the drag gesture on the axis that it started on, - // It disallows vertical directions if the initial direction was horizontal, and vice versa. - drag_lock_to_axis : false, - // drag lock only kicks in when distance > drag_lock_min_distance - // This way, locking occurs only when the distance has become large enough to reliably determine the direction - drag_lock_min_distance : 25 - }, - triggered: false, - handler: function dragGesture(ev, inst) { - // current gesture isnt drag, but dragged is true - // this means an other gesture is busy. now call dragend - if(Hammer.detection.current.name != this.name && this.triggered) { - inst.trigger(this.name +'end', ev); - this.triggered = false; - return; - } - - // max touches - if(inst.options.drag_max_touches > 0 && - ev.touches.length > inst.options.drag_max_touches) { - return; - } - - switch(ev.eventType) { - case Hammer.EVENT_START: - this.triggered = false; - break; - - case Hammer.EVENT_MOVE: - // when the distance we moved is too small we skip this gesture - // or we can be already in dragging - if(ev.distance < inst.options.drag_min_distance && - Hammer.detection.current.name != this.name) { - return; - } - - // we are dragging! - Hammer.detection.current.name = this.name; - - // lock drag to axis? - if(Hammer.detection.current.lastEvent.drag_locked_to_axis || (inst.options.drag_lock_to_axis && inst.options.drag_lock_min_distance<=ev.distance)) { - ev.drag_locked_to_axis = true; - } - var last_direction = Hammer.detection.current.lastEvent.direction; - if(ev.drag_locked_to_axis && last_direction !== ev.direction) { - // keep direction on the axis that the drag gesture started on - if(Hammer.utils.isVertical(last_direction)) { - ev.direction = (ev.deltaY < 0) ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN; - } - else { - ev.direction = (ev.deltaX < 0) ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT; - } - } - - // first time, trigger dragstart event - if(!this.triggered) { - inst.trigger(this.name +'start', ev); - this.triggered = true; - } - - // trigger normal event - inst.trigger(this.name, ev); - - // direction event, like dragdown - inst.trigger(this.name + ev.direction, ev); - - // block the browser events - if( (inst.options.drag_block_vertical && Hammer.utils.isVertical(ev.direction)) || - (inst.options.drag_block_horizontal && !Hammer.utils.isVertical(ev.direction))) { - ev.preventDefault(); - } - break; - - case Hammer.EVENT_END: - // trigger dragend - if(this.triggered) { - inst.trigger(this.name +'end', ev); - } - - this.triggered = false; - break; - } - } -}; - - -/** - * Transform - * User want to scale or rotate with 2 fingers - * @events transform, pinch, pinchin, pinchout, rotate - */ -Hammer.gestures.Transform = { - name: 'transform', - index: 45, - defaults: { - // factor, no scale is 1, zoomin is to 0 and zoomout until higher then 1 - transform_min_scale : 0.01, - // rotation in degrees - transform_min_rotation : 1, - // prevent default browser behavior when two touches are on the screen - // but it makes the element a blocking element - // when you are using the transform gesture, it is a good practice to set this true - transform_always_block : false - }, - triggered: false, - handler: function transformGesture(ev, inst) { - // current gesture isnt drag, but dragged is true - // this means an other gesture is busy. now call dragend - if(Hammer.detection.current.name != this.name && this.triggered) { - inst.trigger(this.name +'end', ev); - this.triggered = false; - return; - } - - // atleast multitouch - if(ev.touches.length < 2) { - return; - } - - // prevent default when two fingers are on the screen - if(inst.options.transform_always_block) { - ev.preventDefault(); - } - - switch(ev.eventType) { - case Hammer.EVENT_START: - this.triggered = false; - break; - - case Hammer.EVENT_MOVE: - var scale_threshold = Math.abs(1-ev.scale); - var rotation_threshold = Math.abs(ev.rotation); - - // when the distance we moved is too small we skip this gesture - // or we can be already in dragging - if(scale_threshold < inst.options.transform_min_scale && - rotation_threshold < inst.options.transform_min_rotation) { - return; - } - - // we are transforming! - Hammer.detection.current.name = this.name; - - // first time, trigger dragstart event - if(!this.triggered) { - inst.trigger(this.name +'start', ev); - this.triggered = true; - } - - inst.trigger(this.name, ev); // basic transform event - - // trigger rotate event - if(rotation_threshold > inst.options.transform_min_rotation) { - inst.trigger('rotate', ev); - } - - // trigger pinch event - if(scale_threshold > inst.options.transform_min_scale) { - inst.trigger('pinch', ev); - inst.trigger('pinch'+ ((ev.scale < 1) ? 'in' : 'out'), ev); - } - break; - - case Hammer.EVENT_END: - // trigger dragend - if(this.triggered) { - inst.trigger(this.name +'end', ev); - } - - this.triggered = false; - break; - } - } -}; - - -/** - * Touch - * Called as first, tells the user has touched the screen - * @events touch - */ -Hammer.gestures.Touch = { - name: 'touch', - index: -Infinity, - defaults: { - // call preventDefault at touchstart, and makes the element blocking by - // disabling the scrolling of the page, but it improves gestures like - // transforming and dragging. - // be careful with using this, it can be very annoying for users to be stuck - // on the page - prevent_default: false, - - // disable mouse events, so only touch (or pen!) input triggers events - prevent_mouseevents: false - }, - handler: function touchGesture(ev, inst) { - if(inst.options.prevent_mouseevents && ev.pointerType == Hammer.POINTER_MOUSE) { - ev.stopDetect(); - return; - } - - if(inst.options.prevent_default) { - ev.preventDefault(); - } - - if(ev.eventType == Hammer.EVENT_START) { - inst.trigger(this.name, ev); - } - } -}; - - -/** - * Release - * Called as last, tells the user has released the screen - * @events release - */ -Hammer.gestures.Release = { - name: 'release', - index: Infinity, - handler: function releaseGesture(ev, inst) { - if(ev.eventType == Hammer.EVENT_END) { - inst.trigger(this.name, ev); - } - } -}; - -// node export -if(typeof module === 'object' && typeof module.exports === 'object'){ - module.exports = Hammer; -} -// just window export -else { - window.Hammer = Hammer; - - // requireJS module definition - if(typeof window.define === 'function' && window.define.amd) { - window.define('hammer', [], function() { - return Hammer; - }); - } -} -})(this); -},{}],3:[function(require,module,exports){ -//! moment.js -//! version : 2.5.1 -//! authors : Tim Wood, Iskren Chernev, Moment.js contributors -//! license : MIT -//! momentjs.com - -(function (undefined) { - - /************************************ - Constants - ************************************/ - - var moment, - VERSION = "2.5.1", - global = this, - round = Math.round, - i, - - YEAR = 0, - MONTH = 1, - DATE = 2, - HOUR = 3, - MINUTE = 4, - SECOND = 5, - MILLISECOND = 6, - - // internal storage for language config files - languages = {}, - - // moment internal properties - momentProperties = { - _isAMomentObject: null, - _i : null, - _f : null, - _l : null, - _strict : null, - _isUTC : null, - _offset : null, // optional. Combine with _isUTC - _pf : null, - _lang : null // optional - }, - - // check for nodeJS - hasModule = (typeof module !== 'undefined' && module.exports && typeof require !== 'undefined'), - - // ASP.NET json date format regex - aspNetJsonRegex = /^\/?Date\((\-?\d+)/i, - aspNetTimeSpanJsonRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/, - - // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html - // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere - isoDurationRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/, - - // format tokens - formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g, - localFormattingTokens = /(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g, - - // parsing token regexes - parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99 - parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999 - parseTokenOneToFourDigits = /\d{1,4}/, // 0 - 9999 - parseTokenOneToSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999 - parseTokenDigits = /\d+/, // nonzero number of digits - parseTokenWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, // any word (or two) characters or numbers including two/three word month in arabic. - parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z - parseTokenT = /T/i, // T (ISO separator) - parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123 - - //strict parsing regexes - parseTokenOneDigit = /\d/, // 0 - 9 - parseTokenTwoDigits = /\d\d/, // 00 - 99 - parseTokenThreeDigits = /\d{3}/, // 000 - 999 - parseTokenFourDigits = /\d{4}/, // 0000 - 9999 - parseTokenSixDigits = /[+-]?\d{6}/, // -999,999 - 999,999 - parseTokenSignedNumber = /[+-]?\d+/, // -inf - inf - - // iso 8601 regex - // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00) - isoRegex = /^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/, - - isoFormat = 'YYYY-MM-DDTHH:mm:ssZ', - - isoDates = [ - ['YYYYYY-MM-DD', /[+-]\d{6}-\d{2}-\d{2}/], - ['YYYY-MM-DD', /\d{4}-\d{2}-\d{2}/], - ['GGGG-[W]WW-E', /\d{4}-W\d{2}-\d/], - ['GGGG-[W]WW', /\d{4}-W\d{2}/], - ['YYYY-DDD', /\d{4}-\d{3}/] - ], - - // iso time formats and regexes - isoTimes = [ - ['HH:mm:ss.SSSS', /(T| )\d\d:\d\d:\d\d\.\d{1,3}/], - ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/], - ['HH:mm', /(T| )\d\d:\d\d/], - ['HH', /(T| )\d\d/] - ], - - // timezone chunker "+10:00" > ["10", "00"] or "-1530" > ["-15", "30"] - parseTimezoneChunker = /([\+\-]|\d\d)/gi, - - // getter and setter names - proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'), - unitMillisecondFactors = { - 'Milliseconds' : 1, - 'Seconds' : 1e3, - 'Minutes' : 6e4, - 'Hours' : 36e5, - 'Days' : 864e5, - 'Months' : 2592e6, - 'Years' : 31536e6 - }, - - unitAliases = { - ms : 'millisecond', - s : 'second', - m : 'minute', - h : 'hour', - d : 'day', - D : 'date', - w : 'week', - W : 'isoWeek', - M : 'month', - y : 'year', - DDD : 'dayOfYear', - e : 'weekday', - E : 'isoWeekday', - gg: 'weekYear', - GG: 'isoWeekYear' - }, - - camelFunctions = { - dayofyear : 'dayOfYear', - isoweekday : 'isoWeekday', - isoweek : 'isoWeek', - weekyear : 'weekYear', - isoweekyear : 'isoWeekYear' - }, - - // format function strings - formatFunctions = {}, - - // tokens to ordinalize and pad - ordinalizeTokens = 'DDD w W M D d'.split(' '), - paddedTokens = 'M D H h m s w W'.split(' '), - - formatTokenFunctions = { - M : function () { - return this.month() + 1; - }, - MMM : function (format) { - return this.lang().monthsShort(this, format); - }, - MMMM : function (format) { - return this.lang().months(this, format); - }, - D : function () { - return this.date(); - }, - DDD : function () { - return this.dayOfYear(); - }, - d : function () { - return this.day(); - }, - dd : function (format) { - return this.lang().weekdaysMin(this, format); - }, - ddd : function (format) { - return this.lang().weekdaysShort(this, format); - }, - dddd : function (format) { - return this.lang().weekdays(this, format); - }, - w : function () { - return this.week(); - }, - W : function () { - return this.isoWeek(); - }, - YY : function () { - return leftZeroFill(this.year() % 100, 2); - }, - YYYY : function () { - return leftZeroFill(this.year(), 4); - }, - YYYYY : function () { - return leftZeroFill(this.year(), 5); - }, - YYYYYY : function () { - var y = this.year(), sign = y >= 0 ? '+' : '-'; - return sign + leftZeroFill(Math.abs(y), 6); - }, - gg : function () { - return leftZeroFill(this.weekYear() % 100, 2); - }, - gggg : function () { - return leftZeroFill(this.weekYear(), 4); - }, - ggggg : function () { - return leftZeroFill(this.weekYear(), 5); - }, - GG : function () { - return leftZeroFill(this.isoWeekYear() % 100, 2); - }, - GGGG : function () { - return leftZeroFill(this.isoWeekYear(), 4); - }, - GGGGG : function () { - return leftZeroFill(this.isoWeekYear(), 5); - }, - e : function () { - return this.weekday(); - }, - E : function () { - return this.isoWeekday(); - }, - a : function () { - return this.lang().meridiem(this.hours(), this.minutes(), true); - }, - A : function () { - return this.lang().meridiem(this.hours(), this.minutes(), false); - }, - H : function () { - return this.hours(); - }, - h : function () { - return this.hours() % 12 || 12; - }, - m : function () { - return this.minutes(); - }, - s : function () { - return this.seconds(); - }, - S : function () { - return toInt(this.milliseconds() / 100); - }, - SS : function () { - return leftZeroFill(toInt(this.milliseconds() / 10), 2); - }, - SSS : function () { - return leftZeroFill(this.milliseconds(), 3); - }, - SSSS : function () { - return leftZeroFill(this.milliseconds(), 3); - }, - Z : function () { - var a = -this.zone(), - b = "+"; - if (a < 0) { - a = -a; - b = "-"; - } - return b + leftZeroFill(toInt(a / 60), 2) + ":" + leftZeroFill(toInt(a) % 60, 2); - }, - ZZ : function () { - var a = -this.zone(), - b = "+"; - if (a < 0) { - a = -a; - b = "-"; - } - return b + leftZeroFill(toInt(a / 60), 2) + leftZeroFill(toInt(a) % 60, 2); - }, - z : function () { - return this.zoneAbbr(); - }, - zz : function () { - return this.zoneName(); - }, - X : function () { - return this.unix(); - }, - Q : function () { - return this.quarter(); - } - }, - - lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin']; - - function defaultParsingFlags() { - // We need to deep clone this object, and es5 standard is not very - // helpful. - return { - empty : false, - unusedTokens : [], - unusedInput : [], - overflow : -2, - charsLeftOver : 0, - nullInput : false, - invalidMonth : null, - invalidFormat : false, - userInvalidated : false, - iso: false - }; - } - - function padToken(func, count) { - return function (a) { - return leftZeroFill(func.call(this, a), count); - }; - } - function ordinalizeToken(func, period) { - return function (a) { - return this.lang().ordinal(func.call(this, a), period); - }; - } - - while (ordinalizeTokens.length) { - i = ordinalizeTokens.pop(); - formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i); - } - while (paddedTokens.length) { - i = paddedTokens.pop(); - formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2); - } - formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3); - - - /************************************ - Constructors - ************************************/ - - function Language() { - - } - - // Moment prototype object - function Moment(config) { - checkOverflow(config); - extend(this, config); - } - - // Duration Constructor - function Duration(duration) { - var normalizedInput = normalizeObjectUnits(duration), - years = normalizedInput.year || 0, - months = normalizedInput.month || 0, - weeks = normalizedInput.week || 0, - days = normalizedInput.day || 0, - hours = normalizedInput.hour || 0, - minutes = normalizedInput.minute || 0, - seconds = normalizedInput.second || 0, - milliseconds = normalizedInput.millisecond || 0; - - // representation for dateAddRemove - this._milliseconds = +milliseconds + - seconds * 1e3 + // 1000 - minutes * 6e4 + // 1000 * 60 - hours * 36e5; // 1000 * 60 * 60 - // Because of dateAddRemove treats 24 hours as different from a - // day when working around DST, we need to store them separately - this._days = +days + - weeks * 7; - // It is impossible translate months into days without knowing - // which months you are are talking about, so we have to store - // it separately. - this._months = +months + - years * 12; - - this._data = {}; - - this._bubble(); - } - - /************************************ - Helpers - ************************************/ - - - function extend(a, b) { - for (var i in b) { - if (b.hasOwnProperty(i)) { - a[i] = b[i]; - } - } - - if (b.hasOwnProperty("toString")) { - a.toString = b.toString; - } - - if (b.hasOwnProperty("valueOf")) { - a.valueOf = b.valueOf; - } - - return a; - } - - function cloneMoment(m) { - var result = {}, i; - for (i in m) { - if (m.hasOwnProperty(i) && momentProperties.hasOwnProperty(i)) { - result[i] = m[i]; - } - } - - return result; - } - - function absRound(number) { - if (number < 0) { - return Math.ceil(number); - } else { - return Math.floor(number); - } - } - - // left zero fill a number - // see http://jsperf.com/left-zero-filling for performance comparison - function leftZeroFill(number, targetLength, forceSign) { - var output = '' + Math.abs(number), - sign = number >= 0; - - while (output.length < targetLength) { - output = '0' + output; - } - return (sign ? (forceSign ? '+' : '') : '-') + output; - } - - // helper function for _.addTime and _.subtractTime - function addOrSubtractDurationFromMoment(mom, duration, isAdding, ignoreUpdateOffset) { - var milliseconds = duration._milliseconds, - days = duration._days, - months = duration._months, - minutes, - hours; - - if (milliseconds) { - mom._d.setTime(+mom._d + milliseconds * isAdding); - } - // store the minutes and hours so we can restore them - if (days || months) { - minutes = mom.minute(); - hours = mom.hour(); - } - if (days) { - mom.date(mom.date() + days * isAdding); - } - if (months) { - mom.month(mom.month() + months * isAdding); - } - if (milliseconds && !ignoreUpdateOffset) { - moment.updateOffset(mom); - } - // restore the minutes and hours after possibly changing dst - if (days || months) { - mom.minute(minutes); - mom.hour(hours); - } - } - - // check if is an array - function isArray(input) { - return Object.prototype.toString.call(input) === '[object Array]'; - } - - function isDate(input) { - return Object.prototype.toString.call(input) === '[object Date]' || - input instanceof Date; - } - - // compare two arrays, return the number of differences - function compareArrays(array1, array2, dontConvert) { - var len = Math.min(array1.length, array2.length), - lengthDiff = Math.abs(array1.length - array2.length), - diffs = 0, - i; - for (i = 0; i < len; i++) { - if ((dontConvert && array1[i] !== array2[i]) || - (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) { - diffs++; - } - } - return diffs + lengthDiff; - } - - function normalizeUnits(units) { - if (units) { - var lowered = units.toLowerCase().replace(/(.)s$/, '$1'); - units = unitAliases[units] || camelFunctions[lowered] || lowered; - } - return units; - } - - function normalizeObjectUnits(inputObject) { - var normalizedInput = {}, - normalizedProp, - prop; - - for (prop in inputObject) { - if (inputObject.hasOwnProperty(prop)) { - normalizedProp = normalizeUnits(prop); - if (normalizedProp) { - normalizedInput[normalizedProp] = inputObject[prop]; - } - } - } - - return normalizedInput; - } - - function makeList(field) { - var count, setter; - - if (field.indexOf('week') === 0) { - count = 7; - setter = 'day'; - } - else if (field.indexOf('month') === 0) { - count = 12; - setter = 'month'; - } - else { - return; - } - - moment[field] = function (format, index) { - var i, getter, - method = moment.fn._lang[field], - results = []; - - if (typeof format === 'number') { - index = format; - format = undefined; - } - - getter = function (i) { - var m = moment().utc().set(setter, i); - return method.call(moment.fn._lang, m, format || ''); - }; - - if (index != null) { - return getter(index); - } - else { - for (i = 0; i < count; i++) { - results.push(getter(i)); - } - return results; - } - }; - } - - function toInt(argumentForCoercion) { - var coercedNumber = +argumentForCoercion, - value = 0; - - if (coercedNumber !== 0 && isFinite(coercedNumber)) { - if (coercedNumber >= 0) { - value = Math.floor(coercedNumber); - } else { - value = Math.ceil(coercedNumber); - } - } - - return value; - } - - function daysInMonth(year, month) { - return new Date(Date.UTC(year, month + 1, 0)).getUTCDate(); - } - - function daysInYear(year) { - return isLeapYear(year) ? 366 : 365; - } - - function isLeapYear(year) { - return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; - } - - function checkOverflow(m) { - var overflow; - if (m._a && m._pf.overflow === -2) { - overflow = - m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH : - m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE : - m._a[HOUR] < 0 || m._a[HOUR] > 23 ? HOUR : - m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE : - m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND : - m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND : - -1; - - if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) { - overflow = DATE; - } - - m._pf.overflow = overflow; - } - } - - function isValid(m) { - if (m._isValid == null) { - m._isValid = !isNaN(m._d.getTime()) && - m._pf.overflow < 0 && - !m._pf.empty && - !m._pf.invalidMonth && - !m._pf.nullInput && - !m._pf.invalidFormat && - !m._pf.userInvalidated; - - if (m._strict) { - m._isValid = m._isValid && - m._pf.charsLeftOver === 0 && - m._pf.unusedTokens.length === 0; - } - } - return m._isValid; - } - - function normalizeLanguage(key) { - return key ? key.toLowerCase().replace('_', '-') : key; - } - - // Return a moment from input, that is local/utc/zone equivalent to model. - function makeAs(input, model) { - return model._isUTC ? moment(input).zone(model._offset || 0) : - moment(input).local(); - } - - /************************************ - Languages - ************************************/ - - - extend(Language.prototype, { - - set : function (config) { - var prop, i; - for (i in config) { - prop = config[i]; - if (typeof prop === 'function') { - this[i] = prop; - } else { - this['_' + i] = prop; - } - } - }, - - _months : "January_February_March_April_May_June_July_August_September_October_November_December".split("_"), - months : function (m) { - return this._months[m.month()]; - }, - - _monthsShort : "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"), - monthsShort : function (m) { - return this._monthsShort[m.month()]; - }, - - monthsParse : function (monthName) { - var i, mom, regex; - - if (!this._monthsParse) { - this._monthsParse = []; - } - - for (i = 0; i < 12; i++) { - // make the regex if we don't have it already - if (!this._monthsParse[i]) { - mom = moment.utc([2000, i]); - regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); - this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); - } - // test the regex - if (this._monthsParse[i].test(monthName)) { - return i; - } - } - }, - - _weekdays : "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), - weekdays : function (m) { - return this._weekdays[m.day()]; - }, - - _weekdaysShort : "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"), - weekdaysShort : function (m) { - return this._weekdaysShort[m.day()]; - }, - - _weekdaysMin : "Su_Mo_Tu_We_Th_Fr_Sa".split("_"), - weekdaysMin : function (m) { - return this._weekdaysMin[m.day()]; - }, - - weekdaysParse : function (weekdayName) { - var i, mom, regex; - - if (!this._weekdaysParse) { - this._weekdaysParse = []; - } - - for (i = 0; i < 7; i++) { - // make the regex if we don't have it already - if (!this._weekdaysParse[i]) { - mom = moment([2000, 1]).day(i); - regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); - this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); - } - // test the regex - if (this._weekdaysParse[i].test(weekdayName)) { - return i; - } - } - }, - - _longDateFormat : { - LT : "h:mm A", - L : "MM/DD/YYYY", - LL : "MMMM D YYYY", - LLL : "MMMM D YYYY LT", - LLLL : "dddd, MMMM D YYYY LT" - }, - longDateFormat : function (key) { - var output = this._longDateFormat[key]; - if (!output && this._longDateFormat[key.toUpperCase()]) { - output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) { - return val.slice(1); - }); - this._longDateFormat[key] = output; - } - return output; - }, - - isPM : function (input) { - // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays - // Using charAt should be more compatible. - return ((input + '').toLowerCase().charAt(0) === 'p'); - }, - - _meridiemParse : /[ap]\.?m?\.?/i, - meridiem : function (hours, minutes, isLower) { - if (hours > 11) { - return isLower ? 'pm' : 'PM'; - } else { - return isLower ? 'am' : 'AM'; - } - }, - - _calendar : { - sameDay : '[Today at] LT', - nextDay : '[Tomorrow at] LT', - nextWeek : 'dddd [at] LT', - lastDay : '[Yesterday at] LT', - lastWeek : '[Last] dddd [at] LT', - sameElse : 'L' - }, - calendar : function (key, mom) { - var output = this._calendar[key]; - return typeof output === 'function' ? output.apply(mom) : output; - }, - - _relativeTime : { - future : "in %s", - past : "%s ago", - s : "a few seconds", - m : "a minute", - mm : "%d minutes", - h : "an hour", - hh : "%d hours", - d : "a day", - dd : "%d days", - M : "a month", - MM : "%d months", - y : "a year", - yy : "%d years" - }, - relativeTime : function (number, withoutSuffix, string, isFuture) { - var output = this._relativeTime[string]; - return (typeof output === 'function') ? - output(number, withoutSuffix, string, isFuture) : - output.replace(/%d/i, number); - }, - pastFuture : function (diff, output) { - var format = this._relativeTime[diff > 0 ? 'future' : 'past']; - return typeof format === 'function' ? format(output) : format.replace(/%s/i, output); - }, - - ordinal : function (number) { - return this._ordinal.replace("%d", number); - }, - _ordinal : "%d", - - preparse : function (string) { - return string; - }, - - postformat : function (string) { - return string; - }, - - week : function (mom) { - return weekOfYear(mom, this._week.dow, this._week.doy).week; - }, - - _week : { - dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. - }, - - _invalidDate: 'Invalid date', - invalidDate: function () { - return this._invalidDate; - } - }); - - // Loads a language definition into the `languages` cache. The function - // takes a key and optionally values. If not in the browser and no values - // are provided, it will load the language file module. As a convenience, - // this function also returns the language values. - function loadLang(key, values) { - values.abbr = key; - if (!languages[key]) { - languages[key] = new Language(); - } - languages[key].set(values); - return languages[key]; - } - - // Remove a language from the `languages` cache. Mostly useful in tests. - function unloadLang(key) { - delete languages[key]; - } - - // Determines which language definition to use and returns it. - // - // With no parameters, it will return the global language. If you - // pass in a language key, such as 'en', it will return the - // definition for 'en', so long as 'en' has already been loaded using - // moment.lang. - function getLangDefinition(key) { - var i = 0, j, lang, next, split, - get = function (k) { - if (!languages[k] && hasModule) { - try { - require('./lang/' + k); - } catch (e) { } - } - return languages[k]; - }; - - if (!key) { - return moment.fn._lang; - } - - if (!isArray(key)) { - //short-circuit everything else - lang = get(key); - if (lang) { - return lang; - } - key = [key]; - } - - //pick the language from the array - //try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each - //substring from most specific to least, but move to the next array item if it's a more specific variant than the current root - while (i < key.length) { - split = normalizeLanguage(key[i]).split('-'); - j = split.length; - next = normalizeLanguage(key[i + 1]); - next = next ? next.split('-') : null; - while (j > 0) { - lang = get(split.slice(0, j).join('-')); - if (lang) { - return lang; - } - if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) { - //the next array item is better than a shallower substring of this one - break; - } - j--; - } - i++; - } - return moment.fn._lang; - } - - /************************************ - Formatting - ************************************/ - - - function removeFormattingTokens(input) { - if (input.match(/\[[\s\S]/)) { - return input.replace(/^\[|\]$/g, ""); - } - return input.replace(/\\/g, ""); - } - - function makeFormatFunction(format) { - var array = format.match(formattingTokens), i, length; - - for (i = 0, length = array.length; i < length; i++) { - if (formatTokenFunctions[array[i]]) { - array[i] = formatTokenFunctions[array[i]]; - } else { - array[i] = removeFormattingTokens(array[i]); - } - } - - return function (mom) { - var output = ""; - for (i = 0; i < length; i++) { - output += array[i] instanceof Function ? array[i].call(mom, format) : array[i]; - } - return output; - }; - } - - // format date using native date object - function formatMoment(m, format) { - - if (!m.isValid()) { - return m.lang().invalidDate(); - } - - format = expandFormat(format, m.lang()); - - if (!formatFunctions[format]) { - formatFunctions[format] = makeFormatFunction(format); - } - - return formatFunctions[format](m); - } - - function expandFormat(format, lang) { - var i = 5; - - function replaceLongDateFormatTokens(input) { - return lang.longDateFormat(input) || input; - } - - localFormattingTokens.lastIndex = 0; - while (i >= 0 && localFormattingTokens.test(format)) { - format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); - localFormattingTokens.lastIndex = 0; - i -= 1; - } - - return format; - } - - - /************************************ - Parsing - ************************************/ - - - // get the regex to find the next token - function getParseRegexForToken(token, config) { - var a, strict = config._strict; - switch (token) { - case 'DDDD': - return parseTokenThreeDigits; - case 'YYYY': - case 'GGGG': - case 'gggg': - return strict ? parseTokenFourDigits : parseTokenOneToFourDigits; - case 'Y': - case 'G': - case 'g': - return parseTokenSignedNumber; - case 'YYYYYY': - case 'YYYYY': - case 'GGGGG': - case 'ggggg': - return strict ? parseTokenSixDigits : parseTokenOneToSixDigits; - case 'S': - if (strict) { return parseTokenOneDigit; } - /* falls through */ - case 'SS': - if (strict) { return parseTokenTwoDigits; } - /* falls through */ - case 'SSS': - if (strict) { return parseTokenThreeDigits; } - /* falls through */ - case 'DDD': - return parseTokenOneToThreeDigits; - case 'MMM': - case 'MMMM': - case 'dd': - case 'ddd': - case 'dddd': - return parseTokenWord; - case 'a': - case 'A': - return getLangDefinition(config._l)._meridiemParse; - case 'X': - return parseTokenTimestampMs; - case 'Z': - case 'ZZ': - return parseTokenTimezone; - case 'T': - return parseTokenT; - case 'SSSS': - return parseTokenDigits; - case 'MM': - case 'DD': - case 'YY': - case 'GG': - case 'gg': - case 'HH': - case 'hh': - case 'mm': - case 'ss': - case 'ww': - case 'WW': - return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits; - case 'M': - case 'D': - case 'd': - case 'H': - case 'h': - case 'm': - case 's': - case 'w': - case 'W': - case 'e': - case 'E': - return parseTokenOneOrTwoDigits; - default : - a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), "i")); - return a; - } - } - - function timezoneMinutesFromString(string) { - string = string || ""; - var possibleTzMatches = (string.match(parseTokenTimezone) || []), - tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [], - parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0], - minutes = +(parts[1] * 60) + toInt(parts[2]); - - return parts[0] === '+' ? -minutes : minutes; - } - - // function to convert string input to date - function addTimeToArrayFromToken(token, input, config) { - var a, datePartArray = config._a; - - switch (token) { - // MONTH - case 'M' : // fall through to MM - case 'MM' : - if (input != null) { - datePartArray[MONTH] = toInt(input) - 1; - } - break; - case 'MMM' : // fall through to MMMM - case 'MMMM' : - a = getLangDefinition(config._l).monthsParse(input); - // if we didn't find a month name, mark the date as invalid. - if (a != null) { - datePartArray[MONTH] = a; - } else { - config._pf.invalidMonth = input; - } - break; - // DAY OF MONTH - case 'D' : // fall through to DD - case 'DD' : - if (input != null) { - datePartArray[DATE] = toInt(input); - } - break; - // DAY OF YEAR - case 'DDD' : // fall through to DDDD - case 'DDDD' : - if (input != null) { - config._dayOfYear = toInt(input); - } - - break; - // YEAR - case 'YY' : - datePartArray[YEAR] = toInt(input) + (toInt(input) > 68 ? 1900 : 2000); - break; - case 'YYYY' : - case 'YYYYY' : - case 'YYYYYY' : - datePartArray[YEAR] = toInt(input); - break; - // AM / PM - case 'a' : // fall through to A - case 'A' : - config._isPm = getLangDefinition(config._l).isPM(input); - break; - // 24 HOUR - case 'H' : // fall through to hh - case 'HH' : // fall through to hh - case 'h' : // fall through to hh - case 'hh' : - datePartArray[HOUR] = toInt(input); - break; - // MINUTE - case 'm' : // fall through to mm - case 'mm' : - datePartArray[MINUTE] = toInt(input); - break; - // SECOND - case 's' : // fall through to ss - case 'ss' : - datePartArray[SECOND] = toInt(input); - break; - // MILLISECOND - case 'S' : - case 'SS' : - case 'SSS' : - case 'SSSS' : - datePartArray[MILLISECOND] = toInt(('0.' + input) * 1000); - break; - // UNIX TIMESTAMP WITH MS - case 'X': - config._d = new Date(parseFloat(input) * 1000); - break; - // TIMEZONE - case 'Z' : // fall through to ZZ - case 'ZZ' : - config._useUTC = true; - config._tzm = timezoneMinutesFromString(input); - break; - case 'w': - case 'ww': - case 'W': - case 'WW': - case 'd': - case 'dd': - case 'ddd': - case 'dddd': - case 'e': - case 'E': - token = token.substr(0, 1); - /* falls through */ - case 'gg': - case 'gggg': - case 'GG': - case 'GGGG': - case 'GGGGG': - token = token.substr(0, 2); - if (input) { - config._w = config._w || {}; - config._w[token] = input; - } - break; - } - } - - // convert an array to a date. - // the array should mirror the parameters below - // note: all values past the year are optional and will default to the lowest possible value. - // [year, month, day , hour, minute, second, millisecond] - function dateFromConfig(config) { - var i, date, input = [], currentDate, - yearToUse, fixYear, w, temp, lang, weekday, week; - - if (config._d) { - return; - } - - currentDate = currentDateArray(config); - - //compute day of the year from weeks and weekdays - if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { - fixYear = function (val) { - var int_val = parseInt(val, 10); - return val ? - (val.length < 3 ? (int_val > 68 ? 1900 + int_val : 2000 + int_val) : int_val) : - (config._a[YEAR] == null ? moment().weekYear() : config._a[YEAR]); - }; - - w = config._w; - if (w.GG != null || w.W != null || w.E != null) { - temp = dayOfYearFromWeeks(fixYear(w.GG), w.W || 1, w.E, 4, 1); - } - else { - lang = getLangDefinition(config._l); - weekday = w.d != null ? parseWeekday(w.d, lang) : - (w.e != null ? parseInt(w.e, 10) + lang._week.dow : 0); - - week = parseInt(w.w, 10) || 1; - - //if we're parsing 'd', then the low day numbers may be next week - if (w.d != null && weekday < lang._week.dow) { - week++; - } - - temp = dayOfYearFromWeeks(fixYear(w.gg), week, weekday, lang._week.doy, lang._week.dow); - } - - config._a[YEAR] = temp.year; - config._dayOfYear = temp.dayOfYear; - } - - //if the day of the year is set, figure out what it is - if (config._dayOfYear) { - yearToUse = config._a[YEAR] == null ? currentDate[YEAR] : config._a[YEAR]; - - if (config._dayOfYear > daysInYear(yearToUse)) { - config._pf._overflowDayOfYear = true; - } - - date = makeUTCDate(yearToUse, 0, config._dayOfYear); - config._a[MONTH] = date.getUTCMonth(); - config._a[DATE] = date.getUTCDate(); - } - - // Default to current date. - // * if no year, month, day of month are given, default to today - // * if day of month is given, default month and year - // * if month is given, default only year - // * if year is given, don't default anything - for (i = 0; i < 3 && config._a[i] == null; ++i) { - config._a[i] = input[i] = currentDate[i]; - } - - // Zero out whatever was not defaulted, including time - for (; i < 7; i++) { - config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; - } - - // add the offsets to the time to be parsed so that we can have a clean array for checking isValid - input[HOUR] += toInt((config._tzm || 0) / 60); - input[MINUTE] += toInt((config._tzm || 0) % 60); - - config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input); - } - - function dateFromObject(config) { - var normalizedInput; - - if (config._d) { - return; - } - - normalizedInput = normalizeObjectUnits(config._i); - config._a = [ - normalizedInput.year, - normalizedInput.month, - normalizedInput.day, - normalizedInput.hour, - normalizedInput.minute, - normalizedInput.second, - normalizedInput.millisecond - ]; - - dateFromConfig(config); - } - - function currentDateArray(config) { - var now = new Date(); - if (config._useUTC) { - return [ - now.getUTCFullYear(), - now.getUTCMonth(), - now.getUTCDate() - ]; - } else { - return [now.getFullYear(), now.getMonth(), now.getDate()]; - } - } - - // date from string and format string - function makeDateFromStringAndFormat(config) { - - config._a = []; - config._pf.empty = true; - - // This array is used to make a Date, either with `new Date` or `Date.UTC` - var lang = getLangDefinition(config._l), - string = '' + config._i, - i, parsedInput, tokens, token, skipped, - stringLength = string.length, - totalParsedInputLength = 0; - - tokens = expandFormat(config._f, lang).match(formattingTokens) || []; - - for (i = 0; i < tokens.length; i++) { - token = tokens[i]; - parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; - if (parsedInput) { - skipped = string.substr(0, string.indexOf(parsedInput)); - if (skipped.length > 0) { - config._pf.unusedInput.push(skipped); - } - string = string.slice(string.indexOf(parsedInput) + parsedInput.length); - totalParsedInputLength += parsedInput.length; - } - // don't parse if it's not a known token - if (formatTokenFunctions[token]) { - if (parsedInput) { - config._pf.empty = false; - } - else { - config._pf.unusedTokens.push(token); - } - addTimeToArrayFromToken(token, parsedInput, config); - } - else if (config._strict && !parsedInput) { - config._pf.unusedTokens.push(token); - } - } - - // add remaining unparsed input length to the string - config._pf.charsLeftOver = stringLength - totalParsedInputLength; - if (string.length > 0) { - config._pf.unusedInput.push(string); - } - - // handle am pm - if (config._isPm && config._a[HOUR] < 12) { - config._a[HOUR] += 12; - } - // if is 12 am, change hours to 0 - if (config._isPm === false && config._a[HOUR] === 12) { - config._a[HOUR] = 0; - } - - dateFromConfig(config); - checkOverflow(config); - } - - function unescapeFormat(s) { - return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) { - return p1 || p2 || p3 || p4; - }); - } - - // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript - function regexpEscape(s) { - return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); - } - - // date from string and array of format strings - function makeDateFromStringAndArray(config) { - var tempConfig, - bestMoment, - - scoreToBeat, - i, - currentScore; - - if (config._f.length === 0) { - config._pf.invalidFormat = true; - config._d = new Date(NaN); - return; - } - - for (i = 0; i < config._f.length; i++) { - currentScore = 0; - tempConfig = extend({}, config); - tempConfig._pf = defaultParsingFlags(); - tempConfig._f = config._f[i]; - makeDateFromStringAndFormat(tempConfig); - - if (!isValid(tempConfig)) { - continue; - } - - // if there is any input that was not parsed add a penalty for that format - currentScore += tempConfig._pf.charsLeftOver; - - //or tokens - currentScore += tempConfig._pf.unusedTokens.length * 10; - - tempConfig._pf.score = currentScore; - - if (scoreToBeat == null || currentScore < scoreToBeat) { - scoreToBeat = currentScore; - bestMoment = tempConfig; - } - } - - extend(config, bestMoment || tempConfig); - } - - // date from iso format - function makeDateFromString(config) { - var i, l, - string = config._i, - match = isoRegex.exec(string); - - if (match) { - config._pf.iso = true; - for (i = 0, l = isoDates.length; i < l; i++) { - if (isoDates[i][1].exec(string)) { - // match[5] should be "T" or undefined - config._f = isoDates[i][0] + (match[6] || " "); - break; - } - } - for (i = 0, l = isoTimes.length; i < l; i++) { - if (isoTimes[i][1].exec(string)) { - config._f += isoTimes[i][0]; - break; - } - } - if (string.match(parseTokenTimezone)) { - config._f += "Z"; - } - makeDateFromStringAndFormat(config); - } - else { - config._d = new Date(string); - } - } - - function makeDateFromInput(config) { - var input = config._i, - matched = aspNetJsonRegex.exec(input); - - if (input === undefined) { - config._d = new Date(); - } else if (matched) { - config._d = new Date(+matched[1]); - } else if (typeof input === 'string') { - makeDateFromString(config); - } else if (isArray(input)) { - config._a = input.slice(0); - dateFromConfig(config); - } else if (isDate(input)) { - config._d = new Date(+input); - } else if (typeof(input) === 'object') { - dateFromObject(config); - } else { - config._d = new Date(input); - } - } - - function makeDate(y, m, d, h, M, s, ms) { - //can't just apply() to create a date: - //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply - var date = new Date(y, m, d, h, M, s, ms); - - //the date constructor doesn't accept years < 1970 - if (y < 1970) { - date.setFullYear(y); - } - return date; - } - - function makeUTCDate(y) { - var date = new Date(Date.UTC.apply(null, arguments)); - if (y < 1970) { - date.setUTCFullYear(y); - } - return date; - } - - function parseWeekday(input, language) { - if (typeof input === 'string') { - if (!isNaN(input)) { - input = parseInt(input, 10); - } - else { - input = language.weekdaysParse(input); - if (typeof input !== 'number') { - return null; - } - } - } - return input; - } - - /************************************ - Relative Time - ************************************/ - - - // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize - function substituteTimeAgo(string, number, withoutSuffix, isFuture, lang) { - return lang.relativeTime(number || 1, !!withoutSuffix, string, isFuture); - } - - function relativeTime(milliseconds, withoutSuffix, lang) { - var seconds = round(Math.abs(milliseconds) / 1000), - minutes = round(seconds / 60), - hours = round(minutes / 60), - days = round(hours / 24), - years = round(days / 365), - args = seconds < 45 && ['s', seconds] || - minutes === 1 && ['m'] || - minutes < 45 && ['mm', minutes] || - hours === 1 && ['h'] || - hours < 22 && ['hh', hours] || - days === 1 && ['d'] || - days <= 25 && ['dd', days] || - days <= 45 && ['M'] || - days < 345 && ['MM', round(days / 30)] || - years === 1 && ['y'] || ['yy', years]; - args[2] = withoutSuffix; - args[3] = milliseconds > 0; - args[4] = lang; - return substituteTimeAgo.apply({}, args); - } - - - /************************************ - Week of Year - ************************************/ - - - // firstDayOfWeek 0 = sun, 6 = sat - // the day of the week that starts the week - // (usually sunday or monday) - // firstDayOfWeekOfYear 0 = sun, 6 = sat - // the first week is the week that contains the first - // of this day of the week - // (eg. ISO weeks use thursday (4)) - function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { - var end = firstDayOfWeekOfYear - firstDayOfWeek, - daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(), - adjustedMoment; - - - if (daysToDayOfWeek > end) { - daysToDayOfWeek -= 7; - } - - if (daysToDayOfWeek < end - 7) { - daysToDayOfWeek += 7; - } - - adjustedMoment = moment(mom).add('d', daysToDayOfWeek); - return { - week: Math.ceil(adjustedMoment.dayOfYear() / 7), - year: adjustedMoment.year() - }; - } - - //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday - function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) { - var d = makeUTCDate(year, 0, 1).getUTCDay(), daysToAdd, dayOfYear; - - weekday = weekday != null ? weekday : firstDayOfWeek; - daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0) - (d < firstDayOfWeek ? 7 : 0); - dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1; - - return { - year: dayOfYear > 0 ? year : year - 1, - dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear - }; - } - - /************************************ - Top Level Functions - ************************************/ - - function makeMoment(config) { - var input = config._i, - format = config._f; - - if (input === null) { - return moment.invalid({nullInput: true}); - } - - if (typeof input === 'string') { - config._i = input = getLangDefinition().preparse(input); - } - - if (moment.isMoment(input)) { - config = cloneMoment(input); - - config._d = new Date(+input._d); - } else if (format) { - if (isArray(format)) { - makeDateFromStringAndArray(config); - } else { - makeDateFromStringAndFormat(config); - } - } else { - makeDateFromInput(config); - } - - return new Moment(config); - } - - moment = function (input, format, lang, strict) { - var c; - - if (typeof(lang) === "boolean") { - strict = lang; - lang = undefined; - } - // object construction must be done this way. - // https://github.com/moment/moment/issues/1423 - c = {}; - c._isAMomentObject = true; - c._i = input; - c._f = format; - c._l = lang; - c._strict = strict; - c._isUTC = false; - c._pf = defaultParsingFlags(); - - return makeMoment(c); - }; - - // creating with utc - moment.utc = function (input, format, lang, strict) { - var c; - - if (typeof(lang) === "boolean") { - strict = lang; - lang = undefined; - } - // object construction must be done this way. - // https://github.com/moment/moment/issues/1423 - c = {}; - c._isAMomentObject = true; - c._useUTC = true; - c._isUTC = true; - c._l = lang; - c._i = input; - c._f = format; - c._strict = strict; - c._pf = defaultParsingFlags(); - - return makeMoment(c).utc(); - }; - - // creating with unix timestamp (in seconds) - moment.unix = function (input) { - return moment(input * 1000); - }; - - // duration - moment.duration = function (input, key) { - var duration = input, - // matching against regexp is expensive, do it on demand - match = null, - sign, - ret, - parseIso; - - if (moment.isDuration(input)) { - duration = { - ms: input._milliseconds, - d: input._days, - M: input._months - }; - } else if (typeof input === 'number') { - duration = {}; - if (key) { - duration[key] = input; - } else { - duration.milliseconds = input; - } - } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) { - sign = (match[1] === "-") ? -1 : 1; - duration = { - y: 0, - d: toInt(match[DATE]) * sign, - h: toInt(match[HOUR]) * sign, - m: toInt(match[MINUTE]) * sign, - s: toInt(match[SECOND]) * sign, - ms: toInt(match[MILLISECOND]) * sign - }; - } else if (!!(match = isoDurationRegex.exec(input))) { - sign = (match[1] === "-") ? -1 : 1; - parseIso = function (inp) { - // We'd normally use ~~inp for this, but unfortunately it also - // converts floats to ints. - // inp may be undefined, so careful calling replace on it. - var res = inp && parseFloat(inp.replace(',', '.')); - // apply sign while we're at it - return (isNaN(res) ? 0 : res) * sign; - }; - duration = { - y: parseIso(match[2]), - M: parseIso(match[3]), - d: parseIso(match[4]), - h: parseIso(match[5]), - m: parseIso(match[6]), - s: parseIso(match[7]), - w: parseIso(match[8]) - }; - } - - ret = new Duration(duration); - - if (moment.isDuration(input) && input.hasOwnProperty('_lang')) { - ret._lang = input._lang; - } - - return ret; - }; - - // version number - moment.version = VERSION; - - // default format - moment.defaultFormat = isoFormat; - - // This function will be called whenever a moment is mutated. - // It is intended to keep the offset in sync with the timezone. - moment.updateOffset = function () {}; - - // This function will load languages and then set the global language. If - // no arguments are passed in, it will simply return the current global - // language key. - moment.lang = function (key, values) { - var r; - if (!key) { - return moment.fn._lang._abbr; - } - if (values) { - loadLang(normalizeLanguage(key), values); - } else if (values === null) { - unloadLang(key); - key = 'en'; - } else if (!languages[key]) { - getLangDefinition(key); - } - r = moment.duration.fn._lang = moment.fn._lang = getLangDefinition(key); - return r._abbr; - }; - - // returns language data - moment.langData = function (key) { - if (key && key._lang && key._lang._abbr) { - key = key._lang._abbr; - } - return getLangDefinition(key); - }; - - // compare moment object - moment.isMoment = function (obj) { - return obj instanceof Moment || - (obj != null && obj.hasOwnProperty('_isAMomentObject')); - }; - - // for typechecking Duration objects - moment.isDuration = function (obj) { - return obj instanceof Duration; - }; - - for (i = lists.length - 1; i >= 0; --i) { - makeList(lists[i]); - } - - moment.normalizeUnits = function (units) { - return normalizeUnits(units); - }; - - moment.invalid = function (flags) { - var m = moment.utc(NaN); - if (flags != null) { - extend(m._pf, flags); - } - else { - m._pf.userInvalidated = true; - } - - return m; - }; - - moment.parseZone = function (input) { - return moment(input).parseZone(); - }; - - /************************************ - Moment Prototype - ************************************/ - - - extend(moment.fn = Moment.prototype, { - - clone : function () { - return moment(this); - }, - - valueOf : function () { - return +this._d + ((this._offset || 0) * 60000); - }, - - unix : function () { - return Math.floor(+this / 1000); - }, - - toString : function () { - return this.clone().lang('en').format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ"); - }, - - toDate : function () { - return this._offset ? new Date(+this) : this._d; - }, - - toISOString : function () { - var m = moment(this).utc(); - if (0 < m.year() && m.year() <= 9999) { - return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); - } else { - return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); - } - }, - - toArray : function () { - var m = this; - return [ - m.year(), - m.month(), - m.date(), - m.hours(), - m.minutes(), - m.seconds(), - m.milliseconds() - ]; - }, - - isValid : function () { - return isValid(this); - }, - - isDSTShifted : function () { - - if (this._a) { - return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0; - } - - return false; - }, - - parsingFlags : function () { - return extend({}, this._pf); - }, - - invalidAt: function () { - return this._pf.overflow; - }, - - utc : function () { - return this.zone(0); - }, - - local : function () { - this.zone(0); - this._isUTC = false; - return this; - }, - - format : function (inputString) { - var output = formatMoment(this, inputString || moment.defaultFormat); - return this.lang().postformat(output); - }, - - add : function (input, val) { - var dur; - // switch args to support add('s', 1) and add(1, 's') - if (typeof input === 'string') { - dur = moment.duration(+val, input); - } else { - dur = moment.duration(input, val); - } - addOrSubtractDurationFromMoment(this, dur, 1); - return this; - }, - - subtract : function (input, val) { - var dur; - // switch args to support subtract('s', 1) and subtract(1, 's') - if (typeof input === 'string') { - dur = moment.duration(+val, input); - } else { - dur = moment.duration(input, val); - } - addOrSubtractDurationFromMoment(this, dur, -1); - return this; - }, - - diff : function (input, units, asFloat) { - var that = makeAs(input, this), - zoneDiff = (this.zone() - that.zone()) * 6e4, - diff, output; - - units = normalizeUnits(units); - - if (units === 'year' || units === 'month') { - // average number of days in the months in the given dates - diff = (this.daysInMonth() + that.daysInMonth()) * 432e5; // 24 * 60 * 60 * 1000 / 2 - // difference in months - output = ((this.year() - that.year()) * 12) + (this.month() - that.month()); - // adjust by taking difference in days, average number of days - // and dst in the given months. - output += ((this - moment(this).startOf('month')) - - (that - moment(that).startOf('month'))) / diff; - // same as above but with zones, to negate all dst - output -= ((this.zone() - moment(this).startOf('month').zone()) - - (that.zone() - moment(that).startOf('month').zone())) * 6e4 / diff; - if (units === 'year') { - output = output / 12; - } - } else { - diff = (this - that); - output = units === 'second' ? diff / 1e3 : // 1000 - units === 'minute' ? diff / 6e4 : // 1000 * 60 - units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60 - units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst - units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst - diff; - } - return asFloat ? output : absRound(output); - }, - - from : function (time, withoutSuffix) { - return moment.duration(this.diff(time)).lang(this.lang()._abbr).humanize(!withoutSuffix); - }, - - fromNow : function (withoutSuffix) { - return this.from(moment(), withoutSuffix); - }, - - calendar : function () { - // We want to compare the start of today, vs this. - // Getting start-of-today depends on whether we're zone'd or not. - var sod = makeAs(moment(), this).startOf('day'), - diff = this.diff(sod, 'days', true), - format = diff < -6 ? 'sameElse' : - diff < -1 ? 'lastWeek' : - diff < 0 ? 'lastDay' : - diff < 1 ? 'sameDay' : - diff < 2 ? 'nextDay' : - diff < 7 ? 'nextWeek' : 'sameElse'; - return this.format(this.lang().calendar(format, this)); - }, - - isLeapYear : function () { - return isLeapYear(this.year()); - }, - - isDST : function () { - return (this.zone() < this.clone().month(0).zone() || - this.zone() < this.clone().month(5).zone()); - }, - - day : function (input) { - var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); - if (input != null) { - input = parseWeekday(input, this.lang()); - return this.add({ d : input - day }); - } else { - return day; - } - }, - - month : function (input) { - var utc = this._isUTC ? 'UTC' : '', - dayOfMonth; - - if (input != null) { - if (typeof input === 'string') { - input = this.lang().monthsParse(input); - if (typeof input !== 'number') { - return this; - } - } - - dayOfMonth = this.date(); - this.date(1); - this._d['set' + utc + 'Month'](input); - this.date(Math.min(dayOfMonth, this.daysInMonth())); - - moment.updateOffset(this); - return this; - } else { - return this._d['get' + utc + 'Month'](); - } - }, - - startOf: function (units) { - units = normalizeUnits(units); - // the following switch intentionally omits break keywords - // to utilize falling through the cases. - switch (units) { - case 'year': - this.month(0); - /* falls through */ - case 'month': - this.date(1); - /* falls through */ - case 'week': - case 'isoWeek': - case 'day': - this.hours(0); - /* falls through */ - case 'hour': - this.minutes(0); - /* falls through */ - case 'minute': - this.seconds(0); - /* falls through */ - case 'second': - this.milliseconds(0); - /* falls through */ - } - - // weeks are a special case - if (units === 'week') { - this.weekday(0); - } else if (units === 'isoWeek') { - this.isoWeekday(1); - } - - return this; - }, - - endOf: function (units) { - units = normalizeUnits(units); - return this.startOf(units).add((units === 'isoWeek' ? 'week' : units), 1).subtract('ms', 1); - }, - - isAfter: function (input, units) { - units = typeof units !== 'undefined' ? units : 'millisecond'; - return +this.clone().startOf(units) > +moment(input).startOf(units); - }, - - isBefore: function (input, units) { - units = typeof units !== 'undefined' ? units : 'millisecond'; - return +this.clone().startOf(units) < +moment(input).startOf(units); - }, - - isSame: function (input, units) { - units = units || 'ms'; - return +this.clone().startOf(units) === +makeAs(input, this).startOf(units); - }, - - min: function (other) { - other = moment.apply(null, arguments); - return other < this ? this : other; - }, - - max: function (other) { - other = moment.apply(null, arguments); - return other > this ? this : other; - }, - - zone : function (input) { - var offset = this._offset || 0; - if (input != null) { - if (typeof input === "string") { - input = timezoneMinutesFromString(input); - } - if (Math.abs(input) < 16) { - input = input * 60; - } - this._offset = input; - this._isUTC = true; - if (offset !== input) { - addOrSubtractDurationFromMoment(this, moment.duration(offset - input, 'm'), 1, true); - } - } else { - return this._isUTC ? offset : this._d.getTimezoneOffset(); - } - return this; - }, - - zoneAbbr : function () { - return this._isUTC ? "UTC" : ""; - }, - - zoneName : function () { - return this._isUTC ? "Coordinated Universal Time" : ""; - }, - - parseZone : function () { - if (this._tzm) { - this.zone(this._tzm); - } else if (typeof this._i === 'string') { - this.zone(this._i); - } - return this; - }, - - hasAlignedHourOffset : function (input) { - if (!input) { - input = 0; - } - else { - input = moment(input).zone(); - } - - return (this.zone() - input) % 60 === 0; - }, - - daysInMonth : function () { - return daysInMonth(this.year(), this.month()); - }, - - dayOfYear : function (input) { - var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1; - return input == null ? dayOfYear : this.add("d", (input - dayOfYear)); - }, - - quarter : function () { - return Math.ceil((this.month() + 1.0) / 3.0); - }, - - weekYear : function (input) { - var year = weekOfYear(this, this.lang()._week.dow, this.lang()._week.doy).year; - return input == null ? year : this.add("y", (input - year)); - }, - - isoWeekYear : function (input) { - var year = weekOfYear(this, 1, 4).year; - return input == null ? year : this.add("y", (input - year)); - }, - - week : function (input) { - var week = this.lang().week(this); - return input == null ? week : this.add("d", (input - week) * 7); - }, - - isoWeek : function (input) { - var week = weekOfYear(this, 1, 4).week; - return input == null ? week : this.add("d", (input - week) * 7); - }, - - weekday : function (input) { - var weekday = (this.day() + 7 - this.lang()._week.dow) % 7; - return input == null ? weekday : this.add("d", input - weekday); - }, - - isoWeekday : function (input) { - // behaves the same as moment#day except - // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) - // as a setter, sunday should belong to the previous week. - return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7); - }, - - get : function (units) { - units = normalizeUnits(units); - return this[units](); - }, - - set : function (units, value) { - units = normalizeUnits(units); - if (typeof this[units] === 'function') { - this[units](value); - } - return this; - }, - - // If passed a language key, it will set the language for this - // instance. Otherwise, it will return the language configuration - // variables for this instance. - lang : function (key) { - if (key === undefined) { - return this._lang; - } else { - this._lang = getLangDefinition(key); - return this; - } - } - }); - - // helper for adding shortcuts - function makeGetterAndSetter(name, key) { - moment.fn[name] = moment.fn[name + 's'] = function (input) { - var utc = this._isUTC ? 'UTC' : ''; - if (input != null) { - this._d['set' + utc + key](input); - moment.updateOffset(this); - return this; - } else { - return this._d['get' + utc + key](); - } - }; - } - - // loop through and add shortcuts (Month, Date, Hours, Minutes, Seconds, Milliseconds) - for (i = 0; i < proxyGettersAndSetters.length; i ++) { - makeGetterAndSetter(proxyGettersAndSetters[i].toLowerCase().replace(/s$/, ''), proxyGettersAndSetters[i]); - } - - // add shortcut for year (uses different syntax than the getter/setter 'year' == 'FullYear') - makeGetterAndSetter('year', 'FullYear'); - - // add plural methods - moment.fn.days = moment.fn.day; - moment.fn.months = moment.fn.month; - moment.fn.weeks = moment.fn.week; - moment.fn.isoWeeks = moment.fn.isoWeek; - - // add aliased format methods - moment.fn.toJSON = moment.fn.toISOString; - - /************************************ - Duration Prototype - ************************************/ - - - extend(moment.duration.fn = Duration.prototype, { - - _bubble : function () { - var milliseconds = this._milliseconds, - days = this._days, - months = this._months, - data = this._data, - seconds, minutes, hours, years; - - // The following code bubbles up values, see the tests for - // examples of what that means. - data.milliseconds = milliseconds % 1000; - - seconds = absRound(milliseconds / 1000); - data.seconds = seconds % 60; - - minutes = absRound(seconds / 60); - data.minutes = minutes % 60; - - hours = absRound(minutes / 60); - data.hours = hours % 24; - - days += absRound(hours / 24); - data.days = days % 30; - - months += absRound(days / 30); - data.months = months % 12; - - years = absRound(months / 12); - data.years = years; - }, - - weeks : function () { - return absRound(this.days() / 7); - }, - - valueOf : function () { - return this._milliseconds + - this._days * 864e5 + - (this._months % 12) * 2592e6 + - toInt(this._months / 12) * 31536e6; - }, - - humanize : function (withSuffix) { - var difference = +this, - output = relativeTime(difference, !withSuffix, this.lang()); - - if (withSuffix) { - output = this.lang().pastFuture(difference, output); - } - - return this.lang().postformat(output); - }, - - add : function (input, val) { - // supports only 2.0-style add(1, 's') or add(moment) - var dur = moment.duration(input, val); - - this._milliseconds += dur._milliseconds; - this._days += dur._days; - this._months += dur._months; - - this._bubble(); - - return this; - }, - - subtract : function (input, val) { - var dur = moment.duration(input, val); - - this._milliseconds -= dur._milliseconds; - this._days -= dur._days; - this._months -= dur._months; - - this._bubble(); - - return this; - }, - - get : function (units) { - units = normalizeUnits(units); - return this[units.toLowerCase() + 's'](); - }, - - as : function (units) { - units = normalizeUnits(units); - return this['as' + units.charAt(0).toUpperCase() + units.slice(1) + 's'](); - }, - - lang : moment.fn.lang, - - toIsoString : function () { - // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js - var years = Math.abs(this.years()), - months = Math.abs(this.months()), - days = Math.abs(this.days()), - hours = Math.abs(this.hours()), - minutes = Math.abs(this.minutes()), - seconds = Math.abs(this.seconds() + this.milliseconds() / 1000); - - if (!this.asSeconds()) { - // this is the same as C#'s (Noda) and python (isodate)... - // but not other JS (goog.date) - return 'P0D'; - } - - return (this.asSeconds() < 0 ? '-' : '') + - 'P' + - (years ? years + 'Y' : '') + - (months ? months + 'M' : '') + - (days ? days + 'D' : '') + - ((hours || minutes || seconds) ? 'T' : '') + - (hours ? hours + 'H' : '') + - (minutes ? minutes + 'M' : '') + - (seconds ? seconds + 'S' : ''); - } - }); - - function makeDurationGetter(name) { - moment.duration.fn[name] = function () { - return this._data[name]; - }; - } - - function makeDurationAsGetter(name, factor) { - moment.duration.fn['as' + name] = function () { - return +this / factor; - }; - } - - for (i in unitMillisecondFactors) { - if (unitMillisecondFactors.hasOwnProperty(i)) { - makeDurationAsGetter(i, unitMillisecondFactors[i]); - makeDurationGetter(i.toLowerCase()); - } - } - - makeDurationAsGetter('Weeks', 6048e5); - moment.duration.fn.asMonths = function () { - return (+this - this.years() * 31536e6) / 2592e6 + this.years() * 12; - }; - - - /************************************ - Default Lang - ************************************/ - - - // Set default language, other languages will inherit from English. - moment.lang('en', { - ordinal : function (number) { - var b = number % 10, - output = (toInt(number % 100 / 10) === 1) ? 'th' : - (b === 1) ? 'st' : - (b === 2) ? 'nd' : - (b === 3) ? 'rd' : 'th'; - return number + output; - } - }); - - /* EMBED_LANGUAGES */ - - /************************************ - Exposing Moment - ************************************/ - - function makeGlobal(deprecate) { - var warned = false, local_moment = moment; - /*global ender:false */ - if (typeof ender !== 'undefined') { - return; - } - // here, `this` means `window` in the browser, or `global` on the server - // add `moment` as a global object via a string identifier, - // for Closure Compiler "advanced" mode - if (deprecate) { - global.moment = function () { - if (!warned && console && console.warn) { - warned = true; - console.warn( - "Accessing Moment through the global scope is " + - "deprecated, and will be removed in an upcoming " + - "release."); - } - return local_moment.apply(null, arguments); - }; - extend(global.moment, local_moment); - } else { - global['moment'] = moment; - } - } - - // CommonJS module is defined - if (hasModule) { - module.exports = moment; - makeGlobal(true); - } else if (typeof define === "function" && define.amd) { - define("moment", function (require, exports, module) { - if (module.config && module.config() && module.config().noGlobal !== true) { - // If user provided noGlobal, he is aware of global - makeGlobal(module.config().noGlobal === undefined); - } - - return moment; - }); - } else { - makeGlobal(); - } -}).call(this); - -},{}],4:[function(require,module,exports){ -/** - * Copyright 2012 Craig Campbell - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Mousetrap is a simple keyboard shortcut library for Javascript with - * no external dependencies - * - * @version 1.1.2 - * @url craig.is/killing/mice - */ - - /** - * mapping of special keycodes to their corresponding keys - * - * everything in this dictionary cannot use keypress events - * so it has to be here to map to the correct keycodes for - * keyup/keydown events - * - * @type {Object} - */ - var _MAP = { - 8: 'backspace', - 9: 'tab', - 13: 'enter', - 16: 'shift', - 17: 'ctrl', - 18: 'alt', - 20: 'capslock', - 27: 'esc', - 32: 'space', - 33: 'pageup', - 34: 'pagedown', - 35: 'end', - 36: 'home', - 37: 'left', - 38: 'up', - 39: 'right', - 40: 'down', - 45: 'ins', - 46: 'del', - 91: 'meta', - 93: 'meta', - 224: 'meta' - }, - - /** - * mapping for special characters so they can support - * - * this dictionary is only used incase you want to bind a - * keyup or keydown event to one of these keys - * - * @type {Object} - */ - _KEYCODE_MAP = { - 106: '*', - 107: '+', - 109: '-', - 110: '.', - 111 : '/', - 186: ';', - 187: '=', - 188: ',', - 189: '-', - 190: '.', - 191: '/', - 192: '`', - 219: '[', - 220: '\\', - 221: ']', - 222: '\'' - }, - - /** - * this is a mapping of keys that require shift on a US keypad - * back to the non shift equivelents - * - * this is so you can use keyup events with these keys - * - * note that this will only work reliably on US keyboards - * - * @type {Object} - */ - _SHIFT_MAP = { - '~': '`', - '!': '1', - '@': '2', - '#': '3', - '$': '4', - '%': '5', - '^': '6', - '&': '7', - '*': '8', - '(': '9', - ')': '0', - '_': '-', - '+': '=', - ':': ';', - '\"': '\'', - '<': ',', - '>': '.', - '?': '/', - '|': '\\' - }, - - /** - * this is a list of special strings you can use to map - * to modifier keys when you specify your keyboard shortcuts - * - * @type {Object} - */ - _SPECIAL_ALIASES = { - 'option': 'alt', - 'command': 'meta', - 'return': 'enter', - 'escape': 'esc' - }, - - /** - * variable to store the flipped version of _MAP from above - * needed to check if we should use keypress or not when no action - * is specified - * - * @type {Object|undefined} - */ - _REVERSE_MAP, - - /** - * a list of all the callbacks setup via Mousetrap.bind() - * - * @type {Object} - */ - _callbacks = {}, - - /** - * direct map of string combinations to callbacks used for trigger() - * - * @type {Object} - */ - _direct_map = {}, - - /** - * keeps track of what level each sequence is at since multiple - * sequences can start out with the same sequence - * - * @type {Object} - */ - _sequence_levels = {}, - - /** - * variable to store the setTimeout call - * - * @type {null|number} - */ - _reset_timer, - - /** - * temporary state where we will ignore the next keyup - * - * @type {boolean|string} - */ - _ignore_next_keyup = false, - - /** - * are we currently inside of a sequence? - * type of action ("keyup" or "keydown" or "keypress") or false - * - * @type {boolean|string} - */ - _inside_sequence = false; - - /** - * loop through the f keys, f1 to f19 and add them to the map - * programatically - */ - for (var i = 1; i < 20; ++i) { - _MAP[111 + i] = 'f' + i; - } - - /** - * loop through to map numbers on the numeric keypad - */ - for (i = 0; i <= 9; ++i) { - _MAP[i + 96] = i; - } - - /** - * cross browser add event method - * - * @param {Element|HTMLDocument} object - * @param {string} type - * @param {Function} callback - * @returns void - */ - function _addEvent(object, type, callback) { - if (object.addEventListener) { - return object.addEventListener(type, callback, false); - } - - object.attachEvent('on' + type, callback); - } - - /** - * takes the event and returns the key character - * - * @param {Event} e - * @return {string} - */ - function _characterFromEvent(e) { - - // for keypress events we should return the character as is - if (e.type == 'keypress') { - return String.fromCharCode(e.which); - } - - // for non keypress events the special maps are needed - if (_MAP[e.which]) { - return _MAP[e.which]; - } - - if (_KEYCODE_MAP[e.which]) { - return _KEYCODE_MAP[e.which]; - } - - // if it is not in the special map - return String.fromCharCode(e.which).toLowerCase(); - } - - /** - * should we stop this event before firing off callbacks - * - * @param {Event} e - * @return {boolean} - */ - function _stop(e) { - var element = e.target || e.srcElement, - tag_name = element.tagName; - - // if the element has the class "mousetrap" then no need to stop - if ((' ' + element.className + ' ').indexOf(' mousetrap ') > -1) { - return false; - } - - // stop for input, select, and textarea - return tag_name == 'INPUT' || tag_name == 'SELECT' || tag_name == 'TEXTAREA' || (element.contentEditable && element.contentEditable == 'true'); - } - - /** - * checks if two arrays are equal - * - * @param {Array} modifiers1 - * @param {Array} modifiers2 - * @returns {boolean} - */ - function _modifiersMatch(modifiers1, modifiers2) { - return modifiers1.sort().join(',') === modifiers2.sort().join(','); - } - - /** - * resets all sequence counters except for the ones passed in - * - * @param {Object} do_not_reset - * @returns void - */ - function _resetSequences(do_not_reset) { - do_not_reset = do_not_reset || {}; - - var active_sequences = false, - key; - - for (key in _sequence_levels) { - if (do_not_reset[key]) { - active_sequences = true; - continue; - } - _sequence_levels[key] = 0; - } - - if (!active_sequences) { - _inside_sequence = false; - } - } - - /** - * finds all callbacks that match based on the keycode, modifiers, - * and action - * - * @param {string} character - * @param {Array} modifiers - * @param {string} action - * @param {boolean=} remove - should we remove any matches - * @param {string=} combination - * @returns {Array} - */ - function _getMatches(character, modifiers, action, remove, combination) { - var i, - callback, - matches = []; - - // if there are no events related to this keycode - if (!_callbacks[character]) { - return []; - } - - // if a modifier key is coming up on its own we should allow it - if (action == 'keyup' && _isModifier(character)) { - modifiers = [character]; - } - - // loop through all callbacks for the key that was pressed - // and see if any of them match - for (i = 0; i < _callbacks[character].length; ++i) { - callback = _callbacks[character][i]; - - // if this is a sequence but it is not at the right level - // then move onto the next match - if (callback.seq && _sequence_levels[callback.seq] != callback.level) { - continue; - } - - // if the action we are looking for doesn't match the action we got - // then we should keep going - if (action != callback.action) { - continue; - } - - // if this is a keypress event that means that we need to only - // look at the character, otherwise check the modifiers as - // well - if (action == 'keypress' || _modifiersMatch(modifiers, callback.modifiers)) { - - // remove is used so if you change your mind and call bind a - // second time with a new function the first one is overwritten - if (remove && callback.combo == combination) { - _callbacks[character].splice(i, 1); - } - - matches.push(callback); - } - } - - return matches; - } - - /** - * takes a key event and figures out what the modifiers are - * - * @param {Event} e - * @returns {Array} - */ - function _eventModifiers(e) { - var modifiers = []; - - if (e.shiftKey) { - modifiers.push('shift'); - } - - if (e.altKey) { - modifiers.push('alt'); - } - - if (e.ctrlKey) { - modifiers.push('ctrl'); - } - - if (e.metaKey) { - modifiers.push('meta'); - } - - return modifiers; - } - - /** - * actually calls the callback function - * - * if your callback function returns false this will use the jquery - * convention - prevent default and stop propogation on the event - * - * @param {Function} callback - * @param {Event} e - * @returns void - */ - function _fireCallback(callback, e) { - if (callback(e) === false) { - if (e.preventDefault) { - e.preventDefault(); - } - - if (e.stopPropagation) { - e.stopPropagation(); - } - - e.returnValue = false; - e.cancelBubble = true; - } - } - - /** - * handles a character key event - * - * @param {string} character - * @param {Event} e - * @returns void - */ - function _handleCharacter(character, e) { - - // if this event should not happen stop here - if (_stop(e)) { - return; - } - - var callbacks = _getMatches(character, _eventModifiers(e), e.type), - i, - do_not_reset = {}, - processed_sequence_callback = false; - - // loop through matching callbacks for this key event - for (i = 0; i < callbacks.length; ++i) { - - // fire for all sequence callbacks - // this is because if for example you have multiple sequences - // bound such as "g i" and "g t" they both need to fire the - // callback for matching g cause otherwise you can only ever - // match the first one - if (callbacks[i].seq) { - processed_sequence_callback = true; - - // keep a list of which sequences were matches for later - do_not_reset[callbacks[i].seq] = 1; - _fireCallback(callbacks[i].callback, e); - continue; - } - - // if there were no sequence matches but we are still here - // that means this is a regular match so we should fire that - if (!processed_sequence_callback && !_inside_sequence) { - _fireCallback(callbacks[i].callback, e); - } - } - - // if you are inside of a sequence and the key you are pressing - // is not a modifier key then we should reset all sequences - // that were not matched by this key event - if (e.type == _inside_sequence && !_isModifier(character)) { - _resetSequences(do_not_reset); - } - } - - /** - * handles a keydown event - * - * @param {Event} e - * @returns void - */ - function _handleKey(e) { - - // normalize e.which for key events - // @see http://stackoverflow.com/questions/4285627/javascript-keycode-vs-charcode-utter-confusion - e.which = typeof e.which == "number" ? e.which : e.keyCode; - - var character = _characterFromEvent(e); - - // no character found then stop - if (!character) { - return; - } - - if (e.type == 'keyup' && _ignore_next_keyup == character) { - _ignore_next_keyup = false; - return; - } - - _handleCharacter(character, e); - } - - /** - * determines if the keycode specified is a modifier key or not - * - * @param {string} key - * @returns {boolean} - */ - function _isModifier(key) { - return key == 'shift' || key == 'ctrl' || key == 'alt' || key == 'meta'; - } - - /** - * called to set a 1 second timeout on the specified sequence - * - * this is so after each key press in the sequence you have 1 second - * to press the next key before you have to start over - * - * @returns void - */ - function _resetSequenceTimer() { - clearTimeout(_reset_timer); - _reset_timer = setTimeout(_resetSequences, 1000); - } - - /** - * reverses the map lookup so that we can look for specific keys - * to see what can and can't use keypress - * - * @return {Object} - */ - function _getReverseMap() { - if (!_REVERSE_MAP) { - _REVERSE_MAP = {}; - for (var key in _MAP) { - - // pull out the numeric keypad from here cause keypress should - // be able to detect the keys from the character - if (key > 95 && key < 112) { - continue; - } - - if (_MAP.hasOwnProperty(key)) { - _REVERSE_MAP[_MAP[key]] = key; - } - } - } - return _REVERSE_MAP; - } - - /** - * picks the best action based on the key combination - * - * @param {string} key - character for key - * @param {Array} modifiers - * @param {string=} action passed in - */ - function _pickBestAction(key, modifiers, action) { - - // if no action was picked in we should try to pick the one - // that we think would work best for this key - if (!action) { - action = _getReverseMap()[key] ? 'keydown' : 'keypress'; - } - - // modifier keys don't work as expected with keypress, - // switch to keydown - if (action == 'keypress' && modifiers.length) { - action = 'keydown'; - } - - return action; - } - - /** - * binds a key sequence to an event - * - * @param {string} combo - combo specified in bind call - * @param {Array} keys - * @param {Function} callback - * @param {string=} action - * @returns void - */ - function _bindSequence(combo, keys, callback, action) { - - // start off by adding a sequence level record for this combination - // and setting the level to 0 - _sequence_levels[combo] = 0; - - // if there is no action pick the best one for the first key - // in the sequence - if (!action) { - action = _pickBestAction(keys[0], []); - } - - /** - * callback to increase the sequence level for this sequence and reset - * all other sequences that were active - * - * @param {Event} e - * @returns void - */ - var _increaseSequence = function(e) { - _inside_sequence = action; - ++_sequence_levels[combo]; - _resetSequenceTimer(); - }, - - /** - * wraps the specified callback inside of another function in order - * to reset all sequence counters as soon as this sequence is done - * - * @param {Event} e - * @returns void - */ - _callbackAndReset = function(e) { - _fireCallback(callback, e); - - // we should ignore the next key up if the action is key down - // or keypress. this is so if you finish a sequence and - // release the key the final key will not trigger a keyup - if (action !== 'keyup') { - _ignore_next_keyup = _characterFromEvent(e); - } - - // weird race condition if a sequence ends with the key - // another sequence begins with - setTimeout(_resetSequences, 10); - }, - i; - - // loop through keys one at a time and bind the appropriate callback - // function. for any key leading up to the final one it should - // increase the sequence. after the final, it should reset all sequences - for (i = 0; i < keys.length; ++i) { - _bindSingle(keys[i], i < keys.length - 1 ? _increaseSequence : _callbackAndReset, action, combo, i); - } - } - - /** - * binds a single keyboard combination - * - * @param {string} combination - * @param {Function} callback - * @param {string=} action - * @param {string=} sequence_name - name of sequence if part of sequence - * @param {number=} level - what part of the sequence the command is - * @returns void - */ - function _bindSingle(combination, callback, action, sequence_name, level) { - - // make sure multiple spaces in a row become a single space - combination = combination.replace(/\s+/g, ' '); - - var sequence = combination.split(' '), - i, - key, - keys, - modifiers = []; - - // if this pattern is a sequence of keys then run through this method - // to reprocess each pattern one key at a time - if (sequence.length > 1) { - return _bindSequence(combination, sequence, callback, action); - } - - // take the keys from this pattern and figure out what the actual - // pattern is all about - keys = combination === '+' ? ['+'] : combination.split('+'); - - for (i = 0; i < keys.length; ++i) { - key = keys[i]; - - // normalize key names - if (_SPECIAL_ALIASES[key]) { - key = _SPECIAL_ALIASES[key]; - } - - // if this is not a keypress event then we should - // be smart about using shift keys - // this will only work for US keyboards however - if (action && action != 'keypress' && _SHIFT_MAP[key]) { - key = _SHIFT_MAP[key]; - modifiers.push('shift'); - } - - // if this key is a modifier then add it to the list of modifiers - if (_isModifier(key)) { - modifiers.push(key); - } - } - - // depending on what the key combination is - // we will try to pick the best event for it - action = _pickBestAction(key, modifiers, action); - - // make sure to initialize array if this is the first time - // a callback is added for this key - if (!_callbacks[key]) { - _callbacks[key] = []; - } - - // remove an existing match if there is one - _getMatches(key, modifiers, action, !sequence_name, combination); - - // add this call back to the array - // if it is a sequence put it at the beginning - // if not put it at the end - // - // this is important because the way these are processed expects - // the sequence ones to come first - _callbacks[key][sequence_name ? 'unshift' : 'push']({ - callback: callback, - modifiers: modifiers, - action: action, - seq: sequence_name, - level: level, - combo: combination - }); - } - - /** - * binds multiple combinations to the same callback - * - * @param {Array} combinations - * @param {Function} callback - * @param {string|undefined} action - * @returns void - */ - function _bindMultiple(combinations, callback, action) { - for (var i = 0; i < combinations.length; ++i) { - _bindSingle(combinations[i], callback, action); - } - } - - // start! - _addEvent(document, 'keypress', _handleKey); - _addEvent(document, 'keydown', _handleKey); - _addEvent(document, 'keyup', _handleKey); - - var mousetrap = { - - /** - * binds an event to mousetrap - * - * can be a single key, a combination of keys separated with +, - * a comma separated list of keys, an array of keys, or - * a sequence of keys separated by spaces - * - * be sure to list the modifier keys first to make sure that the - * correct key ends up getting bound (the last key in the pattern) - * - * @param {string|Array} keys - * @param {Function} callback - * @param {string=} action - 'keypress', 'keydown', or 'keyup' - * @returns void - */ - bind: function(keys, callback, action) { - _bindMultiple(keys instanceof Array ? keys : [keys], callback, action); - _direct_map[keys + ':' + action] = callback; - return this; - }, - - /** - * unbinds an event to mousetrap - * - * the unbinding sets the callback function of the specified key combo - * to an empty function and deletes the corresponding key in the - * _direct_map dict. - * - * the keycombo+action has to be exactly the same as - * it was defined in the bind method - * - * TODO: actually remove this from the _callbacks dictionary instead - * of binding an empty function - * - * @param {string|Array} keys - * @param {string} action - * @returns void - */ - unbind: function(keys, action) { - if (_direct_map[keys + ':' + action]) { - delete _direct_map[keys + ':' + action]; - this.bind(keys, function() {}, action); - } - return this; - }, - - /** - * triggers an event that has already been bound - * - * @param {string} keys - * @param {string=} action - * @returns void - */ - trigger: function(keys, action) { - _direct_map[keys + ':' + action](); - return this; - }, - - /** - * resets the library back to its initial state. this is useful - * if you want to clear out the current keyboard shortcuts and bind - * new ones - for example if you switch to another page - * - * @returns void - */ - reset: function() { - _callbacks = {}; - _direct_map = {}; - return this; - } - }; - -module.exports = mousetrap; - - -},{}]},{},[1]) -(1) -}); \ No newline at end of file diff --git a/src/graph/ClusterMixin.js b/src/graph/ClusterMixin.js index 740f618f..bc8a8815 100644 --- a/src/graph/ClusterMixin.js +++ b/src/graph/ClusterMixin.js @@ -359,9 +359,9 @@ var ClusterMixin = { parentNode.dynamicEdgesLength = parentNode.dynamicEdges.length; // place the child node near the parent, not at the exact same location to avoid chaos in the system - childNode.x = parentNode.x + this.constants.physics.springLength * (0.1 * (0.5 - Math.random()) * parentNode.clusterSize); - childNode.y = parentNode.y + this.constants.physics.springLength * (0.1 * (0.5 - Math.random()) * parentNode.clusterSize); - console.log(childNode.x,childNode.y,parentNode.x,parentNode.y); + childNode.x = parentNode.x + this.constants.edges.length * 0.3 * (0.5 - Math.random()) * parentNode.clusterSize; + childNode.y = parentNode.y + this.constants.edges.length * 0.3 * (0.5 - Math.random()) * parentNode.clusterSize; + // remove node from the list delete parentNode.containedNodes[containedNodeId]; diff --git a/src/graph/Edge.js b/src/graph/Edge.js index c74a5bdc..5b6959f0 100644 --- a/src/graph/Edge.js +++ b/src/graph/Edge.js @@ -31,7 +31,7 @@ function Edge (properties, graph, constants) { this.title = undefined; this.width = constants.edges.width; this.value = undefined; - this.length = constants.physics.springLength; + this.length = constants.edges.length; this.selected = false; this.from = null; // a node @@ -55,6 +55,7 @@ function Edge (properties, graph, constants) { this.lengthFixed = false; this.setProperties(properties, constants); + } /** @@ -102,6 +103,7 @@ Edge.prototype.setProperties = function(properties, constants) { this.widthFixed = this.widthFixed || (properties.width !== undefined); this.lengthFixed = this.lengthFixed || (properties.length !== undefined); + this.stiffness = 1 / this.length; // set draw method based on style switch (this.style) { diff --git a/src/graph/Graph.js b/src/graph/Graph.js index 0dbc111a..e2949bb8 100644 --- a/src/graph/Graph.js +++ b/src/graph/Graph.js @@ -450,7 +450,7 @@ Graph.prototype.setOptions = function (options) { if (options.edges.length !== undefined && options.nodes && options.nodes.distance === undefined) { - this.constants.physics.springLength = options.edges.length; + this.constants.edges.length = options.edges.length; this.constants.nodes.distance = options.edges.length * 1.25; } @@ -1770,7 +1770,6 @@ Graph.prototype.start = function() { } - graph.start(); graph.start(); graph._redraw(); @@ -1792,7 +1791,7 @@ Graph.prototype.start = function() { */ Graph.prototype.singleStep = function() { if (this.moving) { - this._initializeForceCalculation(true); + this._initializeForceCalculation(); this._discreteStepNodes(); var vmin = this.constants.minVelocity; diff --git a/src/graph/physicsMixin.js b/src/graph/physicsMixin.js index b52d32c7..83cb438a 100644 --- a/src/graph/physicsMixin.js +++ b/src/graph/physicsMixin.js @@ -11,7 +11,7 @@ var physicsMixin = { * * @private */ - _initializeForceCalculation : function(useBarnesHut) { + _initializeForceCalculation : function() { // stop calculation if there is only one node if (this.nodeIndices.length == 1) { this.nodes[this.nodeIndices[0]]._setForce(0,0); @@ -22,15 +22,9 @@ var physicsMixin = { this.clusterToFit(this.constants.clustering.reduceToNodes, false); } - this._calculateForcesRepulsion(); - -// // we now start the force calculation -// if (useBarnesHut == true) { -// this._calculateForcesBarnesHut(); -// } -// else { -// this._calculateForcesRepulsion(); -// } + // we now start the force calculation + // this._calculateForcesBarnesHut(); + this._calculateForcesOriginal(); } }, @@ -40,23 +34,23 @@ var physicsMixin = { * Forces are caused by: edges, repulsing forces between nodes, gravity * @private */ - _calculateForcesRepulsion : function() { + _calculateForcesOriginal : function() { // Gravity is required to keep separated groups from floating off // the forces are reset to zero in this loop by using _setForce instead // of _addForce // var startTimeAll = Date.now(); - this._applyCentralGravity(); + this._calculateGravitationalForces(1); // var startTimeRepulsion = Date.now(); // All nodes repel eachother. - this._applyNodeRepulsion(); + this._calculateRepulsionForces(); // var endTimeRepulsion = Date.now(); // the edges are strings - this._applySpringForces(); + this._calculateSpringForces(1); // var endTimeAll = Date.now(); @@ -76,7 +70,7 @@ var physicsMixin = { // var startTimeAll = Date.now(); - this._applyCentralGravity(); + this._clearForces(); // var startTimeRepulsion = Date.now(); // All nodes repel eachother. @@ -85,7 +79,7 @@ var physicsMixin = { // var endTimeRepulsion = Date.now(); // the edges are strings - this._applySpringForces(); + this._calculateSpringForces(1); // var endTimeAll = Date.now(); @@ -105,7 +99,7 @@ var physicsMixin = { } }, - _applyCentralGravity : function() { + _calculateGravitationalForces : function(boost) { var dx, dy, angle, fx, fy, node, i; var nodes = this.nodes; var gravity = this.constants.physics.centralGravity; @@ -130,7 +124,7 @@ var physicsMixin = { } }, - _applyNodeRepulsion : function() { + _calculateRepulsionForces : function() { var dx, dy, angle, distance, fx, fy, clusterSize, repulsingForce, node1, node2, i, j; var nodes = this.nodes; @@ -180,7 +174,7 @@ var physicsMixin = { } }, - _applySpringForces : function() { + _calculateSpringForces : function(boost) { var dx, dy, angle, fx, fy, springForce, length, edgeLength, edge, edgeId, clusterSize; var edges = this.edges; @@ -206,7 +200,7 @@ var physicsMixin = { fx = Math.cos(angle) * springForce; fy = Math.sin(angle) * springForce; - //console.log(edge.length,dx,dy,edge.springConstant,angle) + edge.from._addForce(-fx, -fy); edge.to._addForce(fx, fy); } From da444af45e3d92fd83bb9cfbac14e6c6ff466255 Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Sat, 8 Feb 2014 19:38:29 +0100 Subject: [PATCH 40/52] fixed BUG! barnes hut functional but slower than almende linear approx algorithm. Now to fix the naming of functions and explain code... --- .gitignore | 2 +- examples/graph/02_random_nodes.html | 6 +-- src/graph/ClusterMixin.js | 4 +- src/graph/Edge.js | 4 +- src/graph/Graph.js | 37 +++++++++---- src/graph/Node.js | 6 ++- src/graph/physicsMixin.js | 82 +++++++++++------------------ 7 files changed, 70 insertions(+), 71 deletions(-) diff --git a/.gitignore b/.gitignore index ec01a71f..df8fb4e6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,8 @@ .idea node_modules .project -dist .settings/.jsdtscope .settings/org.eclipse.wst.jsdt.ui.superType.container .settings/org.eclipse.wst.jsdt.ui.superType.name npm-debug.log +dist/ diff --git a/examples/graph/02_random_nodes.html b/examples/graph/02_random_nodes.html index 57ea0714..69ac60f8 100755 --- a/examples/graph/02_random_nodes.html +++ b/examples/graph/02_random_nodes.html @@ -90,8 +90,7 @@ edges: { length: 50 }, - stabilize: false, - clustering : true + stabilize: false }; graph = new vis.Graph(container, data, options); @@ -104,7 +103,8 @@ - +calculation time: ms +render time: ms
    diff --git a/src/graph/ClusterMixin.js b/src/graph/ClusterMixin.js index bc8a8815..c4755a51 100644 --- a/src/graph/ClusterMixin.js +++ b/src/graph/ClusterMixin.js @@ -618,7 +618,7 @@ var ClusterMixin = { // update the properties of the child and parent var massBefore = parentNode.mass; childNode.clusterSession = this.clusterSession; - parentNode.mass += childNode.mass; + parentNode.mass += this.constants.clustering.massTransferCoefficient * childNode.mass; parentNode.clusterSize += childNode.clusterSize; parentNode.fontSize += this.constants.clustering.fontSizeMultiplier * childNode.clusterSize; @@ -931,7 +931,7 @@ var ClusterMixin = { for (var i = 0; i < this.nodeIndices.length; i++) { var node = this.nodes[this.nodeIndices[i]]; if (!node.isFixed()) { - var radius = this.constants.physics.springLength * (1 + 0.6*node.clusterSize); + var radius = this.constants.edges.length * (1 + 0.6*node.clusterSize); var angle = 2 * Math.PI * Math.random(); node.x = radius * Math.cos(angle); node.y = radius * Math.sin(angle); diff --git a/src/graph/Edge.js b/src/graph/Edge.js index 5b6959f0..c5192f90 100644 --- a/src/graph/Edge.js +++ b/src/graph/Edge.js @@ -31,7 +31,7 @@ function Edge (properties, graph, constants) { this.title = undefined; this.width = constants.edges.width; this.value = undefined; - this.length = constants.edges.length; + this.length = constants.physics.springLength; this.selected = false; this.from = null; // a node @@ -49,7 +49,6 @@ function Edge (properties, graph, constants) { // 2012-08-08 this.dash = util.extend({}, constants.edges.dash); // contains properties length, gap, altLength - this.springConstant = constants.physics.springConstant; this.color = constants.edges.color; this.widthFixed = false; this.lengthFixed = false; @@ -103,7 +102,6 @@ Edge.prototype.setProperties = function(properties, constants) { this.widthFixed = this.widthFixed || (properties.width !== undefined); this.lengthFixed = this.lengthFixed || (properties.length !== undefined); - this.stiffness = 1 / this.length; // set draw method based on style switch (this.style) { diff --git a/src/graph/Graph.js b/src/graph/Graph.js index e2949bb8..d7c446f1 100644 --- a/src/graph/Graph.js +++ b/src/graph/Graph.js @@ -66,11 +66,12 @@ function Graph (container, data, options) { } }, physics: { - springConstant:0.05, - springLength: 100, - centralGravity: 0.1, - nodeGravityConstant: -10000, - barnesHutTheta: 0.2 + enableBarnesHut: false, + barnesHutTheta: 1 / 0.4, // inverted to save time during calculation + barnesHutGravitationalConstant: -10000, + centralGravity: 0.08, + springLength: 50, + springConstant: 0.02 }, clustering: { // Per Node in Cluster = PNiC enabled: false, // (Boolean) | global on/off switch for clustering. @@ -88,7 +89,8 @@ function Graph (container, data, options) { nodeScaling: {width: 10, // (px PNiC) | growth of the width per node in cluster. height: 10, // (px PNiC) | growth of the height per node in cluster. radius: 10}, // (px PNiC) | growth of the radius per node in cluster. - activeAreaBoxSize: 100 // (px) | box area around the curser where clusters are popped open. + activeAreaBoxSize: 100, // (px) | box area around the curser where clusters are popped open. + massTransferCoefficient: 1 // (multiplier) | parent.mass += massTransferCoefficient * child.mass }, navigation: { enabled: false, @@ -101,7 +103,7 @@ function Graph (container, data, options) { dataManipulationToolbar: { enabled: false }, - minVelocity: 0.2, // px/s + minVelocity: 0.1, // px/s maxIterations: 1000 // maximum number of iteration to stabilize }; @@ -642,7 +644,7 @@ Graph.prototype._createKeyBinds = function() { this.mousetrap.bind("pagedown",this._zoomOut.bind(me),"keydown"); this.mousetrap.bind("pagedown",this._stopZoom.bind(me), "keyup"); } - this.mousetrap.bind("b",this._formBarnesHutTree.bind(me)); + this.mousetrap.bind("b",this._toggleBarnesHut.bind(me)); if (this.constants.dataManipulationToolbar.enabled == true) { this.mousetrap.bind("escape",this._createManipulatorBar.bind(me)); @@ -1502,7 +1504,7 @@ Graph.prototype._redraw = function() { this._doInAllSectors("_drawEdges",ctx); this._doInAllSectors("_drawNodes",ctx,true); - this._drawTree(ctx,"#F00F0F"); +// this._drawTree(ctx,"#F00F0F"); // restore original scaling and translation ctx.restore(); @@ -1710,7 +1712,7 @@ Graph.prototype._isMoving = function(vmin) { * @private */ Graph.prototype._discreteStepNodes = function() { - var interval = 0.5; + var interval = 1; var nodes = this.nodes; this.constants.maxVelocity = 30; @@ -1769,14 +1771,28 @@ Graph.prototype.start = function() { graph._zoom(graph.scale*(1 + graph.zoomIncrement), center); } + var calctimeStart = Date.now(); graph.start(); + graph.start(); + + var calctime = Date.now() - calctimeStart; + var rendertimeStart = Date.now(); graph._redraw(); + var rendertime = Date.now() - rendertimeStart; //this.end = window.performance.now(); //this.time = this.end - this.startTime; //console.log('refresh time: ' + this.time); //this.startTime = window.performance.now(); + var DOMelement = document.getElementById("calctimereporter"); + if (DOMelement !== undefined) { + DOMelement.innerHTML = calctime; + } + DOMelement = document.getElementById("rendertimereporter"); + if (DOMelement !== undefined) { + DOMelement.innerHTML = rendertime; + } }, this.renderTimestep); } } @@ -1823,6 +1839,7 @@ Graph.prototype.toggleFreeze = function() { * @private */ Graph.prototype._loadPhysicsSystem = function() { + this.forceCalculationTime = 0; for (var mixinFunction in physicsMixin) { if (physicsMixin.hasOwnProperty(mixinFunction)) { Graph.prototype[mixinFunction] = physicsMixin[mixinFunction]; diff --git a/src/graph/Node.js b/src/graph/Node.js index 044eed67..dd0c991f 100644 --- a/src/graph/Node.js +++ b/src/graph/Node.js @@ -993,8 +993,10 @@ Node.prototype.clearVelocity = function() { */ Node.prototype.updateVelocity = function(massBeforeClustering) { var energyBefore = this.vx * this.vx * massBeforeClustering; - this.vx = (this.vx < 0) ? -Math.sqrt(energyBefore/this.mass) : Math.sqrt(energyBefore/this.mass); + //this.vx = (this.vx < 0) ? -Math.sqrt(energyBefore/this.mass) : Math.sqrt(energyBefore/this.mass); + this.vx = Math.sqrt(energyBefore/this.mass); energyBefore = this.vy * this.vy * massBeforeClustering; - this.vy = (this.vy < 0) ? -Math.sqrt(energyBefore/this.mass) : Math.sqrt(energyBefore/this.mass); + //this.vy = (this.vy < 0) ? -Math.sqrt(energyBefore/this.mass) : Math.sqrt(energyBefore/this.mass); + this.vy = Math.sqrt(energyBefore/this.mass); }; diff --git a/src/graph/physicsMixin.js b/src/graph/physicsMixin.js index 83cb438a..357b256e 100644 --- a/src/graph/physicsMixin.js +++ b/src/graph/physicsMixin.js @@ -5,6 +5,12 @@ var physicsMixin = { + + _toggleBarnesHut : function() { + this.constants.physics.enableBarnesHut = !this.constants.physics.enableBarnesHut; + this.moving = true; + this.start(); + }, /** * Before calculating the forces, we check if we need to cluster to keep up performance and we check * if there is more than one node. If it is just one node, we dont calculate anything. @@ -23,8 +29,13 @@ var physicsMixin = { } // we now start the force calculation - // this._calculateForcesBarnesHut(); - this._calculateForcesOriginal(); + if (this.constants.physics.enableBarnesHut == true) { + this._calculateForcesBarnesHut(); + } + else { + this.barnesHutTree = undefined; + this._calculateForcesRepulsion(); + } } }, @@ -34,28 +45,15 @@ var physicsMixin = { * Forces are caused by: edges, repulsing forces between nodes, gravity * @private */ - _calculateForcesOriginal : function() { + _calculateForcesRepulsion : function() { // Gravity is required to keep separated groups from floating off // the forces are reset to zero in this loop by using _setForce instead // of _addForce + this._calculateGravitationalForces(); -// var startTimeAll = Date.now(); - - this._calculateGravitationalForces(1); - -// var startTimeRepulsion = Date.now(); - // All nodes repel eachother. this._calculateRepulsionForces(); -// var endTimeRepulsion = Date.now(); - - // the edges are strings - this._calculateSpringForces(1); - -// var endTimeAll = Date.now(); - -// echo("Time repulsion part:", endTimeRepulsion - startTimeRepulsion); -// echo("Time total force calc:", endTimeAll - startTimeAll); + this._calculateSpringForces(); }, /** @@ -64,27 +62,11 @@ var physicsMixin = { * @private */ _calculateForcesBarnesHut : function() { - // Gravity is required to keep separated groups from floating off - // the forces are reset to zero in this loop by using _setForce instead - // of _addForce - -// var startTimeAll = Date.now(); - - this._clearForces(); + this._calculateGravitationalForces(); -// var startTimeRepulsion = Date.now(); - // All nodes repel eachother. this._calculateBarnesHutForces(); -// var endTimeRepulsion = Date.now(); - - // the edges are strings - this._calculateSpringForces(1); - -// var endTimeAll = Date.now(); - -// echo("Time repulsion part:", endTimeRepulsion - startTimeRepulsion); -// echo("Time total force calc:", endTimeAll - startTimeAll); + this._calculateSpringForces(); }, @@ -99,7 +81,7 @@ var physicsMixin = { } }, - _calculateGravitationalForces : function(boost) { + _calculateGravitationalForces : function() { var dx, dy, angle, fx, fy, node, i; var nodes = this.nodes; var gravity = this.constants.physics.centralGravity; @@ -135,7 +117,6 @@ var physicsMixin = { // repulsing forces between nodes var minimumDistance = this.constants.nodes.distance; - //var steepness = 10; // we loop from i over all but the last entree in the array // j loops from i+1 to the last. This way we do not double count any of the indices, nor i == j @@ -148,8 +129,6 @@ var physicsMixin = { dy = node2.y - node1.y; distance = Math.sqrt(dx * dx + dy * dy); - - // clusters have a larger region of influence minimumDistance = (clusterSize == 0) ? this.constants.nodes.distance : (this.constants.nodes.distance * (1 + clusterSize * this.constants.clustering.distanceAmplification)); var a = a_base / minimumDistance; if (distance < 2*minimumDistance) { // at 2.0 * the minimum distance, the force is 0.000045 @@ -174,7 +153,7 @@ var physicsMixin = { } }, - _calculateSpringForces : function(boost) { + _calculateSpringForces : function() { var dx, dy, angle, fx, fy, springForce, length, edgeLength, edge, edgeId, clusterSize; var edges = this.edges; @@ -196,7 +175,7 @@ var physicsMixin = { length = Math.sqrt(dx * dx + dy * dy); angle = Math.atan2(dy, dx); - springForce = edge.springConstant * (edgeLength - length); + springForce = this.constants.physics.springConstant * (edgeLength - length); fx = Math.cos(angle) * springForce; fy = Math.sin(angle) * springForce; @@ -241,11 +220,8 @@ var physicsMixin = { distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { // distance is 0 if it looks to apply a force on itself. - // we invert it here because we need the inverted distance for the force calculation too. - var distanceInv = 1/distance; - // BarnesHut condition - if (parentBranch.size * distanceInv > this.constants.physics.barnesHutTheta) { + if (distance * parentBranch.calcSize < this.constants.physics.barnesHutTheta) { // Did not pass the condition, go into children if available if (parentBranch.childrenCount == 4) { this._getForceContribution(parentBranch.children.NW,node); @@ -255,20 +231,20 @@ var physicsMixin = { } else { // parentBranch must have only one node, if it was empty we wouldnt be here if (parentBranch.children.data.id != node.id) { // if it is not self - this._getForceOnNode(parentBranch, node, dx ,dy, distanceInv); + this._getForceOnNode(parentBranch, node, dx ,dy, distance); } } } else { - this._getForceOnNode(parentBranch, node, dx ,dy, distanceInv); + this._getForceOnNode(parentBranch, node, dx ,dy, distance); } } } }, - _getForceOnNode : function(parentBranch, node, dx ,dy, distanceInv) { + _getForceOnNode : function(parentBranch, node, dx ,dy, distance) { // even if the parentBranch only has one node, its Center of Mass is at the right place (the node in this case). - var gravityForce = this.constants.physics.nodeGravityConstant * parentBranch.mass * node.mass * distanceInv * distanceInv; + var gravityForce = this.constants.physics.barnesHutGravitationalConstant * parentBranch.mass * node.mass / (distance * distance); var angle = Math.atan2(dy, dx); var fx = Math.cos(angle) * gravityForce; var fy = Math.sin(angle) * gravityForce; @@ -308,6 +284,7 @@ var physicsMixin = { mass:0, range:{minX:minX,maxX:maxX,minY:minY,maxY:maxY}, size: Math.abs(maxX - minX), + calcSize: 1 / Math.abs(maxX - minX), children: {data:null}, level: 0, childrenCount: 4 @@ -324,6 +301,7 @@ var physicsMixin = { this.barnesHutTree = barnesHutTree }, + _updateBranchMass : function(parentBranch, node) { var totalMass = parentBranch.mass + node.mass; var totalMassInv = 1/totalMass; @@ -337,6 +315,7 @@ var physicsMixin = { parentBranch.mass = totalMass; }, + _placeInTree : function(parentBranch,node) { // update the mass of the branch. this._updateBranchMass(parentBranch,node); @@ -359,6 +338,7 @@ var physicsMixin = { } }, + _placeInRegion : function(parentBranch,node,region) { switch (parentBranch.children[region].childrenCount) { case 0: // place node here @@ -376,6 +356,7 @@ var physicsMixin = { } }, + _splitBranch : function(parentBranch) { // if the branch is filled with a node, replace the node in the new subset. var containedNode = null; @@ -441,6 +422,7 @@ var physicsMixin = { mass:0, range:{minX:minX,maxX:maxX,minY:minY,maxY:maxY}, size: 0.5 * parentBranch.size, + calcSize: 2 * parentBranch.calcSize, children: {data:null}, level: parentBranch.level +1, childrenCount: 0 From 4a0826969933458a212de81792ec0c8ce5164591 Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Mon, 10 Feb 2014 16:02:34 +0100 Subject: [PATCH 41/52] mixin refactoring, added cluster normalization, tweaked forces, separated forces for repulsion and barnes hut --- Jakefile.js | 15 +- dist/vis.min.js | 13 +- src/graph/Graph.js | 244 ++++++------------ src/graph/Node.js | 76 +++--- src/graph/{ => graphMixins}/ClusterMixin.js | 122 +++++++-- .../ManipulationMixin.js} | 0 src/graph/graphMixins/MixinLoader.js | 185 +++++++++++++ .../{ => graphMixins}/NavigationMixin.js | 0 src/graph/{ => graphMixins}/SectorsMixin.js | 0 src/graph/{ => graphMixins}/SelectionMixin.js | 0 src/graph/graphMixins/physics/PhysicsMixin.js | 114 ++++++++ .../physics/barnesHut.js} | 234 +++-------------- src/graph/graphMixins/physics/repulsion.js | 61 +++++ 13 files changed, 618 insertions(+), 446 deletions(-) rename src/graph/{ => graphMixins}/ClusterMixin.js (89%) rename src/graph/{manipulationMixin.js => graphMixins/ManipulationMixin.js} (100%) create mode 100644 src/graph/graphMixins/MixinLoader.js rename src/graph/{ => graphMixins}/NavigationMixin.js (100%) rename src/graph/{ => graphMixins}/SectorsMixin.js (100%) rename src/graph/{ => graphMixins}/SelectionMixin.js (100%) create mode 100644 src/graph/graphMixins/physics/PhysicsMixin.js rename src/graph/{physicsMixin.js => graphMixins/physics/barnesHut.js} (55%) create mode 100644 src/graph/graphMixins/physics/repulsion.js diff --git a/Jakefile.js b/Jakefile.js index 511dbd21..971f2a7e 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -82,12 +82,15 @@ task('build', {async: true}, function () { './src/graph/Popup.js', './src/graph/Groups.js', './src/graph/Images.js', - './src/graph/PhysicsMixin.js', - './src/graph/ManipulationMixin.js', - './src/graph/SectorsMixin.js', - './src/graph/ClusterMixin.js', - './src/graph/SelectionMixin.js', - './src/graph/NavigationMixin.js', + './src/graph/graphMixins/physics/PhysicsMixin.js', + './src/graph/graphMixins/physics/barnesHut.js', + './src/graph/graphMixins/physics/repulsion.js', + './src/graph/graphMixins/ManipulationMixin.js', + './src/graph/graphMixins/SectorsMixin.js', + './src/graph/graphMixins/ClusterMixin.js', + './src/graph/graphMixins/SelectionMixin.js', + './src/graph/graphMixins/NavigationMixin.js', + './src/graph/graphMixins/MixinLoader.js', './src/graph/Graph.js', './src/module/exports.js' diff --git a/dist/vis.min.js b/dist/vis.min.js index ebb86c98..95acc029 100644 --- a/dist/vis.min.js +++ b/dist/vis.min.js @@ -5,7 +5,7 @@ * A dynamic, browser-based visualization library. * * @version 0.5.0-SNAPSHOT - * @date 2014-02-08 + * @date 2014-02-10 * * @license * Copyright (C) 2011-2014 Almende B.V, http://almende.com @@ -22,10 +22,11 @@ * License for the specific language governing permissions and limitations under * the License. */ -!function(t){if("object"==typeof exports)module.exports=t();else if("function"==typeof define&&define.amd)define(t);else{var e;"undefined"!=typeof window?e=window:"undefined"!=typeof global?e=global:"undefined"!=typeof self&&(e=self),e.vis=t()}}(function(){var define,module,exports;return function t(e,i,n){function s(r,a){if(!i[r]){if(!e[r]){var h="function"==typeof require&&require;if(!a&&h)return h(r,!0);if(o)return o(r,!0);throw new Error("Cannot find module '"+r+"'")}var l=i[r]={exports:{}};e[r][0].call(l.exports,function(t){var i=e[r][1][t];return s(i?i:t)},l,l.exports,t,e,i,n)}return i[r].exports}for(var o="function"==typeof require&&require,r=0;ri;++i)t.call(e||this,this[i],i,this)}),Array.prototype.map||(Array.prototype.map=function(t,e){var i,n,s;if(null==this)throw new TypeError(" this is null or not defined");var o=Object(this),r=o.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(e&&(i=e),n=new Array(r),s=0;r>s;){var a,h;s in o&&(a=o[s],h=t.call(i,a,s,o),n[s]=h),s++}return n}),Array.prototype.filter||(Array.prototype.filter=function(t){"use strict";if(null==this)throw new TypeError;var e=Object(this),i=e.length>>>0;if("function"!=typeof t)throw new TypeError;for(var n=[],s=arguments[1],o=0;i>o;o++)if(o in e){var r=e[o];t.call(s,r,o,e)&&n.push(r)}return n}),Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,e=!{toString:null}.propertyIsEnumerable("toString"),i=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],n=i.length;return function(s){if("object"!=typeof s&&"function"!=typeof s||null===s)throw new TypeError("Object.keys called on non-object");var o=[];for(var r in s)t.call(s,r)&&o.push(r);if(e)for(var a=0;n>a;a++)t.call(s,i[a])&&o.push(i[a]);return o}}()),Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s}),Object.create||(Object.create=function(t){function e(){}if(arguments.length>1)throw new Error("Object.create implementation only accepts the first parameter.");return e.prototype=t,new e}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s});var util={};util.isNumber=function(t){return t instanceof Number||"number"==typeof t},util.isString=function(t){return t instanceof String||"string"==typeof t},util.isDate=function(t){if(t instanceof Date)return!0;if(util.isString(t)){var e=ASPDateRegex.exec(t);if(e)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},util.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},util.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},util.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var n=arguments[e];for(var s in n)n.hasOwnProperty(s)&&void 0!==n[s]&&(t[s]=n[s])}return t},util.convert=function(t,e){var i;if(void 0===t)return void 0;if(null===t)return null;if(!e)return t;if("string"!=typeof e&&!(e instanceof String))throw new Error("Type must be a string");switch(e){case"boolean":case"Boolean":return Boolean(t);case"number":case"Number":return Number(t.valueOf());case"string":case"String":return String(t);case"Date":if(util.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(moment.isMoment(t))return new Date(t.valueOf());if(util.isString(t))return i=ASPDateRegex.exec(t),i?new Date(Number(i[1])):moment(t).toDate();throw new Error("Cannot convert object of type "+util.getType(t)+" to type Date");case"Moment":if(util.isNumber(t))return moment(t);if(t instanceof Date)return moment(t.valueOf());if(moment.isMoment(t))return moment(t);if(util.isString(t))return i=ASPDateRegex.exec(t),moment(i?Number(i[1]):t);throw new Error("Cannot convert object of type "+util.getType(t)+" to type Date");case"ISODate":if(util.isNumber(t))return new Date(t);if(t instanceof Date)return t.toISOString();if(moment.isMoment(t))return t.toDate().toISOString();if(util.isString(t))return i=ASPDateRegex.exec(t),i?new Date(Number(i[1])).toISOString():new Date(t).toISOString();throw new Error("Cannot convert object of type "+util.getType(t)+" to type ISODate");case"ASPDate":if(util.isNumber(t))return"/Date("+t+")/";if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(util.isString(t)){i=ASPDateRegex.exec(t);var n;return n=i?new Date(Number(i[1])).valueOf():new Date(t).valueOf(),"/Date("+n+")/"}throw new Error("Cannot convert object of type "+util.getType(t)+" to type ASPDate");default:throw new Error("Cannot convert object of type "+util.getType(t)+' to type "'+e+'"')}};var ASPDateRegex=/^\/?Date\((\-?\d+)/i;util.getType=function(t){var e=typeof t;return"object"==e?null==t?"null":t instanceof Boolean?"Boolean":t instanceof Number?"Number":t instanceof String?"String":t instanceof Array?"Array":t instanceof Date?"Date":"Object":"number"==e?"Number":"boolean"==e?"Boolean":"string"==e?"String":e},util.getAbsoluteLeft=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetLeft,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetLeft,n-=s.scrollLeft,s=s.offsetParent;return n},util.getAbsoluteTop=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetTop,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetTop,n-=s.scrollTop,s=s.offsetParent;return n},util.getPageY=function(t){if("pageY"in t)return t.pageY;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientY:t.clientY;var i=document.documentElement,n=document.body;return e+(i&&i.scrollTop||n&&n.scrollTop||0)-(i&&i.clientTop||n&&n.clientTop||0)},util.getPageX=function(t){if("pageY"in t)return t.pageX;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientX:t.clientX;var i=document.documentElement,n=document.body;return e+(i&&i.scrollLeft||n&&n.scrollLeft||0)-(i&&i.clientLeft||n&&n.clientLeft||0)},util.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},util.removeClassName=function(t,e){var i=t.className.split(" "),n=i.indexOf(e);-1!=n&&(i.splice(n,1),t.className=i.join(" "))},util.forEach=function(t,e){var i,n;if(t instanceof Array)for(i=0,n=t.length;n>i;i++)e(t[i],i,t);else for(i in t)t.hasOwnProperty(i)&&e(t[i],i,t)},util.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},util.addEventListener=function(t,e,i,n){t.addEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.addEventListener(e,i,n)):t.attachEvent("on"+e,i)},util.removeEventListener=function(t,e,i,n){t.removeEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.removeEventListener(e,i,n)):t.detachEvent("on"+e,i)},util.getTarget=function(t){t||(t=window.event);var e;return t.target?e=t.target:t.srcElement&&(e=t.srcElement),void 0!=e.nodeType&&3==e.nodeType&&(e=e.parentNode),e},util.stopPropagation=function(t){t||(t=window.event),t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},util.fakeGesture=function(t,e){var i=null;return Hammer.event.collectEventData(this,i,e)},util.preventDefault=function(t){t||(t=window.event),t.preventDefault?t.preventDefault():t.returnValue=!1},util.option={},util.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},util.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},util.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?String(t):e||null},util.option.asSize=function(t,e){return"function"==typeof t&&(t=t()),util.isString(t)?t:util.isNumber(t)?t+"px":e||null},util.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null},util.GiveDec=function GiveDec(Hex){return Value="A"==Hex?10:"B"==Hex?11:"C"==Hex?12:"D"==Hex?13:"E"==Hex?14:"F"==Hex?15:eval(Hex)},util.GiveHex=function(t){return Value=10==t?"A":11==t?"B":12==t?"C":13==t?"D":14==t?"E":15==t?"F":""+t},util.hexToRGB=function(t){t=t.replace("#","").toUpperCase();var e=util.GiveDec(t.substring(0,1)),i=util.GiveDec(t.substring(1,2)),n=util.GiveDec(t.substring(2,3)),s=util.GiveDec(t.substring(3,4)),o=util.GiveDec(t.substring(4,5)),r=util.GiveDec(t.substring(5,6)),a=16*e+i,h=16*n+s,i=16*o+r;return{r:a,g:h,b:i}},util.RGBToHex=function(t,e,i){var n=util.GiveHex(Math.floor(t/16)),s=util.GiveHex(t%16),o=util.GiveHex(Math.floor(e/16)),r=util.GiveHex(e%16),a=util.GiveHex(Math.floor(i/16)),h=util.GiveHex(i%16),l=n+s+o+r+a+h;return"#"+l},util.RGBToHSV=function(t,e,i){t/=255,e/=255,i/=255;var n=Math.min(t,Math.min(e,i)),s=Math.max(t,Math.max(e,i));if(n==s)return{h:0,s:0,v:n};var o=t==n?e-i:i==n?t-e:i-t,r=t==n?3:i==n?1:5,a=60*(r-o/(s-n))/360,h=(s-n)/s,l=s;return{h:a,s:h,v:l}},util.HSVToRGB=function(t,e,i){var n,s,o,r=Math.floor(6*t),a=6*t-r,h=i*(1-e),l=i*(1-a*e),c=i*(1-(1-a)*e);switch(r%6){case 0:n=i,s=c,o=h;break;case 1:n=l,s=i,o=h;break;case 2:n=h,s=i,o=c;break;case 3:n=h,s=l,o=i;break;case 4:n=c,s=h,o=i;break;case 5:n=i,s=h,o=l}return{r:Math.floor(255*n),g:Math.floor(255*s),b:Math.floor(255*o)}},util.HSVToHex=function(t,e,i){var n=util.HSVToRGB(t,e,i);return util.RGBToHex(n.r,n.g,n.b)},util.hexToHSV=function(t){var e=util.hexToRGB(t);return util.RGBToHSV(e.r,e.g,e.b)};var events={listeners:[],indexOf:function(t){for(var e=this.listeners,i=0,n=this.listeners.length;n>i;i++){var s=e[i];if(s&&s.object==t)return i}return-1},addListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];s||(s={object:t,events:{}},this.listeners.push(s));var o=s.events[e];o||(o=[],s.events[e]=o),-1==o.indexOf(i)&&o.push(i)},removeListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];o&&(n=o.indexOf(i),-1!=n&&o.splice(n,1),0==o.length&&delete s.events[e]);var r=0,a=s.events;for(var h in a)a.hasOwnProperty(h)&&r++;0==r&&delete this.listeners[n]}},removeAllListeners:function(){this.listeners=[]},trigger:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];if(o)for(var r=0,a=o.length;a>r;r++)o[r](i)}}};EventBus.prototype.on=function(t,e,i){var n=t instanceof RegExp?t:new RegExp(t.replace("*","\\w+")),s={id:util.randomUUID(),event:t,regexp:n,callback:"function"==typeof e?e:null,target:i};return this.subscriptions.push(s),s.id},EventBus.prototype.off=function(t){for(var e=0;eo;o++)i=s._addItem(t[o]),n.push(i);else if(util.isDataTable(t))for(var a=this._getColumnNames(t),h=0,l=t.getNumberOfRows();l>h;h++){for(var c={},d=0,u=a.length;u>d;d++){var p=a[d];c[p]=t.getValue(h,d)}i=s._addItem(c),n.push(i)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");i=s._addItem(t),n.push(i)}return n.length&&this._trigger("add",{items:n},e),n},DataSet.prototype.update=function(t,e){var i=[],n=[],s=this,o=s.fieldId,r=function(t){var e=t[o];s.data[e]?(e=s._updateItem(t),n.push(e)):(e=s._addItem(t),i.push(e))};if(t instanceof Array)for(var a=0,h=t.length;h>a;a++)r(t[a]);else if(util.isDataTable(t))for(var l=this._getColumnNames(t),c=0,d=t.getNumberOfRows();d>c;c++){for(var u={},p=0,f=l.length;f>p;p++){var g=l[p];u[g]=t.getValue(c,p)}r(u)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");r(t)}return i.length&&this._trigger("add",{items:i},e),n.length&&this._trigger("update",{items:n},e),i.concat(n)},DataSet.prototype.get=function(){var t,e,i,n,s=this,o=this.showInternalIds,r=util.getType(arguments[0]);"String"==r||"Number"==r?(t=arguments[0],i=arguments[1],n=arguments[2]):"Array"==r?(e=arguments[0],i=arguments[1],n=arguments[2]):(i=arguments[0],n=arguments[1]);var a;if(i&&i.type){if(a="DataTable"==i.type?"DataTable":"Array",n&&a!=util.getType(n))throw new Error('Type of parameter "data" ('+util.getType(n)+") does not correspond with specified options.type ("+i.type+")");if("DataTable"==a&&!util.isDataTable(n))throw new Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else a=n?"DataTable"==util.getType(n)?"DataTable":"Array":"Array";void 0!=i&&void 0!=i.showInternalIds&&(this.showInternalIds=i.showInternalIds);var h,l,c,d,u=i&&i.convert||this.options.convert,p=i&&i.filter,f=[];if(void 0!=t)h=s._getItem(t,u),p&&!p(h)&&(h=null);else if(void 0!=e)for(c=0,d=e.length;d>c;c++)h=s._getItem(e[c],u),(!p||p(h))&&f.push(h);else for(l in this.data)this.data.hasOwnProperty(l)&&(h=s._getItem(l,u),(!p||p(h))&&f.push(h));if(this.showInternalIds=o,i&&i.order&&void 0==t&&this._sort(f,i.order),i&&i.fields){var g=i.fields;if(void 0!=t)h=this._filterFields(h,g);else for(c=0,d=f.length;d>c;c++)f[c]=this._filterFields(f[c],g)}if("DataTable"==a){var m=this._getColumnNames(n);if(void 0!=t)s._appendRow(n,m,h);else for(c=0,d=f.length;d>c;c++)s._appendRow(n,m,f[c]);return n}if(void 0!=t)return h;if(n){for(c=0,d=f.length;d>c;c++)n.push(f[c]);return n}return f},DataSet.prototype.getIds=function(t){var e,i,n,s,o,r=this.data,a=t&&t.filter,h=t&&t.order,l=t&&t.convert||this.options.convert,c=[];if(a)if(h){o=[];for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,l),a(s)&&o.push(s));for(this._sort(o,h),e=0,i=o.length;i>e;e++)c[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,l),a(s)&&c.push(s[this.fieldId]));else if(h){o=[];for(n in r)r.hasOwnProperty(n)&&o.push(r[n]);for(this._sort(o,h),e=0,i=o.length;i>e;e++)c[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=r[n],c.push(s[this.fieldId]));return c},DataSet.prototype.forEach=function(t,e){var i,n,s=e&&e.filter,o=e&&e.convert||this.options.convert,r=this.data;if(e&&e.order)for(var a=this.get(e),h=0,l=a.length;l>h;h++)i=a[h],n=i[this.fieldId],t(i,n);else for(n in r)r.hasOwnProperty(n)&&(i=this._getItem(n,o),(!s||s(i))&&t(i,n))},DataSet.prototype.map=function(t,e){var i,n=e&&e.filter,s=e&&e.convert||this.options.convert,o=[],r=this.data;for(var a in r)r.hasOwnProperty(a)&&(i=this._getItem(a,s),(!n||n(i))&&o.push(t(i,a)));return e&&e.order&&this._sort(o,e.order),o},DataSet.prototype._filterFields=function(t,e){var i={};for(var n in t)t.hasOwnProperty(n)&&-1!=e.indexOf(n)&&(i[n]=t[n]);return i},DataSet.prototype._sort=function(t,e){if(util.isString(e)){var i=e;t.sort(function(t,e){var n=t[i],s=e[i];return n>s?1:s>n?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},DataSet.prototype.remove=function(t,e){var i,n,s,o=[];if(t instanceof Array)for(i=0,n=t.length;n>i;i++)s=this._remove(t[i]),null!=s&&o.push(s);else s=this._remove(t),null!=s&&o.push(s);return o.length&&this._trigger("remove",{items:o},e),o},DataSet.prototype._remove=function(t){if(util.isNumber(t)||util.isString(t)){if(this.data[t])return delete this.data[t],delete this.internalIds[t],t}else if(t instanceof Object){var e=t[this.fieldId];if(e&&this.data[e])return delete this.data[e],delete this.internalIds[e],e}return null},DataSet.prototype.clear=function(t){var e=Object.keys(this.data);return this.data={},this.internalIds={},this._trigger("remove",{items:e},t),e},DataSet.prototype.max=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||r>n)&&(i=o,n=r)}return i},DataSet.prototype.min=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||n>r)&&(i=o,n=r)}return i},DataSet.prototype.distinct=function(t){var e=this.data,i=[],n=this.options.convert[t],s=0;for(var o in e)if(e.hasOwnProperty(o)){for(var r=e[o],a=util.convert(r[t],n),h=!1,l=0;s>l;l++)if(i[l]==a){h=!0;break}h||(i[s]=a,s++)}return i},DataSet.prototype._addItem=function(t){var e=t[this.fieldId];if(void 0!=e){if(this.data[e])throw new Error("Cannot add item: item with id "+e+" already exists")}else e=util.randomUUID(),t[this.fieldId]=e,this.internalIds[e]=t;var i={};for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=util.convert(t[n],s)}return this.data[e]=i,e},DataSet.prototype._getItem=function(t,e){var i,n,s=this.data[t];if(!s)return null;var o={},r=this.fieldId,a=this.internalIds;if(e)for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a&&!this.showInternalIds||(o[i]=util.convert(n,e[i])));else for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a&&!this.showInternalIds||(o[i]=n));return o},DataSet.prototype._updateItem=function(t){var e=t[this.fieldId];if(void 0==e)throw new Error("Cannot update item: item has no id (item: "+JSON.stringify(t)+")");var i=this.data[e];if(!i)throw new Error("Cannot update item: no item with id "+e+" found");for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=util.convert(t[n],s)}return e},DataSet.prototype.isInternalId=function(t){return t in this.internalIds},DataSet.prototype._getColumnNames=function(t){for(var e=[],i=0,n=t.getNumberOfColumns();n>i;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},DataSet.prototype._appendRow=function(t,e,i){for(var n=t.addRow(),s=0,o=e.length;o>s;s++){var r=e[s];t.setValue(n,s,i[r])}},DataView.prototype.setData=function(t){var e,i,n;if(this.data){this.data.unsubscribe&&this.data.unsubscribe("*",this.listener),e=[];for(var s in this.ids)this.ids.hasOwnProperty(s)&&e.push(s);this.ids={},this._trigger("remove",{items:e})}if(this.data=t,this.data){for(this.fieldId=this.options.fieldId||this.data&&this.data.options&&this.data.options.fieldId||"id",e=this.data.getIds({filter:this.options&&this.options.filter}),i=0,n=e.length;n>i;i++)s=e[i],this.ids[s]=!0;this._trigger("add",{items:e}),this.data.subscribe&&this.data.subscribe("*",this.listener)}},DataView.prototype.get=function(){var t,e,i,n=this,s=util.getType(arguments[0]);"String"==s||"Number"==s||"Array"==s?(t=arguments[0],e=arguments[1],i=arguments[2]):(e=arguments[0],i=arguments[1]);var o=util.extend({},this.options,e);this.options.filter&&e&&e.filter&&(o.filter=function(t){return n.options.filter(t)&&e.filter(t)});var r=[];return void 0!=t&&r.push(t),r.push(o),r.push(i),this.data&&this.data.get.apply(this.data,r)},DataView.prototype.getIds=function(t){var e;if(this.data){var i,n=this.options.filter; +!function(t){if("object"==typeof exports)module.exports=t();else if("function"==typeof define&&define.amd)define(t);else{var e;"undefined"!=typeof window?e=window:"undefined"!=typeof global?e=global:"undefined"!=typeof self&&(e=self),e.vis=t()}}(function(){var define,module,exports;return function t(e,i,n){function s(r,a){if(!i[r]){if(!e[r]){var h="function"==typeof require&&require;if(!a&&h)return h(r,!0);if(o)return o(r,!0);throw new Error("Cannot find module '"+r+"'")}var l=i[r]={exports:{}};e[r][0].call(l.exports,function(t){var i=e[r][1][t];return s(i?i:t)},l,l.exports,t,e,i,n)}return i[r].exports}for(var o="function"==typeof require&&require,r=0;ri;++i)t.call(e||this,this[i],i,this)}),Array.prototype.map||(Array.prototype.map=function(t,e){var i,n,s;if(null==this)throw new TypeError(" this is null or not defined");var o=Object(this),r=o.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(e&&(i=e),n=new Array(r),s=0;r>s;){var a,h;s in o&&(a=o[s],h=t.call(i,a,s,o),n[s]=h),s++}return n}),Array.prototype.filter||(Array.prototype.filter=function(t){"use strict";if(null==this)throw new TypeError;var e=Object(this),i=e.length>>>0;if("function"!=typeof t)throw new TypeError;for(var n=[],s=arguments[1],o=0;i>o;o++)if(o in e){var r=e[o];t.call(s,r,o,e)&&n.push(r)}return n}),Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,e=!{toString:null}.propertyIsEnumerable("toString"),i=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],n=i.length;return function(s){if("object"!=typeof s&&"function"!=typeof s||null===s)throw new TypeError("Object.keys called on non-object");var o=[];for(var r in s)t.call(s,r)&&o.push(r);if(e)for(var a=0;n>a;a++)t.call(s,i[a])&&o.push(i[a]);return o}}()),Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s}),Object.create||(Object.create=function(t){function e(){}if(arguments.length>1)throw new Error("Object.create implementation only accepts the first parameter.");return e.prototype=t,new e}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s});var util={};util.isNumber=function(t){return t instanceof Number||"number"==typeof t},util.isString=function(t){return t instanceof String||"string"==typeof t},util.isDate=function(t){if(t instanceof Date)return!0;if(util.isString(t)){var e=ASPDateRegex.exec(t);if(e)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},util.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},util.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},util.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var n=arguments[e];for(var s in n)n.hasOwnProperty(s)&&void 0!==n[s]&&(t[s]=n[s])}return t},util.convert=function(t,e){var i;if(void 0===t)return void 0;if(null===t)return null;if(!e)return t;if("string"!=typeof e&&!(e instanceof String))throw new Error("Type must be a string");switch(e){case"boolean":case"Boolean":return Boolean(t);case"number":case"Number":return Number(t.valueOf());case"string":case"String":return String(t);case"Date":if(util.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(moment.isMoment(t))return new Date(t.valueOf());if(util.isString(t))return i=ASPDateRegex.exec(t),i?new Date(Number(i[1])):moment(t).toDate();throw new Error("Cannot convert object of type "+util.getType(t)+" to type Date");case"Moment":if(util.isNumber(t))return moment(t);if(t instanceof Date)return moment(t.valueOf());if(moment.isMoment(t))return moment(t);if(util.isString(t))return i=ASPDateRegex.exec(t),moment(i?Number(i[1]):t);throw new Error("Cannot convert object of type "+util.getType(t)+" to type Date");case"ISODate":if(util.isNumber(t))return new Date(t);if(t instanceof Date)return t.toISOString();if(moment.isMoment(t))return t.toDate().toISOString();if(util.isString(t))return i=ASPDateRegex.exec(t),i?new Date(Number(i[1])).toISOString():new Date(t).toISOString();throw new Error("Cannot convert object of type "+util.getType(t)+" to type ISODate");case"ASPDate":if(util.isNumber(t))return"/Date("+t+")/";if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(util.isString(t)){i=ASPDateRegex.exec(t);var n;return n=i?new Date(Number(i[1])).valueOf():new Date(t).valueOf(),"/Date("+n+")/"}throw new Error("Cannot convert object of type "+util.getType(t)+" to type ASPDate");default:throw new Error("Cannot convert object of type "+util.getType(t)+' to type "'+e+'"')}};var ASPDateRegex=/^\/?Date\((\-?\d+)/i;util.getType=function(t){var e=typeof t;return"object"==e?null==t?"null":t instanceof Boolean?"Boolean":t instanceof Number?"Number":t instanceof String?"String":t instanceof Array?"Array":t instanceof Date?"Date":"Object":"number"==e?"Number":"boolean"==e?"Boolean":"string"==e?"String":e},util.getAbsoluteLeft=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetLeft,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetLeft,n-=s.scrollLeft,s=s.offsetParent;return n},util.getAbsoluteTop=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetTop,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetTop,n-=s.scrollTop,s=s.offsetParent;return n},util.getPageY=function(t){if("pageY"in t)return t.pageY;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientY:t.clientY;var i=document.documentElement,n=document.body;return e+(i&&i.scrollTop||n&&n.scrollTop||0)-(i&&i.clientTop||n&&n.clientTop||0)},util.getPageX=function(t){if("pageY"in t)return t.pageX;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientX:t.clientX;var i=document.documentElement,n=document.body;return e+(i&&i.scrollLeft||n&&n.scrollLeft||0)-(i&&i.clientLeft||n&&n.clientLeft||0)},util.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},util.removeClassName=function(t,e){var i=t.className.split(" "),n=i.indexOf(e);-1!=n&&(i.splice(n,1),t.className=i.join(" "))},util.forEach=function(t,e){var i,n;if(t instanceof Array)for(i=0,n=t.length;n>i;i++)e(t[i],i,t);else for(i in t)t.hasOwnProperty(i)&&e(t[i],i,t)},util.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},util.addEventListener=function(t,e,i,n){t.addEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.addEventListener(e,i,n)):t.attachEvent("on"+e,i)},util.removeEventListener=function(t,e,i,n){t.removeEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.removeEventListener(e,i,n)):t.detachEvent("on"+e,i)},util.getTarget=function(t){t||(t=window.event);var e;return t.target?e=t.target:t.srcElement&&(e=t.srcElement),void 0!=e.nodeType&&3==e.nodeType&&(e=e.parentNode),e},util.stopPropagation=function(t){t||(t=window.event),t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},util.fakeGesture=function(t,e){var i=null;return Hammer.event.collectEventData(this,i,e)},util.preventDefault=function(t){t||(t=window.event),t.preventDefault?t.preventDefault():t.returnValue=!1},util.option={},util.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},util.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},util.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?String(t):e||null},util.option.asSize=function(t,e){return"function"==typeof t&&(t=t()),util.isString(t)?t:util.isNumber(t)?t+"px":e||null},util.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null},util.GiveDec=function GiveDec(Hex){return Value="A"==Hex?10:"B"==Hex?11:"C"==Hex?12:"D"==Hex?13:"E"==Hex?14:"F"==Hex?15:eval(Hex)},util.GiveHex=function(t){return Value=10==t?"A":11==t?"B":12==t?"C":13==t?"D":14==t?"E":15==t?"F":""+t},util.hexToRGB=function(t){t=t.replace("#","").toUpperCase();var e=util.GiveDec(t.substring(0,1)),i=util.GiveDec(t.substring(1,2)),n=util.GiveDec(t.substring(2,3)),s=util.GiveDec(t.substring(3,4)),o=util.GiveDec(t.substring(4,5)),r=util.GiveDec(t.substring(5,6)),a=16*e+i,h=16*n+s,i=16*o+r;return{r:a,g:h,b:i}},util.RGBToHex=function(t,e,i){var n=util.GiveHex(Math.floor(t/16)),s=util.GiveHex(t%16),o=util.GiveHex(Math.floor(e/16)),r=util.GiveHex(e%16),a=util.GiveHex(Math.floor(i/16)),h=util.GiveHex(i%16),l=n+s+o+r+a+h;return"#"+l},util.RGBToHSV=function(t,e,i){t/=255,e/=255,i/=255;var n=Math.min(t,Math.min(e,i)),s=Math.max(t,Math.max(e,i));if(n==s)return{h:0,s:0,v:n};var o=t==n?e-i:i==n?t-e:i-t,r=t==n?3:i==n?1:5,a=60*(r-o/(s-n))/360,h=(s-n)/s,l=s;return{h:a,s:h,v:l}},util.HSVToRGB=function(t,e,i){var n,s,o,r=Math.floor(6*t),a=6*t-r,h=i*(1-e),l=i*(1-a*e),c=i*(1-(1-a)*e);switch(r%6){case 0:n=i,s=c,o=h;break;case 1:n=l,s=i,o=h;break;case 2:n=h,s=i,o=c;break;case 3:n=h,s=l,o=i;break;case 4:n=c,s=h,o=i;break;case 5:n=i,s=h,o=l}return{r:Math.floor(255*n),g:Math.floor(255*s),b:Math.floor(255*o)}},util.HSVToHex=function(t,e,i){var n=util.HSVToRGB(t,e,i);return util.RGBToHex(n.r,n.g,n.b)},util.hexToHSV=function(t){var e=util.hexToRGB(t);return util.RGBToHSV(e.r,e.g,e.b)};var events={listeners:[],indexOf:function(t){for(var e=this.listeners,i=0,n=this.listeners.length;n>i;i++){var s=e[i];if(s&&s.object==t)return i}return-1},addListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];s||(s={object:t,events:{}},this.listeners.push(s));var o=s.events[e];o||(o=[],s.events[e]=o),-1==o.indexOf(i)&&o.push(i)},removeListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];o&&(n=o.indexOf(i),-1!=n&&o.splice(n,1),0==o.length&&delete s.events[e]);var r=0,a=s.events;for(var h in a)a.hasOwnProperty(h)&&r++;0==r&&delete this.listeners[n]}},removeAllListeners:function(){this.listeners=[]},trigger:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];if(o)for(var r=0,a=o.length;a>r;r++)o[r](i)}}};EventBus.prototype.on=function(t,e,i){var n=t instanceof RegExp?t:new RegExp(t.replace("*","\\w+")),s={id:util.randomUUID(),event:t,regexp:n,callback:"function"==typeof e?e:null,target:i};return this.subscriptions.push(s),s.id},EventBus.prototype.off=function(t){for(var e=0;eo;o++)i=s._addItem(t[o]),n.push(i);else if(util.isDataTable(t))for(var a=this._getColumnNames(t),h=0,l=t.getNumberOfRows();l>h;h++){for(var c={},d=0,u=a.length;u>d;d++){var p=a[d];c[p]=t.getValue(h,d)}i=s._addItem(c),n.push(i)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");i=s._addItem(t),n.push(i)}return n.length&&this._trigger("add",{items:n},e),n},DataSet.prototype.update=function(t,e){var i=[],n=[],s=this,o=s.fieldId,r=function(t){var e=t[o];s.data[e]?(e=s._updateItem(t),n.push(e)):(e=s._addItem(t),i.push(e))};if(t instanceof Array)for(var a=0,h=t.length;h>a;a++)r(t[a]);else if(util.isDataTable(t))for(var l=this._getColumnNames(t),c=0,d=t.getNumberOfRows();d>c;c++){for(var u={},p=0,f=l.length;f>p;p++){var g=l[p];u[g]=t.getValue(c,p)}r(u)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");r(t)}return i.length&&this._trigger("add",{items:i},e),n.length&&this._trigger("update",{items:n},e),i.concat(n)},DataSet.prototype.get=function(){var t,e,i,n,s=this,o=this.showInternalIds,r=util.getType(arguments[0]);"String"==r||"Number"==r?(t=arguments[0],i=arguments[1],n=arguments[2]):"Array"==r?(e=arguments[0],i=arguments[1],n=arguments[2]):(i=arguments[0],n=arguments[1]);var a;if(i&&i.type){if(a="DataTable"==i.type?"DataTable":"Array",n&&a!=util.getType(n))throw new Error('Type of parameter "data" ('+util.getType(n)+") does not correspond with specified options.type ("+i.type+")");if("DataTable"==a&&!util.isDataTable(n))throw new Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else a=n?"DataTable"==util.getType(n)?"DataTable":"Array":"Array";void 0!=i&&void 0!=i.showInternalIds&&(this.showInternalIds=i.showInternalIds);var h,l,c,d,u=i&&i.convert||this.options.convert,p=i&&i.filter,f=[];if(void 0!=t)h=s._getItem(t,u),p&&!p(h)&&(h=null);else if(void 0!=e)for(c=0,d=e.length;d>c;c++)h=s._getItem(e[c],u),(!p||p(h))&&f.push(h);else for(l in this.data)this.data.hasOwnProperty(l)&&(h=s._getItem(l,u),(!p||p(h))&&f.push(h));if(this.showInternalIds=o,i&&i.order&&void 0==t&&this._sort(f,i.order),i&&i.fields){var g=i.fields;if(void 0!=t)h=this._filterFields(h,g);else for(c=0,d=f.length;d>c;c++)f[c]=this._filterFields(f[c],g)}if("DataTable"==a){var m=this._getColumnNames(n);if(void 0!=t)s._appendRow(n,m,h);else for(c=0,d=f.length;d>c;c++)s._appendRow(n,m,f[c]);return n}if(void 0!=t)return h;if(n){for(c=0,d=f.length;d>c;c++)n.push(f[c]);return n}return f},DataSet.prototype.getIds=function(t){var e,i,n,s,o,r=this.data,a=t&&t.filter,h=t&&t.order,l=t&&t.convert||this.options.convert,c=[];if(a)if(h){o=[];for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,l),a(s)&&o.push(s));for(this._sort(o,h),e=0,i=o.length;i>e;e++)c[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,l),a(s)&&c.push(s[this.fieldId]));else if(h){o=[];for(n in r)r.hasOwnProperty(n)&&o.push(r[n]);for(this._sort(o,h),e=0,i=o.length;i>e;e++)c[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=r[n],c.push(s[this.fieldId]));return c},DataSet.prototype.forEach=function(t,e){var i,n,s=e&&e.filter,o=e&&e.convert||this.options.convert,r=this.data;if(e&&e.order)for(var a=this.get(e),h=0,l=a.length;l>h;h++)i=a[h],n=i[this.fieldId],t(i,n);else for(n in r)r.hasOwnProperty(n)&&(i=this._getItem(n,o),(!s||s(i))&&t(i,n))},DataSet.prototype.map=function(t,e){var i,n=e&&e.filter,s=e&&e.convert||this.options.convert,o=[],r=this.data;for(var a in r)r.hasOwnProperty(a)&&(i=this._getItem(a,s),(!n||n(i))&&o.push(t(i,a)));return e&&e.order&&this._sort(o,e.order),o},DataSet.prototype._filterFields=function(t,e){var i={};for(var n in t)t.hasOwnProperty(n)&&-1!=e.indexOf(n)&&(i[n]=t[n]);return i},DataSet.prototype._sort=function(t,e){if(util.isString(e)){var i=e;t.sort(function(t,e){var n=t[i],s=e[i];return n>s?1:s>n?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},DataSet.prototype.remove=function(t,e){var i,n,s,o=[];if(t instanceof Array)for(i=0,n=t.length;n>i;i++)s=this._remove(t[i]),null!=s&&o.push(s);else s=this._remove(t),null!=s&&o.push(s);return o.length&&this._trigger("remove",{items:o},e),o},DataSet.prototype._remove=function(t){if(util.isNumber(t)||util.isString(t)){if(this.data[t])return delete this.data[t],delete this.internalIds[t],t}else if(t instanceof Object){var e=t[this.fieldId];if(e&&this.data[e])return delete this.data[e],delete this.internalIds[e],e}return null},DataSet.prototype.clear=function(t){var e=Object.keys(this.data);return this.data={},this.internalIds={},this._trigger("remove",{items:e},t),e},DataSet.prototype.max=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||r>n)&&(i=o,n=r)}return i},DataSet.prototype.min=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||n>r)&&(i=o,n=r)}return i},DataSet.prototype.distinct=function(t){var e=this.data,i=[],n=this.options.convert[t],s=0;for(var o in e)if(e.hasOwnProperty(o)){for(var r=e[o],a=util.convert(r[t],n),h=!1,l=0;s>l;l++)if(i[l]==a){h=!0;break}h||(i[s]=a,s++)}return i},DataSet.prototype._addItem=function(t){var e=t[this.fieldId];if(void 0!=e){if(this.data[e])throw new Error("Cannot add item: item with id "+e+" already exists")}else e=util.randomUUID(),t[this.fieldId]=e,this.internalIds[e]=t;var i={};for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=util.convert(t[n],s)}return this.data[e]=i,e},DataSet.prototype._getItem=function(t,e){var i,n,s=this.data[t];if(!s)return null;var o={},r=this.fieldId,a=this.internalIds;if(e)for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a&&!this.showInternalIds||(o[i]=util.convert(n,e[i])));else for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a&&!this.showInternalIds||(o[i]=n));return o},DataSet.prototype._updateItem=function(t){var e=t[this.fieldId];if(void 0==e)throw new Error("Cannot update item: item has no id (item: "+JSON.stringify(t)+")");var i=this.data[e];if(!i)throw new Error("Cannot update item: no item with id "+e+" found");for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=util.convert(t[n],s)}return e},DataSet.prototype.isInternalId=function(t){return t in this.internalIds},DataSet.prototype._getColumnNames=function(t){for(var e=[],i=0,n=t.getNumberOfColumns();n>i;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},DataSet.prototype._appendRow=function(t,e,i){for(var n=t.addRow(),s=0,o=e.length;o>s;s++){var r=e[s];t.setValue(n,s,i[r])}},DataView.prototype.setData=function(t){var e,i,n;if(this.data){this.data.unsubscribe&&this.data.unsubscribe("*",this.listener),e=[];for(var s in this.ids)this.ids.hasOwnProperty(s)&&e.push(s);this.ids={},this._trigger("remove",{items:e})}if(this.data=t,this.data){for(this.fieldId=this.options.fieldId||this.data&&this.data.options&&this.data.options.fieldId||"id",e=this.data.getIds({filter:this.options&&this.options.filter}),i=0,n=e.length;n>i;i++)s=e[i],this.ids[s]=!0;this._trigger("add",{items:e}),this.data.subscribe&&this.data.subscribe("*",this.listener)}},DataView.prototype.get=function(){var t,e,i,n=this,s=util.getType(arguments[0]);"String"==s||"Number"==s||"Array"==s?(t=arguments[0],e=arguments[1],i=arguments[2]):(e=arguments[0],i=arguments[1]);var o=util.extend({},this.options,e);this.options.filter&&e&&e.filter&&(o.filter=function(t){return n.options.filter(t)&&e.filter(t)});var r=[];return void 0!=t&&r.push(t),r.push(o),r.push(i),this.data&&this.data.get.apply(this.data,r)},DataView.prototype.getIds=function(t){var e;if(this.data){var i,n=this.options.filter; i=t&&t.filter?n?function(e){return n(e)&&t.filter(e)}:t.filter:n,e=this.data.getIds({filter:i,order:t&&t.order})}else e=[];return e},DataView.prototype._onEvent=function(t,e,i){var n,s,o,r,a=e&&e.items,h=this.data,l=[],c=[],d=[];if(a&&h){switch(t){case"add":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r&&(this.ids[o]=!0,l.push(o));break;case"update":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r?this.ids[o]?c.push(o):(this.ids[o]=!0,l.push(o)):this.ids[o]&&(delete this.ids[o],d.push(o));break;case"remove":for(n=0,s=a.length;s>n;n++)o=a[n],this.ids[o]&&(delete this.ids[o],d.push(o))}l.length&&this._trigger("add",{items:l},i),c.length&&this._trigger("update",{items:c},i),d.length&&this._trigger("remove",{items:d},i)}},DataView.prototype.subscribe=DataSet.prototype.subscribe,DataView.prototype.unsubscribe=DataSet.prototype.unsubscribe,DataView.prototype._trigger=DataSet.prototype._trigger,TimeStep=function(t,e,i){this.current=new Date,this._start=new Date,this._end=new Date,this.autoScale=!0,this.scale=TimeStep.SCALE.DAY,this.step=1,this.setRange(t,e,i)},TimeStep.SCALE={MILLISECOND:1,SECOND:2,MINUTE:3,HOUR:4,DAY:5,WEEKDAY:6,MONTH:7,YEAR:8},TimeStep.prototype.setRange=function(t,e,i){if(!(t instanceof Date&&e instanceof Date))throw"No legal start or end date in method setRange";this._start=void 0!=t?new Date(t.valueOf()):new Date,this._end=void 0!=e?new Date(e.valueOf()):new Date,this.autoScale&&this.setMinimumStep(i)},TimeStep.prototype.first=function(){this.current=new Date(this._start.valueOf()),this.roundToMinor()},TimeStep.prototype.roundToMinor=function(){switch(this.scale){case TimeStep.SCALE.YEAR:this.current.setFullYear(this.step*Math.floor(this.current.getFullYear()/this.step)),this.current.setMonth(0);case TimeStep.SCALE.MONTH:this.current.setDate(1);case TimeStep.SCALE.DAY:case TimeStep.SCALE.WEEKDAY:this.current.setHours(0);case TimeStep.SCALE.HOUR:this.current.setMinutes(0);case TimeStep.SCALE.MINUTE:this.current.setSeconds(0);case TimeStep.SCALE.SECOND:this.current.setMilliseconds(0)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.setMilliseconds(this.current.getMilliseconds()-this.current.getMilliseconds()%this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()-this.current.getSeconds()%this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()-this.current.getMinutes()%this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()-this.current.getHours()%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()-1-(this.current.getDate()-1)%this.step+1);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()-this.current.getMonth()%this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()-this.current.getFullYear()%this.step)}},TimeStep.prototype.hasNext=function(){return this.current.valueOf()<=this._end.valueOf()},TimeStep.prototype.next=function(){var t=this.current.valueOf();if(this.current.getMonth()<6)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current=new Date(this.current.valueOf()+1e3*this.step);break;case TimeStep.SCALE.MINUTE:this.current=new Date(this.current.valueOf()+1e3*this.step*60);break;case TimeStep.SCALE.HOUR:this.current=new Date(this.current.valueOf()+1e3*this.step*60*60);var e=this.current.getHours();this.current.setHours(e-e%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}else switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()+this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()+this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()+this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.getMilliseconds()0&&(this.step=e),this.autoScale=!1},TimeStep.prototype.setAutoScale=function(t){this.autoScale=t},TimeStep.prototype.setMinimumStep=function(t){if(void 0!=t){var e=31104e6,i=2592e6,n=864e5,s=36e5,o=6e4,r=1e3,a=1;1e3*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1e3),500*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=500),100*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=100),50*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=50),10*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=10),5*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=5),e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1),3*i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=3),i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=1),5*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=5),2*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=2),n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=1),n/2>t&&(this.scale=TimeStep.SCALE.WEEKDAY,this.step=1),4*s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=4),s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=1),15*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=15),10*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=10),5*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=5),o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=1),15*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=15),10*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=10),5*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=5),r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=1),200*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=200),100*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=100),50*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=50),10*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=10),5*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=5),a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=1)}},TimeStep.prototype.snap=function(t){if(this.scale==TimeStep.SCALE.YEAR){var e=t.getFullYear()+Math.round(t.getMonth()/12);t.setFullYear(Math.round(e/this.step)*this.step),t.setMonth(0),t.setDate(0),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MONTH)t.getDate()>15?(t.setDate(1),t.setMonth(t.getMonth()+1)):t.setDate(1),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0);else if(this.scale==TimeStep.SCALE.DAY||this.scale==TimeStep.SCALE.WEEKDAY){switch(this.step){case 5:case 2:t.setHours(24*Math.round(t.getHours()/24));break;default:t.setHours(12*Math.round(t.getHours()/12))}t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.HOUR){switch(this.step){case 4:t.setMinutes(60*Math.round(t.getMinutes()/60));break;default:t.setMinutes(30*Math.round(t.getMinutes()/30))}t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MINUTE){switch(this.step){case 15:case 10:t.setMinutes(5*Math.round(t.getMinutes()/5)),t.setSeconds(0);break;case 5:t.setSeconds(60*Math.round(t.getSeconds()/60));break;default:t.setSeconds(30*Math.round(t.getSeconds()/30))}t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.SECOND)switch(this.step){case 15:case 10:t.setSeconds(5*Math.round(t.getSeconds()/5)),t.setMilliseconds(0);break;case 5:t.setMilliseconds(1e3*Math.round(t.getMilliseconds()/1e3));break;default:t.setMilliseconds(500*Math.round(t.getMilliseconds()/500))}else if(this.scale==TimeStep.SCALE.MILLISECOND){var i=this.step>5?this.step/2:1;t.setMilliseconds(Math.round(t.getMilliseconds()/i)*i)}},TimeStep.prototype.isMajor=function(){switch(this.scale){case TimeStep.SCALE.MILLISECOND:return 0==this.current.getMilliseconds();case TimeStep.SCALE.SECOND:return 0==this.current.getSeconds();case TimeStep.SCALE.MINUTE:return 0==this.current.getHours()&&0==this.current.getMinutes();case TimeStep.SCALE.HOUR:return 0==this.current.getHours();case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return 1==this.current.getDate();case TimeStep.SCALE.MONTH:return 0==this.current.getMonth();case TimeStep.SCALE.YEAR:return!1;default:return!1}},TimeStep.prototype.getLabelMinor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return moment(t).format("SSS");case TimeStep.SCALE.SECOND:return moment(t).format("s");case TimeStep.SCALE.MINUTE:return moment(t).format("HH:mm");case TimeStep.SCALE.HOUR:return moment(t).format("HH:mm");case TimeStep.SCALE.WEEKDAY:return moment(t).format("ddd D");case TimeStep.SCALE.DAY:return moment(t).format("D");case TimeStep.SCALE.MONTH:return moment(t).format("MMM");case TimeStep.SCALE.YEAR:return moment(t).format("YYYY");default:return""}},TimeStep.prototype.getLabelMajor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return moment(t).format("HH:mm:ss");case TimeStep.SCALE.SECOND:return moment(t).format("D MMMM HH:mm");case TimeStep.SCALE.MINUTE:case TimeStep.SCALE.HOUR:return moment(t).format("ddd D MMMM");case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return moment(t).format("MMMM YYYY");case TimeStep.SCALE.MONTH:return moment(t).format("YYYY");case TimeStep.SCALE.YEAR:return"";default:return""}},Stack.prototype.setOptions=function(t){util.extend(this.options,t)},Stack.prototype.update=function(){this._order(),this._stack()},Stack.prototype._order=function(){var t=this.parent.items;if(!t)throw new Error("Cannot stack items: parent does not contain items");var e=[],i=0;util.forEach(t,function(t){t.visible&&(e[i]=t,i++)});var n=this.options.order||this.defaultOptions.order;if("function"!=typeof n)throw new Error("Option order must be a function");e.sort(n),this.ordered=e},Stack.prototype._stack=function(){var t,e,i,n=this.ordered,s=this.options,o=s.orientation||this.defaultOptions.orientation,r="top"==o;for(i=s.margin&&void 0!==s.margin.item?s.margin.item:this.defaultOptions.margin.item,t=0,e=n.length;e>t;t++){var a=n[t],h=null;do h=this.checkOverlap(n,t,0,t-1,i),null!=h&&(a.top=r?h.top+h.height+i:h.top-a.height-i);while(h)}},Stack.prototype.checkOverlap=function(t,e,i,n,s){for(var o=this.collision,r=t[e],a=n;a>=i;a--){var h=t[a];if(o(r,h,s)&&a!=e)return h}return null},Stack.prototype.collision=function(t,e,i){return t.left-ie.left&&t.top-ie.top},Range.prototype.setOptions=function(t){util.extend(this.options,t),null!==this.start&&null!==this.end&&this.setRange(this.start,this.end)},Range.prototype.subscribe=function(t,e,i){function n(e){s._onMouseWheel(e,t,i)}var s=this;if("move"==e)t.on("dragstart",function(e){s._onDragStart(e,t)}),t.on("drag",function(e){s._onDrag(e,t,i)}),t.on("dragend",function(e){s._onDragEnd(e,t)});else{if("zoom"!=e)throw new TypeError('Unknown event "'+e+'". Choose "move" or "zoom".');t.on("mousewheel",n),t.on("DOMMouseScroll",n),t.on("touch",function(){s._onTouch()}),t.on("pinch",function(e){s._onPinch(e,t,i)})}},Range.prototype.on=function(t,e){var i=["rangechange","rangechanged"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());events.addListener(this,t,e)},Range.prototype.off=function(t,e){events.removeListener(this,t,e)},Range.prototype._trigger=function(t){events.trigger(this,t,{start:this.start,end:this.end})},Range.prototype.setRange=function(t,e){var i=this._applyRange(t,e);i&&(this._trigger("rangechange"),this._trigger("rangechanged"))},Range.prototype._applyRange=function(t,e){var i,n=null!=t?util.convert(t,"Date").valueOf():this.start,s=null!=e?util.convert(e,"Date").valueOf():this.end,o=null!=this.options.max?util.convert(this.options.max,"Date").valueOf():null,r=null!=this.options.min?util.convert(this.options.min,"Date").valueOf():null;if(isNaN(n)||null===n)throw new Error('Invalid start "'+t+'"');if(isNaN(s)||null===s)throw new Error('Invalid end "'+e+'"');if(n>s&&(s=n),null!==r&&r>n&&(i=r-n,n+=i,s+=i,null!=o&&s>o&&(s=o)),null!==o&&s>o&&(i=s-o,n-=i,s-=i,null!=r&&r>n&&(n=r)),null!==this.options.zoomMin){var a=parseFloat(this.options.zoomMin);0>a&&(a=0),a>s-n&&(this.end-this.start===a?(n=this.start,s=this.end):(i=a-(s-n),n-=i/2,s+=i/2))}if(null!==this.options.zoomMax){var h=parseFloat(this.options.zoomMax);0>h&&(h=0),s-n>h&&(this.end-this.start===h?(n=this.start,s=this.end):(i=s-n-h,n+=i/2,s-=i/2))}var l=this.start!=n||this.end!=s;return this.start=n,this.end=s,l},Range.prototype.getRange=function(){return{start:this.start,end:this.end}},Range.prototype.conversion=function(t){return Range.conversion(this.start,this.end,t)},Range.conversion=function(t,e,i){return 0!=i&&e-t!=0?{offset:t,scale:i/(e-t)}:{offset:0,scale:1}};var touchParams={};Range.prototype._onDragStart=function(t,e){if(!touchParams.pinching){touchParams.start=this.start,touchParams.end=this.end;var i=e.frame;i&&(i.style.cursor="move")}},Range.prototype._onDrag=function(t,e,i){if(validateDirection(i),!touchParams.pinching){var n="horizontal"==i?t.gesture.deltaX:t.gesture.deltaY,s=touchParams.end-touchParams.start,o="horizontal"==i?e.width:e.height,r=-n/o*s;this._applyRange(touchParams.start+r,touchParams.end+r),this._trigger("rangechange")}},Range.prototype._onDragEnd=function(t,e){touchParams.pinching||(e.frame&&(e.frame.style.cursor="auto"),this._trigger("rangechanged"))},Range.prototype._onMouseWheel=function(t,e,i){validateDirection(i);var n=0;if(t.wheelDelta?n=t.wheelDelta/120:t.detail&&(n=-t.detail/3),n){var s;s=0>n?1-n/5:1/(1+n/5);var o=util.fakeGesture(this,t),r=getPointer(o.touches[0],e.frame),a=this._pointerToDate(e,i,r);this.zoom(s,a)}util.preventDefault(t)},Range.prototype._onTouch=function(){touchParams.start=this.start,touchParams.end=this.end,touchParams.pinching=!1,touchParams.center=null},Range.prototype._onPinch=function(t,e,i){if(touchParams.pinching=!0,t.gesture.touches.length>1){touchParams.center||(touchParams.center=getPointer(t.gesture.center,e.frame));var n=1/t.gesture.scale,s=this._pointerToDate(e,i,touchParams.center),o=getPointer(t.gesture.center,e.frame),r=(this._pointerToDate(e,i,o),parseInt(s+(touchParams.start-s)*n)),a=parseInt(s+(touchParams.end-s)*n);this.setRange(r,a)}},Range.prototype._pointerToDate=function(t,e,i){var n;if("horizontal"==e){var s=t.width;return n=this.conversion(s),i.x/n.scale+n.offset}var o=t.height;return n=this.conversion(o),i.y/n.scale+n.offset},Range.prototype.zoom=function(t,e){null==e&&(e=(this.start+this.end)/2);var i=e+(this.start-e)*t,n=e+(this.end-e)*t;this.setRange(i,n)},Range.prototype.move=function(t){var e=this.end-this.start,i=this.start+e*t,n=this.end+e*t;this.start=i,this.end=n},Range.prototype.moveTo=function(t){var e=(this.start+this.end)/2,i=e-t,n=this.start-i,s=this.end-i;this.setRange(n,s)},Controller.prototype.add=function(t){if(void 0==t.id)throw new Error("Component has no field id");if(!(t instanceof Component||t instanceof Controller))throw new TypeError("Component must be an instance of prototype Component or Controller");t.controller=this,this.components[t.id]=t},Controller.prototype.remove=function(t){var e;for(e in this.components)if(this.components.hasOwnProperty(e)&&(e==t||this.components[e]==t))break;e&&delete this.components[e]},Controller.prototype.requestReflow=function(t){if(t)this.reflow();else if(!this.reflowTimer){var e=this;this.reflowTimer=setTimeout(function(){e.reflowTimer=void 0,e.reflow()},0)}},Controller.prototype.requestRepaint=function(t){if(t)this.repaint();else if(!this.repaintTimer){var e=this;this.repaintTimer=setTimeout(function(){e.repaintTimer=void 0,e.repaint()},0)}},Controller.prototype.repaint=function t(){function t(n,s){s in i||(n.depends&&n.depends.forEach(function(e){t(e,e.id)}),n.parent&&t(n.parent,n.parent.id),e=n.repaint()||e,i[s]=!0)}var e=!1;this.repaintTimer&&(clearTimeout(this.repaintTimer),this.repaintTimer=void 0);var i={};util.forEach(this.components,t),e&&this.reflow()},Controller.prototype.reflow=function e(){function e(n,s){s in i||(n.depends&&n.depends.forEach(function(t){e(t,t.id)}),n.parent&&e(n.parent,n.parent.id),t=n.reflow()||t,i[s]=!0)}var t=!1;this.reflowTimer&&(clearTimeout(this.reflowTimer),this.reflowTimer=void 0);var i={};util.forEach(this.components,e),t&&this.repaint()},Component.prototype.setOptions=function(t){t&&(util.extend(this.options,t),this.controller&&(this.requestRepaint(),this.requestReflow()))},Component.prototype.getOption=function(t){var e;return this.options&&(e=this.options[t]),void 0===e&&this.defaultOptions&&(e=this.defaultOptions[t]),e},Component.prototype.getContainer=function(){return null},Component.prototype.getFrame=function(){return this.frame},Component.prototype.repaint=function(){return!1},Component.prototype.reflow=function(){return!1},Component.prototype.hide=function(){return this.frame&&this.frame.parentNode?(this.frame.parentNode.removeChild(this.frame),!0):!1},Component.prototype.show=function(){return this.frame&&this.frame.parentNode?!1:this.repaint()},Component.prototype.requestRepaint=function(){if(!this.controller)throw new Error("Cannot request a repaint: no controller configured");this.controller.requestRepaint()},Component.prototype.requestReflow=function(){if(!this.controller)throw new Error("Cannot request a reflow: no controller configured");this.controller.requestReflow()},Panel.prototype=new Component,Panel.prototype.setOptions=Component.prototype.setOptions,Panel.prototype.getContainer=function(){return this.frame},Panel.prototype.repaint=function(){var t=0,e=util.updateProperty,i=util.option.asSize,n=this.options,s=this.frame;if(!s){s=document.createElement("div"),s.className="panel";var o=n.className;o&&("function"==typeof o?util.addClassName(s,String(o())):util.addClassName(s,String(o))),this.frame=s,t+=1}if(!s.parentNode){if(!this.parent)throw new Error("Cannot repaint panel: no parent attached");var r=this.parent.getContainer();if(!r)throw new Error("Cannot repaint panel: parent has no container element");r.appendChild(s),t+=1}return t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),t>0},Panel.prototype.reflow=function(){var t=0,e=util.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},RootPanel.prototype=new Panel,RootPanel.prototype.setOptions=Component.prototype.setOptions,RootPanel.prototype.repaint=function(){var t=0,e=util.updateProperty,i=util.option.asSize,n=this.options,s=this.frame;if(s||(s=document.createElement("div"),this.frame=s,t+=1),!s.parentNode){if(!this.container)throw new Error("Cannot repaint root panel: no container attached");this.container.appendChild(s),t+=1}s.className="vis timeline rootpanel "+n.orientation;var o=n.className;return o&&util.addClassName(s,util.option.asString(o)),t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),this._updateEventEmitters(),this._updateWatch(),t>0},RootPanel.prototype.reflow=function(){var t=0,e=util.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},RootPanel.prototype._updateWatch=function(){var t=this.getOption("autoResize");t?this._watch():this._unwatch()},RootPanel.prototype._watch=function(){var t=this;this._unwatch();var e=function(){var e=t.getOption("autoResize");return e?void(t.frame&&(t.frame.clientWidth!=t.width||t.frame.clientHeight!=t.height)&&t.requestReflow()):void t._unwatch()};util.addEventListener(window,"resize",e),this.watchTimer=setInterval(e,1e3)},RootPanel.prototype._unwatch=function(){this.watchTimer&&(clearInterval(this.watchTimer),this.watchTimer=void 0)},RootPanel.prototype.on=function(t,e){var i=this.listeners[t];i||(i=[],this.listeners[t]=i),i.push(e),this._updateEventEmitters()},RootPanel.prototype._updateEventEmitters=function(){if(this.listeners){var t=this;util.forEach(this.listeners,function(e,i){if(t.emitters||(t.emitters={}),!(i in t.emitters)){var n=t.frame;if(n){var s=function(t){e.forEach(function(e){e(t)})};t.emitters[i]=s,t.hammer||(t.hammer=Hammer(n,{prevent_default:!0})),t.hammer.on(i,s)}}})}},TimeAxis.prototype=new Component,TimeAxis.prototype.setOptions=Component.prototype.setOptions,TimeAxis.prototype.setRange=function(t){if(!(t instanceof Range||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},TimeAxis.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},TimeAxis.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},TimeAxis.prototype.repaint=function(){var t=0,e=util.updateProperty,i=util.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.props,r=this.step,a=this.frame;if(a||(a=document.createElement("div"),this.frame=a,t+=1),a.className="axis",!a.parentNode){if(!this.parent)throw new Error("Cannot repaint time axis: no parent attached");var h=this.parent.getContainer();if(!h)throw new Error("Cannot repaint time axis: parent has no container element");h.appendChild(a),t+=1}var l=a.parentNode;if(l){var c=a.nextSibling;l.removeChild(a);var d="bottom"==s&&this.props.parentHeight&&this.height?this.props.parentHeight-this.height+"px":"0px";if(t+=e(a.style,"top",i(n.top,d)),t+=e(a.style,"left",i(n.left,"0px")),t+=e(a.style,"width",i(n.width,"100%")),t+=e(a.style,"height",i(n.height,this.height+"px")),this._repaintMeasureChars(),this.step){this._repaintStart(),r.first();for(var u=void 0,p=0;r.hasNext()&&1e3>p;){p++;var f=r.getCurrent(),g=this.toScreen(f),m=r.isMajor();this.getOption("showMinorLabels")&&this._repaintMinorText(g,r.getLabelMinor()),m&&this.getOption("showMajorLabels")?(g>0&&(void 0==u&&(u=g),this._repaintMajorText(g,r.getLabelMajor())),this._repaintMajorLine(g)):this._repaintMinorLine(g),r.next()}if(this.getOption("showMajorLabels")){var v=this.toTime(0),y=r.getLabelMajor(v),_=y.length*(o.majorCharWidth||10)+10;(void 0==u||u>_)&&this._repaintMajorText(0,y)}this._repaintEnd()}this._repaintLine(),c?l.insertBefore(a,c):l.appendChild(a)}return t>0},TimeAxis.prototype._repaintStart=function(){var t=this.dom,e=t.redundant;e.majorLines=t.majorLines,e.majorTexts=t.majorTexts,e.minorLines=t.minorLines,e.minorTexts=t.minorTexts,t.majorLines=[],t.majorTexts=[],t.minorLines=[],t.minorTexts=[]},TimeAxis.prototype._repaintEnd=function(){util.forEach(this.dom.redundant,function(t){for(;t.length;){var e=t.pop();e&&e.parentNode&&e.parentNode.removeChild(e)}})},TimeAxis.prototype._repaintMinorText=function(t,e){var i=this.dom.redundant.minorTexts.shift();if(!i){var n=document.createTextNode("");i=document.createElement("div"),i.appendChild(n),i.className="text minor",this.frame.appendChild(i)}this.dom.minorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.left=t+"px",i.style.top=this.props.minorLabelTop+"px"},TimeAxis.prototype._repaintMajorText=function(t,e){var i=this.dom.redundant.majorTexts.shift();if(!i){var n=document.createTextNode(e);i=document.createElement("div"),i.className="text major",i.appendChild(n),this.frame.appendChild(i)}this.dom.majorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.top=this.props.majorLabelTop+"px",i.style.left=t+"px"},TimeAxis.prototype._repaintMinorLine=function(t){var e=this.dom.redundant.minorLines.shift();e||(e=document.createElement("div"),e.className="grid vertical minor",this.frame.appendChild(e)),this.dom.minorLines.push(e);var i=this.props;e.style.top=i.minorLineTop+"px",e.style.height=i.minorLineHeight+"px",e.style.left=t-i.minorLineWidth/2+"px"},TimeAxis.prototype._repaintMajorLine=function(t){var e=this.dom.redundant.majorLines.shift();e||(e=document.createElement("DIV"),e.className="grid vertical major",this.frame.appendChild(e)),this.dom.majorLines.push(e);var i=this.props;e.style.top=i.majorLineTop+"px",e.style.left=t-i.majorLineWidth/2+"px",e.style.height=i.majorLineHeight+"px"},TimeAxis.prototype._repaintLine=function(){{var t=this.dom.line,e=this.frame;this.options}this.getOption("showMinorLabels")||this.getOption("showMajorLabels")?(t?(e.removeChild(t),e.appendChild(t)):(t=document.createElement("div"),t.className="grid horizontal major",e.appendChild(t),this.dom.line=t),t.style.top=this.props.lineTop+"px"):t&&t.parentElement&&(e.removeChild(t.line),delete this.dom.line)},TimeAxis.prototype._repaintMeasureChars=function(){var t,e=this.dom;if(!e.measureCharMinor){t=document.createTextNode("0");var i=document.createElement("DIV");i.className="text minor measure",i.appendChild(t),this.frame.appendChild(i),e.measureCharMinor=i}if(!e.measureCharMajor){t=document.createTextNode("0");var n=document.createElement("DIV");n.className="text major measure",n.appendChild(t),this.frame.appendChild(n),e.measureCharMajor=n}},TimeAxis.prototype.reflow=function(){var t=0,e=util.updateProperty,i=this.frame,n=this.range;if(!n)throw new Error("Cannot repaint time axis: no range configured");if(i){t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft);var s=this.props,o=this.getOption("showMinorLabels"),r=this.getOption("showMajorLabels"),a=this.dom.measureCharMinor,h=this.dom.measureCharMajor;a&&(s.minorCharHeight=a.clientHeight,s.minorCharWidth=a.clientWidth),h&&(s.majorCharHeight=h.clientHeight,s.majorCharWidth=h.clientWidth);var l=i.parentNode?i.parentNode.offsetHeight:0;switch(l!=s.parentHeight&&(s.parentHeight=l,t+=1),this.getOption("orientation")){case"bottom":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.minorLabelTop=0,s.majorLabelTop=s.minorLabelTop+s.minorLabelHeight,s.minorLineTop=-this.top,s.minorLineHeight=Math.max(this.top+s.majorLabelHeight,0),s.minorLineWidth=1,s.majorLineTop=-this.top,s.majorLineHeight=Math.max(this.top+s.minorLabelHeight+s.majorLabelHeight,0),s.majorLineWidth=1,s.lineTop=0;break;case"top":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.majorLabelTop=0,s.minorLabelTop=s.majorLabelTop+s.majorLabelHeight,s.minorLineTop=s.minorLabelTop,s.minorLineHeight=Math.max(l-s.majorLabelHeight-this.top),s.minorLineWidth=1,s.majorLineTop=0,s.majorLineHeight=Math.max(l-this.top),s.majorLineWidth=1,s.lineTop=s.majorLabelHeight+s.minorLabelHeight;break;default:throw new Error('Unkown orientation "'+this.getOption("orientation")+'"')}var c=s.minorLabelHeight+s.majorLabelHeight;t+=e(this,"width",i.offsetWidth),t+=e(this,"height",c),this._updateConversion();var d=util.convert(n.start,"Number"),u=util.convert(n.end,"Number"),p=this.toTime(5*(s.minorCharWidth||10)).valueOf()-this.toTime(0).valueOf();this.step=new TimeStep(new Date(d),new Date(u),p),t+=e(s.range,"start",d),t+=e(s.range,"end",u),t+=e(s.range,"minimumStep",p.valueOf())}return t>0},TimeAxis.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):Range.conversion(t.start,t.end,this.width)},CurrentTime.prototype=new Component,CurrentTime.prototype.setOptions=Component.prototype.setOptions,CurrentTime.prototype.getContainer=function(){return this.frame},CurrentTime.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCurrentTime"))return void(t&&(i.removeChild(t),delete this.frame));t||(t=document.createElement("div"),t.className="currenttime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t),this.frame=t),e.conversion||e._updateConversion();var n=new Date,s=e.toScreen(n);t.style.left=s+"px",t.title="Current time: "+n,void 0!==this.currentTimeTimer&&(clearTimeout(this.currentTimeTimer),delete this.currentTimeTimer);var o=this,r=1/e.conversion.scale/2;return 30>r&&(r=30),this.currentTimeTimer=setTimeout(function(){o.repaint()},r),!1},CustomTime.prototype=new Component,CustomTime.prototype.setOptions=Component.prototype.setOptions,CustomTime.prototype.getContainer=function(){return this.frame},CustomTime.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCustomTime"))return void(t&&(i.removeChild(t),delete this.frame));if(!t){t=document.createElement("div"),t.className="customtime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t);var n=document.createElement("div");n.style.position="relative",n.style.top="0px",n.style.left="-10px",n.style.height="100%",n.style.width="20px",t.appendChild(n),this.frame=t,this.subscribe(this,"movetime")}e.conversion||e._updateConversion();var s=e.toScreen(this.customTime);return t.style.left=s+"px",t.title="Time: "+this.customTime,!1},CustomTime.prototype._setCustomTime=function(t){this.customTime=new Date(t.valueOf()),this.repaint()},CustomTime.prototype._getCustomTime=function(){return new Date(this.customTime.valueOf())},CustomTime.prototype.subscribe=function(t,e){var i=this,n={component:t,event:e,callback:function(t){i._onMouseDown(t,n)},params:{}};t.on("mousedown",n.callback),i.listeners.push(n)},CustomTime.prototype.on=function(t,e){var i=this.frame;if(!i)throw new Error("Cannot add event listener: no parent attached");events.addListener(this,t,e),util.addEventListener(i,t,e)},CustomTime.prototype._onMouseDown=function(t,e){t=t||window.event;var i=e.params,n=t.which?1==t.which:1==t.button;if(n){i.mouseX=util.getPageX(t),i.moved=!1,i.customTime=this.customTime;var s=this;i.onMouseMove||(i.onMouseMove=function(t){s._onMouseMove(t,e)},util.addEventListener(document,"mousemove",i.onMouseMove)),i.onMouseUp||(i.onMouseUp=function(t){s._onMouseUp(t,e)},util.addEventListener(document,"mouseup",i.onMouseUp)),util.stopPropagation(t),util.preventDefault(t)}},CustomTime.prototype._onMouseMove=function(t,e){t=t||window.event;var i=e.params,n=this.parent,s=util.getPageX(t);void 0===i.mouseX&&(i.mouseX=s);var o=s-i.mouseX;Math.abs(o)>=1&&(i.moved=!0);var r=n.toScreen(i.customTime),a=r+o,h=n.toTime(a);this._setCustomTime(h),events.trigger(this,"timechange",{customTime:this.customTime}),util.preventDefault(t)},CustomTime.prototype._onMouseUp=function(t,e){t=t||window.event;var i=e.params;i.onMouseMove&&(util.removeEventListener(document,"mousemove",i.onMouseMove),i.onMouseMove=null),i.onMouseUp&&(util.removeEventListener(document,"mouseup",i.onMouseUp),i.onMouseUp=null),i.moved&&events.trigger(this,"timechanged",{customTime:this.customTime}) },ItemSet.prototype=new Panel,ItemSet.types={box:ItemBox,range:ItemRange,rangeoverflow:ItemRangeOverflow,point:ItemPoint},ItemSet.prototype.setOptions=Component.prototype.setOptions,ItemSet.prototype.setRange=function(t){if(!(t instanceof Range||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},ItemSet.prototype.setSelection=function(t){var e,i,n,s,o;if(t){if(!Array.isArray(t))throw new TypeError("Array expected");for(e=0,i=this.selection.length;i>e;e++)n=this.selection[e],s=this.items[n],s&&s.unselect();for(this.selection=[],e=0,i=t.length;i>e;e++)n=t[e],s=this.items[n],s&&(this.selection.push(n),s.select());o=this.selection.concat([]),events.trigger(this,"select",{ids:o}),this.controller&&this.requestRepaint()}},ItemSet.prototype.getSelection=function(){return this.selection.concat([])},ItemSet.prototype._deselect=function(t){for(var e=this.selection,i=0,n=e.length;n>i;i++)if(e[i]==t){e.splice(i,1);break}},ItemSet.prototype.repaint=function(){var t=0,e=util.updateProperty,i=util.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.defaultOptions,r=this.frame;if(!r){r=document.createElement("div"),r.className="itemset";var a=n.className;a&&util.addClassName(r,util.option.asString(a));var h=document.createElement("div");h.className="background",r.appendChild(h),this.dom.background=h;var l=document.createElement("div");l.className="foreground",r.appendChild(l),this.dom.foreground=l;var c=document.createElement("div");c.className="itemset-axis",this.dom.axis=c,this.frame=r,t+=1}if(!this.parent)throw new Error("Cannot repaint itemset: no parent attached");var d=this.parent.getContainer();if(!d)throw new Error("Cannot repaint itemset: parent has no container element");r.parentNode||(d.appendChild(r),t+=1),this.dom.axis.parentNode||(d.appendChild(this.dom.axis),t+=1),t+=e(r.style,"left",i(n.left,"0px")),t+=e(r.style,"top",i(n.top,"0px")),t+=e(r.style,"width",i(n.width,"100%")),t+=e(r.style,"height",i(n.height,this.height+"px")),t+=e(this.dom.axis.style,"left",i(n.left,"0px")),t+=e(this.dom.axis.style,"width",i(n.width,"100%")),t+="bottom"==s?e(this.dom.axis.style,"top",this.height+this.top+"px"):e(this.dom.axis.style,"top",this.top+"px"),this._updateConversion();var u=this,p=this.queue,f=this.itemsData,g=this.items,m={};for(var v in p)if(p.hasOwnProperty(v)){var y=p[v],_=g[v],b=y.action;switch(b){case"add":case"update":var w=f&&f.get(v,m);if(w){var S=w.type||w.start&&w.end&&"range"||n.type||"box",T=ItemSet.types[S];if(_&&(T&&_ instanceof T?(_.data=w,t++):(t+=_.hide(),_=null)),!_){if(!T)throw new TypeError('Unknown item type "'+S+'"');_=new T(u,w,n,o),_.id=y.id,t++}_.repaint(),g[v]=_}delete p[v];break;case"remove":_&&(_.selected&&u._deselect(v),t+=_.hide()),delete g[v],delete p[v];break;default:console.log('Error: unknown action "'+b+'"')}}return util.forEach(this.items,function(e){e.visible?(t+=e.show(),e.reposition()):t+=e.hide()}),t>0},ItemSet.prototype.getForeground=function(){return this.dom.foreground},ItemSet.prototype.getBackground=function(){return this.dom.background},ItemSet.prototype.getAxis=function(){return this.dom.axis},ItemSet.prototype.reflow=function(){var t=0,e=this.options,i=e.margin&&e.margin.axis||this.defaultOptions.margin.axis,n=e.margin&&e.margin.item||this.defaultOptions.margin.item,s=util.updateProperty,o=util.option.asNumber,r=util.option.asSize,a=this.frame;if(a){this._updateConversion(),util.forEach(this.items,function(e){t+=e.reflow()}),this.stack.update();var h,l=o(e.maxHeight),c=null!=r(e.height);if(c)h=a.offsetHeight;else{var d=this.stack.ordered;if(d.length){var u=d[0].top,p=d[0].top+d[0].height;util.forEach(d,function(t){u=Math.min(u,t.top),p=Math.max(p,t.top+t.height)}),h=p-u+i+n}else h=i+n}null!=l&&(h=Math.min(h,l)),t+=s(this,"height",h),t+=s(this,"top",a.offsetTop),t+=s(this,"left",a.offsetLeft),t+=s(this,"width",a.offsetWidth)}else t+=1;return t>0},ItemSet.prototype.hide=function(){var t=!1;return this.frame&&this.frame.parentNode&&(this.frame.parentNode.removeChild(this.frame),t=!0),this.dom.axis&&this.dom.axis.parentNode&&(this.dom.axis.parentNode.removeChild(this.dom.axis),t=!0),t},ItemSet.prototype.setItems=function(t){var e,i=this,n=this.itemsData;if(t){if(!(t instanceof DataSet||t instanceof DataView))throw new TypeError("Data must be an instance of DataSet");this.itemsData=t}else this.itemsData=null;if(n&&(util.forEach(this.listeners,function(t,e){n.unsubscribe(e,t)}),e=n.getIds(),this._onRemove(e)),this.itemsData){var s=this.id;util.forEach(this.listeners,function(t,e){i.itemsData.subscribe(e,t,s)}),e=this.itemsData.getIds(),this._onAdd(e)}},ItemSet.prototype.getItems=function(){return this.itemsData},ItemSet.prototype._onUpdate=function(t){this._toQueue("update",t)},ItemSet.prototype._onAdd=function(t){this._toQueue("add",t)},ItemSet.prototype._onRemove=function(t){this._toQueue("remove",t)},ItemSet.prototype._toQueue=function(t,e){var i=this.queue;e.forEach(function(e){i[e]={id:e,action:t}}),this.controller&&this.requestRepaint()},ItemSet.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):Range.conversion(t.start,t.end,this.width)},ItemSet.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},ItemSet.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},Item.prototype.select=function(){this.selected=!0,this.visible&&this.repaint()},Item.prototype.unselect=function(){this.selected=!1,this.visible&&this.repaint()},Item.prototype.show=function(){return!1},Item.prototype.hide=function(){return!1},Item.prototype.repaint=function(){return!1},Item.prototype.reflow=function(){return!1},Item.prototype.getWidth=function(){return this.width},ItemBox.prototype=new Item(null,null),ItemBox.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");if(!e.box.parentNode){var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");i.appendChild(e.box),t=!0}if(!e.line.parentNode){var n=this.parent.getBackground();if(!n)throw new Error("Cannot repaint time axis: parent has no background container element");n.appendChild(e.line),t=!0}if(!e.dot.parentNode){var s=this.parent.getAxis();if(!n)throw new Error("Cannot repaint time axis: parent has no axis container element");s.appendChild(e.dot),t=!0}if(this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var o=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=o&&(this.className=o,e.box.className="item box"+o,e.line.className="item line"+o,e.dot.className="item dot"+o,t=!0)}return t},ItemBox.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},ItemBox.prototype.hide=function(){var t=!1,e=this.dom;return e&&(e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),e.line.parentNode&&e.line.parentNode.removeChild(e.line),e.dot.parentNode&&e.dot.parentNode.removeChild(e.dot)),t},ItemBox.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,l,c,d,u=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(c=this.data,d=this.parent&&this.parent.range,c&&d){var p=d.end-d.start;this.visible=c.start>d.start-p&&c.start0},ItemBox.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("DIV"),t.content=document.createElement("DIV"),t.content.className="content",t.box.appendChild(t.content),t.line=document.createElement("DIV"),t.line.className="line",t.dot=document.createElement("DIV"),t.dot.className="dot",t.box["timeline-item"]=this)},ItemBox.prototype.reposition=function(){var t=this.dom,e=this.props,i=this.options.orientation||this.defaultOptions.orientation;if(t){var n=t.box,s=t.line,o=t.dot;n.style.left=this.left+"px",n.style.top=this.top+"px",s.style.left=e.line.left+"px","top"==i?(s.style.top="0px",s.style.height=this.top+"px"):(s.style.top=this.top+this.height+"px",s.style.height=Math.max(this.parent.height-this.top-this.height+this.props.dot.height/2,0)+"px"),o.style.left=e.dot.left+"px",o.style.top=e.dot.top+"px"}},ItemPoint.prototype=new Item(null,null),ItemPoint.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.point.parentNode||(i.appendChild(e.point),i.appendChild(e.point),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.point.className="item point"+n,t=!0)}return t},ItemPoint.prototype.show=function(){return this.dom&&this.dom.point.parentNode?!1:this.repaint()},ItemPoint.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.point.parentNode&&(e.point.parentNode.removeChild(e.point),t=!0),t},ItemPoint.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,l,c=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(h=this.data,l=this.parent&&this.parent.range,h&&l){var d=l.end-l.start;this.visible=h.start>l.start-d&&h.start0},ItemPoint.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.point=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.point.appendChild(t.content),t.dot=document.createElement("div"),t.dot.className="dot",t.point.appendChild(t.dot),t.point["timeline-item"]=this)},ItemPoint.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.point.style.top=this.top+"px",t.point.style.left=this.left+"px",t.content.style.marginLeft=e.content.marginLeft+"px",t.dot.style.top=e.dot.top+"px")},ItemRange.prototype=new Item(null,null),ItemRange.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.box.className="item range"+n,t=!0)}return t},ItemRange.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},ItemRange.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),t},ItemRange.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,l,c,d,u,p,f,g,m=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(void 0==this.data.end)throw new Error('Property "end" missing in item '+this.data.id);return h=this.data,l=this.parent&&this.parent.range,this.visible=h&&l?h.startl.start:!1,this.visible&&(t=this.dom,t?(e=this.props,i=this.options,o=this.parent,r=o.toScreen(this.data.start),a=o.toScreen(this.data.end),c=util.updateProperty,d=t.box,u=o.width,f=i.orientation||this.defaultOptions.orientation,n=i.margin&&i.margin.axis||this.defaultOptions.margin.axis,s=i.padding||this.defaultOptions.padding,m+=c(e.content,"width",t.content.offsetWidth),m+=c(this,"height",d.offsetHeight),-u>r&&(r=-u),a>2*u&&(a=2*u),p=0>r?Math.min(-r,a-r-e.content.width-2*s):0,m+=c(e.content,"left",p),"top"==f?(g=n,m+=c(this,"top",g)):(g=o.height-this.height-n,m+=c(this,"top",g)),m+=c(this,"left",r),m+=c(this,"width",Math.max(a-r,1))):m+=1),m>0},ItemRange.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content),t.box["timeline-item"]=this)},ItemRange.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.box.style.top=this.top+"px",t.box.style.left=this.left+"px",t.box.style.width=this.width+"px",t.content.style.left=e.content.left+"px")},ItemRangeOverflow.prototype=new ItemRange(null,null),ItemRangeOverflow.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=this.data.className?" "+this.data.className:"";this.className!=n&&(this.className=n,e.box.className="item rangeoverflow"+n,t=!0)}return t},ItemRangeOverflow.prototype.getWidth=function(){return void 0!==this.props.content&&this.width0},GroupSet.prototype=new Panel,GroupSet.prototype.setOptions=Component.prototype.setOptions,GroupSet.prototype.setRange=function(){},GroupSet.prototype.setItems=function(t){this.itemsData=t;for(var e in this.groups)if(this.groups.hasOwnProperty(e)){var i=this.groups[e];i.setItems(t)}},GroupSet.prototype.getItems=function(){return this.itemsData},GroupSet.prototype.setRange=function(t){this.range=t},GroupSet.prototype.setGroups=function(t){var e,i=this;if(this.groupsData&&(util.forEach(this.listeners,function(t,e){i.groupsData.unsubscribe(e,t)}),e=this.groupsData.getIds(),this._onRemove(e)),t?t instanceof DataSet?this.groupsData=t:(this.groupsData=new DataSet({convert:{start:"Date",end:"Date"}}),this.groupsData.add(t)):this.groupsData=null,this.groupsData){var n=this.id;util.forEach(this.listeners,function(t,e){i.groupsData.subscribe(e,t,n)}),e=this.groupsData.getIds(),this._onAdd(e)}},GroupSet.prototype.getGroups=function(){return this.groupsData},GroupSet.prototype.setSelection=function(t){var e=[],i=this.groups;for(var n in i)if(i.hasOwnProperty(n)){var s=i[n];s.setSelection(t)}return e},GroupSet.prototype.getSelection=function(){var t=[],e=this.groups;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];t=t.concat(n.getSelection())}return t},GroupSet.prototype.repaint=function(){var t,e,i,n,s=0,o=util.updateProperty,r=util.option.asSize,a=util.option.asElement,h=this.options,l=this.dom.frame,c=this.dom.labels,d=this.dom.labelSet;if(!this.parent)throw new Error("Cannot repaint groupset: no parent attached");var u=this.parent.getContainer();if(!u)throw new Error("Cannot repaint groupset: parent has no container element");if(!l){l=document.createElement("div"),l.className="groupset",this.dom.frame=l;var p=h.className;p&&util.addClassName(l,util.option.asString(p)),s+=1}l.parentNode||(u.appendChild(l),s+=1);var f=a(h.labelContainer);if(!f)throw new Error('Cannot repaint groupset: option "labelContainer" not defined');c||(c=document.createElement("div"),c.className="labels",this.dom.labels=c),d||(d=document.createElement("div"),d.className="label-set",c.appendChild(d),this.dom.labelSet=d),c.parentNode&&c.parentNode==f||(c.parentNode&&c.parentNode.removeChild(c.parentNode),f.appendChild(c)),s+=o(l.style,"height",r(h.height,this.height+"px")),s+=o(l.style,"top",r(h.top,"0px")),s+=o(l.style,"left",r(h.left,"0px")),s+=o(l.style,"width",r(h.width,"100%")),s+=o(d.style,"top",r(h.top,"0px")),s+=o(d.style,"height",r(h.height,this.height+"px"));var g=this,m=this.queue,v=this.groups,y=this.groupsData,_=Object.keys(m);if(_.length){_.forEach(function(t){var e=m[t],i=v[t];switch(e){case"add":case"update":if(!i){var n=Object.create(g.options);util.extend(n,{height:null,maxHeight:null}),i=new Group(g,t,n),i.setItems(g.itemsData),v[t]=i,g.controller.add(i)}i.data=y.get(t),delete m[t];break;case"remove":i&&(i.setItems(),delete v[t],g.controller.remove(i)),delete m[t];break;default:console.log('Error: unknown action "'+e+'"')}});var b=this.groupsData.getIds({order:this.options.groupOrder});for(t=0;t0},GroupSet.prototype._createLabel=function(t){var e=this.groups[t],i=document.createElement("div");i.className="label";var n=document.createElement("div");n.className="inner",i.appendChild(n);var s=e.data&&e.data.content;s instanceof Element?n.appendChild(s):void 0!=s&&(n.innerHTML=s);var o=e.data&&e.data.className;return o&&util.addClassName(i,o),e.label=i,i},GroupSet.prototype.getContainer=function(){return this.dom.frame},GroupSet.prototype.getLabelsWidth=function(){return this.props.labels.width},GroupSet.prototype.reflow=function(){var t,e,i=0,n=this.options,s=util.updateProperty,o=util.option.asNumber,r=util.option.asSize,a=this.dom.frame;if(a){var h,l=o(n.maxHeight),c=null!=r(n.height);if(c)h=a.offsetHeight;else{h=0;for(t in this.groups)this.groups.hasOwnProperty(t)&&(e=this.groups[t],h+=e.height)}null!=l&&(h=Math.min(h,l)),i+=s(this,"height",h),i+=s(this,"top",a.offsetTop),i+=s(this,"left",a.offsetLeft),i+=s(this,"width",a.offsetWidth)}var d=0;for(t in this.groups)if(this.groups.hasOwnProperty(t)){e=this.groups[t];var u=e.props&&e.props.label&&e.props.label.width||0;d=Math.max(d,u)}return i+=s(this.props.labels,"width",d),i>0},GroupSet.prototype.hide=function(){return this.dom.frame&&this.dom.frame.parentNode?(this.dom.frame.parentNode.removeChild(this.dom.frame),!0):!1},GroupSet.prototype.show=function(){return this.dom.frame&&this.dom.frame.parentNode?!1:this.repaint()},GroupSet.prototype._onUpdate=function(t){this._toQueue(t,"update")},GroupSet.prototype._onAdd=function(t){this._toQueue(t,"add")},GroupSet.prototype._onRemove=function(t){this._toQueue(t,"remove")},GroupSet.prototype._toQueue=function(t,e){var i=this.queue;t.forEach(function(t){i[t]=e}),this.controller&&this.requestRepaint()},Timeline.prototype.setOptions=function(t){util.extend(this.options,t),this.range.setRange(t.start,t.end),this.controller.reflow(),this.controller.repaint()},Timeline.prototype.setCustomTime=function(t){this.customtime._setCustomTime(t)},Timeline.prototype.getCustomTime=function(){return new Date(this.customtime.customTime.valueOf())},Timeline.prototype.setItems=function(t){var e,i=null==this.itemsData;if(t?t instanceof DataSet&&(e=t):e=null,t instanceof DataSet||(e=new DataSet({convert:{start:"Date",end:"Date"}}),e.add(t)),this.itemsData=e,this.content.setItems(e),i&&(void 0==this.options.start||void 0==this.options.end)){var n=this.getItemRange(),s=n.min,o=n.max;if(null!=s&&null!=o){var r=o.valueOf()-s.valueOf();0>=r&&(r=864e5),s=new Date(s.valueOf()-.05*r),o=new Date(o.valueOf()+.05*r)}void 0!=this.options.start&&(s=util.convert(this.options.start,"Date")),void 0!=this.options.end&&(o=util.convert(this.options.end,"Date")),(null!=s||null!=o)&&this.range.setRange(s,o)}},Timeline.prototype.setGroups=function(t){var e=this;this.groupsData=t;var i=this.groupsData?GroupSet:ItemSet;if(!(this.content instanceof i)){this.content&&(this.content.hide(),this.content.setItems&&this.content.setItems(),this.content.setGroups&&this.content.setGroups(),this.controller.remove(this.content));var n=Object.create(this.options);util.extend(n,{top:function(){return"top"==e.options.orientation?e.timeaxis.height:e.itemPanel.height-e.timeaxis.height-e.content.height},left:null,width:"100%",height:function(){return e.options.height?e.itemPanel.height-e.timeaxis.height:null},maxHeight:function(){if(e.options.maxHeight){if(!util.isNumber(e.options.maxHeight))throw new TypeError("Number expected for property maxHeight");return e.options.maxHeight-e.timeaxis.height}return null},labelContainer:function(){return e.labelPanel.getContainer()}}),this.content=new i(this.itemPanel,[this.timeaxis],n),this.content.setRange&&this.content.setRange(this.range),this.content.setItems&&this.content.setItems(this.itemsData),this.content.setGroups&&this.content.setGroups(this.groupsData),this.controller.add(this.content)}},Timeline.prototype.getItemRange=function(){var t=this.itemsData,e=null,i=null;if(t){var n=t.min("start");e=n?n.start.valueOf():null;var s=t.max("start");s&&(i=s.start.valueOf());var o=t.max("end");o&&(i=null==i?o.end.valueOf():Math.max(i,o.end.valueOf()))}return{min:null!=e?new Date(e):null,max:null!=i?new Date(i):null}},Timeline.prototype.setSelection=function(t){this.content&&this.content.setSelection(t)},Timeline.prototype.getSelection=function(){return this.content?this.content.getSelection():[]},Timeline.prototype.on=function(t,e){var i=["rangechange","rangechanged","select"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());events.addListener(this,t,e)},Timeline.prototype.off=function(t,e){events.removeListener(this,t,e)},Timeline.prototype._trigger=function(t,e){events.trigger(this,t,e||{})},Timeline.prototype._onSelectItem=function(t){var e=this._itemFromTarget(t),i=e?[e.id]:[];this.setSelection(i),this._trigger("select",{items:this.getSelection()}),t.stopPropagation()},Timeline.prototype._onMultiSelectItem=function(t){var e,i=this._itemFromTarget(t);if(i){e=this.getSelection();var n=e.indexOf(i.id);-1==n?e.push(i.id):e.splice(n,1),this.setSelection(e),this._trigger("select",{items:this.getSelection()}),t.stopPropagation()}},Timeline.prototype._itemFromTarget=function(t){for(var e=t.target;e;){if(e.hasOwnProperty("timeline-item"))return e["timeline-item"];e=e.parentNode}return null},function(t){function e(t){return C=t,u()}function i(){M=0,D=C.charAt(0)}function n(){M++,D=C.charAt(M)}function s(){return C.charAt(M+1)}function o(t){return O.test(t)}function r(t,e){if(t||(t={}),e)for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function a(t,e,i){for(var n=e.split("."),s=t;n.length;){var o=n.shift();n.length?(s[o]||(s[o]={}),s=s[o]):s[o]=i}}function h(t,e){for(var i,n,s=null,o=[t],a=t;a.parent;)o.push(a.parent),a=a.parent;if(a.nodes)for(i=0,n=a.nodes.length;n>i;i++)if(e.id===a.nodes[i].id){s=a.nodes[i];break}for(s||(s={id:e.id},t.node&&(s.attr=r(s.attr,t.node))),i=o.length-1;i>=0;i--){var h=o[i];h.nodes||(h.nodes=[]),-1==h.nodes.indexOf(s)&&h.nodes.push(s)}e.attr&&(s.attr=r(s.attr,e.attr))}function l(t,e){if(t.edges||(t.edges=[]),t.edges.push(e),t.edge){var i=r({},t.edge);e.attr=r(i,e.attr)}}function c(t,e,i,n,s){var o={from:e,to:i,type:n};return t.edge&&(o.attr=r({},t.edge)),o.attr=r(o.attr||{},s),o}function d(){for(N=E.NULL,I="";" "==D||" "==D||"\n"==D||"\r"==D;)n();do{var t=!1;if("#"==D){for(var e=M-1;" "==C.charAt(e)||" "==C.charAt(e);)e--;if("\n"==C.charAt(e)||""==C.charAt(e)){for(;""!=D&&"\n"!=D;)n();t=!0}}if("/"==D&&"/"==s()){for(;""!=D&&"\n"!=D;)n();t=!0}if("/"==D&&"*"==s()){for(;""!=D;){if("*"==D&&"/"==s()){n(),n();break}n()}t=!0}for(;" "==D||" "==D||"\n"==D||"\r"==D;)n()}while(t);if(""==D)return void(N=E.DELIMITER);var i=D+s();if(x[i])return N=E.DELIMITER,I=i,n(),void n();if(x[D])return N=E.DELIMITER,I=D,void n();if(o(D)||"-"==D){for(I+=D,n();o(D);)I+=D,n();return"false"==I?I=!1:"true"==I?I=!0:isNaN(Number(I))||(I=Number(I)),void(N=E.IDENTIFIER)}if('"'==D){for(n();""!=D&&('"'!=D||'"'==D&&'"'==s());)I+=D,'"'==D&&n(),n();if('"'!=D)throw b('End of string " expected');return n(),void(N=E.IDENTIFIER)}for(N=E.UNKNOWN;""!=D;)I+=D,n();throw new SyntaxError('Syntax error in part "'+w(I,30)+'"')}function u(){var t={};if(i(),d(),"strict"==I&&(t.strict=!0,d()),("graph"==I||"digraph"==I)&&(t.type=I,d()),N==E.IDENTIFIER&&(t.id=I,d()),"{"!=I)throw b("Angle bracket { expected");if(d(),p(t),"}"!=I)throw b("Angle bracket } expected");if(d(),""!==I)throw b("End of file expected");return d(),delete t.node,delete t.edge,delete t.graph,t}function p(t){for(;""!==I&&"}"!=I;)f(t),";"==I&&d()}function f(t){var e=g(t);if(e)return void y(t,e);var i=m(t);if(!i){if(N!=E.IDENTIFIER)throw b("Identifier expected");var n=I;if(d(),"="==I){if(d(),N!=E.IDENTIFIER)throw b("Identifier expected");t[n]=I,d()}else v(t,n)}}function g(t){var e=null;if("subgraph"==I&&(e={},e.type="subgraph",d(),N==E.IDENTIFIER&&(e.id=I,d())),"{"==I){if(d(),e||(e={}),e.parent=t,e.node=t.node,e.edge=t.edge,e.graph=t.graph,p(e),"}"!=I)throw b("Angle bracket } expected");d(),delete e.node,delete e.edge,delete e.graph,delete e.parent,t.subgraphs||(t.subgraphs=[]),t.subgraphs.push(e)}return e}function m(t){return"node"==I?(d(),t.node=_(),"node"):"edge"==I?(d(),t.edge=_(),"edge"):"graph"==I?(d(),t.graph=_(),"graph"):null}function v(t,e){var i={id:e},n=_();n&&(i.attr=n),h(t,i),y(t,e)}function y(t,e){for(;"->"==I||"--"==I;){var i,n=I;d();var s=g(t);if(s)i=s;else{if(N!=E.IDENTIFIER)throw b("Identifier or subgraph expected");i=I,h(t,{id:i}),d()}var o=_(),r=c(t,e,i,n,o);l(t,r),e=i}}function _(){for(var t=null;"["==I;){for(d(),t={};""!==I&&"]"!=I;){if(N!=E.IDENTIFIER)throw b("Attribute name expected");var e=I;if(d(),"="!=I)throw b("Equal sign = expected");if(d(),N!=E.IDENTIFIER)throw b("Attribute value expected");var i=I;a(t,e,i),d(),","==I&&d()}if("]"!=I)throw b("Bracket ] expected");d()}return t}function b(t){return new SyntaxError(t+', got "'+w(I,30)+'" (char '+M+")")}function w(t,e){return t.length<=e?t:t.substr(0,27)+"..."}function S(t,e,i){t instanceof Array?t.forEach(function(t){e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}):e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}function T(t){function i(t){var e={from:t.from,to:t.to};return r(e,t.attr),e.style="->"==t.type?"arrow":"line",e}var n=e(t),s={nodes:[],edges:[],options:{}};return n.nodes&&n.nodes.forEach(function(t){var e={id:t.id,label:String(t.label||t.id)};r(e,t.attr),e.image&&(e.shape="image"),s.nodes.push(e)}),n.edges&&n.edges.forEach(function(t){var e,n;e=t.from instanceof Object?t.from.nodes:{id:t.from},n=t.to instanceof Object?t.to.nodes:{id:t.to},t.from instanceof Object&&t.from.edges&&t.from.edges.forEach(function(t){var e=i(t);s.edges.push(e)}),S(e,n,function(e,n){var o=c(s,e.id,n.id,t.type,t.attr),r=i(o);s.edges.push(r)}),t.to instanceof Object&&t.to.edges&&t.to.edges.forEach(function(t){var e=i(t);s.edges.push(e)})}),n.attr&&(s.options=n.attr),s}var E={NULL:0,DELIMITER:1,IDENTIFIER:2,UNKNOWN:3},x={"{":!0,"}":!0,"[":!0,"]":!0,";":!0,"=":!0,",":!0,"->":!0,"--":!0},C="",M=0,D="",I="",N=E.NULL,O=/[a-zA-Z_0-9.:#]/;t.parseDOT=e,t.DOTToGraph=T}("undefined"!=typeof util?util:exports),"undefined"!=typeof CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.circle=function(t,e,i){this.beginPath(),this.arc(t,e,i,0,2*Math.PI,!1)},CanvasRenderingContext2D.prototype.square=function(t,e,i){this.beginPath(),this.rect(t-i,e-i,2*i,2*i)},CanvasRenderingContext2D.prototype.triangle=function(t,e,i){this.beginPath();var n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e-(r-o)),this.lineTo(t+s,e+o),this.lineTo(t-s,e+o),this.lineTo(t,e-(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.triangleDown=function(t,e,i){this.beginPath();var n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e+(r-o)),this.lineTo(t+s,e-o),this.lineTo(t-s,e-o),this.lineTo(t,e+(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.star=function(t,e,i){this.beginPath();for(var n=0;10>n;n++){var s=n%2===0?1.3*i:.5*i;this.lineTo(t+s*Math.sin(2*n*Math.PI/10),e-s*Math.cos(2*n*Math.PI/10))}this.closePath()},CanvasRenderingContext2D.prototype.roundRect=function(t,e,i,n,s){var o=Math.PI/180;0>i-2*s&&(s=i/2),0>n-2*s&&(s=n/2),this.beginPath(),this.moveTo(t+s,e),this.lineTo(t+i-s,e),this.arc(t+i-s,e+s,s,270*o,360*o,!1),this.lineTo(t+i,e+n-s),this.arc(t+i-s,e+n-s,s,0,90*o,!1),this.lineTo(t+s,e+n),this.arc(t+s,e+n-s,s,90*o,180*o,!1),this.lineTo(t,e+s),this.arc(t+s,e+s,s,180*o,270*o,!1)},CanvasRenderingContext2D.prototype.ellipse=function(t,e,i,n){var s=.5522848,o=i/2*s,r=n/2*s,a=t+i,h=e+n,l=t+i/2,c=e+n/2;this.beginPath(),this.moveTo(t,c),this.bezierCurveTo(t,c-r,l-o,e,l,e),this.bezierCurveTo(l+o,e,a,c-r,a,c),this.bezierCurveTo(a,c+r,l+o,h,l,h),this.bezierCurveTo(l-o,h,t,c+r,t,c)},CanvasRenderingContext2D.prototype.database=function(t,e,i,n){var s=1/3,o=i,r=n*s,a=.5522848,h=o/2*a,l=r/2*a,c=t+o,d=e+r,u=t+o/2,p=e+r/2,f=e+(n-r/2),g=e+n; -this.beginPath(),this.moveTo(c,p),this.bezierCurveTo(c,p+l,u+h,d,u,d),this.bezierCurveTo(u-h,d,t,p+l,t,p),this.bezierCurveTo(t,p-l,u-h,e,u,e),this.bezierCurveTo(u+h,e,c,p-l,c,p),this.lineTo(c,f),this.bezierCurveTo(c,f+l,u+h,g,u,g),this.bezierCurveTo(u-h,g,t,f+l,t,f),this.lineTo(t,p)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,n){var s=t-n*Math.cos(i),o=e-n*Math.sin(i),r=t-.9*n*Math.cos(i),a=e-.9*n*Math.sin(i),h=s+n/3*Math.cos(i+.5*Math.PI),l=o+n/3*Math.sin(i+.5*Math.PI),c=s+n/3*Math.cos(i-.5*Math.PI),d=o+n/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,l),this.lineTo(r,a),this.lineTo(c,d),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,n,s){s||(s=[10,5]),0==u&&(u=.001);var o=s.length;this.moveTo(t,e);for(var r=i-t,a=n-e,h=a/r,l=Math.sqrt(r*r+a*a),c=0,d=!0;l>=.1;){var u=s[c++%o];u>l&&(u=l);var p=Math.sqrt(u*u/(1+h*h));0>r&&(p=-p),t+=p,e+=h*p,this[d?"lineTo":"moveTo"](t,e),l-=u,d=!d}}),Node.prototype.resetCluster=function(){this.formationScale=void 0,this.clusterSize=1,this.containedNodes={},this.containedEdges={},this.clusterSessions=[]},Node.prototype.attachEdge=function(t){-1==this.edges.indexOf(t)&&this.edges.push(t),-1==this.dynamicEdges.indexOf(t)&&this.dynamicEdges.push(t),this.dynamicEdgesLength=this.dynamicEdges.length,this._updateMass()},Node.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&(this.edges.splice(e,1),this.dynamicEdges.splice(e,1)),this.dynamicEdgesLength=this.dynamicEdges.length,this._updateMass()},Node.prototype._updateMass=function(){this.mass=1},Node.prototype.setProperties=function(t,e){if(t){if(this.originalLabel=void 0,void 0!==t.id&&(this.id=t.id),void 0!==t.label&&(this.label=t.label,this.originalLabel=t.label),void 0!==t.title&&(this.title=t.title),void 0!==t.group&&(this.group=t.group),void 0!==t.x&&(this.x=t.x),void 0!==t.y&&(this.y=t.y),void 0!==t.value&&(this.value=t.value),void 0!==t.horizontalAlignLeft&&(this.horizontalAlignLeft=t.horizontalAlignLeft),void 0!==t.verticalAlignTop&&(this.verticalAlignTop=t.verticalAlignTop),void 0!==t.triggerFunction&&(this.triggerFunction=t.triggerFunction),void 0===this.id)throw"Node must have an id";if(this.group){var i=this.grouplist.get(this.group);for(var n in i)i.hasOwnProperty(n)&&(this[n]=i[n])}if(void 0!==t.shape&&(this.shape=t.shape),void 0!==t.image&&(this.image=t.image),void 0!==t.radius&&(this.radius=t.radius),void 0!==t.color&&(this.color=Node.parseColor(t.color)),void 0!==t.fontColor&&(this.fontColor=t.fontColor),void 0!==t.fontSize&&(this.fontSize=t.fontSize),void 0!==t.fontFace&&(this.fontFace=t.fontFace),void 0!==this.image){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.image)}switch(this.xFixed=this.xFixed||void 0!==t.x&&t.fixed,this.yFixed=this.yFixed||void 0!==t.y&&t.fixed,this.radiusFixed=this.radiusFixed||void 0!==t.radius,"image"==this.shape&&(this.radiusMin=e.nodes.widthMin,this.radiusMax=e.nodes.widthMax),this.shape){case"database":this.draw=this._drawDatabase,this.resize=this._resizeDatabase;break;case"box":this.draw=this._drawBox,this.resize=this._resizeBox;break;case"circle":this.draw=this._drawCircle,this.resize=this._resizeCircle;break;case"ellipse":this.draw=this._drawEllipse,this.resize=this._resizeEllipse;break;case"image":this.draw=this._drawImage,this.resize=this._resizeImage;break;case"text":this.draw=this._drawText,this.resize=this._resizeText;break;case"dot":this.draw=this._drawDot,this.resize=this._resizeShape;break;case"square":this.draw=this._drawSquare,this.resize=this._resizeShape;break;case"triangle":this.draw=this._drawTriangle,this.resize=this._resizeShape;break;case"triangleDown":this.draw=this._drawTriangleDown,this.resize=this._resizeShape;break;case"star":this.draw=this._drawStar,this.resize=this._resizeShape;break;default:this.draw=this._drawEllipse,this.resize=this._resizeEllipse}this._reset()}},Node.parseColor=function(t){var e;return util.isString(t)?e={border:t,background:t,highlight:{border:t,background:t}}:(e={},e.background=t.background||"white",e.border=t.border||e.background,util.isString(t.highlight)?e.highlight={border:t.highlight,background:t.highlight}:(e.highlight={},e.highlight.background=t.highlight&&t.highlight.background||e.background,e.highlight.border=t.highlight&&t.highlight.border||e.border)),e},Node.prototype.select=function(){this.selected=!0,this._reset()},Node.prototype.unselect=function(){this.selected=!1,this._reset()},Node.prototype.clearSizeCache=function(){this._reset()},Node.prototype._reset=function(){this.width=void 0,this.height=void 0},Node.prototype.getTitle=function(){return this.title},Node.prototype.distanceToBorder=function(t,e){var i=1;switch(this.width||this.resize(t),this.shape){case"circle":case"dot":return this.radius+i;case"ellipse":var n=this.width/2,s=this.height/2,o=Math.sin(e)*n,r=Math.cos(e)*s;return n*s/Math.sqrt(o*o+r*r);case"box":case"image":case"text":default:return this.width?Math.min(Math.abs(this.width/2/Math.cos(e)),Math.abs(this.height/2/Math.sin(e)))+i:0}},Node.prototype._setForce=function(t,e){this.fx=t,this.fy=e},Node.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},Node.prototype.discreteStep=function(t){if(!this.xFixed){var e=-this.damping*this.vx,i=(this.fx+e)/this.mass;this.vx+=i*t,this.x+=this.vx*t}if(!this.yFixed){var n=-this.damping*this.vy,s=(this.fy+n)/this.mass;this.vy+=s*t,this.y+=this.vy*t}},Node.prototype.discreteStepLimited=function(t,e){if(!this.xFixed){var i=-this.damping*this.vx,n=(this.fx+i)/this.mass;this.vx+=n*t,this.vx=Math.abs(this.vx)>e?this.vx>0?e:-e:this.vx,this.x+=this.vx*t}if(!this.yFixed){var s=-this.damping*this.vy,o=(this.fy+s)/this.mass;this.vy+=o*t,this.vy=Math.abs(this.vy)>e?this.vy>0?e:-e:this.vy,this.y+=this.vy*t}},Node.prototype.isFixed=function(){return this.xFixed&&this.yFixed},Node.prototype.isMoving=function(t){return Math.abs(this.vx)>t||Math.abs(this.vy)>t?!0:(this.vx=0,this.vy=0,!1)},Node.prototype.isSelected=function(){return this.selected},Node.prototype.getValue=function(){return this.value},Node.prototype.getDistance=function(t,e){var i=this.x-t,n=this.y-e;return Math.sqrt(i*i+n*n)},Node.prototype.setValueRange=function(t,e){if(!this.radiusFixed&&void 0!==this.value)if(e==t)this.radius=(this.radiusMin+this.radiusMax)/2;else{var i=(this.radiusMax-this.radiusMin)/(e-t);this.radius=(this.value-t)*i+this.radiusMin}this.baseRadiusValue=this.radius},Node.prototype.draw=function(){throw"Draw method not initialized for node"},Node.prototype.resize=function(){throw"Resize method not initialized for node"},Node.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},Node.prototype._resizeImage=function(){if(!this.width||!this.height){var t,e;if(this.value){this.radius=this.baseRadiusValue;var i=this.imageObj.height/this.imageObj.width;void 0!==i?(t=this.radius||this.imageObj.width,e=this.radius*i||this.imageObj.height):(t=0,e=0)}else t=this.imageObj.width,e=this.imageObj.height;this.width=t,this.height=e,this.width>0&&this.height>0&&(this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor)}},Node.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e;if(0!=this.imageObj.width){if(this.clusterSize>1){var i=this.clusterSize>1?10:0;i*=this.graphScaleInv,i=Math.min(.2*this.width,i),t.globalAlpha=.5,t.drawImage(this.imageObj,this.left-i,this.top-i,this.width+2*i,this.height+2*i)}t.globalAlpha=1,t.drawImage(this.imageObj,this.left,this.top,this.width,this.height),e=this.y+this.height/2}else e=this.y;this._label(t,this.label,this.x,e,void 0,"top")},Node.prototype._resizeBox=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=.5*(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=.5*(this.clusterSize-1)*this.clusterSizeHeightFactor}},Node.prototype._drawBox=function(t){this._resizeBox(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.roundRect(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth,this.radius),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.roundRect(this.left,this.top,this.width,this.height,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.prototype._resizeDatabase=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=i.width+2*e;this.width=n,this.height=n,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor}},Node.prototype._drawDatabase=function(t){this._resizeDatabase(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.database(this.x-this.width/2-2*t.lineWidth,this.y-.5*this.height-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.database(this.x-this.width/2,this.y-.5*this.height,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=Math.max(i.width,i.height)+2*e;this.radius=n/2,this.width=n,this.height=n,this.radius+=.5*(this.clusterSize-1)*this.clusterSizeRadiusFactor}},Node.prototype._drawCircle=function(t){this._resizeCircle(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.circle(this.x,this.y,this.radius+2*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.circle(this.x,this.y,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.prototype._resizeEllipse=function(t){if(!this.width){var e=this.getTextSize(t);this.width=1.5*e.width,this.height=2*e.height,this.width1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.ellipse(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.ellipse(this.left,this.top,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.prototype._drawDot=function(t){this._drawShape(t,"circle")},Node.prototype._drawTriangle=function(t){this._drawShape(t,"triangle")},Node.prototype._drawTriangleDown=function(t){this._drawShape(t,"triangleDown")},Node.prototype._drawSquare=function(t){this._drawShape(t,"square")},Node.prototype._drawStar=function(t){this._drawShape(t,"star")},Node.prototype._resizeShape=function(){if(!this.width){this.radius=this.baseRadiusValue;var t=2*this.radius;this.width=t,this.height=t,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=.5*(this.clusterSize-1)*this.clusterSizeRadiusFactor}},Node.prototype._drawShape=function(t,e){this._resizeShape(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var i=2.5,n=2,s=2;switch(e){case"dot":s=2;break;case"square":s=2;break;case"triangle":s=3;break;case"triangleDown":s=3;break;case"star":s=4}t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?n:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t[e](this.x,this.y,this.radius+s*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?n:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t[e](this.x,this.y,this.radius),t.fill(),t.stroke(),this.label&&this._label(t,this.label,this.x,this.y+this.height/2,void 0,"top")},Node.prototype._resizeText=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor}},Node.prototype._drawText=function(t){this._resizeText(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,this._label(t,this.label,this.x,this.y)},Node.prototype._label=function(t,e,i,n,s,o){if(e){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle=this.fontColor||"black",t.textAlign=s||"center",t.textBaseline=o||"middle";for(var r=e.split("\n"),a=r.length,h=this.fontSize+4,l=n+(1-a)/2*h,c=0;a>c;c++)t.fillText(r[c],i,l),l+=h}},Node.prototype.getTextSize=function(t){if(void 0!==this.label){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace;for(var e=this.label.split("\n"),i=(this.fontSize+4)*e.length,n=0,s=0,o=e.length;o>s;s++)n=Math.max(n,t.measureText(e[s]).width);return{width:n,height:i}}return{width:0,height:0}},Node.prototype.inArea=function(){return void 0!==this.width?this.x+this.width*this.graphScaleInv>=this.canvasTopLeft.x&&this.x-this.width*this.graphScaleInv=this.canvasTopLeft.y&&this.y-this.height*this.graphScaleInv=this.canvasTopLeft.x&&this.x=this.canvasTopLeft.y&&this.yh},Edge.prototype._drawLine=function(t){t.strokeStyle=this.color,t.lineWidth=this._getLineWidth();var e;if(this.from!=this.to)this._line(t),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y));else{var i,n,s=this.length/4,o=this.from;o.width||o.resize(t),o.width>o.height?(i=o.x+o.width/2,n=o.y-s):(i=o.x+s,n=o.y-o.height/2),this._circle(t,i,n,s),e=this._pointOnCircle(i,n,s,.5),this._label(t,this.label,e.x,e.y)}},Edge.prototype._getLineWidth=function(){return 1==this.selected?Math.min(2*this.width,this.widthMax)*this.graphScaleInv:this.width*this.graphScaleInv},Edge.prototype._line=function(t){t.beginPath(),t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y),t.stroke()},Edge.prototype._circle=function(t,e,i,n){t.beginPath(),t.arc(e,i,n,0,2*Math.PI,!1),t.stroke()},Edge.prototype._label=function(t,e,i,n){if(e){t.font=(this.from.selected||this.to.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle="white";var s=t.measureText(e).width,o=this.fontSize,r=i-s/2,a=n-o/2;t.fillRect(r,a,s,o),t.fillStyle=this.fontColor||"black",t.textAlign="left",t.textBaseline="top",t.fillText(e,r,a)}},Edge.prototype._drawDashLine=function(t){if(t.strokeStyle=this.color,t.lineWidth=this._getLineWidth(),t.beginPath(),t.lineCap="round",void 0!==this.dash.altLength?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]):void 0!==this.dash.length&&void 0!==this.dash.gap?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap]):(t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y)),t.stroke(),this.label){var e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}},Edge.prototype._pointOnLine=function(t){return{x:(1-t)*this.from.x+t*this.to.x,y:(1-t)*this.from.y+t*this.to.y}},Edge.prototype._pointOnCircle=function(t,e,i,n){var s=2*(n-3/8)*Math.PI;return{x:t+i*Math.cos(s),y:e-i*Math.sin(s)}},Edge.prototype._drawArrowCenter=function(t){var e;if(t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth(),this.from!=this.to){this._line(t);var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),n=10+5*this.width;e=this._pointOnLine(.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y))}else{var s,o,r=this.length/4,a=this.from;a.width||a.resize(t),a.width>a.height?(s=a.x+a.width/2,o=a.y-r):(s=a.x+r,o=a.y-a.height/2),this._circle(t,s,o,r);var i=.2*Math.PI,n=10+5*this.width;e=this._pointOnCircle(s,o,r,.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(s,o,r,.5),this._label(t,this.label,e.x,e.y))}},Edge.prototype._drawArrow=function(t){t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth();var e,i;if(this.from!=this.to){e=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x);var n=this.to.x-this.from.x,s=this.to.y-this.from.y,o=Math.sqrt(n*n+s*s),r=this.from.distanceToBorder(t,e+Math.PI),a=(o-r)/o,h=a*this.from.x+(1-a)*this.to.x,l=a*this.from.y+(1-a)*this.to.y,c=this.to.distanceToBorder(t,e),d=(o-c)/o,u=(1-d)*this.from.x+d*this.to.x,p=(1-d)*this.from.y+d*this.to.y;if(t.beginPath(),t.moveTo(h,l),t.lineTo(u,p),t.stroke(),i=10+5*this.width,t.arrow(u,p,e,i),t.fill(),t.stroke(),this.label){var f=this._pointOnLine(.5);this._label(t,this.label,f.x,f.y)}}else{var g,m,v,y=this.from,_=this.length/4;y.width||y.resize(t),y.width>y.height?(g=y.x+y.width/2,m=y.y-_,v={x:g,y:y.y,angle:.9*Math.PI}):(g=y.x+_,m=y.y-y.height/2,v={x:y.x,y:m,angle:.6*Math.PI}),t.beginPath(),t.arc(g,m,_,0,2*Math.PI,!1),t.stroke(),i=10+5*this.width,t.arrow(v.x,v.y,v.angle,i),t.fill(),t.stroke(),this.label&&(f=this._pointOnCircle(g,m,_,.5),this._label(t,this.label,f.x,f.y))}},Edge._dist=function(t,e,i,n,s,o){var r=i-t,a=n-e,h=r*r+a*a,l=((s-t)*r+(o-e)*a)/h;l>1?l=1:0>l&&(l=0);var c=t+l*r,d=e+l*a,u=c-s,p=d-o;return Math.sqrt(u*u+p*p)},Edge.prototype.setScale=function(t){this.graphScaleInv=1/t},Edge.prototype.select=function(){this.selected=!0},Edge.prototype.unselect=function(){this.selected=!1},Popup.prototype.setPosition=function(t,e){this.x=parseInt(t),this.y=parseInt(e)},Popup.prototype.setText=function(t){this.frame.innerHTML=t},Popup.prototype.show=function(t){if(void 0===t&&(t=!0),t){var e=this.frame.clientHeight,i=this.frame.clientWidth,n=this.frame.parentNode.clientHeight,s=this.frame.parentNode.clientWidth,o=this.y-e;o+e+this.padding>n&&(o=n-e-this.padding),os&&(r=s-i-this.padding),rthis.constants.clustering.clusterThreshold&&1==this.constants.clustering.enabled&&this.clusterToFit(this.constants.clustering.reduceToNodes,!1),this._calculateForcesBarnesHut())},_calculateForcesOriginal:function(){this._calculateGravitationalForces(1),this._calculateRepulsionForces(),this._calculateSpringForces(1)},_calculateForcesBarnesHut:function(){this._clearForces(),this._calculateBarnesHutForces(),this._calculateSpringForces(1)},_clearForces:function(){for(var t,e=this.nodes,i=0;in&&(i=Math.atan2(e,t),a=.5*g>n?1:m*n+f,a*=0==r?1:1+r*this.constants.clustering.forceAmplification,s=Math.cos(i)*a,o=Math.sin(i)*a,h._addForce(-s,-o),l._addForce(s,o))}},_calculateSpringForces:function(t){var e,i,n,s,o,r,a,h,l,c,d,u=this.edges;for(c in u)u.hasOwnProperty(c)&&(l=u[c],l.connected&&this.nodes.hasOwnProperty(l.toId)&&this.nodes.hasOwnProperty(l.fromId)&&(d=l.to.clusterSize+l.from.clusterSize-2,e=l.to.x-l.from.x,i=l.to.y-l.from.y,h=l.length,h+=d*this.constants.clustering.edgeGrowth,a=Math.sqrt(e*e+i*i),n=Math.atan2(i,e),r=.02*(h-a)*t,s=Math.cos(n)*r,o=Math.sin(n)*r,l.from._addForce(-s,-o),l.to._addForce(s,o)))},_calculateBarnesHutForces:function(){this._formBarnesHutTree();var t,e=this.nodes,i=this.nodeIndices,n=i.length,s=this.barnesHutTree;this.theta=.2,this.graviationalConstant=-1e4;for(var o=0;n>o;o++)t=e[i[o]],this._getForceContribution(s.root.children.NW,t),this._getForceContribution(s.root.children.NE,t),this._getForceContribution(s.root.children.SW,t),this._getForceContribution(s.root.children.SE,t)},_getForceContribution:function(t,e){if(t.childrenCount>0){var i,n,s;if(i=t.CenterOfMass.x-e.x,n=t.CenterOfMass.y-e.y,s=Math.sqrt(i*i+n*n),s>0){var o=1/s;t.size*o>this.theta?4==t.childrenCount?(this._getForceContribution(t.children.NW,e),this._getForceContribution(t.children.NE,e),this._getForceContribution(t.children.SW,e),this._getForceContribution(t.children.SE,e)):this._getForceOnNode(t,e,i,n,o):this._getForceOnNode(t,e,i,n,o)}}},_getForceOnNode:function(t,e,i,n,s){var o=this.graviationalConstant*t.mass*e.mass*s*s,r=Math.atan2(n,i),a=Math.cos(r)*o,h=Math.sin(r)*o;e._addForce(a,h)},_formBarnesHutTree:function(){for(var t,e=this.nodes,i=this.nodeIndices,n=i.length,s=Number.MAX_VALUE,o=Number.MAX_VALUE,r=-Number.MAX_VALUE,a=-Number.MAX_VALUE,h=0;n>h;h++){var l=e[i[h]].x,c=e[i[h]].y;s>l&&(s=l),l>r&&(r=l),o>c&&(o=c),c>a&&(a=c)}var d=Math.abs(r-s)-Math.abs(a-o);d>0?(o-=.5*d,a+=.5*d):(s+=.5*d,a-=.5*d);var u={root:{CenterOfMass:{x:0,y:0},mass:0,range:{minX:s,maxX:r,minY:o,maxY:a},size:Math.abs(r-s),children:{data:null},childrenCount:4}};for(this._splitBranch(u.root),h=0;n>h;h++)t=e[i[h]],this._placeInTree(u.root,t);this.barnesHutTree=u},_updateBranchMass:function(t,e){var i=t.mass+e.mass,n=1/i;t.CenterOfMass.x=t.CenterOfMass.x*t.mass+e.x*e.mass,t.CenterOfMass.x*=n,t.CenterOfMass.y=t.CenterOfMass.y*t.mass+e.y*e.mass,t.CenterOfMass.y*=n,t.mass=i},_placeInTree:function(t,e){this._updateBranchMass(t,e),t.children.NW.range.maxX>e.x?t.children.NW.range.maxY>e.y?this._placeInRegion(t,e,"NW"):this._placeInRegion(t,e,"SW"):t.children.NE.range.maxY>e.y?this._placeInRegion(t,e,"NE"):this._placeInRegion(t,e,"SE")},_placeInRegion:function(t,e,i){switch(t.children[i].childrenCount){case 0:t.children[i].children.data=e,t.children[i].childrenCount=1,this._updateBranchMass(t.children[i],e);break;case 1:this._splitBranch(t.children[i]),this._placeInTree(t.children[i],e);break;case 4:this._placeInTree(t.children[i],e)}},_splitBranch:function(t){var e=null;1==t.childrenCount&&(e=t.children.data,t.mass=0,t.CenterOfMass.x=0,t.CenterOfMass.y=0),t.childrenCount=4,t.children.data=null,this._insertRegion(t,"NW"),this._insertRegion(t,"NE"),this._insertRegion(t,"SW"),this._insertRegion(t,"SE"),null!=e&&this._placeInTree(t,e)},_insertRegion:function(t,e){var i,n,s,o;switch(e){case"NW":i=t.range.minX,n=t.range.minX+t.size,s=t.range.minY,o=t.range.minY+t.size;break;case"NE":i=t.range.minX+t.size,n=t.range.maxX,s=t.range.minY,o=t.range.minY+t.size;break;case"SW":i=t.range.minX,n=t.range.minX+t.size,s=t.range.minY+t.size,o=t.range.maxY;break;case"SE":i=t.range.minX+t.size,n=t.range.maxX,s=t.range.minY+t.size,o=t.range.maxY}t.children[e]={CenterOfMass:{x:0,y:0},mass:0,range:{minX:i,maxX:n,minY:s,maxY:o},size:.5*t.size,children:{data:null},childrenCount:0}},_drawTree:function(t,e){void 0!==this.barnesHutTree&&(t.lineWidth=2,this._drawBranch(this.barnesHutTree.root,t,e))},_drawBranch:function(t,e,i){void 0===i&&(i="#FF0000"),4==t.childrenCount&&(this._drawBranch(t.children.NW,e),this._drawBranch(t.children.NE,e),this._drawBranch(t.children.SE,e),this._drawBranch(t.children.SW,e)),e.strokeStyle=i,e.beginPath(),e.moveTo(t.range.minX,t.range.minY),e.lineTo(t.range.maxX,t.range.minY),e.stroke(),e.beginPath(),e.moveTo(t.range.maxX,t.range.minY),e.lineTo(t.range.maxX,t.range.maxY),e.stroke(),e.beginPath(),e.moveTo(t.range.maxX,t.range.maxY),e.lineTo(t.range.minX,t.range.maxY),e.stroke(),e.beginPath(),e.moveTo(t.range.minX,t.range.maxY),e.lineTo(t.range.minX,t.range.minY),e.stroke()}},manipulationMixin={_clearManipulatorBar:function(){for(;this.manipulationDiv.hasChildNodes();)this.manipulationDiv.removeChild(this.manipulationDiv.firstChild)},_createManipulatorBar:function(){for(this.off("select",this.boundFunction),this.blockConnectingEdgeSelection=!1,this.forceAppendSelection=!1;this.manipulationDiv.hasChildNodes();)this.manipulationDiv.removeChild(this.manipulationDiv.firstChild);this.manipulationDiv.innerHTML="Add Node
    Edit Selected
    Connect Node
    Delete selected";var t=document.getElementById("manipulate-addNode");t.onclick=this._createAddToolbar.bind(this);var e=document.getElementById("manipulate-editNode");e.onclick=this._createEditToolbar.bind(this);var i=document.getElementById("manipulate-connectNode");i.onclick=this._createConnectToolbar.bind(this); -var n=document.getElementById("manipulate-delete");n.onclick=this._createDeletionToolbar.bind(this)},_createAddToolbar:function(){this._clearManipulatorBar(),this.off("select",this.boundFunction),this.manipulationDiv.innerHTML="Back
    Click in an empty space to place a new node";var t=document.getElementById("manipulate-back");t.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._addNode.bind(this),this.on("select",this.boundFunction)},_createEditToolbar:function(){this.blockConnectingEdgeSelection=!1,this._clearManipulatorBar(),this.off("select",this.boundFunction);var t="";if(this._selectionIsEmpty()?t="Select a node or edge to edit.":this._getSelectedObjectCount()>1?(t="Select a single node or edge to edit.",this._unselectAll(!0)):this._clusterInSelection()?(t="You cannot edit a cluster.",this._unselectAll(!0)):this._getSelectedNodeCount()>0?this._createEditNodeToolbar():this._createEditEdgeToolbar(),""!=t){this.blockConnectingEdgeSelection=!0,this.manipulationDiv.innerHTML="Back
    "+t+"";var e=document.getElementById("manipulate-back");e.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._createEditToolbar.bind(this),this.on("select",this.boundFunction)}},_createEditNodeToolbar:function(){this.blockConnectingEdgeSelection=!1,this._clearManipulatorBar(),this.off("select",this.boundFunction);var t=this._getEditObject();this.manipulationDiv.innerHTML="Cancel
    label:
    color:
    ";var e=document.getElementById("manipulate-back");e.onclick=this._createManipulatorBar.bind(this);var i=document.getElementById("manipulator-obj-save");i.onclick=this._saveNodeData.bind(this),this.boundFunction=this._createManipulatorBar.bind(this),this.on("select",this.boundFunction)},_saveNodeData:function(){var t=this._getEditObject().id,e=document.getElementById("manipulator-obj-label").value,i=document.getElementById("manipulator-obj-color").value,n=util.hexToHSV(i),s={h:n.h,s:.45*n.s,v:Math.min(1,1.05*n.v)},o={h:n.h,s:Math.min(1,1.25*n.v),v:.6*n.v},r=util.HSVToHex(o.h,o.h,o.v),a=util.HSVToHex(s.h,s.s,s.v),h={id:t,label:e,color:{background:i,border:r,highlight:{background:a,border:r}}};this.nodesData.update(h),this._createManipulatorBar()},_createEditEdgeToolbar:function(){this.blockConnectingEdgeSelection=!1,this._clearManipulatorBar(),this.off("select",this.boundFunction),this.manipulationDiv.innerHTML="Back
    Currently only nodes can be edited.";var t=document.getElementById("manipulate-back");t.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._createManipulatorBar.bind(this),this.on("select",this.boundFunction)},_createConnectToolbar:function(){this._clearManipulatorBar(),this.off("select",this.boundFunction),this._unselectAll(),this.forceAppendSelection=!1,this.blockConnectingEdgeSelection=!0,this.manipulationDiv.innerHTML="Back
    Select the node you want to connect to other nodes.";var t=document.getElementById("manipulate-back");t.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._handleConnect.bind(this),this.on("select",this.boundFunction)},_createDeletionToolbar:function(){if(this._clearManipulatorBar(),this.off("select",this.boundFunction),this._selectionIsEmpty()){this.manipulationDiv.innerHTML="Cannot delete an empty selection.";var t=this;window.setTimeout(function(){t._createManipulatorBar()},1500)}else{this.manipulationDiv.innerHTML="Back
    Are you sure? This cannot be undone.
    Yes.";var e=document.getElementById("manipulate-back");e.onclick=this._createManipulatorBar.bind(this);var i=document.getElementById("manipulate-acceptDelete");i.onclick=this._deleteSelected.bind(this),this.boundFunction=this._createManipulatorBar.bind(this),this.on("select",this.boundFunction)}},_handleConnect:function(){this.forceAppendSelection=!1,this._clusterInSelection()?(this._unselectClusters(!0),this._selectionIsEmpty()?this._setManipulationMessage("You cannot connect anything to a cluster."):(this._setManipulationMessage("You cannot connect a node to a cluster."),this.forceAppendSelection=!0)):this._selectionIsEmpty()?this._setManipulationMessage("Select the node you want to connect to other nodes."):2==this._getSelectedNodeCount()?(this._connectNodes(),this._restoreSourceNode(),this._setManipulationMessage("Click on another node you want to connect this node to or go back.")):(this._setManipulationMessage("Click on the node you want to connect this node."),this._setSourceNode(),this.forceAppendSelection=!0)},_getEditObject:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t))return this.selectionObj[t];return null},_setSourceNode:function(){for(var t in this.selectionObj)this.selectionObj.hasOwnProperty(t)&&this.selectionObj[t]instanceof Node&&(this.manipulationSourceNode=this.selectionObj[t])},_getTargetNode:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t)&&this.selectionObj[t]instanceof Node&&this.manipulationSourceNode.id!=this.selectionObj[t].id)return this.selectionObj[t];return null},_restoreSourceNode:function(){this._unselectAll(!0),this._selectObject(this.manipulationSourceNode)},_setManipulationMessage:function(t){var e=document.getElementById("manipulatorLabel");e.innerHTML=t},_addNode:function(){if(this._selectionIsEmpty()){var t=this._pointerToPositionObject(this.pointerPosition);this.createNodeOnClick=!0,this.nodesData.add({id:util.randomUUID(),x:t.left,y:t.top,label:"new",fixed:!1}),this.createNodeOnClick=!1,this.moving=!0,this.start()}},_connectNodes:function(){var t=this._getTargetNode(),e=this.manipulationSourceNode;this.edgesData.add({from:e.id,to:t.id}),this.moving=!0,this.start()},_deleteSelected:function(){if(this._clusterInSelection())alert("Clusters cannot be deleted.");else{var t=this.getSelectedNodes(),e=this.getSelectedEdges();this._removeEdges(e),this._removeNodes(t),this.moving=!0,this.start()}}},SectorMixin={_putDataInSector:function(){this.sectors.active[this._sector()].nodes=this.nodes,this.sectors.active[this._sector()].edges=this.edges,this.sectors.active[this._sector()].nodeIndices=this.nodeIndices},_switchToSector:function(t,e){void 0===e||"active"==e?this._switchToActiveSector(t):this._switchToFrozenSector(t)},_switchToActiveSector:function(t){this.nodeIndices=this.sectors.active[t].nodeIndices,this.nodes=this.sectors.active[t].nodes,this.edges=this.sectors.active[t].edges},_switchToFrozenSector:function(t){this.nodeIndices=this.sectors.frozen[t].nodeIndices,this.nodes=this.sectors.frozen[t].nodes,this.edges=this.sectors.frozen[t].edges},_switchToNavigationSector:function(){this.nodeIndices=this.sectors.navigation.nodeIndices,this.nodes=this.sectors.navigation.nodes,this.edges=this.sectors.navigation.edges},_loadLatestSector:function(){this._switchToSector(this._sector())},_sector:function(){return this.activeSector[this.activeSector.length-1]},_previousSector:function(){if(this.activeSector.length>1)return this.activeSector[this.activeSector.length-2];throw new TypeError("there are not enough sectors in the this.activeSector array.")},_setActiveSector:function(t){this.activeSector.push(t)},_forgetLastSector:function(){this.activeSector.pop()},_createNewSector:function(t){this.sectors.active[t]={nodes:{},edges:{},nodeIndices:[],formationScale:this.scale,drawingNode:void 0},this.sectors.active[t].drawingNode=new Node({id:t,color:{background:"#eaefef",border:"495c5e"}},{},{},this.constants),this.sectors.active[t].drawingNode.clusterSize=2},_deleteActiveSector:function(t){delete this.sectors.active[t]},_deleteFrozenSector:function(t){delete this.sectors.frozen[t]},_freezeSector:function(t){this.sectors.frozen[t]=this.sectors.active[t],this._deleteActiveSector(t)},_activateSector:function(t){this.sectors.active[t]=this.sectors.frozen[t],this._deleteFrozenSector(t)},_mergeThisWithFrozen:function(t){for(var e in this.nodes)this.nodes.hasOwnProperty(e)&&(this.sectors.frozen[t].nodes[e]=this.nodes[e]);for(var i in this.edges)this.edges.hasOwnProperty(i)&&(this.sectors.frozen[t].edges[i]=this.edges[i]);for(var n=0;n1?this[t](n[0],n[1]):this[t](e)}this._loadLatestSector()},_doInAllFrozenSectors:function(t,e){if(void 0===e)for(var i in this.sectors.frozen)this.sectors.frozen.hasOwnProperty(i)&&(this._switchToFrozenSector(i),this[t]());else for(var i in this.sectors.frozen)if(this.sectors.frozen.hasOwnProperty(i)){this._switchToFrozenSector(i);var n=Array.prototype.splice.call(arguments,1);n.length>1?this[t](n[0],n[1]):this[t](e)}this._loadLatestSector()},_doInNavigationSector:function(t,e){if(this._switchToNavigationSector(),void 0===e)this[t]();else{var i=Array.prototype.splice.call(arguments,1);i.length>1?this[t](i[0],i[1]):this[t](e)}this._loadLatestSector()},_doInAllSectors:function(t,e){var i=Array.prototype.splice.call(arguments,1);void 0===e?(this._doInAllActiveSectors(t),this._doInAllFrozenSectors(t)):i.length>1?(this._doInAllActiveSectors(t,i[0],i[1]),this._doInAllFrozenSectors(t,i[0],i[1])):(this._doInAllActiveSectors(t,e),this._doInAllFrozenSectors(t,e))},_clearNodeIndexList:function(){var t=this._sector();this.sectors.active[t].nodeIndices=[],this.nodeIndices=this.sectors.active[t].nodeIndices},_drawSectorNodes:function(t,e){var i,n=1e9,s=-1e9,o=1e9,r=-1e9;for(var a in this.sectors[e])if(this.sectors[e].hasOwnProperty(a)&&void 0!==this.sectors[e][a].drawingNode){this._switchToSector(a,e),n=1e9,s=-1e9,o=1e9,r=-1e9;for(var h in this.nodes)this.nodes.hasOwnProperty(h)&&(i=this.nodes[h],i.resize(t),o>i.x-.5*i.width&&(o=i.x-.5*i.width),ri.y-.5*i.height&&(n=i.y-.5*i.height),st&&n>s;)s%3==0?this.forceAggregateHubs():this.increaseClusterLevel(),i=this.nodeIndices.length,s+=1;s>1&&1==e&&this.repositionNodes()},openCluster:function(t){var e=this.moving;if(t.clusterSize>this.constants.clustering.sectorThreshold&&this._nodeInActiveArea(t)&&("default"!=this._sector()||1!=this.nodeIndices.length)){this._addSector(t);for(var i=0;this.nodeIndices.lengthi;)this.decreaseClusterLevel(),i+=1}else this._expandClusterNode(t,!1,!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels();this.moving!=e&&this.start()},updateClustersDefault:function(){1==this.constants.clustering.enabled&&this.updateClusters(0,!1,!1)},increaseClusterLevel:function(){this.updateClusters(-1,!1,!0)},decreaseClusterLevel:function(){this.updateClusters(1,!1,!0)},updateClusters:function(t,e,i){var n=this.moving,s=this.nodeIndices.length;this.previousScale>this.scale&&0==t&&this._collapseSector(),this.previousScale>this.scale||-1==t?this._formClusters(i):(this.previousScalethis.scale||-1==t)&&(this._aggregateHubs(i),this._updateNodeIndexList()),(this.previousScale>this.scale||-1==t)&&(this.handleChains(),this._updateNodeIndexList()),this.previousScale=this.scale,this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.lengththis.constants.clustering.chainThreshold&&this._reduceAmountOfChains(1-this.constants.clustering.chainThreshold/t)},_aggregateHubs:function(t){this._getHubSize(),this._formClustersByHub(t,!1)},forceAggregateHubs:function(){var t=this.moving,e=this.nodeIndices.length;this._aggregateHubs(!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.length!=e&&(this.clusterSession+=1),this.moving!=t&&this.start()},_openClustersBySize:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];1==e.inView()&&(e.width*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientWidth||e.height*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientHeight)&&this.openCluster(e)}},_openClusters:function(t,e){for(var i=0;i1&&(t.clusterSizei)){var r=o.from,a=o.to;o.to.mass>o.from.mass&&(r=o.to,a=o.from),1==a.dynamicEdgesLength?this._addToCluster(r,a,!1):1==r.dynamicEdgesLength&&this._addToCluster(a,r,!1)}}},_forceClustersByZoom:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];if(1==e.dynamicEdgesLength&&0!=e.dynamicEdges.length){var i=e.dynamicEdges[0],n=i.toId==e.id?this.nodes[i.fromId]:this.nodes[i.toId];e.id!=n.id&&(n.mass>e.mass?this._addToCluster(n,e,!0):this._addToCluster(e,n,!0))}}},_formClustersByHub:function(t,e){for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&this._formClusterFromHub(this.nodes[i],t,e)},_formClusterFromHub:function(t,e,i,n){if(void 0===n&&(n=0),t.dynamicEdgesLength>=this.hubThreshold&&0==i||t.dynamicEdgesLength==this.hubThreshold&&1==i){for(var s,o,r,a=this.constants.clustering.clusterEdgeThreshold/this.scale,h=!1,l=[],c=t.dynamicEdges.length,d=0;c>d;d++)l.push(t.dynamicEdges[d].id);if(0==e)for(h=!1,d=0;c>d;d++){var u=this.edges[l[d]];if(void 0!==u&&u.connected&&u.toId!=u.fromId&&(s=u.to.x-u.from.x,o=u.to.y-u.from.y,r=Math.sqrt(s*s+o*o),a>r)){h=!0;break}}if(!e&&h||e)for(d=0;c>d;d++)if(u=this.edges[l[d]],void 0!==u){var p=this.nodes[u.fromId==t.id?u.toId:u.fromId];p.dynamicEdges.length<=this.hubThreshold+n&&p.id!=t.id&&this._addToCluster(t,p,e)}}},_addToCluster:function(t,e,i){t.containedNodes[e.id]=e;for(var n=0;n1)for(var n=0;n1&&(e.label="[".concat(String(e.clusterSize),"]"))}for(t in this.nodes)this.nodes.hasOwnProperty(t)&&(e=this.nodes[t],1==e.clusterSize&&(e.label=void 0!==e.originalLabel?e.originalLabel:String(e.id)))},_nodeInActiveArea:function(t){return Math.abs(t.x-this.areaCenter.x)<=this.constants.clustering.activeAreaBoxSize/this.scale&&Math.abs(t.y-this.areaCenter.y)<=this.constants.clustering.activeAreaBoxSize/this.scale},repositionNodes:function(){for(var t=0;tn&&(n=o.dynamicEdgesLength),t+=o.dynamicEdgesLength,e+=Math.pow(o.dynamicEdgesLength,2),i+=1}t/=i,e/=i;var r=e-Math.pow(t,2),a=Math.sqrt(r);this.hubThreshold=Math.floor(t+2*a),this.hubThreshold>n&&(this.hubThreshold=n)},_reduceAmountOfChains:function(t){this.hubThreshold=2;var e=Math.floor(this.nodeIndices.length*t);for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&e>0&&(this._formClusterFromHub(this.nodes[i],!0,!0,1),e-=1)},_getChainFraction:function(){var t=0,e=0;for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&(2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&(t+=1),e+=1);return t/e}},SelectionMixin={_getNodesOverlappingWith:function(t,e){var i=this.nodes;for(var n in i)i.hasOwnProperty(n)&&i[n].isOverlappingWith(t)&&e.push(n)},_getAllNodesOverlappingWith:function(t){var e=[];return this._doInAllActiveSectors("_getNodesOverlappingWith",t,e),e},_getAllNavigationNodesOverlappingWith:function(t){var e=[];return this._doInNavigationSector("_getNodesOverlappingWith",t,e),e},_pointerToPositionObject:function(t){var e=this._canvasToX(t.x),i=this._canvasToY(t.y);return{left:e,top:i,right:e,bottom:i}},_pointerToScreenPositionObject:function(t){var e=t.x,i=t.y;return{left:e,top:i,right:e,bottom:i}},_getNavigationNodeAt:function(t){var e=this._pointerToScreenPositionObject(t),i=this._getAllNavigationNodesOverlappingWith(e);return i.length>0?this.sectors.navigation.nodes[i[i.length-1]]:null},_getNodeAt:function(t){var e=this._pointerToPositionObject(t),i=this._getAllNodesOverlappingWith(e);return i.length>0?this.nodes[i[i.length-1]]:null},_getEdgesOverlappingWith:function(t,e){var i=this.edges;for(var n in i)i.hasOwnProperty(n)&&i[n].isOverlappingWith(t)&&e.push(n)},_getAllEdgesOverlappingWith:function(t){var e=[];return this._doInAllActiveSectors("_getEdgesOverlappingWith",t,e),e},_getEdgeAt:function(t){var e=this._pointerToPositionObject(t),i=this._getAllEdgesOverlappingWith(e);return i.length>0?this.edges[i[i.length-1]]:null},_addToSelection:function(t){this.selectionObj[t.id]=t},_removeFromSelection:function(t){delete this.selectionObj[t.id]},_unselectAll:function(t){void 0===t&&(t=!1);for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e].unselect();this.selectionObj={},0==t&&this._trigger("select",this.getSelection())},_unselectClusters:function(t){void 0===t&&(t=!1);for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e]instanceof Node&&this.selectionObj[e].clusterSize>1&&(this.selectionObj[e].unselect(),this._removeFromSelection(this.selectionObj[e]));0==t&&this._trigger("select",this.getSelection())},_getSelectedNodeCount:function(){var t=0;for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e]instanceof Node&&(t+=1);return t},_getSelectedEdgeCount:function(){var t=0;for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e]instanceof Edge&&(t+=1);return t},_getSelectedObjectCount:function(){var t=0;for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&(t+=1);return t},_selectionIsEmpty:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t))return!1;return!0},_clusterInSelection:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t)&&this.selectionObj[t]instanceof Node&&this.selectionObj[t].clusterSize>1)return!0;return!1},_selectConnectedEdges:function(t){for(var e=0;ee;e++){n=t[e];var s=this.nodes[n];if(!s)throw new RangeError('Node with id "'+n+'" not found');this._selectObject(s,!0,!0)}this.redraw()},_updateSelection:function(){for(var t in this.selectionObj)this.selectionObj.hasOwnProperty(t)&&(this.selectionObj[t]instanceof Node?this.nodes.hasOwnProperty(t)||delete this.selectionObj[t]:this.edges.hasOwnProperty(t)||delete this.selectionObj[t])}},NavigationMixin={_relocateNavigation:function(){if(void 0!==this.sectors){var t=this.navigationClientWidth-this.frame.canvas.clientWidth,e=this.navigationClientHeight-this.frame.canvas.clientHeight;this.navigationClientWidth=this.frame.canvas.clientWidth,this.navigationClientHeight=this.frame.canvas.clientHeight;var i=null;for(var n in this.sectors.navigation.nodes)this.sectors.navigation.nodes.hasOwnProperty(n)&&(i=this.sectors.navigation.nodes[n],i.horizontalAlignLeft||(i.x-=t),i.verticalAlignTop||(i.y-=e))}},_loadNavigationElements:function(){var t=this.constants.navigation.iconPath;this.navigationClientWidth=this.frame.canvas.clientWidth,this.navigationClientHeight=this.frame.canvas.clientHeight,void 0===this.navigationClientWidth&&(this.navigationClientWidth=0,this.navigationClientHeight=0);for(var e=15,i=7,n=[{id:"navigation_up",shape:"image",image:t+"/uparrow.png",triggerFunction:"_moveUp",verticalAlignTop:!1,x:45+e+i,y:this.navigationClientHeight-45-e-i},{id:"navigation_down",shape:"image",image:t+"/downarrow.png",triggerFunction:"_moveDown",verticalAlignTop:!1,x:45+e+i,y:this.navigationClientHeight-15-e},{id:"navigation_left",shape:"image",image:t+"/leftarrow.png",triggerFunction:"_moveLeft",verticalAlignTop:!1,x:15+e,y:this.navigationClientHeight-15-e},{id:"navigation_right",shape:"image",image:t+"/rightarrow.png",triggerFunction:"_moveRight",verticalAlignTop:!1,x:75+e+2*i,y:this.navigationClientHeight-15-e},{id:"navigation_plus",shape:"image",image:t+"/plus.png",triggerFunction:"_zoomIn",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-45-e-i,y:this.navigationClientHeight-15-e},{id:"navigation_min",shape:"image",image:t+"/minus.png",triggerFunction:"_zoomOut",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-15-e,y:this.navigationClientHeight-15-e},{id:"navigation_zoomExtends",shape:"image",image:t+"/zoomExtends.png",triggerFunction:"zoomToFit",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-15-e,y:this.navigationClientHeight-45-e-i}],s=null,o=0;ot.x-t.width&&(n=t.x-t.width),st.y-t.height&&(e=t.y-t.height),i=this.constants.clustering.initialMaxNodes)var n=38.8467/(e-14.50184)+.0116;else var n=42.54117319/(e+39.31966387)+.1944405;else{var s=1.1*(Math.abs(i.minX)+Math.abs(i.maxX)),o=1.1*(Math.abs(i.minY)+Math.abs(i.maxY)),r=this.frame.canvas.clientWidth/s,a=this.frame.canvas.clientHeight/o;n=a>=r?r:a}n>1&&(n=1),this.pinch.mousewheelScale=n,this._setScale(n),this._centerGraph(i),this.start()},Graph.prototype._updateNodeIndexList=function(){this._clearNodeIndexList();for(var t in this.nodes)this.nodes.hasOwnProperty(t)&&this.nodeIndices.push(t)},Graph.prototype.setData=function(t,e){if(void 0===e&&(e=!1),t&&t.dot&&(t.nodes||t.edges))throw new SyntaxError('Data must contain either parameter "dot" or parameter pair "nodes" and "edges", but not both.');if(this.setOptions(t&&t.options),t&&t.dot){if(t&&t.dot){var i=vis.util.DOTToGraph(t.dot);return void this.setData(i)}}else this._setNodes(t&&t.nodes),this._setEdges(t&&t.edges);this._putDataInSector(),e||(this.stabilize&&this._doStabilize(),this.moving=!0,this.start())},Graph.prototype.setOptions=function(t){if(t){if(void 0!==t.width&&(this.width=t.width),void 0!==t.height&&(this.height=t.height),void 0!==t.stabilize&&(this.stabilize=t.stabilize),void 0!==t.selectable&&(this.selectable=t.selectable),t.clustering){this.constants.clustering.enabled=!0;for(var e in t.clustering)t.clustering.hasOwnProperty(e)&&(this.constants.clustering[e]=t.clustering[e])}else void 0!==t.clustering&&(this.constants.clustering.enabled=!1);if(t.navigation){this.constants.navigation.enabled=!0;for(var e in t.navigation)t.navigation.hasOwnProperty(e)&&(this.constants.navigation[e]=t.navigation[e])}else void 0!==t.navigation&&(this.constants.navigation.enabled=!1);if(t.keyboard){this.constants.keyboard.enabled=!0;for(var e in t.keyboard)t.keyboard.hasOwnProperty(e)&&(this.constants.keyboard[e]=t.keyboard[e])}else void 0!==t.keyboard&&(this.constants.keyboard.enabled=!1);if(t.dataManipulationToolbar){this.constants.dataManipulationToolbar.enabled=!0;for(var e in t.dataManipulationToolbar)t.dataManipulationToolbar.hasOwnProperty(e)&&(this.constants.dataManipulationToolbar[e]=t.dataManipulationToolbar[e])}else void 0!==t.dataManipulationToolbar&&(this.constants.dataManipulationToolbar.enabled=!1);if(t.edges){for(e in t.edges)t.edges.hasOwnProperty(e)&&(this.constants.edges[e]=t.edges[e]);void 0!==t.edges.length&&t.nodes&&void 0===t.nodes.distance&&(this.constants.edges.length=t.edges.length,this.constants.nodes.distance=1.25*t.edges.length),t.edges.fontColor||(this.constants.edges.fontColor=t.edges.color),t.edges.dash&&(void 0!==t.edges.dash.length&&(this.constants.edges.dash.length=t.edges.dash.length),void 0!==t.edges.dash.gap&&(this.constants.edges.dash.gap=t.edges.dash.gap),void 0!==t.edges.dash.altLength&&(this.constants.edges.dash.altLength=t.edges.dash.altLength))}if(t.nodes){for(e in t.nodes)t.nodes.hasOwnProperty(e)&&(this.constants.nodes[e]=t.nodes[e]);t.nodes.color&&(this.constants.nodes.color=Node.parseColor(t.nodes.color))}if(t.groups)for(var i in t.groups)if(t.groups.hasOwnProperty(i)){var n=t.groups[i];this.groups.add(i,n)}}this._loadNavigationControls(),this._loadManipulationSystem(),this._createKeyBinds(),this.setSize(this.width,this.height),this._setTranslation(this.frame.clientWidth/2,this.frame.clientHeight/2),this._setScale(1),this._redraw()},Graph.prototype.on=function(t,e){var i=["select"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());events.addListener(this,t,e)},Graph.prototype.off=function(t,e){events.removeListener(this,t,e)},Graph.prototype._trigger=function(t,e){events.trigger(this,t,e)},Graph.prototype._create=function(){for(;this.containerElement.hasChildNodes();)this.containerElement.removeChild(this.containerElement.firstChild);if(this.frame=document.createElement("div"),this.frame.className="graph-frame",this.frame.style.position="relative",this.frame.style.overflow="hidden",this.frame.style.zIndex="1",this.frame.canvas=document.createElement("canvas"),this.frame.canvas.style.position="relative",this.frame.appendChild(this.frame.canvas),!this.frame.canvas.getContext){var t=document.createElement("DIV");t.style.color="red",t.style.fontWeight="bold",t.style.padding="10px",t.innerHTML="Error: your browser does not support HTML canvas",this.frame.canvas.appendChild(t)}var e=this;this.drag={},this.pinch={},this.hammer=Hammer(this.frame.canvas,{prevent_default:!0}),this.hammer.on("tap",e._onTap.bind(e)),this.hammer.on("doubletap",e._onDoubleTap.bind(e)),this.hammer.on("hold",e._onHold.bind(e)),this.hammer.on("pinch",e._onPinch.bind(e)),this.hammer.on("touch",e._onTouch.bind(e)),this.hammer.on("dragstart",e._onDragStart.bind(e)),this.hammer.on("drag",e._onDrag.bind(e)),this.hammer.on("dragend",e._onDragEnd.bind(e)),this.hammer.on("release",e._onRelease.bind(e)),this.hammer.on("mousewheel",e._onMouseWheel.bind(e)),this.hammer.on("DOMMouseScroll",e._onMouseWheel.bind(e)),this.hammer.on("mousemove",e._onMouseMoveTitle.bind(e)),this.containerElement.appendChild(this.frame)},Graph.prototype._createKeyBinds=function(){var t=this;this.mousetrap=mousetrap,this.mousetrap.reset(),1==this.constants.keyboard.enabled&&(this.mousetrap.bind("up",this._moveUp.bind(t),"keydown"),this.mousetrap.bind("up",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("down",this._moveDown.bind(t),"keydown"),this.mousetrap.bind("down",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("left",this._moveLeft.bind(t),"keydown"),this.mousetrap.bind("left",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("right",this._moveRight.bind(t),"keydown"),this.mousetrap.bind("right",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("=",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("=",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("-",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("-",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("[",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("[",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("]",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("]",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pageup",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("pageup",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pagedown",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("pagedown",this._stopZoom.bind(t),"keyup")),this.mousetrap.bind("b",this._formBarnesHutTree.bind(t)),1==this.constants.dataManipulationToolbar.enabled&&this.mousetrap.bind("escape",this._createManipulatorBar.bind(t))},Graph.prototype._getPointer=function(t){return{x:t.pageX-vis.util.getAbsoluteLeft(this.frame.canvas),y:t.pageY-vis.util.getAbsoluteTop(this.frame.canvas)}},Graph.prototype._onTouch=function(t){this.drag.pointer=this._getPointer(t.gesture.touches[0]),this.drag.pinched=!1,this.pinch.scale=this._getScale(),this._handleTouch(this.drag.pointer)},Graph.prototype._onDragStart=function(){var t=this.drag,e=this._getNodeAt(t.pointer);if(t.dragging=!0,t.selection=[],t.translation=this._getTranslation(),t.nodeId=null,null!=e){t.nodeId=e.id,e.isSelected()||this._selectObject(e,!1);for(var i in this.selectionObj)if(this.selectionObj.hasOwnProperty(i)){var n=this.selectionObj[i];if(n instanceof Node){var s={id:n.id,node:n,x:n.x,y:n.y,xFixed:n.xFixed,yFixed:n.yFixed};n.xFixed=!0,n.yFixed=!0,t.selection.push(s)}}}},Graph.prototype._onDrag=function(t){if(!this.drag.pinched){var e=this._getPointer(t.gesture.touches[0]),i=this,n=this.drag,s=n.selection;if(s&&s.length){var o=e.x-n.pointer.x,r=e.y-n.pointer.y;s.forEach(function(t){var e=t.node;t.xFixed||(e.x=i._canvasToX(i._xToCanvas(t.x)+o)),t.yFixed||(e.y=i._canvasToY(i._yToCanvas(t.y)+r))}),this.moving||(this.moving=!0,this.start())}else{var a=e.x-this.drag.pointer.x,h=e.y-this.drag.pointer.y;this._setTranslation(this.drag.translation.x+a,this.drag.translation.y+h),this._redraw(),this.moved=!0}}},Graph.prototype._onDragEnd=function(){this.drag.dragging=!1;var t=this.drag.selection;t&&t.forEach(function(t){t.node.xFixed=t.xFixed,t.node.yFixed=t.yFixed})},Graph.prototype._onTap=function(t){var e=this._getPointer(t.gesture.touches[0]);this.pointerPosition=e,this._handleTap(e)},Graph.prototype._onDoubleTap=function(t){var e=this._getPointer(t.gesture.touches[0]);this._handleDoubleTap(e)},Graph.prototype._onHold=function(t){var e=this._getPointer(t.gesture.touches[0]);this.pointerPosition=e,this._handleOnHold(e)},Graph.prototype._onRelease=function(){this._handleOnRelease()},Graph.prototype._onPinch=function(t){var e=this._getPointer(t.gesture.center);this.drag.pinched=!0,"scale"in this.pinch||(this.pinch.scale=1);var i=this.pinch.scale*t.gesture.scale;this._zoom(i,e)},Graph.prototype._zoom=function(t,e){var i=this._getScale();1e-5>t&&(t=1e-5),t>10&&(t=10);var n=this._getTranslation(),s=t/i,o=(1-s)*e.x+n.x*s,r=(1-s)*e.y+n.y*s;return this.areaCenter={x:this._canvasToX(e.x),y:this._canvasToY(e.y)},this.pinch.mousewheelScale=t,this._setScale(t),this._setTranslation(o,r),this.updateClustersDefault(),this._redraw(),t},Graph.prototype._onMouseWheel=function(t){var e=0;if(t.wheelDelta?e=t.wheelDelta/120:t.detail&&(e=-t.detail/3),e){"mousewheelScale"in this.pinch||(this.pinch.mousewheelScale=1);var i=this.pinch.mousewheelScale,n=e/10;0>e&&(n/=1-n),i*=1+n;var s=util.fakeGesture(this,t),o=this._getPointer(s.center);i=this._zoom(i,o)}t.preventDefault()},Graph.prototype._onMouseMoveTitle=function(t){var e=util.fakeGesture(this,t),i=this._getPointer(e.center);this.popupNode&&this._checkHidePopup(i);var n=this,s=function(){n._checkShowPopup(i)};this.popupTimer&&clearInterval(this.popupTimer),this.drag.dragging||(this.popupTimer=setTimeout(s,300))},Graph.prototype._checkShowPopup=function(t){var e,i={left:this._canvasToX(t.x),top:this._canvasToY(t.y),right:this._canvasToX(t.x),bottom:this._canvasToY(t.y)},n=this.popupNode;if(void 0==this.popupNode){var s=this.nodes;for(e in s)if(s.hasOwnProperty(e)){var o=s[e];if(void 0!==o.getTitle()&&o.isOverlappingWith(i)){this.popupNode=o;break}}}if(void 0===this.popupNode){var r=this.edges;for(e in r)if(r.hasOwnProperty(e)){var a=r[e];if(a.connected&&void 0!==a.getTitle()&&a.isOverlappingWith(i)){this.popupNode=a;break}}}if(this.popupNode){if(this.popupNode!=n){var h=this;h.popup||(h.popup=new Popup(h.frame)),h.popup.setPosition(t.x-3,t.y-3),h.popup.setText(h.popupNode.getTitle()),h.popup.show()}}else this.popup&&this.popup.hide()},Graph.prototype._checkHidePopup=function(t){this.popupNode&&this._getNodeAt(t)||(this.popupNode=void 0,this.popup&&this.popup.hide())},Graph.prototype._getConnectionCount=function(t){function e(t){for(var e=[],i=0,n=t.length;n>i;i++)for(var s=t[i],o=s.edges,r=0,a=o.length;a>r;r++){var h=o[r],l=null;h.from==s?l=h.to:h.to==s&&(l=h.from);var c,d;if(l)for(c=0,d=t.length;d>c;c++)if(t[c]==l){l=null;break}if(l)for(c=0,d=e.length;d>c;c++)if(e[c]==l){l=null;break}l&&e.push(l)}return e}void 0==t&&(t=1);var i=[],n=this.nodes;for(var s in n)if(n.hasOwnProperty(s)){for(var o=[n[s]],r=0;t>r;r++)o=o.concat(e(o));i.push(o)}for(var a=[],h=0,l=i.length;l>h;h++)a.push(i[h].length);return a},Graph.prototype.setSize=function(t,e){this.frame.style.width=t,this.frame.style.height=e,this.frame.canvas.style.width="100%",this.frame.canvas.style.height="100%",this.frame.canvas.width=this.frame.canvas.clientWidth,this.frame.canvas.height=this.frame.canvas.clientHeight,void 0!==this.manipulationDiv&&(this.manipulationDiv.style.width=this.frame.canvas.clientWidth),1==this.constants.navigation.enabled&&this._relocateNavigation()},Graph.prototype._setNodes=function(t){var e=this.nodesData;if(t instanceof DataSet||t instanceof DataView)this.nodesData=t;else if(t instanceof Array)this.nodesData=new DataSet,this.nodesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.nodesData=new DataSet}if(e&&util.forEach(this.nodesListeners,function(t,i){e.unsubscribe(i,t)}),this.nodes={},this.nodesData){var i=this;util.forEach(this.nodesListeners,function(t,e){i.nodesData.subscribe(e,t)});var n=this.nodesData.getIds();this._addNodes(n)}this._updateSelection()},Graph.prototype._addNodes=function(t){for(var e,i=0,n=t.length;n>i;i++){e=t[i];var s=this.nodesData.get(e),o=new Node(s,this.images,this.groups,this.constants);if(this.nodes[e]=o,!o.isFixed()&&1!=this.createNodeOnClick){var r=this.constants.edges.length,a=t.length,h=2*Math.PI*(i/a);o.x=r*Math.cos(h),o.y=r*Math.sin(h),this.moving=!0}}this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(this.nodes),this.updateLabels()},Graph.prototype._updateNodes=function(t){for(var e=this.nodes,i=this.nodesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o],a=i.get(o);r?r.setProperties(a,this.constants):(r=new Node(properties,this.images,this.groups,this.constants),e[o]=r,r.isFixed()||(this.moving=!0))}this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(e)},Graph.prototype._removeNodes=function(t){for(var e=this.nodes,i=0,n=t.length;n>i;i++){var s=t[i];delete e[s]}this._updateNodeIndexList(),this._reconnectEdges(),this._updateSelection(),this._updateValueRange(e)},Graph.prototype._setEdges=function(t){var e=this.edgesData;if(t instanceof DataSet||t instanceof DataView)this.edgesData=t;else if(t instanceof Array)this.edgesData=new DataSet,this.edgesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.edgesData=new DataSet}if(e&&util.forEach(this.edgesListeners,function(t,i){e.unsubscribe(i,t)}),this.edges={},this.edgesData){var i=this;util.forEach(this.edgesListeners,function(t,e){i.edgesData.subscribe(e,t)});var n=this.edgesData.getIds();this._addEdges(n)}this._reconnectEdges()},Graph.prototype._addEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o];r&&r.disconnect();var a=i.get(o,{showInternalIds:!0});e[o]=new Edge(a,this,this.constants)}this.moving=!0,this._updateValueRange(e)},Graph.prototype._updateEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=i.get(o),a=e[o];a?(a.disconnect(),a.setProperties(r,this.constants),a.connect()):(a=new Edge(r,this,this.constants),this.edges[o]=a)}this.moving=!0,this._updateValueRange(e)},Graph.prototype._removeEdges=function(t){for(var e=this.edges,i=0,n=t.length;n>i;i++){var s=t[i],o=e[s];o&&(o.disconnect(),delete e[s])}this.moving=!0,this._updateValueRange(e)},Graph.prototype._reconnectEdges=function(){var t,e=this.nodes,i=this.edges;for(t in e)e.hasOwnProperty(t)&&(e[t].edges=[]);for(t in i)if(i.hasOwnProperty(t)){var n=i[t];n.from=null,n.to=null,n.connect()}},Graph.prototype._updateValueRange=function(t){var e,i=void 0,n=void 0;for(e in t)if(t.hasOwnProperty(e)){var s=t[e].getValue();void 0!==s&&(i=void 0===i?s:Math.min(s,i),n=void 0===n?s:Math.max(s,n))}if(void 0!==i&&void 0!==n)for(e in t)t.hasOwnProperty(e)&&t[e].setValueRange(i,n)},Graph.prototype.redraw=function(){this.setSize(this.width,this.height),this._redraw()},Graph.prototype._redraw=function(){var t=this.frame.canvas.getContext("2d"),e=this.frame.canvas.width,i=this.frame.canvas.height;t.clearRect(0,0,e,i),t.save(),t.translate(this.translation.x,this.translation.y),t.scale(this.scale,this.scale),this.canvasTopLeft={x:this._canvasToX(0),y:this._canvasToY(0)},this.canvasBottomRight={x:this._canvasToX(this.frame.canvas.clientWidth),y:this._canvasToY(this.frame.canvas.clientHeight)},this._doInAllSectors("_drawAllSectorNodes",t),this._doInAllSectors("_drawEdges",t),this._doInAllSectors("_drawNodes",t,!0),t.restore(),1==this.constants.navigation.enabled&&this._doInNavigationSector("_drawNodes",t,!0)},Graph.prototype._setTranslation=function(t,e){void 0===this.translation&&(this.translation={x:0,y:0}),void 0!==t&&(this.translation.x=t),void 0!==e&&(this.translation.y=e)},Graph.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},Graph.prototype._setScale=function(t){this.scale=t},Graph.prototype._getScale=function(){return this.scale},Graph.prototype._canvasToX=function(t){return(t-this.translation.x)/this.scale},Graph.prototype._xToCanvas=function(t){return t*this.scale+this.translation.x},Graph.prototype._canvasToY=function(t){return(t-this.translation.y)/this.scale},Graph.prototype._yToCanvas=function(t){return t*this.scale+this.translation.y},Graph.prototype._drawNodes=function(t,e){void 0===e&&(e=!1);var i=this.nodes,n=[];for(var s in i)i.hasOwnProperty(s)&&(i[s].setScaleAndPos(this.scale,this.canvasTopLeft,this.canvasBottomRight),i[s].isSelected()?n.push(s):(i[s].inArea()||e)&&i[s].draw(t));for(var o=0,r=n.length;r>o;o++)(i[n[o]].inArea()||e)&&i[n[o]].draw(t)},Graph.prototype._drawEdges=function(t){var e=this.edges;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];n.setScale(this.scale),n.connected&&e[i].draw(t)}},Graph.prototype._doStabilize=function(){for(var t=0,e=this.constants.minVelocity,i=!1;!i&&t0)for(var i in e)e.hasOwnProperty(i)&&e[i].discreteStepLimited(t,this.constants.maxVelocity);else for(var i in e)e.hasOwnProperty(i)&&e[i].discreteStep(t);var n=this.constants.minVelocity;this.moving=this._isMoving(n)},Graph.prototype.start=function(){if(!this.freezeSimulation)if(this.moving&&(this._doInAllActiveSectors("_initializeForceCalculation"),this._doInAllActiveSectors("_discreteStepNodes"),this._findCenter(this._getRange())),this.moving||0!=this.xIncrement||0!=this.yIncrement||0!=this.zoomIncrement){if(!this.timer){var t=this;this.timer=window.setTimeout(function(){if(t.timer=void 0,0!=t.xIncrement||0!=t.yIncrement){var e=t._getTranslation();t._setTranslation(e.x+t.xIncrement,e.y+t.yIncrement)}if(0!=t.zoomIncrement){var i={x:t.frame.canvas.clientWidth/2,y:t.frame.canvas.clientHeight/2};t._zoom(t.scale*(1+t.zoomIncrement),i)}t.start(),t.start(),t._redraw()},this.renderTimestep)}}else this._redraw()},Graph.prototype.singleStep=function(){if(this.moving){this._initializeForceCalculation(),this._discreteStepNodes();var t=this.constants.minVelocity;this.moving=this._isMoving(t),this._redraw()}},Graph.prototype.toggleFreeze=function(){0==this.freezeSimulation?this.freezeSimulation=!0:(this.freezeSimulation=!1,this.start())},Graph.prototype._loadPhysicsSystem=function(){for(var t in physicsMixin)physicsMixin.hasOwnProperty(t)&&(Graph.prototype[t]=physicsMixin[t])},Graph.prototype._loadClusterSystem=function(){this.clusterSession=0,this.hubThreshold=5;for(var t in ClusterMixin)ClusterMixin.hasOwnProperty(t)&&(Graph.prototype[t]=ClusterMixin[t])},Graph.prototype._loadSectorSystem=function(){this.sectors={},this.activeSector=["default"],this.sectors.active={},this.sectors.active["default"]={nodes:{},edges:{},nodeIndices:[],formationScale:1,drawingNode:void 0},this.sectors.frozen={},this.sectors.navigation={nodes:{},edges:{},nodeIndices:[],formationScale:1,drawingNode:void 0},this.nodeIndices=this.sectors.active["default"].nodeIndices;for(var t in SectorMixin)SectorMixin.hasOwnProperty(t)&&(Graph.prototype[t]=SectorMixin[t])},Graph.prototype._loadSelectionSystem=function(){this.selectionObj={};for(var t in SelectionMixin)SelectionMixin.hasOwnProperty(t)&&(Graph.prototype[t]=SelectionMixin[t])},Graph.prototype._loadManipulationSystem=function(){if(this.blockConnectingEdgeSelection=!1,this.forceAppendSelection=!1,1==this.constants.dataManipulationToolbar.enabled){void 0===this.manipulationDiv&&(this.manipulationDiv=document.createElement("div"),this.manipulationDiv.className="graph-manipulationDiv",this.containerElement.insertBefore(this.manipulationDiv,this.frame));for(var t in manipulationMixin)manipulationMixin.hasOwnProperty(t)&&(Graph.prototype[t]=manipulationMixin[t]);this._createManipulatorBar()}},Graph.prototype._loadNavigationControls=function(){for(var t in NavigationMixin)NavigationMixin.hasOwnProperty(t)&&(Graph.prototype[t]=NavigationMixin[t]);1==this.constants.navigation.enabled&&this._loadNavigationElements()},Graph.prototype._relocateNavigation=function(){},Graph.prototype._unHighlightAll=function(){};var vis={util:util,events:events,Controller:Controller,DataSet:DataSet,DataView:DataView,Range:Range,Stack:Stack,TimeStep:TimeStep,EventBus:EventBus,components:{items:{Item:Item,ItemBox:ItemBox,ItemPoint:ItemPoint,ItemRange:ItemRange},Component:Component,Panel:Panel,RootPanel:RootPanel,ItemSet:ItemSet,TimeAxis:TimeAxis},graph:{Node:Node,Edge:Edge,Popup:Popup,Groups:Groups,Images:Images},Timeline:Timeline,Graph:Graph};"undefined"!=typeof exports&&(exports=vis),"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=vis),"function"==typeof define&&define(function(){return vis}),"undefined"!=typeof window&&(window.vis=vis)},{hammerjs:2,moment:3,mousetrap:4}],2:[function(t,e){!function(t,i){"use strict";function n(){if(!s.READY){s.event.determineEventTypes();for(var t in s.gestures)s.gestures.hasOwnProperty(t)&&s.detection.register(s.gestures[t]);s.event.onTouch(s.DOCUMENT,s.EVENT_MOVE,s.detection.detect),s.event.onTouch(s.DOCUMENT,s.EVENT_END,s.detection.detect),s.READY=!0}}var s=function(t,e){return new s.Instance(t,e||{})};s.defaults={stop_browser_behavior:{userSelect:"none",touchAction:"none",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}},s.HAS_POINTEREVENTS=navigator.pointerEnabled||navigator.msPointerEnabled,s.HAS_TOUCHEVENTS="ontouchstart"in t,s.MOBILE_REGEX=/mobile|tablet|ip(ad|hone|od)|android/i,s.NO_MOUSEEVENTS=s.HAS_TOUCHEVENTS&&navigator.userAgent.match(s.MOBILE_REGEX),s.EVENT_TYPES={},s.DIRECTION_DOWN="down",s.DIRECTION_LEFT="left",s.DIRECTION_UP="up",s.DIRECTION_RIGHT="right",s.POINTER_MOUSE="mouse",s.POINTER_TOUCH="touch",s.POINTER_PEN="pen",s.EVENT_START="start",s.EVENT_MOVE="move",s.EVENT_END="end",s.DOCUMENT=document,s.plugins={},s.READY=!1,s.Instance=function(t,e){var i=this;return n(),this.element=t,this.enabled=!0,this.options=s.utils.extend(s.utils.extend({},s.defaults),e||{}),this.options.stop_browser_behavior&&s.utils.stopDefaultBrowserBehavior(this.element,this.options.stop_browser_behavior),s.event.onTouch(t,s.EVENT_START,function(t){i.enabled&&s.detection.startDetect(i,t)}),this},s.Instance.prototype={on:function(t,e){for(var i=t.split(" "),n=0;n0&&e==s.EVENT_END?e=s.EVENT_MOVE:c||(e=s.EVENT_END),c||null===o?o=h:h=o,i.call(s.detection,n.collectEventData(t,e,h)),s.HAS_POINTEREVENTS&&e==s.EVENT_END&&(c=s.PointerEvent.updatePointer(e,h))),c||(o=null,r=!1,a=!1,s.PointerEvent.reset())}})},determineEventTypes:function(){var t;t=s.HAS_POINTEREVENTS?s.PointerEvent.getEvents():s.NO_MOUSEEVENTS?["touchstart","touchmove","touchend touchcancel"]:["touchstart mousedown","touchmove mousemove","touchend touchcancel mouseup"],s.EVENT_TYPES[s.EVENT_START]=t[0],s.EVENT_TYPES[s.EVENT_MOVE]=t[1],s.EVENT_TYPES[s.EVENT_END]=t[2]},getTouchList:function(t){return s.HAS_POINTEREVENTS?s.PointerEvent.getTouchList():t.touches?t.touches:[{identifier:1,pageX:t.pageX,pageY:t.pageY,target:t.target}]},collectEventData:function(t,e,i){var n=this.getTouchList(i,e),o=s.POINTER_TOUCH;return(i.type.match(/mouse/)||s.PointerEvent.matchType(s.POINTER_MOUSE,i))&&(o=s.POINTER_MOUSE),{center:s.utils.getCenter(n),timeStamp:(new Date).getTime(),target:i.target,touches:n,eventType:e,pointerType:o,srcEvent:i,preventDefault:function(){this.srcEvent.preventManipulation&&this.srcEvent.preventManipulation(),this.srcEvent.preventDefault&&this.srcEvent.preventDefault()},stopPropagation:function(){this.srcEvent.stopPropagation()},stopDetect:function(){return s.detection.stopDetect()}}}},s.PointerEvent={pointers:{},getTouchList:function(){var t=this,e=[];return Object.keys(t.pointers).sort().forEach(function(i){e.push(t.pointers[i])}),e},updatePointer:function(t,e){return t==s.EVENT_END?this.pointers={}:(e.identifier=e.pointerId,this.pointers[e.pointerId]=e),Object.keys(this.pointers).length},matchType:function(t,e){if(!e.pointerType)return!1;var i={};return i[s.POINTER_MOUSE]=e.pointerType==e.MSPOINTER_TYPE_MOUSE||e.pointerType==s.POINTER_MOUSE,i[s.POINTER_TOUCH]=e.pointerType==e.MSPOINTER_TYPE_TOUCH||e.pointerType==s.POINTER_TOUCH,i[s.POINTER_PEN]=e.pointerType==e.MSPOINTER_TYPE_PEN||e.pointerType==s.POINTER_PEN,i[t]},getEvents:function(){return["pointerdown MSPointerDown","pointermove MSPointerMove","pointerup pointercancel MSPointerUp MSPointerCancel"]},reset:function(){this.pointers={}}},s.utils={extend:function(t,e,n){for(var s in e)t[s]!==i&&n||(t[s]=e[s]);return t},hasParent:function(t,e){for(;t;){if(t==e)return!0;t=t.parentNode}return!1},getCenter:function(t){for(var e=[],i=[],n=0,s=t.length;s>n;n++)e.push(t[n].pageX),i.push(t[n].pageY);return{pageX:(Math.min.apply(Math,e)+Math.max.apply(Math,e))/2,pageY:(Math.min.apply(Math,i)+Math.max.apply(Math,i))/2}},getVelocity:function(t,e,i){return{x:Math.abs(e/t)||0,y:Math.abs(i/t)||0}},getAngle:function(t,e){var i=e.pageY-t.pageY,n=e.pageX-t.pageX;return 180*Math.atan2(i,n)/Math.PI},getDirection:function(t,e){var i=Math.abs(t.pageX-e.pageX),n=Math.abs(t.pageY-e.pageY);return i>=n?t.pageX-e.pageX>0?s.DIRECTION_LEFT:s.DIRECTION_RIGHT:t.pageY-e.pageY>0?s.DIRECTION_UP:s.DIRECTION_DOWN},getDistance:function(t,e){var i=e.pageX-t.pageX,n=e.pageY-t.pageY;return Math.sqrt(i*i+n*n)},getScale:function(t,e){return t.length>=2&&e.length>=2?this.getDistance(e[0],e[1])/this.getDistance(t[0],t[1]):1},getRotation:function(t,e){return t.length>=2&&e.length>=2?this.getAngle(e[1],e[0])-this.getAngle(t[1],t[0]):0},isVertical:function(t){return t==s.DIRECTION_UP||t==s.DIRECTION_DOWN},stopDefaultBrowserBehavior:function(t,e){var i,n=["webkit","khtml","moz","ms","o",""];if(e&&t.style){for(var s=0;si;i++){var o=this.gestures[i];if(!this.stopped&&e[o.name]!==!1&&o.handler.call(o,t,this.current.inst)===!1){this.stopDetect();break}}return this.current&&(this.current.lastEvent=t),t.eventType==s.EVENT_END&&!t.touches.length-1&&this.stopDetect(),t}},stopDetect:function(){this.previous=s.utils.extend({},this.current),this.current=null,this.stopped=!0},extendEventData:function(t){var e=this.current.startEvent;if(e&&(t.touches.length!=e.touches.length||t.touches===e.touches)){e.touches=[];for(var i=0,n=t.touches.length;n>i;i++)e.touches.push(s.utils.extend({},t.touches[i]))}var o=t.timeStamp-e.timeStamp,r=t.center.pageX-e.center.pageX,a=t.center.pageY-e.center.pageY,h=s.utils.getVelocity(o,r,a);return s.utils.extend(t,{deltaTime:o,deltaX:r,deltaY:a,velocityX:h.x,velocityY:h.y,distance:s.utils.getDistance(e.center,t.center),angle:s.utils.getAngle(e.center,t.center),direction:s.utils.getDirection(e.center,t.center),scale:s.utils.getScale(e.touches,t.touches),rotation:s.utils.getRotation(e.touches,t.touches),startEvent:e}),t},register:function(t){var e=t.defaults||{};return e[t.name]===i&&(e[t.name]=!0),s.utils.extend(s.defaults,e,!0),t.index=t.index||1e3,this.gestures.push(t),this.gestures.sort(function(t,e){return t.indexe.index?1:0}),this.gestures}},s.gestures=s.gestures||{},s.gestures.Hold={name:"hold",index:10,defaults:{hold_timeout:500,hold_threshold:1},timer:null,handler:function(t,e){switch(t.eventType){case s.EVENT_START:clearTimeout(this.timer),s.detection.current.name=this.name,this.timer=setTimeout(function(){"hold"==s.detection.current.name&&e.trigger("hold",t)},e.options.hold_timeout);break;case s.EVENT_MOVE:t.distance>e.options.hold_threshold&&clearTimeout(this.timer);break;case s.EVENT_END:clearTimeout(this.timer)}}},s.gestures.Tap={name:"tap",index:100,defaults:{tap_max_touchtime:250,tap_max_distance:10,tap_always:!0,doubletap_distance:20,doubletap_interval:300},handler:function(t,e){if(t.eventType==s.EVENT_END){var i=s.detection.previous,n=!1;if(t.deltaTime>e.options.tap_max_touchtime||t.distance>e.options.tap_max_distance)return;i&&"tap"==i.name&&t.timeStamp-i.lastEvent.timeStamp0&&t.touches.length>e.options.swipe_max_touches)return;(t.velocityX>e.options.swipe_velocity||t.velocityY>e.options.swipe_velocity)&&(e.trigger(this.name,t),e.trigger(this.name+t.direction,t))}}},s.gestures.Drag={name:"drag",index:50,defaults:{drag_min_distance:10,drag_max_touches:1,drag_block_horizontal:!1,drag_block_vertical:!1,drag_lock_to_axis:!1,drag_lock_min_distance:25},triggered:!1,handler:function(t,e){if(s.detection.current.name!=this.name&&this.triggered)return e.trigger(this.name+"end",t),void(this.triggered=!1); -if(!(e.options.drag_max_touches>0&&t.touches.length>e.options.drag_max_touches))switch(t.eventType){case s.EVENT_START:this.triggered=!1;break;case s.EVENT_MOVE:if(t.distancee.options.transform_min_rotation&&e.trigger("rotate",t),i>e.options.transform_min_scale&&(e.trigger("pinch",t),e.trigger("pinch"+(t.scale<1?"in":"out"),t));break;case s.EVENT_END:this.triggered&&e.trigger(this.name+"end",t),this.triggered=!1}}},s.gestures.Touch={name:"touch",index:-1/0,defaults:{prevent_default:!1,prevent_mouseevents:!1},handler:function(t,e){return e.options.prevent_mouseevents&&t.pointerType==s.POINTER_MOUSE?void t.stopDetect():(e.options.prevent_default&&t.preventDefault(),void(t.eventType==s.EVENT_START&&e.trigger(this.name,t)))}},s.gestures.Release={name:"release",index:1/0,handler:function(t,e){t.eventType==s.EVENT_END&&e.trigger(this.name,t)}},"object"==typeof e&&"object"==typeof e.exports?e.exports=s:(t.Hammer=s,"function"==typeof t.define&&t.define.amd&&t.define("hammer",[],function(){return s}))}(this)},{}],3:[function(t,e){(function(i){function n(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function s(t,e){return function(i){return u(t.call(this,i),e)}}function o(t,e){return function(i){return this.lang().ordinal(t.call(this,i),e)}}function r(){}function a(t){E(t),l(this,t)}function h(t){var e=y(t),i=e.year||0,n=e.month||0,s=e.week||0,o=e.day||0,r=e.hour||0,a=e.minute||0,h=e.second||0,l=e.millisecond||0;this._milliseconds=+l+1e3*h+6e4*a+36e5*r,this._days=+o+7*s,this._months=+n+12*i,this._data={},this._bubble()}function l(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return e.hasOwnProperty("toString")&&(t.toString=e.toString),e.hasOwnProperty("valueOf")&&(t.valueOf=e.valueOf),t}function c(t){var e,i={};for(e in t)t.hasOwnProperty(e)&&ye.hasOwnProperty(e)&&(i[e]=t[e]);return i}function d(t){return 0>t?Math.ceil(t):Math.floor(t)}function u(t,e,i){for(var n=""+Math.abs(t),s=t>=0;n.lengthn;n++)(i&&t[n]!==e[n]||!i&&b(t[n])!==b(e[n]))&&r++;return r+o}function v(t){if(t){var e=t.toLowerCase().replace(/(.)s$/,"$1");t=Xe[t]||qe[e]||e}return t}function y(t){var e,i,n={};for(i in t)t.hasOwnProperty(i)&&(e=v(i),e&&(n[e]=t[i]));return n}function _(t){var e,n;if(0===t.indexOf("week"))e=7,n="day";else{if(0!==t.indexOf("month"))return;e=12,n="month"}oe[t]=function(s,o){var r,a,h=oe.fn._lang[t],l=[];if("number"==typeof s&&(o=s,s=i),a=function(t){var e=oe().utc().set(n,t);return h.call(oe.fn._lang,e,s||"")},null!=o)return a(o);for(r=0;e>r;r++)l.push(a(r));return l}}function b(t){var e=+t,i=0;return 0!==e&&isFinite(e)&&(i=e>=0?Math.floor(e):Math.ceil(e)),i}function w(t,e){return new Date(Date.UTC(t,e+1,0)).getUTCDate()}function S(t){return T(t)?366:365}function T(t){return t%4===0&&t%100!==0||t%400===0}function E(t){var e;t._a&&-2===t._pf.overflow&&(e=t._a[de]<0||t._a[de]>11?de:t._a[ue]<1||t._a[ue]>w(t._a[ce],t._a[de])?ue:t._a[pe]<0||t._a[pe]>23?pe:t._a[fe]<0||t._a[fe]>59?fe:t._a[ge]<0||t._a[ge]>59?ge:t._a[me]<0||t._a[me]>999?me:-1,t._pf._overflowDayOfYear&&(ce>e||e>ue)&&(e=ue),t._pf.overflow=e)}function x(t){return null==t._isValid&&(t._isValid=!isNaN(t._d.getTime())&&t._pf.overflow<0&&!t._pf.empty&&!t._pf.invalidMonth&&!t._pf.nullInput&&!t._pf.invalidFormat&&!t._pf.userInvalidated,t._strict&&(t._isValid=t._isValid&&0===t._pf.charsLeftOver&&0===t._pf.unusedTokens.length)),t._isValid}function C(t){return t?t.toLowerCase().replace("_","-"):t}function M(t,e){return e._isUTC?oe(t).zone(e._offset||0):oe(t).local()}function D(t,e){return e.abbr=t,ve[t]||(ve[t]=new r),ve[t].set(e),ve[t]}function I(t){delete ve[t]}function N(e){var i,n,s,o,r=0,a=function(e){if(!ve[e]&&_e)try{t("./lang/"+e)}catch(i){}return ve[e]};if(!e)return oe.fn._lang;if(!f(e)){if(n=a(e))return n;e=[e]}for(;r0;){if(n=a(o.slice(0,i).join("-")))return n;if(s&&s.length>=i&&m(o,s,!0)>=i-1)break;i--}r++}return oe.fn._lang}function O(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function L(t){var e,i,n=t.match(Te);for(e=0,i=n.length;i>e;e++)n[e]=Qe[n[e]]?Qe[n[e]]:O(n[e]);return function(s){var o="";for(e=0;i>e;e++)o+=n[e]instanceof Function?n[e].call(s,t):n[e];return o}}function k(t,e){return t.isValid()?(e=A(e,t.lang()),Ze[e]||(Ze[e]=L(e)),Ze[e](t)):t.lang().invalidDate()}function A(t,e){function i(t){return e.longDateFormat(t)||t}var n=5;for(Ee.lastIndex=0;n>=0&&Ee.test(t);)t=t.replace(Ee,i),Ee.lastIndex=0,n-=1;return t}function P(t,e){var i,n=e._strict;switch(t){case"DDDD":return ze;case"YYYY":case"GGGG":case"gggg":return n?Fe:Me;case"Y":case"G":case"g":return Ye;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return n?Re:De;case"S":if(n)return Ae;case"SS":if(n)return Pe;case"SSS":if(n)return ze;case"DDD":return Ce;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Ne;case"a":case"A":return N(e._l)._meridiemParse;case"X":return ke;case"Z":case"ZZ":return Oe;case"T":return Le;case"SSSS":return Ie;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return n?Pe:xe;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return xe;default:return i=new RegExp(G(j(t.replace("\\","")),"i"))}}function z(t){t=t||"";var e=t.match(Oe)||[],i=e[e.length-1]||[],n=(i+"").match(Ue)||["-",0,0],s=+(60*n[1])+b(n[2]);return"+"===n[0]?-s:s}function F(t,e,i){var n,s=i._a;switch(t){case"M":case"MM":null!=e&&(s[de]=b(e)-1);break;case"MMM":case"MMMM":n=N(i._l).monthsParse(e),null!=n?s[de]=n:i._pf.invalidMonth=e;break;case"D":case"DD":null!=e&&(s[ue]=b(e));break;case"DDD":case"DDDD":null!=e&&(i._dayOfYear=b(e));break;case"YY":s[ce]=b(e)+(b(e)>68?1900:2e3);break;case"YYYY":case"YYYYY":case"YYYYYY":s[ce]=b(e);break;case"a":case"A":i._isPm=N(i._l).isPM(e);break;case"H":case"HH":case"h":case"hh":s[pe]=b(e);break;case"m":case"mm":s[fe]=b(e);break;case"s":case"ss":s[ge]=b(e);break;case"S":case"SS":case"SSS":case"SSSS":s[me]=b(1e3*("0."+e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,i._tzm=z(e);break;case"w":case"ww":case"W":case"WW":case"d":case"dd":case"ddd":case"dddd":case"e":case"E":t=t.substr(0,1);case"gg":case"gggg":case"GG":case"GGGG":case"GGGGG":t=t.substr(0,2),e&&(i._w=i._w||{},i._w[t]=e)}}function R(t){var e,i,n,s,o,r,a,h,l,c,d=[];if(!t._d){for(n=H(t),t._w&&null==t._a[ue]&&null==t._a[de]&&(o=function(e){var i=parseInt(e,10);return e?e.length<3?i>68?1900+i:2e3+i:i:null==t._a[ce]?oe().weekYear():t._a[ce]},r=t._w,null!=r.GG||null!=r.W||null!=r.E?a=J(o(r.GG),r.W||1,r.E,4,1):(h=N(t._l),l=null!=r.d?Z(r.d,h):null!=r.e?parseInt(r.e,10)+h._week.dow:0,c=parseInt(r.w,10)||1,null!=r.d&&lS(s)&&(t._pf._overflowDayOfYear=!0),i=q(s,0,t._dayOfYear),t._a[de]=i.getUTCMonth(),t._a[ue]=i.getUTCDate()),e=0;3>e&&null==t._a[e];++e)t._a[e]=d[e]=n[e];for(;7>e;e++)t._a[e]=d[e]=null==t._a[e]?2===e?1:0:t._a[e];d[pe]+=b((t._tzm||0)/60),d[fe]+=b((t._tzm||0)%60),t._d=(t._useUTC?q:X).apply(null,d)}}function Y(t){var e;t._d||(e=y(t._i),t._a=[e.year,e.month,e.day,e.hour,e.minute,e.second,e.millisecond],R(t))}function H(t){var e=new Date;return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function W(t){t._a=[],t._pf.empty=!0;var e,i,n,s,o,r=N(t._l),a=""+t._i,h=a.length,l=0;for(n=A(t._f,r).match(Te)||[],e=0;e0&&t._pf.unusedInput.push(o),a=a.slice(a.indexOf(i)+i.length),l+=i.length),Qe[s]?(i?t._pf.empty=!1:t._pf.unusedTokens.push(s),F(s,i,t)):t._strict&&!i&&t._pf.unusedTokens.push(s);t._pf.charsLeftOver=h-l,a.length>0&&t._pf.unusedInput.push(a),t._isPm&&t._a[pe]<12&&(t._a[pe]+=12),t._isPm===!1&&12===t._a[pe]&&(t._a[pe]=0),R(t),E(t)}function j(t){return t.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,i,n,s){return e||i||n||s})}function G(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function U(t){var e,i,s,o,r;if(0===t._f.length)return t._pf.invalidFormat=!0,void(t._d=new Date(0/0));for(o=0;or)&&(s=r,i=e));l(t,i||e)}function B(t){var e,i,n=t._i,s=He.exec(n);if(s){for(t._pf.iso=!0,e=0,i=je.length;i>e;e++)if(je[e][1].exec(n)){t._f=je[e][0]+(s[6]||" ");break}for(e=0,i=Ge.length;i>e;e++)if(Ge[e][1].exec(n)){t._f+=Ge[e][0];break}n.match(Oe)&&(t._f+="Z"),W(t)}else t._d=new Date(n)}function V(t){var e=t._i,n=be.exec(e);e===i?t._d=new Date:n?t._d=new Date(+n[1]):"string"==typeof e?B(t):f(e)?(t._a=e.slice(0),R(t)):g(e)?t._d=new Date(+e):"object"==typeof e?Y(t):t._d=new Date(e)}function X(t,e,i,n,s,o,r){var a=new Date(t,e,i,n,s,o,r);return 1970>t&&a.setFullYear(t),a}function q(t){var e=new Date(Date.UTC.apply(null,arguments));return 1970>t&&e.setUTCFullYear(t),e}function Z(t,e){if("string"==typeof t)if(isNaN(t)){if(t=e.weekdaysParse(t),"number"!=typeof t)return null}else t=parseInt(t,10);return t}function K(t,e,i,n,s){return s.relativeTime(e||1,!!i,t,n)}function $(t,e,i){var n=le(Math.abs(t)/1e3),s=le(n/60),o=le(s/60),r=le(o/24),a=le(r/365),h=45>n&&["s",n]||1===s&&["m"]||45>s&&["mm",s]||1===o&&["h"]||22>o&&["hh",o]||1===r&&["d"]||25>=r&&["dd",r]||45>=r&&["M"]||345>r&&["MM",le(r/30)]||1===a&&["y"]||["yy",a];return h[2]=e,h[3]=t>0,h[4]=i,K.apply({},h)}function Q(t,e,i){var n,s=i-e,o=i-t.day();return o>s&&(o-=7),s-7>o&&(o+=7),n=oe(t).add("d",o),{week:Math.ceil(n.dayOfYear()/7),year:n.year()}}function J(t,e,i,n,s){var o,r,a=q(t,0,1).getUTCDay();return i=null!=i?i:s,o=s-a+(a>n?7:0)-(s>a?7:0),r=7*(e-1)+(i-s)+o+1,{year:r>0?t:t-1,dayOfYear:r>0?r:S(t-1)+r}}function te(t){var e=t._i,i=t._f;return null===e?oe.invalid({nullInput:!0}):("string"==typeof e&&(t._i=e=N().preparse(e)),oe.isMoment(e)?(t=c(e),t._d=new Date(+e._d)):i?f(i)?U(t):W(t):V(t),new a(t))}function ee(t,e){oe.fn[t]=oe.fn[t+"s"]=function(t){var i=this._isUTC?"UTC":"";return null!=t?(this._d["set"+i+e](t),oe.updateOffset(this),this):this._d["get"+i+e]()}}function ie(t){oe.duration.fn[t]=function(){return this._data[t]}}function ne(t,e){oe.duration.fn["as"+t]=function(){return+this/e}}function se(t){var e=!1,i=oe;"undefined"==typeof ender&&(t?(he.moment=function(){return!e&&console&&console.warn&&(e=!0,console.warn("Accessing Moment through the global scope is deprecated, and will be removed in an upcoming release.")),i.apply(null,arguments)},l(he.moment,i)):he.moment=oe)}for(var oe,re,ae="2.5.1",he=this,le=Math.round,ce=0,de=1,ue=2,pe=3,fe=4,ge=5,me=6,ve={},ye={_isAMomentObject:null,_i:null,_f:null,_l:null,_strict:null,_isUTC:null,_offset:null,_pf:null,_lang:null},_e="undefined"!=typeof e&&e.exports&&"undefined"!=typeof t,be=/^\/?Date\((\-?\d+)/i,we=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,Se=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,Te=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g,Ee=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,xe=/\d\d?/,Ce=/\d{1,3}/,Me=/\d{1,4}/,De=/[+\-]?\d{1,6}/,Ie=/\d+/,Ne=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Oe=/Z|[\+\-]\d\d:?\d\d/gi,Le=/T/i,ke=/[\+\-]?\d+(\.\d{1,3})?/,Ae=/\d/,Pe=/\d\d/,ze=/\d{3}/,Fe=/\d{4}/,Re=/[+-]?\d{6}/,Ye=/[+-]?\d+/,He=/^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,We="YYYY-MM-DDTHH:mm:ssZ",je=[["YYYYYY-MM-DD",/[+-]\d{6}-\d{2}-\d{2}/],["YYYY-MM-DD",/\d{4}-\d{2}-\d{2}/],["GGGG-[W]WW-E",/\d{4}-W\d{2}-\d/],["GGGG-[W]WW",/\d{4}-W\d{2}/],["YYYY-DDD",/\d{4}-\d{3}/]],Ge=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d{1,3}/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],Ue=/([\+\-]|\d\d)/gi,Be="Date|Hours|Minutes|Seconds|Milliseconds".split("|"),Ve={Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6},Xe={ms:"millisecond",s:"second",m:"minute",h:"hour",d:"day",D:"date",w:"week",W:"isoWeek",M:"month",y:"year",DDD:"dayOfYear",e:"weekday",E:"isoWeekday",gg:"weekYear",GG:"isoWeekYear"},qe={dayofyear:"dayOfYear",isoweekday:"isoWeekday",isoweek:"isoWeek",weekyear:"weekYear",isoweekyear:"isoWeekYear"},Ze={},Ke="DDD w W M D d".split(" "),$e="M D H h m s w W".split(" "),Qe={M:function(){return this.month()+1},MMM:function(t){return this.lang().monthsShort(this,t)},MMMM:function(t){return this.lang().months(this,t)},D:function(){return this.date()},DDD:function(){return this.dayOfYear()},d:function(){return this.day()},dd:function(t){return this.lang().weekdaysMin(this,t)},ddd:function(t){return this.lang().weekdaysShort(this,t)},dddd:function(t){return this.lang().weekdays(this,t)},w:function(){return this.week()},W:function(){return this.isoWeek()},YY:function(){return u(this.year()%100,2)},YYYY:function(){return u(this.year(),4)},YYYYY:function(){return u(this.year(),5)},YYYYYY:function(){var t=this.year(),e=t>=0?"+":"-";return e+u(Math.abs(t),6)},gg:function(){return u(this.weekYear()%100,2)},gggg:function(){return u(this.weekYear(),4)},ggggg:function(){return u(this.weekYear(),5)},GG:function(){return u(this.isoWeekYear()%100,2)},GGGG:function(){return u(this.isoWeekYear(),4)},GGGGG:function(){return u(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.lang().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.lang().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return b(this.milliseconds()/100)},SS:function(){return u(b(this.milliseconds()/10),2)},SSS:function(){return u(this.milliseconds(),3)},SSSS:function(){return u(this.milliseconds(),3)},Z:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+u(b(t/60),2)+":"+u(b(t)%60,2)},ZZ:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+u(b(t/60),2)+u(b(t)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},X:function(){return this.unix()},Q:function(){return this.quarter()}},Je=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"];Ke.length;)re=Ke.pop(),Qe[re+"o"]=o(Qe[re],re);for(;$e.length;)re=$e.pop(),Qe[re+re]=s(Qe[re],2);for(Qe.DDDD=s(Qe.DDD,3),l(r.prototype,{set:function(t){var e,i;for(i in t)e=t[i],"function"==typeof e?this[i]=e:this["_"+i]=e},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(t){return this._months[t.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(t){return this._monthsShort[t.month()]},monthsParse:function(t){var e,i,n;for(this._monthsParse||(this._monthsParse=[]),e=0;12>e;e++)if(this._monthsParse[e]||(i=oe.utc([2e3,e]),n="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[e]=new RegExp(n.replace(".",""),"i")),this._monthsParse[e].test(t))return e},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(t){return this._weekdays[t.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(t){return this._weekdaysShort[t.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(t){return this._weekdaysMin[t.day()]},weekdaysParse:function(t){var e,i,n;for(this._weekdaysParse||(this._weekdaysParse=[]),e=0;7>e;e++)if(this._weekdaysParse[e]||(i=oe([2e3,1]).day(e),n="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[e]=new RegExp(n.replace(".",""),"i")),this._weekdaysParse[e].test(t))return e},_longDateFormat:{LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D YYYY",LLL:"MMMM D YYYY LT",LLLL:"dddd, MMMM D YYYY LT"},longDateFormat:function(t){var e=this._longDateFormat[t];return!e&&this._longDateFormat[t.toUpperCase()]&&(e=this._longDateFormat[t.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t]=e),e},isPM:function(t){return"p"===(t+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(t,e,i){return t>11?i?"pm":"PM":i?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(t,e){var i=this._calendar[t];return"function"==typeof i?i.apply(e):i},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(t,e,i,n){var s=this._relativeTime[i];return"function"==typeof s?s(t,e,i,n):s.replace(/%d/i,t)},pastFuture:function(t,e){var i=this._relativeTime[t>0?"future":"past"];return"function"==typeof i?i(e):i.replace(/%s/i,e)},ordinal:function(t){return this._ordinal.replace("%d",t)},_ordinal:"%d",preparse:function(t){return t},postformat:function(t){return t},week:function(t){return Q(t,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),oe=function(t,e,s,o){var r;return"boolean"==typeof s&&(o=s,s=i),r={},r._isAMomentObject=!0,r._i=t,r._f=e,r._l=s,r._strict=o,r._isUTC=!1,r._pf=n(),te(r)},oe.utc=function(t,e,s,o){var r;return"boolean"==typeof s&&(o=s,s=i),r={},r._isAMomentObject=!0,r._useUTC=!0,r._isUTC=!0,r._l=s,r._i=t,r._f=e,r._strict=o,r._pf=n(),te(r).utc()},oe.unix=function(t){return oe(1e3*t)},oe.duration=function(t,e){var i,n,s,o=t,r=null;return oe.isDuration(t)?o={ms:t._milliseconds,d:t._days,M:t._months}:"number"==typeof t?(o={},e?o[e]=t:o.milliseconds=t):(r=we.exec(t))?(i="-"===r[1]?-1:1,o={y:0,d:b(r[ue])*i,h:b(r[pe])*i,m:b(r[fe])*i,s:b(r[ge])*i,ms:b(r[me])*i}):(r=Se.exec(t))&&(i="-"===r[1]?-1:1,s=function(t){var e=t&&parseFloat(t.replace(",","."));return(isNaN(e)?0:e)*i},o={y:s(r[2]),M:s(r[3]),d:s(r[4]),h:s(r[5]),m:s(r[6]),s:s(r[7]),w:s(r[8])}),n=new h(o),oe.isDuration(t)&&t.hasOwnProperty("_lang")&&(n._lang=t._lang),n},oe.version=ae,oe.defaultFormat=We,oe.updateOffset=function(){},oe.lang=function(t,e){var i;return t?(e?D(C(t),e):null===e?(I(t),t="en"):ve[t]||N(t),i=oe.duration.fn._lang=oe.fn._lang=N(t),i._abbr):oe.fn._lang._abbr},oe.langData=function(t){return t&&t._lang&&t._lang._abbr&&(t=t._lang._abbr),N(t)},oe.isMoment=function(t){return t instanceof a||null!=t&&t.hasOwnProperty("_isAMomentObject")},oe.isDuration=function(t){return t instanceof h},re=Je.length-1;re>=0;--re)_(Je[re]);for(oe.normalizeUnits=function(t){return v(t)},oe.invalid=function(t){var e=oe.utc(0/0);return null!=t?l(e._pf,t):e._pf.userInvalidated=!0,e},oe.parseZone=function(t){return oe(t).parseZone()},l(oe.fn=a.prototype,{clone:function(){return oe(this)},valueOf:function(){return+this._d+6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().lang("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){var t=oe(this).utc();return 00:!1},parsingFlags:function(){return l({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(){return this.zone(0)},local:function(){return this.zone(0),this._isUTC=!1,this},format:function(t){var e=k(this,t||oe.defaultFormat);return this.lang().postformat(e)},add:function(t,e){var i;return i="string"==typeof t?oe.duration(+e,t):oe.duration(t,e),p(this,i,1),this},subtract:function(t,e){var i;return i="string"==typeof t?oe.duration(+e,t):oe.duration(t,e),p(this,i,-1),this},diff:function(t,e,i){var n,s,o=M(t,this),r=6e4*(this.zone()-o.zone());return e=v(e),"year"===e||"month"===e?(n=432e5*(this.daysInMonth()+o.daysInMonth()),s=12*(this.year()-o.year())+(this.month()-o.month()),s+=(this-oe(this).startOf("month")-(o-oe(o).startOf("month")))/n,s-=6e4*(this.zone()-oe(this).startOf("month").zone()-(o.zone()-oe(o).startOf("month").zone()))/n,"year"===e&&(s/=12)):(n=this-o,s="second"===e?n/1e3:"minute"===e?n/6e4:"hour"===e?n/36e5:"day"===e?(n-r)/864e5:"week"===e?(n-r)/6048e5:n),i?s:d(s)},from:function(t,e){return oe.duration(this.diff(t)).lang(this.lang()._abbr).humanize(!e)},fromNow:function(t){return this.from(oe(),t)},calendar:function(){var t=M(oe(),this).startOf("day"),e=this.diff(t,"days",!0),i=-6>e?"sameElse":-1>e?"lastWeek":0>e?"lastDay":1>e?"sameDay":2>e?"nextDay":7>e?"nextWeek":"sameElse";return this.format(this.lang().calendar(i,this))},isLeapYear:function(){return T(this.year())},isDST:function(){return this.zone()+oe(t).startOf(e)},isBefore:function(t,e){return e="undefined"!=typeof e?e:"millisecond",+this.clone().startOf(e)<+oe(t).startOf(e)},isSame:function(t,e){return e=e||"ms",+this.clone().startOf(e)===+M(t,this).startOf(e)},min:function(t){return t=oe.apply(null,arguments),this>t?this:t},max:function(t){return t=oe.apply(null,arguments),t>this?this:t},zone:function(t){var e=this._offset||0;return null==t?this._isUTC?e:this._d.getTimezoneOffset():("string"==typeof t&&(t=z(t)),Math.abs(t)<16&&(t=60*t),this._offset=t,this._isUTC=!0,e!==t&&p(this,oe.duration(e-t,"m"),1,!0),this)},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.zone(this._tzm):"string"==typeof this._i&&this.zone(this._i),this},hasAlignedHourOffset:function(t){return t=t?oe(t).zone():0,(this.zone()-t)%60===0},daysInMonth:function(){return w(this.year(),this.month())},dayOfYear:function(t){var e=le((oe(this).startOf("day")-oe(this).startOf("year"))/864e5)+1;return null==t?e:this.add("d",t-e)},quarter:function(){return Math.ceil((this.month()+1)/3)},weekYear:function(t){var e=Q(this,this.lang()._week.dow,this.lang()._week.doy).year;return null==t?e:this.add("y",t-e)},isoWeekYear:function(t){var e=Q(this,1,4).year;return null==t?e:this.add("y",t-e)},week:function(t){var e=this.lang().week(this);return null==t?e:this.add("d",7*(t-e))},isoWeek:function(t){var e=Q(this,1,4).week;return null==t?e:this.add("d",7*(t-e))},weekday:function(t){var e=(this.day()+7-this.lang()._week.dow)%7;return null==t?e:this.add("d",t-e)},isoWeekday:function(t){return null==t?this.day()||7:this.day(this.day()%7?t:t-7)},get:function(t){return t=v(t),this[t]()},set:function(t,e){return t=v(t),"function"==typeof this[t]&&this[t](e),this},lang:function(t){return t===i?this._lang:(this._lang=N(t),this)}}),re=0;re-1?!1:"INPUT"==i||"SELECT"==i||"TEXTAREA"==i||e.contentEditable&&"true"==e.contentEditable}function o(t,e){return t.sort().join(",")===e.sort().join(",")}function r(t){t=t||{};var e,i=!1;for(e in M)t[e]?i=!0:M[e]=0;i||(I=!1)}function a(t,e,i,n,s){var r,a,h=[];if(!x[t])return[];for("keyup"==i&&u(t)&&(e=[t]),r=0;r95&&112>t||w.hasOwnProperty(t)&&(_[w[t]]=t)}return _}function g(t,e,i){return i||(i=f()[t]?"keydown":"keypress"),"keypress"==i&&e.length&&(i="keydown"),i}function m(t,e,i,s){M[t]=0,s||(s=g(e[0],[]));var o,a=function(){I=s,++M[t],p()},h=function(t){l(i,t),"keyup"!==s&&(D=n(t)),setTimeout(r,10)};for(o=0;o1)return m(t,l,e,i);for(h="+"===t?["+"]:t.split("+"),o=0;o":".","?":"/","|":"\\"},E={option:"alt",command:"meta","return":"enter",escape:"esc"},x={},C={},M={},D=!1,I=!1,N=1;20>N;++N)w[111+N]="f"+N;for(N=0;9>=N;++N)w[N+96]=N;i(document,"keypress",d),i(document,"keydown",d),i(document,"keyup",d);var O={bind:function(t,e,i){return y(t instanceof Array?t:[t],e,i),C[t+":"+i]=e,this},unbind:function(t,e){return C[t+":"+e]&&(delete C[t+":"+e],this.bind(t,function(){},e)),this},trigger:function(t,e){return C[t+":"+e](),this},reset:function(){return x={},C={},this}};e.exports=O},{}]},{},[1])(1)}); \ No newline at end of file +this.beginPath(),this.moveTo(c,p),this.bezierCurveTo(c,p+l,u+h,d,u,d),this.bezierCurveTo(u-h,d,t,p+l,t,p),this.bezierCurveTo(t,p-l,u-h,e,u,e),this.bezierCurveTo(u+h,e,c,p-l,c,p),this.lineTo(c,f),this.bezierCurveTo(c,f+l,u+h,g,u,g),this.bezierCurveTo(u-h,g,t,f+l,t,f),this.lineTo(t,p)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,n){var s=t-n*Math.cos(i),o=e-n*Math.sin(i),r=t-.9*n*Math.cos(i),a=e-.9*n*Math.sin(i),h=s+n/3*Math.cos(i+.5*Math.PI),l=o+n/3*Math.sin(i+.5*Math.PI),c=s+n/3*Math.cos(i-.5*Math.PI),d=o+n/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,l),this.lineTo(r,a),this.lineTo(c,d),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,n,s){s||(s=[10,5]),0==u&&(u=.001);var o=s.length;this.moveTo(t,e);for(var r=i-t,a=n-e,h=a/r,l=Math.sqrt(r*r+a*a),c=0,d=!0;l>=.1;){var u=s[c++%o];u>l&&(u=l);var p=Math.sqrt(u*u/(1+h*h));0>r&&(p=-p),t+=p,e+=h*p,this[d?"lineTo":"moveTo"](t,e),l-=u,d=!d}}),Node.prototype.resetCluster=function(){this.formationScale=void 0,this.clusterSize=1,this.containedNodes={},this.containedEdges={},this.clusterSessions=[]},Node.prototype.attachEdge=function(t){-1==this.edges.indexOf(t)&&this.edges.push(t),-1==this.dynamicEdges.indexOf(t)&&this.dynamicEdges.push(t),this.dynamicEdgesLength=this.dynamicEdges.length},Node.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&(this.edges.splice(e,1),this.dynamicEdges.splice(e,1)),this.dynamicEdgesLength=this.dynamicEdges.length},Node.prototype.setProperties=function(t,e){if(t){if(this.originalLabel=void 0,void 0!==t.id&&(this.id=t.id),void 0!==t.label&&(this.label=t.label,this.originalLabel=t.label),void 0!==t.title&&(this.title=t.title),void 0!==t.group&&(this.group=t.group),void 0!==t.x&&(this.x=t.x),void 0!==t.y&&(this.y=t.y),void 0!==t.value&&(this.value=t.value),void 0!==t.internalMultiplier&&(this.internalMultiplier=t.value),void 0!==t.horizontalAlignLeft&&(this.horizontalAlignLeft=t.horizontalAlignLeft),void 0!==t.verticalAlignTop&&(this.verticalAlignTop=t.verticalAlignTop),void 0!==t.triggerFunction&&(this.triggerFunction=t.triggerFunction),void 0===this.id)throw"Node must have an id";if(this.group){var i=this.grouplist.get(this.group);for(var n in i)i.hasOwnProperty(n)&&(this[n]=i[n])}if(void 0!==t.shape&&(this.shape=t.shape),void 0!==t.image&&(this.image=t.image),void 0!==t.radius&&(this.radius=t.radius),void 0!==t.color&&(this.color=Node.parseColor(t.color)),void 0!==t.fontColor&&(this.fontColor=t.fontColor),void 0!==t.fontSize&&(this.fontSize=t.fontSize),void 0!==t.fontFace&&(this.fontFace=t.fontFace),void 0!==this.image){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.image)}switch(this.xFixed=this.xFixed||void 0!==t.x&&t.fixed,this.yFixed=this.yFixed||void 0!==t.y&&t.fixed,this.radiusFixed=this.radiusFixed||void 0!==t.radius,"image"==this.shape&&(this.radiusMin=e.nodes.widthMin,this.radiusMax=e.nodes.widthMax),this.shape){case"database":this.draw=this._drawDatabase,this.resize=this._resizeDatabase;break;case"box":this.draw=this._drawBox,this.resize=this._resizeBox;break;case"circle":this.draw=this._drawCircle,this.resize=this._resizeCircle;break;case"ellipse":this.draw=this._drawEllipse,this.resize=this._resizeEllipse;break;case"image":this.draw=this._drawImage,this.resize=this._resizeImage;break;case"text":this.draw=this._drawText,this.resize=this._resizeText;break;case"dot":this.draw=this._drawDot,this.resize=this._resizeShape;break;case"square":this.draw=this._drawSquare,this.resize=this._resizeShape;break;case"triangle":this.draw=this._drawTriangle,this.resize=this._resizeShape;break;case"triangleDown":this.draw=this._drawTriangleDown,this.resize=this._resizeShape;break;case"star":this.draw=this._drawStar,this.resize=this._resizeShape;break;default:this.draw=this._drawEllipse,this.resize=this._resizeEllipse}this._reset()}},Node.parseColor=function(t){var e;return util.isString(t)?e={border:t,background:t,highlight:{border:t,background:t}}:(e={},e.background=t.background||"white",e.border=t.border||e.background,util.isString(t.highlight)?e.highlight={border:t.highlight,background:t.highlight}:(e.highlight={},e.highlight.background=t.highlight&&t.highlight.background||e.background,e.highlight.border=t.highlight&&t.highlight.border||e.border)),e},Node.prototype.select=function(){this.selected=!0,this._reset()},Node.prototype.unselect=function(){this.selected=!1,this._reset()},Node.prototype.clearSizeCache=function(){this._reset()},Node.prototype._reset=function(){this.width=void 0,this.height=void 0},Node.prototype.getTitle=function(){return this.title},Node.prototype.distanceToBorder=function(t,e){var i=1;switch(this.width||this.resize(t),this.shape){case"circle":case"dot":return this.radius+i;case"ellipse":var n=this.width/2,s=this.height/2,o=Math.sin(e)*n,r=Math.cos(e)*s;return n*s/Math.sqrt(o*o+r*r);case"box":case"image":case"text":default:return this.width?Math.min(Math.abs(this.width/2/Math.cos(e)),Math.abs(this.height/2/Math.sin(e)))+i:0}},Node.prototype._setForce=function(t,e){this.fx=t,this.fy=e},Node.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},Node.prototype.discreteStep=function(t){if(!this.xFixed){var e=-this.damping*this.vx,i=(this.fx+e)/this.mass;this.vx+=i*t,this.x+=this.vx*t}if(!this.yFixed){var n=-this.damping*this.vy,s=(this.fy+n)/this.mass;this.vy+=s*t,this.y+=this.vy*t}},Node.prototype.discreteStepLimited=function(t,e){if(!this.xFixed){var i=-this.damping*this.vx,n=(this.fx+i)/this.mass;this.vx+=n*t,this.vx=Math.abs(this.vx)>e?this.vx>0?e:-e:this.vx,this.x+=this.vx*t}if(!this.yFixed){var s=-this.damping*this.vy,o=(this.fy+s)/this.mass;this.vy+=o*t,this.vy=Math.abs(this.vy)>e?this.vy>0?e:-e:this.vy,this.y+=this.vy*t}},Node.prototype.isFixed=function(){return this.xFixed&&this.yFixed},Node.prototype.isMoving=function(t){return Math.abs(this.vx)>t||Math.abs(this.vy)>t?!0:(this.vx=0,this.vy=0,!1)},Node.prototype.isSelected=function(){return this.selected},Node.prototype.getValue=function(){return this.value},Node.prototype.getDistance=function(t,e){var i=this.x-t,n=this.y-e;return Math.sqrt(i*i+n*n)},Node.prototype.setValueRange=function(t,e){if(!this.radiusFixed&&void 0!==this.value)if(e==t)this.radius=(this.radiusMin+this.radiusMax)/2;else{var i=(this.radiusMax-this.radiusMin)/(e-t);this.radius=(this.value-t)*i+this.radiusMin}this.baseRadiusValue=this.radius},Node.prototype.draw=function(){throw"Draw method not initialized for node"},Node.prototype.resize=function(){throw"Resize method not initialized for node"},Node.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},Node.prototype._resizeImage=function(){if(!this.width||!this.height){var t,e;if(this.value){this.radius=this.baseRadiusValue;var i=this.imageObj.height/this.imageObj.width;void 0!==i?(t=this.radius||this.imageObj.width,e=this.radius*i||this.imageObj.height):(t=0,e=0)}else t=this.imageObj.width,e=this.imageObj.height;this.width=t,this.height=e,this.width>0&&this.height>0&&(this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor)}},Node.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e;if(0!=this.imageObj.width){if(this.clusterSize>1){var i=this.clusterSize>1?10:0;i*=this.graphScaleInv,i=Math.min(.2*this.width,i),t.globalAlpha=.5,t.drawImage(this.imageObj,this.left-i,this.top-i,this.width+2*i,this.height+2*i)}t.globalAlpha=1,t.drawImage(this.imageObj,this.left,this.top,this.width,this.height),e=this.y+this.height/2}else e=this.y;this._label(t,this.label,this.x,e,void 0,"top")},Node.prototype._resizeBox=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=.5*(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=.5*(this.clusterSize-1)*this.clusterSizeHeightFactor}},Node.prototype._drawBox=function(t){this._resizeBox(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.roundRect(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth,this.radius),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.roundRect(this.left,this.top,this.width,this.height,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.prototype._resizeDatabase=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=i.width+2*e;this.width=n,this.height=n,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor}},Node.prototype._drawDatabase=function(t){this._resizeDatabase(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.database(this.x-this.width/2-2*t.lineWidth,this.y-.5*this.height-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.database(this.x-this.width/2,this.y-.5*this.height,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=Math.max(i.width,i.height)+2*e;this.radius=n/2,this.width=n,this.height=n,this.radius+=.5*(this.clusterSize-1)*this.clusterSizeRadiusFactor}},Node.prototype._drawCircle=function(t){this._resizeCircle(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.circle(this.x,this.y,this.radius+2*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.circle(this.x,this.y,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.prototype._resizeEllipse=function(t){if(!this.width){var e=this.getTextSize(t);this.width=1.5*e.width,this.height=2*e.height,this.width1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.ellipse(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.ellipse(this.left,this.top,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.prototype._drawDot=function(t){this._drawShape(t,"circle")},Node.prototype._drawTriangle=function(t){this._drawShape(t,"triangle")},Node.prototype._drawTriangleDown=function(t){this._drawShape(t,"triangleDown")},Node.prototype._drawSquare=function(t){this._drawShape(t,"square")},Node.prototype._drawStar=function(t){this._drawShape(t,"star")},Node.prototype._resizeShape=function(){if(!this.width){this.radius=this.baseRadiusValue;var t=2*this.radius;this.width=t,this.height=t,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=.5*(this.clusterSize-1)*this.clusterSizeRadiusFactor}},Node.prototype._drawShape=function(t,e){this._resizeShape(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var i=2.5,n=2,s=2;switch(e){case"dot":s=2;break;case"square":s=2;break;case"triangle":s=3;break;case"triangleDown":s=3;break;case"star":s=4}t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?n:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t[e](this.x,this.y,this.radius+s*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?n:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t[e](this.x,this.y,this.radius),t.fill(),t.stroke(),this.label&&this._label(t,this.label,this.x,this.y+this.height/2,void 0,"top")},Node.prototype._resizeText=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor}},Node.prototype._drawText=function(t){this._resizeText(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,this._label(t,this.label,this.x,this.y)},Node.prototype._label=function(t,e,i,n,s,o){if(e){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle=this.fontColor||"black",t.textAlign=s||"center",t.textBaseline=o||"middle";for(var r=e.split("\n"),a=r.length,h=this.fontSize+4,l=n+(1-a)/2*h,c=0;a>c;c++)t.fillText(r[c],i,l),l+=h}},Node.prototype.getTextSize=function(t){if(void 0!==this.label){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace;for(var e=this.label.split("\n"),i=(this.fontSize+4)*e.length,n=0,s=0,o=e.length;o>s;s++)n=Math.max(n,t.measureText(e[s]).width);return{width:n,height:i}}return{width:0,height:0}},Node.prototype.inArea=function(){return void 0!==this.width?this.x+this.width*this.graphScaleInv>=this.canvasTopLeft.x&&this.x-this.width*this.graphScaleInv=this.canvasTopLeft.y&&this.y-this.height*this.graphScaleInv=this.canvasTopLeft.x&&this.x=this.canvasTopLeft.y&&this.yh},Edge.prototype._drawLine=function(t){t.strokeStyle=this.color,t.lineWidth=this._getLineWidth();var e;if(this.from!=this.to)this._line(t),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y));else{var i,n,s=this.length/4,o=this.from;o.width||o.resize(t),o.width>o.height?(i=o.x+o.width/2,n=o.y-s):(i=o.x+s,n=o.y-o.height/2),this._circle(t,i,n,s),e=this._pointOnCircle(i,n,s,.5),this._label(t,this.label,e.x,e.y)}},Edge.prototype._getLineWidth=function(){return 1==this.selected?Math.min(2*this.width,this.widthMax)*this.graphScaleInv:this.width*this.graphScaleInv},Edge.prototype._line=function(t){t.beginPath(),t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y),t.stroke()},Edge.prototype._circle=function(t,e,i,n){t.beginPath(),t.arc(e,i,n,0,2*Math.PI,!1),t.stroke()},Edge.prototype._label=function(t,e,i,n){if(e){t.font=(this.from.selected||this.to.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle="white";var s=t.measureText(e).width,o=this.fontSize,r=i-s/2,a=n-o/2;t.fillRect(r,a,s,o),t.fillStyle=this.fontColor||"black",t.textAlign="left",t.textBaseline="top",t.fillText(e,r,a)}},Edge.prototype._drawDashLine=function(t){if(t.strokeStyle=this.color,t.lineWidth=this._getLineWidth(),t.beginPath(),t.lineCap="round",void 0!==this.dash.altLength?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]):void 0!==this.dash.length&&void 0!==this.dash.gap?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap]):(t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y)),t.stroke(),this.label){var e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}},Edge.prototype._pointOnLine=function(t){return{x:(1-t)*this.from.x+t*this.to.x,y:(1-t)*this.from.y+t*this.to.y}},Edge.prototype._pointOnCircle=function(t,e,i,n){var s=2*(n-3/8)*Math.PI;return{x:t+i*Math.cos(s),y:e-i*Math.sin(s)}},Edge.prototype._drawArrowCenter=function(t){var e;if(t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth(),this.from!=this.to){this._line(t);var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),n=10+5*this.width;e=this._pointOnLine(.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y))}else{var s,o,r=this.length/4,a=this.from;a.width||a.resize(t),a.width>a.height?(s=a.x+a.width/2,o=a.y-r):(s=a.x+r,o=a.y-a.height/2),this._circle(t,s,o,r);var i=.2*Math.PI,n=10+5*this.width;e=this._pointOnCircle(s,o,r,.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(s,o,r,.5),this._label(t,this.label,e.x,e.y))}},Edge.prototype._drawArrow=function(t){t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth();var e,i;if(this.from!=this.to){e=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x);var n=this.to.x-this.from.x,s=this.to.y-this.from.y,o=Math.sqrt(n*n+s*s),r=this.from.distanceToBorder(t,e+Math.PI),a=(o-r)/o,h=a*this.from.x+(1-a)*this.to.x,l=a*this.from.y+(1-a)*this.to.y,c=this.to.distanceToBorder(t,e),d=(o-c)/o,u=(1-d)*this.from.x+d*this.to.x,p=(1-d)*this.from.y+d*this.to.y;if(t.beginPath(),t.moveTo(h,l),t.lineTo(u,p),t.stroke(),i=10+5*this.width,t.arrow(u,p,e,i),t.fill(),t.stroke(),this.label){var f=this._pointOnLine(.5);this._label(t,this.label,f.x,f.y)}}else{var g,m,v,y=this.from,_=this.length/4;y.width||y.resize(t),y.width>y.height?(g=y.x+y.width/2,m=y.y-_,v={x:g,y:y.y,angle:.9*Math.PI}):(g=y.x+_,m=y.y-y.height/2,v={x:y.x,y:m,angle:.6*Math.PI}),t.beginPath(),t.arc(g,m,_,0,2*Math.PI,!1),t.stroke(),i=10+5*this.width,t.arrow(v.x,v.y,v.angle,i),t.fill(),t.stroke(),this.label&&(f=this._pointOnCircle(g,m,_,.5),this._label(t,this.label,f.x,f.y))}},Edge._dist=function(t,e,i,n,s,o){var r=i-t,a=n-e,h=r*r+a*a,l=((s-t)*r+(o-e)*a)/h;l>1?l=1:0>l&&(l=0);var c=t+l*r,d=e+l*a,u=c-s,p=d-o;return Math.sqrt(u*u+p*p)},Edge.prototype.setScale=function(t){this.graphScaleInv=1/t},Edge.prototype.select=function(){this.selected=!0},Edge.prototype.unselect=function(){this.selected=!1},Popup.prototype.setPosition=function(t,e){this.x=parseInt(t),this.y=parseInt(e)},Popup.prototype.setText=function(t){this.frame.innerHTML=t},Popup.prototype.show=function(t){if(void 0===t&&(t=!0),t){var e=this.frame.clientHeight,i=this.frame.clientWidth,n=this.frame.parentNode.clientHeight,s=this.frame.parentNode.clientWidth,o=this.y-e;o+e+this.padding>n&&(o=n-e-this.padding),os&&(r=s-i-this.padding),rthis.constants.clustering.clusterThreshold&&1==this.constants.clustering.enabled&&this.clusterToFit(this.constants.clustering.reduceToNodes,!1),this._calculateForces())},_calculateForces:function(){this.barnesHutTree=void 0,this._calculateGravitationalForces(),this._calculateNodeForces(),this._calculateSpringForces()},_calculateGravitationalForces:function(){var t,e,i,n,s,o,r,a=this.nodes,h=this.constants.physics.centralGravity;for(r=0;ro;o++)t=e[i[o]],this._getForceContribution(s.root.children.NW,t),this._getForceContribution(s.root.children.NE,t),this._getForceContribution(s.root.children.SW,t),this._getForceContribution(s.root.children.SE,t)},_getForceContribution:function(t,e){if(t.childrenCount>0){var i,n,s;i=t.CenterOfMass.x-e.x,n=t.CenterOfMass.y-e.y,s=Math.sqrt(i*i+n*n),s>0&&(s*t.calcSizeh;h++){var l=e[i[h]].x,c=e[i[h]].y;s>l&&(s=l),l>r&&(r=l),o>c&&(o=c),c>a&&(a=c)}var d=Math.abs(r-s)-Math.abs(a-o);d>0?(o-=.5*d,a+=.5*d):(s+=.5*d,r-=.5*d);var u={root:{CenterOfMass:{x:0,y:0},mass:0,range:{minX:s,maxX:r,minY:o,maxY:a},size:Math.abs(r-s),calcSize:1/Math.abs(r-s),children:{data:null},maxWidth:0,level:0,childrenCount:4}};for(this._splitBranch(u.root),h=0;n>h;h++)t=e[i[h]],this._placeInTree(u.root,t);this.barnesHutTree=u},_updateBranchMass:function(t,e){var i=t.mass+e.mass,n=1/i;t.CenterOfMass.x=t.CenterOfMass.x*t.mass+e.x*e.mass,t.CenterOfMass.x*=n,t.CenterOfMass.y=t.CenterOfMass.y*t.mass+e.y*e.mass,t.CenterOfMass.y*=n,t.mass=i;var s=Math.max(Math.max(e.height,e.radius),e.width);t.maxWidth=t.maxWidthe.x?t.children.NW.range.maxY>e.y?this._placeInRegion(t,e,"NW"):this._placeInRegion(t,e,"SW"):t.children.NE.range.maxY>e.y?this._placeInRegion(t,e,"NE"):this._placeInRegion(t,e,"SE")},_placeInRegion:function(t,e,i){switch(t.children[i].childrenCount){case 0:t.children[i].children.data=e,t.children[i].childrenCount=1,this._updateBranchMass(t.children[i],e);break;case 1:this._splitBranch(t.children[i]),this._placeInTree(t.children[i],e);break;case 4:this._placeInTree(t.children[i],e)}},_splitBranch:function(t){var e=null;1==t.childrenCount&&(e=t.children.data,t.mass=0,t.CenterOfMass.x=0,t.CenterOfMass.y=0),t.childrenCount=4,t.children.data=null,this._insertRegion(t,"NW"),this._insertRegion(t,"NE"),this._insertRegion(t,"SW"),this._insertRegion(t,"SE"),null!=e&&this._placeInTree(t,e)},_insertRegion:function(t,e){var i,n,s,o;switch(e){case"NW":i=t.range.minX,n=t.range.minX+t.size,s=t.range.minY,o=t.range.minY+t.size;break;case"NE":i=t.range.minX+t.size,n=t.range.maxX,s=t.range.minY,o=t.range.minY+t.size;break;case"SW":i=t.range.minX,n=t.range.minX+t.size,s=t.range.minY+t.size,o=t.range.maxY;break;case"SE":i=t.range.minX+t.size,n=t.range.maxX,s=t.range.minY+t.size,o=t.range.maxY}t.children[e]={CenterOfMass:{x:0,y:0},mass:0,range:{minX:i,maxX:n,minY:s,maxY:o},size:.5*t.size,calcSize:2*t.calcSize,children:{data:null},maxWidth:0,level:t.level+1,childrenCount:0}},_drawTree:function(t,e){void 0!==this.barnesHutTree&&(t.lineWidth=1,this._drawBranch(this.barnesHutTree.root,t,e))},_drawBranch:function(t,e,i){void 0===i&&(i="#FF0000"),4==t.childrenCount&&(this._drawBranch(t.children.NW,e),this._drawBranch(t.children.NE,e),this._drawBranch(t.children.SE,e),this._drawBranch(t.children.SW,e)),e.strokeStyle=i,e.beginPath(),e.moveTo(t.range.minX,t.range.minY),e.lineTo(t.range.maxX,t.range.minY),e.stroke(),e.beginPath(),e.moveTo(t.range.maxX,t.range.minY),e.lineTo(t.range.maxX,t.range.maxY),e.stroke(),e.beginPath(),e.moveTo(t.range.maxX,t.range.maxY),e.lineTo(t.range.minX,t.range.maxY),e.stroke(),e.beginPath(),e.moveTo(t.range.minX,t.range.maxY),e.lineTo(t.range.minX,t.range.minY),e.stroke()}},repulsionMixin={_calculateNodeForces:function(){var t,e,i,n,s,o,r,a,h,l,c,d,u=this.nodes,p=-2/3,f=4/3,g=this.constants.nodes.distance;for(c=0;cn&&(i=Math.atan2(e,t),a=.5*g>n?1:m*n+f,a*=0==r?1:1+r*this.constants.clustering.forceAmplification,a*=h.internalMultiplier*l.internalMultiplier,s=Math.cos(i)*a,o=Math.sin(i)*a,h._addForce(-s,-o),l._addForce(s,o))}}},manipulationMixin={_clearManipulatorBar:function(){for(;this.manipulationDiv.hasChildNodes();)this.manipulationDiv.removeChild(this.manipulationDiv.firstChild)},_createManipulatorBar:function(){for(this.off("select",this.boundFunction),this.blockConnectingEdgeSelection=!1,this.forceAppendSelection=!1;this.manipulationDiv.hasChildNodes();)this.manipulationDiv.removeChild(this.manipulationDiv.firstChild);this.manipulationDiv.innerHTML="Add Node
    Edit Selected
    Connect Node
    Delete selected";var t=document.getElementById("manipulate-addNode");t.onclick=this._createAddToolbar.bind(this); +var e=document.getElementById("manipulate-editNode");e.onclick=this._createEditToolbar.bind(this);var i=document.getElementById("manipulate-connectNode");i.onclick=this._createConnectToolbar.bind(this);var n=document.getElementById("manipulate-delete");n.onclick=this._createDeletionToolbar.bind(this)},_createAddToolbar:function(){this._clearManipulatorBar(),this.off("select",this.boundFunction),this.manipulationDiv.innerHTML="Back
    Click in an empty space to place a new node";var t=document.getElementById("manipulate-back");t.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._addNode.bind(this),this.on("select",this.boundFunction)},_createEditToolbar:function(){this.blockConnectingEdgeSelection=!1,this._clearManipulatorBar(),this.off("select",this.boundFunction);var t="";if(this._selectionIsEmpty()?t="Select a node or edge to edit.":this._getSelectedObjectCount()>1?(t="Select a single node or edge to edit.",this._unselectAll(!0)):this._clusterInSelection()?(t="You cannot edit a cluster.",this._unselectAll(!0)):this._getSelectedNodeCount()>0?this._createEditNodeToolbar():this._createEditEdgeToolbar(),""!=t){this.blockConnectingEdgeSelection=!0,this.manipulationDiv.innerHTML="Back
    "+t+"";var e=document.getElementById("manipulate-back");e.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._createEditToolbar.bind(this),this.on("select",this.boundFunction)}},_createEditNodeToolbar:function(){this.blockConnectingEdgeSelection=!1,this._clearManipulatorBar(),this.off("select",this.boundFunction);var t=this._getEditObject();this.manipulationDiv.innerHTML="Cancel
    label:
    color:
    ";var e=document.getElementById("manipulate-back");e.onclick=this._createManipulatorBar.bind(this);var i=document.getElementById("manipulator-obj-save");i.onclick=this._saveNodeData.bind(this),this.boundFunction=this._createManipulatorBar.bind(this),this.on("select",this.boundFunction)},_saveNodeData:function(){var t=this._getEditObject().id,e=document.getElementById("manipulator-obj-label").value,i=document.getElementById("manipulator-obj-color").value,n=util.hexToHSV(i),s={h:n.h,s:.45*n.s,v:Math.min(1,1.05*n.v)},o={h:n.h,s:Math.min(1,1.25*n.v),v:.6*n.v},r=util.HSVToHex(o.h,o.h,o.v),a=util.HSVToHex(s.h,s.s,s.v),h={id:t,label:e,color:{background:i,border:r,highlight:{background:a,border:r}}};this.nodesData.update(h),this._createManipulatorBar()},_createEditEdgeToolbar:function(){this.blockConnectingEdgeSelection=!1,this._clearManipulatorBar(),this.off("select",this.boundFunction),this.manipulationDiv.innerHTML="Back
    Currently only nodes can be edited.";var t=document.getElementById("manipulate-back");t.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._createManipulatorBar.bind(this),this.on("select",this.boundFunction)},_createConnectToolbar:function(){this._clearManipulatorBar(),this.off("select",this.boundFunction),this._unselectAll(),this.forceAppendSelection=!1,this.blockConnectingEdgeSelection=!0,this.manipulationDiv.innerHTML="Back
    Select the node you want to connect to other nodes.";var t=document.getElementById("manipulate-back");t.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._handleConnect.bind(this),this.on("select",this.boundFunction)},_createDeletionToolbar:function(){if(this._clearManipulatorBar(),this.off("select",this.boundFunction),this._selectionIsEmpty()){this.manipulationDiv.innerHTML="Cannot delete an empty selection.";var t=this;window.setTimeout(function(){t._createManipulatorBar()},1500)}else{this.manipulationDiv.innerHTML="Back
    Are you sure? This cannot be undone.
    Yes.";var e=document.getElementById("manipulate-back");e.onclick=this._createManipulatorBar.bind(this);var i=document.getElementById("manipulate-acceptDelete");i.onclick=this._deleteSelected.bind(this),this.boundFunction=this._createManipulatorBar.bind(this),this.on("select",this.boundFunction)}},_handleConnect:function(){this.forceAppendSelection=!1,this._clusterInSelection()?(this._unselectClusters(!0),this._selectionIsEmpty()?this._setManipulationMessage("You cannot connect anything to a cluster."):(this._setManipulationMessage("You cannot connect a node to a cluster."),this.forceAppendSelection=!0)):this._selectionIsEmpty()?this._setManipulationMessage("Select the node you want to connect to other nodes."):2==this._getSelectedNodeCount()?(this._connectNodes(),this._restoreSourceNode(),this._setManipulationMessage("Click on another node you want to connect this node to or go back.")):(this._setManipulationMessage("Click on the node you want to connect this node."),this._setSourceNode(),this.forceAppendSelection=!0)},_getEditObject:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t))return this.selectionObj[t];return null},_setSourceNode:function(){for(var t in this.selectionObj)this.selectionObj.hasOwnProperty(t)&&this.selectionObj[t]instanceof Node&&(this.manipulationSourceNode=this.selectionObj[t])},_getTargetNode:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t)&&this.selectionObj[t]instanceof Node&&this.manipulationSourceNode.id!=this.selectionObj[t].id)return this.selectionObj[t];return null},_restoreSourceNode:function(){this._unselectAll(!0),this._selectObject(this.manipulationSourceNode)},_setManipulationMessage:function(t){var e=document.getElementById("manipulatorLabel");e.innerHTML=t},_addNode:function(){if(this._selectionIsEmpty()){var t=this._pointerToPositionObject(this.pointerPosition);this.createNodeOnClick=!0,this.nodesData.add({id:util.randomUUID(),x:t.left,y:t.top,label:"new",fixed:!1}),this.createNodeOnClick=!1,this.moving=!0,this.start()}},_connectNodes:function(){var t=this._getTargetNode(),e=this.manipulationSourceNode;this.edgesData.add({from:e.id,to:t.id}),this.moving=!0,this.start()},_deleteSelected:function(){if(this._clusterInSelection())alert("Clusters cannot be deleted.");else{var t=this.getSelectedNodes(),e=this.getSelectedEdges();this._removeEdges(e),this._removeNodes(t),this.moving=!0,this.start()}}},SectorMixin={_putDataInSector:function(){this.sectors.active[this._sector()].nodes=this.nodes,this.sectors.active[this._sector()].edges=this.edges,this.sectors.active[this._sector()].nodeIndices=this.nodeIndices},_switchToSector:function(t,e){void 0===e||"active"==e?this._switchToActiveSector(t):this._switchToFrozenSector(t)},_switchToActiveSector:function(t){this.nodeIndices=this.sectors.active[t].nodeIndices,this.nodes=this.sectors.active[t].nodes,this.edges=this.sectors.active[t].edges},_switchToFrozenSector:function(t){this.nodeIndices=this.sectors.frozen[t].nodeIndices,this.nodes=this.sectors.frozen[t].nodes,this.edges=this.sectors.frozen[t].edges},_switchToNavigationSector:function(){this.nodeIndices=this.sectors.navigation.nodeIndices,this.nodes=this.sectors.navigation.nodes,this.edges=this.sectors.navigation.edges},_loadLatestSector:function(){this._switchToSector(this._sector())},_sector:function(){return this.activeSector[this.activeSector.length-1]},_previousSector:function(){if(this.activeSector.length>1)return this.activeSector[this.activeSector.length-2];throw new TypeError("there are not enough sectors in the this.activeSector array.")},_setActiveSector:function(t){this.activeSector.push(t)},_forgetLastSector:function(){this.activeSector.pop()},_createNewSector:function(t){this.sectors.active[t]={nodes:{},edges:{},nodeIndices:[],formationScale:this.scale,drawingNode:void 0},this.sectors.active[t].drawingNode=new Node({id:t,color:{background:"#eaefef",border:"495c5e"}},{},{},this.constants),this.sectors.active[t].drawingNode.clusterSize=2},_deleteActiveSector:function(t){delete this.sectors.active[t]},_deleteFrozenSector:function(t){delete this.sectors.frozen[t]},_freezeSector:function(t){this.sectors.frozen[t]=this.sectors.active[t],this._deleteActiveSector(t)},_activateSector:function(t){this.sectors.active[t]=this.sectors.frozen[t],this._deleteFrozenSector(t)},_mergeThisWithFrozen:function(t){for(var e in this.nodes)this.nodes.hasOwnProperty(e)&&(this.sectors.frozen[t].nodes[e]=this.nodes[e]);for(var i in this.edges)this.edges.hasOwnProperty(i)&&(this.sectors.frozen[t].edges[i]=this.edges[i]);for(var n=0;n1?this[t](n[0],n[1]):this[t](e)}this._loadLatestSector()},_doInAllFrozenSectors:function(t,e){if(void 0===e)for(var i in this.sectors.frozen)this.sectors.frozen.hasOwnProperty(i)&&(this._switchToFrozenSector(i),this[t]());else for(var i in this.sectors.frozen)if(this.sectors.frozen.hasOwnProperty(i)){this._switchToFrozenSector(i);var n=Array.prototype.splice.call(arguments,1);n.length>1?this[t](n[0],n[1]):this[t](e)}this._loadLatestSector()},_doInNavigationSector:function(t,e){if(this._switchToNavigationSector(),void 0===e)this[t]();else{var i=Array.prototype.splice.call(arguments,1);i.length>1?this[t](i[0],i[1]):this[t](e)}this._loadLatestSector()},_doInAllSectors:function(t,e){var i=Array.prototype.splice.call(arguments,1);void 0===e?(this._doInAllActiveSectors(t),this._doInAllFrozenSectors(t)):i.length>1?(this._doInAllActiveSectors(t,i[0],i[1]),this._doInAllFrozenSectors(t,i[0],i[1])):(this._doInAllActiveSectors(t,e),this._doInAllFrozenSectors(t,e))},_clearNodeIndexList:function(){var t=this._sector();this.sectors.active[t].nodeIndices=[],this.nodeIndices=this.sectors.active[t].nodeIndices},_drawSectorNodes:function(t,e){var i,n=1e9,s=-1e9,o=1e9,r=-1e9;for(var a in this.sectors[e])if(this.sectors[e].hasOwnProperty(a)&&void 0!==this.sectors[e][a].drawingNode){this._switchToSector(a,e),n=1e9,s=-1e9,o=1e9,r=-1e9;for(var h in this.nodes)this.nodes.hasOwnProperty(h)&&(i=this.nodes[h],i.resize(t),o>i.x-.5*i.width&&(o=i.x-.5*i.width),ri.y-.5*i.height&&(n=i.y-.5*i.height),st&&n>s;)s%3==0?this.forceAggregateHubs():this.increaseClusterLevel(),i=this.nodeIndices.length,s+=1;s>1&&1==e&&this.repositionNodes()},openCluster:function(t){var e=this.moving;if(t.clusterSize>this.constants.clustering.sectorThreshold&&this._nodeInActiveArea(t)&&("default"!=this._sector()||1!=this.nodeIndices.length)){this._addSector(t);for(var i=0;this.nodeIndices.lengthi;)this.decreaseClusterLevel(),i+=1}else this._expandClusterNode(t,!1,!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels();this.moving!=e&&this.start()},updateClustersDefault:function(){1==this.constants.clustering.enabled&&this.updateClusters(0,!1,!1)},increaseClusterLevel:function(){this.updateClusters(-1,!1,!0)},decreaseClusterLevel:function(){this.updateClusters(1,!1,!0)},updateClusters:function(t,e,i){var n=this.moving,s=this.nodeIndices.length;this.previousScale>this.scale&&0==t&&this._collapseSector(),this.previousScale>this.scale||-1==t?this._formClusters(i):(this.previousScalethis.scale||-1==t)&&(this._aggregateHubs(i),this._updateNodeIndexList()),(this.previousScale>this.scale||-1==t)&&(this.handleChains(),this._updateNodeIndexList()),this.previousScale=this.scale,this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.lengththis.constants.clustering.chainThreshold&&this._reduceAmountOfChains(1-this.constants.clustering.chainThreshold/t)},_aggregateHubs:function(t){this._getHubSize(),this._formClustersByHub(t,!1)},forceAggregateHubs:function(){var t=this.moving,e=this.nodeIndices.length;this._aggregateHubs(!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.length!=e&&(this.clusterSession+=1),this.moving!=t&&this.start()},_openClustersBySize:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];1==e.inView()&&(e.width*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientWidth||e.height*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientHeight)&&this.openCluster(e)}},_openClusters:function(t,e){for(var i=0;i1&&(t.clusterSizei)){var r=o.from,a=o.to;o.to.mass>o.from.mass&&(r=o.to,a=o.from),1==a.dynamicEdgesLength?this._addToCluster(r,a,!1):1==r.dynamicEdgesLength&&this._addToCluster(a,r,!1)}}},_forceClustersByZoom:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];if(1==e.dynamicEdgesLength&&0!=e.dynamicEdges.length){var i=e.dynamicEdges[0],n=i.toId==e.id?this.nodes[i.fromId]:this.nodes[i.toId];e.id!=n.id&&(n.mass>e.mass?this._addToCluster(n,e,!0):this._addToCluster(e,n,!0))}}},_formClustersByHub:function(t,e){for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&this._formClusterFromHub(this.nodes[i],t,e)},_formClusterFromHub:function(t,e,i,n){if(void 0===n&&(n=0),t.dynamicEdgesLength>=this.hubThreshold&&0==i||t.dynamicEdgesLength==this.hubThreshold&&1==i){for(var s,o,r,a=this.constants.clustering.clusterEdgeThreshold/this.scale,h=!1,l=[],c=t.dynamicEdges.length,d=0;c>d;d++)l.push(t.dynamicEdges[d].id);if(0==e)for(h=!1,d=0;c>d;d++){var u=this.edges[l[d]];if(void 0!==u&&u.connected&&u.toId!=u.fromId&&(s=u.to.x-u.from.x,o=u.to.y-u.from.y,r=Math.sqrt(s*s+o*o),a>r)){h=!0;break}}if(!e&&h||e)for(d=0;c>d;d++)if(u=this.edges[l[d]],void 0!==u){var p=this.nodes[u.fromId==t.id?u.toId:u.fromId];p.dynamicEdges.length<=this.hubThreshold+n&&p.id!=t.id&&this._addToCluster(t,p,e)}}},_addToCluster:function(t,e,i){t.containedNodes[e.id]=e;for(var n=0;n1)for(var n=0;n1&&(e.label="[".concat(String(e.clusterSize),"]"))}for(t in this.nodes)this.nodes.hasOwnProperty(t)&&(e=this.nodes[t],1==e.clusterSize&&(e.label=void 0!==e.originalLabel?e.originalLabel:String(e.id)))},_nodeInActiveArea:function(t){return Math.abs(t.x-this.areaCenter.x)<=this.constants.clustering.activeAreaBoxSize/this.scale&&Math.abs(t.y-this.areaCenter.y)<=this.constants.clustering.activeAreaBoxSize/this.scale},repositionNodes:function(){for(var t=0;tn&&(n=o.dynamicEdgesLength),t+=o.dynamicEdgesLength,e+=Math.pow(o.dynamicEdgesLength,2),i+=1}t/=i,e/=i;var r=e-Math.pow(t,2),a=Math.sqrt(r);this.hubThreshold=Math.floor(t+2*a),this.hubThreshold>n&&(this.hubThreshold=n)},_reduceAmountOfChains:function(t){this.hubThreshold=2;var e=Math.floor(this.nodeIndices.length*t);for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&e>0&&(this._formClusterFromHub(this.nodes[i],!0,!0,1),e-=1)},_getChainFraction:function(){var t=0,e=0;for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&(2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&(t+=1),e+=1);return t/e}},SelectionMixin={_getNodesOverlappingWith:function(t,e){var i=this.nodes;for(var n in i)i.hasOwnProperty(n)&&i[n].isOverlappingWith(t)&&e.push(n)},_getAllNodesOverlappingWith:function(t){var e=[];return this._doInAllActiveSectors("_getNodesOverlappingWith",t,e),e},_getAllNavigationNodesOverlappingWith:function(t){var e=[];return this._doInNavigationSector("_getNodesOverlappingWith",t,e),e},_pointerToPositionObject:function(t){var e=this._canvasToX(t.x),i=this._canvasToY(t.y);return{left:e,top:i,right:e,bottom:i}},_pointerToScreenPositionObject:function(t){var e=t.x,i=t.y;return{left:e,top:i,right:e,bottom:i}},_getNavigationNodeAt:function(t){var e=this._pointerToScreenPositionObject(t),i=this._getAllNavigationNodesOverlappingWith(e);return i.length>0?this.sectors.navigation.nodes[i[i.length-1]]:null},_getNodeAt:function(t){var e=this._pointerToPositionObject(t),i=this._getAllNodesOverlappingWith(e);return i.length>0?this.nodes[i[i.length-1]]:null},_getEdgesOverlappingWith:function(t,e){var i=this.edges;for(var n in i)i.hasOwnProperty(n)&&i[n].isOverlappingWith(t)&&e.push(n)},_getAllEdgesOverlappingWith:function(t){var e=[];return this._doInAllActiveSectors("_getEdgesOverlappingWith",t,e),e},_getEdgeAt:function(t){var e=this._pointerToPositionObject(t),i=this._getAllEdgesOverlappingWith(e);return i.length>0?this.edges[i[i.length-1]]:null},_addToSelection:function(t){this.selectionObj[t.id]=t},_removeFromSelection:function(t){delete this.selectionObj[t.id]},_unselectAll:function(t){void 0===t&&(t=!1);for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e].unselect();this.selectionObj={},0==t&&this._trigger("select",this.getSelection())},_unselectClusters:function(t){void 0===t&&(t=!1);for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e]instanceof Node&&this.selectionObj[e].clusterSize>1&&(this.selectionObj[e].unselect(),this._removeFromSelection(this.selectionObj[e]));0==t&&this._trigger("select",this.getSelection())},_getSelectedNodeCount:function(){var t=0;for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e]instanceof Node&&(t+=1);return t},_getSelectedEdgeCount:function(){var t=0;for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e]instanceof Edge&&(t+=1);return t},_getSelectedObjectCount:function(){var t=0;for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&(t+=1);return t},_selectionIsEmpty:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t))return!1;return!0},_clusterInSelection:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t)&&this.selectionObj[t]instanceof Node&&this.selectionObj[t].clusterSize>1)return!0;return!1},_selectConnectedEdges:function(t){for(var e=0;ee;e++){n=t[e];var s=this.nodes[n];if(!s)throw new RangeError('Node with id "'+n+'" not found');this._selectObject(s,!0,!0)}this.redraw()},_updateSelection:function(){for(var t in this.selectionObj)this.selectionObj.hasOwnProperty(t)&&(this.selectionObj[t]instanceof Node?this.nodes.hasOwnProperty(t)||delete this.selectionObj[t]:this.edges.hasOwnProperty(t)||delete this.selectionObj[t])}},NavigationMixin={_relocateNavigation:function(){if(void 0!==this.sectors){var t=this.navigationClientWidth-this.frame.canvas.clientWidth,e=this.navigationClientHeight-this.frame.canvas.clientHeight;this.navigationClientWidth=this.frame.canvas.clientWidth,this.navigationClientHeight=this.frame.canvas.clientHeight;var i=null;for(var n in this.sectors.navigation.nodes)this.sectors.navigation.nodes.hasOwnProperty(n)&&(i=this.sectors.navigation.nodes[n],i.horizontalAlignLeft||(i.x-=t),i.verticalAlignTop||(i.y-=e))}},_loadNavigationElements:function(){var t=this.constants.navigation.iconPath;this.navigationClientWidth=this.frame.canvas.clientWidth,this.navigationClientHeight=this.frame.canvas.clientHeight,void 0===this.navigationClientWidth&&(this.navigationClientWidth=0,this.navigationClientHeight=0);for(var e=15,i=7,n=[{id:"navigation_up",shape:"image",image:t+"/uparrow.png",triggerFunction:"_moveUp",verticalAlignTop:!1,x:45+e+i,y:this.navigationClientHeight-45-e-i},{id:"navigation_down",shape:"image",image:t+"/downarrow.png",triggerFunction:"_moveDown",verticalAlignTop:!1,x:45+e+i,y:this.navigationClientHeight-15-e},{id:"navigation_left",shape:"image",image:t+"/leftarrow.png",triggerFunction:"_moveLeft",verticalAlignTop:!1,x:15+e,y:this.navigationClientHeight-15-e},{id:"navigation_right",shape:"image",image:t+"/rightarrow.png",triggerFunction:"_moveRight",verticalAlignTop:!1,x:75+e+2*i,y:this.navigationClientHeight-15-e},{id:"navigation_plus",shape:"image",image:t+"/plus.png",triggerFunction:"_zoomIn",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-45-e-i,y:this.navigationClientHeight-15-e},{id:"navigation_min",shape:"image",image:t+"/minus.png",triggerFunction:"_zoomOut",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-15-e,y:this.navigationClientHeight-15-e},{id:"navigation_zoomExtends",shape:"image",image:t+"/zoomExtends.png",triggerFunction:"zoomToFit",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-15-e,y:this.navigationClientHeight-45-e-i}],s=null,o=0;ot.x-t.width&&(n=t.x-t.width),st.y-t.height&&(e=t.y-t.height),i=this.constants.clustering.initialMaxNodes)var n=38.8467/(e-14.50184)+.0116;else var n=42.54117319/(e+39.31966387)+.1944405;else{var s=1.1*(Math.abs(i.minX)+Math.abs(i.maxX)),o=1.1*(Math.abs(i.minY)+Math.abs(i.maxY)),r=this.frame.canvas.clientWidth/s,a=this.frame.canvas.clientHeight/o;n=a>=r?r:a}n>1&&(n=1),this.pinch.mousewheelScale=n,this._setScale(n),this._centerGraph(i),this.start()},Graph.prototype._updateNodeIndexList=function(){this._clearNodeIndexList();for(var t in this.nodes)this.nodes.hasOwnProperty(t)&&this.nodeIndices.push(t)},Graph.prototype.setData=function(t,e){if(void 0===e&&(e=!1),t&&t.dot&&(t.nodes||t.edges))throw new SyntaxError('Data must contain either parameter "dot" or parameter pair "nodes" and "edges", but not both.');if(this.setOptions(t&&t.options),t&&t.dot){if(t&&t.dot){var i=vis.util.DOTToGraph(t.dot);return void this.setData(i)}}else this._setNodes(t&&t.nodes),this._setEdges(t&&t.edges);this._putDataInSector(),e||(this.stabilize&&this._doStabilize(),this.moving=!0,this.start())},Graph.prototype.setOptions=function(t){if(t){if(void 0!==t.width&&(this.width=t.width),void 0!==t.height&&(this.height=t.height),void 0!==t.stabilize&&(this.stabilize=t.stabilize),void 0!==t.selectable&&(this.selectable=t.selectable),t.clustering){this.constants.clustering.enabled=!0;for(var e in t.clustering)t.clustering.hasOwnProperty(e)&&(this.constants.clustering[e]=t.clustering[e])}else void 0!==t.clustering&&(this.constants.clustering.enabled=!1);if(t.navigation){this.constants.navigation.enabled=!0;for(var e in t.navigation)t.navigation.hasOwnProperty(e)&&(this.constants.navigation[e]=t.navigation[e])}else void 0!==t.navigation&&(this.constants.navigation.enabled=!1);if(t.keyboard){this.constants.keyboard.enabled=!0;for(var e in t.keyboard)t.keyboard.hasOwnProperty(e)&&(this.constants.keyboard[e]=t.keyboard[e])}else void 0!==t.keyboard&&(this.constants.keyboard.enabled=!1);if(t.dataManipulationToolbar){this.constants.dataManipulationToolbar.enabled=!0;for(var e in t.dataManipulationToolbar)t.dataManipulationToolbar.hasOwnProperty(e)&&(this.constants.dataManipulationToolbar[e]=t.dataManipulationToolbar[e])}else void 0!==t.dataManipulationToolbar&&(this.constants.dataManipulationToolbar.enabled=!1);if(t.edges){for(e in t.edges)t.edges.hasOwnProperty(e)&&(this.constants.edges[e]=t.edges[e]);void 0!==t.edges.length&&t.nodes&&void 0===t.nodes.distance&&(this.constants.edges.length=t.edges.length,this.constants.nodes.distance=1.25*t.edges.length),t.edges.fontColor||(this.constants.edges.fontColor=t.edges.color),t.edges.dash&&(void 0!==t.edges.dash.length&&(this.constants.edges.dash.length=t.edges.dash.length),void 0!==t.edges.dash.gap&&(this.constants.edges.dash.gap=t.edges.dash.gap),void 0!==t.edges.dash.altLength&&(this.constants.edges.dash.altLength=t.edges.dash.altLength))}if(t.nodes){for(e in t.nodes)t.nodes.hasOwnProperty(e)&&(this.constants.nodes[e]=t.nodes[e]);t.nodes.color&&(this.constants.nodes.color=Node.parseColor(t.nodes.color))}if(t.groups)for(var i in t.groups)if(t.groups.hasOwnProperty(i)){var n=t.groups[i];this.groups.add(i,n)}}this._loadPhysicsSystem(),this._loadNavigationControls(),this._loadManipulationSystem(),this._createKeyBinds(),this.setSize(this.width,this.height),this._setTranslation(this.frame.clientWidth/2,this.frame.clientHeight/2),this._setScale(1),this._redraw()},Graph.prototype.on=function(t,e){var i=["select"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());events.addListener(this,t,e)},Graph.prototype.off=function(t,e){events.removeListener(this,t,e)},Graph.prototype._trigger=function(t,e){events.trigger(this,t,e)},Graph.prototype._create=function(){for(;this.containerElement.hasChildNodes();)this.containerElement.removeChild(this.containerElement.firstChild);if(this.frame=document.createElement("div"),this.frame.className="graph-frame",this.frame.style.position="relative",this.frame.style.overflow="hidden",this.frame.style.zIndex="1",this.frame.canvas=document.createElement("canvas"),this.frame.canvas.style.position="relative",this.frame.appendChild(this.frame.canvas),!this.frame.canvas.getContext){var t=document.createElement("DIV");t.style.color="red",t.style.fontWeight="bold",t.style.padding="10px",t.innerHTML="Error: your browser does not support HTML canvas",this.frame.canvas.appendChild(t)}var e=this;this.drag={},this.pinch={},this.hammer=Hammer(this.frame.canvas,{prevent_default:!0}),this.hammer.on("tap",e._onTap.bind(e)),this.hammer.on("doubletap",e._onDoubleTap.bind(e)),this.hammer.on("hold",e._onHold.bind(e)),this.hammer.on("pinch",e._onPinch.bind(e)),this.hammer.on("touch",e._onTouch.bind(e)),this.hammer.on("dragstart",e._onDragStart.bind(e)),this.hammer.on("drag",e._onDrag.bind(e)),this.hammer.on("dragend",e._onDragEnd.bind(e)),this.hammer.on("release",e._onRelease.bind(e)),this.hammer.on("mousewheel",e._onMouseWheel.bind(e)),this.hammer.on("DOMMouseScroll",e._onMouseWheel.bind(e)),this.hammer.on("mousemove",e._onMouseMoveTitle.bind(e)),this.containerElement.appendChild(this.frame)},Graph.prototype._createKeyBinds=function(){var t=this;this.mousetrap=mousetrap,this.mousetrap.reset(),1==this.constants.keyboard.enabled&&(this.mousetrap.bind("up",this._moveUp.bind(t),"keydown"),this.mousetrap.bind("up",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("down",this._moveDown.bind(t),"keydown"),this.mousetrap.bind("down",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("left",this._moveLeft.bind(t),"keydown"),this.mousetrap.bind("left",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("right",this._moveRight.bind(t),"keydown"),this.mousetrap.bind("right",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("=",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("=",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("-",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("-",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("[",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("[",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("]",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("]",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pageup",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("pageup",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pagedown",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("pagedown",this._stopZoom.bind(t),"keyup")),this.mousetrap.bind("b",this._toggleBarnesHut.bind(t)),1==this.constants.dataManipulationToolbar.enabled&&this.mousetrap.bind("escape",this._createManipulatorBar.bind(t))},Graph.prototype._getPointer=function(t){return{x:t.pageX-vis.util.getAbsoluteLeft(this.frame.canvas),y:t.pageY-vis.util.getAbsoluteTop(this.frame.canvas)}},Graph.prototype._onTouch=function(t){this.drag.pointer=this._getPointer(t.gesture.touches[0]),this.drag.pinched=!1,this.pinch.scale=this._getScale(),this._handleTouch(this.drag.pointer)},Graph.prototype._onDragStart=function(){var t=this.drag,e=this._getNodeAt(t.pointer);if(t.dragging=!0,t.selection=[],t.translation=this._getTranslation(),t.nodeId=null,null!=e){t.nodeId=e.id,e.isSelected()||this._selectObject(e,!1);for(var i in this.selectionObj)if(this.selectionObj.hasOwnProperty(i)){var n=this.selectionObj[i];if(n instanceof Node){var s={id:n.id,node:n,x:n.x,y:n.y,xFixed:n.xFixed,yFixed:n.yFixed};n.xFixed=!0,n.yFixed=!0,t.selection.push(s)}}}},Graph.prototype._onDrag=function(t){if(!this.drag.pinched){var e=this._getPointer(t.gesture.touches[0]),i=this,n=this.drag,s=n.selection;if(s&&s.length){var o=e.x-n.pointer.x,r=e.y-n.pointer.y;s.forEach(function(t){var e=t.node;t.xFixed||(e.x=i._canvasToX(i._xToCanvas(t.x)+o)),t.yFixed||(e.y=i._canvasToY(i._yToCanvas(t.y)+r))}),this.moving||(this.moving=!0,this.start())}else{var a=e.x-this.drag.pointer.x,h=e.y-this.drag.pointer.y;this._setTranslation(this.drag.translation.x+a,this.drag.translation.y+h),this._redraw(),this.moved=!0}}},Graph.prototype._onDragEnd=function(){this.drag.dragging=!1;var t=this.drag.selection;t&&t.forEach(function(t){t.node.xFixed=t.xFixed,t.node.yFixed=t.yFixed})},Graph.prototype._onTap=function(t){var e=this._getPointer(t.gesture.touches[0]);this.pointerPosition=e,this._handleTap(e)},Graph.prototype._onDoubleTap=function(t){var e=this._getPointer(t.gesture.touches[0]);this._handleDoubleTap(e)},Graph.prototype._onHold=function(t){var e=this._getPointer(t.gesture.touches[0]);this.pointerPosition=e,this._handleOnHold(e)},Graph.prototype._onRelease=function(){this._handleOnRelease()},Graph.prototype._onPinch=function(t){var e=this._getPointer(t.gesture.center);this.drag.pinched=!0,"scale"in this.pinch||(this.pinch.scale=1);var i=this.pinch.scale*t.gesture.scale;this._zoom(i,e)},Graph.prototype._zoom=function(t,e){var i=this._getScale();1e-5>t&&(t=1e-5),t>10&&(t=10);var n=this._getTranslation(),s=t/i,o=(1-s)*e.x+n.x*s,r=(1-s)*e.y+n.y*s;return this.areaCenter={x:this._canvasToX(e.x),y:this._canvasToY(e.y)},this.pinch.mousewheelScale=t,this._setScale(t),this._setTranslation(o,r),this.updateClustersDefault(),this._redraw(),t},Graph.prototype._onMouseWheel=function(t){var e=0;if(t.wheelDelta?e=t.wheelDelta/120:t.detail&&(e=-t.detail/3),e){"mousewheelScale"in this.pinch||(this.pinch.mousewheelScale=1);var i=this.pinch.mousewheelScale,n=e/10;0>e&&(n/=1-n),i*=1+n;var s=util.fakeGesture(this,t),o=this._getPointer(s.center);i=this._zoom(i,o)}t.preventDefault()},Graph.prototype._onMouseMoveTitle=function(t){var e=util.fakeGesture(this,t),i=this._getPointer(e.center);this.popupNode&&this._checkHidePopup(i);var n=this,s=function(){n._checkShowPopup(i)};this.popupTimer&&clearInterval(this.popupTimer),this.drag.dragging||(this.popupTimer=setTimeout(s,300))},Graph.prototype._checkShowPopup=function(t){var e,i={left:this._canvasToX(t.x),top:this._canvasToY(t.y),right:this._canvasToX(t.x),bottom:this._canvasToY(t.y)},n=this.popupNode;if(void 0==this.popupNode){var s=this.nodes;for(e in s)if(s.hasOwnProperty(e)){var o=s[e];if(void 0!==o.getTitle()&&o.isOverlappingWith(i)){this.popupNode=o;break}}}if(void 0===this.popupNode){var r=this.edges;for(e in r)if(r.hasOwnProperty(e)){var a=r[e];if(a.connected&&void 0!==a.getTitle()&&a.isOverlappingWith(i)){this.popupNode=a;break}}}if(this.popupNode){if(this.popupNode!=n){var h=this;h.popup||(h.popup=new Popup(h.frame)),h.popup.setPosition(t.x-3,t.y-3),h.popup.setText(h.popupNode.getTitle()),h.popup.show()}}else this.popup&&this.popup.hide()},Graph.prototype._checkHidePopup=function(t){this.popupNode&&this._getNodeAt(t)||(this.popupNode=void 0,this.popup&&this.popup.hide())},Graph.prototype._getConnectionCount=function(t){function e(t){for(var e=[],i=0,n=t.length;n>i;i++)for(var s=t[i],o=s.edges,r=0,a=o.length;a>r;r++){var h=o[r],l=null;h.from==s?l=h.to:h.to==s&&(l=h.from);var c,d;if(l)for(c=0,d=t.length;d>c;c++)if(t[c]==l){l=null;break}if(l)for(c=0,d=e.length;d>c;c++)if(e[c]==l){l=null;break}l&&e.push(l)}return e}void 0==t&&(t=1);var i=[],n=this.nodes;for(var s in n)if(n.hasOwnProperty(s)){for(var o=[n[s]],r=0;t>r;r++)o=o.concat(e(o));i.push(o)}for(var a=[],h=0,l=i.length;l>h;h++)a.push(i[h].length);return a},Graph.prototype.setSize=function(t,e){this.frame.style.width=t,this.frame.style.height=e,this.frame.canvas.style.width="100%",this.frame.canvas.style.height="100%",this.frame.canvas.width=this.frame.canvas.clientWidth,this.frame.canvas.height=this.frame.canvas.clientHeight,void 0!==this.manipulationDiv&&(this.manipulationDiv.style.width=this.frame.canvas.clientWidth),1==this.constants.navigation.enabled&&this._relocateNavigation()},Graph.prototype._setNodes=function(t){var e=this.nodesData;if(t instanceof DataSet||t instanceof DataView)this.nodesData=t;else if(t instanceof Array)this.nodesData=new DataSet,this.nodesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.nodesData=new DataSet}if(e&&util.forEach(this.nodesListeners,function(t,i){e.unsubscribe(i,t)}),this.nodes={},this.nodesData){var i=this;util.forEach(this.nodesListeners,function(t,e){i.nodesData.subscribe(e,t)});var n=this.nodesData.getIds();this._addNodes(n)}this._updateSelection()},Graph.prototype._addNodes=function(t){for(var e,i=0,n=t.length;n>i;i++){e=t[i];var s=this.nodesData.get(e),o=new Node(s,this.images,this.groups,this.constants);if(this.nodes[e]=o,!o.isFixed()&&1!=this.createNodeOnClick){var r=this.constants.edges.length,a=t.length,h=2*Math.PI*(i/a);o.x=r*Math.cos(h),o.y=r*Math.sin(h),this.moving=!0}}this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(this.nodes),this.updateLabels()},Graph.prototype._updateNodes=function(t){for(var e=this.nodes,i=this.nodesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o],a=i.get(o);r?r.setProperties(a,this.constants):(r=new Node(properties,this.images,this.groups,this.constants),e[o]=r,r.isFixed()||(this.moving=!0))}this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(e)},Graph.prototype._removeNodes=function(t){for(var e=this.nodes,i=0,n=t.length;n>i;i++){var s=t[i];delete e[s]}this._updateNodeIndexList(),this._reconnectEdges(),this._updateSelection(),this._updateValueRange(e)},Graph.prototype._setEdges=function(t){var e=this.edgesData;if(t instanceof DataSet||t instanceof DataView)this.edgesData=t;else if(t instanceof Array)this.edgesData=new DataSet,this.edgesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.edgesData=new DataSet}if(e&&util.forEach(this.edgesListeners,function(t,i){e.unsubscribe(i,t)}),this.edges={},this.edgesData){var i=this;util.forEach(this.edgesListeners,function(t,e){i.edgesData.subscribe(e,t)});var n=this.edgesData.getIds();this._addEdges(n)}this._reconnectEdges()},Graph.prototype._addEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o];r&&r.disconnect();var a=i.get(o,{showInternalIds:!0});e[o]=new Edge(a,this,this.constants)}this.moving=!0,this._updateValueRange(e)},Graph.prototype._updateEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=i.get(o),a=e[o];a?(a.disconnect(),a.setProperties(r,this.constants),a.connect()):(a=new Edge(r,this,this.constants),this.edges[o]=a)}this.moving=!0,this._updateValueRange(e)},Graph.prototype._removeEdges=function(t){for(var e=this.edges,i=0,n=t.length;n>i;i++){var s=t[i],o=e[s];o&&(o.disconnect(),delete e[s])}this.moving=!0,this._updateValueRange(e)},Graph.prototype._reconnectEdges=function(){var t,e=this.nodes,i=this.edges;for(t in e)e.hasOwnProperty(t)&&(e[t].edges=[]);for(t in i)if(i.hasOwnProperty(t)){var n=i[t];n.from=null,n.to=null,n.connect()}},Graph.prototype._updateValueRange=function(t){var e,i=void 0,n=void 0;for(e in t)if(t.hasOwnProperty(e)){var s=t[e].getValue();void 0!==s&&(i=void 0===i?s:Math.min(s,i),n=void 0===n?s:Math.max(s,n))}if(void 0!==i&&void 0!==n)for(e in t)t.hasOwnProperty(e)&&t[e].setValueRange(i,n)},Graph.prototype.redraw=function(){this.setSize(this.width,this.height),this._redraw()},Graph.prototype._redraw=function(){var t=this.frame.canvas.getContext("2d"),e=this.frame.canvas.width,i=this.frame.canvas.height;t.clearRect(0,0,e,i),t.save(),t.translate(this.translation.x,this.translation.y),t.scale(this.scale,this.scale),this.canvasTopLeft={x:this._canvasToX(0),y:this._canvasToY(0)},this.canvasBottomRight={x:this._canvasToX(this.frame.canvas.clientWidth),y:this._canvasToY(this.frame.canvas.clientHeight)},this._doInAllSectors("_drawAllSectorNodes",t),this._doInAllSectors("_drawEdges",t),this._doInAllSectors("_drawNodes",t,!0),t.restore(),1==this.constants.navigation.enabled&&this._doInNavigationSector("_drawNodes",t,!0)},Graph.prototype._setTranslation=function(t,e){void 0===this.translation&&(this.translation={x:0,y:0}),void 0!==t&&(this.translation.x=t),void 0!==e&&(this.translation.y=e)},Graph.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},Graph.prototype._setScale=function(t){this.scale=t},Graph.prototype._getScale=function(){return this.scale},Graph.prototype._canvasToX=function(t){return(t-this.translation.x)/this.scale},Graph.prototype._xToCanvas=function(t){return t*this.scale+this.translation.x},Graph.prototype._canvasToY=function(t){return(t-this.translation.y)/this.scale},Graph.prototype._yToCanvas=function(t){return t*this.scale+this.translation.y},Graph.prototype._drawNodes=function(t,e){void 0===e&&(e=!1);var i=this.nodes,n=[];for(var s in i)i.hasOwnProperty(s)&&(i[s].setScaleAndPos(this.scale,this.canvasTopLeft,this.canvasBottomRight),i[s].isSelected()?n.push(s):(i[s].inArea()||e)&&i[s].draw(t));for(var o=0,r=n.length;r>o;o++)(i[n[o]].inArea()||e)&&i[n[o]].draw(t)},Graph.prototype._drawEdges=function(t){var e=this.edges;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];n.setScale(this.scale),n.connected&&e[i].draw(t)}},Graph.prototype._doStabilize=function(){for(var t=0,e=this.constants.minVelocity,i=!1;!i&&t0)for(var i in e)e.hasOwnProperty(i)&&e[i].discreteStepLimited(t,this.constants.maxVelocity);else for(var i in e)e.hasOwnProperty(i)&&e[i].discreteStep(t);var n=this.constants.minVelocity;this.moving=this._isMoving(n)},Graph.prototype.start=function(){if(!this.freezeSimulation)if(this.moving&&(this._doInAllActiveSectors("_initializeForceCalculation"),this._doInAllActiveSectors("_discreteStepNodes"),this._findCenter(this._getRange())),this.moving||0!=this.xIncrement||0!=this.yIncrement||0!=this.zoomIncrement){if(!this.timer){var t=this;this.timer=window.setTimeout(function(){if(t.timer=void 0,0!=t.xIncrement||0!=t.yIncrement){var e=t._getTranslation();t._setTranslation(e.x+t.xIncrement,e.y+t.yIncrement)}if(0!=t.zoomIncrement){var i={x:t.frame.canvas.clientWidth/2,y:t.frame.canvas.clientHeight/2};t._zoom(t.scale*(1+t.zoomIncrement),i)}var n=Date.now();t.start(),t.start();var s=(Date.now()-n,Date.now());t._redraw();Date.now()-s},this.renderTimestep)}}else this._redraw()},Graph.prototype.singleStep=function(){if(this.moving){this._initializeForceCalculation(),this._discreteStepNodes();var t=this.constants.minVelocity;this.moving=this._isMoving(t),this._redraw()}},Graph.prototype.toggleFreeze=function(){0==this.freezeSimulation?this.freezeSimulation=!0:(this.freezeSimulation=!1,this.start())},Graph.prototype._initializeMixinLoaders=function(){for(var t in graphMixinLoaders)graphMixinLoaders.hasOwnProperty(t)&&(Graph.prototype[t]=graphMixinLoaders[t])};var vis={util:util,events:events,Controller:Controller,DataSet:DataSet,DataView:DataView,Range:Range,Stack:Stack,TimeStep:TimeStep,EventBus:EventBus,components:{items:{Item:Item,ItemBox:ItemBox,ItemPoint:ItemPoint,ItemRange:ItemRange},Component:Component,Panel:Panel,RootPanel:RootPanel,ItemSet:ItemSet,TimeAxis:TimeAxis},graph:{Node:Node,Edge:Edge,Popup:Popup,Groups:Groups,Images:Images},Timeline:Timeline,Graph:Graph};"undefined"!=typeof exports&&(exports=vis),"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=vis),"function"==typeof define&&define(function(){return vis}),"undefined"!=typeof window&&(window.vis=vis)},{hammerjs:2,moment:3,mousetrap:4}],2:[function(t,e){!function(t,i){"use strict";function n(){if(!s.READY){s.event.determineEventTypes();for(var t in s.gestures)s.gestures.hasOwnProperty(t)&&s.detection.register(s.gestures[t]);s.event.onTouch(s.DOCUMENT,s.EVENT_MOVE,s.detection.detect),s.event.onTouch(s.DOCUMENT,s.EVENT_END,s.detection.detect),s.READY=!0}}var s=function(t,e){return new s.Instance(t,e||{})};s.defaults={stop_browser_behavior:{userSelect:"none",touchAction:"none",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}},s.HAS_POINTEREVENTS=navigator.pointerEnabled||navigator.msPointerEnabled,s.HAS_TOUCHEVENTS="ontouchstart"in t,s.MOBILE_REGEX=/mobile|tablet|ip(ad|hone|od)|android/i,s.NO_MOUSEEVENTS=s.HAS_TOUCHEVENTS&&navigator.userAgent.match(s.MOBILE_REGEX),s.EVENT_TYPES={},s.DIRECTION_DOWN="down",s.DIRECTION_LEFT="left",s.DIRECTION_UP="up",s.DIRECTION_RIGHT="right",s.POINTER_MOUSE="mouse",s.POINTER_TOUCH="touch",s.POINTER_PEN="pen",s.EVENT_START="start",s.EVENT_MOVE="move",s.EVENT_END="end",s.DOCUMENT=document,s.plugins={},s.READY=!1,s.Instance=function(t,e){var i=this;return n(),this.element=t,this.enabled=!0,this.options=s.utils.extend(s.utils.extend({},s.defaults),e||{}),this.options.stop_browser_behavior&&s.utils.stopDefaultBrowserBehavior(this.element,this.options.stop_browser_behavior),s.event.onTouch(t,s.EVENT_START,function(t){i.enabled&&s.detection.startDetect(i,t)}),this},s.Instance.prototype={on:function(t,e){for(var i=t.split(" "),n=0;n0&&e==s.EVENT_END?e=s.EVENT_MOVE:c||(e=s.EVENT_END),c||null===o?o=h:h=o,i.call(s.detection,n.collectEventData(t,e,h)),s.HAS_POINTEREVENTS&&e==s.EVENT_END&&(c=s.PointerEvent.updatePointer(e,h))),c||(o=null,r=!1,a=!1,s.PointerEvent.reset())}})},determineEventTypes:function(){var t;t=s.HAS_POINTEREVENTS?s.PointerEvent.getEvents():s.NO_MOUSEEVENTS?["touchstart","touchmove","touchend touchcancel"]:["touchstart mousedown","touchmove mousemove","touchend touchcancel mouseup"],s.EVENT_TYPES[s.EVENT_START]=t[0],s.EVENT_TYPES[s.EVENT_MOVE]=t[1],s.EVENT_TYPES[s.EVENT_END]=t[2]},getTouchList:function(t){return s.HAS_POINTEREVENTS?s.PointerEvent.getTouchList():t.touches?t.touches:[{identifier:1,pageX:t.pageX,pageY:t.pageY,target:t.target}]},collectEventData:function(t,e,i){var n=this.getTouchList(i,e),o=s.POINTER_TOUCH;return(i.type.match(/mouse/)||s.PointerEvent.matchType(s.POINTER_MOUSE,i))&&(o=s.POINTER_MOUSE),{center:s.utils.getCenter(n),timeStamp:(new Date).getTime(),target:i.target,touches:n,eventType:e,pointerType:o,srcEvent:i,preventDefault:function(){this.srcEvent.preventManipulation&&this.srcEvent.preventManipulation(),this.srcEvent.preventDefault&&this.srcEvent.preventDefault()},stopPropagation:function(){this.srcEvent.stopPropagation()},stopDetect:function(){return s.detection.stopDetect()}}}},s.PointerEvent={pointers:{},getTouchList:function(){var t=this,e=[];return Object.keys(t.pointers).sort().forEach(function(i){e.push(t.pointers[i])}),e},updatePointer:function(t,e){return t==s.EVENT_END?this.pointers={}:(e.identifier=e.pointerId,this.pointers[e.pointerId]=e),Object.keys(this.pointers).length},matchType:function(t,e){if(!e.pointerType)return!1;var i={};return i[s.POINTER_MOUSE]=e.pointerType==e.MSPOINTER_TYPE_MOUSE||e.pointerType==s.POINTER_MOUSE,i[s.POINTER_TOUCH]=e.pointerType==e.MSPOINTER_TYPE_TOUCH||e.pointerType==s.POINTER_TOUCH,i[s.POINTER_PEN]=e.pointerType==e.MSPOINTER_TYPE_PEN||e.pointerType==s.POINTER_PEN,i[t]},getEvents:function(){return["pointerdown MSPointerDown","pointermove MSPointerMove","pointerup pointercancel MSPointerUp MSPointerCancel"]},reset:function(){this.pointers={}}},s.utils={extend:function(t,e,n){for(var s in e)t[s]!==i&&n||(t[s]=e[s]);return t},hasParent:function(t,e){for(;t;){if(t==e)return!0;t=t.parentNode}return!1},getCenter:function(t){for(var e=[],i=[],n=0,s=t.length;s>n;n++)e.push(t[n].pageX),i.push(t[n].pageY);return{pageX:(Math.min.apply(Math,e)+Math.max.apply(Math,e))/2,pageY:(Math.min.apply(Math,i)+Math.max.apply(Math,i))/2}},getVelocity:function(t,e,i){return{x:Math.abs(e/t)||0,y:Math.abs(i/t)||0}},getAngle:function(t,e){var i=e.pageY-t.pageY,n=e.pageX-t.pageX;return 180*Math.atan2(i,n)/Math.PI},getDirection:function(t,e){var i=Math.abs(t.pageX-e.pageX),n=Math.abs(t.pageY-e.pageY);return i>=n?t.pageX-e.pageX>0?s.DIRECTION_LEFT:s.DIRECTION_RIGHT:t.pageY-e.pageY>0?s.DIRECTION_UP:s.DIRECTION_DOWN},getDistance:function(t,e){var i=e.pageX-t.pageX,n=e.pageY-t.pageY;return Math.sqrt(i*i+n*n)},getScale:function(t,e){return t.length>=2&&e.length>=2?this.getDistance(e[0],e[1])/this.getDistance(t[0],t[1]):1},getRotation:function(t,e){return t.length>=2&&e.length>=2?this.getAngle(e[1],e[0])-this.getAngle(t[1],t[0]):0},isVertical:function(t){return t==s.DIRECTION_UP||t==s.DIRECTION_DOWN},stopDefaultBrowserBehavior:function(t,e){var i,n=["webkit","khtml","moz","ms","o",""];if(e&&t.style){for(var s=0;si;i++){var o=this.gestures[i];if(!this.stopped&&e[o.name]!==!1&&o.handler.call(o,t,this.current.inst)===!1){this.stopDetect();break}}return this.current&&(this.current.lastEvent=t),t.eventType==s.EVENT_END&&!t.touches.length-1&&this.stopDetect(),t}},stopDetect:function(){this.previous=s.utils.extend({},this.current),this.current=null,this.stopped=!0},extendEventData:function(t){var e=this.current.startEvent;if(e&&(t.touches.length!=e.touches.length||t.touches===e.touches)){e.touches=[];for(var i=0,n=t.touches.length;n>i;i++)e.touches.push(s.utils.extend({},t.touches[i]))}var o=t.timeStamp-e.timeStamp,r=t.center.pageX-e.center.pageX,a=t.center.pageY-e.center.pageY,h=s.utils.getVelocity(o,r,a);return s.utils.extend(t,{deltaTime:o,deltaX:r,deltaY:a,velocityX:h.x,velocityY:h.y,distance:s.utils.getDistance(e.center,t.center),angle:s.utils.getAngle(e.center,t.center),direction:s.utils.getDirection(e.center,t.center),scale:s.utils.getScale(e.touches,t.touches),rotation:s.utils.getRotation(e.touches,t.touches),startEvent:e}),t},register:function(t){var e=t.defaults||{};return e[t.name]===i&&(e[t.name]=!0),s.utils.extend(s.defaults,e,!0),t.index=t.index||1e3,this.gestures.push(t),this.gestures.sort(function(t,e){return t.indexe.index?1:0}),this.gestures}},s.gestures=s.gestures||{},s.gestures.Hold={name:"hold",index:10,defaults:{hold_timeout:500,hold_threshold:1},timer:null,handler:function(t,e){switch(t.eventType){case s.EVENT_START:clearTimeout(this.timer),s.detection.current.name=this.name,this.timer=setTimeout(function(){"hold"==s.detection.current.name&&e.trigger("hold",t)},e.options.hold_timeout);break;case s.EVENT_MOVE:t.distance>e.options.hold_threshold&&clearTimeout(this.timer); +break;case s.EVENT_END:clearTimeout(this.timer)}}},s.gestures.Tap={name:"tap",index:100,defaults:{tap_max_touchtime:250,tap_max_distance:10,tap_always:!0,doubletap_distance:20,doubletap_interval:300},handler:function(t,e){if(t.eventType==s.EVENT_END){var i=s.detection.previous,n=!1;if(t.deltaTime>e.options.tap_max_touchtime||t.distance>e.options.tap_max_distance)return;i&&"tap"==i.name&&t.timeStamp-i.lastEvent.timeStamp0&&t.touches.length>e.options.swipe_max_touches)return;(t.velocityX>e.options.swipe_velocity||t.velocityY>e.options.swipe_velocity)&&(e.trigger(this.name,t),e.trigger(this.name+t.direction,t))}}},s.gestures.Drag={name:"drag",index:50,defaults:{drag_min_distance:10,drag_max_touches:1,drag_block_horizontal:!1,drag_block_vertical:!1,drag_lock_to_axis:!1,drag_lock_min_distance:25},triggered:!1,handler:function(t,e){if(s.detection.current.name!=this.name&&this.triggered)return e.trigger(this.name+"end",t),void(this.triggered=!1);if(!(e.options.drag_max_touches>0&&t.touches.length>e.options.drag_max_touches))switch(t.eventType){case s.EVENT_START:this.triggered=!1;break;case s.EVENT_MOVE:if(t.distancee.options.transform_min_rotation&&e.trigger("rotate",t),i>e.options.transform_min_scale&&(e.trigger("pinch",t),e.trigger("pinch"+(t.scale<1?"in":"out"),t));break;case s.EVENT_END:this.triggered&&e.trigger(this.name+"end",t),this.triggered=!1}}},s.gestures.Touch={name:"touch",index:-1/0,defaults:{prevent_default:!1,prevent_mouseevents:!1},handler:function(t,e){return e.options.prevent_mouseevents&&t.pointerType==s.POINTER_MOUSE?void t.stopDetect():(e.options.prevent_default&&t.preventDefault(),void(t.eventType==s.EVENT_START&&e.trigger(this.name,t)))}},s.gestures.Release={name:"release",index:1/0,handler:function(t,e){t.eventType==s.EVENT_END&&e.trigger(this.name,t)}},"object"==typeof e&&"object"==typeof e.exports?e.exports=s:(t.Hammer=s,"function"==typeof t.define&&t.define.amd&&t.define("hammer",[],function(){return s}))}(this)},{}],3:[function(t,e){(function(i){function n(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function s(t,e){return function(i){return u(t.call(this,i),e)}}function o(t,e){return function(i){return this.lang().ordinal(t.call(this,i),e)}}function r(){}function a(t){E(t),l(this,t)}function h(t){var e=y(t),i=e.year||0,n=e.month||0,s=e.week||0,o=e.day||0,r=e.hour||0,a=e.minute||0,h=e.second||0,l=e.millisecond||0;this._milliseconds=+l+1e3*h+6e4*a+36e5*r,this._days=+o+7*s,this._months=+n+12*i,this._data={},this._bubble()}function l(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return e.hasOwnProperty("toString")&&(t.toString=e.toString),e.hasOwnProperty("valueOf")&&(t.valueOf=e.valueOf),t}function c(t){var e,i={};for(e in t)t.hasOwnProperty(e)&&ye.hasOwnProperty(e)&&(i[e]=t[e]);return i}function d(t){return 0>t?Math.ceil(t):Math.floor(t)}function u(t,e,i){for(var n=""+Math.abs(t),s=t>=0;n.lengthn;n++)(i&&t[n]!==e[n]||!i&&b(t[n])!==b(e[n]))&&r++;return r+o}function v(t){if(t){var e=t.toLowerCase().replace(/(.)s$/,"$1");t=Xe[t]||qe[e]||e}return t}function y(t){var e,i,n={};for(i in t)t.hasOwnProperty(i)&&(e=v(i),e&&(n[e]=t[i]));return n}function _(t){var e,n;if(0===t.indexOf("week"))e=7,n="day";else{if(0!==t.indexOf("month"))return;e=12,n="month"}oe[t]=function(s,o){var r,a,h=oe.fn._lang[t],l=[];if("number"==typeof s&&(o=s,s=i),a=function(t){var e=oe().utc().set(n,t);return h.call(oe.fn._lang,e,s||"")},null!=o)return a(o);for(r=0;e>r;r++)l.push(a(r));return l}}function b(t){var e=+t,i=0;return 0!==e&&isFinite(e)&&(i=e>=0?Math.floor(e):Math.ceil(e)),i}function w(t,e){return new Date(Date.UTC(t,e+1,0)).getUTCDate()}function S(t){return T(t)?366:365}function T(t){return t%4===0&&t%100!==0||t%400===0}function E(t){var e;t._a&&-2===t._pf.overflow&&(e=t._a[de]<0||t._a[de]>11?de:t._a[ue]<1||t._a[ue]>w(t._a[ce],t._a[de])?ue:t._a[pe]<0||t._a[pe]>23?pe:t._a[fe]<0||t._a[fe]>59?fe:t._a[ge]<0||t._a[ge]>59?ge:t._a[me]<0||t._a[me]>999?me:-1,t._pf._overflowDayOfYear&&(ce>e||e>ue)&&(e=ue),t._pf.overflow=e)}function x(t){return null==t._isValid&&(t._isValid=!isNaN(t._d.getTime())&&t._pf.overflow<0&&!t._pf.empty&&!t._pf.invalidMonth&&!t._pf.nullInput&&!t._pf.invalidFormat&&!t._pf.userInvalidated,t._strict&&(t._isValid=t._isValid&&0===t._pf.charsLeftOver&&0===t._pf.unusedTokens.length)),t._isValid}function C(t){return t?t.toLowerCase().replace("_","-"):t}function M(t,e){return e._isUTC?oe(t).zone(e._offset||0):oe(t).local()}function D(t,e){return e.abbr=t,ve[t]||(ve[t]=new r),ve[t].set(e),ve[t]}function I(t){delete ve[t]}function N(e){var i,n,s,o,r=0,a=function(e){if(!ve[e]&&_e)try{t("./lang/"+e)}catch(i){}return ve[e]};if(!e)return oe.fn._lang;if(!f(e)){if(n=a(e))return n;e=[e]}for(;r0;){if(n=a(o.slice(0,i).join("-")))return n;if(s&&s.length>=i&&m(o,s,!0)>=i-1)break;i--}r++}return oe.fn._lang}function O(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function L(t){var e,i,n=t.match(Te);for(e=0,i=n.length;i>e;e++)n[e]=Qe[n[e]]?Qe[n[e]]:O(n[e]);return function(s){var o="";for(e=0;i>e;e++)o+=n[e]instanceof Function?n[e].call(s,t):n[e];return o}}function k(t,e){return t.isValid()?(e=A(e,t.lang()),Ze[e]||(Ze[e]=L(e)),Ze[e](t)):t.lang().invalidDate()}function A(t,e){function i(t){return e.longDateFormat(t)||t}var n=5;for(Ee.lastIndex=0;n>=0&&Ee.test(t);)t=t.replace(Ee,i),Ee.lastIndex=0,n-=1;return t}function P(t,e){var i,n=e._strict;switch(t){case"DDDD":return ze;case"YYYY":case"GGGG":case"gggg":return n?Fe:Me;case"Y":case"G":case"g":return Ye;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return n?Re:De;case"S":if(n)return Ae;case"SS":if(n)return Pe;case"SSS":if(n)return ze;case"DDD":return Ce;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Ne;case"a":case"A":return N(e._l)._meridiemParse;case"X":return ke;case"Z":case"ZZ":return Oe;case"T":return Le;case"SSSS":return Ie;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return n?Pe:xe;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return xe;default:return i=new RegExp(j(G(t.replace("\\","")),"i"))}}function z(t){t=t||"";var e=t.match(Oe)||[],i=e[e.length-1]||[],n=(i+"").match(Ue)||["-",0,0],s=+(60*n[1])+b(n[2]);return"+"===n[0]?-s:s}function F(t,e,i){var n,s=i._a;switch(t){case"M":case"MM":null!=e&&(s[de]=b(e)-1);break;case"MMM":case"MMMM":n=N(i._l).monthsParse(e),null!=n?s[de]=n:i._pf.invalidMonth=e;break;case"D":case"DD":null!=e&&(s[ue]=b(e));break;case"DDD":case"DDDD":null!=e&&(i._dayOfYear=b(e));break;case"YY":s[ce]=b(e)+(b(e)>68?1900:2e3);break;case"YYYY":case"YYYYY":case"YYYYYY":s[ce]=b(e);break;case"a":case"A":i._isPm=N(i._l).isPM(e);break;case"H":case"HH":case"h":case"hh":s[pe]=b(e);break;case"m":case"mm":s[fe]=b(e);break;case"s":case"ss":s[ge]=b(e);break;case"S":case"SS":case"SSS":case"SSSS":s[me]=b(1e3*("0."+e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,i._tzm=z(e);break;case"w":case"ww":case"W":case"WW":case"d":case"dd":case"ddd":case"dddd":case"e":case"E":t=t.substr(0,1);case"gg":case"gggg":case"GG":case"GGGG":case"GGGGG":t=t.substr(0,2),e&&(i._w=i._w||{},i._w[t]=e)}}function R(t){var e,i,n,s,o,r,a,h,l,c,d=[];if(!t._d){for(n=H(t),t._w&&null==t._a[ue]&&null==t._a[de]&&(o=function(e){var i=parseInt(e,10);return e?e.length<3?i>68?1900+i:2e3+i:i:null==t._a[ce]?oe().weekYear():t._a[ce]},r=t._w,null!=r.GG||null!=r.W||null!=r.E?a=J(o(r.GG),r.W||1,r.E,4,1):(h=N(t._l),l=null!=r.d?Z(r.d,h):null!=r.e?parseInt(r.e,10)+h._week.dow:0,c=parseInt(r.w,10)||1,null!=r.d&&lS(s)&&(t._pf._overflowDayOfYear=!0),i=q(s,0,t._dayOfYear),t._a[de]=i.getUTCMonth(),t._a[ue]=i.getUTCDate()),e=0;3>e&&null==t._a[e];++e)t._a[e]=d[e]=n[e];for(;7>e;e++)t._a[e]=d[e]=null==t._a[e]?2===e?1:0:t._a[e];d[pe]+=b((t._tzm||0)/60),d[fe]+=b((t._tzm||0)%60),t._d=(t._useUTC?q:X).apply(null,d)}}function Y(t){var e;t._d||(e=y(t._i),t._a=[e.year,e.month,e.day,e.hour,e.minute,e.second,e.millisecond],R(t))}function H(t){var e=new Date;return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function W(t){t._a=[],t._pf.empty=!0;var e,i,n,s,o,r=N(t._l),a=""+t._i,h=a.length,l=0;for(n=A(t._f,r).match(Te)||[],e=0;e0&&t._pf.unusedInput.push(o),a=a.slice(a.indexOf(i)+i.length),l+=i.length),Qe[s]?(i?t._pf.empty=!1:t._pf.unusedTokens.push(s),F(s,i,t)):t._strict&&!i&&t._pf.unusedTokens.push(s);t._pf.charsLeftOver=h-l,a.length>0&&t._pf.unusedInput.push(a),t._isPm&&t._a[pe]<12&&(t._a[pe]+=12),t._isPm===!1&&12===t._a[pe]&&(t._a[pe]=0),R(t),E(t)}function G(t){return t.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,i,n,s){return e||i||n||s})}function j(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function U(t){var e,i,s,o,r;if(0===t._f.length)return t._pf.invalidFormat=!0,void(t._d=new Date(0/0));for(o=0;or)&&(s=r,i=e));l(t,i||e)}function B(t){var e,i,n=t._i,s=He.exec(n);if(s){for(t._pf.iso=!0,e=0,i=Ge.length;i>e;e++)if(Ge[e][1].exec(n)){t._f=Ge[e][0]+(s[6]||" ");break}for(e=0,i=je.length;i>e;e++)if(je[e][1].exec(n)){t._f+=je[e][0];break}n.match(Oe)&&(t._f+="Z"),W(t)}else t._d=new Date(n)}function V(t){var e=t._i,n=be.exec(e);e===i?t._d=new Date:n?t._d=new Date(+n[1]):"string"==typeof e?B(t):f(e)?(t._a=e.slice(0),R(t)):g(e)?t._d=new Date(+e):"object"==typeof e?Y(t):t._d=new Date(e)}function X(t,e,i,n,s,o,r){var a=new Date(t,e,i,n,s,o,r);return 1970>t&&a.setFullYear(t),a}function q(t){var e=new Date(Date.UTC.apply(null,arguments));return 1970>t&&e.setUTCFullYear(t),e}function Z(t,e){if("string"==typeof t)if(isNaN(t)){if(t=e.weekdaysParse(t),"number"!=typeof t)return null}else t=parseInt(t,10);return t}function K(t,e,i,n,s){return s.relativeTime(e||1,!!i,t,n)}function $(t,e,i){var n=le(Math.abs(t)/1e3),s=le(n/60),o=le(s/60),r=le(o/24),a=le(r/365),h=45>n&&["s",n]||1===s&&["m"]||45>s&&["mm",s]||1===o&&["h"]||22>o&&["hh",o]||1===r&&["d"]||25>=r&&["dd",r]||45>=r&&["M"]||345>r&&["MM",le(r/30)]||1===a&&["y"]||["yy",a];return h[2]=e,h[3]=t>0,h[4]=i,K.apply({},h)}function Q(t,e,i){var n,s=i-e,o=i-t.day();return o>s&&(o-=7),s-7>o&&(o+=7),n=oe(t).add("d",o),{week:Math.ceil(n.dayOfYear()/7),year:n.year()}}function J(t,e,i,n,s){var o,r,a=q(t,0,1).getUTCDay();return i=null!=i?i:s,o=s-a+(a>n?7:0)-(s>a?7:0),r=7*(e-1)+(i-s)+o+1,{year:r>0?t:t-1,dayOfYear:r>0?r:S(t-1)+r}}function te(t){var e=t._i,i=t._f;return null===e?oe.invalid({nullInput:!0}):("string"==typeof e&&(t._i=e=N().preparse(e)),oe.isMoment(e)?(t=c(e),t._d=new Date(+e._d)):i?f(i)?U(t):W(t):V(t),new a(t))}function ee(t,e){oe.fn[t]=oe.fn[t+"s"]=function(t){var i=this._isUTC?"UTC":"";return null!=t?(this._d["set"+i+e](t),oe.updateOffset(this),this):this._d["get"+i+e]()}}function ie(t){oe.duration.fn[t]=function(){return this._data[t]}}function ne(t,e){oe.duration.fn["as"+t]=function(){return+this/e}}function se(t){var e=!1,i=oe;"undefined"==typeof ender&&(t?(he.moment=function(){return!e&&console&&console.warn&&(e=!0,console.warn("Accessing Moment through the global scope is deprecated, and will be removed in an upcoming release.")),i.apply(null,arguments)},l(he.moment,i)):he.moment=oe)}for(var oe,re,ae="2.5.1",he=this,le=Math.round,ce=0,de=1,ue=2,pe=3,fe=4,ge=5,me=6,ve={},ye={_isAMomentObject:null,_i:null,_f:null,_l:null,_strict:null,_isUTC:null,_offset:null,_pf:null,_lang:null},_e="undefined"!=typeof e&&e.exports&&"undefined"!=typeof t,be=/^\/?Date\((\-?\d+)/i,we=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,Se=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,Te=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g,Ee=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,xe=/\d\d?/,Ce=/\d{1,3}/,Me=/\d{1,4}/,De=/[+\-]?\d{1,6}/,Ie=/\d+/,Ne=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Oe=/Z|[\+\-]\d\d:?\d\d/gi,Le=/T/i,ke=/[\+\-]?\d+(\.\d{1,3})?/,Ae=/\d/,Pe=/\d\d/,ze=/\d{3}/,Fe=/\d{4}/,Re=/[+-]?\d{6}/,Ye=/[+-]?\d+/,He=/^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,We="YYYY-MM-DDTHH:mm:ssZ",Ge=[["YYYYYY-MM-DD",/[+-]\d{6}-\d{2}-\d{2}/],["YYYY-MM-DD",/\d{4}-\d{2}-\d{2}/],["GGGG-[W]WW-E",/\d{4}-W\d{2}-\d/],["GGGG-[W]WW",/\d{4}-W\d{2}/],["YYYY-DDD",/\d{4}-\d{3}/]],je=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d{1,3}/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],Ue=/([\+\-]|\d\d)/gi,Be="Date|Hours|Minutes|Seconds|Milliseconds".split("|"),Ve={Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6},Xe={ms:"millisecond",s:"second",m:"minute",h:"hour",d:"day",D:"date",w:"week",W:"isoWeek",M:"month",y:"year",DDD:"dayOfYear",e:"weekday",E:"isoWeekday",gg:"weekYear",GG:"isoWeekYear"},qe={dayofyear:"dayOfYear",isoweekday:"isoWeekday",isoweek:"isoWeek",weekyear:"weekYear",isoweekyear:"isoWeekYear"},Ze={},Ke="DDD w W M D d".split(" "),$e="M D H h m s w W".split(" "),Qe={M:function(){return this.month()+1},MMM:function(t){return this.lang().monthsShort(this,t)},MMMM:function(t){return this.lang().months(this,t)},D:function(){return this.date()},DDD:function(){return this.dayOfYear()},d:function(){return this.day()},dd:function(t){return this.lang().weekdaysMin(this,t)},ddd:function(t){return this.lang().weekdaysShort(this,t)},dddd:function(t){return this.lang().weekdays(this,t)},w:function(){return this.week()},W:function(){return this.isoWeek()},YY:function(){return u(this.year()%100,2)},YYYY:function(){return u(this.year(),4)},YYYYY:function(){return u(this.year(),5)},YYYYYY:function(){var t=this.year(),e=t>=0?"+":"-";return e+u(Math.abs(t),6)},gg:function(){return u(this.weekYear()%100,2)},gggg:function(){return u(this.weekYear(),4)},ggggg:function(){return u(this.weekYear(),5)},GG:function(){return u(this.isoWeekYear()%100,2)},GGGG:function(){return u(this.isoWeekYear(),4)},GGGGG:function(){return u(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.lang().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.lang().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return b(this.milliseconds()/100)},SS:function(){return u(b(this.milliseconds()/10),2)},SSS:function(){return u(this.milliseconds(),3)},SSSS:function(){return u(this.milliseconds(),3)},Z:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+u(b(t/60),2)+":"+u(b(t)%60,2)},ZZ:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+u(b(t/60),2)+u(b(t)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},X:function(){return this.unix()},Q:function(){return this.quarter()}},Je=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"];Ke.length;)re=Ke.pop(),Qe[re+"o"]=o(Qe[re],re);for(;$e.length;)re=$e.pop(),Qe[re+re]=s(Qe[re],2);for(Qe.DDDD=s(Qe.DDD,3),l(r.prototype,{set:function(t){var e,i;for(i in t)e=t[i],"function"==typeof e?this[i]=e:this["_"+i]=e},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(t){return this._months[t.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(t){return this._monthsShort[t.month()]},monthsParse:function(t){var e,i,n;for(this._monthsParse||(this._monthsParse=[]),e=0;12>e;e++)if(this._monthsParse[e]||(i=oe.utc([2e3,e]),n="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[e]=new RegExp(n.replace(".",""),"i")),this._monthsParse[e].test(t))return e},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(t){return this._weekdays[t.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(t){return this._weekdaysShort[t.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(t){return this._weekdaysMin[t.day()]},weekdaysParse:function(t){var e,i,n;for(this._weekdaysParse||(this._weekdaysParse=[]),e=0;7>e;e++)if(this._weekdaysParse[e]||(i=oe([2e3,1]).day(e),n="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[e]=new RegExp(n.replace(".",""),"i")),this._weekdaysParse[e].test(t))return e},_longDateFormat:{LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D YYYY",LLL:"MMMM D YYYY LT",LLLL:"dddd, MMMM D YYYY LT"},longDateFormat:function(t){var e=this._longDateFormat[t];return!e&&this._longDateFormat[t.toUpperCase()]&&(e=this._longDateFormat[t.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t]=e),e},isPM:function(t){return"p"===(t+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(t,e,i){return t>11?i?"pm":"PM":i?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(t,e){var i=this._calendar[t];return"function"==typeof i?i.apply(e):i},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(t,e,i,n){var s=this._relativeTime[i];return"function"==typeof s?s(t,e,i,n):s.replace(/%d/i,t)},pastFuture:function(t,e){var i=this._relativeTime[t>0?"future":"past"];return"function"==typeof i?i(e):i.replace(/%s/i,e)},ordinal:function(t){return this._ordinal.replace("%d",t)},_ordinal:"%d",preparse:function(t){return t},postformat:function(t){return t},week:function(t){return Q(t,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),oe=function(t,e,s,o){var r;return"boolean"==typeof s&&(o=s,s=i),r={},r._isAMomentObject=!0,r._i=t,r._f=e,r._l=s,r._strict=o,r._isUTC=!1,r._pf=n(),te(r)},oe.utc=function(t,e,s,o){var r;return"boolean"==typeof s&&(o=s,s=i),r={},r._isAMomentObject=!0,r._useUTC=!0,r._isUTC=!0,r._l=s,r._i=t,r._f=e,r._strict=o,r._pf=n(),te(r).utc()},oe.unix=function(t){return oe(1e3*t)},oe.duration=function(t,e){var i,n,s,o=t,r=null;return oe.isDuration(t)?o={ms:t._milliseconds,d:t._days,M:t._months}:"number"==typeof t?(o={},e?o[e]=t:o.milliseconds=t):(r=we.exec(t))?(i="-"===r[1]?-1:1,o={y:0,d:b(r[ue])*i,h:b(r[pe])*i,m:b(r[fe])*i,s:b(r[ge])*i,ms:b(r[me])*i}):(r=Se.exec(t))&&(i="-"===r[1]?-1:1,s=function(t){var e=t&&parseFloat(t.replace(",","."));return(isNaN(e)?0:e)*i},o={y:s(r[2]),M:s(r[3]),d:s(r[4]),h:s(r[5]),m:s(r[6]),s:s(r[7]),w:s(r[8])}),n=new h(o),oe.isDuration(t)&&t.hasOwnProperty("_lang")&&(n._lang=t._lang),n},oe.version=ae,oe.defaultFormat=We,oe.updateOffset=function(){},oe.lang=function(t,e){var i;return t?(e?D(C(t),e):null===e?(I(t),t="en"):ve[t]||N(t),i=oe.duration.fn._lang=oe.fn._lang=N(t),i._abbr):oe.fn._lang._abbr},oe.langData=function(t){return t&&t._lang&&t._lang._abbr&&(t=t._lang._abbr),N(t)},oe.isMoment=function(t){return t instanceof a||null!=t&&t.hasOwnProperty("_isAMomentObject")},oe.isDuration=function(t){return t instanceof h},re=Je.length-1;re>=0;--re)_(Je[re]);for(oe.normalizeUnits=function(t){return v(t)},oe.invalid=function(t){var e=oe.utc(0/0);return null!=t?l(e._pf,t):e._pf.userInvalidated=!0,e},oe.parseZone=function(t){return oe(t).parseZone()},l(oe.fn=a.prototype,{clone:function(){return oe(this)},valueOf:function(){return+this._d+6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().lang("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){var t=oe(this).utc();return 00:!1},parsingFlags:function(){return l({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(){return this.zone(0)},local:function(){return this.zone(0),this._isUTC=!1,this},format:function(t){var e=k(this,t||oe.defaultFormat);return this.lang().postformat(e)},add:function(t,e){var i;return i="string"==typeof t?oe.duration(+e,t):oe.duration(t,e),p(this,i,1),this},subtract:function(t,e){var i;return i="string"==typeof t?oe.duration(+e,t):oe.duration(t,e),p(this,i,-1),this},diff:function(t,e,i){var n,s,o=M(t,this),r=6e4*(this.zone()-o.zone());return e=v(e),"year"===e||"month"===e?(n=432e5*(this.daysInMonth()+o.daysInMonth()),s=12*(this.year()-o.year())+(this.month()-o.month()),s+=(this-oe(this).startOf("month")-(o-oe(o).startOf("month")))/n,s-=6e4*(this.zone()-oe(this).startOf("month").zone()-(o.zone()-oe(o).startOf("month").zone()))/n,"year"===e&&(s/=12)):(n=this-o,s="second"===e?n/1e3:"minute"===e?n/6e4:"hour"===e?n/36e5:"day"===e?(n-r)/864e5:"week"===e?(n-r)/6048e5:n),i?s:d(s)},from:function(t,e){return oe.duration(this.diff(t)).lang(this.lang()._abbr).humanize(!e)},fromNow:function(t){return this.from(oe(),t)},calendar:function(){var t=M(oe(),this).startOf("day"),e=this.diff(t,"days",!0),i=-6>e?"sameElse":-1>e?"lastWeek":0>e?"lastDay":1>e?"sameDay":2>e?"nextDay":7>e?"nextWeek":"sameElse";return this.format(this.lang().calendar(i,this))},isLeapYear:function(){return T(this.year())},isDST:function(){return this.zone()+oe(t).startOf(e)},isBefore:function(t,e){return e="undefined"!=typeof e?e:"millisecond",+this.clone().startOf(e)<+oe(t).startOf(e)},isSame:function(t,e){return e=e||"ms",+this.clone().startOf(e)===+M(t,this).startOf(e)},min:function(t){return t=oe.apply(null,arguments),this>t?this:t},max:function(t){return t=oe.apply(null,arguments),t>this?this:t},zone:function(t){var e=this._offset||0;return null==t?this._isUTC?e:this._d.getTimezoneOffset():("string"==typeof t&&(t=z(t)),Math.abs(t)<16&&(t=60*t),this._offset=t,this._isUTC=!0,e!==t&&p(this,oe.duration(e-t,"m"),1,!0),this)},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.zone(this._tzm):"string"==typeof this._i&&this.zone(this._i),this},hasAlignedHourOffset:function(t){return t=t?oe(t).zone():0,(this.zone()-t)%60===0},daysInMonth:function(){return w(this.year(),this.month())},dayOfYear:function(t){var e=le((oe(this).startOf("day")-oe(this).startOf("year"))/864e5)+1;return null==t?e:this.add("d",t-e)},quarter:function(){return Math.ceil((this.month()+1)/3)},weekYear:function(t){var e=Q(this,this.lang()._week.dow,this.lang()._week.doy).year;return null==t?e:this.add("y",t-e)},isoWeekYear:function(t){var e=Q(this,1,4).year;return null==t?e:this.add("y",t-e)},week:function(t){var e=this.lang().week(this);return null==t?e:this.add("d",7*(t-e))},isoWeek:function(t){var e=Q(this,1,4).week;return null==t?e:this.add("d",7*(t-e))},weekday:function(t){var e=(this.day()+7-this.lang()._week.dow)%7;return null==t?e:this.add("d",t-e)},isoWeekday:function(t){return null==t?this.day()||7:this.day(this.day()%7?t:t-7)},get:function(t){return t=v(t),this[t]()},set:function(t,e){return t=v(t),"function"==typeof this[t]&&this[t](e),this},lang:function(t){return t===i?this._lang:(this._lang=N(t),this)}}),re=0;re-1?!1:"INPUT"==i||"SELECT"==i||"TEXTAREA"==i||e.contentEditable&&"true"==e.contentEditable}function o(t,e){return t.sort().join(",")===e.sort().join(",")}function r(t){t=t||{};var e,i=!1;for(e in M)t[e]?i=!0:M[e]=0;i||(I=!1)}function a(t,e,i,n,s){var r,a,h=[];if(!x[t])return[];for("keyup"==i&&u(t)&&(e=[t]),r=0;r95&&112>t||w.hasOwnProperty(t)&&(_[w[t]]=t)}return _}function g(t,e,i){return i||(i=f()[t]?"keydown":"keypress"),"keypress"==i&&e.length&&(i="keydown"),i}function m(t,e,i,s){M[t]=0,s||(s=g(e[0],[]));var o,a=function(){I=s,++M[t],p()},h=function(t){l(i,t),"keyup"!==s&&(D=n(t)),setTimeout(r,10)};for(o=0;o1)return m(t,l,e,i);for(h="+"===t?["+"]:t.split("+"),o=0;o":".","?":"/","|":"\\"},E={option:"alt",command:"meta","return":"enter",escape:"esc"},x={},C={},M={},D=!1,I=!1,N=1;20>N;++N)w[111+N]="f"+N;for(N=0;9>=N;++N)w[N+96]=N;i(document,"keypress",d),i(document,"keydown",d),i(document,"keyup",d);var O={bind:function(t,e,i){return y(t instanceof Array?t:[t],e,i),C[t+":"+i]=e,this},unbind:function(t,e){return C[t+":"+e]&&(delete C[t+":"+e],this.bind(t,function(){},e)),this},trigger:function(t,e){return C[t+":"+e](),this},reset:function(){return x={},C={},this}};e.exports=O},{}]},{},[1])(1)}); \ No newline at end of file diff --git a/src/graph/Graph.js b/src/graph/Graph.js index d7c446f1..ba319788 100644 --- a/src/graph/Graph.js +++ b/src/graph/Graph.js @@ -10,6 +10,9 @@ * @param {Object} options Options */ function Graph (container, data, options) { + + this._initializeMixinLoaders(); + // create variables and set default values this.containerElement = container; this.width = '100%'; @@ -66,12 +69,22 @@ function Graph (container, data, options) { } }, physics: { - enableBarnesHut: false, - barnesHutTheta: 1 / 0.4, // inverted to save time during calculation - barnesHutGravitationalConstant: -10000, - centralGravity: 0.08, - springLength: 50, - springConstant: 0.02 + barnesHut: { + enabled: false, + theta: 1 / 0.3, // inverted to save time during calculation + gravitationalConstant: -10000, + centralGravity: 0.08, + springLength: 100, + springConstant: 0.02 + }, + repulsion: { + centralGravity: 0.01, + springLength: 100, + springConstant: 0.05 + }, + centralGravity: null, + springLength: null, + springConstant: null }, clustering: { // Per Node in Cluster = PNiC enabled: false, // (Boolean) | global on/off switch for clustering. @@ -80,17 +93,19 @@ function Graph (container, data, options) { reduceToNodes:300, // (# nodes) | during calculate forces, we check if the total number of nodes is larger than clusterThreshold. If it is, cluster until reduced to this chainThreshold: 0.4, // (% of all drawn nodes)| maximum percentage of allowed chainnodes (long strings of connected nodes) within all nodes. (lower means less chains). clusterEdgeThreshold: 20, // (px) | edge length threshold. if smaller, this node is clustered. - sectorThreshold: 50, // (# nodes in cluster) | cluster size threshold. If larger, expanding in own sector. + sectorThreshold: 100, // (# nodes in cluster) | cluster size threshold. If larger, expanding in own sector. screenSizeThreshold: 0.2, // (% of canvas) | relative size threshold. If the width or height of a clusternode takes up this much of the screen, decluster node. fontSizeMultiplier: 4.0, // (px PNiC) | how much the cluster font size grows per node in cluster (in px). - forceAmplification: 0.6, // (multiplier PNiC) | factor of increase fo the repulsion force of a cluster (per node in cluster). - distanceAmplification: 0.2, // (multiplier PNiC) | factor how much the repulsion distance of a cluster increases (per node in cluster). - edgeGrowth: 11, // (px PNiC) | amount of clusterSize connected to the edge is multiplied with this and added to edgeLength. - nodeScaling: {width: 10, // (px PNiC) | growth of the width per node in cluster. - height: 10, // (px PNiC) | growth of the height per node in cluster. - radius: 10}, // (px PNiC) | growth of the radius per node in cluster. - activeAreaBoxSize: 100, // (px) | box area around the curser where clusters are popped open. - massTransferCoefficient: 1 // (multiplier) | parent.mass += massTransferCoefficient * child.mass + forceAmplification: 0.1, // (multiplier PNiC) | factor of increase fo the repulsion force of a cluster (per node in cluster). + maxFontSize: 1000, + distanceAmplification: 0.03, // (multiplier PNiC) | factor how much the repulsion distance of a cluster increases (per node in cluster). + edgeGrowth: 1, // (px PNiC) | amount of clusterSize connected to the edge is multiplied with this and added to edgeLength. + nodeScaling: {width: 5, // (px PNiC) | growth of the width per node in cluster. + height: 5, // (px PNiC) | growth of the height per node in cluster. + radius: 5}, // (px PNiC) | growth of the radius per node in cluster. + maxNodeSizeIncrements: 600, // (# increments) | max growth of the width per node in cluster. + activeAreaBoxSize: 80, // (px) | box area around the curser where clusters are popped open. + clusterLevelDifference: 2 }, navigation: { enabled: false, @@ -103,6 +118,7 @@ function Graph (container, data, options) { dataManipulationToolbar: { enabled: false }, + maxVelocity: 35, minVelocity: 0.1, // px/s maxIterations: 1000 // maximum number of iteration to stabilize }; @@ -194,11 +210,12 @@ function Graph (container, data, options) { this.moving = false; // True if any of the nodes have an undefined position this.timer = undefined; + // load data (the disable start variable will be the same as the enabled clustering) this.setData(data,this.constants.clustering.enabled); // zoom so all data will fit on the screen - this.zoomToFit(true); + this.zoomToFit(true,this.constants.clustering.enabled); // if clustering is disabled, the simulation will have started in the setData function if (this.constants.clustering.enabled) { @@ -281,7 +298,7 @@ Graph.prototype._centerGraph = function(range) { * * @param {Boolean} [initialZoom] | zoom based on fitted formula or range, true = fitted, default = false; */ -Graph.prototype.zoomToFit = function(initialZoom) { +Graph.prototype.zoomToFit = function(initialZoom, doNotStart) { if (initialZoom === undefined) { initialZoom = false; } @@ -315,7 +332,9 @@ Graph.prototype.zoomToFit = function(initialZoom) { this.pinch.mousewheelScale = zoomLevel; this._setScale(zoomLevel); this._centerGraph(range); - this.start(); + if (doNotStart == false || doNotStart === undefined) { + this.start(); + } }; @@ -394,6 +413,27 @@ Graph.prototype.setOptions = function (options) { if (options.stabilize !== undefined) {this.stabilize = options.stabilize;} if (options.selectable !== undefined) {this.selectable = options.selectable;} +/* + if (options.physics) { + if (options.physics.barnesHut) { + this.constants.physics.barnesHut.enabled = true; + for (var prop in options.physics.barnesHut) { + if (options.physics.barnesHut.hasOwnProperty(prop)) { + this.constants.physics.barnesHut[prop] = options.physics.barnesHut[prop]; + } + } + } + + if (options.physics.repulsion) { + this.constants.physics.barnesHut.enabled = false; + for (var prop in options.physics.repulsion) { + if (options.physics.repulsion.hasOwnProperty(prop)) { + this.constants.physics.repulsion[prop] = options.physics.repulsion[prop]; + } + } + } + } +*/ if (options.clustering) { this.constants.clustering.enabled = true; for (var prop in options.clustering) { @@ -502,6 +542,9 @@ Graph.prototype.setOptions = function (options) { } } + // load the force calculation functions, grouped under the physics system. + this._loadPhysicsSystem(); + // load the navigation system. this._loadNavigationControls(); @@ -1693,7 +1736,7 @@ Graph.prototype._doStabilize = function() { * @private */ Graph.prototype._isMoving = function(vmin) { - var vminCorrected = vmin / this.scale; + var vminCorrected = vmin / Math.max(this.scale,0.05); var nodes = this.nodes; for (var id in nodes) { if (nodes.hasOwnProperty(id) && nodes[id].isMoving(vminCorrected)) { @@ -1715,8 +1758,6 @@ Graph.prototype._discreteStepNodes = function() { var interval = 1; var nodes = this.nodes; - this.constants.maxVelocity = 30; - if (this.constants.maxVelocity > 0) { for (var id in nodes) { if (nodes.hasOwnProperty(id)) { @@ -1785,14 +1826,14 @@ Graph.prototype.start = function() { //this.time = this.end - this.startTime; //console.log('refresh time: ' + this.time); //this.startTime = window.performance.now(); - var DOMelement = document.getElementById("calctimereporter"); - if (DOMelement !== undefined) { - DOMelement.innerHTML = calctime; - } - DOMelement = document.getElementById("rendertimereporter"); - if (DOMelement !== undefined) { - DOMelement.innerHTML = rendertime; - } +// var DOMelement = document.getElementById("calctimereporter"); +// if (DOMelement !== undefined) { +// DOMelement.innerHTML = calctime; +// } +// DOMelement = document.getElementById("rendertimereporter"); +// if (DOMelement !== undefined) { +// DOMelement.innerHTML = rendertime; +// } }, this.renderTimestep); } } @@ -1832,151 +1873,14 @@ Graph.prototype.toggleFreeze = function() { }; - -/** - * Mixin the physics system and initialize the parameters required. - * - * @private - */ -Graph.prototype._loadPhysicsSystem = function() { - this.forceCalculationTime = 0; - for (var mixinFunction in physicsMixin) { - if (physicsMixin.hasOwnProperty(mixinFunction)) { - Graph.prototype[mixinFunction] = physicsMixin[mixinFunction]; - } - } -}; - - -/** - * Mixin the cluster system and initialize the parameters required. - * - * @private - */ -Graph.prototype._loadClusterSystem = function() { - this.clusterSession = 0; - this.hubThreshold = 5; - - for (var mixinFunction in ClusterMixin) { - if (ClusterMixin.hasOwnProperty(mixinFunction)) { - Graph.prototype[mixinFunction] = ClusterMixin[mixinFunction]; - } - } -} - -/** - * Mixin the sector system and initialize the parameters required - * - * @private - */ -Graph.prototype._loadSectorSystem = function() { - this.sectors = {}; - this.activeSector = ["default"]; - this.sectors["active"] = {}; - this.sectors["active"]["default"] = {"nodes":{}, - "edges":{}, - "nodeIndices":[], - "formationScale": 1.0, - "drawingNode": undefined}; - this.sectors["frozen"] = {}; - this.sectors["navigation"] = {"nodes":{}, - "edges":{}, - "nodeIndices":[], - "formationScale": 1.0, - "drawingNode": undefined}; - - this.nodeIndices = this.sectors["active"]["default"]["nodeIndices"]; // the node indices list is used to speed up the computation of the repulsion fields - for (var mixinFunction in SectorMixin) { - if (SectorMixin.hasOwnProperty(mixinFunction)) { - Graph.prototype[mixinFunction] = SectorMixin[mixinFunction]; - } - } -}; - - -/** - * Mixin the selection system and initialize the parameters required - * - * @private - */ -Graph.prototype._loadSelectionSystem = function() { - this.selectionObj = {}; - - for (var mixinFunction in SelectionMixin) { - if (SelectionMixin.hasOwnProperty(mixinFunction)) { - Graph.prototype[mixinFunction] = SelectionMixin[mixinFunction]; - } - } -} - - - -/** - * Mixin the navigationUI (User Interface) system and initialize the parameters required - * - * @private - */ -Graph.prototype._loadManipulationSystem = function() { - // reset global variables -- these are used by the selection of nodes and edges. - this.blockConnectingEdgeSelection = false; - this.forceAppendSelection = false - - - if (this.constants.dataManipulationToolbar.enabled == true) { - // load the manipulator HTML elements. All styling done in css. - if (this.manipulationDiv === undefined) { - this.manipulationDiv = document.createElement('div'); - this.manipulationDiv.className = 'graph-manipulationDiv'; - this.containerElement.insertBefore(this.manipulationDiv, this.frame); - } - // load the manipulation functions - for (var mixinFunction in manipulationMixin) { - if (manipulationMixin.hasOwnProperty(mixinFunction)) { - Graph.prototype[mixinFunction] = manipulationMixin[mixinFunction]; - } +Graph.prototype._initializeMixinLoaders = function () { + for (var mixinFunction in graphMixinLoaders) { + if (graphMixinLoaders.hasOwnProperty(mixinFunction)) { + Graph.prototype[mixinFunction] = graphMixinLoaders[mixinFunction]; } - - // create the manipulator toolbar - this._createManipulatorBar(); } } -/** - * Mixin the navigation (User Interface) system and initialize the parameters required - * - * @private - */ -Graph.prototype._loadNavigationControls = function() { - for (var mixinFunction in NavigationMixin) { - if (NavigationMixin.hasOwnProperty(mixinFunction)) { - Graph.prototype[mixinFunction] = NavigationMixin[mixinFunction]; - } - } - - if (this.constants.navigation.enabled == true) { - this._loadNavigationElements(); - } -} - -/** - * this function exists to avoid errors when not loading the navigation system - */ -Graph.prototype._relocateNavigation = function() { - // empty, is overloaded by navigation system -} - -/** - * * this function exists to avoid errors when not loading the navigation system - */ -Graph.prototype._unHighlightAll = function() { - // empty, is overloaded by the navigation system -} - - - - - - diff --git a/src/graph/Node.js b/src/graph/Node.js index dd0c991f..33009663 100644 --- a/src/graph/Node.js +++ b/src/graph/Node.js @@ -52,6 +52,7 @@ function Node(properties, imagelist, grouplist, constants) { this.radiusFixed = false; this.radiusMin = constants.nodes.radiusMin; this.radiusMax = constants.nodes.radiusMax; + this.internalMultiplier = 1; this.imagelist = imagelist; @@ -66,6 +67,8 @@ function Node(properties, imagelist, grouplist, constants) { this.clusterSizeWidthFactor = constants.clustering.nodeScaling.width; this.clusterSizeHeightFactor = constants.clustering.nodeScaling.height; this.clusterSizeRadiusFactor = constants.clustering.nodeScaling.radius; + this.maxNodeSizeIncrements = constants.clustering.maxNodeSizeIncrements; + this.growthIndicator = 0; // mass, force, velocity this.mass = 1; // kg @@ -105,7 +108,6 @@ Node.prototype.attachEdge = function(edge) { this.dynamicEdges.push(edge); } this.dynamicEdgesLength = this.dynamicEdges.length; -// this._updateMass(); }; /** @@ -119,17 +121,8 @@ Node.prototype.detachEdge = function(edge) { this.dynamicEdges.splice(index, 1); } this.dynamicEdgesLength = this.dynamicEdges.length; -// this._updateMass(); }; -/** - * Update the nodes mass, which is determined by the number of edges connecting - * to it (more edges -> heavier node). - * @private - */ -//Node.prototype._updateMass = function() { -// this.mass = 1;// + 0.6 * this.edges.length; // kg -//}; /** * Set or overwrite properties for the node @@ -150,6 +143,10 @@ Node.prototype.setProperties = function(properties, constants) { if (properties.y !== undefined) {this.y = properties.y;} if (properties.value !== undefined) {this.value = properties.value;} + // physics + if (properties.internalMultiplier !== undefined) {this.internalMultiplier = properties.value;} + + // navigation controls properties if (properties.horizontalAlignLeft !== undefined) {this.horizontalAlignLeft = properties.horizontalAlignLeft;} if (properties.verticalAlignTop !== undefined) {this.verticalAlignTop = properties.verticalAlignTop;} @@ -542,10 +539,12 @@ Node.prototype._resizeImage = function (ctx) { this.width = width; this.height = height; + this.growthIndicator = 0; if (this.width > 0 && this.height > 0) { - this.width += (this.clusterSize - 1) * this.clusterSizeWidthFactor; - this.height += (this.clusterSize - 1) * this.clusterSizeHeightFactor; - this.radius += (this.clusterSize - 1) * this.clusterSizeRadiusFactor; + this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; + this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; + this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor; + this.growthIndicator = this.width - width; } } @@ -590,9 +589,11 @@ Node.prototype._resizeBox = function (ctx) { this.width = textSize.width + 2 * margin; this.height = textSize.height + 2 * margin; - this.width += (this.clusterSize - 1) * 0.5 * this.clusterSizeWidthFactor; - this.height += (this.clusterSize - 1) * 0.5 * this.clusterSizeHeightFactor; -// this.radius += (this.clusterSize - 1) * 0.5 * this.clusterSizeRadiusFactor; + this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeWidthFactor; + this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeHeightFactor; + this.growthIndicator = this.width - textSize.width + 2 * margin; +// this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor; + } }; @@ -639,9 +640,10 @@ Node.prototype._resizeDatabase = function (ctx) { this.height = size; // scaling used for clustering - this.width += (this.clusterSize - 1) * this.clusterSizeWidthFactor; - this.height += (this.clusterSize - 1) * this.clusterSizeHeightFactor; - this.radius += (this.clusterSize - 1) * this.clusterSizeRadiusFactor; + this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; + this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; + this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor; + this.growthIndicator = this.width - size; } }; @@ -688,9 +690,10 @@ Node.prototype._resizeCircle = function (ctx) { this.height = diameter; // scaling used for clustering -// this.width += (this.clusterSize - 1) * 0.5 * this.clusterSizeWidthFactor; -// this.height += (this.clusterSize - 1) * 0.5 * this.clusterSizeHeightFactor; - this.radius += (this.clusterSize - 1) * 0.5 * this.clusterSizeRadiusFactor; +// this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeWidthFactor; +// this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeHeightFactor; + this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor; + this.growthIndicator = this.radius - diameter; } }; @@ -734,11 +737,13 @@ Node.prototype._resizeEllipse = function (ctx) { if (this.width < this.height) { this.width = this.height; } + var defaultSize = this.width; - // scaling used for clustering - this.width += (this.clusterSize - 1) * this.clusterSizeWidthFactor; - this.height += (this.clusterSize - 1) * this.clusterSizeHeightFactor; - this.radius += (this.clusterSize - 1) * this.clusterSizeRadiusFactor; + // scaling used for clustering + this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; + this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; + this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor; + this.growthIndicator = this.width - defaultSize; } }; @@ -801,9 +806,10 @@ Node.prototype._resizeShape = function (ctx) { this.height = size; // scaling used for clustering - this.width += (this.clusterSize - 1) * this.clusterSizeWidthFactor; - this.height += (this.clusterSize - 1) * this.clusterSizeHeightFactor; - this.radius += (this.clusterSize - 1) * 0.5 * this.clusterSizeRadiusFactor; + this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; + this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; + this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor; + this.growthIndicator = this.width - size; } }; @@ -860,9 +866,10 @@ Node.prototype._resizeText = function (ctx) { this.height = textSize.height + 2 * margin; // scaling used for clustering - this.width += (this.clusterSize - 1) * this.clusterSizeWidthFactor; - this.height += (this.clusterSize - 1) * this.clusterSizeHeightFactor; - this.radius += (this.clusterSize - 1) * this.clusterSizeRadiusFactor; + this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; + this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; + this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor; + this.growthIndicator = this.width - textSize.width + 2 * margin; } }; @@ -968,12 +975,13 @@ Node.prototype.setScale = function(scale) { }; /** - * This function updates the damping parameter for clusters, based ont he + * This function updates the damping parameter of the node based on its mass, + * heavier nodes have more damping. * * @param {Number} numberOfNodes */ Node.prototype.updateDamping = function(numberOfNodes) { - this.damping = (0.9 + 0.1*this.clusterSize * (1 + Math.pow(numberOfNodes,-2))); + this.damping = Math.min(1.5,0.9 + 0.01*this.growthIndicator); }; diff --git a/src/graph/ClusterMixin.js b/src/graph/graphMixins/ClusterMixin.js similarity index 89% rename from src/graph/ClusterMixin.js rename to src/graph/graphMixins/ClusterMixin.js index c4755a51..d377e326 100644 --- a/src/graph/ClusterMixin.js +++ b/src/graph/graphMixins/ClusterMixin.js @@ -41,17 +41,19 @@ var ClusterMixin = { // we first cluster the hubs, then we pull in the outliers, repeat while (numberOfNodes > maxNumberOfNodes && level < maxLevels) { if (level % 3 == 0) { - this.forceAggregateHubs(); + this.forceAggregateHubs(true); + this.normalizeClusterLevels(); } else { - this.increaseClusterLevel(); + this.increaseClusterLevel(); // this also includes a cluster normalization } + numberOfNodes = this.nodeIndices.length; level += 1; } // after the clustering we reposition the nodes to reduce the initial chaos - if (level > 1 && reposition == true) { + if (level > 0 && reposition == true) { this.repositionNodes(); } }, @@ -88,6 +90,7 @@ var ClusterMixin = { } }, + /** * This calls the updateClustes with default arguments */ @@ -97,6 +100,7 @@ var ClusterMixin = { } }, + /** * This function can be called to increase the cluster level. This means that the nodes with only one edge connection will * be clustered with their connected node. This can be repeated as many times as needed. @@ -107,7 +111,6 @@ var ClusterMixin = { }, - /** * This function can be called to decrease the cluster level. This means that the nodes with only one edge connection will * be unpacked if they are a cluster. This can be repeated as many times as needed. @@ -129,7 +132,7 @@ var ClusterMixin = { * @param {Boolean} force | enabled or disable forcing * */ - updateClusters : function(zoomDirection,recursive,force) { + updateClusters : function(zoomDirection,recursive,force,doNotStart) { var isMovingBeforeClustering = this.moving; var amountOfNodes = this.nodeIndices.length; @@ -178,11 +181,15 @@ var ClusterMixin = { // if a cluster was formed, we increase the clusterSession if (this.nodeIndices.length < amountOfNodes) { // this means a clustering operation has taken place this.clusterSession += 1; + // if clusters have been made, we normalize the cluster level + this.normalizeClusterLevels(); } - // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded - if (this.moving != isMovingBeforeClustering) { - this.start(); + if (doNotStart == false || doNotStart === undefined) { + // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded + if (this.moving != isMovingBeforeClustering) { + this.start(); + } } }, @@ -214,7 +221,7 @@ var ClusterMixin = { * This function is fired by keypress. It forces hubs to form. * */ - forceAggregateHubs : function() { + forceAggregateHubs : function(doNotStart) { var isMovingBeforeClustering = this.moving; var amountOfNodes = this.nodeIndices.length; @@ -230,9 +237,11 @@ var ClusterMixin = { this.clusterSession += 1; } - // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded - if (this.moving != isMovingBeforeClustering) { - this.start(); + if (doNotStart == false || doNotStart === undefined) { + // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded + if (this.moving != isMovingBeforeClustering) { + this.start(); + } } }, @@ -353,14 +362,14 @@ var ClusterMixin = { this._validateEdges(parentNode); // undo the changes from the clustering operation on the parent node - parentNode.mass -= this.constants.clustering.massTransferCoefficient * childNode.mass; - parentNode.fontSize -= this.constants.clustering.fontSizeMultiplier * childNode.clusterSize; + parentNode.mass -= childNode.mass; parentNode.clusterSize -= childNode.clusterSize; + parentNode.fontSize = Math.min(this.constants.clustering.maxFontSize, this.constants.nodes.fontSize + this.constants.clustering.fontSizeMultiplier*parentNode.clusterSize); parentNode.dynamicEdgesLength = parentNode.dynamicEdges.length; // place the child node near the parent, not at the exact same location to avoid chaos in the system - childNode.x = parentNode.x + this.constants.edges.length * 0.3 * (0.5 - Math.random()) * parentNode.clusterSize; - childNode.y = parentNode.y + this.constants.edges.length * 0.3 * (0.5 - Math.random()) * parentNode.clusterSize; + childNode.x = parentNode.x + parentNode.growthIndicator * (0.5 - Math.random()) * childNode.clusterSize; + childNode.y = parentNode.y + parentNode.growthIndicator * (0.5 - Math.random()) * childNode.clusterSize; // remove node from the list delete parentNode.containedNodes[containedNodeId]; @@ -493,6 +502,32 @@ var ClusterMixin = { }, + _clusterToSmallestNeighbour : function(node) { + var smallestNeighbour = -1; + var smallestNeighbourNode = null; + for (var i = 0; i < node.dynamicEdges.length; i++) { + if (node.dynamicEdges[i] !== undefined) { + var neighbour = null; + if (node.dynamicEdges[i].fromId != node.id) { + neighbour = node.dynamicEdges[i].from; + } + else if (node.dynamicEdges[i].toId != node.id) { + neighbour = node.dynamicEdges[i].to; + } + + + if (neighbour != null && smallestNeighbour > neighbour.clusterSessions.length) { + smallestNeighbour = neighbour.clusterSessions.length; + smallestNeighbourNode = neighbour; + } + } + } + + if (neighbour != null && this.nodes[neighbour.id] !== undefined) { + this._addToCluster(neighbour, node, true); + } + }, + /** * This function forms clusters from hubs, it loops over all nodes @@ -618,9 +653,9 @@ var ClusterMixin = { // update the properties of the child and parent var massBefore = parentNode.mass; childNode.clusterSession = this.clusterSession; - parentNode.mass += this.constants.clustering.massTransferCoefficient * childNode.mass; + parentNode.mass += childNode.mass; parentNode.clusterSize += childNode.clusterSize; - parentNode.fontSize += this.constants.clustering.fontSizeMultiplier * childNode.clusterSize; + parentNode.fontSize = Math.min(this.constants.clustering.maxFontSize, this.constants.nodes.fontSize + this.constants.clustering.fontSizeMultiplier*parentNode.clusterSize); // keep track of the clustersessions so we can open the cluster up as it has been formed. if (parentNode.clusterSessions[parentNode.clusterSessions.length - 1] != this.clusterSession) { @@ -895,16 +930,52 @@ var ClusterMixin = { } /* Debug Override */ - // for (nodeId in this.nodes) { - // if (this.nodes.hasOwnProperty(nodeId)) { - // node = this.nodes[nodeId]; - // node.label = String(Math.round(node.width)).concat(":",Math.round(node.width*this.scale)); - // } - // } +// for (nodeId in this.nodes) { +// if (this.nodes.hasOwnProperty(nodeId)) { +// node = this.nodes[nodeId]; +// node.label = String(node.fx).concat(",",node.fy); +// } +// } }, + normalizeClusterLevels : function() { + var maxLevel = 0; + var minLevel = 1e9; + var clusterLevel = 0; + + // we loop over all nodes in the list + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + clusterLevel = this.nodes[nodeId].clusterSessions.length; + if (maxLevel < clusterLevel) {maxLevel = clusterLevel;} + if (minLevel > clusterLevel) {minLevel = clusterLevel;} + } + } + + if (maxLevel - minLevel > this.constants.clustering.clusterLevelDifference) { + var amountOfNodes = this.nodeIndices.length; + var targetLevel = maxLevel - this.constants.clustering.clusterLevelDifference; + // we loop over all nodes in the list + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + if (this.nodes[nodeId].clusterSessions.length < targetLevel) { + this._clusterToSmallestNeighbour(this.nodes[nodeId]); + } + } + } + this._updateNodeIndexList(); + this._updateDynamicEdges(); + // if a cluster was formed, we increase the clusterSession + if (this.nodeIndices.length != amountOfNodes) { + this.clusterSession += 1; + } + } + }, + + + /** * This function determines if the cluster we want to decluster is in the active area * this means around the zoom center @@ -931,7 +1002,7 @@ var ClusterMixin = { for (var i = 0; i < this.nodeIndices.length; i++) { var node = this.nodes[this.nodeIndices[i]]; if (!node.isFixed()) { - var radius = this.constants.edges.length * (1 + 0.6*node.clusterSize); + var radius = this.constants.physics.springLength * (1 + 0.1*node.mass); var angle = 2 * Math.PI * Math.random(); node.x = radius * Math.cos(angle); node.y = radius * Math.sin(angle); @@ -956,6 +1027,7 @@ var ClusterMixin = { var largestHub = 0; for (var i = 0; i < this.nodeIndices.length; i++) { + var node = this.nodes[this.nodeIndices[i]]; if (node.dynamicEdgesLength > largestHub) { largestHub = node.dynamicEdgesLength; diff --git a/src/graph/manipulationMixin.js b/src/graph/graphMixins/ManipulationMixin.js similarity index 100% rename from src/graph/manipulationMixin.js rename to src/graph/graphMixins/ManipulationMixin.js diff --git a/src/graph/graphMixins/MixinLoader.js b/src/graph/graphMixins/MixinLoader.js new file mode 100644 index 00000000..fd13ef13 --- /dev/null +++ b/src/graph/graphMixins/MixinLoader.js @@ -0,0 +1,185 @@ +/** + * Created by Alex on 2/10/14. + */ + + +var graphMixinLoaders = { + + /** + * Load a mixin into the graph object + * + * @param {Object} sourceVariable | this object has to contain functions. + * @private + */ + _loadMixin : function(sourceVariable) { + for (var mixinFunction in sourceVariable) { + if (sourceVariable.hasOwnProperty(mixinFunction)) { + Graph.prototype[mixinFunction] = sourceVariable[mixinFunction]; + } + } + }, + + + /** + * removes a mixin from the graph object. + * + * @param {Object} sourceVariable | this object has to contain functions. + * @private + */ + _clearMixin : function(sourceVariable) { + for (var mixinFunction in sourceVariable) { + if (sourceVariable.hasOwnProperty(mixinFunction)) { + Graph.prototype[mixinFunction] = undefined; + } + } + }, + + + /** + * Mixin the physics system and initialize the parameters required. + * + * @private + */ + _loadPhysicsSystem : function() { + this._loadMixin(physicsMixin); + this._loadSelectedForceSolver(); + }, + + + /** + * This loads the node force solver based on the barnes hut or repulsion algorithm + * + * @private + */ + _loadSelectedForceSolver : function() { + // this overloads the this._calculateNodeForces + if (this.constants.physics.barnesHut.enabled == true) { + this._clearMixin(repulsionMixin); + + this.constants.physics.centralGravity = this.constants.physics.barnesHut.centralGravity; + this.constants.physics.springLength = this.constants.physics.barnesHut.springLength; + this.constants.physics.springConstant = this.constants.physics.barnesHut.springConstant; + this.constants.physics.springGrowthPerMass = this.constants.physics.barnesHut.springGrowthPerMass; + + this._loadMixin(barnesHutMixin); + } + else { + this._clearMixin(barnesHutMixin); + + this.constants.physics.centralGravity = this.constants.physics.repulsion.centralGravity; + this.constants.physics.springLength = this.constants.physics.repulsion.springLength; + this.constants.physics.springConstant = this.constants.physics.repulsion.springConstant; + this.constants.physics.springGrowthPerMass = this.constants.physics.repulsion.springGrowthPerMass; + + this._loadMixin(repulsionMixin); + } + }, + + + /** + * Mixin the cluster system and initialize the parameters required. + * + * @private + */ + _loadClusterSystem : function() { + this.clusterSession = 0; + this.hubThreshold = 5; + this._loadMixin(ClusterMixin); + }, + + + /** + * Mixin the sector system and initialize the parameters required + * + * @private + */ + _loadSectorSystem : function() { + this.sectors = { }, + this.activeSector = ["default"]; + this.sectors["active"] = { }, + this.sectors["active"]["default"] = {"nodes":{}, + "edges":{}, + "nodeIndices":[], + "formationScale": 1.0, + "drawingNode": undefined }, + this.sectors["frozen"] = { }, + this.sectors["navigation"] = {"nodes":{}, + "edges":{}, + "nodeIndices":[], + "formationScale": 1.0, + "drawingNode": undefined }, + + this.nodeIndices = this.sectors["active"]["default"]["nodeIndices"]; // the node indices list is used to speed up the computation of the repulsion fields + + this._loadMixin(SectorMixin); + }, + + + /** + * Mixin the selection system and initialize the parameters required + * + * @private + */ + _loadSelectionSystem : function() { + this.selectionObj = { }; + + this._loadMixin(SelectionMixin); + }, + + + /** + * Mixin the navigationUI (User Interface) system and initialize the parameters required + * + * @private + */ + _loadManipulationSystem : function() { + // reset global variables -- these are used by the selection of nodes and edges. + this.blockConnectingEdgeSelection = false; + this.forceAppendSelection = false + + + if (this.constants.dataManipulationToolbar.enabled == true) { + // load the manipulator HTML elements. All styling done in css. + if (this.manipulationDiv === undefined) { + this.manipulationDiv = document.createElement('div'); + this.manipulationDiv.className = 'graph-manipulationDiv'; + this.containerElement.insertBefore(this.manipulationDiv, this.frame); + } + // load the manipulation functions + this._loadMixin(manipulationMixin); + + // create the manipulator toolbar + this._createManipulatorBar(); + } + }, + + + /** + * Mixin the navigation (User Interface) system and initialize the parameters required + * + * @private + */ + _loadNavigationControls : function() { + this._loadMixin(NavigationMixin); + + if (this.constants.navigation.enabled == true) { + this._loadNavigationElements(); + } + }, + + + /** + * this function exists to avoid errors when not loading the navigation system + */ + _relocateNavigation : function() { + // empty, is overloaded by navigation system + }, + + + /** + * this function exists to avoid errors when not loading the navigation system + */ + _unHighlightAll : function() { + // empty, is overloaded by the navigation system + } +} diff --git a/src/graph/NavigationMixin.js b/src/graph/graphMixins/NavigationMixin.js similarity index 100% rename from src/graph/NavigationMixin.js rename to src/graph/graphMixins/NavigationMixin.js diff --git a/src/graph/SectorsMixin.js b/src/graph/graphMixins/SectorsMixin.js similarity index 100% rename from src/graph/SectorsMixin.js rename to src/graph/graphMixins/SectorsMixin.js diff --git a/src/graph/SelectionMixin.js b/src/graph/graphMixins/SelectionMixin.js similarity index 100% rename from src/graph/SelectionMixin.js rename to src/graph/graphMixins/SelectionMixin.js diff --git a/src/graph/graphMixins/physics/PhysicsMixin.js b/src/graph/graphMixins/physics/PhysicsMixin.js new file mode 100644 index 00000000..2f155f94 --- /dev/null +++ b/src/graph/graphMixins/physics/PhysicsMixin.js @@ -0,0 +1,114 @@ +/** + * Created by Alex on 2/6/14. + */ + + +var physicsMixin = { + + _toggleBarnesHut : function() { + this.constants.physics.barnesHut.enabled = !this.constants.physics.barnesHut.enabled; + this._loadSelectedForceSolver(); + this.moving = true; + this.start(); + }, + /** + * Before calculating the forces, we check if we need to cluster to keep up performance and we check + * if there is more than one node. If it is just one node, we dont calculate anything. + * + * @private + */ + _initializeForceCalculation : function() { + // stop calculation if there is only one node + if (this.nodeIndices.length == 1) { + this.nodes[this.nodeIndices[0]]._setForce(0,0); + } + else { + // if there are too many nodes on screen, we cluster without repositioning + if (this.nodeIndices.length > this.constants.clustering.clusterThreshold && this.constants.clustering.enabled == true) { + this.clusterToFit(this.constants.clustering.reduceToNodes, false); + } + + // we now start the force calculation + this._calculateForces(); + } + }, + + + /** + * Calculate the external forces acting on the nodes + * Forces are caused by: edges, repulsing forces between nodes, gravity + * @private + */ + _calculateForces : function() { + this.barnesHutTree = undefined; + // Gravity is required to keep separated groups from floating off + // the forces are reset to zero in this loop by using _setForce instead + // of _addForce + this._calculateGravitationalForces(); + + this._calculateNodeForces(); + + this._calculateSpringForces(); + }, + + + _calculateGravitationalForces : function() { + var dx, dy, angle, fx, fy, node, i; + var nodes = this.nodes; + var gravity = this.constants.physics.centralGravity; + + for (i = 0; i < this.nodeIndices.length; i++) { + node = nodes[this.nodeIndices[i]]; + // gravity does not apply when we are in a pocket sector + if (this._sector() == "default") { + dx = -node.x;// + screenCenterPos.x; + dy = -node.y;// + screenCenterPos.y; + + angle = Math.atan2(dy, dx); + fx = Math.cos(angle) * gravity; + fy = Math.sin(angle) * gravity; + } + else { + fx = 0; + fy = 0; + } + node._setForce(fx, fy); + node.updateDamping(this.nodeIndices.length); + } + }, + + _calculateSpringForces : function() { + var dx, dy, angle, fx, fy, springForce, length, edgeLength, edge, edgeId; + var edges = this.edges; + + // forces caused by the edges, modelled as springs + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.connected) { + // only calculate forces if nodes are in the same sector + if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { + dx = (edge.to.x - edge.from.x); + dy = (edge.to.y - edge.from.y); + + edgeLength = edge.length; + + // this implies that the edges between big clusters are longer + edgeLength += (edge.to.growthIndicator + edge.from.growthIndicator) * this.constants.clustering.edgeGrowth; + length = Math.sqrt(dx * dx + dy * dy); + angle = Math.atan2(dy, dx); + + springForce = this.constants.physics.springConstant * (edgeLength - length); + + fx = Math.cos(angle) * springForce; + fy = Math.sin(angle) * springForce; + + edge.from._addForce(-fx, -fy); + edge.to._addForce(fx, fy); + } + } + } + } + } + +} \ No newline at end of file diff --git a/src/graph/physicsMixin.js b/src/graph/graphMixins/physics/barnesHut.js similarity index 55% rename from src/graph/physicsMixin.js rename to src/graph/graphMixins/physics/barnesHut.js index 357b256e..fd34fcee 100644 --- a/src/graph/physicsMixin.js +++ b/src/graph/graphMixins/physics/barnesHut.js @@ -1,194 +1,11 @@ /** - * Created by Alex on 2/6/14. + * Created by Alex on 2/10/14. */ +var barnesHutMixin = { -var physicsMixin = { - - _toggleBarnesHut : function() { - this.constants.physics.enableBarnesHut = !this.constants.physics.enableBarnesHut; - this.moving = true; - this.start(); - }, - /** - * Before calculating the forces, we check if we need to cluster to keep up performance and we check - * if there is more than one node. If it is just one node, we dont calculate anything. - * - * @private - */ - _initializeForceCalculation : function() { - // stop calculation if there is only one node - if (this.nodeIndices.length == 1) { - this.nodes[this.nodeIndices[0]]._setForce(0,0); - } - else { - // if there are too many nodes on screen, we cluster without repositioning - if (this.nodeIndices.length > this.constants.clustering.clusterThreshold && this.constants.clustering.enabled == true) { - this.clusterToFit(this.constants.clustering.reduceToNodes, false); - } - - // we now start the force calculation - if (this.constants.physics.enableBarnesHut == true) { - this._calculateForcesBarnesHut(); - } - else { - this.barnesHutTree = undefined; - this._calculateForcesRepulsion(); - } - } - }, - - - /** - * Calculate the external forces acting on the nodes - * Forces are caused by: edges, repulsing forces between nodes, gravity - * @private - */ - _calculateForcesRepulsion : function() { - // Gravity is required to keep separated groups from floating off - // the forces are reset to zero in this loop by using _setForce instead - // of _addForce - this._calculateGravitationalForces(); - - this._calculateRepulsionForces(); - - this._calculateSpringForces(); - }, - - /** - * Calculate the external forces acting on the nodes - * Forces are caused by: edges, repulsing forces between nodes, gravity - * @private - */ - _calculateForcesBarnesHut : function() { - this._calculateGravitationalForces(); - - this._calculateBarnesHutForces(); - - this._calculateSpringForces(); - }, - - - _clearForces : function() { - var node; - var nodes = this.nodes; - - for (var i = 0; i < this.nodeIndices.length; i++) { - node = nodes[this.nodeIndices[i]]; - node._setForce(0, 0); - node.updateDamping(this.nodeIndices.length); - } - }, - - _calculateGravitationalForces : function() { - var dx, dy, angle, fx, fy, node, i; - var nodes = this.nodes; - var gravity = this.constants.physics.centralGravity; - - for (i = 0; i < this.nodeIndices.length; i++) { - node = nodes[this.nodeIndices[i]]; - // gravity does not apply when we are in a pocket sector - if (this._sector() == "default") { - dx = -node.x;// + screenCenterPos.x; - dy = -node.y;// + screenCenterPos.y; - - angle = Math.atan2(dy, dx); - fx = Math.cos(angle) * gravity; - fy = Math.sin(angle) * gravity; - } - else { - fx = 0; - fy = 0; - } - node._setForce(fx, fy); - node.updateDamping(this.nodeIndices.length); - } - }, - - _calculateRepulsionForces : function() { - var dx, dy, angle, distance, fx, fy, clusterSize, - repulsingForce, node1, node2, i, j; - var nodes = this.nodes; - - // approximation constants - var a_base = -2/3; - var b = 4/3; - - // repulsing forces between nodes - var minimumDistance = this.constants.nodes.distance; - - // we loop from i over all but the last entree in the array - // j loops from i+1 to the last. This way we do not double count any of the indices, nor i == j - for (i = 0; i < this.nodeIndices.length-1; i++) { - node1 = nodes[this.nodeIndices[i]]; - for (j = i+1; j < this.nodeIndices.length; j++) { - node2 = nodes[this.nodeIndices[j]]; - clusterSize = (node1.clusterSize + node2.clusterSize - 2); - dx = node2.x - node1.x; - dy = node2.y - node1.y; - distance = Math.sqrt(dx * dx + dy * dy); - - minimumDistance = (clusterSize == 0) ? this.constants.nodes.distance : (this.constants.nodes.distance * (1 + clusterSize * this.constants.clustering.distanceAmplification)); - var a = a_base / minimumDistance; - if (distance < 2*minimumDistance) { // at 2.0 * the minimum distance, the force is 0.000045 - angle = Math.atan2(dy, dx); - - if (distance < 0.5*minimumDistance) { // at 0.5 * the minimum distance, the force is 0.993307 - repulsingForce = 1.0; - } - else { - repulsingForce = a * distance + b; // linear approx of 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)) - } - // amplify the repulsion for clusters. - repulsingForce *= (clusterSize == 0) ? 1 : 1 + clusterSize * this.constants.clustering.forceAmplification; - - fx = Math.cos(angle) * repulsingForce; - fy = Math.sin(angle) * repulsingForce ; - - node1._addForce(-fx, -fy); - node2._addForce(fx, fy); - } - } - } - }, - - _calculateSpringForces : function() { - var dx, dy, angle, fx, fy, springForce, length, edgeLength, edge, edgeId, clusterSize; - var edges = this.edges; - - // forces caused by the edges, modelled as springs - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.connected) { - // only calculate forces if nodes are in the same sector - if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { - clusterSize = (edge.to.clusterSize + edge.from.clusterSize - 2); - dx = (edge.to.x - edge.from.x); - dy = (edge.to.y - edge.from.y); - - edgeLength = edge.length; - - // this implies that the edges between big clusters are longer - edgeLength += clusterSize * this.constants.clustering.edgeGrowth; - length = Math.sqrt(dx * dx + dy * dy); - angle = Math.atan2(dy, dx); - - springForce = this.constants.physics.springConstant * (edgeLength - length); - - fx = Math.cos(angle) * springForce; - fy = Math.sin(angle) * springForce; - - edge.from._addForce(-fx, -fy); - edge.to._addForce(fx, fy); - } - } - } - } - }, - - _calculateBarnesHutForces : function() { + _calculateNodeForces : function() { this._formBarnesHutTree(); var nodes = this.nodes; @@ -221,7 +38,7 @@ var physicsMixin = { if (distance > 0) { // distance is 0 if it looks to apply a force on itself. // BarnesHut condition - if (distance * parentBranch.calcSize < this.constants.physics.barnesHutTheta) { + if (distance * parentBranch.calcSize < this.constants.physics.barnesHut.theta) { // Did not pass the condition, go into children if available if (parentBranch.childrenCount == 4) { this._getForceContribution(parentBranch.children.NW,node); @@ -243,8 +60,9 @@ var physicsMixin = { }, _getForceOnNode : function(parentBranch, node, dx ,dy, distance) { + //console.log(Math.max(Math.max(node.height,node.radius),node.width),parentBranch.maxWidth,distance); // even if the parentBranch only has one node, its Center of Mass is at the right place (the node in this case). - var gravityForce = this.constants.physics.barnesHutGravitationalConstant * parentBranch.mass * node.mass / (distance * distance); + var gravityForce = this.constants.physics.barnesHut.gravitationalConstant * parentBranch.mass * node.mass / (distance * distance); var angle = Math.atan2(dy, dx); var fx = Math.cos(angle) * gravityForce; var fy = Math.sin(angle) * gravityForce; @@ -259,9 +77,9 @@ var physicsMixin = { var nodeCount = nodeIndices.length; var minX = Number.MAX_VALUE, - minY = Number.MAX_VALUE, - maxX =-Number.MAX_VALUE, - maxY =-Number.MAX_VALUE; + minY = Number.MAX_VALUE, + maxX =-Number.MAX_VALUE, + maxY =-Number.MAX_VALUE; // get the range of the nodes for (var i = 0; i < nodeCount; i++) { @@ -280,15 +98,16 @@ var physicsMixin = { // construct the barnesHutTree var barnesHutTree = {root:{ - CenterOfMass:{x:0,y:0}, // Center of Mass - mass:0, - range:{minX:minX,maxX:maxX,minY:minY,maxY:maxY}, - size: Math.abs(maxX - minX), - calcSize: 1 / Math.abs(maxX - minX), - children: {data:null}, - level: 0, - childrenCount: 4 - }}; + CenterOfMass:{x:0,y:0}, // Center of Mass + mass:0, + range:{minX:minX,maxX:maxX,minY:minY,maxY:maxY}, + size: Math.abs(maxX - minX), + calcSize: 1 / Math.abs(maxX - minX), + children: {data:null}, + maxWidth: 0, + level: 0, + childrenCount: 4 + }}; this._splitBranch(barnesHutTree.root); // place the nodes one by one recursively @@ -313,6 +132,9 @@ var physicsMixin = { parentBranch.CenterOfMass.y *= totalMassInv; parentBranch.mass = totalMass; + var biggestSize = Math.max(Math.max(node.height,node.radius),node.width); + parentBranch.maxWidth = (parentBranch.maxWidth < biggestSize) ? biggestSize : parentBranch.maxWidth; + }, @@ -424,6 +246,7 @@ var physicsMixin = { size: 0.5 * parentBranch.size, calcSize: 2 * parentBranch.calcSize, children: {data:null}, + maxWidth: 0, level: parentBranch.level +1, childrenCount: 0 }; @@ -471,10 +294,11 @@ var physicsMixin = { ctx.stroke(); /* - if (branch.mass > 0) { - ctx.circle(branch.CenterOfMass.x, branch.CenterOfMass.y, 3*branch.mass); - ctx.stroke(); - } - */ + if (branch.mass > 0) { + ctx.circle(branch.CenterOfMass.x, branch.CenterOfMass.y, 3*branch.mass); + ctx.stroke(); + } + */ } + }; \ No newline at end of file diff --git a/src/graph/graphMixins/physics/repulsion.js b/src/graph/graphMixins/physics/repulsion.js new file mode 100644 index 00000000..26eacda9 --- /dev/null +++ b/src/graph/graphMixins/physics/repulsion.js @@ -0,0 +1,61 @@ +/** + * Created by Alex on 2/10/14. + */ + +var repulsionMixin = { + + + /** + * Calculate the forces the nodes apply on eachother based on a repulsion field. + * This field is linearly approximated. + * + * @private + */ + _calculateNodeForces : function() { + var dx, dy, angle, distance, fx, fy, combinedClusterSize, + repulsingForce, node1, node2, i, j; + var nodes = this.nodes; + + // approximation constants + var a_base = -2/3; + var b = 4/3; + + // repulsing forces between nodes + var minimumDistance = this.constants.nodes.distance; + + // we loop from i over all but the last entree in the array + // j loops from i+1 to the last. This way we do not double count any of the indices, nor i == j + for (i = 0; i < this.nodeIndices.length-1; i++) { + node1 = nodes[this.nodeIndices[i]]; + for (j = i+1; j < this.nodeIndices.length; j++) { + node2 = nodes[this.nodeIndices[j]]; + combinedClusterSize = (node1.growthIndicator + node2.growthIndicator); + dx = node2.x - node1.x; + dy = node2.y - node1.y; + distance = Math.sqrt(dx * dx + dy * dy); + + minimumDistance = (combinedClusterSize == 0) ? this.constants.nodes.distance : (this.constants.nodes.distance * (1 + combinedClusterSize * this.constants.clustering.distanceAmplification)); + var a = a_base / minimumDistance; + if (distance < 2*minimumDistance) { + angle = Math.atan2(dy, dx); + + if (distance < 0.5*minimumDistance) { + repulsingForce = 1.0; + } + else { + repulsingForce = a * distance + b; // linear approx of 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)) + } + // amplify the repulsion for clusters. + repulsingForce *= (combinedClusterSize == 0) ? 1 : 1 + combinedClusterSize * this.constants.clustering.forceAmplification; + repulsingForce *= node1.internalMultiplier * node2.internalMultiplier; + + fx = Math.cos(angle) * repulsingForce; + fy = Math.sin(angle) * repulsingForce; + + node1._addForce(-fx, -fy); + node2._addForce(fx, fy); + } + } + } + } +} \ No newline at end of file From 4b367b512cfaa579eea9df2a48b28fdaefc1c8a5 Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Mon, 10 Feb 2014 18:36:36 +0100 Subject: [PATCH 42/52] added most of smooth curve system. Check example 16 for bug related to size. --- examples/graph/02_random_nodes.html | 2 +- src/graph/Edge.js | 19 ++- src/graph/Graph.js | 37 +++++- src/graph/Node.js | 21 ++-- src/graph/graphMixins/ClusterMixin.js | 2 + src/graph/graphMixins/MixinLoader.js | 10 +- src/graph/graphMixins/SectorsMixin.js | 47 +++++++- src/graph/graphMixins/physics/PhysicsMixin.js | 109 ++++++++++++++++-- src/graph/graphMixins/physics/barnesHut.js | 13 +-- src/graph/graphMixins/physics/repulsion.js | 19 ++- 10 files changed, 241 insertions(+), 38 deletions(-) diff --git a/examples/graph/02_random_nodes.html b/examples/graph/02_random_nodes.html index 69ac60f8..e7ed640d 100755 --- a/examples/graph/02_random_nodes.html +++ b/examples/graph/02_random_nodes.html @@ -88,7 +88,7 @@ */ var options = { edges: { - length: 50 + }, stabilize: false }; diff --git a/src/graph/Edge.js b/src/graph/Edge.js index c5192f90..65c27f88 100644 --- a/src/graph/Edge.js +++ b/src/graph/Edge.js @@ -33,9 +33,11 @@ function Edge (properties, graph, constants) { this.value = undefined; this.length = constants.physics.springLength; this.selected = false; + this.smooth = constants.smoothCurves; this.from = null; // a node this.to = null; // a node + this.via = null; // a temp node // we use this to be able to reconnect the edge to a cluster if its node is put into a cluster // by storing the original information we can revert to the original connection when the cluser is opened. @@ -54,7 +56,6 @@ function Edge (properties, graph, constants) { this.lengthFixed = false; this.setProperties(properties, constants); - } /** @@ -73,6 +74,7 @@ Edge.prototype.setProperties = function(properties, constants) { if (properties.id !== undefined) {this.id = properties.id;} if (properties.style !== undefined) {this.style = properties.style;} if (properties.label !== undefined) {this.label = properties.label;} + if (this.label) { this.fontSize = constants.edges.fontSize; this.fontFace = constants.edges.fontFace; @@ -81,6 +83,7 @@ Edge.prototype.setProperties = function(properties, constants) { if (properties.fontSize !== undefined) {this.fontSize = properties.fontSize;} if (properties.fontFace !== undefined) {this.fontFace = properties.fontFace;} } + if (properties.title !== undefined) {this.title = properties.title;} if (properties.width !== undefined) {this.width = properties.width;} if (properties.value !== undefined) {this.value = properties.value;} @@ -284,7 +287,12 @@ Edge.prototype._line = function (ctx) { // draw a straight line ctx.beginPath(); ctx.moveTo(this.from.x, this.from.y); - ctx.lineTo(this.to.x, this.to.y); + if (this.smooth == true) { + ctx.quadraticCurveTo(this.via.x,this.via.y,this.to.x, this.to.y); + } + else { + ctx.lineTo(this.to.x, this.to.y); + } ctx.stroke(); }; @@ -625,4 +633,11 @@ Edge.prototype.select = function() { Edge.prototype.unselect = function() { this.selected = false; +} + +Edge.prototype.positionBezierNode = function() { + if (this.via !== null) { + this.via.x = 0.5 * (this.from.x + this.to.x); + this.via.y = 0.5 * (this.from.y + this.to.y); + } } \ No newline at end of file diff --git a/src/graph/Graph.js b/src/graph/Graph.js index ba319788..6801ed85 100644 --- a/src/graph/Graph.js +++ b/src/graph/Graph.js @@ -118,6 +118,7 @@ function Graph (container, data, options) { dataManipulationToolbar: { enabled: false }, + smoothCurves: true, maxVelocity: 35, minVelocity: 0.1, // px/s maxIterations: 1000 // maximum number of iteration to stabilize @@ -157,6 +158,9 @@ function Graph (container, data, options) { var graph = this; this.freezeSimulation = false;// freeze the simulation + + this.calculationNodes = {}; + this.calculationNodeIndices = []; this.nodeIndices = []; // array with all the indices of the nodes. Used to speed up forces calculation this.nodes = {}; // object with Node objects this.edges = {}; // object with Edge objects @@ -1398,6 +1402,7 @@ Graph.prototype._addEdges = function (ids) { this.moving = true; this._updateValueRange(edges); + this._createBezierNodes(); }; /** @@ -1545,8 +1550,9 @@ Graph.prototype._redraw = function() { this._doInAllSectors("_drawAllSectorNodes",ctx); this._doInAllSectors("_drawEdges",ctx); - this._doInAllSectors("_drawNodes",ctx,true); + this._doInAllSectors("_drawNodes",ctx,false); +// this._doInSupportSector("_drawNodes",ctx,true); // this._drawTree(ctx,"#F00F0F"); // restore original scaling and translation @@ -1660,7 +1666,6 @@ Graph.prototype._drawNodes = function(ctx,alwaysShow) { if (alwaysShow === undefined) { alwaysShow = false; } - // first draw the unselected nodes var nodes = this.nodes; var selected = []; @@ -1755,7 +1760,7 @@ Graph.prototype._isMoving = function(vmin) { * @private */ Graph.prototype._discreteStepNodes = function() { - var interval = 1; + var interval = 1.2; var nodes = this.nodes; if (this.constants.maxVelocity > 0) { @@ -1789,6 +1794,9 @@ Graph.prototype.start = function() { if (this.moving) { this._doInAllActiveSectors("_initializeForceCalculation"); this._doInAllActiveSectors("_discreteStepNodes"); + if (this.constants.smoothCurves) { + this._doInSupportSector("_discreteStepNodes"); + } this._findCenter(this._getRange()) } @@ -1873,6 +1881,29 @@ Graph.prototype.toggleFreeze = function() { }; +Graph.prototype._createBezierNodes = function() { + for (var edgeId in this.edges) { + if (this.edges.hasOwnProperty(edgeId)) { + var edge = this.edges[edgeId]; + if (edge.smooth == true) { + if (edge.via == null) { + this.sectors['support']['nodes'][edge.id] = new Node( + {id:edge.id, + mass:1, + shape:'circle', + internalMultiplier:1, + damping: 0.9},{},{},this.constants); + edge.via = this.sectors['support']['nodes'][edge.id]; + edge.via.parentEdgeId = edge.id; + edge.positionBezierNode(); + } + } + } + } + +}; + + Graph.prototype._initializeMixinLoaders = function () { for (var mixinFunction in graphMixinLoaders) { if (graphMixinLoaders.hasOwnProperty(mixinFunction)) { diff --git a/src/graph/Node.js b/src/graph/Node.js index 33009663..c9f96466 100644 --- a/src/graph/Node.js +++ b/src/graph/Node.js @@ -58,6 +58,9 @@ function Node(properties, imagelist, grouplist, constants) { this.grouplist = grouplist; + this.dampingBase = 0.9; + this.damping = 0.9; // this is manipulated in the updateDamping function + this.setProperties(properties, constants); // creating the variables for clustering @@ -77,11 +80,11 @@ function Node(properties, imagelist, grouplist, constants) { this.vx = 0.0; // velocity x this.vy = 0.0; // velocity y this.minForce = constants.minForce; - this.damping = 0.9; // this is manipulated in the updateDamping function this.graphScaleInv = 1; this.canvasTopLeft = {"x": -300, "y": -300}; this.canvasBottomRight = {"x": 300, "y": 300}; + this.parentEdgeId = null; } /** @@ -143,10 +146,10 @@ Node.prototype.setProperties = function(properties, constants) { if (properties.y !== undefined) {this.y = properties.y;} if (properties.value !== undefined) {this.value = properties.value;} - // physics - if (properties.internalMultiplier !== undefined) {this.internalMultiplier = properties.value;} - + // physics + if (properties.internalMultiplier !== undefined) {this.internalMultiplier = properties.internalMultiplier;} + if (properties.damping !== undefined) {this.dampingBase = properties.damping;} // navigation controls properties if (properties.horizontalAlignLeft !== undefined) {this.horizontalAlignLeft = properties.horizontalAlignLeft;} if (properties.verticalAlignTop !== undefined) {this.verticalAlignTop = properties.verticalAlignTop;} @@ -591,7 +594,7 @@ Node.prototype._resizeBox = function (ctx) { this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeWidthFactor; this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeHeightFactor; - this.growthIndicator = this.width - textSize.width + 2 * margin; + this.growthIndicator = this.width - (textSize.width + 2 * margin); // this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor; } @@ -693,7 +696,7 @@ Node.prototype._resizeCircle = function (ctx) { // this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeWidthFactor; // this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeHeightFactor; this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor; - this.growthIndicator = this.radius - diameter; + this.growthIndicator = this.radius - 0.5*diameter; } }; @@ -869,7 +872,7 @@ Node.prototype._resizeText = function (ctx) { this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor; - this.growthIndicator = this.width - textSize.width + 2 * margin; + this.growthIndicator = this.width - (textSize.width + 2 * margin); } }; @@ -980,8 +983,8 @@ Node.prototype.setScale = function(scale) { * * @param {Number} numberOfNodes */ -Node.prototype.updateDamping = function(numberOfNodes) { - this.damping = Math.min(1.5,0.9 + 0.01*this.growthIndicator); +Node.prototype.updateDamping = function() { + this.damping = Math.min(Math.max(1.5,this.dampingBase),this.dampingBase + 0.01*this.growthIndicator); }; diff --git a/src/graph/graphMixins/ClusterMixin.js b/src/graph/graphMixins/ClusterMixin.js index d377e326..ccc8fbba 100644 --- a/src/graph/graphMixins/ClusterMixin.js +++ b/src/graph/graphMixins/ClusterMixin.js @@ -81,6 +81,7 @@ var ClusterMixin = { // update the index list, dynamic edges and labels this._updateNodeIndexList(); this._updateDynamicEdges(); + this._setCalculationNodes(); this.updateLabels(); } @@ -275,6 +276,7 @@ var ClusterMixin = { for (var i = 0; i < this.nodeIndices.length; i++) { var node = this.nodes[this.nodeIndices[i]]; this._expandClusterNode(node,recursive,force); + this._setCalculationNodes(); } }, diff --git a/src/graph/graphMixins/MixinLoader.js b/src/graph/graphMixins/MixinLoader.js index fd13ef13..062e65ad 100644 --- a/src/graph/graphMixins/MixinLoader.js +++ b/src/graph/graphMixins/MixinLoader.js @@ -65,6 +65,7 @@ var graphMixinLoaders = { } else { this._clearMixin(barnesHutMixin); + this.barnesHutTree = undefined; this.constants.physics.centralGravity = this.constants.physics.repulsion.centralGravity; this.constants.physics.springLength = this.constants.physics.repulsion.springLength; @@ -101,13 +102,18 @@ var graphMixinLoaders = { "edges":{}, "nodeIndices":[], "formationScale": 1.0, - "drawingNode": undefined }, + "drawingNode": undefined }; this.sectors["frozen"] = { }, this.sectors["navigation"] = {"nodes":{}, "edges":{}, "nodeIndices":[], "formationScale": 1.0, - "drawingNode": undefined }, + "drawingNode": undefined }; + this.sectors["support"] = {"nodes":{}, + "edges":{}, + "nodeIndices":[], + "formationScale": 1.0, + "drawingNode": undefined }; this.nodeIndices = this.sectors["active"]["default"]["nodeIndices"]; // the node indices list is used to speed up the computation of the repulsion fields diff --git a/src/graph/graphMixins/SectorsMixin.js b/src/graph/graphMixins/SectorsMixin.js index f242dcfb..1661c28c 100644 --- a/src/graph/graphMixins/SectorsMixin.js +++ b/src/graph/graphMixins/SectorsMixin.js @@ -56,6 +56,20 @@ var SectorMixin = { }, + /** + * This function sets the global references to nodes, edges and nodeIndices back to + * those of the supplied active sector. + * + * @param sectorId + * @private + */ + _switchToSupportSector : function() { + this.nodeIndices = this.sectors["support"]["nodeIndices"]; + this.nodes = this.sectors["support"]["nodes"]; + this.edges = this.sectors["support"]["edges"]; + }, + + /** * This function sets the global references to nodes, edges and nodeIndices back to * those of the supplied frozen sector. @@ -349,6 +363,9 @@ var SectorMixin = { // finally, we update the node index list. this._updateNodeIndexList(); + + // we refresh the list with calulation nodes and calculation node indices. + this._setCalculationNodes(); } } }, @@ -393,6 +410,35 @@ var SectorMixin = { }, + /** + * This runs a function in all active sectors. This is used in _redraw() and the _initializeForceCalculation(). + * + * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors + * | we dont pass the function itself because then the "this" is the window object + * | instead of the Graph object + * @param {*} [argument] | Optional: arguments to pass to the runFunction + * @private + */ + _doInSupportSector : function(runFunction,argument) { + if (argument === undefined) { + this._switchToSupportSector(); + this[runFunction](); + } + else { + this._switchToSupportSector(); + var args = Array.prototype.splice.call(arguments, 1); + if (args.length > 1) { + this[runFunction](args[0],args[1]); + } + else { + this[runFunction](argument); + } + } + // we revert the global references back to our active sector + this._loadLatestSector(); + }, + + /** * This runs a function in all frozen sectors. This is used in the _redraw(). * @@ -483,7 +529,6 @@ var SectorMixin = { this._doInAllFrozenSectors(runFunction,argument); } } - }, diff --git a/src/graph/graphMixins/physics/PhysicsMixin.js b/src/graph/graphMixins/physics/PhysicsMixin.js index 2f155f94..1f7dc85c 100644 --- a/src/graph/graphMixins/physics/PhysicsMixin.js +++ b/src/graph/graphMixins/physics/PhysicsMixin.js @@ -40,25 +40,74 @@ var physicsMixin = { * @private */ _calculateForces : function() { - this.barnesHutTree = undefined; // Gravity is required to keep separated groups from floating off // the forces are reset to zero in this loop by using _setForce instead // of _addForce + this._setCalculationNodes(); + this._calculateGravitationalForces(); this._calculateNodeForces(); - this._calculateSpringForces(); + + if (this.constants.smoothCurves == true) { + this._calculateSpringForcesOnSupport(); + } + else { + this._calculateSpringForces(); + } }, + _setCalculationNodes : function() { + if (this.constants.smoothCurves == true) { + this.calculationNodes = {}; + this.calculationNodeIndices = []; - _calculateGravitationalForces : function() { - var dx, dy, angle, fx, fy, node, i; + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + this.calculationNodes[nodeId] = this.nodes[nodeId]; + } + } + var supportNodes = this.sectors['support']['nodes']; + for (var supportNodeId in supportNodes) { + if (supportNodes.hasOwnProperty(supportNodeId)) { + if (this.edges.hasOwnProperty(supportNodes[supportNodeId].parentEdgeId)) { + this.calculationNodes[supportNodeId] = supportNodes[supportNodeId]; + } + } + } + + for (var idx in this.calculationNodes) { + if (this.calculationNodes.hasOwnProperty(idx)) { + this.calculationNodeIndices.push(idx); + } + } + } + else { + this.calculationNodes = this.nodes; + this.calculationNodeIndices = this.nodeIndices; + } + }, + + + _clearForces : function() { + var node, i; var nodes = this.nodes; - var gravity = this.constants.physics.centralGravity; for (i = 0; i < this.nodeIndices.length; i++) { node = nodes[this.nodeIndices[i]]; + node._setForce(0, 0); + node.updateDamping(this.nodeIndices.length); + } + }, + + _calculateGravitationalForces : function() { + var dx, dy, angle, fx, fy, node, i; + var nodes = this.calculationNodes; + var gravity = this.constants.physics.centralGravity; + + for (i = 0; i < this.calculationNodeIndices.length; i++) { + node = nodes[this.calculationNodeIndices[i]]; // gravity does not apply when we are in a pocket sector if (this._sector() == "default") { dx = -node.x;// + screenCenterPos.x; @@ -73,7 +122,7 @@ var physicsMixin = { fy = 0; } node._setForce(fx, fy); - node.updateDamping(this.nodeIndices.length); + node.updateDamping(); } }, @@ -109,6 +158,52 @@ var physicsMixin = { } } } - } + }, + + _calculateSpringForcesOnSupport : function() { + var edgeLength, edge, edgeId, growthIndicator; + var edges = this.edges; + // forces caused by the edges, modelled as springs + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.connected) { + // only calculate forces if nodes are in the same sector + if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { + if (edge.via != null) { + var node1 = edge.to; + var node2 = edge.via; + var node3 = edge.from; + + edgeLength = 0.5*edge.length; + growthIndicator = 0.5*(node1.growthIndicator + node3.growthIndicator); + + // this implies that the edges between big clusters are longer + edgeLength += growthIndicator * this.constants.clustering.edgeGrowth; + + this._calculateSpringForce(node1,node2,edgeLength); + this._calculateSpringForce(node2,node3,edgeLength); + } + } + } + } + } + }, + + _calculateSpringForce : function(node1,node2,edgeLength) { + var dx, dy, angle, fx, fy, springForce, length; + + dx = (node1.x - node2.x); + dy = (node1.y - node2.y); + length = Math.sqrt(dx * dx + dy * dy); + angle = Math.atan2(dy, dx); + springForce = this.constants.physics.springConstant * (edgeLength - length); + + fx = Math.cos(angle) * springForce; + fy = Math.sin(angle) * springForce; + + node1._addForce(fx, fy); + node2._addForce(-fx, -fy); + } } \ No newline at end of file diff --git a/src/graph/graphMixins/physics/barnesHut.js b/src/graph/graphMixins/physics/barnesHut.js index fd34fcee..2321320b 100644 --- a/src/graph/graphMixins/physics/barnesHut.js +++ b/src/graph/graphMixins/physics/barnesHut.js @@ -6,13 +6,14 @@ var barnesHutMixin = { _calculateNodeForces : function() { - this._formBarnesHutTree(); - - var nodes = this.nodes; - var nodeIndices = this.nodeIndices; var node; + var nodes = this.calculationNodes; + var nodeIndices = this.calculationNodeIndices; var nodeCount = nodeIndices.length; + this._formBarnesHutTree(nodes,nodeIndices); + + var barnesHutTree = this.barnesHutTree; // place the nodes one by one recursively @@ -70,9 +71,7 @@ var barnesHutMixin = { }, - _formBarnesHutTree : function() { - var nodes = this.nodes; - var nodeIndices = this.nodeIndices; + _formBarnesHutTree : function(nodes,nodeIndices) { var node; var nodeCount = nodeIndices.length; diff --git a/src/graph/graphMixins/physics/repulsion.js b/src/graph/graphMixins/physics/repulsion.js index 26eacda9..3c01932f 100644 --- a/src/graph/graphMixins/physics/repulsion.js +++ b/src/graph/graphMixins/physics/repulsion.js @@ -14,7 +14,9 @@ var repulsionMixin = { _calculateNodeForces : function() { var dx, dy, angle, distance, fx, fy, combinedClusterSize, repulsingForce, node1, node2, i, j; - var nodes = this.nodes; + + var nodes = this.calculationNodes; + var nodeIndices = this.calculationNodeIndices; // approximation constants var a_base = -2/3; @@ -22,14 +24,14 @@ var repulsionMixin = { // repulsing forces between nodes var minimumDistance = this.constants.nodes.distance; - // we loop from i over all but the last entree in the array // j loops from i+1 to the last. This way we do not double count any of the indices, nor i == j - for (i = 0; i < this.nodeIndices.length-1; i++) { - node1 = nodes[this.nodeIndices[i]]; - for (j = i+1; j < this.nodeIndices.length; j++) { - node2 = nodes[this.nodeIndices[j]]; + for (i = 0; i < nodeIndices.length-1; i++) { + node1 = nodes[nodeIndices[i]]; + for (j = i+1; j < nodeIndices.length; j++) { + node2 = nodes[nodeIndices[j]]; combinedClusterSize = (node1.growthIndicator + node2.growthIndicator); + dx = node2.x - node1.x; dy = node2.y - node1.y; distance = Math.sqrt(dx * dx + dy * dy); @@ -45,6 +47,11 @@ var repulsionMixin = { else { repulsingForce = a * distance + b; // linear approx of 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)) } + + if (this.sectors['support']['nodes'].hasOwnProperty(node1.id)) { + // console.log(combinedClusterSize, repulsingForce, minimumDistance); + } + // amplify the repulsion for clusters. repulsingForce *= (combinedClusterSize == 0) ? 1 : 1 + combinedClusterSize * this.constants.clustering.forceAmplification; repulsingForce *= node1.internalMultiplier * node2.internalMultiplier; From fc95490f8a60c767f795865d36d17a7e52b88be1 Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Tue, 11 Feb 2014 16:00:04 +0100 Subject: [PATCH 43/52] Finalized Barnes Hut force calculation, set it to default. Completed smooth curves. Added comments. --- dist/vis.min.js | 32 ---- .../graph/19_scale_free_graph_clustering.html | 3 - src/graph/Graph.js | 96 ++++++----- src/graph/Node.js | 7 +- src/graph/graphMixins/ClusterMixin.js | 162 +++++++++++------- src/graph/graphMixins/physics/PhysicsMixin.js | 84 +++++---- src/graph/graphMixins/physics/barnesHut.js | 134 +++++++++++---- src/graph/graphMixins/physics/repulsion.js | 2 +- 8 files changed, 313 insertions(+), 207 deletions(-) delete mode 100644 dist/vis.min.js diff --git a/dist/vis.min.js b/dist/vis.min.js deleted file mode 100644 index 95acc029..00000000 --- a/dist/vis.min.js +++ /dev/null @@ -1,32 +0,0 @@ -/** - * vis.js - * https://github.com/almende/vis - * - * A dynamic, browser-based visualization library. - * - * @version 0.5.0-SNAPSHOT - * @date 2014-02-10 - * - * @license - * Copyright (C) 2011-2014 Almende B.V, http://almende.com - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -!function(t){if("object"==typeof exports)module.exports=t();else if("function"==typeof define&&define.amd)define(t);else{var e;"undefined"!=typeof window?e=window:"undefined"!=typeof global?e=global:"undefined"!=typeof self&&(e=self),e.vis=t()}}(function(){var define,module,exports;return function t(e,i,n){function s(r,a){if(!i[r]){if(!e[r]){var h="function"==typeof require&&require;if(!a&&h)return h(r,!0);if(o)return o(r,!0);throw new Error("Cannot find module '"+r+"'")}var l=i[r]={exports:{}};e[r][0].call(l.exports,function(t){var i=e[r][1][t];return s(i?i:t)},l,l.exports,t,e,i,n)}return i[r].exports}for(var o="function"==typeof require&&require,r=0;ri;++i)t.call(e||this,this[i],i,this)}),Array.prototype.map||(Array.prototype.map=function(t,e){var i,n,s;if(null==this)throw new TypeError(" this is null or not defined");var o=Object(this),r=o.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(e&&(i=e),n=new Array(r),s=0;r>s;){var a,h;s in o&&(a=o[s],h=t.call(i,a,s,o),n[s]=h),s++}return n}),Array.prototype.filter||(Array.prototype.filter=function(t){"use strict";if(null==this)throw new TypeError;var e=Object(this),i=e.length>>>0;if("function"!=typeof t)throw new TypeError;for(var n=[],s=arguments[1],o=0;i>o;o++)if(o in e){var r=e[o];t.call(s,r,o,e)&&n.push(r)}return n}),Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,e=!{toString:null}.propertyIsEnumerable("toString"),i=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],n=i.length;return function(s){if("object"!=typeof s&&"function"!=typeof s||null===s)throw new TypeError("Object.keys called on non-object");var o=[];for(var r in s)t.call(s,r)&&o.push(r);if(e)for(var a=0;n>a;a++)t.call(s,i[a])&&o.push(i[a]);return o}}()),Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s}),Object.create||(Object.create=function(t){function e(){}if(arguments.length>1)throw new Error("Object.create implementation only accepts the first parameter.");return e.prototype=t,new e}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s});var util={};util.isNumber=function(t){return t instanceof Number||"number"==typeof t},util.isString=function(t){return t instanceof String||"string"==typeof t},util.isDate=function(t){if(t instanceof Date)return!0;if(util.isString(t)){var e=ASPDateRegex.exec(t);if(e)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},util.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},util.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},util.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var n=arguments[e];for(var s in n)n.hasOwnProperty(s)&&void 0!==n[s]&&(t[s]=n[s])}return t},util.convert=function(t,e){var i;if(void 0===t)return void 0;if(null===t)return null;if(!e)return t;if("string"!=typeof e&&!(e instanceof String))throw new Error("Type must be a string");switch(e){case"boolean":case"Boolean":return Boolean(t);case"number":case"Number":return Number(t.valueOf());case"string":case"String":return String(t);case"Date":if(util.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(moment.isMoment(t))return new Date(t.valueOf());if(util.isString(t))return i=ASPDateRegex.exec(t),i?new Date(Number(i[1])):moment(t).toDate();throw new Error("Cannot convert object of type "+util.getType(t)+" to type Date");case"Moment":if(util.isNumber(t))return moment(t);if(t instanceof Date)return moment(t.valueOf());if(moment.isMoment(t))return moment(t);if(util.isString(t))return i=ASPDateRegex.exec(t),moment(i?Number(i[1]):t);throw new Error("Cannot convert object of type "+util.getType(t)+" to type Date");case"ISODate":if(util.isNumber(t))return new Date(t);if(t instanceof Date)return t.toISOString();if(moment.isMoment(t))return t.toDate().toISOString();if(util.isString(t))return i=ASPDateRegex.exec(t),i?new Date(Number(i[1])).toISOString():new Date(t).toISOString();throw new Error("Cannot convert object of type "+util.getType(t)+" to type ISODate");case"ASPDate":if(util.isNumber(t))return"/Date("+t+")/";if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(util.isString(t)){i=ASPDateRegex.exec(t);var n;return n=i?new Date(Number(i[1])).valueOf():new Date(t).valueOf(),"/Date("+n+")/"}throw new Error("Cannot convert object of type "+util.getType(t)+" to type ASPDate");default:throw new Error("Cannot convert object of type "+util.getType(t)+' to type "'+e+'"')}};var ASPDateRegex=/^\/?Date\((\-?\d+)/i;util.getType=function(t){var e=typeof t;return"object"==e?null==t?"null":t instanceof Boolean?"Boolean":t instanceof Number?"Number":t instanceof String?"String":t instanceof Array?"Array":t instanceof Date?"Date":"Object":"number"==e?"Number":"boolean"==e?"Boolean":"string"==e?"String":e},util.getAbsoluteLeft=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetLeft,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetLeft,n-=s.scrollLeft,s=s.offsetParent;return n},util.getAbsoluteTop=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetTop,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetTop,n-=s.scrollTop,s=s.offsetParent;return n},util.getPageY=function(t){if("pageY"in t)return t.pageY;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientY:t.clientY;var i=document.documentElement,n=document.body;return e+(i&&i.scrollTop||n&&n.scrollTop||0)-(i&&i.clientTop||n&&n.clientTop||0)},util.getPageX=function(t){if("pageY"in t)return t.pageX;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientX:t.clientX;var i=document.documentElement,n=document.body;return e+(i&&i.scrollLeft||n&&n.scrollLeft||0)-(i&&i.clientLeft||n&&n.clientLeft||0)},util.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},util.removeClassName=function(t,e){var i=t.className.split(" "),n=i.indexOf(e);-1!=n&&(i.splice(n,1),t.className=i.join(" "))},util.forEach=function(t,e){var i,n;if(t instanceof Array)for(i=0,n=t.length;n>i;i++)e(t[i],i,t);else for(i in t)t.hasOwnProperty(i)&&e(t[i],i,t)},util.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},util.addEventListener=function(t,e,i,n){t.addEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.addEventListener(e,i,n)):t.attachEvent("on"+e,i)},util.removeEventListener=function(t,e,i,n){t.removeEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.removeEventListener(e,i,n)):t.detachEvent("on"+e,i)},util.getTarget=function(t){t||(t=window.event);var e;return t.target?e=t.target:t.srcElement&&(e=t.srcElement),void 0!=e.nodeType&&3==e.nodeType&&(e=e.parentNode),e},util.stopPropagation=function(t){t||(t=window.event),t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},util.fakeGesture=function(t,e){var i=null;return Hammer.event.collectEventData(this,i,e)},util.preventDefault=function(t){t||(t=window.event),t.preventDefault?t.preventDefault():t.returnValue=!1},util.option={},util.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},util.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},util.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?String(t):e||null},util.option.asSize=function(t,e){return"function"==typeof t&&(t=t()),util.isString(t)?t:util.isNumber(t)?t+"px":e||null},util.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null},util.GiveDec=function GiveDec(Hex){return Value="A"==Hex?10:"B"==Hex?11:"C"==Hex?12:"D"==Hex?13:"E"==Hex?14:"F"==Hex?15:eval(Hex)},util.GiveHex=function(t){return Value=10==t?"A":11==t?"B":12==t?"C":13==t?"D":14==t?"E":15==t?"F":""+t},util.hexToRGB=function(t){t=t.replace("#","").toUpperCase();var e=util.GiveDec(t.substring(0,1)),i=util.GiveDec(t.substring(1,2)),n=util.GiveDec(t.substring(2,3)),s=util.GiveDec(t.substring(3,4)),o=util.GiveDec(t.substring(4,5)),r=util.GiveDec(t.substring(5,6)),a=16*e+i,h=16*n+s,i=16*o+r;return{r:a,g:h,b:i}},util.RGBToHex=function(t,e,i){var n=util.GiveHex(Math.floor(t/16)),s=util.GiveHex(t%16),o=util.GiveHex(Math.floor(e/16)),r=util.GiveHex(e%16),a=util.GiveHex(Math.floor(i/16)),h=util.GiveHex(i%16),l=n+s+o+r+a+h;return"#"+l},util.RGBToHSV=function(t,e,i){t/=255,e/=255,i/=255;var n=Math.min(t,Math.min(e,i)),s=Math.max(t,Math.max(e,i));if(n==s)return{h:0,s:0,v:n};var o=t==n?e-i:i==n?t-e:i-t,r=t==n?3:i==n?1:5,a=60*(r-o/(s-n))/360,h=(s-n)/s,l=s;return{h:a,s:h,v:l}},util.HSVToRGB=function(t,e,i){var n,s,o,r=Math.floor(6*t),a=6*t-r,h=i*(1-e),l=i*(1-a*e),c=i*(1-(1-a)*e);switch(r%6){case 0:n=i,s=c,o=h;break;case 1:n=l,s=i,o=h;break;case 2:n=h,s=i,o=c;break;case 3:n=h,s=l,o=i;break;case 4:n=c,s=h,o=i;break;case 5:n=i,s=h,o=l}return{r:Math.floor(255*n),g:Math.floor(255*s),b:Math.floor(255*o)}},util.HSVToHex=function(t,e,i){var n=util.HSVToRGB(t,e,i);return util.RGBToHex(n.r,n.g,n.b)},util.hexToHSV=function(t){var e=util.hexToRGB(t);return util.RGBToHSV(e.r,e.g,e.b)};var events={listeners:[],indexOf:function(t){for(var e=this.listeners,i=0,n=this.listeners.length;n>i;i++){var s=e[i];if(s&&s.object==t)return i}return-1},addListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];s||(s={object:t,events:{}},this.listeners.push(s));var o=s.events[e];o||(o=[],s.events[e]=o),-1==o.indexOf(i)&&o.push(i)},removeListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];o&&(n=o.indexOf(i),-1!=n&&o.splice(n,1),0==o.length&&delete s.events[e]);var r=0,a=s.events;for(var h in a)a.hasOwnProperty(h)&&r++;0==r&&delete this.listeners[n]}},removeAllListeners:function(){this.listeners=[]},trigger:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];if(o)for(var r=0,a=o.length;a>r;r++)o[r](i)}}};EventBus.prototype.on=function(t,e,i){var n=t instanceof RegExp?t:new RegExp(t.replace("*","\\w+")),s={id:util.randomUUID(),event:t,regexp:n,callback:"function"==typeof e?e:null,target:i};return this.subscriptions.push(s),s.id},EventBus.prototype.off=function(t){for(var e=0;eo;o++)i=s._addItem(t[o]),n.push(i);else if(util.isDataTable(t))for(var a=this._getColumnNames(t),h=0,l=t.getNumberOfRows();l>h;h++){for(var c={},d=0,u=a.length;u>d;d++){var p=a[d];c[p]=t.getValue(h,d)}i=s._addItem(c),n.push(i)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");i=s._addItem(t),n.push(i)}return n.length&&this._trigger("add",{items:n},e),n},DataSet.prototype.update=function(t,e){var i=[],n=[],s=this,o=s.fieldId,r=function(t){var e=t[o];s.data[e]?(e=s._updateItem(t),n.push(e)):(e=s._addItem(t),i.push(e))};if(t instanceof Array)for(var a=0,h=t.length;h>a;a++)r(t[a]);else if(util.isDataTable(t))for(var l=this._getColumnNames(t),c=0,d=t.getNumberOfRows();d>c;c++){for(var u={},p=0,f=l.length;f>p;p++){var g=l[p];u[g]=t.getValue(c,p)}r(u)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");r(t)}return i.length&&this._trigger("add",{items:i},e),n.length&&this._trigger("update",{items:n},e),i.concat(n)},DataSet.prototype.get=function(){var t,e,i,n,s=this,o=this.showInternalIds,r=util.getType(arguments[0]);"String"==r||"Number"==r?(t=arguments[0],i=arguments[1],n=arguments[2]):"Array"==r?(e=arguments[0],i=arguments[1],n=arguments[2]):(i=arguments[0],n=arguments[1]);var a;if(i&&i.type){if(a="DataTable"==i.type?"DataTable":"Array",n&&a!=util.getType(n))throw new Error('Type of parameter "data" ('+util.getType(n)+") does not correspond with specified options.type ("+i.type+")");if("DataTable"==a&&!util.isDataTable(n))throw new Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else a=n?"DataTable"==util.getType(n)?"DataTable":"Array":"Array";void 0!=i&&void 0!=i.showInternalIds&&(this.showInternalIds=i.showInternalIds);var h,l,c,d,u=i&&i.convert||this.options.convert,p=i&&i.filter,f=[];if(void 0!=t)h=s._getItem(t,u),p&&!p(h)&&(h=null);else if(void 0!=e)for(c=0,d=e.length;d>c;c++)h=s._getItem(e[c],u),(!p||p(h))&&f.push(h);else for(l in this.data)this.data.hasOwnProperty(l)&&(h=s._getItem(l,u),(!p||p(h))&&f.push(h));if(this.showInternalIds=o,i&&i.order&&void 0==t&&this._sort(f,i.order),i&&i.fields){var g=i.fields;if(void 0!=t)h=this._filterFields(h,g);else for(c=0,d=f.length;d>c;c++)f[c]=this._filterFields(f[c],g)}if("DataTable"==a){var m=this._getColumnNames(n);if(void 0!=t)s._appendRow(n,m,h);else for(c=0,d=f.length;d>c;c++)s._appendRow(n,m,f[c]);return n}if(void 0!=t)return h;if(n){for(c=0,d=f.length;d>c;c++)n.push(f[c]);return n}return f},DataSet.prototype.getIds=function(t){var e,i,n,s,o,r=this.data,a=t&&t.filter,h=t&&t.order,l=t&&t.convert||this.options.convert,c=[];if(a)if(h){o=[];for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,l),a(s)&&o.push(s));for(this._sort(o,h),e=0,i=o.length;i>e;e++)c[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,l),a(s)&&c.push(s[this.fieldId]));else if(h){o=[];for(n in r)r.hasOwnProperty(n)&&o.push(r[n]);for(this._sort(o,h),e=0,i=o.length;i>e;e++)c[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=r[n],c.push(s[this.fieldId]));return c},DataSet.prototype.forEach=function(t,e){var i,n,s=e&&e.filter,o=e&&e.convert||this.options.convert,r=this.data;if(e&&e.order)for(var a=this.get(e),h=0,l=a.length;l>h;h++)i=a[h],n=i[this.fieldId],t(i,n);else for(n in r)r.hasOwnProperty(n)&&(i=this._getItem(n,o),(!s||s(i))&&t(i,n))},DataSet.prototype.map=function(t,e){var i,n=e&&e.filter,s=e&&e.convert||this.options.convert,o=[],r=this.data;for(var a in r)r.hasOwnProperty(a)&&(i=this._getItem(a,s),(!n||n(i))&&o.push(t(i,a)));return e&&e.order&&this._sort(o,e.order),o},DataSet.prototype._filterFields=function(t,e){var i={};for(var n in t)t.hasOwnProperty(n)&&-1!=e.indexOf(n)&&(i[n]=t[n]);return i},DataSet.prototype._sort=function(t,e){if(util.isString(e)){var i=e;t.sort(function(t,e){var n=t[i],s=e[i];return n>s?1:s>n?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},DataSet.prototype.remove=function(t,e){var i,n,s,o=[];if(t instanceof Array)for(i=0,n=t.length;n>i;i++)s=this._remove(t[i]),null!=s&&o.push(s);else s=this._remove(t),null!=s&&o.push(s);return o.length&&this._trigger("remove",{items:o},e),o},DataSet.prototype._remove=function(t){if(util.isNumber(t)||util.isString(t)){if(this.data[t])return delete this.data[t],delete this.internalIds[t],t}else if(t instanceof Object){var e=t[this.fieldId];if(e&&this.data[e])return delete this.data[e],delete this.internalIds[e],e}return null},DataSet.prototype.clear=function(t){var e=Object.keys(this.data);return this.data={},this.internalIds={},this._trigger("remove",{items:e},t),e},DataSet.prototype.max=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||r>n)&&(i=o,n=r)}return i},DataSet.prototype.min=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||n>r)&&(i=o,n=r)}return i},DataSet.prototype.distinct=function(t){var e=this.data,i=[],n=this.options.convert[t],s=0;for(var o in e)if(e.hasOwnProperty(o)){for(var r=e[o],a=util.convert(r[t],n),h=!1,l=0;s>l;l++)if(i[l]==a){h=!0;break}h||(i[s]=a,s++)}return i},DataSet.prototype._addItem=function(t){var e=t[this.fieldId];if(void 0!=e){if(this.data[e])throw new Error("Cannot add item: item with id "+e+" already exists")}else e=util.randomUUID(),t[this.fieldId]=e,this.internalIds[e]=t;var i={};for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=util.convert(t[n],s)}return this.data[e]=i,e},DataSet.prototype._getItem=function(t,e){var i,n,s=this.data[t];if(!s)return null;var o={},r=this.fieldId,a=this.internalIds;if(e)for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a&&!this.showInternalIds||(o[i]=util.convert(n,e[i])));else for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a&&!this.showInternalIds||(o[i]=n));return o},DataSet.prototype._updateItem=function(t){var e=t[this.fieldId];if(void 0==e)throw new Error("Cannot update item: item has no id (item: "+JSON.stringify(t)+")");var i=this.data[e];if(!i)throw new Error("Cannot update item: no item with id "+e+" found");for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=util.convert(t[n],s)}return e},DataSet.prototype.isInternalId=function(t){return t in this.internalIds},DataSet.prototype._getColumnNames=function(t){for(var e=[],i=0,n=t.getNumberOfColumns();n>i;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},DataSet.prototype._appendRow=function(t,e,i){for(var n=t.addRow(),s=0,o=e.length;o>s;s++){var r=e[s];t.setValue(n,s,i[r])}},DataView.prototype.setData=function(t){var e,i,n;if(this.data){this.data.unsubscribe&&this.data.unsubscribe("*",this.listener),e=[];for(var s in this.ids)this.ids.hasOwnProperty(s)&&e.push(s);this.ids={},this._trigger("remove",{items:e})}if(this.data=t,this.data){for(this.fieldId=this.options.fieldId||this.data&&this.data.options&&this.data.options.fieldId||"id",e=this.data.getIds({filter:this.options&&this.options.filter}),i=0,n=e.length;n>i;i++)s=e[i],this.ids[s]=!0;this._trigger("add",{items:e}),this.data.subscribe&&this.data.subscribe("*",this.listener)}},DataView.prototype.get=function(){var t,e,i,n=this,s=util.getType(arguments[0]);"String"==s||"Number"==s||"Array"==s?(t=arguments[0],e=arguments[1],i=arguments[2]):(e=arguments[0],i=arguments[1]);var o=util.extend({},this.options,e);this.options.filter&&e&&e.filter&&(o.filter=function(t){return n.options.filter(t)&&e.filter(t)});var r=[];return void 0!=t&&r.push(t),r.push(o),r.push(i),this.data&&this.data.get.apply(this.data,r)},DataView.prototype.getIds=function(t){var e;if(this.data){var i,n=this.options.filter; -i=t&&t.filter?n?function(e){return n(e)&&t.filter(e)}:t.filter:n,e=this.data.getIds({filter:i,order:t&&t.order})}else e=[];return e},DataView.prototype._onEvent=function(t,e,i){var n,s,o,r,a=e&&e.items,h=this.data,l=[],c=[],d=[];if(a&&h){switch(t){case"add":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r&&(this.ids[o]=!0,l.push(o));break;case"update":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r?this.ids[o]?c.push(o):(this.ids[o]=!0,l.push(o)):this.ids[o]&&(delete this.ids[o],d.push(o));break;case"remove":for(n=0,s=a.length;s>n;n++)o=a[n],this.ids[o]&&(delete this.ids[o],d.push(o))}l.length&&this._trigger("add",{items:l},i),c.length&&this._trigger("update",{items:c},i),d.length&&this._trigger("remove",{items:d},i)}},DataView.prototype.subscribe=DataSet.prototype.subscribe,DataView.prototype.unsubscribe=DataSet.prototype.unsubscribe,DataView.prototype._trigger=DataSet.prototype._trigger,TimeStep=function(t,e,i){this.current=new Date,this._start=new Date,this._end=new Date,this.autoScale=!0,this.scale=TimeStep.SCALE.DAY,this.step=1,this.setRange(t,e,i)},TimeStep.SCALE={MILLISECOND:1,SECOND:2,MINUTE:3,HOUR:4,DAY:5,WEEKDAY:6,MONTH:7,YEAR:8},TimeStep.prototype.setRange=function(t,e,i){if(!(t instanceof Date&&e instanceof Date))throw"No legal start or end date in method setRange";this._start=void 0!=t?new Date(t.valueOf()):new Date,this._end=void 0!=e?new Date(e.valueOf()):new Date,this.autoScale&&this.setMinimumStep(i)},TimeStep.prototype.first=function(){this.current=new Date(this._start.valueOf()),this.roundToMinor()},TimeStep.prototype.roundToMinor=function(){switch(this.scale){case TimeStep.SCALE.YEAR:this.current.setFullYear(this.step*Math.floor(this.current.getFullYear()/this.step)),this.current.setMonth(0);case TimeStep.SCALE.MONTH:this.current.setDate(1);case TimeStep.SCALE.DAY:case TimeStep.SCALE.WEEKDAY:this.current.setHours(0);case TimeStep.SCALE.HOUR:this.current.setMinutes(0);case TimeStep.SCALE.MINUTE:this.current.setSeconds(0);case TimeStep.SCALE.SECOND:this.current.setMilliseconds(0)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.setMilliseconds(this.current.getMilliseconds()-this.current.getMilliseconds()%this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()-this.current.getSeconds()%this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()-this.current.getMinutes()%this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()-this.current.getHours()%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()-1-(this.current.getDate()-1)%this.step+1);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()-this.current.getMonth()%this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()-this.current.getFullYear()%this.step)}},TimeStep.prototype.hasNext=function(){return this.current.valueOf()<=this._end.valueOf()},TimeStep.prototype.next=function(){var t=this.current.valueOf();if(this.current.getMonth()<6)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current=new Date(this.current.valueOf()+1e3*this.step);break;case TimeStep.SCALE.MINUTE:this.current=new Date(this.current.valueOf()+1e3*this.step*60);break;case TimeStep.SCALE.HOUR:this.current=new Date(this.current.valueOf()+1e3*this.step*60*60);var e=this.current.getHours();this.current.setHours(e-e%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}else switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()+this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()+this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()+this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.getMilliseconds()0&&(this.step=e),this.autoScale=!1},TimeStep.prototype.setAutoScale=function(t){this.autoScale=t},TimeStep.prototype.setMinimumStep=function(t){if(void 0!=t){var e=31104e6,i=2592e6,n=864e5,s=36e5,o=6e4,r=1e3,a=1;1e3*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1e3),500*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=500),100*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=100),50*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=50),10*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=10),5*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=5),e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1),3*i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=3),i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=1),5*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=5),2*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=2),n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=1),n/2>t&&(this.scale=TimeStep.SCALE.WEEKDAY,this.step=1),4*s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=4),s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=1),15*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=15),10*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=10),5*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=5),o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=1),15*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=15),10*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=10),5*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=5),r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=1),200*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=200),100*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=100),50*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=50),10*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=10),5*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=5),a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=1)}},TimeStep.prototype.snap=function(t){if(this.scale==TimeStep.SCALE.YEAR){var e=t.getFullYear()+Math.round(t.getMonth()/12);t.setFullYear(Math.round(e/this.step)*this.step),t.setMonth(0),t.setDate(0),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MONTH)t.getDate()>15?(t.setDate(1),t.setMonth(t.getMonth()+1)):t.setDate(1),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0);else if(this.scale==TimeStep.SCALE.DAY||this.scale==TimeStep.SCALE.WEEKDAY){switch(this.step){case 5:case 2:t.setHours(24*Math.round(t.getHours()/24));break;default:t.setHours(12*Math.round(t.getHours()/12))}t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.HOUR){switch(this.step){case 4:t.setMinutes(60*Math.round(t.getMinutes()/60));break;default:t.setMinutes(30*Math.round(t.getMinutes()/30))}t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MINUTE){switch(this.step){case 15:case 10:t.setMinutes(5*Math.round(t.getMinutes()/5)),t.setSeconds(0);break;case 5:t.setSeconds(60*Math.round(t.getSeconds()/60));break;default:t.setSeconds(30*Math.round(t.getSeconds()/30))}t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.SECOND)switch(this.step){case 15:case 10:t.setSeconds(5*Math.round(t.getSeconds()/5)),t.setMilliseconds(0);break;case 5:t.setMilliseconds(1e3*Math.round(t.getMilliseconds()/1e3));break;default:t.setMilliseconds(500*Math.round(t.getMilliseconds()/500))}else if(this.scale==TimeStep.SCALE.MILLISECOND){var i=this.step>5?this.step/2:1;t.setMilliseconds(Math.round(t.getMilliseconds()/i)*i)}},TimeStep.prototype.isMajor=function(){switch(this.scale){case TimeStep.SCALE.MILLISECOND:return 0==this.current.getMilliseconds();case TimeStep.SCALE.SECOND:return 0==this.current.getSeconds();case TimeStep.SCALE.MINUTE:return 0==this.current.getHours()&&0==this.current.getMinutes();case TimeStep.SCALE.HOUR:return 0==this.current.getHours();case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return 1==this.current.getDate();case TimeStep.SCALE.MONTH:return 0==this.current.getMonth();case TimeStep.SCALE.YEAR:return!1;default:return!1}},TimeStep.prototype.getLabelMinor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return moment(t).format("SSS");case TimeStep.SCALE.SECOND:return moment(t).format("s");case TimeStep.SCALE.MINUTE:return moment(t).format("HH:mm");case TimeStep.SCALE.HOUR:return moment(t).format("HH:mm");case TimeStep.SCALE.WEEKDAY:return moment(t).format("ddd D");case TimeStep.SCALE.DAY:return moment(t).format("D");case TimeStep.SCALE.MONTH:return moment(t).format("MMM");case TimeStep.SCALE.YEAR:return moment(t).format("YYYY");default:return""}},TimeStep.prototype.getLabelMajor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return moment(t).format("HH:mm:ss");case TimeStep.SCALE.SECOND:return moment(t).format("D MMMM HH:mm");case TimeStep.SCALE.MINUTE:case TimeStep.SCALE.HOUR:return moment(t).format("ddd D MMMM");case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return moment(t).format("MMMM YYYY");case TimeStep.SCALE.MONTH:return moment(t).format("YYYY");case TimeStep.SCALE.YEAR:return"";default:return""}},Stack.prototype.setOptions=function(t){util.extend(this.options,t)},Stack.prototype.update=function(){this._order(),this._stack()},Stack.prototype._order=function(){var t=this.parent.items;if(!t)throw new Error("Cannot stack items: parent does not contain items");var e=[],i=0;util.forEach(t,function(t){t.visible&&(e[i]=t,i++)});var n=this.options.order||this.defaultOptions.order;if("function"!=typeof n)throw new Error("Option order must be a function");e.sort(n),this.ordered=e},Stack.prototype._stack=function(){var t,e,i,n=this.ordered,s=this.options,o=s.orientation||this.defaultOptions.orientation,r="top"==o;for(i=s.margin&&void 0!==s.margin.item?s.margin.item:this.defaultOptions.margin.item,t=0,e=n.length;e>t;t++){var a=n[t],h=null;do h=this.checkOverlap(n,t,0,t-1,i),null!=h&&(a.top=r?h.top+h.height+i:h.top-a.height-i);while(h)}},Stack.prototype.checkOverlap=function(t,e,i,n,s){for(var o=this.collision,r=t[e],a=n;a>=i;a--){var h=t[a];if(o(r,h,s)&&a!=e)return h}return null},Stack.prototype.collision=function(t,e,i){return t.left-ie.left&&t.top-ie.top},Range.prototype.setOptions=function(t){util.extend(this.options,t),null!==this.start&&null!==this.end&&this.setRange(this.start,this.end)},Range.prototype.subscribe=function(t,e,i){function n(e){s._onMouseWheel(e,t,i)}var s=this;if("move"==e)t.on("dragstart",function(e){s._onDragStart(e,t)}),t.on("drag",function(e){s._onDrag(e,t,i)}),t.on("dragend",function(e){s._onDragEnd(e,t)});else{if("zoom"!=e)throw new TypeError('Unknown event "'+e+'". Choose "move" or "zoom".');t.on("mousewheel",n),t.on("DOMMouseScroll",n),t.on("touch",function(){s._onTouch()}),t.on("pinch",function(e){s._onPinch(e,t,i)})}},Range.prototype.on=function(t,e){var i=["rangechange","rangechanged"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());events.addListener(this,t,e)},Range.prototype.off=function(t,e){events.removeListener(this,t,e)},Range.prototype._trigger=function(t){events.trigger(this,t,{start:this.start,end:this.end})},Range.prototype.setRange=function(t,e){var i=this._applyRange(t,e);i&&(this._trigger("rangechange"),this._trigger("rangechanged"))},Range.prototype._applyRange=function(t,e){var i,n=null!=t?util.convert(t,"Date").valueOf():this.start,s=null!=e?util.convert(e,"Date").valueOf():this.end,o=null!=this.options.max?util.convert(this.options.max,"Date").valueOf():null,r=null!=this.options.min?util.convert(this.options.min,"Date").valueOf():null;if(isNaN(n)||null===n)throw new Error('Invalid start "'+t+'"');if(isNaN(s)||null===s)throw new Error('Invalid end "'+e+'"');if(n>s&&(s=n),null!==r&&r>n&&(i=r-n,n+=i,s+=i,null!=o&&s>o&&(s=o)),null!==o&&s>o&&(i=s-o,n-=i,s-=i,null!=r&&r>n&&(n=r)),null!==this.options.zoomMin){var a=parseFloat(this.options.zoomMin);0>a&&(a=0),a>s-n&&(this.end-this.start===a?(n=this.start,s=this.end):(i=a-(s-n),n-=i/2,s+=i/2))}if(null!==this.options.zoomMax){var h=parseFloat(this.options.zoomMax);0>h&&(h=0),s-n>h&&(this.end-this.start===h?(n=this.start,s=this.end):(i=s-n-h,n+=i/2,s-=i/2))}var l=this.start!=n||this.end!=s;return this.start=n,this.end=s,l},Range.prototype.getRange=function(){return{start:this.start,end:this.end}},Range.prototype.conversion=function(t){return Range.conversion(this.start,this.end,t)},Range.conversion=function(t,e,i){return 0!=i&&e-t!=0?{offset:t,scale:i/(e-t)}:{offset:0,scale:1}};var touchParams={};Range.prototype._onDragStart=function(t,e){if(!touchParams.pinching){touchParams.start=this.start,touchParams.end=this.end;var i=e.frame;i&&(i.style.cursor="move")}},Range.prototype._onDrag=function(t,e,i){if(validateDirection(i),!touchParams.pinching){var n="horizontal"==i?t.gesture.deltaX:t.gesture.deltaY,s=touchParams.end-touchParams.start,o="horizontal"==i?e.width:e.height,r=-n/o*s;this._applyRange(touchParams.start+r,touchParams.end+r),this._trigger("rangechange")}},Range.prototype._onDragEnd=function(t,e){touchParams.pinching||(e.frame&&(e.frame.style.cursor="auto"),this._trigger("rangechanged"))},Range.prototype._onMouseWheel=function(t,e,i){validateDirection(i);var n=0;if(t.wheelDelta?n=t.wheelDelta/120:t.detail&&(n=-t.detail/3),n){var s;s=0>n?1-n/5:1/(1+n/5);var o=util.fakeGesture(this,t),r=getPointer(o.touches[0],e.frame),a=this._pointerToDate(e,i,r);this.zoom(s,a)}util.preventDefault(t)},Range.prototype._onTouch=function(){touchParams.start=this.start,touchParams.end=this.end,touchParams.pinching=!1,touchParams.center=null},Range.prototype._onPinch=function(t,e,i){if(touchParams.pinching=!0,t.gesture.touches.length>1){touchParams.center||(touchParams.center=getPointer(t.gesture.center,e.frame));var n=1/t.gesture.scale,s=this._pointerToDate(e,i,touchParams.center),o=getPointer(t.gesture.center,e.frame),r=(this._pointerToDate(e,i,o),parseInt(s+(touchParams.start-s)*n)),a=parseInt(s+(touchParams.end-s)*n);this.setRange(r,a)}},Range.prototype._pointerToDate=function(t,e,i){var n;if("horizontal"==e){var s=t.width;return n=this.conversion(s),i.x/n.scale+n.offset}var o=t.height;return n=this.conversion(o),i.y/n.scale+n.offset},Range.prototype.zoom=function(t,e){null==e&&(e=(this.start+this.end)/2);var i=e+(this.start-e)*t,n=e+(this.end-e)*t;this.setRange(i,n)},Range.prototype.move=function(t){var e=this.end-this.start,i=this.start+e*t,n=this.end+e*t;this.start=i,this.end=n},Range.prototype.moveTo=function(t){var e=(this.start+this.end)/2,i=e-t,n=this.start-i,s=this.end-i;this.setRange(n,s)},Controller.prototype.add=function(t){if(void 0==t.id)throw new Error("Component has no field id");if(!(t instanceof Component||t instanceof Controller))throw new TypeError("Component must be an instance of prototype Component or Controller");t.controller=this,this.components[t.id]=t},Controller.prototype.remove=function(t){var e;for(e in this.components)if(this.components.hasOwnProperty(e)&&(e==t||this.components[e]==t))break;e&&delete this.components[e]},Controller.prototype.requestReflow=function(t){if(t)this.reflow();else if(!this.reflowTimer){var e=this;this.reflowTimer=setTimeout(function(){e.reflowTimer=void 0,e.reflow()},0)}},Controller.prototype.requestRepaint=function(t){if(t)this.repaint();else if(!this.repaintTimer){var e=this;this.repaintTimer=setTimeout(function(){e.repaintTimer=void 0,e.repaint()},0)}},Controller.prototype.repaint=function t(){function t(n,s){s in i||(n.depends&&n.depends.forEach(function(e){t(e,e.id)}),n.parent&&t(n.parent,n.parent.id),e=n.repaint()||e,i[s]=!0)}var e=!1;this.repaintTimer&&(clearTimeout(this.repaintTimer),this.repaintTimer=void 0);var i={};util.forEach(this.components,t),e&&this.reflow()},Controller.prototype.reflow=function e(){function e(n,s){s in i||(n.depends&&n.depends.forEach(function(t){e(t,t.id)}),n.parent&&e(n.parent,n.parent.id),t=n.reflow()||t,i[s]=!0)}var t=!1;this.reflowTimer&&(clearTimeout(this.reflowTimer),this.reflowTimer=void 0);var i={};util.forEach(this.components,e),t&&this.repaint()},Component.prototype.setOptions=function(t){t&&(util.extend(this.options,t),this.controller&&(this.requestRepaint(),this.requestReflow()))},Component.prototype.getOption=function(t){var e;return this.options&&(e=this.options[t]),void 0===e&&this.defaultOptions&&(e=this.defaultOptions[t]),e},Component.prototype.getContainer=function(){return null},Component.prototype.getFrame=function(){return this.frame},Component.prototype.repaint=function(){return!1},Component.prototype.reflow=function(){return!1},Component.prototype.hide=function(){return this.frame&&this.frame.parentNode?(this.frame.parentNode.removeChild(this.frame),!0):!1},Component.prototype.show=function(){return this.frame&&this.frame.parentNode?!1:this.repaint()},Component.prototype.requestRepaint=function(){if(!this.controller)throw new Error("Cannot request a repaint: no controller configured");this.controller.requestRepaint()},Component.prototype.requestReflow=function(){if(!this.controller)throw new Error("Cannot request a reflow: no controller configured");this.controller.requestReflow()},Panel.prototype=new Component,Panel.prototype.setOptions=Component.prototype.setOptions,Panel.prototype.getContainer=function(){return this.frame},Panel.prototype.repaint=function(){var t=0,e=util.updateProperty,i=util.option.asSize,n=this.options,s=this.frame;if(!s){s=document.createElement("div"),s.className="panel";var o=n.className;o&&("function"==typeof o?util.addClassName(s,String(o())):util.addClassName(s,String(o))),this.frame=s,t+=1}if(!s.parentNode){if(!this.parent)throw new Error("Cannot repaint panel: no parent attached");var r=this.parent.getContainer();if(!r)throw new Error("Cannot repaint panel: parent has no container element");r.appendChild(s),t+=1}return t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),t>0},Panel.prototype.reflow=function(){var t=0,e=util.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},RootPanel.prototype=new Panel,RootPanel.prototype.setOptions=Component.prototype.setOptions,RootPanel.prototype.repaint=function(){var t=0,e=util.updateProperty,i=util.option.asSize,n=this.options,s=this.frame;if(s||(s=document.createElement("div"),this.frame=s,t+=1),!s.parentNode){if(!this.container)throw new Error("Cannot repaint root panel: no container attached");this.container.appendChild(s),t+=1}s.className="vis timeline rootpanel "+n.orientation;var o=n.className;return o&&util.addClassName(s,util.option.asString(o)),t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),this._updateEventEmitters(),this._updateWatch(),t>0},RootPanel.prototype.reflow=function(){var t=0,e=util.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},RootPanel.prototype._updateWatch=function(){var t=this.getOption("autoResize");t?this._watch():this._unwatch()},RootPanel.prototype._watch=function(){var t=this;this._unwatch();var e=function(){var e=t.getOption("autoResize");return e?void(t.frame&&(t.frame.clientWidth!=t.width||t.frame.clientHeight!=t.height)&&t.requestReflow()):void t._unwatch()};util.addEventListener(window,"resize",e),this.watchTimer=setInterval(e,1e3)},RootPanel.prototype._unwatch=function(){this.watchTimer&&(clearInterval(this.watchTimer),this.watchTimer=void 0)},RootPanel.prototype.on=function(t,e){var i=this.listeners[t];i||(i=[],this.listeners[t]=i),i.push(e),this._updateEventEmitters()},RootPanel.prototype._updateEventEmitters=function(){if(this.listeners){var t=this;util.forEach(this.listeners,function(e,i){if(t.emitters||(t.emitters={}),!(i in t.emitters)){var n=t.frame;if(n){var s=function(t){e.forEach(function(e){e(t)})};t.emitters[i]=s,t.hammer||(t.hammer=Hammer(n,{prevent_default:!0})),t.hammer.on(i,s)}}})}},TimeAxis.prototype=new Component,TimeAxis.prototype.setOptions=Component.prototype.setOptions,TimeAxis.prototype.setRange=function(t){if(!(t instanceof Range||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},TimeAxis.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},TimeAxis.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},TimeAxis.prototype.repaint=function(){var t=0,e=util.updateProperty,i=util.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.props,r=this.step,a=this.frame;if(a||(a=document.createElement("div"),this.frame=a,t+=1),a.className="axis",!a.parentNode){if(!this.parent)throw new Error("Cannot repaint time axis: no parent attached");var h=this.parent.getContainer();if(!h)throw new Error("Cannot repaint time axis: parent has no container element");h.appendChild(a),t+=1}var l=a.parentNode;if(l){var c=a.nextSibling;l.removeChild(a);var d="bottom"==s&&this.props.parentHeight&&this.height?this.props.parentHeight-this.height+"px":"0px";if(t+=e(a.style,"top",i(n.top,d)),t+=e(a.style,"left",i(n.left,"0px")),t+=e(a.style,"width",i(n.width,"100%")),t+=e(a.style,"height",i(n.height,this.height+"px")),this._repaintMeasureChars(),this.step){this._repaintStart(),r.first();for(var u=void 0,p=0;r.hasNext()&&1e3>p;){p++;var f=r.getCurrent(),g=this.toScreen(f),m=r.isMajor();this.getOption("showMinorLabels")&&this._repaintMinorText(g,r.getLabelMinor()),m&&this.getOption("showMajorLabels")?(g>0&&(void 0==u&&(u=g),this._repaintMajorText(g,r.getLabelMajor())),this._repaintMajorLine(g)):this._repaintMinorLine(g),r.next()}if(this.getOption("showMajorLabels")){var v=this.toTime(0),y=r.getLabelMajor(v),_=y.length*(o.majorCharWidth||10)+10;(void 0==u||u>_)&&this._repaintMajorText(0,y)}this._repaintEnd()}this._repaintLine(),c?l.insertBefore(a,c):l.appendChild(a)}return t>0},TimeAxis.prototype._repaintStart=function(){var t=this.dom,e=t.redundant;e.majorLines=t.majorLines,e.majorTexts=t.majorTexts,e.minorLines=t.minorLines,e.minorTexts=t.minorTexts,t.majorLines=[],t.majorTexts=[],t.minorLines=[],t.minorTexts=[]},TimeAxis.prototype._repaintEnd=function(){util.forEach(this.dom.redundant,function(t){for(;t.length;){var e=t.pop();e&&e.parentNode&&e.parentNode.removeChild(e)}})},TimeAxis.prototype._repaintMinorText=function(t,e){var i=this.dom.redundant.minorTexts.shift();if(!i){var n=document.createTextNode("");i=document.createElement("div"),i.appendChild(n),i.className="text minor",this.frame.appendChild(i)}this.dom.minorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.left=t+"px",i.style.top=this.props.minorLabelTop+"px"},TimeAxis.prototype._repaintMajorText=function(t,e){var i=this.dom.redundant.majorTexts.shift();if(!i){var n=document.createTextNode(e);i=document.createElement("div"),i.className="text major",i.appendChild(n),this.frame.appendChild(i)}this.dom.majorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.top=this.props.majorLabelTop+"px",i.style.left=t+"px"},TimeAxis.prototype._repaintMinorLine=function(t){var e=this.dom.redundant.minorLines.shift();e||(e=document.createElement("div"),e.className="grid vertical minor",this.frame.appendChild(e)),this.dom.minorLines.push(e);var i=this.props;e.style.top=i.minorLineTop+"px",e.style.height=i.minorLineHeight+"px",e.style.left=t-i.minorLineWidth/2+"px"},TimeAxis.prototype._repaintMajorLine=function(t){var e=this.dom.redundant.majorLines.shift();e||(e=document.createElement("DIV"),e.className="grid vertical major",this.frame.appendChild(e)),this.dom.majorLines.push(e);var i=this.props;e.style.top=i.majorLineTop+"px",e.style.left=t-i.majorLineWidth/2+"px",e.style.height=i.majorLineHeight+"px"},TimeAxis.prototype._repaintLine=function(){{var t=this.dom.line,e=this.frame;this.options}this.getOption("showMinorLabels")||this.getOption("showMajorLabels")?(t?(e.removeChild(t),e.appendChild(t)):(t=document.createElement("div"),t.className="grid horizontal major",e.appendChild(t),this.dom.line=t),t.style.top=this.props.lineTop+"px"):t&&t.parentElement&&(e.removeChild(t.line),delete this.dom.line)},TimeAxis.prototype._repaintMeasureChars=function(){var t,e=this.dom;if(!e.measureCharMinor){t=document.createTextNode("0");var i=document.createElement("DIV");i.className="text minor measure",i.appendChild(t),this.frame.appendChild(i),e.measureCharMinor=i}if(!e.measureCharMajor){t=document.createTextNode("0");var n=document.createElement("DIV");n.className="text major measure",n.appendChild(t),this.frame.appendChild(n),e.measureCharMajor=n}},TimeAxis.prototype.reflow=function(){var t=0,e=util.updateProperty,i=this.frame,n=this.range;if(!n)throw new Error("Cannot repaint time axis: no range configured");if(i){t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft);var s=this.props,o=this.getOption("showMinorLabels"),r=this.getOption("showMajorLabels"),a=this.dom.measureCharMinor,h=this.dom.measureCharMajor;a&&(s.minorCharHeight=a.clientHeight,s.minorCharWidth=a.clientWidth),h&&(s.majorCharHeight=h.clientHeight,s.majorCharWidth=h.clientWidth);var l=i.parentNode?i.parentNode.offsetHeight:0;switch(l!=s.parentHeight&&(s.parentHeight=l,t+=1),this.getOption("orientation")){case"bottom":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.minorLabelTop=0,s.majorLabelTop=s.minorLabelTop+s.minorLabelHeight,s.minorLineTop=-this.top,s.minorLineHeight=Math.max(this.top+s.majorLabelHeight,0),s.minorLineWidth=1,s.majorLineTop=-this.top,s.majorLineHeight=Math.max(this.top+s.minorLabelHeight+s.majorLabelHeight,0),s.majorLineWidth=1,s.lineTop=0;break;case"top":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.majorLabelTop=0,s.minorLabelTop=s.majorLabelTop+s.majorLabelHeight,s.minorLineTop=s.minorLabelTop,s.minorLineHeight=Math.max(l-s.majorLabelHeight-this.top),s.minorLineWidth=1,s.majorLineTop=0,s.majorLineHeight=Math.max(l-this.top),s.majorLineWidth=1,s.lineTop=s.majorLabelHeight+s.minorLabelHeight;break;default:throw new Error('Unkown orientation "'+this.getOption("orientation")+'"')}var c=s.minorLabelHeight+s.majorLabelHeight;t+=e(this,"width",i.offsetWidth),t+=e(this,"height",c),this._updateConversion();var d=util.convert(n.start,"Number"),u=util.convert(n.end,"Number"),p=this.toTime(5*(s.minorCharWidth||10)).valueOf()-this.toTime(0).valueOf();this.step=new TimeStep(new Date(d),new Date(u),p),t+=e(s.range,"start",d),t+=e(s.range,"end",u),t+=e(s.range,"minimumStep",p.valueOf())}return t>0},TimeAxis.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):Range.conversion(t.start,t.end,this.width)},CurrentTime.prototype=new Component,CurrentTime.prototype.setOptions=Component.prototype.setOptions,CurrentTime.prototype.getContainer=function(){return this.frame},CurrentTime.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCurrentTime"))return void(t&&(i.removeChild(t),delete this.frame));t||(t=document.createElement("div"),t.className="currenttime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t),this.frame=t),e.conversion||e._updateConversion();var n=new Date,s=e.toScreen(n);t.style.left=s+"px",t.title="Current time: "+n,void 0!==this.currentTimeTimer&&(clearTimeout(this.currentTimeTimer),delete this.currentTimeTimer);var o=this,r=1/e.conversion.scale/2;return 30>r&&(r=30),this.currentTimeTimer=setTimeout(function(){o.repaint()},r),!1},CustomTime.prototype=new Component,CustomTime.prototype.setOptions=Component.prototype.setOptions,CustomTime.prototype.getContainer=function(){return this.frame},CustomTime.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCustomTime"))return void(t&&(i.removeChild(t),delete this.frame));if(!t){t=document.createElement("div"),t.className="customtime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t);var n=document.createElement("div");n.style.position="relative",n.style.top="0px",n.style.left="-10px",n.style.height="100%",n.style.width="20px",t.appendChild(n),this.frame=t,this.subscribe(this,"movetime")}e.conversion||e._updateConversion();var s=e.toScreen(this.customTime);return t.style.left=s+"px",t.title="Time: "+this.customTime,!1},CustomTime.prototype._setCustomTime=function(t){this.customTime=new Date(t.valueOf()),this.repaint()},CustomTime.prototype._getCustomTime=function(){return new Date(this.customTime.valueOf())},CustomTime.prototype.subscribe=function(t,e){var i=this,n={component:t,event:e,callback:function(t){i._onMouseDown(t,n)},params:{}};t.on("mousedown",n.callback),i.listeners.push(n)},CustomTime.prototype.on=function(t,e){var i=this.frame;if(!i)throw new Error("Cannot add event listener: no parent attached");events.addListener(this,t,e),util.addEventListener(i,t,e)},CustomTime.prototype._onMouseDown=function(t,e){t=t||window.event;var i=e.params,n=t.which?1==t.which:1==t.button;if(n){i.mouseX=util.getPageX(t),i.moved=!1,i.customTime=this.customTime;var s=this;i.onMouseMove||(i.onMouseMove=function(t){s._onMouseMove(t,e)},util.addEventListener(document,"mousemove",i.onMouseMove)),i.onMouseUp||(i.onMouseUp=function(t){s._onMouseUp(t,e)},util.addEventListener(document,"mouseup",i.onMouseUp)),util.stopPropagation(t),util.preventDefault(t)}},CustomTime.prototype._onMouseMove=function(t,e){t=t||window.event;var i=e.params,n=this.parent,s=util.getPageX(t);void 0===i.mouseX&&(i.mouseX=s);var o=s-i.mouseX;Math.abs(o)>=1&&(i.moved=!0);var r=n.toScreen(i.customTime),a=r+o,h=n.toTime(a);this._setCustomTime(h),events.trigger(this,"timechange",{customTime:this.customTime}),util.preventDefault(t)},CustomTime.prototype._onMouseUp=function(t,e){t=t||window.event;var i=e.params;i.onMouseMove&&(util.removeEventListener(document,"mousemove",i.onMouseMove),i.onMouseMove=null),i.onMouseUp&&(util.removeEventListener(document,"mouseup",i.onMouseUp),i.onMouseUp=null),i.moved&&events.trigger(this,"timechanged",{customTime:this.customTime}) -},ItemSet.prototype=new Panel,ItemSet.types={box:ItemBox,range:ItemRange,rangeoverflow:ItemRangeOverflow,point:ItemPoint},ItemSet.prototype.setOptions=Component.prototype.setOptions,ItemSet.prototype.setRange=function(t){if(!(t instanceof Range||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},ItemSet.prototype.setSelection=function(t){var e,i,n,s,o;if(t){if(!Array.isArray(t))throw new TypeError("Array expected");for(e=0,i=this.selection.length;i>e;e++)n=this.selection[e],s=this.items[n],s&&s.unselect();for(this.selection=[],e=0,i=t.length;i>e;e++)n=t[e],s=this.items[n],s&&(this.selection.push(n),s.select());o=this.selection.concat([]),events.trigger(this,"select",{ids:o}),this.controller&&this.requestRepaint()}},ItemSet.prototype.getSelection=function(){return this.selection.concat([])},ItemSet.prototype._deselect=function(t){for(var e=this.selection,i=0,n=e.length;n>i;i++)if(e[i]==t){e.splice(i,1);break}},ItemSet.prototype.repaint=function(){var t=0,e=util.updateProperty,i=util.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.defaultOptions,r=this.frame;if(!r){r=document.createElement("div"),r.className="itemset";var a=n.className;a&&util.addClassName(r,util.option.asString(a));var h=document.createElement("div");h.className="background",r.appendChild(h),this.dom.background=h;var l=document.createElement("div");l.className="foreground",r.appendChild(l),this.dom.foreground=l;var c=document.createElement("div");c.className="itemset-axis",this.dom.axis=c,this.frame=r,t+=1}if(!this.parent)throw new Error("Cannot repaint itemset: no parent attached");var d=this.parent.getContainer();if(!d)throw new Error("Cannot repaint itemset: parent has no container element");r.parentNode||(d.appendChild(r),t+=1),this.dom.axis.parentNode||(d.appendChild(this.dom.axis),t+=1),t+=e(r.style,"left",i(n.left,"0px")),t+=e(r.style,"top",i(n.top,"0px")),t+=e(r.style,"width",i(n.width,"100%")),t+=e(r.style,"height",i(n.height,this.height+"px")),t+=e(this.dom.axis.style,"left",i(n.left,"0px")),t+=e(this.dom.axis.style,"width",i(n.width,"100%")),t+="bottom"==s?e(this.dom.axis.style,"top",this.height+this.top+"px"):e(this.dom.axis.style,"top",this.top+"px"),this._updateConversion();var u=this,p=this.queue,f=this.itemsData,g=this.items,m={};for(var v in p)if(p.hasOwnProperty(v)){var y=p[v],_=g[v],b=y.action;switch(b){case"add":case"update":var w=f&&f.get(v,m);if(w){var S=w.type||w.start&&w.end&&"range"||n.type||"box",T=ItemSet.types[S];if(_&&(T&&_ instanceof T?(_.data=w,t++):(t+=_.hide(),_=null)),!_){if(!T)throw new TypeError('Unknown item type "'+S+'"');_=new T(u,w,n,o),_.id=y.id,t++}_.repaint(),g[v]=_}delete p[v];break;case"remove":_&&(_.selected&&u._deselect(v),t+=_.hide()),delete g[v],delete p[v];break;default:console.log('Error: unknown action "'+b+'"')}}return util.forEach(this.items,function(e){e.visible?(t+=e.show(),e.reposition()):t+=e.hide()}),t>0},ItemSet.prototype.getForeground=function(){return this.dom.foreground},ItemSet.prototype.getBackground=function(){return this.dom.background},ItemSet.prototype.getAxis=function(){return this.dom.axis},ItemSet.prototype.reflow=function(){var t=0,e=this.options,i=e.margin&&e.margin.axis||this.defaultOptions.margin.axis,n=e.margin&&e.margin.item||this.defaultOptions.margin.item,s=util.updateProperty,o=util.option.asNumber,r=util.option.asSize,a=this.frame;if(a){this._updateConversion(),util.forEach(this.items,function(e){t+=e.reflow()}),this.stack.update();var h,l=o(e.maxHeight),c=null!=r(e.height);if(c)h=a.offsetHeight;else{var d=this.stack.ordered;if(d.length){var u=d[0].top,p=d[0].top+d[0].height;util.forEach(d,function(t){u=Math.min(u,t.top),p=Math.max(p,t.top+t.height)}),h=p-u+i+n}else h=i+n}null!=l&&(h=Math.min(h,l)),t+=s(this,"height",h),t+=s(this,"top",a.offsetTop),t+=s(this,"left",a.offsetLeft),t+=s(this,"width",a.offsetWidth)}else t+=1;return t>0},ItemSet.prototype.hide=function(){var t=!1;return this.frame&&this.frame.parentNode&&(this.frame.parentNode.removeChild(this.frame),t=!0),this.dom.axis&&this.dom.axis.parentNode&&(this.dom.axis.parentNode.removeChild(this.dom.axis),t=!0),t},ItemSet.prototype.setItems=function(t){var e,i=this,n=this.itemsData;if(t){if(!(t instanceof DataSet||t instanceof DataView))throw new TypeError("Data must be an instance of DataSet");this.itemsData=t}else this.itemsData=null;if(n&&(util.forEach(this.listeners,function(t,e){n.unsubscribe(e,t)}),e=n.getIds(),this._onRemove(e)),this.itemsData){var s=this.id;util.forEach(this.listeners,function(t,e){i.itemsData.subscribe(e,t,s)}),e=this.itemsData.getIds(),this._onAdd(e)}},ItemSet.prototype.getItems=function(){return this.itemsData},ItemSet.prototype._onUpdate=function(t){this._toQueue("update",t)},ItemSet.prototype._onAdd=function(t){this._toQueue("add",t)},ItemSet.prototype._onRemove=function(t){this._toQueue("remove",t)},ItemSet.prototype._toQueue=function(t,e){var i=this.queue;e.forEach(function(e){i[e]={id:e,action:t}}),this.controller&&this.requestRepaint()},ItemSet.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):Range.conversion(t.start,t.end,this.width)},ItemSet.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},ItemSet.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},Item.prototype.select=function(){this.selected=!0,this.visible&&this.repaint()},Item.prototype.unselect=function(){this.selected=!1,this.visible&&this.repaint()},Item.prototype.show=function(){return!1},Item.prototype.hide=function(){return!1},Item.prototype.repaint=function(){return!1},Item.prototype.reflow=function(){return!1},Item.prototype.getWidth=function(){return this.width},ItemBox.prototype=new Item(null,null),ItemBox.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");if(!e.box.parentNode){var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");i.appendChild(e.box),t=!0}if(!e.line.parentNode){var n=this.parent.getBackground();if(!n)throw new Error("Cannot repaint time axis: parent has no background container element");n.appendChild(e.line),t=!0}if(!e.dot.parentNode){var s=this.parent.getAxis();if(!n)throw new Error("Cannot repaint time axis: parent has no axis container element");s.appendChild(e.dot),t=!0}if(this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var o=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=o&&(this.className=o,e.box.className="item box"+o,e.line.className="item line"+o,e.dot.className="item dot"+o,t=!0)}return t},ItemBox.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},ItemBox.prototype.hide=function(){var t=!1,e=this.dom;return e&&(e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),e.line.parentNode&&e.line.parentNode.removeChild(e.line),e.dot.parentNode&&e.dot.parentNode.removeChild(e.dot)),t},ItemBox.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,l,c,d,u=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(c=this.data,d=this.parent&&this.parent.range,c&&d){var p=d.end-d.start;this.visible=c.start>d.start-p&&c.start0},ItemBox.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("DIV"),t.content=document.createElement("DIV"),t.content.className="content",t.box.appendChild(t.content),t.line=document.createElement("DIV"),t.line.className="line",t.dot=document.createElement("DIV"),t.dot.className="dot",t.box["timeline-item"]=this)},ItemBox.prototype.reposition=function(){var t=this.dom,e=this.props,i=this.options.orientation||this.defaultOptions.orientation;if(t){var n=t.box,s=t.line,o=t.dot;n.style.left=this.left+"px",n.style.top=this.top+"px",s.style.left=e.line.left+"px","top"==i?(s.style.top="0px",s.style.height=this.top+"px"):(s.style.top=this.top+this.height+"px",s.style.height=Math.max(this.parent.height-this.top-this.height+this.props.dot.height/2,0)+"px"),o.style.left=e.dot.left+"px",o.style.top=e.dot.top+"px"}},ItemPoint.prototype=new Item(null,null),ItemPoint.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.point.parentNode||(i.appendChild(e.point),i.appendChild(e.point),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.point.className="item point"+n,t=!0)}return t},ItemPoint.prototype.show=function(){return this.dom&&this.dom.point.parentNode?!1:this.repaint()},ItemPoint.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.point.parentNode&&(e.point.parentNode.removeChild(e.point),t=!0),t},ItemPoint.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,l,c=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(h=this.data,l=this.parent&&this.parent.range,h&&l){var d=l.end-l.start;this.visible=h.start>l.start-d&&h.start0},ItemPoint.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.point=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.point.appendChild(t.content),t.dot=document.createElement("div"),t.dot.className="dot",t.point.appendChild(t.dot),t.point["timeline-item"]=this)},ItemPoint.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.point.style.top=this.top+"px",t.point.style.left=this.left+"px",t.content.style.marginLeft=e.content.marginLeft+"px",t.dot.style.top=e.dot.top+"px")},ItemRange.prototype=new Item(null,null),ItemRange.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.box.className="item range"+n,t=!0)}return t},ItemRange.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},ItemRange.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),t},ItemRange.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,l,c,d,u,p,f,g,m=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(void 0==this.data.end)throw new Error('Property "end" missing in item '+this.data.id);return h=this.data,l=this.parent&&this.parent.range,this.visible=h&&l?h.startl.start:!1,this.visible&&(t=this.dom,t?(e=this.props,i=this.options,o=this.parent,r=o.toScreen(this.data.start),a=o.toScreen(this.data.end),c=util.updateProperty,d=t.box,u=o.width,f=i.orientation||this.defaultOptions.orientation,n=i.margin&&i.margin.axis||this.defaultOptions.margin.axis,s=i.padding||this.defaultOptions.padding,m+=c(e.content,"width",t.content.offsetWidth),m+=c(this,"height",d.offsetHeight),-u>r&&(r=-u),a>2*u&&(a=2*u),p=0>r?Math.min(-r,a-r-e.content.width-2*s):0,m+=c(e.content,"left",p),"top"==f?(g=n,m+=c(this,"top",g)):(g=o.height-this.height-n,m+=c(this,"top",g)),m+=c(this,"left",r),m+=c(this,"width",Math.max(a-r,1))):m+=1),m>0},ItemRange.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content),t.box["timeline-item"]=this)},ItemRange.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.box.style.top=this.top+"px",t.box.style.left=this.left+"px",t.box.style.width=this.width+"px",t.content.style.left=e.content.left+"px")},ItemRangeOverflow.prototype=new ItemRange(null,null),ItemRangeOverflow.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=this.data.className?" "+this.data.className:"";this.className!=n&&(this.className=n,e.box.className="item rangeoverflow"+n,t=!0)}return t},ItemRangeOverflow.prototype.getWidth=function(){return void 0!==this.props.content&&this.width0},GroupSet.prototype=new Panel,GroupSet.prototype.setOptions=Component.prototype.setOptions,GroupSet.prototype.setRange=function(){},GroupSet.prototype.setItems=function(t){this.itemsData=t;for(var e in this.groups)if(this.groups.hasOwnProperty(e)){var i=this.groups[e];i.setItems(t)}},GroupSet.prototype.getItems=function(){return this.itemsData},GroupSet.prototype.setRange=function(t){this.range=t},GroupSet.prototype.setGroups=function(t){var e,i=this;if(this.groupsData&&(util.forEach(this.listeners,function(t,e){i.groupsData.unsubscribe(e,t)}),e=this.groupsData.getIds(),this._onRemove(e)),t?t instanceof DataSet?this.groupsData=t:(this.groupsData=new DataSet({convert:{start:"Date",end:"Date"}}),this.groupsData.add(t)):this.groupsData=null,this.groupsData){var n=this.id;util.forEach(this.listeners,function(t,e){i.groupsData.subscribe(e,t,n)}),e=this.groupsData.getIds(),this._onAdd(e)}},GroupSet.prototype.getGroups=function(){return this.groupsData},GroupSet.prototype.setSelection=function(t){var e=[],i=this.groups;for(var n in i)if(i.hasOwnProperty(n)){var s=i[n];s.setSelection(t)}return e},GroupSet.prototype.getSelection=function(){var t=[],e=this.groups;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];t=t.concat(n.getSelection())}return t},GroupSet.prototype.repaint=function(){var t,e,i,n,s=0,o=util.updateProperty,r=util.option.asSize,a=util.option.asElement,h=this.options,l=this.dom.frame,c=this.dom.labels,d=this.dom.labelSet;if(!this.parent)throw new Error("Cannot repaint groupset: no parent attached");var u=this.parent.getContainer();if(!u)throw new Error("Cannot repaint groupset: parent has no container element");if(!l){l=document.createElement("div"),l.className="groupset",this.dom.frame=l;var p=h.className;p&&util.addClassName(l,util.option.asString(p)),s+=1}l.parentNode||(u.appendChild(l),s+=1);var f=a(h.labelContainer);if(!f)throw new Error('Cannot repaint groupset: option "labelContainer" not defined');c||(c=document.createElement("div"),c.className="labels",this.dom.labels=c),d||(d=document.createElement("div"),d.className="label-set",c.appendChild(d),this.dom.labelSet=d),c.parentNode&&c.parentNode==f||(c.parentNode&&c.parentNode.removeChild(c.parentNode),f.appendChild(c)),s+=o(l.style,"height",r(h.height,this.height+"px")),s+=o(l.style,"top",r(h.top,"0px")),s+=o(l.style,"left",r(h.left,"0px")),s+=o(l.style,"width",r(h.width,"100%")),s+=o(d.style,"top",r(h.top,"0px")),s+=o(d.style,"height",r(h.height,this.height+"px"));var g=this,m=this.queue,v=this.groups,y=this.groupsData,_=Object.keys(m);if(_.length){_.forEach(function(t){var e=m[t],i=v[t];switch(e){case"add":case"update":if(!i){var n=Object.create(g.options);util.extend(n,{height:null,maxHeight:null}),i=new Group(g,t,n),i.setItems(g.itemsData),v[t]=i,g.controller.add(i)}i.data=y.get(t),delete m[t];break;case"remove":i&&(i.setItems(),delete v[t],g.controller.remove(i)),delete m[t];break;default:console.log('Error: unknown action "'+e+'"')}});var b=this.groupsData.getIds({order:this.options.groupOrder});for(t=0;t0},GroupSet.prototype._createLabel=function(t){var e=this.groups[t],i=document.createElement("div");i.className="label";var n=document.createElement("div");n.className="inner",i.appendChild(n);var s=e.data&&e.data.content;s instanceof Element?n.appendChild(s):void 0!=s&&(n.innerHTML=s);var o=e.data&&e.data.className;return o&&util.addClassName(i,o),e.label=i,i},GroupSet.prototype.getContainer=function(){return this.dom.frame},GroupSet.prototype.getLabelsWidth=function(){return this.props.labels.width},GroupSet.prototype.reflow=function(){var t,e,i=0,n=this.options,s=util.updateProperty,o=util.option.asNumber,r=util.option.asSize,a=this.dom.frame;if(a){var h,l=o(n.maxHeight),c=null!=r(n.height);if(c)h=a.offsetHeight;else{h=0;for(t in this.groups)this.groups.hasOwnProperty(t)&&(e=this.groups[t],h+=e.height)}null!=l&&(h=Math.min(h,l)),i+=s(this,"height",h),i+=s(this,"top",a.offsetTop),i+=s(this,"left",a.offsetLeft),i+=s(this,"width",a.offsetWidth)}var d=0;for(t in this.groups)if(this.groups.hasOwnProperty(t)){e=this.groups[t];var u=e.props&&e.props.label&&e.props.label.width||0;d=Math.max(d,u)}return i+=s(this.props.labels,"width",d),i>0},GroupSet.prototype.hide=function(){return this.dom.frame&&this.dom.frame.parentNode?(this.dom.frame.parentNode.removeChild(this.dom.frame),!0):!1},GroupSet.prototype.show=function(){return this.dom.frame&&this.dom.frame.parentNode?!1:this.repaint()},GroupSet.prototype._onUpdate=function(t){this._toQueue(t,"update")},GroupSet.prototype._onAdd=function(t){this._toQueue(t,"add")},GroupSet.prototype._onRemove=function(t){this._toQueue(t,"remove")},GroupSet.prototype._toQueue=function(t,e){var i=this.queue;t.forEach(function(t){i[t]=e}),this.controller&&this.requestRepaint()},Timeline.prototype.setOptions=function(t){util.extend(this.options,t),this.range.setRange(t.start,t.end),this.controller.reflow(),this.controller.repaint()},Timeline.prototype.setCustomTime=function(t){this.customtime._setCustomTime(t)},Timeline.prototype.getCustomTime=function(){return new Date(this.customtime.customTime.valueOf())},Timeline.prototype.setItems=function(t){var e,i=null==this.itemsData;if(t?t instanceof DataSet&&(e=t):e=null,t instanceof DataSet||(e=new DataSet({convert:{start:"Date",end:"Date"}}),e.add(t)),this.itemsData=e,this.content.setItems(e),i&&(void 0==this.options.start||void 0==this.options.end)){var n=this.getItemRange(),s=n.min,o=n.max;if(null!=s&&null!=o){var r=o.valueOf()-s.valueOf();0>=r&&(r=864e5),s=new Date(s.valueOf()-.05*r),o=new Date(o.valueOf()+.05*r)}void 0!=this.options.start&&(s=util.convert(this.options.start,"Date")),void 0!=this.options.end&&(o=util.convert(this.options.end,"Date")),(null!=s||null!=o)&&this.range.setRange(s,o)}},Timeline.prototype.setGroups=function(t){var e=this;this.groupsData=t;var i=this.groupsData?GroupSet:ItemSet;if(!(this.content instanceof i)){this.content&&(this.content.hide(),this.content.setItems&&this.content.setItems(),this.content.setGroups&&this.content.setGroups(),this.controller.remove(this.content));var n=Object.create(this.options);util.extend(n,{top:function(){return"top"==e.options.orientation?e.timeaxis.height:e.itemPanel.height-e.timeaxis.height-e.content.height},left:null,width:"100%",height:function(){return e.options.height?e.itemPanel.height-e.timeaxis.height:null},maxHeight:function(){if(e.options.maxHeight){if(!util.isNumber(e.options.maxHeight))throw new TypeError("Number expected for property maxHeight");return e.options.maxHeight-e.timeaxis.height}return null},labelContainer:function(){return e.labelPanel.getContainer()}}),this.content=new i(this.itemPanel,[this.timeaxis],n),this.content.setRange&&this.content.setRange(this.range),this.content.setItems&&this.content.setItems(this.itemsData),this.content.setGroups&&this.content.setGroups(this.groupsData),this.controller.add(this.content)}},Timeline.prototype.getItemRange=function(){var t=this.itemsData,e=null,i=null;if(t){var n=t.min("start");e=n?n.start.valueOf():null;var s=t.max("start");s&&(i=s.start.valueOf());var o=t.max("end");o&&(i=null==i?o.end.valueOf():Math.max(i,o.end.valueOf()))}return{min:null!=e?new Date(e):null,max:null!=i?new Date(i):null}},Timeline.prototype.setSelection=function(t){this.content&&this.content.setSelection(t)},Timeline.prototype.getSelection=function(){return this.content?this.content.getSelection():[]},Timeline.prototype.on=function(t,e){var i=["rangechange","rangechanged","select"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());events.addListener(this,t,e)},Timeline.prototype.off=function(t,e){events.removeListener(this,t,e)},Timeline.prototype._trigger=function(t,e){events.trigger(this,t,e||{})},Timeline.prototype._onSelectItem=function(t){var e=this._itemFromTarget(t),i=e?[e.id]:[];this.setSelection(i),this._trigger("select",{items:this.getSelection()}),t.stopPropagation()},Timeline.prototype._onMultiSelectItem=function(t){var e,i=this._itemFromTarget(t);if(i){e=this.getSelection();var n=e.indexOf(i.id);-1==n?e.push(i.id):e.splice(n,1),this.setSelection(e),this._trigger("select",{items:this.getSelection()}),t.stopPropagation()}},Timeline.prototype._itemFromTarget=function(t){for(var e=t.target;e;){if(e.hasOwnProperty("timeline-item"))return e["timeline-item"];e=e.parentNode}return null},function(t){function e(t){return C=t,u()}function i(){M=0,D=C.charAt(0)}function n(){M++,D=C.charAt(M)}function s(){return C.charAt(M+1)}function o(t){return O.test(t)}function r(t,e){if(t||(t={}),e)for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function a(t,e,i){for(var n=e.split("."),s=t;n.length;){var o=n.shift();n.length?(s[o]||(s[o]={}),s=s[o]):s[o]=i}}function h(t,e){for(var i,n,s=null,o=[t],a=t;a.parent;)o.push(a.parent),a=a.parent;if(a.nodes)for(i=0,n=a.nodes.length;n>i;i++)if(e.id===a.nodes[i].id){s=a.nodes[i];break}for(s||(s={id:e.id},t.node&&(s.attr=r(s.attr,t.node))),i=o.length-1;i>=0;i--){var h=o[i];h.nodes||(h.nodes=[]),-1==h.nodes.indexOf(s)&&h.nodes.push(s)}e.attr&&(s.attr=r(s.attr,e.attr))}function l(t,e){if(t.edges||(t.edges=[]),t.edges.push(e),t.edge){var i=r({},t.edge);e.attr=r(i,e.attr)}}function c(t,e,i,n,s){var o={from:e,to:i,type:n};return t.edge&&(o.attr=r({},t.edge)),o.attr=r(o.attr||{},s),o}function d(){for(N=E.NULL,I="";" "==D||" "==D||"\n"==D||"\r"==D;)n();do{var t=!1;if("#"==D){for(var e=M-1;" "==C.charAt(e)||" "==C.charAt(e);)e--;if("\n"==C.charAt(e)||""==C.charAt(e)){for(;""!=D&&"\n"!=D;)n();t=!0}}if("/"==D&&"/"==s()){for(;""!=D&&"\n"!=D;)n();t=!0}if("/"==D&&"*"==s()){for(;""!=D;){if("*"==D&&"/"==s()){n(),n();break}n()}t=!0}for(;" "==D||" "==D||"\n"==D||"\r"==D;)n()}while(t);if(""==D)return void(N=E.DELIMITER);var i=D+s();if(x[i])return N=E.DELIMITER,I=i,n(),void n();if(x[D])return N=E.DELIMITER,I=D,void n();if(o(D)||"-"==D){for(I+=D,n();o(D);)I+=D,n();return"false"==I?I=!1:"true"==I?I=!0:isNaN(Number(I))||(I=Number(I)),void(N=E.IDENTIFIER)}if('"'==D){for(n();""!=D&&('"'!=D||'"'==D&&'"'==s());)I+=D,'"'==D&&n(),n();if('"'!=D)throw b('End of string " expected');return n(),void(N=E.IDENTIFIER)}for(N=E.UNKNOWN;""!=D;)I+=D,n();throw new SyntaxError('Syntax error in part "'+w(I,30)+'"')}function u(){var t={};if(i(),d(),"strict"==I&&(t.strict=!0,d()),("graph"==I||"digraph"==I)&&(t.type=I,d()),N==E.IDENTIFIER&&(t.id=I,d()),"{"!=I)throw b("Angle bracket { expected");if(d(),p(t),"}"!=I)throw b("Angle bracket } expected");if(d(),""!==I)throw b("End of file expected");return d(),delete t.node,delete t.edge,delete t.graph,t}function p(t){for(;""!==I&&"}"!=I;)f(t),";"==I&&d()}function f(t){var e=g(t);if(e)return void y(t,e);var i=m(t);if(!i){if(N!=E.IDENTIFIER)throw b("Identifier expected");var n=I;if(d(),"="==I){if(d(),N!=E.IDENTIFIER)throw b("Identifier expected");t[n]=I,d()}else v(t,n)}}function g(t){var e=null;if("subgraph"==I&&(e={},e.type="subgraph",d(),N==E.IDENTIFIER&&(e.id=I,d())),"{"==I){if(d(),e||(e={}),e.parent=t,e.node=t.node,e.edge=t.edge,e.graph=t.graph,p(e),"}"!=I)throw b("Angle bracket } expected");d(),delete e.node,delete e.edge,delete e.graph,delete e.parent,t.subgraphs||(t.subgraphs=[]),t.subgraphs.push(e)}return e}function m(t){return"node"==I?(d(),t.node=_(),"node"):"edge"==I?(d(),t.edge=_(),"edge"):"graph"==I?(d(),t.graph=_(),"graph"):null}function v(t,e){var i={id:e},n=_();n&&(i.attr=n),h(t,i),y(t,e)}function y(t,e){for(;"->"==I||"--"==I;){var i,n=I;d();var s=g(t);if(s)i=s;else{if(N!=E.IDENTIFIER)throw b("Identifier or subgraph expected");i=I,h(t,{id:i}),d()}var o=_(),r=c(t,e,i,n,o);l(t,r),e=i}}function _(){for(var t=null;"["==I;){for(d(),t={};""!==I&&"]"!=I;){if(N!=E.IDENTIFIER)throw b("Attribute name expected");var e=I;if(d(),"="!=I)throw b("Equal sign = expected");if(d(),N!=E.IDENTIFIER)throw b("Attribute value expected");var i=I;a(t,e,i),d(),","==I&&d()}if("]"!=I)throw b("Bracket ] expected");d()}return t}function b(t){return new SyntaxError(t+', got "'+w(I,30)+'" (char '+M+")")}function w(t,e){return t.length<=e?t:t.substr(0,27)+"..."}function S(t,e,i){t instanceof Array?t.forEach(function(t){e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}):e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}function T(t){function i(t){var e={from:t.from,to:t.to};return r(e,t.attr),e.style="->"==t.type?"arrow":"line",e}var n=e(t),s={nodes:[],edges:[],options:{}};return n.nodes&&n.nodes.forEach(function(t){var e={id:t.id,label:String(t.label||t.id)};r(e,t.attr),e.image&&(e.shape="image"),s.nodes.push(e)}),n.edges&&n.edges.forEach(function(t){var e,n;e=t.from instanceof Object?t.from.nodes:{id:t.from},n=t.to instanceof Object?t.to.nodes:{id:t.to},t.from instanceof Object&&t.from.edges&&t.from.edges.forEach(function(t){var e=i(t);s.edges.push(e)}),S(e,n,function(e,n){var o=c(s,e.id,n.id,t.type,t.attr),r=i(o);s.edges.push(r)}),t.to instanceof Object&&t.to.edges&&t.to.edges.forEach(function(t){var e=i(t);s.edges.push(e)})}),n.attr&&(s.options=n.attr),s}var E={NULL:0,DELIMITER:1,IDENTIFIER:2,UNKNOWN:3},x={"{":!0,"}":!0,"[":!0,"]":!0,";":!0,"=":!0,",":!0,"->":!0,"--":!0},C="",M=0,D="",I="",N=E.NULL,O=/[a-zA-Z_0-9.:#]/;t.parseDOT=e,t.DOTToGraph=T}("undefined"!=typeof util?util:exports),"undefined"!=typeof CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.circle=function(t,e,i){this.beginPath(),this.arc(t,e,i,0,2*Math.PI,!1)},CanvasRenderingContext2D.prototype.square=function(t,e,i){this.beginPath(),this.rect(t-i,e-i,2*i,2*i)},CanvasRenderingContext2D.prototype.triangle=function(t,e,i){this.beginPath();var n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e-(r-o)),this.lineTo(t+s,e+o),this.lineTo(t-s,e+o),this.lineTo(t,e-(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.triangleDown=function(t,e,i){this.beginPath();var n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e+(r-o)),this.lineTo(t+s,e-o),this.lineTo(t-s,e-o),this.lineTo(t,e+(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.star=function(t,e,i){this.beginPath();for(var n=0;10>n;n++){var s=n%2===0?1.3*i:.5*i;this.lineTo(t+s*Math.sin(2*n*Math.PI/10),e-s*Math.cos(2*n*Math.PI/10))}this.closePath()},CanvasRenderingContext2D.prototype.roundRect=function(t,e,i,n,s){var o=Math.PI/180;0>i-2*s&&(s=i/2),0>n-2*s&&(s=n/2),this.beginPath(),this.moveTo(t+s,e),this.lineTo(t+i-s,e),this.arc(t+i-s,e+s,s,270*o,360*o,!1),this.lineTo(t+i,e+n-s),this.arc(t+i-s,e+n-s,s,0,90*o,!1),this.lineTo(t+s,e+n),this.arc(t+s,e+n-s,s,90*o,180*o,!1),this.lineTo(t,e+s),this.arc(t+s,e+s,s,180*o,270*o,!1)},CanvasRenderingContext2D.prototype.ellipse=function(t,e,i,n){var s=.5522848,o=i/2*s,r=n/2*s,a=t+i,h=e+n,l=t+i/2,c=e+n/2;this.beginPath(),this.moveTo(t,c),this.bezierCurveTo(t,c-r,l-o,e,l,e),this.bezierCurveTo(l+o,e,a,c-r,a,c),this.bezierCurveTo(a,c+r,l+o,h,l,h),this.bezierCurveTo(l-o,h,t,c+r,t,c)},CanvasRenderingContext2D.prototype.database=function(t,e,i,n){var s=1/3,o=i,r=n*s,a=.5522848,h=o/2*a,l=r/2*a,c=t+o,d=e+r,u=t+o/2,p=e+r/2,f=e+(n-r/2),g=e+n; -this.beginPath(),this.moveTo(c,p),this.bezierCurveTo(c,p+l,u+h,d,u,d),this.bezierCurveTo(u-h,d,t,p+l,t,p),this.bezierCurveTo(t,p-l,u-h,e,u,e),this.bezierCurveTo(u+h,e,c,p-l,c,p),this.lineTo(c,f),this.bezierCurveTo(c,f+l,u+h,g,u,g),this.bezierCurveTo(u-h,g,t,f+l,t,f),this.lineTo(t,p)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,n){var s=t-n*Math.cos(i),o=e-n*Math.sin(i),r=t-.9*n*Math.cos(i),a=e-.9*n*Math.sin(i),h=s+n/3*Math.cos(i+.5*Math.PI),l=o+n/3*Math.sin(i+.5*Math.PI),c=s+n/3*Math.cos(i-.5*Math.PI),d=o+n/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,l),this.lineTo(r,a),this.lineTo(c,d),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,n,s){s||(s=[10,5]),0==u&&(u=.001);var o=s.length;this.moveTo(t,e);for(var r=i-t,a=n-e,h=a/r,l=Math.sqrt(r*r+a*a),c=0,d=!0;l>=.1;){var u=s[c++%o];u>l&&(u=l);var p=Math.sqrt(u*u/(1+h*h));0>r&&(p=-p),t+=p,e+=h*p,this[d?"lineTo":"moveTo"](t,e),l-=u,d=!d}}),Node.prototype.resetCluster=function(){this.formationScale=void 0,this.clusterSize=1,this.containedNodes={},this.containedEdges={},this.clusterSessions=[]},Node.prototype.attachEdge=function(t){-1==this.edges.indexOf(t)&&this.edges.push(t),-1==this.dynamicEdges.indexOf(t)&&this.dynamicEdges.push(t),this.dynamicEdgesLength=this.dynamicEdges.length},Node.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&(this.edges.splice(e,1),this.dynamicEdges.splice(e,1)),this.dynamicEdgesLength=this.dynamicEdges.length},Node.prototype.setProperties=function(t,e){if(t){if(this.originalLabel=void 0,void 0!==t.id&&(this.id=t.id),void 0!==t.label&&(this.label=t.label,this.originalLabel=t.label),void 0!==t.title&&(this.title=t.title),void 0!==t.group&&(this.group=t.group),void 0!==t.x&&(this.x=t.x),void 0!==t.y&&(this.y=t.y),void 0!==t.value&&(this.value=t.value),void 0!==t.internalMultiplier&&(this.internalMultiplier=t.value),void 0!==t.horizontalAlignLeft&&(this.horizontalAlignLeft=t.horizontalAlignLeft),void 0!==t.verticalAlignTop&&(this.verticalAlignTop=t.verticalAlignTop),void 0!==t.triggerFunction&&(this.triggerFunction=t.triggerFunction),void 0===this.id)throw"Node must have an id";if(this.group){var i=this.grouplist.get(this.group);for(var n in i)i.hasOwnProperty(n)&&(this[n]=i[n])}if(void 0!==t.shape&&(this.shape=t.shape),void 0!==t.image&&(this.image=t.image),void 0!==t.radius&&(this.radius=t.radius),void 0!==t.color&&(this.color=Node.parseColor(t.color)),void 0!==t.fontColor&&(this.fontColor=t.fontColor),void 0!==t.fontSize&&(this.fontSize=t.fontSize),void 0!==t.fontFace&&(this.fontFace=t.fontFace),void 0!==this.image){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.image)}switch(this.xFixed=this.xFixed||void 0!==t.x&&t.fixed,this.yFixed=this.yFixed||void 0!==t.y&&t.fixed,this.radiusFixed=this.radiusFixed||void 0!==t.radius,"image"==this.shape&&(this.radiusMin=e.nodes.widthMin,this.radiusMax=e.nodes.widthMax),this.shape){case"database":this.draw=this._drawDatabase,this.resize=this._resizeDatabase;break;case"box":this.draw=this._drawBox,this.resize=this._resizeBox;break;case"circle":this.draw=this._drawCircle,this.resize=this._resizeCircle;break;case"ellipse":this.draw=this._drawEllipse,this.resize=this._resizeEllipse;break;case"image":this.draw=this._drawImage,this.resize=this._resizeImage;break;case"text":this.draw=this._drawText,this.resize=this._resizeText;break;case"dot":this.draw=this._drawDot,this.resize=this._resizeShape;break;case"square":this.draw=this._drawSquare,this.resize=this._resizeShape;break;case"triangle":this.draw=this._drawTriangle,this.resize=this._resizeShape;break;case"triangleDown":this.draw=this._drawTriangleDown,this.resize=this._resizeShape;break;case"star":this.draw=this._drawStar,this.resize=this._resizeShape;break;default:this.draw=this._drawEllipse,this.resize=this._resizeEllipse}this._reset()}},Node.parseColor=function(t){var e;return util.isString(t)?e={border:t,background:t,highlight:{border:t,background:t}}:(e={},e.background=t.background||"white",e.border=t.border||e.background,util.isString(t.highlight)?e.highlight={border:t.highlight,background:t.highlight}:(e.highlight={},e.highlight.background=t.highlight&&t.highlight.background||e.background,e.highlight.border=t.highlight&&t.highlight.border||e.border)),e},Node.prototype.select=function(){this.selected=!0,this._reset()},Node.prototype.unselect=function(){this.selected=!1,this._reset()},Node.prototype.clearSizeCache=function(){this._reset()},Node.prototype._reset=function(){this.width=void 0,this.height=void 0},Node.prototype.getTitle=function(){return this.title},Node.prototype.distanceToBorder=function(t,e){var i=1;switch(this.width||this.resize(t),this.shape){case"circle":case"dot":return this.radius+i;case"ellipse":var n=this.width/2,s=this.height/2,o=Math.sin(e)*n,r=Math.cos(e)*s;return n*s/Math.sqrt(o*o+r*r);case"box":case"image":case"text":default:return this.width?Math.min(Math.abs(this.width/2/Math.cos(e)),Math.abs(this.height/2/Math.sin(e)))+i:0}},Node.prototype._setForce=function(t,e){this.fx=t,this.fy=e},Node.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},Node.prototype.discreteStep=function(t){if(!this.xFixed){var e=-this.damping*this.vx,i=(this.fx+e)/this.mass;this.vx+=i*t,this.x+=this.vx*t}if(!this.yFixed){var n=-this.damping*this.vy,s=(this.fy+n)/this.mass;this.vy+=s*t,this.y+=this.vy*t}},Node.prototype.discreteStepLimited=function(t,e){if(!this.xFixed){var i=-this.damping*this.vx,n=(this.fx+i)/this.mass;this.vx+=n*t,this.vx=Math.abs(this.vx)>e?this.vx>0?e:-e:this.vx,this.x+=this.vx*t}if(!this.yFixed){var s=-this.damping*this.vy,o=(this.fy+s)/this.mass;this.vy+=o*t,this.vy=Math.abs(this.vy)>e?this.vy>0?e:-e:this.vy,this.y+=this.vy*t}},Node.prototype.isFixed=function(){return this.xFixed&&this.yFixed},Node.prototype.isMoving=function(t){return Math.abs(this.vx)>t||Math.abs(this.vy)>t?!0:(this.vx=0,this.vy=0,!1)},Node.prototype.isSelected=function(){return this.selected},Node.prototype.getValue=function(){return this.value},Node.prototype.getDistance=function(t,e){var i=this.x-t,n=this.y-e;return Math.sqrt(i*i+n*n)},Node.prototype.setValueRange=function(t,e){if(!this.radiusFixed&&void 0!==this.value)if(e==t)this.radius=(this.radiusMin+this.radiusMax)/2;else{var i=(this.radiusMax-this.radiusMin)/(e-t);this.radius=(this.value-t)*i+this.radiusMin}this.baseRadiusValue=this.radius},Node.prototype.draw=function(){throw"Draw method not initialized for node"},Node.prototype.resize=function(){throw"Resize method not initialized for node"},Node.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},Node.prototype._resizeImage=function(){if(!this.width||!this.height){var t,e;if(this.value){this.radius=this.baseRadiusValue;var i=this.imageObj.height/this.imageObj.width;void 0!==i?(t=this.radius||this.imageObj.width,e=this.radius*i||this.imageObj.height):(t=0,e=0)}else t=this.imageObj.width,e=this.imageObj.height;this.width=t,this.height=e,this.width>0&&this.height>0&&(this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor)}},Node.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e;if(0!=this.imageObj.width){if(this.clusterSize>1){var i=this.clusterSize>1?10:0;i*=this.graphScaleInv,i=Math.min(.2*this.width,i),t.globalAlpha=.5,t.drawImage(this.imageObj,this.left-i,this.top-i,this.width+2*i,this.height+2*i)}t.globalAlpha=1,t.drawImage(this.imageObj,this.left,this.top,this.width,this.height),e=this.y+this.height/2}else e=this.y;this._label(t,this.label,this.x,e,void 0,"top")},Node.prototype._resizeBox=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=.5*(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=.5*(this.clusterSize-1)*this.clusterSizeHeightFactor}},Node.prototype._drawBox=function(t){this._resizeBox(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.roundRect(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth,this.radius),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.roundRect(this.left,this.top,this.width,this.height,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.prototype._resizeDatabase=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=i.width+2*e;this.width=n,this.height=n,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor}},Node.prototype._drawDatabase=function(t){this._resizeDatabase(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.database(this.x-this.width/2-2*t.lineWidth,this.y-.5*this.height-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.database(this.x-this.width/2,this.y-.5*this.height,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=Math.max(i.width,i.height)+2*e;this.radius=n/2,this.width=n,this.height=n,this.radius+=.5*(this.clusterSize-1)*this.clusterSizeRadiusFactor}},Node.prototype._drawCircle=function(t){this._resizeCircle(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.circle(this.x,this.y,this.radius+2*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.circle(this.x,this.y,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.prototype._resizeEllipse=function(t){if(!this.width){var e=this.getTextSize(t);this.width=1.5*e.width,this.height=2*e.height,this.width1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.ellipse(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.ellipse(this.left,this.top,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.prototype._drawDot=function(t){this._drawShape(t,"circle")},Node.prototype._drawTriangle=function(t){this._drawShape(t,"triangle")},Node.prototype._drawTriangleDown=function(t){this._drawShape(t,"triangleDown")},Node.prototype._drawSquare=function(t){this._drawShape(t,"square")},Node.prototype._drawStar=function(t){this._drawShape(t,"star")},Node.prototype._resizeShape=function(){if(!this.width){this.radius=this.baseRadiusValue;var t=2*this.radius;this.width=t,this.height=t,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=.5*(this.clusterSize-1)*this.clusterSizeRadiusFactor}},Node.prototype._drawShape=function(t,e){this._resizeShape(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var i=2.5,n=2,s=2;switch(e){case"dot":s=2;break;case"square":s=2;break;case"triangle":s=3;break;case"triangleDown":s=3;break;case"star":s=4}t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?n:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t[e](this.x,this.y,this.radius+s*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?n:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t[e](this.x,this.y,this.radius),t.fill(),t.stroke(),this.label&&this._label(t,this.label,this.x,this.y+this.height/2,void 0,"top")},Node.prototype._resizeText=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=(this.clusterSize-1)*this.clusterSizeWidthFactor,this.height+=(this.clusterSize-1)*this.clusterSizeHeightFactor,this.radius+=(this.clusterSize-1)*this.clusterSizeRadiusFactor}},Node.prototype._drawText=function(t){this._resizeText(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,this._label(t,this.label,this.x,this.y)},Node.prototype._label=function(t,e,i,n,s,o){if(e){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle=this.fontColor||"black",t.textAlign=s||"center",t.textBaseline=o||"middle";for(var r=e.split("\n"),a=r.length,h=this.fontSize+4,l=n+(1-a)/2*h,c=0;a>c;c++)t.fillText(r[c],i,l),l+=h}},Node.prototype.getTextSize=function(t){if(void 0!==this.label){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace;for(var e=this.label.split("\n"),i=(this.fontSize+4)*e.length,n=0,s=0,o=e.length;o>s;s++)n=Math.max(n,t.measureText(e[s]).width);return{width:n,height:i}}return{width:0,height:0}},Node.prototype.inArea=function(){return void 0!==this.width?this.x+this.width*this.graphScaleInv>=this.canvasTopLeft.x&&this.x-this.width*this.graphScaleInv=this.canvasTopLeft.y&&this.y-this.height*this.graphScaleInv=this.canvasTopLeft.x&&this.x=this.canvasTopLeft.y&&this.yh},Edge.prototype._drawLine=function(t){t.strokeStyle=this.color,t.lineWidth=this._getLineWidth();var e;if(this.from!=this.to)this._line(t),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y));else{var i,n,s=this.length/4,o=this.from;o.width||o.resize(t),o.width>o.height?(i=o.x+o.width/2,n=o.y-s):(i=o.x+s,n=o.y-o.height/2),this._circle(t,i,n,s),e=this._pointOnCircle(i,n,s,.5),this._label(t,this.label,e.x,e.y)}},Edge.prototype._getLineWidth=function(){return 1==this.selected?Math.min(2*this.width,this.widthMax)*this.graphScaleInv:this.width*this.graphScaleInv},Edge.prototype._line=function(t){t.beginPath(),t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y),t.stroke()},Edge.prototype._circle=function(t,e,i,n){t.beginPath(),t.arc(e,i,n,0,2*Math.PI,!1),t.stroke()},Edge.prototype._label=function(t,e,i,n){if(e){t.font=(this.from.selected||this.to.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle="white";var s=t.measureText(e).width,o=this.fontSize,r=i-s/2,a=n-o/2;t.fillRect(r,a,s,o),t.fillStyle=this.fontColor||"black",t.textAlign="left",t.textBaseline="top",t.fillText(e,r,a)}},Edge.prototype._drawDashLine=function(t){if(t.strokeStyle=this.color,t.lineWidth=this._getLineWidth(),t.beginPath(),t.lineCap="round",void 0!==this.dash.altLength?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]):void 0!==this.dash.length&&void 0!==this.dash.gap?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap]):(t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y)),t.stroke(),this.label){var e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}},Edge.prototype._pointOnLine=function(t){return{x:(1-t)*this.from.x+t*this.to.x,y:(1-t)*this.from.y+t*this.to.y}},Edge.prototype._pointOnCircle=function(t,e,i,n){var s=2*(n-3/8)*Math.PI;return{x:t+i*Math.cos(s),y:e-i*Math.sin(s)}},Edge.prototype._drawArrowCenter=function(t){var e;if(t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth(),this.from!=this.to){this._line(t);var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),n=10+5*this.width;e=this._pointOnLine(.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y))}else{var s,o,r=this.length/4,a=this.from;a.width||a.resize(t),a.width>a.height?(s=a.x+a.width/2,o=a.y-r):(s=a.x+r,o=a.y-a.height/2),this._circle(t,s,o,r);var i=.2*Math.PI,n=10+5*this.width;e=this._pointOnCircle(s,o,r,.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(s,o,r,.5),this._label(t,this.label,e.x,e.y))}},Edge.prototype._drawArrow=function(t){t.strokeStyle=this.color,t.fillStyle=this.color,t.lineWidth=this._getLineWidth();var e,i;if(this.from!=this.to){e=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x);var n=this.to.x-this.from.x,s=this.to.y-this.from.y,o=Math.sqrt(n*n+s*s),r=this.from.distanceToBorder(t,e+Math.PI),a=(o-r)/o,h=a*this.from.x+(1-a)*this.to.x,l=a*this.from.y+(1-a)*this.to.y,c=this.to.distanceToBorder(t,e),d=(o-c)/o,u=(1-d)*this.from.x+d*this.to.x,p=(1-d)*this.from.y+d*this.to.y;if(t.beginPath(),t.moveTo(h,l),t.lineTo(u,p),t.stroke(),i=10+5*this.width,t.arrow(u,p,e,i),t.fill(),t.stroke(),this.label){var f=this._pointOnLine(.5);this._label(t,this.label,f.x,f.y)}}else{var g,m,v,y=this.from,_=this.length/4;y.width||y.resize(t),y.width>y.height?(g=y.x+y.width/2,m=y.y-_,v={x:g,y:y.y,angle:.9*Math.PI}):(g=y.x+_,m=y.y-y.height/2,v={x:y.x,y:m,angle:.6*Math.PI}),t.beginPath(),t.arc(g,m,_,0,2*Math.PI,!1),t.stroke(),i=10+5*this.width,t.arrow(v.x,v.y,v.angle,i),t.fill(),t.stroke(),this.label&&(f=this._pointOnCircle(g,m,_,.5),this._label(t,this.label,f.x,f.y))}},Edge._dist=function(t,e,i,n,s,o){var r=i-t,a=n-e,h=r*r+a*a,l=((s-t)*r+(o-e)*a)/h;l>1?l=1:0>l&&(l=0);var c=t+l*r,d=e+l*a,u=c-s,p=d-o;return Math.sqrt(u*u+p*p)},Edge.prototype.setScale=function(t){this.graphScaleInv=1/t},Edge.prototype.select=function(){this.selected=!0},Edge.prototype.unselect=function(){this.selected=!1},Popup.prototype.setPosition=function(t,e){this.x=parseInt(t),this.y=parseInt(e)},Popup.prototype.setText=function(t){this.frame.innerHTML=t},Popup.prototype.show=function(t){if(void 0===t&&(t=!0),t){var e=this.frame.clientHeight,i=this.frame.clientWidth,n=this.frame.parentNode.clientHeight,s=this.frame.parentNode.clientWidth,o=this.y-e;o+e+this.padding>n&&(o=n-e-this.padding),os&&(r=s-i-this.padding),rthis.constants.clustering.clusterThreshold&&1==this.constants.clustering.enabled&&this.clusterToFit(this.constants.clustering.reduceToNodes,!1),this._calculateForces())},_calculateForces:function(){this.barnesHutTree=void 0,this._calculateGravitationalForces(),this._calculateNodeForces(),this._calculateSpringForces()},_calculateGravitationalForces:function(){var t,e,i,n,s,o,r,a=this.nodes,h=this.constants.physics.centralGravity;for(r=0;ro;o++)t=e[i[o]],this._getForceContribution(s.root.children.NW,t),this._getForceContribution(s.root.children.NE,t),this._getForceContribution(s.root.children.SW,t),this._getForceContribution(s.root.children.SE,t)},_getForceContribution:function(t,e){if(t.childrenCount>0){var i,n,s;i=t.CenterOfMass.x-e.x,n=t.CenterOfMass.y-e.y,s=Math.sqrt(i*i+n*n),s>0&&(s*t.calcSizeh;h++){var l=e[i[h]].x,c=e[i[h]].y;s>l&&(s=l),l>r&&(r=l),o>c&&(o=c),c>a&&(a=c)}var d=Math.abs(r-s)-Math.abs(a-o);d>0?(o-=.5*d,a+=.5*d):(s+=.5*d,r-=.5*d);var u={root:{CenterOfMass:{x:0,y:0},mass:0,range:{minX:s,maxX:r,minY:o,maxY:a},size:Math.abs(r-s),calcSize:1/Math.abs(r-s),children:{data:null},maxWidth:0,level:0,childrenCount:4}};for(this._splitBranch(u.root),h=0;n>h;h++)t=e[i[h]],this._placeInTree(u.root,t);this.barnesHutTree=u},_updateBranchMass:function(t,e){var i=t.mass+e.mass,n=1/i;t.CenterOfMass.x=t.CenterOfMass.x*t.mass+e.x*e.mass,t.CenterOfMass.x*=n,t.CenterOfMass.y=t.CenterOfMass.y*t.mass+e.y*e.mass,t.CenterOfMass.y*=n,t.mass=i;var s=Math.max(Math.max(e.height,e.radius),e.width);t.maxWidth=t.maxWidthe.x?t.children.NW.range.maxY>e.y?this._placeInRegion(t,e,"NW"):this._placeInRegion(t,e,"SW"):t.children.NE.range.maxY>e.y?this._placeInRegion(t,e,"NE"):this._placeInRegion(t,e,"SE")},_placeInRegion:function(t,e,i){switch(t.children[i].childrenCount){case 0:t.children[i].children.data=e,t.children[i].childrenCount=1,this._updateBranchMass(t.children[i],e);break;case 1:this._splitBranch(t.children[i]),this._placeInTree(t.children[i],e);break;case 4:this._placeInTree(t.children[i],e)}},_splitBranch:function(t){var e=null;1==t.childrenCount&&(e=t.children.data,t.mass=0,t.CenterOfMass.x=0,t.CenterOfMass.y=0),t.childrenCount=4,t.children.data=null,this._insertRegion(t,"NW"),this._insertRegion(t,"NE"),this._insertRegion(t,"SW"),this._insertRegion(t,"SE"),null!=e&&this._placeInTree(t,e)},_insertRegion:function(t,e){var i,n,s,o;switch(e){case"NW":i=t.range.minX,n=t.range.minX+t.size,s=t.range.minY,o=t.range.minY+t.size;break;case"NE":i=t.range.minX+t.size,n=t.range.maxX,s=t.range.minY,o=t.range.minY+t.size;break;case"SW":i=t.range.minX,n=t.range.minX+t.size,s=t.range.minY+t.size,o=t.range.maxY;break;case"SE":i=t.range.minX+t.size,n=t.range.maxX,s=t.range.minY+t.size,o=t.range.maxY}t.children[e]={CenterOfMass:{x:0,y:0},mass:0,range:{minX:i,maxX:n,minY:s,maxY:o},size:.5*t.size,calcSize:2*t.calcSize,children:{data:null},maxWidth:0,level:t.level+1,childrenCount:0}},_drawTree:function(t,e){void 0!==this.barnesHutTree&&(t.lineWidth=1,this._drawBranch(this.barnesHutTree.root,t,e))},_drawBranch:function(t,e,i){void 0===i&&(i="#FF0000"),4==t.childrenCount&&(this._drawBranch(t.children.NW,e),this._drawBranch(t.children.NE,e),this._drawBranch(t.children.SE,e),this._drawBranch(t.children.SW,e)),e.strokeStyle=i,e.beginPath(),e.moveTo(t.range.minX,t.range.minY),e.lineTo(t.range.maxX,t.range.minY),e.stroke(),e.beginPath(),e.moveTo(t.range.maxX,t.range.minY),e.lineTo(t.range.maxX,t.range.maxY),e.stroke(),e.beginPath(),e.moveTo(t.range.maxX,t.range.maxY),e.lineTo(t.range.minX,t.range.maxY),e.stroke(),e.beginPath(),e.moveTo(t.range.minX,t.range.maxY),e.lineTo(t.range.minX,t.range.minY),e.stroke()}},repulsionMixin={_calculateNodeForces:function(){var t,e,i,n,s,o,r,a,h,l,c,d,u=this.nodes,p=-2/3,f=4/3,g=this.constants.nodes.distance;for(c=0;cn&&(i=Math.atan2(e,t),a=.5*g>n?1:m*n+f,a*=0==r?1:1+r*this.constants.clustering.forceAmplification,a*=h.internalMultiplier*l.internalMultiplier,s=Math.cos(i)*a,o=Math.sin(i)*a,h._addForce(-s,-o),l._addForce(s,o))}}},manipulationMixin={_clearManipulatorBar:function(){for(;this.manipulationDiv.hasChildNodes();)this.manipulationDiv.removeChild(this.manipulationDiv.firstChild)},_createManipulatorBar:function(){for(this.off("select",this.boundFunction),this.blockConnectingEdgeSelection=!1,this.forceAppendSelection=!1;this.manipulationDiv.hasChildNodes();)this.manipulationDiv.removeChild(this.manipulationDiv.firstChild);this.manipulationDiv.innerHTML="Add Node
    Edit Selected
    Connect Node
    Delete selected";var t=document.getElementById("manipulate-addNode");t.onclick=this._createAddToolbar.bind(this); -var e=document.getElementById("manipulate-editNode");e.onclick=this._createEditToolbar.bind(this);var i=document.getElementById("manipulate-connectNode");i.onclick=this._createConnectToolbar.bind(this);var n=document.getElementById("manipulate-delete");n.onclick=this._createDeletionToolbar.bind(this)},_createAddToolbar:function(){this._clearManipulatorBar(),this.off("select",this.boundFunction),this.manipulationDiv.innerHTML="Back
    Click in an empty space to place a new node";var t=document.getElementById("manipulate-back");t.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._addNode.bind(this),this.on("select",this.boundFunction)},_createEditToolbar:function(){this.blockConnectingEdgeSelection=!1,this._clearManipulatorBar(),this.off("select",this.boundFunction);var t="";if(this._selectionIsEmpty()?t="Select a node or edge to edit.":this._getSelectedObjectCount()>1?(t="Select a single node or edge to edit.",this._unselectAll(!0)):this._clusterInSelection()?(t="You cannot edit a cluster.",this._unselectAll(!0)):this._getSelectedNodeCount()>0?this._createEditNodeToolbar():this._createEditEdgeToolbar(),""!=t){this.blockConnectingEdgeSelection=!0,this.manipulationDiv.innerHTML="Back
    "+t+"";var e=document.getElementById("manipulate-back");e.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._createEditToolbar.bind(this),this.on("select",this.boundFunction)}},_createEditNodeToolbar:function(){this.blockConnectingEdgeSelection=!1,this._clearManipulatorBar(),this.off("select",this.boundFunction);var t=this._getEditObject();this.manipulationDiv.innerHTML="Cancel
    label:
    color:
    ";var e=document.getElementById("manipulate-back");e.onclick=this._createManipulatorBar.bind(this);var i=document.getElementById("manipulator-obj-save");i.onclick=this._saveNodeData.bind(this),this.boundFunction=this._createManipulatorBar.bind(this),this.on("select",this.boundFunction)},_saveNodeData:function(){var t=this._getEditObject().id,e=document.getElementById("manipulator-obj-label").value,i=document.getElementById("manipulator-obj-color").value,n=util.hexToHSV(i),s={h:n.h,s:.45*n.s,v:Math.min(1,1.05*n.v)},o={h:n.h,s:Math.min(1,1.25*n.v),v:.6*n.v},r=util.HSVToHex(o.h,o.h,o.v),a=util.HSVToHex(s.h,s.s,s.v),h={id:t,label:e,color:{background:i,border:r,highlight:{background:a,border:r}}};this.nodesData.update(h),this._createManipulatorBar()},_createEditEdgeToolbar:function(){this.blockConnectingEdgeSelection=!1,this._clearManipulatorBar(),this.off("select",this.boundFunction),this.manipulationDiv.innerHTML="Back
    Currently only nodes can be edited.";var t=document.getElementById("manipulate-back");t.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._createManipulatorBar.bind(this),this.on("select",this.boundFunction)},_createConnectToolbar:function(){this._clearManipulatorBar(),this.off("select",this.boundFunction),this._unselectAll(),this.forceAppendSelection=!1,this.blockConnectingEdgeSelection=!0,this.manipulationDiv.innerHTML="Back
    Select the node you want to connect to other nodes.";var t=document.getElementById("manipulate-back");t.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._handleConnect.bind(this),this.on("select",this.boundFunction)},_createDeletionToolbar:function(){if(this._clearManipulatorBar(),this.off("select",this.boundFunction),this._selectionIsEmpty()){this.manipulationDiv.innerHTML="Cannot delete an empty selection.";var t=this;window.setTimeout(function(){t._createManipulatorBar()},1500)}else{this.manipulationDiv.innerHTML="Back
    Are you sure? This cannot be undone.
    Yes.";var e=document.getElementById("manipulate-back");e.onclick=this._createManipulatorBar.bind(this);var i=document.getElementById("manipulate-acceptDelete");i.onclick=this._deleteSelected.bind(this),this.boundFunction=this._createManipulatorBar.bind(this),this.on("select",this.boundFunction)}},_handleConnect:function(){this.forceAppendSelection=!1,this._clusterInSelection()?(this._unselectClusters(!0),this._selectionIsEmpty()?this._setManipulationMessage("You cannot connect anything to a cluster."):(this._setManipulationMessage("You cannot connect a node to a cluster."),this.forceAppendSelection=!0)):this._selectionIsEmpty()?this._setManipulationMessage("Select the node you want to connect to other nodes."):2==this._getSelectedNodeCount()?(this._connectNodes(),this._restoreSourceNode(),this._setManipulationMessage("Click on another node you want to connect this node to or go back.")):(this._setManipulationMessage("Click on the node you want to connect this node."),this._setSourceNode(),this.forceAppendSelection=!0)},_getEditObject:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t))return this.selectionObj[t];return null},_setSourceNode:function(){for(var t in this.selectionObj)this.selectionObj.hasOwnProperty(t)&&this.selectionObj[t]instanceof Node&&(this.manipulationSourceNode=this.selectionObj[t])},_getTargetNode:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t)&&this.selectionObj[t]instanceof Node&&this.manipulationSourceNode.id!=this.selectionObj[t].id)return this.selectionObj[t];return null},_restoreSourceNode:function(){this._unselectAll(!0),this._selectObject(this.manipulationSourceNode)},_setManipulationMessage:function(t){var e=document.getElementById("manipulatorLabel");e.innerHTML=t},_addNode:function(){if(this._selectionIsEmpty()){var t=this._pointerToPositionObject(this.pointerPosition);this.createNodeOnClick=!0,this.nodesData.add({id:util.randomUUID(),x:t.left,y:t.top,label:"new",fixed:!1}),this.createNodeOnClick=!1,this.moving=!0,this.start()}},_connectNodes:function(){var t=this._getTargetNode(),e=this.manipulationSourceNode;this.edgesData.add({from:e.id,to:t.id}),this.moving=!0,this.start()},_deleteSelected:function(){if(this._clusterInSelection())alert("Clusters cannot be deleted.");else{var t=this.getSelectedNodes(),e=this.getSelectedEdges();this._removeEdges(e),this._removeNodes(t),this.moving=!0,this.start()}}},SectorMixin={_putDataInSector:function(){this.sectors.active[this._sector()].nodes=this.nodes,this.sectors.active[this._sector()].edges=this.edges,this.sectors.active[this._sector()].nodeIndices=this.nodeIndices},_switchToSector:function(t,e){void 0===e||"active"==e?this._switchToActiveSector(t):this._switchToFrozenSector(t)},_switchToActiveSector:function(t){this.nodeIndices=this.sectors.active[t].nodeIndices,this.nodes=this.sectors.active[t].nodes,this.edges=this.sectors.active[t].edges},_switchToFrozenSector:function(t){this.nodeIndices=this.sectors.frozen[t].nodeIndices,this.nodes=this.sectors.frozen[t].nodes,this.edges=this.sectors.frozen[t].edges},_switchToNavigationSector:function(){this.nodeIndices=this.sectors.navigation.nodeIndices,this.nodes=this.sectors.navigation.nodes,this.edges=this.sectors.navigation.edges},_loadLatestSector:function(){this._switchToSector(this._sector())},_sector:function(){return this.activeSector[this.activeSector.length-1]},_previousSector:function(){if(this.activeSector.length>1)return this.activeSector[this.activeSector.length-2];throw new TypeError("there are not enough sectors in the this.activeSector array.")},_setActiveSector:function(t){this.activeSector.push(t)},_forgetLastSector:function(){this.activeSector.pop()},_createNewSector:function(t){this.sectors.active[t]={nodes:{},edges:{},nodeIndices:[],formationScale:this.scale,drawingNode:void 0},this.sectors.active[t].drawingNode=new Node({id:t,color:{background:"#eaefef",border:"495c5e"}},{},{},this.constants),this.sectors.active[t].drawingNode.clusterSize=2},_deleteActiveSector:function(t){delete this.sectors.active[t]},_deleteFrozenSector:function(t){delete this.sectors.frozen[t]},_freezeSector:function(t){this.sectors.frozen[t]=this.sectors.active[t],this._deleteActiveSector(t)},_activateSector:function(t){this.sectors.active[t]=this.sectors.frozen[t],this._deleteFrozenSector(t)},_mergeThisWithFrozen:function(t){for(var e in this.nodes)this.nodes.hasOwnProperty(e)&&(this.sectors.frozen[t].nodes[e]=this.nodes[e]);for(var i in this.edges)this.edges.hasOwnProperty(i)&&(this.sectors.frozen[t].edges[i]=this.edges[i]);for(var n=0;n1?this[t](n[0],n[1]):this[t](e)}this._loadLatestSector()},_doInAllFrozenSectors:function(t,e){if(void 0===e)for(var i in this.sectors.frozen)this.sectors.frozen.hasOwnProperty(i)&&(this._switchToFrozenSector(i),this[t]());else for(var i in this.sectors.frozen)if(this.sectors.frozen.hasOwnProperty(i)){this._switchToFrozenSector(i);var n=Array.prototype.splice.call(arguments,1);n.length>1?this[t](n[0],n[1]):this[t](e)}this._loadLatestSector()},_doInNavigationSector:function(t,e){if(this._switchToNavigationSector(),void 0===e)this[t]();else{var i=Array.prototype.splice.call(arguments,1);i.length>1?this[t](i[0],i[1]):this[t](e)}this._loadLatestSector()},_doInAllSectors:function(t,e){var i=Array.prototype.splice.call(arguments,1);void 0===e?(this._doInAllActiveSectors(t),this._doInAllFrozenSectors(t)):i.length>1?(this._doInAllActiveSectors(t,i[0],i[1]),this._doInAllFrozenSectors(t,i[0],i[1])):(this._doInAllActiveSectors(t,e),this._doInAllFrozenSectors(t,e))},_clearNodeIndexList:function(){var t=this._sector();this.sectors.active[t].nodeIndices=[],this.nodeIndices=this.sectors.active[t].nodeIndices},_drawSectorNodes:function(t,e){var i,n=1e9,s=-1e9,o=1e9,r=-1e9;for(var a in this.sectors[e])if(this.sectors[e].hasOwnProperty(a)&&void 0!==this.sectors[e][a].drawingNode){this._switchToSector(a,e),n=1e9,s=-1e9,o=1e9,r=-1e9;for(var h in this.nodes)this.nodes.hasOwnProperty(h)&&(i=this.nodes[h],i.resize(t),o>i.x-.5*i.width&&(o=i.x-.5*i.width),ri.y-.5*i.height&&(n=i.y-.5*i.height),st&&n>s;)s%3==0?this.forceAggregateHubs():this.increaseClusterLevel(),i=this.nodeIndices.length,s+=1;s>1&&1==e&&this.repositionNodes()},openCluster:function(t){var e=this.moving;if(t.clusterSize>this.constants.clustering.sectorThreshold&&this._nodeInActiveArea(t)&&("default"!=this._sector()||1!=this.nodeIndices.length)){this._addSector(t);for(var i=0;this.nodeIndices.lengthi;)this.decreaseClusterLevel(),i+=1}else this._expandClusterNode(t,!1,!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels();this.moving!=e&&this.start()},updateClustersDefault:function(){1==this.constants.clustering.enabled&&this.updateClusters(0,!1,!1)},increaseClusterLevel:function(){this.updateClusters(-1,!1,!0)},decreaseClusterLevel:function(){this.updateClusters(1,!1,!0)},updateClusters:function(t,e,i){var n=this.moving,s=this.nodeIndices.length;this.previousScale>this.scale&&0==t&&this._collapseSector(),this.previousScale>this.scale||-1==t?this._formClusters(i):(this.previousScalethis.scale||-1==t)&&(this._aggregateHubs(i),this._updateNodeIndexList()),(this.previousScale>this.scale||-1==t)&&(this.handleChains(),this._updateNodeIndexList()),this.previousScale=this.scale,this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.lengththis.constants.clustering.chainThreshold&&this._reduceAmountOfChains(1-this.constants.clustering.chainThreshold/t)},_aggregateHubs:function(t){this._getHubSize(),this._formClustersByHub(t,!1)},forceAggregateHubs:function(){var t=this.moving,e=this.nodeIndices.length;this._aggregateHubs(!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.length!=e&&(this.clusterSession+=1),this.moving!=t&&this.start()},_openClustersBySize:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];1==e.inView()&&(e.width*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientWidth||e.height*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientHeight)&&this.openCluster(e)}},_openClusters:function(t,e){for(var i=0;i1&&(t.clusterSizei)){var r=o.from,a=o.to;o.to.mass>o.from.mass&&(r=o.to,a=o.from),1==a.dynamicEdgesLength?this._addToCluster(r,a,!1):1==r.dynamicEdgesLength&&this._addToCluster(a,r,!1)}}},_forceClustersByZoom:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];if(1==e.dynamicEdgesLength&&0!=e.dynamicEdges.length){var i=e.dynamicEdges[0],n=i.toId==e.id?this.nodes[i.fromId]:this.nodes[i.toId];e.id!=n.id&&(n.mass>e.mass?this._addToCluster(n,e,!0):this._addToCluster(e,n,!0))}}},_formClustersByHub:function(t,e){for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&this._formClusterFromHub(this.nodes[i],t,e)},_formClusterFromHub:function(t,e,i,n){if(void 0===n&&(n=0),t.dynamicEdgesLength>=this.hubThreshold&&0==i||t.dynamicEdgesLength==this.hubThreshold&&1==i){for(var s,o,r,a=this.constants.clustering.clusterEdgeThreshold/this.scale,h=!1,l=[],c=t.dynamicEdges.length,d=0;c>d;d++)l.push(t.dynamicEdges[d].id);if(0==e)for(h=!1,d=0;c>d;d++){var u=this.edges[l[d]];if(void 0!==u&&u.connected&&u.toId!=u.fromId&&(s=u.to.x-u.from.x,o=u.to.y-u.from.y,r=Math.sqrt(s*s+o*o),a>r)){h=!0;break}}if(!e&&h||e)for(d=0;c>d;d++)if(u=this.edges[l[d]],void 0!==u){var p=this.nodes[u.fromId==t.id?u.toId:u.fromId];p.dynamicEdges.length<=this.hubThreshold+n&&p.id!=t.id&&this._addToCluster(t,p,e)}}},_addToCluster:function(t,e,i){t.containedNodes[e.id]=e;for(var n=0;n1)for(var n=0;n1&&(e.label="[".concat(String(e.clusterSize),"]"))}for(t in this.nodes)this.nodes.hasOwnProperty(t)&&(e=this.nodes[t],1==e.clusterSize&&(e.label=void 0!==e.originalLabel?e.originalLabel:String(e.id)))},_nodeInActiveArea:function(t){return Math.abs(t.x-this.areaCenter.x)<=this.constants.clustering.activeAreaBoxSize/this.scale&&Math.abs(t.y-this.areaCenter.y)<=this.constants.clustering.activeAreaBoxSize/this.scale},repositionNodes:function(){for(var t=0;tn&&(n=o.dynamicEdgesLength),t+=o.dynamicEdgesLength,e+=Math.pow(o.dynamicEdgesLength,2),i+=1}t/=i,e/=i;var r=e-Math.pow(t,2),a=Math.sqrt(r);this.hubThreshold=Math.floor(t+2*a),this.hubThreshold>n&&(this.hubThreshold=n)},_reduceAmountOfChains:function(t){this.hubThreshold=2;var e=Math.floor(this.nodeIndices.length*t);for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&e>0&&(this._formClusterFromHub(this.nodes[i],!0,!0,1),e-=1)},_getChainFraction:function(){var t=0,e=0;for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&(2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&(t+=1),e+=1);return t/e}},SelectionMixin={_getNodesOverlappingWith:function(t,e){var i=this.nodes;for(var n in i)i.hasOwnProperty(n)&&i[n].isOverlappingWith(t)&&e.push(n)},_getAllNodesOverlappingWith:function(t){var e=[];return this._doInAllActiveSectors("_getNodesOverlappingWith",t,e),e},_getAllNavigationNodesOverlappingWith:function(t){var e=[];return this._doInNavigationSector("_getNodesOverlappingWith",t,e),e},_pointerToPositionObject:function(t){var e=this._canvasToX(t.x),i=this._canvasToY(t.y);return{left:e,top:i,right:e,bottom:i}},_pointerToScreenPositionObject:function(t){var e=t.x,i=t.y;return{left:e,top:i,right:e,bottom:i}},_getNavigationNodeAt:function(t){var e=this._pointerToScreenPositionObject(t),i=this._getAllNavigationNodesOverlappingWith(e);return i.length>0?this.sectors.navigation.nodes[i[i.length-1]]:null},_getNodeAt:function(t){var e=this._pointerToPositionObject(t),i=this._getAllNodesOverlappingWith(e);return i.length>0?this.nodes[i[i.length-1]]:null},_getEdgesOverlappingWith:function(t,e){var i=this.edges;for(var n in i)i.hasOwnProperty(n)&&i[n].isOverlappingWith(t)&&e.push(n)},_getAllEdgesOverlappingWith:function(t){var e=[];return this._doInAllActiveSectors("_getEdgesOverlappingWith",t,e),e},_getEdgeAt:function(t){var e=this._pointerToPositionObject(t),i=this._getAllEdgesOverlappingWith(e);return i.length>0?this.edges[i[i.length-1]]:null},_addToSelection:function(t){this.selectionObj[t.id]=t},_removeFromSelection:function(t){delete this.selectionObj[t.id]},_unselectAll:function(t){void 0===t&&(t=!1);for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e].unselect();this.selectionObj={},0==t&&this._trigger("select",this.getSelection())},_unselectClusters:function(t){void 0===t&&(t=!1);for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e]instanceof Node&&this.selectionObj[e].clusterSize>1&&(this.selectionObj[e].unselect(),this._removeFromSelection(this.selectionObj[e]));0==t&&this._trigger("select",this.getSelection())},_getSelectedNodeCount:function(){var t=0;for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e]instanceof Node&&(t+=1);return t},_getSelectedEdgeCount:function(){var t=0;for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&this.selectionObj[e]instanceof Edge&&(t+=1);return t},_getSelectedObjectCount:function(){var t=0;for(var e in this.selectionObj)this.selectionObj.hasOwnProperty(e)&&(t+=1);return t},_selectionIsEmpty:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t))return!1;return!0},_clusterInSelection:function(){for(var t in this.selectionObj)if(this.selectionObj.hasOwnProperty(t)&&this.selectionObj[t]instanceof Node&&this.selectionObj[t].clusterSize>1)return!0;return!1},_selectConnectedEdges:function(t){for(var e=0;ee;e++){n=t[e];var s=this.nodes[n];if(!s)throw new RangeError('Node with id "'+n+'" not found');this._selectObject(s,!0,!0)}this.redraw()},_updateSelection:function(){for(var t in this.selectionObj)this.selectionObj.hasOwnProperty(t)&&(this.selectionObj[t]instanceof Node?this.nodes.hasOwnProperty(t)||delete this.selectionObj[t]:this.edges.hasOwnProperty(t)||delete this.selectionObj[t])}},NavigationMixin={_relocateNavigation:function(){if(void 0!==this.sectors){var t=this.navigationClientWidth-this.frame.canvas.clientWidth,e=this.navigationClientHeight-this.frame.canvas.clientHeight;this.navigationClientWidth=this.frame.canvas.clientWidth,this.navigationClientHeight=this.frame.canvas.clientHeight;var i=null;for(var n in this.sectors.navigation.nodes)this.sectors.navigation.nodes.hasOwnProperty(n)&&(i=this.sectors.navigation.nodes[n],i.horizontalAlignLeft||(i.x-=t),i.verticalAlignTop||(i.y-=e))}},_loadNavigationElements:function(){var t=this.constants.navigation.iconPath;this.navigationClientWidth=this.frame.canvas.clientWidth,this.navigationClientHeight=this.frame.canvas.clientHeight,void 0===this.navigationClientWidth&&(this.navigationClientWidth=0,this.navigationClientHeight=0);for(var e=15,i=7,n=[{id:"navigation_up",shape:"image",image:t+"/uparrow.png",triggerFunction:"_moveUp",verticalAlignTop:!1,x:45+e+i,y:this.navigationClientHeight-45-e-i},{id:"navigation_down",shape:"image",image:t+"/downarrow.png",triggerFunction:"_moveDown",verticalAlignTop:!1,x:45+e+i,y:this.navigationClientHeight-15-e},{id:"navigation_left",shape:"image",image:t+"/leftarrow.png",triggerFunction:"_moveLeft",verticalAlignTop:!1,x:15+e,y:this.navigationClientHeight-15-e},{id:"navigation_right",shape:"image",image:t+"/rightarrow.png",triggerFunction:"_moveRight",verticalAlignTop:!1,x:75+e+2*i,y:this.navigationClientHeight-15-e},{id:"navigation_plus",shape:"image",image:t+"/plus.png",triggerFunction:"_zoomIn",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-45-e-i,y:this.navigationClientHeight-15-e},{id:"navigation_min",shape:"image",image:t+"/minus.png",triggerFunction:"_zoomOut",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-15-e,y:this.navigationClientHeight-15-e},{id:"navigation_zoomExtends",shape:"image",image:t+"/zoomExtends.png",triggerFunction:"zoomToFit",verticalAlignTop:!1,horizontalAlignLeft:!1,x:this.navigationClientWidth-15-e,y:this.navigationClientHeight-45-e-i}],s=null,o=0;ot.x-t.width&&(n=t.x-t.width),st.y-t.height&&(e=t.y-t.height),i=this.constants.clustering.initialMaxNodes)var n=38.8467/(e-14.50184)+.0116;else var n=42.54117319/(e+39.31966387)+.1944405;else{var s=1.1*(Math.abs(i.minX)+Math.abs(i.maxX)),o=1.1*(Math.abs(i.minY)+Math.abs(i.maxY)),r=this.frame.canvas.clientWidth/s,a=this.frame.canvas.clientHeight/o;n=a>=r?r:a}n>1&&(n=1),this.pinch.mousewheelScale=n,this._setScale(n),this._centerGraph(i),this.start()},Graph.prototype._updateNodeIndexList=function(){this._clearNodeIndexList();for(var t in this.nodes)this.nodes.hasOwnProperty(t)&&this.nodeIndices.push(t)},Graph.prototype.setData=function(t,e){if(void 0===e&&(e=!1),t&&t.dot&&(t.nodes||t.edges))throw new SyntaxError('Data must contain either parameter "dot" or parameter pair "nodes" and "edges", but not both.');if(this.setOptions(t&&t.options),t&&t.dot){if(t&&t.dot){var i=vis.util.DOTToGraph(t.dot);return void this.setData(i)}}else this._setNodes(t&&t.nodes),this._setEdges(t&&t.edges);this._putDataInSector(),e||(this.stabilize&&this._doStabilize(),this.moving=!0,this.start())},Graph.prototype.setOptions=function(t){if(t){if(void 0!==t.width&&(this.width=t.width),void 0!==t.height&&(this.height=t.height),void 0!==t.stabilize&&(this.stabilize=t.stabilize),void 0!==t.selectable&&(this.selectable=t.selectable),t.clustering){this.constants.clustering.enabled=!0;for(var e in t.clustering)t.clustering.hasOwnProperty(e)&&(this.constants.clustering[e]=t.clustering[e])}else void 0!==t.clustering&&(this.constants.clustering.enabled=!1);if(t.navigation){this.constants.navigation.enabled=!0;for(var e in t.navigation)t.navigation.hasOwnProperty(e)&&(this.constants.navigation[e]=t.navigation[e])}else void 0!==t.navigation&&(this.constants.navigation.enabled=!1);if(t.keyboard){this.constants.keyboard.enabled=!0;for(var e in t.keyboard)t.keyboard.hasOwnProperty(e)&&(this.constants.keyboard[e]=t.keyboard[e])}else void 0!==t.keyboard&&(this.constants.keyboard.enabled=!1);if(t.dataManipulationToolbar){this.constants.dataManipulationToolbar.enabled=!0;for(var e in t.dataManipulationToolbar)t.dataManipulationToolbar.hasOwnProperty(e)&&(this.constants.dataManipulationToolbar[e]=t.dataManipulationToolbar[e])}else void 0!==t.dataManipulationToolbar&&(this.constants.dataManipulationToolbar.enabled=!1);if(t.edges){for(e in t.edges)t.edges.hasOwnProperty(e)&&(this.constants.edges[e]=t.edges[e]);void 0!==t.edges.length&&t.nodes&&void 0===t.nodes.distance&&(this.constants.edges.length=t.edges.length,this.constants.nodes.distance=1.25*t.edges.length),t.edges.fontColor||(this.constants.edges.fontColor=t.edges.color),t.edges.dash&&(void 0!==t.edges.dash.length&&(this.constants.edges.dash.length=t.edges.dash.length),void 0!==t.edges.dash.gap&&(this.constants.edges.dash.gap=t.edges.dash.gap),void 0!==t.edges.dash.altLength&&(this.constants.edges.dash.altLength=t.edges.dash.altLength))}if(t.nodes){for(e in t.nodes)t.nodes.hasOwnProperty(e)&&(this.constants.nodes[e]=t.nodes[e]);t.nodes.color&&(this.constants.nodes.color=Node.parseColor(t.nodes.color))}if(t.groups)for(var i in t.groups)if(t.groups.hasOwnProperty(i)){var n=t.groups[i];this.groups.add(i,n)}}this._loadPhysicsSystem(),this._loadNavigationControls(),this._loadManipulationSystem(),this._createKeyBinds(),this.setSize(this.width,this.height),this._setTranslation(this.frame.clientWidth/2,this.frame.clientHeight/2),this._setScale(1),this._redraw()},Graph.prototype.on=function(t,e){var i=["select"];if(-1==i.indexOf(t))throw new Error('Unknown event "'+t+'". Choose from '+i.join());events.addListener(this,t,e)},Graph.prototype.off=function(t,e){events.removeListener(this,t,e)},Graph.prototype._trigger=function(t,e){events.trigger(this,t,e)},Graph.prototype._create=function(){for(;this.containerElement.hasChildNodes();)this.containerElement.removeChild(this.containerElement.firstChild);if(this.frame=document.createElement("div"),this.frame.className="graph-frame",this.frame.style.position="relative",this.frame.style.overflow="hidden",this.frame.style.zIndex="1",this.frame.canvas=document.createElement("canvas"),this.frame.canvas.style.position="relative",this.frame.appendChild(this.frame.canvas),!this.frame.canvas.getContext){var t=document.createElement("DIV");t.style.color="red",t.style.fontWeight="bold",t.style.padding="10px",t.innerHTML="Error: your browser does not support HTML canvas",this.frame.canvas.appendChild(t)}var e=this;this.drag={},this.pinch={},this.hammer=Hammer(this.frame.canvas,{prevent_default:!0}),this.hammer.on("tap",e._onTap.bind(e)),this.hammer.on("doubletap",e._onDoubleTap.bind(e)),this.hammer.on("hold",e._onHold.bind(e)),this.hammer.on("pinch",e._onPinch.bind(e)),this.hammer.on("touch",e._onTouch.bind(e)),this.hammer.on("dragstart",e._onDragStart.bind(e)),this.hammer.on("drag",e._onDrag.bind(e)),this.hammer.on("dragend",e._onDragEnd.bind(e)),this.hammer.on("release",e._onRelease.bind(e)),this.hammer.on("mousewheel",e._onMouseWheel.bind(e)),this.hammer.on("DOMMouseScroll",e._onMouseWheel.bind(e)),this.hammer.on("mousemove",e._onMouseMoveTitle.bind(e)),this.containerElement.appendChild(this.frame)},Graph.prototype._createKeyBinds=function(){var t=this;this.mousetrap=mousetrap,this.mousetrap.reset(),1==this.constants.keyboard.enabled&&(this.mousetrap.bind("up",this._moveUp.bind(t),"keydown"),this.mousetrap.bind("up",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("down",this._moveDown.bind(t),"keydown"),this.mousetrap.bind("down",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("left",this._moveLeft.bind(t),"keydown"),this.mousetrap.bind("left",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("right",this._moveRight.bind(t),"keydown"),this.mousetrap.bind("right",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("=",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("=",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("-",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("-",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("[",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("[",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("]",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("]",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pageup",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("pageup",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pagedown",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("pagedown",this._stopZoom.bind(t),"keyup")),this.mousetrap.bind("b",this._toggleBarnesHut.bind(t)),1==this.constants.dataManipulationToolbar.enabled&&this.mousetrap.bind("escape",this._createManipulatorBar.bind(t))},Graph.prototype._getPointer=function(t){return{x:t.pageX-vis.util.getAbsoluteLeft(this.frame.canvas),y:t.pageY-vis.util.getAbsoluteTop(this.frame.canvas)}},Graph.prototype._onTouch=function(t){this.drag.pointer=this._getPointer(t.gesture.touches[0]),this.drag.pinched=!1,this.pinch.scale=this._getScale(),this._handleTouch(this.drag.pointer)},Graph.prototype._onDragStart=function(){var t=this.drag,e=this._getNodeAt(t.pointer);if(t.dragging=!0,t.selection=[],t.translation=this._getTranslation(),t.nodeId=null,null!=e){t.nodeId=e.id,e.isSelected()||this._selectObject(e,!1);for(var i in this.selectionObj)if(this.selectionObj.hasOwnProperty(i)){var n=this.selectionObj[i];if(n instanceof Node){var s={id:n.id,node:n,x:n.x,y:n.y,xFixed:n.xFixed,yFixed:n.yFixed};n.xFixed=!0,n.yFixed=!0,t.selection.push(s)}}}},Graph.prototype._onDrag=function(t){if(!this.drag.pinched){var e=this._getPointer(t.gesture.touches[0]),i=this,n=this.drag,s=n.selection;if(s&&s.length){var o=e.x-n.pointer.x,r=e.y-n.pointer.y;s.forEach(function(t){var e=t.node;t.xFixed||(e.x=i._canvasToX(i._xToCanvas(t.x)+o)),t.yFixed||(e.y=i._canvasToY(i._yToCanvas(t.y)+r))}),this.moving||(this.moving=!0,this.start())}else{var a=e.x-this.drag.pointer.x,h=e.y-this.drag.pointer.y;this._setTranslation(this.drag.translation.x+a,this.drag.translation.y+h),this._redraw(),this.moved=!0}}},Graph.prototype._onDragEnd=function(){this.drag.dragging=!1;var t=this.drag.selection;t&&t.forEach(function(t){t.node.xFixed=t.xFixed,t.node.yFixed=t.yFixed})},Graph.prototype._onTap=function(t){var e=this._getPointer(t.gesture.touches[0]);this.pointerPosition=e,this._handleTap(e)},Graph.prototype._onDoubleTap=function(t){var e=this._getPointer(t.gesture.touches[0]);this._handleDoubleTap(e)},Graph.prototype._onHold=function(t){var e=this._getPointer(t.gesture.touches[0]);this.pointerPosition=e,this._handleOnHold(e)},Graph.prototype._onRelease=function(){this._handleOnRelease()},Graph.prototype._onPinch=function(t){var e=this._getPointer(t.gesture.center);this.drag.pinched=!0,"scale"in this.pinch||(this.pinch.scale=1);var i=this.pinch.scale*t.gesture.scale;this._zoom(i,e)},Graph.prototype._zoom=function(t,e){var i=this._getScale();1e-5>t&&(t=1e-5),t>10&&(t=10);var n=this._getTranslation(),s=t/i,o=(1-s)*e.x+n.x*s,r=(1-s)*e.y+n.y*s;return this.areaCenter={x:this._canvasToX(e.x),y:this._canvasToY(e.y)},this.pinch.mousewheelScale=t,this._setScale(t),this._setTranslation(o,r),this.updateClustersDefault(),this._redraw(),t},Graph.prototype._onMouseWheel=function(t){var e=0;if(t.wheelDelta?e=t.wheelDelta/120:t.detail&&(e=-t.detail/3),e){"mousewheelScale"in this.pinch||(this.pinch.mousewheelScale=1);var i=this.pinch.mousewheelScale,n=e/10;0>e&&(n/=1-n),i*=1+n;var s=util.fakeGesture(this,t),o=this._getPointer(s.center);i=this._zoom(i,o)}t.preventDefault()},Graph.prototype._onMouseMoveTitle=function(t){var e=util.fakeGesture(this,t),i=this._getPointer(e.center);this.popupNode&&this._checkHidePopup(i);var n=this,s=function(){n._checkShowPopup(i)};this.popupTimer&&clearInterval(this.popupTimer),this.drag.dragging||(this.popupTimer=setTimeout(s,300))},Graph.prototype._checkShowPopup=function(t){var e,i={left:this._canvasToX(t.x),top:this._canvasToY(t.y),right:this._canvasToX(t.x),bottom:this._canvasToY(t.y)},n=this.popupNode;if(void 0==this.popupNode){var s=this.nodes;for(e in s)if(s.hasOwnProperty(e)){var o=s[e];if(void 0!==o.getTitle()&&o.isOverlappingWith(i)){this.popupNode=o;break}}}if(void 0===this.popupNode){var r=this.edges;for(e in r)if(r.hasOwnProperty(e)){var a=r[e];if(a.connected&&void 0!==a.getTitle()&&a.isOverlappingWith(i)){this.popupNode=a;break}}}if(this.popupNode){if(this.popupNode!=n){var h=this;h.popup||(h.popup=new Popup(h.frame)),h.popup.setPosition(t.x-3,t.y-3),h.popup.setText(h.popupNode.getTitle()),h.popup.show()}}else this.popup&&this.popup.hide()},Graph.prototype._checkHidePopup=function(t){this.popupNode&&this._getNodeAt(t)||(this.popupNode=void 0,this.popup&&this.popup.hide())},Graph.prototype._getConnectionCount=function(t){function e(t){for(var e=[],i=0,n=t.length;n>i;i++)for(var s=t[i],o=s.edges,r=0,a=o.length;a>r;r++){var h=o[r],l=null;h.from==s?l=h.to:h.to==s&&(l=h.from);var c,d;if(l)for(c=0,d=t.length;d>c;c++)if(t[c]==l){l=null;break}if(l)for(c=0,d=e.length;d>c;c++)if(e[c]==l){l=null;break}l&&e.push(l)}return e}void 0==t&&(t=1);var i=[],n=this.nodes;for(var s in n)if(n.hasOwnProperty(s)){for(var o=[n[s]],r=0;t>r;r++)o=o.concat(e(o));i.push(o)}for(var a=[],h=0,l=i.length;l>h;h++)a.push(i[h].length);return a},Graph.prototype.setSize=function(t,e){this.frame.style.width=t,this.frame.style.height=e,this.frame.canvas.style.width="100%",this.frame.canvas.style.height="100%",this.frame.canvas.width=this.frame.canvas.clientWidth,this.frame.canvas.height=this.frame.canvas.clientHeight,void 0!==this.manipulationDiv&&(this.manipulationDiv.style.width=this.frame.canvas.clientWidth),1==this.constants.navigation.enabled&&this._relocateNavigation()},Graph.prototype._setNodes=function(t){var e=this.nodesData;if(t instanceof DataSet||t instanceof DataView)this.nodesData=t;else if(t instanceof Array)this.nodesData=new DataSet,this.nodesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.nodesData=new DataSet}if(e&&util.forEach(this.nodesListeners,function(t,i){e.unsubscribe(i,t)}),this.nodes={},this.nodesData){var i=this;util.forEach(this.nodesListeners,function(t,e){i.nodesData.subscribe(e,t)});var n=this.nodesData.getIds();this._addNodes(n)}this._updateSelection()},Graph.prototype._addNodes=function(t){for(var e,i=0,n=t.length;n>i;i++){e=t[i];var s=this.nodesData.get(e),o=new Node(s,this.images,this.groups,this.constants);if(this.nodes[e]=o,!o.isFixed()&&1!=this.createNodeOnClick){var r=this.constants.edges.length,a=t.length,h=2*Math.PI*(i/a);o.x=r*Math.cos(h),o.y=r*Math.sin(h),this.moving=!0}}this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(this.nodes),this.updateLabels()},Graph.prototype._updateNodes=function(t){for(var e=this.nodes,i=this.nodesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o],a=i.get(o);r?r.setProperties(a,this.constants):(r=new Node(properties,this.images,this.groups,this.constants),e[o]=r,r.isFixed()||(this.moving=!0))}this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(e)},Graph.prototype._removeNodes=function(t){for(var e=this.nodes,i=0,n=t.length;n>i;i++){var s=t[i];delete e[s]}this._updateNodeIndexList(),this._reconnectEdges(),this._updateSelection(),this._updateValueRange(e)},Graph.prototype._setEdges=function(t){var e=this.edgesData;if(t instanceof DataSet||t instanceof DataView)this.edgesData=t;else if(t instanceof Array)this.edgesData=new DataSet,this.edgesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.edgesData=new DataSet}if(e&&util.forEach(this.edgesListeners,function(t,i){e.unsubscribe(i,t)}),this.edges={},this.edgesData){var i=this;util.forEach(this.edgesListeners,function(t,e){i.edgesData.subscribe(e,t)});var n=this.edgesData.getIds();this._addEdges(n)}this._reconnectEdges()},Graph.prototype._addEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o];r&&r.disconnect();var a=i.get(o,{showInternalIds:!0});e[o]=new Edge(a,this,this.constants)}this.moving=!0,this._updateValueRange(e)},Graph.prototype._updateEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=i.get(o),a=e[o];a?(a.disconnect(),a.setProperties(r,this.constants),a.connect()):(a=new Edge(r,this,this.constants),this.edges[o]=a)}this.moving=!0,this._updateValueRange(e)},Graph.prototype._removeEdges=function(t){for(var e=this.edges,i=0,n=t.length;n>i;i++){var s=t[i],o=e[s];o&&(o.disconnect(),delete e[s])}this.moving=!0,this._updateValueRange(e)},Graph.prototype._reconnectEdges=function(){var t,e=this.nodes,i=this.edges;for(t in e)e.hasOwnProperty(t)&&(e[t].edges=[]);for(t in i)if(i.hasOwnProperty(t)){var n=i[t];n.from=null,n.to=null,n.connect()}},Graph.prototype._updateValueRange=function(t){var e,i=void 0,n=void 0;for(e in t)if(t.hasOwnProperty(e)){var s=t[e].getValue();void 0!==s&&(i=void 0===i?s:Math.min(s,i),n=void 0===n?s:Math.max(s,n))}if(void 0!==i&&void 0!==n)for(e in t)t.hasOwnProperty(e)&&t[e].setValueRange(i,n)},Graph.prototype.redraw=function(){this.setSize(this.width,this.height),this._redraw()},Graph.prototype._redraw=function(){var t=this.frame.canvas.getContext("2d"),e=this.frame.canvas.width,i=this.frame.canvas.height;t.clearRect(0,0,e,i),t.save(),t.translate(this.translation.x,this.translation.y),t.scale(this.scale,this.scale),this.canvasTopLeft={x:this._canvasToX(0),y:this._canvasToY(0)},this.canvasBottomRight={x:this._canvasToX(this.frame.canvas.clientWidth),y:this._canvasToY(this.frame.canvas.clientHeight)},this._doInAllSectors("_drawAllSectorNodes",t),this._doInAllSectors("_drawEdges",t),this._doInAllSectors("_drawNodes",t,!0),t.restore(),1==this.constants.navigation.enabled&&this._doInNavigationSector("_drawNodes",t,!0)},Graph.prototype._setTranslation=function(t,e){void 0===this.translation&&(this.translation={x:0,y:0}),void 0!==t&&(this.translation.x=t),void 0!==e&&(this.translation.y=e)},Graph.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},Graph.prototype._setScale=function(t){this.scale=t},Graph.prototype._getScale=function(){return this.scale},Graph.prototype._canvasToX=function(t){return(t-this.translation.x)/this.scale},Graph.prototype._xToCanvas=function(t){return t*this.scale+this.translation.x},Graph.prototype._canvasToY=function(t){return(t-this.translation.y)/this.scale},Graph.prototype._yToCanvas=function(t){return t*this.scale+this.translation.y},Graph.prototype._drawNodes=function(t,e){void 0===e&&(e=!1);var i=this.nodes,n=[];for(var s in i)i.hasOwnProperty(s)&&(i[s].setScaleAndPos(this.scale,this.canvasTopLeft,this.canvasBottomRight),i[s].isSelected()?n.push(s):(i[s].inArea()||e)&&i[s].draw(t));for(var o=0,r=n.length;r>o;o++)(i[n[o]].inArea()||e)&&i[n[o]].draw(t)},Graph.prototype._drawEdges=function(t){var e=this.edges;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];n.setScale(this.scale),n.connected&&e[i].draw(t)}},Graph.prototype._doStabilize=function(){for(var t=0,e=this.constants.minVelocity,i=!1;!i&&t0)for(var i in e)e.hasOwnProperty(i)&&e[i].discreteStepLimited(t,this.constants.maxVelocity);else for(var i in e)e.hasOwnProperty(i)&&e[i].discreteStep(t);var n=this.constants.minVelocity;this.moving=this._isMoving(n)},Graph.prototype.start=function(){if(!this.freezeSimulation)if(this.moving&&(this._doInAllActiveSectors("_initializeForceCalculation"),this._doInAllActiveSectors("_discreteStepNodes"),this._findCenter(this._getRange())),this.moving||0!=this.xIncrement||0!=this.yIncrement||0!=this.zoomIncrement){if(!this.timer){var t=this;this.timer=window.setTimeout(function(){if(t.timer=void 0,0!=t.xIncrement||0!=t.yIncrement){var e=t._getTranslation();t._setTranslation(e.x+t.xIncrement,e.y+t.yIncrement)}if(0!=t.zoomIncrement){var i={x:t.frame.canvas.clientWidth/2,y:t.frame.canvas.clientHeight/2};t._zoom(t.scale*(1+t.zoomIncrement),i)}var n=Date.now();t.start(),t.start();var s=(Date.now()-n,Date.now());t._redraw();Date.now()-s},this.renderTimestep)}}else this._redraw()},Graph.prototype.singleStep=function(){if(this.moving){this._initializeForceCalculation(),this._discreteStepNodes();var t=this.constants.minVelocity;this.moving=this._isMoving(t),this._redraw()}},Graph.prototype.toggleFreeze=function(){0==this.freezeSimulation?this.freezeSimulation=!0:(this.freezeSimulation=!1,this.start())},Graph.prototype._initializeMixinLoaders=function(){for(var t in graphMixinLoaders)graphMixinLoaders.hasOwnProperty(t)&&(Graph.prototype[t]=graphMixinLoaders[t])};var vis={util:util,events:events,Controller:Controller,DataSet:DataSet,DataView:DataView,Range:Range,Stack:Stack,TimeStep:TimeStep,EventBus:EventBus,components:{items:{Item:Item,ItemBox:ItemBox,ItemPoint:ItemPoint,ItemRange:ItemRange},Component:Component,Panel:Panel,RootPanel:RootPanel,ItemSet:ItemSet,TimeAxis:TimeAxis},graph:{Node:Node,Edge:Edge,Popup:Popup,Groups:Groups,Images:Images},Timeline:Timeline,Graph:Graph};"undefined"!=typeof exports&&(exports=vis),"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=vis),"function"==typeof define&&define(function(){return vis}),"undefined"!=typeof window&&(window.vis=vis)},{hammerjs:2,moment:3,mousetrap:4}],2:[function(t,e){!function(t,i){"use strict";function n(){if(!s.READY){s.event.determineEventTypes();for(var t in s.gestures)s.gestures.hasOwnProperty(t)&&s.detection.register(s.gestures[t]);s.event.onTouch(s.DOCUMENT,s.EVENT_MOVE,s.detection.detect),s.event.onTouch(s.DOCUMENT,s.EVENT_END,s.detection.detect),s.READY=!0}}var s=function(t,e){return new s.Instance(t,e||{})};s.defaults={stop_browser_behavior:{userSelect:"none",touchAction:"none",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}},s.HAS_POINTEREVENTS=navigator.pointerEnabled||navigator.msPointerEnabled,s.HAS_TOUCHEVENTS="ontouchstart"in t,s.MOBILE_REGEX=/mobile|tablet|ip(ad|hone|od)|android/i,s.NO_MOUSEEVENTS=s.HAS_TOUCHEVENTS&&navigator.userAgent.match(s.MOBILE_REGEX),s.EVENT_TYPES={},s.DIRECTION_DOWN="down",s.DIRECTION_LEFT="left",s.DIRECTION_UP="up",s.DIRECTION_RIGHT="right",s.POINTER_MOUSE="mouse",s.POINTER_TOUCH="touch",s.POINTER_PEN="pen",s.EVENT_START="start",s.EVENT_MOVE="move",s.EVENT_END="end",s.DOCUMENT=document,s.plugins={},s.READY=!1,s.Instance=function(t,e){var i=this;return n(),this.element=t,this.enabled=!0,this.options=s.utils.extend(s.utils.extend({},s.defaults),e||{}),this.options.stop_browser_behavior&&s.utils.stopDefaultBrowserBehavior(this.element,this.options.stop_browser_behavior),s.event.onTouch(t,s.EVENT_START,function(t){i.enabled&&s.detection.startDetect(i,t)}),this},s.Instance.prototype={on:function(t,e){for(var i=t.split(" "),n=0;n0&&e==s.EVENT_END?e=s.EVENT_MOVE:c||(e=s.EVENT_END),c||null===o?o=h:h=o,i.call(s.detection,n.collectEventData(t,e,h)),s.HAS_POINTEREVENTS&&e==s.EVENT_END&&(c=s.PointerEvent.updatePointer(e,h))),c||(o=null,r=!1,a=!1,s.PointerEvent.reset())}})},determineEventTypes:function(){var t;t=s.HAS_POINTEREVENTS?s.PointerEvent.getEvents():s.NO_MOUSEEVENTS?["touchstart","touchmove","touchend touchcancel"]:["touchstart mousedown","touchmove mousemove","touchend touchcancel mouseup"],s.EVENT_TYPES[s.EVENT_START]=t[0],s.EVENT_TYPES[s.EVENT_MOVE]=t[1],s.EVENT_TYPES[s.EVENT_END]=t[2]},getTouchList:function(t){return s.HAS_POINTEREVENTS?s.PointerEvent.getTouchList():t.touches?t.touches:[{identifier:1,pageX:t.pageX,pageY:t.pageY,target:t.target}]},collectEventData:function(t,e,i){var n=this.getTouchList(i,e),o=s.POINTER_TOUCH;return(i.type.match(/mouse/)||s.PointerEvent.matchType(s.POINTER_MOUSE,i))&&(o=s.POINTER_MOUSE),{center:s.utils.getCenter(n),timeStamp:(new Date).getTime(),target:i.target,touches:n,eventType:e,pointerType:o,srcEvent:i,preventDefault:function(){this.srcEvent.preventManipulation&&this.srcEvent.preventManipulation(),this.srcEvent.preventDefault&&this.srcEvent.preventDefault()},stopPropagation:function(){this.srcEvent.stopPropagation()},stopDetect:function(){return s.detection.stopDetect()}}}},s.PointerEvent={pointers:{},getTouchList:function(){var t=this,e=[];return Object.keys(t.pointers).sort().forEach(function(i){e.push(t.pointers[i])}),e},updatePointer:function(t,e){return t==s.EVENT_END?this.pointers={}:(e.identifier=e.pointerId,this.pointers[e.pointerId]=e),Object.keys(this.pointers).length},matchType:function(t,e){if(!e.pointerType)return!1;var i={};return i[s.POINTER_MOUSE]=e.pointerType==e.MSPOINTER_TYPE_MOUSE||e.pointerType==s.POINTER_MOUSE,i[s.POINTER_TOUCH]=e.pointerType==e.MSPOINTER_TYPE_TOUCH||e.pointerType==s.POINTER_TOUCH,i[s.POINTER_PEN]=e.pointerType==e.MSPOINTER_TYPE_PEN||e.pointerType==s.POINTER_PEN,i[t]},getEvents:function(){return["pointerdown MSPointerDown","pointermove MSPointerMove","pointerup pointercancel MSPointerUp MSPointerCancel"]},reset:function(){this.pointers={}}},s.utils={extend:function(t,e,n){for(var s in e)t[s]!==i&&n||(t[s]=e[s]);return t},hasParent:function(t,e){for(;t;){if(t==e)return!0;t=t.parentNode}return!1},getCenter:function(t){for(var e=[],i=[],n=0,s=t.length;s>n;n++)e.push(t[n].pageX),i.push(t[n].pageY);return{pageX:(Math.min.apply(Math,e)+Math.max.apply(Math,e))/2,pageY:(Math.min.apply(Math,i)+Math.max.apply(Math,i))/2}},getVelocity:function(t,e,i){return{x:Math.abs(e/t)||0,y:Math.abs(i/t)||0}},getAngle:function(t,e){var i=e.pageY-t.pageY,n=e.pageX-t.pageX;return 180*Math.atan2(i,n)/Math.PI},getDirection:function(t,e){var i=Math.abs(t.pageX-e.pageX),n=Math.abs(t.pageY-e.pageY);return i>=n?t.pageX-e.pageX>0?s.DIRECTION_LEFT:s.DIRECTION_RIGHT:t.pageY-e.pageY>0?s.DIRECTION_UP:s.DIRECTION_DOWN},getDistance:function(t,e){var i=e.pageX-t.pageX,n=e.pageY-t.pageY;return Math.sqrt(i*i+n*n)},getScale:function(t,e){return t.length>=2&&e.length>=2?this.getDistance(e[0],e[1])/this.getDistance(t[0],t[1]):1},getRotation:function(t,e){return t.length>=2&&e.length>=2?this.getAngle(e[1],e[0])-this.getAngle(t[1],t[0]):0},isVertical:function(t){return t==s.DIRECTION_UP||t==s.DIRECTION_DOWN},stopDefaultBrowserBehavior:function(t,e){var i,n=["webkit","khtml","moz","ms","o",""];if(e&&t.style){for(var s=0;si;i++){var o=this.gestures[i];if(!this.stopped&&e[o.name]!==!1&&o.handler.call(o,t,this.current.inst)===!1){this.stopDetect();break}}return this.current&&(this.current.lastEvent=t),t.eventType==s.EVENT_END&&!t.touches.length-1&&this.stopDetect(),t}},stopDetect:function(){this.previous=s.utils.extend({},this.current),this.current=null,this.stopped=!0},extendEventData:function(t){var e=this.current.startEvent;if(e&&(t.touches.length!=e.touches.length||t.touches===e.touches)){e.touches=[];for(var i=0,n=t.touches.length;n>i;i++)e.touches.push(s.utils.extend({},t.touches[i]))}var o=t.timeStamp-e.timeStamp,r=t.center.pageX-e.center.pageX,a=t.center.pageY-e.center.pageY,h=s.utils.getVelocity(o,r,a);return s.utils.extend(t,{deltaTime:o,deltaX:r,deltaY:a,velocityX:h.x,velocityY:h.y,distance:s.utils.getDistance(e.center,t.center),angle:s.utils.getAngle(e.center,t.center),direction:s.utils.getDirection(e.center,t.center),scale:s.utils.getScale(e.touches,t.touches),rotation:s.utils.getRotation(e.touches,t.touches),startEvent:e}),t},register:function(t){var e=t.defaults||{};return e[t.name]===i&&(e[t.name]=!0),s.utils.extend(s.defaults,e,!0),t.index=t.index||1e3,this.gestures.push(t),this.gestures.sort(function(t,e){return t.indexe.index?1:0}),this.gestures}},s.gestures=s.gestures||{},s.gestures.Hold={name:"hold",index:10,defaults:{hold_timeout:500,hold_threshold:1},timer:null,handler:function(t,e){switch(t.eventType){case s.EVENT_START:clearTimeout(this.timer),s.detection.current.name=this.name,this.timer=setTimeout(function(){"hold"==s.detection.current.name&&e.trigger("hold",t)},e.options.hold_timeout);break;case s.EVENT_MOVE:t.distance>e.options.hold_threshold&&clearTimeout(this.timer); -break;case s.EVENT_END:clearTimeout(this.timer)}}},s.gestures.Tap={name:"tap",index:100,defaults:{tap_max_touchtime:250,tap_max_distance:10,tap_always:!0,doubletap_distance:20,doubletap_interval:300},handler:function(t,e){if(t.eventType==s.EVENT_END){var i=s.detection.previous,n=!1;if(t.deltaTime>e.options.tap_max_touchtime||t.distance>e.options.tap_max_distance)return;i&&"tap"==i.name&&t.timeStamp-i.lastEvent.timeStamp0&&t.touches.length>e.options.swipe_max_touches)return;(t.velocityX>e.options.swipe_velocity||t.velocityY>e.options.swipe_velocity)&&(e.trigger(this.name,t),e.trigger(this.name+t.direction,t))}}},s.gestures.Drag={name:"drag",index:50,defaults:{drag_min_distance:10,drag_max_touches:1,drag_block_horizontal:!1,drag_block_vertical:!1,drag_lock_to_axis:!1,drag_lock_min_distance:25},triggered:!1,handler:function(t,e){if(s.detection.current.name!=this.name&&this.triggered)return e.trigger(this.name+"end",t),void(this.triggered=!1);if(!(e.options.drag_max_touches>0&&t.touches.length>e.options.drag_max_touches))switch(t.eventType){case s.EVENT_START:this.triggered=!1;break;case s.EVENT_MOVE:if(t.distancee.options.transform_min_rotation&&e.trigger("rotate",t),i>e.options.transform_min_scale&&(e.trigger("pinch",t),e.trigger("pinch"+(t.scale<1?"in":"out"),t));break;case s.EVENT_END:this.triggered&&e.trigger(this.name+"end",t),this.triggered=!1}}},s.gestures.Touch={name:"touch",index:-1/0,defaults:{prevent_default:!1,prevent_mouseevents:!1},handler:function(t,e){return e.options.prevent_mouseevents&&t.pointerType==s.POINTER_MOUSE?void t.stopDetect():(e.options.prevent_default&&t.preventDefault(),void(t.eventType==s.EVENT_START&&e.trigger(this.name,t)))}},s.gestures.Release={name:"release",index:1/0,handler:function(t,e){t.eventType==s.EVENT_END&&e.trigger(this.name,t)}},"object"==typeof e&&"object"==typeof e.exports?e.exports=s:(t.Hammer=s,"function"==typeof t.define&&t.define.amd&&t.define("hammer",[],function(){return s}))}(this)},{}],3:[function(t,e){(function(i){function n(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function s(t,e){return function(i){return u(t.call(this,i),e)}}function o(t,e){return function(i){return this.lang().ordinal(t.call(this,i),e)}}function r(){}function a(t){E(t),l(this,t)}function h(t){var e=y(t),i=e.year||0,n=e.month||0,s=e.week||0,o=e.day||0,r=e.hour||0,a=e.minute||0,h=e.second||0,l=e.millisecond||0;this._milliseconds=+l+1e3*h+6e4*a+36e5*r,this._days=+o+7*s,this._months=+n+12*i,this._data={},this._bubble()}function l(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return e.hasOwnProperty("toString")&&(t.toString=e.toString),e.hasOwnProperty("valueOf")&&(t.valueOf=e.valueOf),t}function c(t){var e,i={};for(e in t)t.hasOwnProperty(e)&&ye.hasOwnProperty(e)&&(i[e]=t[e]);return i}function d(t){return 0>t?Math.ceil(t):Math.floor(t)}function u(t,e,i){for(var n=""+Math.abs(t),s=t>=0;n.lengthn;n++)(i&&t[n]!==e[n]||!i&&b(t[n])!==b(e[n]))&&r++;return r+o}function v(t){if(t){var e=t.toLowerCase().replace(/(.)s$/,"$1");t=Xe[t]||qe[e]||e}return t}function y(t){var e,i,n={};for(i in t)t.hasOwnProperty(i)&&(e=v(i),e&&(n[e]=t[i]));return n}function _(t){var e,n;if(0===t.indexOf("week"))e=7,n="day";else{if(0!==t.indexOf("month"))return;e=12,n="month"}oe[t]=function(s,o){var r,a,h=oe.fn._lang[t],l=[];if("number"==typeof s&&(o=s,s=i),a=function(t){var e=oe().utc().set(n,t);return h.call(oe.fn._lang,e,s||"")},null!=o)return a(o);for(r=0;e>r;r++)l.push(a(r));return l}}function b(t){var e=+t,i=0;return 0!==e&&isFinite(e)&&(i=e>=0?Math.floor(e):Math.ceil(e)),i}function w(t,e){return new Date(Date.UTC(t,e+1,0)).getUTCDate()}function S(t){return T(t)?366:365}function T(t){return t%4===0&&t%100!==0||t%400===0}function E(t){var e;t._a&&-2===t._pf.overflow&&(e=t._a[de]<0||t._a[de]>11?de:t._a[ue]<1||t._a[ue]>w(t._a[ce],t._a[de])?ue:t._a[pe]<0||t._a[pe]>23?pe:t._a[fe]<0||t._a[fe]>59?fe:t._a[ge]<0||t._a[ge]>59?ge:t._a[me]<0||t._a[me]>999?me:-1,t._pf._overflowDayOfYear&&(ce>e||e>ue)&&(e=ue),t._pf.overflow=e)}function x(t){return null==t._isValid&&(t._isValid=!isNaN(t._d.getTime())&&t._pf.overflow<0&&!t._pf.empty&&!t._pf.invalidMonth&&!t._pf.nullInput&&!t._pf.invalidFormat&&!t._pf.userInvalidated,t._strict&&(t._isValid=t._isValid&&0===t._pf.charsLeftOver&&0===t._pf.unusedTokens.length)),t._isValid}function C(t){return t?t.toLowerCase().replace("_","-"):t}function M(t,e){return e._isUTC?oe(t).zone(e._offset||0):oe(t).local()}function D(t,e){return e.abbr=t,ve[t]||(ve[t]=new r),ve[t].set(e),ve[t]}function I(t){delete ve[t]}function N(e){var i,n,s,o,r=0,a=function(e){if(!ve[e]&&_e)try{t("./lang/"+e)}catch(i){}return ve[e]};if(!e)return oe.fn._lang;if(!f(e)){if(n=a(e))return n;e=[e]}for(;r0;){if(n=a(o.slice(0,i).join("-")))return n;if(s&&s.length>=i&&m(o,s,!0)>=i-1)break;i--}r++}return oe.fn._lang}function O(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function L(t){var e,i,n=t.match(Te);for(e=0,i=n.length;i>e;e++)n[e]=Qe[n[e]]?Qe[n[e]]:O(n[e]);return function(s){var o="";for(e=0;i>e;e++)o+=n[e]instanceof Function?n[e].call(s,t):n[e];return o}}function k(t,e){return t.isValid()?(e=A(e,t.lang()),Ze[e]||(Ze[e]=L(e)),Ze[e](t)):t.lang().invalidDate()}function A(t,e){function i(t){return e.longDateFormat(t)||t}var n=5;for(Ee.lastIndex=0;n>=0&&Ee.test(t);)t=t.replace(Ee,i),Ee.lastIndex=0,n-=1;return t}function P(t,e){var i,n=e._strict;switch(t){case"DDDD":return ze;case"YYYY":case"GGGG":case"gggg":return n?Fe:Me;case"Y":case"G":case"g":return Ye;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return n?Re:De;case"S":if(n)return Ae;case"SS":if(n)return Pe;case"SSS":if(n)return ze;case"DDD":return Ce;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Ne;case"a":case"A":return N(e._l)._meridiemParse;case"X":return ke;case"Z":case"ZZ":return Oe;case"T":return Le;case"SSSS":return Ie;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return n?Pe:xe;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return xe;default:return i=new RegExp(j(G(t.replace("\\","")),"i"))}}function z(t){t=t||"";var e=t.match(Oe)||[],i=e[e.length-1]||[],n=(i+"").match(Ue)||["-",0,0],s=+(60*n[1])+b(n[2]);return"+"===n[0]?-s:s}function F(t,e,i){var n,s=i._a;switch(t){case"M":case"MM":null!=e&&(s[de]=b(e)-1);break;case"MMM":case"MMMM":n=N(i._l).monthsParse(e),null!=n?s[de]=n:i._pf.invalidMonth=e;break;case"D":case"DD":null!=e&&(s[ue]=b(e));break;case"DDD":case"DDDD":null!=e&&(i._dayOfYear=b(e));break;case"YY":s[ce]=b(e)+(b(e)>68?1900:2e3);break;case"YYYY":case"YYYYY":case"YYYYYY":s[ce]=b(e);break;case"a":case"A":i._isPm=N(i._l).isPM(e);break;case"H":case"HH":case"h":case"hh":s[pe]=b(e);break;case"m":case"mm":s[fe]=b(e);break;case"s":case"ss":s[ge]=b(e);break;case"S":case"SS":case"SSS":case"SSSS":s[me]=b(1e3*("0."+e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,i._tzm=z(e);break;case"w":case"ww":case"W":case"WW":case"d":case"dd":case"ddd":case"dddd":case"e":case"E":t=t.substr(0,1);case"gg":case"gggg":case"GG":case"GGGG":case"GGGGG":t=t.substr(0,2),e&&(i._w=i._w||{},i._w[t]=e)}}function R(t){var e,i,n,s,o,r,a,h,l,c,d=[];if(!t._d){for(n=H(t),t._w&&null==t._a[ue]&&null==t._a[de]&&(o=function(e){var i=parseInt(e,10);return e?e.length<3?i>68?1900+i:2e3+i:i:null==t._a[ce]?oe().weekYear():t._a[ce]},r=t._w,null!=r.GG||null!=r.W||null!=r.E?a=J(o(r.GG),r.W||1,r.E,4,1):(h=N(t._l),l=null!=r.d?Z(r.d,h):null!=r.e?parseInt(r.e,10)+h._week.dow:0,c=parseInt(r.w,10)||1,null!=r.d&&lS(s)&&(t._pf._overflowDayOfYear=!0),i=q(s,0,t._dayOfYear),t._a[de]=i.getUTCMonth(),t._a[ue]=i.getUTCDate()),e=0;3>e&&null==t._a[e];++e)t._a[e]=d[e]=n[e];for(;7>e;e++)t._a[e]=d[e]=null==t._a[e]?2===e?1:0:t._a[e];d[pe]+=b((t._tzm||0)/60),d[fe]+=b((t._tzm||0)%60),t._d=(t._useUTC?q:X).apply(null,d)}}function Y(t){var e;t._d||(e=y(t._i),t._a=[e.year,e.month,e.day,e.hour,e.minute,e.second,e.millisecond],R(t))}function H(t){var e=new Date;return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function W(t){t._a=[],t._pf.empty=!0;var e,i,n,s,o,r=N(t._l),a=""+t._i,h=a.length,l=0;for(n=A(t._f,r).match(Te)||[],e=0;e0&&t._pf.unusedInput.push(o),a=a.slice(a.indexOf(i)+i.length),l+=i.length),Qe[s]?(i?t._pf.empty=!1:t._pf.unusedTokens.push(s),F(s,i,t)):t._strict&&!i&&t._pf.unusedTokens.push(s);t._pf.charsLeftOver=h-l,a.length>0&&t._pf.unusedInput.push(a),t._isPm&&t._a[pe]<12&&(t._a[pe]+=12),t._isPm===!1&&12===t._a[pe]&&(t._a[pe]=0),R(t),E(t)}function G(t){return t.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,i,n,s){return e||i||n||s})}function j(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function U(t){var e,i,s,o,r;if(0===t._f.length)return t._pf.invalidFormat=!0,void(t._d=new Date(0/0));for(o=0;or)&&(s=r,i=e));l(t,i||e)}function B(t){var e,i,n=t._i,s=He.exec(n);if(s){for(t._pf.iso=!0,e=0,i=Ge.length;i>e;e++)if(Ge[e][1].exec(n)){t._f=Ge[e][0]+(s[6]||" ");break}for(e=0,i=je.length;i>e;e++)if(je[e][1].exec(n)){t._f+=je[e][0];break}n.match(Oe)&&(t._f+="Z"),W(t)}else t._d=new Date(n)}function V(t){var e=t._i,n=be.exec(e);e===i?t._d=new Date:n?t._d=new Date(+n[1]):"string"==typeof e?B(t):f(e)?(t._a=e.slice(0),R(t)):g(e)?t._d=new Date(+e):"object"==typeof e?Y(t):t._d=new Date(e)}function X(t,e,i,n,s,o,r){var a=new Date(t,e,i,n,s,o,r);return 1970>t&&a.setFullYear(t),a}function q(t){var e=new Date(Date.UTC.apply(null,arguments));return 1970>t&&e.setUTCFullYear(t),e}function Z(t,e){if("string"==typeof t)if(isNaN(t)){if(t=e.weekdaysParse(t),"number"!=typeof t)return null}else t=parseInt(t,10);return t}function K(t,e,i,n,s){return s.relativeTime(e||1,!!i,t,n)}function $(t,e,i){var n=le(Math.abs(t)/1e3),s=le(n/60),o=le(s/60),r=le(o/24),a=le(r/365),h=45>n&&["s",n]||1===s&&["m"]||45>s&&["mm",s]||1===o&&["h"]||22>o&&["hh",o]||1===r&&["d"]||25>=r&&["dd",r]||45>=r&&["M"]||345>r&&["MM",le(r/30)]||1===a&&["y"]||["yy",a];return h[2]=e,h[3]=t>0,h[4]=i,K.apply({},h)}function Q(t,e,i){var n,s=i-e,o=i-t.day();return o>s&&(o-=7),s-7>o&&(o+=7),n=oe(t).add("d",o),{week:Math.ceil(n.dayOfYear()/7),year:n.year()}}function J(t,e,i,n,s){var o,r,a=q(t,0,1).getUTCDay();return i=null!=i?i:s,o=s-a+(a>n?7:0)-(s>a?7:0),r=7*(e-1)+(i-s)+o+1,{year:r>0?t:t-1,dayOfYear:r>0?r:S(t-1)+r}}function te(t){var e=t._i,i=t._f;return null===e?oe.invalid({nullInput:!0}):("string"==typeof e&&(t._i=e=N().preparse(e)),oe.isMoment(e)?(t=c(e),t._d=new Date(+e._d)):i?f(i)?U(t):W(t):V(t),new a(t))}function ee(t,e){oe.fn[t]=oe.fn[t+"s"]=function(t){var i=this._isUTC?"UTC":"";return null!=t?(this._d["set"+i+e](t),oe.updateOffset(this),this):this._d["get"+i+e]()}}function ie(t){oe.duration.fn[t]=function(){return this._data[t]}}function ne(t,e){oe.duration.fn["as"+t]=function(){return+this/e}}function se(t){var e=!1,i=oe;"undefined"==typeof ender&&(t?(he.moment=function(){return!e&&console&&console.warn&&(e=!0,console.warn("Accessing Moment through the global scope is deprecated, and will be removed in an upcoming release.")),i.apply(null,arguments)},l(he.moment,i)):he.moment=oe)}for(var oe,re,ae="2.5.1",he=this,le=Math.round,ce=0,de=1,ue=2,pe=3,fe=4,ge=5,me=6,ve={},ye={_isAMomentObject:null,_i:null,_f:null,_l:null,_strict:null,_isUTC:null,_offset:null,_pf:null,_lang:null},_e="undefined"!=typeof e&&e.exports&&"undefined"!=typeof t,be=/^\/?Date\((\-?\d+)/i,we=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,Se=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,Te=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g,Ee=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,xe=/\d\d?/,Ce=/\d{1,3}/,Me=/\d{1,4}/,De=/[+\-]?\d{1,6}/,Ie=/\d+/,Ne=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Oe=/Z|[\+\-]\d\d:?\d\d/gi,Le=/T/i,ke=/[\+\-]?\d+(\.\d{1,3})?/,Ae=/\d/,Pe=/\d\d/,ze=/\d{3}/,Fe=/\d{4}/,Re=/[+-]?\d{6}/,Ye=/[+-]?\d+/,He=/^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,We="YYYY-MM-DDTHH:mm:ssZ",Ge=[["YYYYYY-MM-DD",/[+-]\d{6}-\d{2}-\d{2}/],["YYYY-MM-DD",/\d{4}-\d{2}-\d{2}/],["GGGG-[W]WW-E",/\d{4}-W\d{2}-\d/],["GGGG-[W]WW",/\d{4}-W\d{2}/],["YYYY-DDD",/\d{4}-\d{3}/]],je=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d{1,3}/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],Ue=/([\+\-]|\d\d)/gi,Be="Date|Hours|Minutes|Seconds|Milliseconds".split("|"),Ve={Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6},Xe={ms:"millisecond",s:"second",m:"minute",h:"hour",d:"day",D:"date",w:"week",W:"isoWeek",M:"month",y:"year",DDD:"dayOfYear",e:"weekday",E:"isoWeekday",gg:"weekYear",GG:"isoWeekYear"},qe={dayofyear:"dayOfYear",isoweekday:"isoWeekday",isoweek:"isoWeek",weekyear:"weekYear",isoweekyear:"isoWeekYear"},Ze={},Ke="DDD w W M D d".split(" "),$e="M D H h m s w W".split(" "),Qe={M:function(){return this.month()+1},MMM:function(t){return this.lang().monthsShort(this,t)},MMMM:function(t){return this.lang().months(this,t)},D:function(){return this.date()},DDD:function(){return this.dayOfYear()},d:function(){return this.day()},dd:function(t){return this.lang().weekdaysMin(this,t)},ddd:function(t){return this.lang().weekdaysShort(this,t)},dddd:function(t){return this.lang().weekdays(this,t)},w:function(){return this.week()},W:function(){return this.isoWeek()},YY:function(){return u(this.year()%100,2)},YYYY:function(){return u(this.year(),4)},YYYYY:function(){return u(this.year(),5)},YYYYYY:function(){var t=this.year(),e=t>=0?"+":"-";return e+u(Math.abs(t),6)},gg:function(){return u(this.weekYear()%100,2)},gggg:function(){return u(this.weekYear(),4)},ggggg:function(){return u(this.weekYear(),5)},GG:function(){return u(this.isoWeekYear()%100,2)},GGGG:function(){return u(this.isoWeekYear(),4)},GGGGG:function(){return u(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.lang().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.lang().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return b(this.milliseconds()/100)},SS:function(){return u(b(this.milliseconds()/10),2)},SSS:function(){return u(this.milliseconds(),3)},SSSS:function(){return u(this.milliseconds(),3)},Z:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+u(b(t/60),2)+":"+u(b(t)%60,2)},ZZ:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+u(b(t/60),2)+u(b(t)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},X:function(){return this.unix()},Q:function(){return this.quarter()}},Je=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"];Ke.length;)re=Ke.pop(),Qe[re+"o"]=o(Qe[re],re);for(;$e.length;)re=$e.pop(),Qe[re+re]=s(Qe[re],2);for(Qe.DDDD=s(Qe.DDD,3),l(r.prototype,{set:function(t){var e,i;for(i in t)e=t[i],"function"==typeof e?this[i]=e:this["_"+i]=e},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(t){return this._months[t.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(t){return this._monthsShort[t.month()]},monthsParse:function(t){var e,i,n;for(this._monthsParse||(this._monthsParse=[]),e=0;12>e;e++)if(this._monthsParse[e]||(i=oe.utc([2e3,e]),n="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[e]=new RegExp(n.replace(".",""),"i")),this._monthsParse[e].test(t))return e},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(t){return this._weekdays[t.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(t){return this._weekdaysShort[t.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(t){return this._weekdaysMin[t.day()]},weekdaysParse:function(t){var e,i,n;for(this._weekdaysParse||(this._weekdaysParse=[]),e=0;7>e;e++)if(this._weekdaysParse[e]||(i=oe([2e3,1]).day(e),n="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[e]=new RegExp(n.replace(".",""),"i")),this._weekdaysParse[e].test(t))return e},_longDateFormat:{LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D YYYY",LLL:"MMMM D YYYY LT",LLLL:"dddd, MMMM D YYYY LT"},longDateFormat:function(t){var e=this._longDateFormat[t];return!e&&this._longDateFormat[t.toUpperCase()]&&(e=this._longDateFormat[t.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t]=e),e},isPM:function(t){return"p"===(t+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(t,e,i){return t>11?i?"pm":"PM":i?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(t,e){var i=this._calendar[t];return"function"==typeof i?i.apply(e):i},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(t,e,i,n){var s=this._relativeTime[i];return"function"==typeof s?s(t,e,i,n):s.replace(/%d/i,t)},pastFuture:function(t,e){var i=this._relativeTime[t>0?"future":"past"];return"function"==typeof i?i(e):i.replace(/%s/i,e)},ordinal:function(t){return this._ordinal.replace("%d",t)},_ordinal:"%d",preparse:function(t){return t},postformat:function(t){return t},week:function(t){return Q(t,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),oe=function(t,e,s,o){var r;return"boolean"==typeof s&&(o=s,s=i),r={},r._isAMomentObject=!0,r._i=t,r._f=e,r._l=s,r._strict=o,r._isUTC=!1,r._pf=n(),te(r)},oe.utc=function(t,e,s,o){var r;return"boolean"==typeof s&&(o=s,s=i),r={},r._isAMomentObject=!0,r._useUTC=!0,r._isUTC=!0,r._l=s,r._i=t,r._f=e,r._strict=o,r._pf=n(),te(r).utc()},oe.unix=function(t){return oe(1e3*t)},oe.duration=function(t,e){var i,n,s,o=t,r=null;return oe.isDuration(t)?o={ms:t._milliseconds,d:t._days,M:t._months}:"number"==typeof t?(o={},e?o[e]=t:o.milliseconds=t):(r=we.exec(t))?(i="-"===r[1]?-1:1,o={y:0,d:b(r[ue])*i,h:b(r[pe])*i,m:b(r[fe])*i,s:b(r[ge])*i,ms:b(r[me])*i}):(r=Se.exec(t))&&(i="-"===r[1]?-1:1,s=function(t){var e=t&&parseFloat(t.replace(",","."));return(isNaN(e)?0:e)*i},o={y:s(r[2]),M:s(r[3]),d:s(r[4]),h:s(r[5]),m:s(r[6]),s:s(r[7]),w:s(r[8])}),n=new h(o),oe.isDuration(t)&&t.hasOwnProperty("_lang")&&(n._lang=t._lang),n},oe.version=ae,oe.defaultFormat=We,oe.updateOffset=function(){},oe.lang=function(t,e){var i;return t?(e?D(C(t),e):null===e?(I(t),t="en"):ve[t]||N(t),i=oe.duration.fn._lang=oe.fn._lang=N(t),i._abbr):oe.fn._lang._abbr},oe.langData=function(t){return t&&t._lang&&t._lang._abbr&&(t=t._lang._abbr),N(t)},oe.isMoment=function(t){return t instanceof a||null!=t&&t.hasOwnProperty("_isAMomentObject")},oe.isDuration=function(t){return t instanceof h},re=Je.length-1;re>=0;--re)_(Je[re]);for(oe.normalizeUnits=function(t){return v(t)},oe.invalid=function(t){var e=oe.utc(0/0);return null!=t?l(e._pf,t):e._pf.userInvalidated=!0,e},oe.parseZone=function(t){return oe(t).parseZone()},l(oe.fn=a.prototype,{clone:function(){return oe(this)},valueOf:function(){return+this._d+6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().lang("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){var t=oe(this).utc();return 00:!1},parsingFlags:function(){return l({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(){return this.zone(0)},local:function(){return this.zone(0),this._isUTC=!1,this},format:function(t){var e=k(this,t||oe.defaultFormat);return this.lang().postformat(e)},add:function(t,e){var i;return i="string"==typeof t?oe.duration(+e,t):oe.duration(t,e),p(this,i,1),this},subtract:function(t,e){var i;return i="string"==typeof t?oe.duration(+e,t):oe.duration(t,e),p(this,i,-1),this},diff:function(t,e,i){var n,s,o=M(t,this),r=6e4*(this.zone()-o.zone());return e=v(e),"year"===e||"month"===e?(n=432e5*(this.daysInMonth()+o.daysInMonth()),s=12*(this.year()-o.year())+(this.month()-o.month()),s+=(this-oe(this).startOf("month")-(o-oe(o).startOf("month")))/n,s-=6e4*(this.zone()-oe(this).startOf("month").zone()-(o.zone()-oe(o).startOf("month").zone()))/n,"year"===e&&(s/=12)):(n=this-o,s="second"===e?n/1e3:"minute"===e?n/6e4:"hour"===e?n/36e5:"day"===e?(n-r)/864e5:"week"===e?(n-r)/6048e5:n),i?s:d(s)},from:function(t,e){return oe.duration(this.diff(t)).lang(this.lang()._abbr).humanize(!e)},fromNow:function(t){return this.from(oe(),t)},calendar:function(){var t=M(oe(),this).startOf("day"),e=this.diff(t,"days",!0),i=-6>e?"sameElse":-1>e?"lastWeek":0>e?"lastDay":1>e?"sameDay":2>e?"nextDay":7>e?"nextWeek":"sameElse";return this.format(this.lang().calendar(i,this))},isLeapYear:function(){return T(this.year())},isDST:function(){return this.zone()+oe(t).startOf(e)},isBefore:function(t,e){return e="undefined"!=typeof e?e:"millisecond",+this.clone().startOf(e)<+oe(t).startOf(e)},isSame:function(t,e){return e=e||"ms",+this.clone().startOf(e)===+M(t,this).startOf(e)},min:function(t){return t=oe.apply(null,arguments),this>t?this:t},max:function(t){return t=oe.apply(null,arguments),t>this?this:t},zone:function(t){var e=this._offset||0;return null==t?this._isUTC?e:this._d.getTimezoneOffset():("string"==typeof t&&(t=z(t)),Math.abs(t)<16&&(t=60*t),this._offset=t,this._isUTC=!0,e!==t&&p(this,oe.duration(e-t,"m"),1,!0),this)},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.zone(this._tzm):"string"==typeof this._i&&this.zone(this._i),this},hasAlignedHourOffset:function(t){return t=t?oe(t).zone():0,(this.zone()-t)%60===0},daysInMonth:function(){return w(this.year(),this.month())},dayOfYear:function(t){var e=le((oe(this).startOf("day")-oe(this).startOf("year"))/864e5)+1;return null==t?e:this.add("d",t-e)},quarter:function(){return Math.ceil((this.month()+1)/3)},weekYear:function(t){var e=Q(this,this.lang()._week.dow,this.lang()._week.doy).year;return null==t?e:this.add("y",t-e)},isoWeekYear:function(t){var e=Q(this,1,4).year;return null==t?e:this.add("y",t-e)},week:function(t){var e=this.lang().week(this);return null==t?e:this.add("d",7*(t-e))},isoWeek:function(t){var e=Q(this,1,4).week;return null==t?e:this.add("d",7*(t-e))},weekday:function(t){var e=(this.day()+7-this.lang()._week.dow)%7;return null==t?e:this.add("d",t-e)},isoWeekday:function(t){return null==t?this.day()||7:this.day(this.day()%7?t:t-7)},get:function(t){return t=v(t),this[t]()},set:function(t,e){return t=v(t),"function"==typeof this[t]&&this[t](e),this},lang:function(t){return t===i?this._lang:(this._lang=N(t),this)}}),re=0;re-1?!1:"INPUT"==i||"SELECT"==i||"TEXTAREA"==i||e.contentEditable&&"true"==e.contentEditable}function o(t,e){return t.sort().join(",")===e.sort().join(",")}function r(t){t=t||{};var e,i=!1;for(e in M)t[e]?i=!0:M[e]=0;i||(I=!1)}function a(t,e,i,n,s){var r,a,h=[];if(!x[t])return[];for("keyup"==i&&u(t)&&(e=[t]),r=0;r95&&112>t||w.hasOwnProperty(t)&&(_[w[t]]=t)}return _}function g(t,e,i){return i||(i=f()[t]?"keydown":"keypress"),"keypress"==i&&e.length&&(i="keydown"),i}function m(t,e,i,s){M[t]=0,s||(s=g(e[0],[]));var o,a=function(){I=s,++M[t],p()},h=function(t){l(i,t),"keyup"!==s&&(D=n(t)),setTimeout(r,10)};for(o=0;o1)return m(t,l,e,i);for(h="+"===t?["+"]:t.split("+"),o=0;o":".","?":"/","|":"\\"},E={option:"alt",command:"meta","return":"enter",escape:"esc"},x={},C={},M={},D=!1,I=!1,N=1;20>N;++N)w[111+N]="f"+N;for(N=0;9>=N;++N)w[N+96]=N;i(document,"keypress",d),i(document,"keydown",d),i(document,"keyup",d);var O={bind:function(t,e,i){return y(t instanceof Array?t:[t],e,i),C[t+":"+i]=e,this},unbind:function(t,e){return C[t+":"+e]&&(delete C[t+":"+e],this.bind(t,function(){},e)),this},trigger:function(t,e){return C[t+":"+e](),this},reset:function(){return x={},C={},this}};e.exports=O},{}]},{},[1])(1)}); \ No newline at end of file diff --git a/examples/graph/19_scale_free_graph_clustering.html b/examples/graph/19_scale_free_graph_clustering.html index cced805b..640e2207 100644 --- a/examples/graph/19_scale_free_graph_clustering.html +++ b/examples/graph/19_scale_free_graph_clustering.html @@ -88,9 +88,6 @@ }; */ var options = { - edges: { - length: 50 - }, clustering: { enabled: clusteringOn, clusterEdgeThreshold: clusterEdgeThreshold diff --git a/src/graph/Graph.js b/src/graph/Graph.js index 6801ed85..c61ad086 100644 --- a/src/graph/Graph.js +++ b/src/graph/Graph.js @@ -70,16 +70,16 @@ function Graph (container, data, options) { }, physics: { barnesHut: { - enabled: false, - theta: 1 / 0.3, // inverted to save time during calculation - gravitationalConstant: -10000, - centralGravity: 0.08, - springLength: 100, - springConstant: 0.02 + enabled: true, + theta: 1 / 0.4, // inverted to save time during calculation + gravitationalConstant: -7500, + centralGravity: 0.9, + springLength: 20, + springConstant: 0.06 }, repulsion: { centralGravity: 0.01, - springLength: 100, + springLength: 60, springConstant: 0.05 }, centralGravity: null, @@ -98,11 +98,11 @@ function Graph (container, data, options) { fontSizeMultiplier: 4.0, // (px PNiC) | how much the cluster font size grows per node in cluster (in px). forceAmplification: 0.1, // (multiplier PNiC) | factor of increase fo the repulsion force of a cluster (per node in cluster). maxFontSize: 1000, - distanceAmplification: 0.03, // (multiplier PNiC) | factor how much the repulsion distance of a cluster increases (per node in cluster). + distanceAmplification: 0.1, // (multiplier PNiC) | factor how much the repulsion distance of a cluster increases (per node in cluster). edgeGrowth: 1, // (px PNiC) | amount of clusterSize connected to the edge is multiplied with this and added to edgeLength. - nodeScaling: {width: 5, // (px PNiC) | growth of the width per node in cluster. - height: 5, // (px PNiC) | growth of the height per node in cluster. - radius: 5}, // (px PNiC) | growth of the radius per node in cluster. + nodeScaling: {width: 1, // (px PNiC) | growth of the width per node in cluster. + height: 1, // (px PNiC) | growth of the height per node in cluster. + radius: 1}, // (px PNiC) | growth of the radius per node in cluster. maxNodeSizeIncrements: 600, // (# increments) | max growth of the width per node in cluster. activeAreaBoxSize: 80, // (px) | box area around the curser where clusters are popped open. clusterLevelDifference: 2 @@ -417,7 +417,6 @@ Graph.prototype.setOptions = function (options) { if (options.stabilize !== undefined) {this.stabilize = options.stabilize;} if (options.selectable !== undefined) {this.selectable = options.selectable;} -/* if (options.physics) { if (options.physics.barnesHut) { this.constants.physics.barnesHut.enabled = true; @@ -437,7 +436,7 @@ Graph.prototype.setOptions = function (options) { } } } -*/ + if (options.clustering) { this.constants.clustering.enabled = true; for (var prop in options.clustering) { @@ -1264,13 +1263,11 @@ Graph.prototype._addNodes = function(ids) { var node = new Node(data, this.images, this.groups, this.constants); this.nodes[id] = node; // note: this may replace an existing node - if (!node.isFixed() && this.createNodeOnClick != true) { - // TODO: position new nodes in a smarter way! - var radius = this.constants.edges.length; - var count = ids.length; - var angle = 2 * Math.PI * (i / count); - node.x = radius * Math.cos(angle); - node.y = radius * Math.sin(angle); + if ((node.xFixed == false || node.yFixed == false) && this.createNodeOnClick != true) { + var radius = this.constants.physics.springLength * 0.1*ids.length; + var angle = 2 * Math.PI * Math.random(); + if (node.xFixed == false) {node.x = radius * Math.cos(angle);} + if (node.yFixed == false) {node.y = radius * Math.sin(angle);} // note: no not use node.isMoving() here, as that gives the current // velocity of the node, which is zero after creation of the node. @@ -1431,6 +1428,7 @@ Graph.prototype._updateEdges = function (ids) { } } + this._createBezierNodes(); this.moving = true; this._updateValueRange(edges); }; @@ -1446,6 +1444,9 @@ Graph.prototype._removeEdges = function (ids) { var id = ids[i]; var edge = edges[id]; if (edge) { + if (edge.via != null) { + delete this.sectors['support']['nodes'][edge.via.id]; + } edge.disconnect(); delete edges[id]; } @@ -1453,6 +1454,7 @@ Graph.prototype._removeEdges = function (ids) { this.moving = true; this._updateValueRange(edges); + this._setCalculationNodes(); }; /** @@ -1741,10 +1743,9 @@ Graph.prototype._doStabilize = function() { * @private */ Graph.prototype._isMoving = function(vmin) { - var vminCorrected = vmin / Math.max(this.scale,0.05); var nodes = this.nodes; for (var id in nodes) { - if (nodes.hasOwnProperty(id) && nodes[id].isMoving(vminCorrected)) { + if (nodes.hasOwnProperty(id) && nodes[id].isMoving(vmin)) { return true; } } @@ -1760,7 +1761,7 @@ Graph.prototype._isMoving = function(vmin) { * @private */ Graph.prototype._discreteStepNodes = function() { - var interval = 1.2; + var interval = 1.0; var nodes = this.nodes; if (this.constants.maxVelocity > 0) { @@ -1777,8 +1778,13 @@ Graph.prototype._discreteStepNodes = function() { } } } - var vmin = this.constants.minVelocity; - this.moving = this._isMoving(vmin); + var vminCorrected = this.constants.minVelocity / Math.max(this.scale,0.05); + if (vminCorrected > 0.5*this.constants.maxVelocity) { + this.moving = true; + } + else { + this.moving = this._isMoving(vminCorrected); + } }; @@ -1820,15 +1826,15 @@ Graph.prototype.start = function() { graph._zoom(graph.scale*(1 + graph.zoomIncrement), center); } - var calctimeStart = Date.now(); +// var calctimeStart = Date.now(); graph.start(); graph.start(); - var calctime = Date.now() - calctimeStart; - var rendertimeStart = Date.now(); +// var calctime = Date.now() - calctimeStart; +// var rendertimeStart = Date.now(); graph._redraw(); - var rendertime = Date.now() - rendertimeStart; +// var rendertime = Date.now() - rendertimeStart; //this.end = window.performance.now(); //this.time = this.end - this.startTime; @@ -1882,25 +1888,27 @@ Graph.prototype.toggleFreeze = function() { Graph.prototype._createBezierNodes = function() { - for (var edgeId in this.edges) { - if (this.edges.hasOwnProperty(edgeId)) { - var edge = this.edges[edgeId]; - if (edge.smooth == true) { - if (edge.via == null) { - this.sectors['support']['nodes'][edge.id] = new Node( - {id:edge.id, - mass:1, - shape:'circle', - internalMultiplier:1, - damping: 0.9},{},{},this.constants); - edge.via = this.sectors['support']['nodes'][edge.id]; - edge.via.parentEdgeId = edge.id; - edge.positionBezierNode(); + if (this.constants.smoothCurves == true) { + for (var edgeId in this.edges) { + if (this.edges.hasOwnProperty(edgeId)) { + var edge = this.edges[edgeId]; + if (edge.smooth == true) { + if (edge.via == null) { + var nodeId = "edgeId:".concat(edge.id); + this.sectors['support']['nodes'][nodeId] = new Node( + {id:nodeId, + mass:1, + shape:'circle', + internalMultiplier:1, + damping: 1},{},{},this.constants); + edge.via = this.sectors['support']['nodes'][nodeId]; + edge.via.parentEdgeId = edge.id; + edge.positionBezierNode(); + } } } } } - }; diff --git a/src/graph/Node.js b/src/graph/Node.js index c9f96466..764db270 100644 --- a/src/graph/Node.js +++ b/src/graph/Node.js @@ -60,6 +60,7 @@ function Node(properties, imagelist, grouplist, constants) { this.dampingBase = 0.9; this.damping = 0.9; // this is manipulated in the updateDamping function + this.mass = 1; // kg this.setProperties(properties, constants); @@ -74,7 +75,7 @@ function Node(properties, imagelist, grouplist, constants) { this.growthIndicator = 0; // mass, force, velocity - this.mass = 1; // kg + this.fx = 0.0; // external force x this.fy = 0.0; // external force y this.vx = 0.0; // velocity x @@ -150,6 +151,8 @@ Node.prototype.setProperties = function(properties, constants) { // physics if (properties.internalMultiplier !== undefined) {this.internalMultiplier = properties.internalMultiplier;} if (properties.damping !== undefined) {this.dampingBase = properties.damping;} + if (properties.mass !== undefined) {this.mass = properties.mass;} + // navigation controls properties if (properties.horizontalAlignLeft !== undefined) {this.horizontalAlignLeft = properties.horizontalAlignLeft;} if (properties.verticalAlignTop !== undefined) {this.verticalAlignTop = properties.verticalAlignTop;} @@ -984,7 +987,7 @@ Node.prototype.setScale = function(scale) { * @param {Number} numberOfNodes */ Node.prototype.updateDamping = function() { - this.damping = Math.min(Math.max(1.5,this.dampingBase),this.dampingBase + 0.01*this.growthIndicator); + this.damping = Math.min(Math.max(1.2,this.dampingBase),this.dampingBase + 0.01*this.growthIndicator); }; diff --git a/src/graph/graphMixins/ClusterMixin.js b/src/graph/graphMixins/ClusterMixin.js index ccc8fbba..74f825b3 100644 --- a/src/graph/graphMixins/ClusterMixin.js +++ b/src/graph/graphMixins/ClusterMixin.js @@ -8,23 +8,24 @@ */ var ClusterMixin = { -/** - * This is only called in the constructor of the graph object - * */ + /** + * This is only called in the constructor of the graph object + * + */ startWithClustering : function() { - // cluster if the data set is big - this.clusterToFit(this.constants.clustering.initialMaxNodes, true); + // cluster if the data set is big + this.clusterToFit(this.constants.clustering.initialMaxNodes, true); - // updates the lables after clustering - this.updateLabels(); + // updates the lables after clustering + this.updateLabels(); - // this is called here because if clusterin is disabled, the start and stabilize are called in - // the setData function. - if (this.stabilize) { - this._doStabilize(); - } - this.start(); - }, + // this is called here because if clusterin is disabled, the start and stabilize are called in + // the setData function. + if (this.stabilize) { + this._doStabilize(); + } + this.start(); + }, /** * This function clusters until the initialMaxNodes has been reached @@ -56,7 +57,7 @@ var ClusterMixin = { if (level > 0 && reposition == true) { this.repositionNodes(); } - }, + }, /** * This function can be called to open up a specific cluster. It is only called by @@ -68,12 +69,16 @@ var ClusterMixin = { var isMovingBeforeClustering = this.moving; if (node.clusterSize > this.constants.clustering.sectorThreshold && this._nodeInActiveArea(node) && !(this._sector() == "default" && this.nodeIndices.length == 1)) { + // this loads a new sector, loads the nodes and edges and nodeIndices of it. this._addSector(node); var level = 0; + + // we decluster until we reach a decent number of nodes while ((this.nodeIndices.length < this.constants.clustering.initialMaxNodes) && (level < 10)) { this.decreaseClusterLevel(); level += 1; } + } else { this._expandClusterNode(node,false,true); @@ -89,7 +94,7 @@ var ClusterMixin = { if (this.moving != isMovingBeforeClustering) { this.start(); } - }, + }, /** @@ -109,7 +114,7 @@ var ClusterMixin = { */ increaseClusterLevel : function() { this.updateClusters(-1,false,true); - }, + }, /** @@ -119,7 +124,7 @@ var ClusterMixin = { */ decreaseClusterLevel : function() { this.updateClusters(1,false,true); - }, + }, /** @@ -192,7 +197,9 @@ var ClusterMixin = { this.start(); } } - }, + + this._setCalculationNodes(); + }, /** * This function handles the chains. It is called on every updateClusters(). @@ -204,7 +211,7 @@ var ClusterMixin = { this._reduceAmountOfChains(1 - this.constants.clustering.chainThreshold / chainPercentage) } - }, + }, /** * this functions starts clustering by hubs @@ -215,7 +222,7 @@ var ClusterMixin = { _aggregateHubs : function(force) { this._getHubSize(); this._formClustersByHub(force,false); - }, + }, /** @@ -244,7 +251,7 @@ var ClusterMixin = { this.start(); } } - }, + }, /** * If a cluster takes up more than a set percentage of the screen, open the cluster @@ -263,7 +270,7 @@ var ClusterMixin = { } } } - }, + }, /** @@ -278,7 +285,7 @@ var ClusterMixin = { this._expandClusterNode(node,recursive,force); this._setCalculationNodes(); } - }, + }, /** * This function checks if a node has to be opened. This is done by checking the zoom level. @@ -324,8 +331,7 @@ var ClusterMixin = { } } } - - }, + }, /** * ONLY CALLED FROM _expandClusterNode @@ -342,14 +348,13 @@ var ClusterMixin = { * @param {Boolean} openAll | This will recursively force all nodes in the parent to be released * @private */ - _expelChildFromParent : function(parentNode, containedNodeId, recursive, force, openAll) { + _expelChildFromParent : function(parentNode, containedNodeId, recursive, force, openAll) { var childNode = parentNode.containedNodes[containedNodeId]; // if child node has been added on smaller scale than current, kick out if (childNode.formationScale < this.scale || force == true) { - // remove the selection, first remove the selection from the connected edges - this._unselectConnectedEdges(parentNode); - parentNode.unselect(); + // unselect all selected items + this._unselectAll(); // put the child node back in the global nodes object this.nodes[containedNodeId] = childNode; @@ -370,8 +375,8 @@ var ClusterMixin = { parentNode.dynamicEdgesLength = parentNode.dynamicEdges.length; // place the child node near the parent, not at the exact same location to avoid chaos in the system - childNode.x = parentNode.x + parentNode.growthIndicator * (0.5 - Math.random()) * childNode.clusterSize; - childNode.y = parentNode.y + parentNode.growthIndicator * (0.5 - Math.random()) * childNode.clusterSize; + childNode.x = parentNode.x + parentNode.growthIndicator * (0.5 - Math.random()); + childNode.y = parentNode.y + parentNode.growthIndicator * (0.5 - Math.random()); // remove node from the list delete parentNode.containedNodes[containedNodeId]; @@ -391,24 +396,37 @@ var ClusterMixin = { parentNode.clusterSessions.pop(); } + this._repositionBezierNodes(childNode); +// this._repositionBezierNodes(parentNode); + // remove the clusterSession from the child node childNode.clusterSession = 0; - // restart the simulation to reorganise all nodes - this.moving = true; - // recalculate the size of the node on the next time the node is rendered parentNode.clearSizeCache(); - // this unselects the rest of the edges - this._unselectConnectedEdges(parentNode); + // restart the simulation to reorganise all nodes + this.moving = true; } // check if a further expansion step is possible if recursivity is enabled if (recursive == true) { this._expandClusterNode(childNode,recursive,force,openAll); } - }, + }, + + + /** + * position the bezier nodes at the center of the edges + * + * @param node + * @private + */ + _repositionBezierNodes : function(node) { + for (var i = 0; i < node.dynamicEdges.length; i++) { + node.dynamicEdges[i].positionBezierNode(); + } + }, /** @@ -427,7 +445,8 @@ var ClusterMixin = { else { this._forceClustersByZoom(); } - }, + }, + /** * This function handles the clustering by zooming out, this is based on a minimum edge distance @@ -470,7 +489,7 @@ var ClusterMixin = { } } } - }, + }, /** * This function forces the graph to cluster all nodes with only one connecting edge to their @@ -501,9 +520,16 @@ var ClusterMixin = { } } } - }, + }, + /** + * To keep the nodes of roughly equal size we normalize the cluster levels. + * This function clusters a node to its smallest connected neighbour. + * + * @param node + * @private + */ _clusterToSmallestNeighbour : function(node) { var smallestNeighbour = -1; var smallestNeighbourNode = null; @@ -546,7 +572,7 @@ var ClusterMixin = { this._formClusterFromHub(this.nodes[nodeId],force,onlyEqual); } } - }, + }, /** * This function forms a cluster from a specific preselected hub node @@ -616,7 +642,7 @@ var ClusterMixin = { } } } - }, + }, @@ -687,7 +713,7 @@ var ClusterMixin = { // restart the simulation to reorganise all nodes this.moving = true; - }, + }, /** @@ -717,7 +743,7 @@ var ClusterMixin = { } node.dynamicEdgesLength -= correction; } - }, + }, /** @@ -746,7 +772,7 @@ var ClusterMixin = { break; } } - }, + }, /** * This function connects an edge that was connected to a child node to the parent node. @@ -777,9 +803,17 @@ var ClusterMixin = { this._addToReroutedEdges(parentNode,childNode,edge); } - }, + }, + /** + * If a node is connected to itself, a circular edge is drawn. When clustering we want to contain + * these edges inside of the cluster. + * + * @param parentNode + * @param childNode + * @private + */ _containCircularEdgesFromNode : function(parentNode, childNode) { // manage all the edges connected to the child and parent nodes for (var i = 0; i < parentNode.dynamicEdges.length; i++) { @@ -850,7 +884,7 @@ var ClusterMixin = { // remove the entry from the rerouted edges delete parentNode.reroutedEdges[childNode.id]; } - }, + }, /** @@ -868,7 +902,7 @@ var ClusterMixin = { parentNode.dynamicEdges.splice(i,1); } } - }, + }, /** @@ -893,7 +927,7 @@ var ClusterMixin = { // remove the entry from the contained edges delete parentNode.containedEdges[childNode.id]; - }, + }, @@ -939,9 +973,15 @@ var ClusterMixin = { // } // } - }, + }, + /** + * We want to keep the cluster level distribution rather small. This means we do not want unclustered nodes + * if the rest of the nodes are already a few cluster levels in. + * To fix this we use this function. It determines the min and max cluster level and sends nodes that have not + * clustered enough to the clusterToSmallestNeighbours function. + */ normalizeClusterLevels : function() { var maxLevel = 0; var minLevel = 1e9; @@ -992,7 +1032,7 @@ var ClusterMixin = { && Math.abs(node.y - this.areaCenter.y) <= this.constants.clustering.activeAreaBoxSize/this.scale ) - }, + }, /** @@ -1003,17 +1043,14 @@ var ClusterMixin = { repositionNodes : function() { for (var i = 0; i < this.nodeIndices.length; i++) { var node = this.nodes[this.nodeIndices[i]]; - if (!node.isFixed()) { + if ((node.xFixed == false || node.yFixed == false) && this.createNodeOnClick != true) { var radius = this.constants.physics.springLength * (1 + 0.1*node.mass); var angle = 2 * Math.PI * Math.random(); - node.x = radius * Math.cos(angle); - node.y = radius * Math.sin(angle); + if (node.xFixed == false) {node.x = radius * Math.cos(angle);} + if (node.yFixed == false) {node.y = radius * Math.sin(angle);} } } - }, - - - + }, /** @@ -1054,7 +1091,7 @@ var ClusterMixin = { // console.log("average",average,"averageSQ",averageSquared,"var",variance,"std",standardDeviation); // console.log("hubThreshold:",this.hubThreshold); - }, + }, /** @@ -1077,7 +1114,7 @@ var ClusterMixin = { } } } - }, + }, /** * We get the amount of "extension nodes" or chains. These are not quickly clustered with the outliers and hubs methods @@ -1097,5 +1134,6 @@ var ClusterMixin = { } } return chains/total; - } + } + }; diff --git a/src/graph/graphMixins/physics/PhysicsMixin.js b/src/graph/graphMixins/physics/PhysicsMixin.js index 1f7dc85c..3608ab20 100644 --- a/src/graph/graphMixins/physics/PhysicsMixin.js +++ b/src/graph/graphMixins/physics/PhysicsMixin.js @@ -5,12 +5,19 @@ var physicsMixin = { + /** + * Toggling barnes Hut calculation on and off. + * + * @private + */ _toggleBarnesHut : function() { this.constants.physics.barnesHut.enabled = !this.constants.physics.barnesHut.enabled; this._loadSelectedForceSolver(); this.moving = true; this.start(); }, + + /** * Before calculating the forces, we check if we need to cluster to keep up performance and we check * if there is more than one node. If it is just one node, we dont calculate anything. @@ -51,13 +58,22 @@ var physicsMixin = { if (this.constants.smoothCurves == true) { - this._calculateSpringForcesOnSupport(); + this._calculateSpringForcesWithSupport(); } else { this._calculateSpringForces(); } }, + + /** + * Smooth curves are created by adding invisible nodes in the center of the edges. These nodes are also + * handled in the calculateForces function. We then use a quadratic curve with the center node as control. + * This function joins the datanodes and invisible (called support) nodes into one object. + * We do this so we do not contaminate this.nodes with the support nodes. + * + * @private + */ _setCalculationNodes : function() { if (this.constants.smoothCurves == true) { this.calculationNodes = {}; @@ -74,6 +90,9 @@ var physicsMixin = { if (this.edges.hasOwnProperty(supportNodes[supportNodeId].parentEdgeId)) { this.calculationNodes[supportNodeId] = supportNodes[supportNodeId]; } + else { + supportNodes[supportNodeId]._setForce(0,0); + } } } @@ -90,17 +109,11 @@ var physicsMixin = { }, - _clearForces : function() { - var node, i; - var nodes = this.nodes; - - for (i = 0; i < this.nodeIndices.length; i++) { - node = nodes[this.nodeIndices[i]]; - node._setForce(0, 0); - node.updateDamping(this.nodeIndices.length); - } - }, - + /** + * this function applies the central gravity effect to keep groups from floating off + * + * @private + */ _calculateGravitationalForces : function() { var dx, dy, angle, fx, fy, node, i; var nodes = this.calculationNodes; @@ -110,8 +123,8 @@ var physicsMixin = { node = nodes[this.calculationNodeIndices[i]]; // gravity does not apply when we are in a pocket sector if (this._sector() == "default") { - dx = -node.x;// + screenCenterPos.x; - dy = -node.y;// + screenCenterPos.y; + dx = -node.x; + dy = -node.y; angle = Math.atan2(dy, dx); fx = Math.cos(angle) * gravity; @@ -126,8 +139,14 @@ var physicsMixin = { } }, + + /** + * this function calculates the effects of the springs in the case of unsmooth curves. + * + * @private + */ _calculateSpringForces : function() { - var dx, dy, angle, fx, fy, springForce, length, edgeLength, edge, edgeId; + var edgeLength, edge, edgeId; var edges = this.edges; // forces caused by the edges, modelled as springs @@ -137,30 +156,23 @@ var physicsMixin = { if (edge.connected) { // only calculate forces if nodes are in the same sector if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { - dx = (edge.to.x - edge.from.x); - dy = (edge.to.y - edge.from.y); - edgeLength = edge.length; - // this implies that the edges between big clusters are longer edgeLength += (edge.to.growthIndicator + edge.from.growthIndicator) * this.constants.clustering.edgeGrowth; - length = Math.sqrt(dx * dx + dy * dy); - angle = Math.atan2(dy, dx); - - springForce = this.constants.physics.springConstant * (edgeLength - length); - - fx = Math.cos(angle) * springForce; - fy = Math.sin(angle) * springForce; - - edge.from._addForce(-fx, -fy); - edge.to._addForce(fx, fy); + this._calculateSpringForce(edge.from,edge.to,edgeLength); } } } } }, - _calculateSpringForcesOnSupport : function() { + + /** + * This function calculates the springforces on the nodes, accounting for the support nodes. + * + * @private + */ + _calculateSpringForcesWithSupport : function() { var edgeLength, edge, edgeId, growthIndicator; var edges = this.edges; @@ -177,11 +189,11 @@ var physicsMixin = { var node3 = edge.from; edgeLength = 0.5*edge.length; + growthIndicator = 0.5*(node1.growthIndicator + node3.growthIndicator); // this implies that the edges between big clusters are longer edgeLength += growthIndicator * this.constants.clustering.edgeGrowth; - this._calculateSpringForce(node1,node2,edgeLength); this._calculateSpringForce(node2,node3,edgeLength); } @@ -191,6 +203,15 @@ var physicsMixin = { } }, + + /** + * This is the code actually performing the calculation for the function above. It is split out to avoid repetition. + * + * @param node1 + * @param node2 + * @param edgeLength + * @private + */ _calculateSpringForce : function(node1,node2,edgeLength) { var dx, dy, angle, fx, fy, springForce, length; @@ -198,6 +219,7 @@ var physicsMixin = { dy = (node1.y - node2.y); length = Math.sqrt(dx * dx + dy * dy); angle = Math.atan2(dy, dx); + springForce = this.constants.physics.springConstant * (edgeLength - length); fx = Math.cos(angle) * springForce; diff --git a/src/graph/graphMixins/physics/barnesHut.js b/src/graph/graphMixins/physics/barnesHut.js index 2321320b..a7646213 100644 --- a/src/graph/graphMixins/physics/barnesHut.js +++ b/src/graph/graphMixins/physics/barnesHut.js @@ -4,7 +4,12 @@ var barnesHutMixin = { - + /** + * This function calculates the forces the nodes apply on eachother based on a gravitational model. + * The Barnes Hut method is used to speed up this N-body simulation. + * + * @private + */ _calculateNodeForces : function() { var node; var nodes = this.calculationNodes; @@ -13,7 +18,6 @@ var barnesHutMixin = { this._formBarnesHutTree(nodes,nodeIndices); - var barnesHutTree = this.barnesHutTree; // place the nodes one by one recursively @@ -27,14 +31,23 @@ var barnesHutMixin = { } }, + + /** + * This function traverses the barnesHutTree. It checks when it can approximate distant nodes with their center of mass. + * If a region contains a single node, we check if it is not itself, then we apply the force. + * + * @param parentBranch + * @param node + * @private + */ _getForceContribution : function(parentBranch,node) { // we get no force contribution from an empty region if (parentBranch.childrenCount > 0) { var dx,dy,distance; // get the distance from the center of mass to the node. - dx = parentBranch.CenterOfMass.x - node.x; - dy = parentBranch.CenterOfMass.y - node.y; + dx = parentBranch.centerOfMass.x - node.x; + dy = parentBranch.centerOfMass.y - node.y; distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { // distance is 0 if it looks to apply a force on itself. @@ -60,8 +73,17 @@ var barnesHutMixin = { } }, + /** + * The gravitational force applied on the node by the mass of the branch. + * + * @param parentBranch + * @param node + * @param dx + * @param dy + * @param distance + * @private + */ _getForceOnNode : function(parentBranch, node, dx ,dy, distance) { - //console.log(Math.max(Math.max(node.height,node.radius),node.width),parentBranch.maxWidth,distance); // even if the parentBranch only has one node, its Center of Mass is at the right place (the node in this case). var gravityForce = this.constants.physics.barnesHut.gravitationalConstant * parentBranch.mass * node.mass / (distance * distance); var angle = Math.atan2(dy, dx); @@ -71,6 +93,13 @@ var barnesHutMixin = { }, + /** + * This function constructs the barnesHut tree recursively. It creates the root, splits it and starts placing the nodes. + * + * @param nodes + * @param nodeIndices + * @private + */ _formBarnesHutTree : function(nodes,nodeIndices) { var node; var nodeCount = nodeIndices.length; @@ -95,13 +124,19 @@ var barnesHutMixin = { else {minX += 0.5 * sizeDiff; maxX -= 0.5 * sizeDiff;} // xSize < ySize + var minimumTreeSize = 1e-5; + var rootSize = Math.max(minimumTreeSize,Math.abs(maxX - minX)); + var halfRootSize = 0.5 * rootSize; + var centerX = 0.5 * (minX + maxX), centerY = 0.5 * (minY + maxY); + // construct the barnesHutTree var barnesHutTree = {root:{ - CenterOfMass:{x:0,y:0}, // Center of Mass + centerOfMass:{x:0,y:0}, // Center of Mass mass:0, - range:{minX:minX,maxX:maxX,minY:minY,maxY:maxY}, - size: Math.abs(maxX - minX), - calcSize: 1 / Math.abs(maxX - minX), + range: {minX:centerX-halfRootSize,maxX:centerX+halfRootSize, + minY:centerY-halfRootSize,maxY:centerY+halfRootSize}, + size: rootSize, + calcSize: 1 / rootSize, children: {data:null}, maxWidth: 0, level: 0, @@ -124,11 +159,11 @@ var barnesHutMixin = { var totalMass = parentBranch.mass + node.mass; var totalMassInv = 1/totalMass; - parentBranch.CenterOfMass.x = parentBranch.CenterOfMass.x * parentBranch.mass + node.x * node.mass; - parentBranch.CenterOfMass.x *= totalMassInv; + parentBranch.centerOfMass.x = parentBranch.centerOfMass.x * parentBranch.mass + node.x * node.mass; + parentBranch.centerOfMass.x *= totalMassInv; - parentBranch.CenterOfMass.y = parentBranch.CenterOfMass.y * parentBranch.mass + node.y * node.mass; - parentBranch.CenterOfMass.y *= totalMassInv; + parentBranch.centerOfMass.y = parentBranch.centerOfMass.y * parentBranch.mass + node.y * node.mass; + parentBranch.centerOfMass.y *= totalMassInv; parentBranch.mass = totalMass; var biggestSize = Math.max(Math.max(node.height,node.radius),node.width); @@ -137,10 +172,12 @@ var barnesHutMixin = { }, - _placeInTree : function(parentBranch,node) { - // update the mass of the branch. - this._updateBranchMass(parentBranch,node); - + _placeInTree : function(parentBranch,node,skipMassUpdate) { + if (skipMassUpdate != true || skipMassUpdate === undefined) { + // update the mass of the branch. + this._updateBranchMass(parentBranch,node); + } + //console.log(parentBranch.children.NW.range.maxX,parentBranch.children.NW.range.maxY, node.x,node.y); if (parentBranch.children.NW.range.maxX > node.x) { // in NW or SW if (parentBranch.children.NW.range.maxY > node.y) { // in NW this._placeInRegion(parentBranch,node,"NW"); @@ -150,7 +187,7 @@ var barnesHutMixin = { } } else { // in NE or SE - if (parentBranch.children.NE.range.maxY > node.y) { // in NE + if (parentBranch.children.NW.range.maxY > node.y) { // in NE this._placeInRegion(parentBranch,node,"NE"); } else { // in SE @@ -168,8 +205,16 @@ var barnesHutMixin = { this._updateBranchMass(parentBranch.children[region],node); break; case 1: // convert into children - this._splitBranch(parentBranch.children[region]); - this._placeInTree(parentBranch.children[region],node); + // if there are two nodes exactly overlapping (on init, on opening of cluster etc.) + // we move one node a pixel and we do not put it in the tree. + if (parentBranch.children[region].children.data.x == node.x && + parentBranch.children[region].children.data.y == node.y) { + node.x += 0.1; + } + else { + this._splitBranch(parentBranch.children[region]); + this._placeInTree(parentBranch.children[region],node); + } break; case 4: // place in branch this._placeInTree(parentBranch.children[region],node); @@ -178,12 +223,19 @@ var barnesHutMixin = { }, + /** + * this function splits a branch into 4 sub branches. If the branch contained a node, we place it in the subbranch + * after the split is complete. + * + * @param parentBranch + * @private + */ _splitBranch : function(parentBranch) { // if the branch is filled with a node, replace the node in the new subset. var containedNode = null; if (parentBranch.childrenCount == 1) { containedNode = parentBranch.children.data; - parentBranch.mass = 0; parentBranch.CenterOfMass.x = 0; parentBranch.CenterOfMass.y = 0; + parentBranch.mass = 0; parentBranch.centerOfMass.x = 0; parentBranch.centerOfMass.y = 0; } parentBranch.childrenCount = 4; parentBranch.children.data = null; @@ -210,47 +262,56 @@ var barnesHutMixin = { */ _insertRegion : function(parentBranch, region) { var minX,maxX,minY,maxY; + var childSize = 0.5 * parentBranch.size; switch (region) { case "NW": minX = parentBranch.range.minX; - maxX = parentBranch.range.minX + parentBranch.size; + maxX = parentBranch.range.minX + childSize; minY = parentBranch.range.minY; - maxY = parentBranch.range.minY + parentBranch.size; + maxY = parentBranch.range.minY + childSize; break; case "NE": - minX = parentBranch.range.minX + parentBranch.size; + minX = parentBranch.range.minX + childSize; maxX = parentBranch.range.maxX; minY = parentBranch.range.minY; - maxY = parentBranch.range.minY + parentBranch.size; + maxY = parentBranch.range.minY + childSize; break; case "SW": minX = parentBranch.range.minX; - maxX = parentBranch.range.minX + parentBranch.size; - minY = parentBranch.range.minY + parentBranch.size; + maxX = parentBranch.range.minX + childSize; + minY = parentBranch.range.minY + childSize; maxY = parentBranch.range.maxY; break; case "SE": - minX = parentBranch.range.minX + parentBranch.size; + minX = parentBranch.range.minX + childSize; maxX = parentBranch.range.maxX; - minY = parentBranch.range.minY + parentBranch.size; + minY = parentBranch.range.minY + childSize; maxY = parentBranch.range.maxY; break; } parentBranch.children[region] = { - CenterOfMass:{x:0,y:0}, + centerOfMass:{x:0,y:0}, mass:0, range:{minX:minX,maxX:maxX,minY:minY,maxY:maxY}, size: 0.5 * parentBranch.size, calcSize: 2 * parentBranch.calcSize, children: {data:null}, maxWidth: 0, - level: parentBranch.level +1, + level: parentBranch.level+1, childrenCount: 0 }; }, + + /** + * This function is for debugging purposed, it draws the tree. + * + * @param ctx + * @param color + * @private + */ _drawTree : function(ctx,color) { if (this.barnesHutTree !== undefined) { @@ -260,6 +321,15 @@ var barnesHutMixin = { } }, + + /** + * This function is for debugging purposes. It draws the branches recursively. + * + * @param branch + * @param ctx + * @param color + * @private + */ _drawBranch : function(branch,ctx,color) { if (color === undefined) { color = "#FF0000"; @@ -294,7 +364,7 @@ var barnesHutMixin = { /* if (branch.mass > 0) { - ctx.circle(branch.CenterOfMass.x, branch.CenterOfMass.y, 3*branch.mass); + ctx.circle(branch.centerOfMass.x, branch.centerOfMass.y, 3*branch.mass); ctx.stroke(); } */ diff --git a/src/graph/graphMixins/physics/repulsion.js b/src/graph/graphMixins/physics/repulsion.js index 3c01932f..8bc9895e 100644 --- a/src/graph/graphMixins/physics/repulsion.js +++ b/src/graph/graphMixins/physics/repulsion.js @@ -30,7 +30,7 @@ var repulsionMixin = { node1 = nodes[nodeIndices[i]]; for (j = i+1; j < nodeIndices.length; j++) { node2 = nodes[nodeIndices[j]]; - combinedClusterSize = (node1.growthIndicator + node2.growthIndicator); + combinedClusterSize = node1.clusterSize + node2.clusterSize - 2; dx = node2.x - node1.x; dy = node2.y - node1.y; From 15f0e10b39313620169e7e9a84fd3393d5298641 Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Tue, 11 Feb 2014 16:10:27 +0100 Subject: [PATCH 44/52] minor tweaks --- src/graph/Graph.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/graph/Graph.js b/src/graph/Graph.js index c61ad086..e9110dfd 100644 --- a/src/graph/Graph.js +++ b/src/graph/Graph.js @@ -36,8 +36,8 @@ function Graph (container, data, options) { widthMax: 64, // px fontColor: 'black', fontSize: 14, // px - //fontFace: verdana, - fontFace: 'arial', + fontFace: 'verdana', +// fontFace: 'arial', color: { border: '#2B7CE9', background: '#97C2FC', @@ -71,11 +71,11 @@ function Graph (container, data, options) { physics: { barnesHut: { enabled: true, - theta: 1 / 0.4, // inverted to save time during calculation + theta: 1 / 0.3, // inverted to save time during calculation gravitationalConstant: -7500, centralGravity: 0.9, - springLength: 20, - springConstant: 0.06 + springLength: 25, + springConstant: 0.05 }, repulsion: { centralGravity: 0.01, From 48b9499a3cfca4db28bf517583b0c2ca1c6ad341 Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Tue, 11 Feb 2014 17:39:19 +0100 Subject: [PATCH 45/52] Added smooth curve support for center arrow and arrow. --- src/graph/Edge.js | 70 +++++++++++++++++++++++++++++------------------ src/graph/Node.js | 2 -- 2 files changed, 44 insertions(+), 28 deletions(-) diff --git a/src/graph/Edge.js b/src/graph/Edge.js index 65c27f88..2468fd68 100644 --- a/src/graph/Edge.js +++ b/src/graph/Edge.js @@ -287,8 +287,8 @@ Edge.prototype._line = function (ctx) { // draw a straight line ctx.beginPath(); ctx.moveTo(this.from.x, this.from.y); - if (this.smooth == true) { - ctx.quadraticCurveTo(this.via.x,this.via.y,this.to.x, this.to.y); + if (this.smooth == true) { + ctx.quadraticCurveTo(this.via.x,this.via.y,this.to.x, this.to.y); } else { ctx.lineTo(this.to.x, this.to.y); @@ -429,10 +429,18 @@ Edge.prototype._drawArrowCenter = function(ctx) { // draw line this._line(ctx); - // draw an arrow halfway the line var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); var length = 10 + 5 * this.width; // TODO: make customizable? - point = this._pointOnLine(0.5); + // draw an arrow halfway the line + if (this.smooth == true) { + var midpointX = 0.5*(0.5*(this.from.x + this.via.x) + 0.5*(this.to.x + this.via.x)); + var midpointY = 0.5*(0.5*(this.from.y + this.via.y) + 0.5*(this.to.y + this.via.y)); + point = {x:midpointX, y:midpointY}; + } + else { + point = this._pointOnLine(0.5); + } + ctx.arrow(point.x, point.y, angle, length); ctx.fill(); ctx.stroke(); @@ -446,18 +454,18 @@ Edge.prototype._drawArrowCenter = function(ctx) { else { // draw circle var x, y; - var radius = this.length / 4; + var radius = 0.25 * Math.max(100,this.length); var node = this.from; if (!node.width) { node.resize(ctx); } if (node.width > node.height) { - x = node.x + node.width / 2; + x = node.x + node.width * 0.5; y = node.y - radius; } else { x = node.x + radius; - y = node.y - node.height / 2; + y = node.y - node.height * 0.5; } this._circle(ctx, x, y, radius); @@ -492,32 +500,43 @@ Edge.prototype._drawArrow = function(ctx) { ctx.fillStyle = this.color; ctx.lineWidth = this._getLineWidth(); - // draw line var angle, length; + //draw a line if (this.from != this.to) { - // calculate length and angle of the line angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); var dx = (this.to.x - this.from.x); var dy = (this.to.y - this.from.y); - var lEdge = Math.sqrt(dx * dx + dy * dy); - - var lFrom = this.from.distanceToBorder(ctx, angle + Math.PI); - var pFrom = (lEdge - lFrom) / lEdge; - var xFrom = (pFrom) * this.from.x + (1 - pFrom) * this.to.x; - var yFrom = (pFrom) * this.from.y + (1 - pFrom) * this.to.y; + var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); + + var fromBorderDist = this.from.distanceToBorder(ctx, angle + Math.PI); + var fromBorderPoint = (edgeSegmentLength - fromBorderDist) / edgeSegmentLength; + var xFrom = (fromBorderPoint) * this.from.x + (1 - fromBorderPoint) * this.to.x; + var yFrom = (fromBorderPoint) * this.from.y + (1 - fromBorderPoint) * this.to.y; + + if (this.smooth == true) { + angle = Math.atan2((this.to.y - this.via.y), (this.to.x - this.via.x)); + dx = (this.to.x - this.via.x); + dy = (this.to.y - this.via.y); + edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); + } + var toBorderDist = this.to.distanceToBorder(ctx, angle); + var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength; + var xTo = (1 - toBorderPoint) * this.via.x + toBorderPoint * this.to.x; + var yTo = (1 - toBorderPoint) * this.via.y + toBorderPoint * this.to.y; - var lTo = this.to.distanceToBorder(ctx, angle); - var pTo = (lEdge - lTo) / lEdge; - var xTo = (1 - pTo) * this.from.x + pTo * this.to.x; - var yTo = (1 - pTo) * this.from.y + pTo * this.to.y; ctx.beginPath(); - ctx.moveTo(xFrom, yFrom); - ctx.lineTo(xTo, yTo); + ctx.moveTo(xFrom,yFrom); + if (this.smooth == true) { + ctx.quadraticCurveTo(this.via.x,this.via.y,xTo, yTo); + } + else { + ctx.lineTo(xTo, yTo); + } ctx.stroke(); // draw arrow at the end of the line - length = 10 + 5 * this.width; // TODO: make customizable? + length = 10 + 5 * this.width; ctx.arrow(xTo, yTo, angle, length); ctx.fill(); ctx.stroke(); @@ -532,12 +551,12 @@ Edge.prototype._drawArrow = function(ctx) { // draw circle var node = this.from; var x, y, arrow; - var radius = this.length / 4; + var radius = 0.25 * Math.max(100,this.length); if (!node.width) { node.resize(ctx); } if (node.width > node.height) { - x = node.x + node.width / 2; + x = node.x + node.width * 0.5; y = node.y - radius; arrow = { x: x, @@ -547,7 +566,7 @@ Edge.prototype._drawArrow = function(ctx) { } else { x = node.x + radius; - y = node.y - node.height / 2; + y = node.y - node.height * 0.5; arrow = { x: node.x, y: y, @@ -555,7 +574,6 @@ Edge.prototype._drawArrow = function(ctx) { }; } ctx.beginPath(); - // TODO: do not draw a circle, but an arc // TODO: similarly, for a line without arrows, draw to the border of the nodes instead of the center ctx.arc(x, y, radius, 0, 2 * Math.PI, false); ctx.stroke(); diff --git a/src/graph/Node.js b/src/graph/Node.js index 764db270..0535a639 100644 --- a/src/graph/Node.js +++ b/src/graph/Node.js @@ -315,7 +315,6 @@ Node.prototype.distanceToBorder = function (ctx, angle) { this.resize(ctx); } - //noinspection FallthroughInSwitchStatementJS switch (this.shape) { case 'circle': case 'dot': @@ -347,7 +346,6 @@ Node.prototype.distanceToBorder = function (ctx, angle) { } } - // TODO: implement calculation of distance to border for all shapes }; From ba081895aaaa090872d16336d72b1881e2a3c0bd Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Tue, 11 Feb 2014 17:57:30 +0100 Subject: [PATCH 46/52] Added smooth curve support to dashed lines (Only FIREFOX and CHROME!) --- src/graph/Edge.js | 79 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 62 insertions(+), 17 deletions(-) diff --git a/src/graph/Edge.js b/src/graph/Edge.js index 2468fd68..06281645 100644 --- a/src/graph/Edge.js +++ b/src/graph/Edge.js @@ -354,25 +354,70 @@ Edge.prototype._drawDashLine = function(ctx) { ctx.strokeStyle = this.color; ctx.lineWidth = this._getLineWidth(); - // draw dashed line - ctx.beginPath(); - ctx.lineCap = 'round'; - if (this.dash.altLength !== undefined) //If an alt dash value has been set add to the array this value - { - ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, - [this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]); - } - else if (this.dash.length !== undefined && this.dash.gap !== undefined) //If a dash and gap value has been set add to the array this value - { - ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, - [this.dash.length,this.dash.gap]); - } - else //If all else fails draw a line - { + // only firefox and chrome support this method, else we use the legacy one. + if (ctx.mozDash !== undefined || ctx.setLineDash !== undefined) { + ctx.beginPath(); ctx.moveTo(this.from.x, this.from.y); - ctx.lineTo(this.to.x, this.to.y); + + // configure the dash pattern + var pattern = [0]; + if (this.dash.length !== undefined && this.dash.gap !== undefined) { + pattern = [this.dash.length,this.dash.gap]; + } + else { + pattern = [5,5]; + } + + // set dash settings for chrome or firefox + if (typeof ctx.setLineDash !== 'undefined') { //Chrome + ctx.setLineDash(pattern); + ctx.lineDashOffset = 0; + + } else { //Firefox + ctx.mozDash = pattern; + ctx.mozDashOffset = 0; + } + + // draw the line + if (this.smooth == true) { + ctx.quadraticCurveTo(this.via.x,this.via.y,this.to.x, this.to.y); + } + else { + ctx.lineTo(this.to.x, this.to.y); + } + ctx.stroke(); + + // restore the dash settings. + if (typeof ctx.setLineDash !== 'undefined') { //Chrome + ctx.setLineDash([0]); + ctx.lineDashOffset = 0; + + } else { //Firefox + ctx.mozDash = [0]; + ctx.mozDashOffset = 0; + } + } + else { // unsupporting smooth lines + // draw dashed line + ctx.beginPath(); + ctx.lineCap = 'round'; + if (this.dash.altLength !== undefined) //If an alt dash value has been set add to the array this value + { + ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, + [this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]); + } + else if (this.dash.length !== undefined && this.dash.gap !== undefined) //If a dash and gap value has been set add to the array this value + { + ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, + [this.dash.length,this.dash.gap]); + } + else //If all else fails draw a line + { + ctx.moveTo(this.from.x, this.from.y); + ctx.lineTo(this.to.x, this.to.y); + } + ctx.stroke(); } - ctx.stroke(); // draw label if (this.label) { From 0bd417bdec72e2064a2b655ae59fe4d3dab8f95d Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Wed, 12 Feb 2014 17:12:59 +0100 Subject: [PATCH 47/52] finalized smooth edges and force calculation --- src/graph/Graph.js | 165 +++++------------- src/graph/Node.js | 18 +- src/graph/graphMixins/ClusterMixin.js | 1 + src/graph/graphMixins/physics/PhysicsMixin.js | 16 +- src/graph/graphMixins/physics/repulsion.js | 2 - 5 files changed, 55 insertions(+), 147 deletions(-) diff --git a/src/graph/Graph.js b/src/graph/Graph.js index e9110dfd..a9b43fb6 100644 --- a/src/graph/Graph.js +++ b/src/graph/Graph.js @@ -56,7 +56,7 @@ function Graph (container, data, options) { widthMax: 15, width: 1, style: 'line', - color: '#343434', + color: '#848484', fontColor: '#343434', fontSize: 14, // px fontFace: 'arial', @@ -71,16 +71,17 @@ function Graph (container, data, options) { physics: { barnesHut: { enabled: true, - theta: 1 / 0.3, // inverted to save time during calculation - gravitationalConstant: -7500, + theta: 1 / 0.5, // inverted to save time during calculation + gravitationalConstant: -3000, centralGravity: 0.9, - springLength: 25, - springConstant: 0.05 + springLength: 40, + springConstant: 0.04 }, repulsion: { centralGravity: 0.01, - springLength: 60, - springConstant: 0.05 + springLength: 80, + springConstant: 0.05, + nodeDistance: 100 }, centralGravity: null, springLength: null, @@ -99,7 +100,7 @@ function Graph (container, data, options) { forceAmplification: 0.1, // (multiplier PNiC) | factor of increase fo the repulsion force of a cluster (per node in cluster). maxFontSize: 1000, distanceAmplification: 0.1, // (multiplier PNiC) | factor how much the repulsion distance of a cluster increases (per node in cluster). - edgeGrowth: 1, // (px PNiC) | amount of clusterSize connected to the edge is multiplied with this and added to edgeLength. + edgeGrowth: 20, // (px PNiC) | amount of clusterSize connected to the edge is multiplied with this and added to edgeLength. nodeScaling: {width: 1, // (px PNiC) | growth of the width per node in cluster. height: 1, // (px PNiC) | growth of the height per node in cluster. radius: 1}, // (px PNiC) | growth of the radius per node in cluster. @@ -119,7 +120,7 @@ function Graph (container, data, options) { enabled: false }, smoothCurves: true, - maxVelocity: 35, + maxVelocity: 25, minVelocity: 0.1, // px/s maxIterations: 1000 // maximum number of iteration to stabilize }; @@ -172,9 +173,6 @@ function Graph (container, data, options) { this.areaCenter = {}; // object with x and y elements used for determining the center of the zoom action this.scale = 1; // defining the global scale variable in the constructor this.previousScale = this.scale; // this is used to check if the zoom operation is zooming in or out - // TODO: create a counter to keep track on the number of nodes having values - // TODO: create a counter to keep track on the number of nodes currently moving - // TODO: create a counter to keep track on the number of edges having values this.nodesData = null; // A DataSet or DataView this.edgesData = null; // A DataSet or DataView @@ -218,7 +216,7 @@ function Graph (container, data, options) { // load data (the disable start variable will be the same as the enabled clustering) this.setData(data,this.constants.clustering.enabled); - // zoom so all data will fit on the screen + // zoom so all data will fit on the screen, if clustering is enabled, we do not want start to be called here. this.zoomToFit(true,this.constants.clustering.enabled); // if clustering is disabled, the simulation will have started in the setData function @@ -274,9 +272,8 @@ Graph.prototype._getRange = function() { * @private */ Graph.prototype._findCenter = function(range) { - var center = {x: (0.5 * (range.maxX + range.minX)), - y: (0.5 * (range.maxY + range.minY))}; - return center; + return {x: (0.5 * (range.maxX + range.minX)), + y: (0.5 * (range.maxY + range.minY))}; }; @@ -309,14 +306,15 @@ Graph.prototype.zoomToFit = function(initialZoom, doNotStart) { var numberOfNodes = this.nodeIndices.length; var range = this._getRange(); + var zoomLevel; if (initialZoom == true) { if (this.constants.clustering.enabled == true && numberOfNodes >= this.constants.clustering.initialMaxNodes) { - var zoomLevel = 38.8467 / (numberOfNodes - 14.50184) + 0.0116; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. + zoomLevel = 38.8467 / (numberOfNodes - 14.50184) + 0.0116; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. } else { - var zoomLevel = 42.54117319 / (numberOfNodes + 39.31966387) + 0.1944405; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. + zoomLevel = 42.54117319 / (numberOfNodes + 39.31966387) + 0.1944405; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. } } else { @@ -411,6 +409,7 @@ Graph.prototype.setData = function(data, disableStart) { */ Graph.prototype.setOptions = function (options) { if (options) { + var prop; // retrieve parameter values if (options.width !== undefined) {this.width = options.width;} if (options.height !== undefined) {this.height = options.height;} @@ -420,7 +419,7 @@ Graph.prototype.setOptions = function (options) { if (options.physics) { if (options.physics.barnesHut) { this.constants.physics.barnesHut.enabled = true; - for (var prop in options.physics.barnesHut) { + for (prop in options.physics.barnesHut) { if (options.physics.barnesHut.hasOwnProperty(prop)) { this.constants.physics.barnesHut[prop] = options.physics.barnesHut[prop]; } @@ -429,7 +428,7 @@ Graph.prototype.setOptions = function (options) { if (options.physics.repulsion) { this.constants.physics.barnesHut.enabled = false; - for (var prop in options.physics.repulsion) { + for (prop in options.physics.repulsion) { if (options.physics.repulsion.hasOwnProperty(prop)) { this.constants.physics.repulsion[prop] = options.physics.repulsion[prop]; } @@ -439,7 +438,7 @@ Graph.prototype.setOptions = function (options) { if (options.clustering) { this.constants.clustering.enabled = true; - for (var prop in options.clustering) { + for (prop in options.clustering) { if (options.clustering.hasOwnProperty(prop)) { this.constants.clustering[prop] = options.clustering[prop]; } @@ -451,7 +450,7 @@ Graph.prototype.setOptions = function (options) { if (options.navigation) { this.constants.navigation.enabled = true; - for (var prop in options.navigation) { + for (prop in options.navigation) { if (options.navigation.hasOwnProperty(prop)) { this.constants.navigation[prop] = options.navigation[prop]; } @@ -463,7 +462,7 @@ Graph.prototype.setOptions = function (options) { if (options.keyboard) { this.constants.keyboard.enabled = true; - for (var prop in options.keyboard) { + for (prop in options.keyboard) { if (options.keyboard.hasOwnProperty(prop)) { this.constants.keyboard[prop] = options.keyboard[prop]; } @@ -475,7 +474,7 @@ Graph.prototype.setOptions = function (options) { if (options.dataManipulationToolbar) { this.constants.dataManipulationToolbar.enabled = true; - for (var prop in options.dataManipulationToolbar) { + for (prop in options.dataManipulationToolbar) { if (options.dataManipulationToolbar.hasOwnProperty(prop)) { this.constants.dataManipulationToolbar[prop] = options.dataManipulationToolbar[prop]; } @@ -493,12 +492,6 @@ Graph.prototype.setOptions = function (options) { } } - if (options.edges.length !== undefined && - options.nodes && options.nodes.distance === undefined) { - this.constants.edges.length = options.edges.length; - this.constants.nodes.distance = options.edges.length * 1.25; - } - if (!options.edges.fontColor) { this.constants.edges.fontColor = options.edges.color; } @@ -873,7 +866,6 @@ Graph.prototype._onHold = function (event) { /** * handle the release of the screen * - * @param event * @private */ Graph.prototype._onRelease = function (event) { @@ -973,7 +965,7 @@ Graph.prototype._onMouseWheel = function(event) { var pointer = this._getPointer(gesture.center); // apply the new scale - scale = this._zoom(scale, pointer); + this._zoom(scale, pointer); // store the new, applied scale -- this is now done in _zoom // this.pinch.mousewheelScale = scale; @@ -1099,85 +1091,6 @@ Graph.prototype._checkHidePopup = function (pointer) { }; -/** - * Temporary method to test calculating a hub value for the nodes - * @param {number} level Maximum number edges between two nodes in order - * to call them connected. Optional, 1 by default - * @return {Number[]} connectioncount array with the connection count - * for each node - * @private - */ -Graph.prototype._getConnectionCount = function(level) { - if (level == undefined) { - level = 1; - } - - // get the nodes connected to given nodes - function getConnectedNodes(nodes) { - var connectedNodes = []; - - for (var j = 0, jMax = nodes.length; j < jMax; j++) { - var node = nodes[j]; - - // find all nodes connected to this node - var edges = node.edges; - for (var i = 0, iMax = edges.length; i < iMax; i++) { - var edge = edges[i]; - var other = null; - - // check if connected - if (edge.from == node) - other = edge.to; - else if (edge.to == node) - other = edge.from; - - // check if the other node is not already in the list with nodes - var k, kMax; - if (other) { - for (k = 0, kMax = nodes.length; k < kMax; k++) { - if (nodes[k] == other) { - other = null; - break; - } - } - } - if (other) { - for (k = 0, kMax = connectedNodes.length; k < kMax; k++) { - if (connectedNodes[k] == other) { - other = null; - break; - } - } - } - - if (other) - connectedNodes.push(other); - } - } - - return connectedNodes; - } - - var connections = []; - var nodes = this.nodes; - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - var c = [nodes[id]]; - for (var l = 0; l < level; l++) { - c = c.concat(getConnectedNodes(c)); - } - connections.push(c); - } - } - - var hubs = []; - for (var i = 0, len = connections.length; i < len; i++) { - hubs.push(connections[i].length); - } - - return hubs; -}; - /** * Set a new size for the graph * @param {string} width Width in pixels or percentage (for example '800px' @@ -1264,7 +1177,7 @@ Graph.prototype._addNodes = function(ids) { this.nodes[id] = node; // note: this may replace an existing node if ((node.xFixed == false || node.yFixed == false) && this.createNodeOnClick != true) { - var radius = this.constants.physics.springLength * 0.1*ids.length; + var radius = this.constants.physics.springLength * 0.2*ids.length; var angle = 2 * Math.PI * Math.random(); if (node.xFixed == false) {node.x = radius * Math.cos(angle);} if (node.yFixed == false) {node.y = radius * Math.sin(angle);} @@ -1400,6 +1313,7 @@ Graph.prototype._addEdges = function (ids) { this.moving = true; this._updateValueRange(edges); this._createBezierNodes(); + this._setCalculationNodes(); }; /** @@ -1757,24 +1671,24 @@ Graph.prototype._isMoving = function(vmin) { * /** * Perform one discrete step for all nodes * - * @param interval * @private */ Graph.prototype._discreteStepNodes = function() { var interval = 1.0; var nodes = this.nodes; + var nodeId; if (this.constants.maxVelocity > 0) { - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - nodes[id].discreteStepLimited(interval, this.constants.maxVelocity); + for (nodeId in nodes) { + if (nodes.hasOwnProperty(nodeId)) { + nodes[nodeId].discreteStepLimited(interval, this.constants.maxVelocity); } } } else { - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - nodes[id].discreteStep(interval); + for (nodeId in nodes) { + if (nodes.hasOwnProperty(nodeId)) { + nodes[nodeId].discreteStep(interval); } } } @@ -1799,10 +1713,10 @@ Graph.prototype.start = function() { if (this.moving) { this._doInAllActiveSectors("_initializeForceCalculation"); - this._doInAllActiveSectors("_discreteStepNodes"); if (this.constants.smoothCurves) { this._doInSupportSector("_discreteStepNodes"); } + this._doInAllActiveSectors("_discreteStepNodes"); this._findCenter(this._getRange()) } @@ -1830,16 +1744,15 @@ Graph.prototype.start = function() { graph.start(); graph.start(); - // var calctime = Date.now() - calctimeStart; // var rendertimeStart = Date.now(); graph._redraw(); // var rendertime = Date.now() - rendertimeStart; - //this.end = window.performance.now(); - //this.time = this.end - this.startTime; - //console.log('refresh time: ' + this.time); - //this.startTime = window.performance.now(); +// this.end = window.performance.now(); +// this.time = this.end - this.startTime; +// console.log('refresh time: ' + this.time); +// this.startTime = window.performance.now(); // var DOMelement = document.getElementById("calctimereporter"); // if (DOMelement !== undefined) { // DOMelement.innerHTML = calctime; @@ -1900,7 +1813,7 @@ Graph.prototype._createBezierNodes = function() { mass:1, shape:'circle', internalMultiplier:1, - damping: 1},{},{},this.constants); + damping: 1.2},{},{},this.constants); edge.via = this.sectors['support']['nodes'][nodeId]; edge.via.parentEdgeId = edge.id; edge.positionBezierNode(); diff --git a/src/graph/Node.js b/src/graph/Node.js index 0535a639..e36d427d 100644 --- a/src/graph/Node.js +++ b/src/graph/Node.js @@ -52,7 +52,6 @@ function Node(properties, imagelist, grouplist, constants) { this.radiusFixed = false; this.radiusMin = constants.nodes.radiusMin; this.radiusMax = constants.nodes.radiusMax; - this.internalMultiplier = 1; this.imagelist = imagelist; @@ -376,15 +375,15 @@ Node.prototype._addForce = function(fx, fy) { */ Node.prototype.discreteStep = function(interval) { if (!this.xFixed) { - var dx = -this.damping * this.vx; // damping force - var ax = (this.fx + dx) / this.mass; // acceleration + var dx = this.damping * this.vx; // damping force + var ax = (this.fx - dx) / this.mass; // acceleration this.vx += ax * interval; // velocity this.x += this.vx * interval; // position } if (!this.yFixed) { - var dy = -this.damping * this.vy; // damping force - var ay = (this.fy + dy) / this.mass; // acceleration + var dy = this.damping * this.vy; // damping force + var ay = (this.fy - dy) / this.mass; // acceleration this.vy += ay * interval; // velocity this.y += this.vy * interval; // position } @@ -398,16 +397,16 @@ Node.prototype.discreteStep = function(interval) { */ Node.prototype.discreteStepLimited = function(interval, maxVelocity) { if (!this.xFixed) { - var dx = -this.damping * this.vx; // damping force - var ax = (this.fx + dx) / this.mass; // acceleration + var dx = this.damping * this.vx; // damping force + var ax = (this.fx - dx) / this.mass; // acceleration this.vx += ax * interval; // velocity this.vx = (Math.abs(this.vx) > maxVelocity) ? ((this.vx > 0) ? maxVelocity : -maxVelocity) : this.vx; this.x += this.vx * interval; // position } if (!this.yFixed) { - var dy = -this.damping * this.vy; // damping force - var ay = (this.fy + dy) / this.mass; // acceleration + var dy = this.damping * this.vy; // damping force + var ay = (this.fy - dy) / this.mass; // acceleration this.vy += ay * interval; // velocity this.vy = (Math.abs(this.vy) > maxVelocity) ? ((this.vy > 0) ? maxVelocity : -maxVelocity) : this.vy; this.y += this.vy * interval; // position @@ -435,7 +434,6 @@ Node.prototype.isMoving = function(vmin) { return true; } else { - this.vx = 0; this.vy = 0; return false; } //return (Math.abs(this.vx) > vmin || Math.abs(this.vy) > vmin); diff --git a/src/graph/graphMixins/ClusterMixin.js b/src/graph/graphMixins/ClusterMixin.js index 74f825b3..b84dd84f 100644 --- a/src/graph/graphMixins/ClusterMixin.js +++ b/src/graph/graphMixins/ClusterMixin.js @@ -1048,6 +1048,7 @@ var ClusterMixin = { var angle = 2 * Math.PI * Math.random(); if (node.xFixed == false) {node.x = radius * Math.cos(angle);} if (node.yFixed == false) {node.y = radius * Math.sin(angle);} + this._repositionBezierNodes(node); } } }, diff --git a/src/graph/graphMixins/physics/PhysicsMixin.js b/src/graph/graphMixins/physics/PhysicsMixin.js index 3608ab20..4fb4284a 100644 --- a/src/graph/graphMixins/physics/PhysicsMixin.js +++ b/src/graph/graphMixins/physics/PhysicsMixin.js @@ -50,10 +50,8 @@ var physicsMixin = { // Gravity is required to keep separated groups from floating off // the forces are reset to zero in this loop by using _setForce instead // of _addForce - this._setCalculationNodes(); this._calculateGravitationalForces(); - this._calculateNodeForces(); @@ -158,7 +156,7 @@ var physicsMixin = { if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { edgeLength = edge.length; // this implies that the edges between big clusters are longer - edgeLength += (edge.to.growthIndicator + edge.from.growthIndicator) * this.constants.clustering.edgeGrowth; + edgeLength += (edge.to.clusterSize + edge.from.clusterSize - 2) * this.constants.clustering.edgeGrowth; this._calculateSpringForce(edge.from,edge.to,edgeLength); } } @@ -173,7 +171,7 @@ var physicsMixin = { * @private */ _calculateSpringForcesWithSupport : function() { - var edgeLength, edge, edgeId, growthIndicator; + var edgeLength, edge, edgeId, combinedClusterSize; var edges = this.edges; // forces caused by the edges, modelled as springs @@ -188,14 +186,14 @@ var physicsMixin = { var node2 = edge.via; var node3 = edge.from; - edgeLength = 0.5*edge.length; + edgeLength = edge.length; - growthIndicator = 0.5*(node1.growthIndicator + node3.growthIndicator); + combinedClusterSize = node1.clusterSize + node3.clusterSize - 2; // this implies that the edges between big clusters are longer - edgeLength += growthIndicator * this.constants.clustering.edgeGrowth; - this._calculateSpringForce(node1,node2,edgeLength); - this._calculateSpringForce(node2,node3,edgeLength); + edgeLength += combinedClusterSize * this.constants.clustering.edgeGrowth; + this._calculateSpringForce(node1,node2,0.5*edgeLength); + this._calculateSpringForce(node2,node3,0.5*edgeLength); } } } diff --git a/src/graph/graphMixins/physics/repulsion.js b/src/graph/graphMixins/physics/repulsion.js index 8bc9895e..8df7236f 100644 --- a/src/graph/graphMixins/physics/repulsion.js +++ b/src/graph/graphMixins/physics/repulsion.js @@ -49,12 +49,10 @@ var repulsionMixin = { } if (this.sectors['support']['nodes'].hasOwnProperty(node1.id)) { - // console.log(combinedClusterSize, repulsingForce, minimumDistance); } // amplify the repulsion for clusters. repulsingForce *= (combinedClusterSize == 0) ? 1 : 1 + combinedClusterSize * this.constants.clustering.forceAmplification; - repulsingForce *= node1.internalMultiplier * node2.internalMultiplier; fx = Math.cos(angle) * repulsingForce; fy = Math.sin(angle) * repulsingForce; From d3506a82b3876223ff4f3ff2769e6b41cd2a8367 Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Thu, 13 Feb 2014 17:58:04 +0100 Subject: [PATCH 48/52] refactoring, altered data manipulation, added callbacks and triggers, inserted temporary function overloading --- examples/graph/02_random_nodes.html | 1 - examples/graph/21_data_manipulation.html | 31 +- examples/graph/index.html | 1 + src/graph/Edge.js | 60 ++- src/graph/Graph.js | 121 ++--- src/graph/Node.js | 33 +- src/graph/graphMixins/ManipulationMixin.js | 565 +++++++++------------ src/graph/graphMixins/MixinLoader.js | 15 + src/graph/graphMixins/SelectionMixin.js | 19 +- src/graph/graphMixins/physics/repulsion.js | 6 +- src/util.js | 4 + 11 files changed, 439 insertions(+), 417 deletions(-) diff --git a/examples/graph/02_random_nodes.html b/examples/graph/02_random_nodes.html index e7ed640d..ee648bbc 100755 --- a/examples/graph/02_random_nodes.html +++ b/examples/graph/02_random_nodes.html @@ -88,7 +88,6 @@ */ var options = { edges: { - }, stabilize: false }; diff --git a/examples/graph/21_data_manipulation.html b/examples/graph/21_data_manipulation.html index 4b7236bf..1ea7694e 100644 --- a/examples/graph/21_data_manipulation.html +++ b/examples/graph/21_data_manipulation.html @@ -38,13 +38,14 @@ border-style:solid; border-color: #d6d9d8; background: #ffffff; /* Old browsers */ - background: -moz-linear-gradient(top, #ffffff 0%, #f3f3f3 50%, #ededed 51%, #ffffff 100%); /* FF3.6+ */ - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(50%,#f3f3f3), color-stop(51%,#ededed), color-stop(100%,#ffffff)); /* Chrome,Safari4+ */ - background: -webkit-linear-gradient(top, #ffffff 0%,#f3f3f3 50%,#ededed 51%,#ffffff 100%); /* Chrome10+,Safari5.1+ */ - background: -o-linear-gradient(top, #ffffff 0%,#f3f3f3 50%,#ededed 51%,#ffffff 100%); /* Opera 11.10+ */ - background: -ms-linear-gradient(top, #ffffff 0%,#f3f3f3 50%,#ededed 51%,#ffffff 100%); /* IE10+ */ - background: linear-gradient(to bottom, #ffffff 0%,#f3f3f3 50%,#ededed 51%,#ffffff 100%); /* W3C */ - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#ffffff',GradientType=0 ); /* IE6-9 */ + background: -moz-linear-gradient(top, #ffffff 0%, #fcfcfc 48%, #fafafa 50%, #fcfcfc 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(48%,#fcfcfc), color-stop(50%,#fafafa), color-stop(100%,#fcfcfc)); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, #ffffff 0%,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(top, #ffffff 0%,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%); /* Opera 11.10+ */ + background: -ms-linear-gradient(top, #ffffff 0%,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%); /* IE10+ */ + background: linear-gradient(to bottom, #ffffff 0%,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%); /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#fcfcfc',GradientType=0 ); /* IE6-9 */ + width: 600px; height:30px; z-index:10; @@ -223,7 +224,21 @@ clustering:false, navigation: true, keyboard: true, - dataManipulationToolbar: true + dataManipulationToolbar: true, + triggerFunctions: {add: function(data,callback) { + data.label = "hello"; + callback(data); + }, + edit: function(data,callback) { + data.label='edited' + callback(data); + }, + edit: function(data,callback) { + data.label='edited' + callback(data); + } + } + }; graph = new vis.Graph(container, data, options); diff --git a/examples/graph/index.html b/examples/graph/index.html index 53720b5b..4b38888d 100644 --- a/examples/graph/index.html +++ b/examples/graph/index.html @@ -33,6 +33,7 @@

    19_scale_free_graph_clustering.html

    20_navigation.html

    21_data_manipulation.html

    +

    22_les_miserables.html

    graphviz_gallery.html

    diff --git a/src/graph/Edge.js b/src/graph/Edge.js index 06281645..ba5aa6da 100644 --- a/src/graph/Edge.js +++ b/src/graph/Edge.js @@ -212,8 +212,7 @@ Edge.prototype.isOverlappingWith = function(obj) { var xObj = obj.left; var yObj = obj.top; - - var dist = Edge._dist(xFrom, yFrom, xTo, yTo, xObj, yObj); + var dist = this._getDistanceToEdge(xFrom, yFrom, xTo, yTo, xObj, yObj); return (dist < distMax); }; @@ -651,31 +650,46 @@ Edge.prototype._drawArrow = function(ctx) { * @param {number} y3 * @private */ -Edge._dist = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point - var px = x2-x1, - py = y2-y1, - something = px*px + py*py, - u = ((x3 - x1) * px + (y3 - y1) * py) / something; - - if (u > 1) { - u = 1; - } - else if (u < 0) { - u = 0; +Edge.prototype._getDistanceToEdge = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point + if (this.smooth == true) { + var minDistance = 1e9; + var i,t,x,y,dx,dy; + for (i = 0; i < 10; i++) { + t = 0.1*i; + x = Math.pow(1-t,2)*x1 + (2*t*(1 - t))*this.via.x + Math.pow(t,2)*x2; + y = Math.pow(1-t,2)*y1 + (2*t*(1 - t))*this.via.y + Math.pow(t,2)*y2; + dx = Math.abs(x3-x); + dy = Math.abs(y3-y); + minDistance = Math.min(minDistance,Math.sqrt(dx*dx + dy*dy)); + } + return minDistance } + else { + var px = x2-x1, + py = y2-y1, + something = px*px + py*py, + u = ((x3 - x1) * px + (y3 - y1) * py) / something; - var x = x1 + u * px, - y = y1 + u * py, - dx = x - x3, - dy = y - y3; + if (u > 1) { + u = 1; + } + else if (u < 0) { + u = 0; + } - //# Note: If the actual distance does not matter, - //# if you only want to compare what this function - //# returns to other results of this function, you - //# can just return the squared distance instead - //# (i.e. remove the sqrt) to gain a little performance + var x = x1 + u * px, + y = y1 + u * py, + dx = x - x3, + dy = y - y3; - return Math.sqrt(dx*dx + dy*dy); + //# Note: If the actual distance does not matter, + //# if you only want to compare what this function + //# returns to other results of this function, you + //# can just return the squared distance instead + //# (i.e. remove the sqrt) to gain a little performance + + return Math.sqrt(dx*dx + dy*dy); + } }; diff --git a/src/graph/Graph.js b/src/graph/Graph.js index a9b43fb6..bbfff971 100644 --- a/src/graph/Graph.js +++ b/src/graph/Graph.js @@ -22,6 +22,8 @@ function Graph (container, data, options) { this.renderTimestep = 1000 / this.renderRefreshRate; // ms -- saves calculation later on this.stabilize = true; // stabilize before displaying the graph this.selectable = true; + // these functions can be triggered when the dataset is edited + this.triggerFunctions = {add:null,edit:null,connect:null,delete:null}; // set constant values this.constants = { @@ -29,7 +31,6 @@ function Graph (container, data, options) { radiusMin: 5, radiusMax: 20, radius: 5, - distance: 100, // px shape: 'ellipse', image: undefined, widthMin: 16, // px @@ -117,13 +118,15 @@ function Graph (container, data, options) { speed: {x: 10, y: 10, zoom: 0.02} }, dataManipulationToolbar: { - enabled: false + enabled: false, + initiallyVisible: false }, smoothCurves: true, maxVelocity: 25, minVelocity: 0.1, // px/s maxIterations: 1000 // maximum number of iteration to stabilize }; + this.editMode = this.constants.dataManipulationToolbar.initiallyVisible; // Node variables this.groups = new Groups(); // object with groups @@ -158,7 +161,7 @@ function Graph (container, data, options) { // other vars var graph = this; this.freezeSimulation = false;// freeze the simulation - + this.cachedFunctions = {}; this.calculationNodes = {}; this.calculationNodeIndices = []; @@ -416,6 +419,12 @@ Graph.prototype.setOptions = function (options) { if (options.stabilize !== undefined) {this.stabilize = options.stabilize;} if (options.selectable !== undefined) {this.selectable = options.selectable;} + if (options.triggerFunctions) { + for (prop in options.triggerFunctions) { + this.triggerFunctions[prop] = options.triggerFunctions[prop]; + } + } + if (options.physics) { if (options.physics.barnesHut) { this.constants.physics.barnesHut.enabled = true; @@ -553,6 +562,7 @@ Graph.prototype.setOptions = function (options) { this.setSize(this.width, this.height); this._setTranslation(this.frame.clientWidth / 2, this.frame.clientHeight / 2); this._setScale(1); + this.zoomToFit() this._redraw(); }; @@ -687,6 +697,8 @@ Graph.prototype._createKeyBinds = function() { if (this.constants.dataManipulationToolbar.enabled == true) { this.mousetrap.bind("escape",this._createManipulatorBar.bind(me)); + this.mousetrap.bind("del",this._deleteSelected.bind(me)); + this.mousetrap.bind("e",this._toggleEditMode.bind(me)); } } @@ -721,6 +733,11 @@ Graph.prototype._onTouch = function (event) { * @private */ Graph.prototype._onDragStart = function () { + this._handleDragStart(); +}; + + +Graph.prototype._handleDragStart = function() { var drag = this.drag; var node = this._getNodeAt(drag.pointer); // note: drag.pointer is set in _onTouch to get the initial touch location @@ -761,13 +778,18 @@ Graph.prototype._onDragStart = function () { } } } -}; +} + /** * handle drag event * @private */ Graph.prototype._onDrag = function (event) { + this._handleOnDrag(event) +}; + +Graph.prototype._handleOnDrag = function(event) { if (this.drag.pinched) { return; } @@ -775,12 +797,12 @@ Graph.prototype._onDrag = function (event) { var pointer = this._getPointer(event.gesture.touches[0]); var me = this, - drag = this.drag, - selection = drag.selection; + drag = this.drag, + selection = drag.selection; if (selection && selection.length) { // calculate delta's and new location var deltaX = pointer.x - drag.pointer.x, - deltaY = pointer.y - drag.pointer.y; + deltaY = pointer.y - drag.pointer.y; // update position of all selected nodes selection.forEach(function (s) { @@ -807,12 +829,12 @@ Graph.prototype._onDrag = function (event) { var diffY = pointer.y - this.drag.pointer.y; this._setTranslation( - this.drag.translation.x + diffX, - this.drag.translation.y + diffY); + this.drag.translation.x + diffX, + this.drag.translation.y + diffY); this._redraw(); this.moved = true; } -}; +} /** * handle drag start event @@ -869,7 +891,8 @@ Graph.prototype._onHold = function (event) { * @private */ Graph.prototype._onRelease = function (event) { - this._handleOnRelease(); + var pointer = this._getPointer(event.gesture.touches[0]); + this._handleOnRelease(pointer); }; /** @@ -1188,6 +1211,7 @@ Graph.prototype._addNodes = function(ids) { } } this._updateNodeIndexList(); + this._setCalculationNodes() this._reconnectEdges(); this._updateValueRange(this.nodes); this.updateLabels(); @@ -1710,7 +1734,6 @@ Graph.prototype._discreteStepNodes = function() { */ Graph.prototype.start = function() { if (!this.freezeSimulation) { - if (this.moving) { this._doInAllActiveSectors("_initializeForceCalculation"); if (this.constants.smoothCurves) { @@ -1719,55 +1742,39 @@ Graph.prototype.start = function() { this._doInAllActiveSectors("_discreteStepNodes"); this._findCenter(this._getRange()) } + } - if (this.moving || this.xIncrement != 0 || this.yIncrement != 0 || this.zoomIncrement != 0) { - // start animation. only start calculationTimer if it is not already running - if (!this.timer) { - var graph = this; - this.timer = window.setTimeout(function () { - graph.timer = undefined; - - // keyboad movement - if (graph.xIncrement != 0 || graph.yIncrement != 0) { - var translation = graph._getTranslation(); - graph._setTranslation(translation.x+graph.xIncrement, translation.y+graph.yIncrement); - } - if (graph.zoomIncrement != 0) { - var center = { - x: graph.frame.canvas.clientWidth / 2, - y: graph.frame.canvas.clientHeight / 2 - }; - graph._zoom(graph.scale*(1 + graph.zoomIncrement), center); - } + if (this.moving || this.xIncrement != 0 || this.yIncrement != 0 || this.zoomIncrement != 0) { + // start animation. only start calculationTimer if it is not already running + if (!this.timer) { + var graph = this; + this.timer = window.setTimeout(function () { + graph.timer = undefined; -// var calctimeStart = Date.now(); - - graph.start(); - graph.start(); -// var calctime = Date.now() - calctimeStart; -// var rendertimeStart = Date.now(); - graph._redraw(); -// var rendertime = Date.now() - rendertimeStart; - -// this.end = window.performance.now(); -// this.time = this.end - this.startTime; -// console.log('refresh time: ' + this.time); -// this.startTime = window.performance.now(); -// var DOMelement = document.getElementById("calctimereporter"); -// if (DOMelement !== undefined) { -// DOMelement.innerHTML = calctime; -// } -// DOMelement = document.getElementById("rendertimereporter"); -// if (DOMelement !== undefined) { -// DOMelement.innerHTML = rendertime; -// } - }, this.renderTimestep); - } - } - else { - this._redraw(); + // keyboad movement + if (graph.xIncrement != 0 || graph.yIncrement != 0) { + var translation = graph._getTranslation(); + graph._setTranslation(translation.x+graph.xIncrement, translation.y+graph.yIncrement); + } + if (graph.zoomIncrement != 0) { + var center = { + x: graph.frame.canvas.clientWidth / 2, + y: graph.frame.canvas.clientHeight / 2 + }; + graph._zoom(graph.scale*(1 + graph.zoomIncrement), center); + } + + + graph.start(); + graph.start(); + graph._redraw(); + + }, this.renderTimestep); } } + else { + this._redraw(); + } }; /** diff --git a/src/graph/Node.js b/src/graph/Node.js index e36d427d..ba86acde 100644 --- a/src/graph/Node.js +++ b/src/graph/Node.js @@ -228,15 +228,32 @@ Node.prototype.setProperties = function(properties, constants) { Node.parseColor = function(color) { var c; if (util.isString(color)) { - c = { - border: color, - background: color, - highlight: { + if (util.isValidHex(color)) { + var hsv = util.hexToHSV(color); + var lighterColorHSV = {h:hsv.h,s:hsv.s * 0.45,v:Math.min(1,hsv.v * 1.05)}; + var darkerColorHSV = {h:hsv.h,s:Math.min(1,hsv.v * 1.25),v:hsv.v*0.6}; + var darkerColorHex = util.HSVToHex(darkerColorHSV.h ,darkerColorHSV.h ,darkerColorHSV.v); + var lighterColorHex = util.HSVToHex(lighterColorHSV.h,lighterColorHSV.s,lighterColorHSV.v); + + c = { border: color, - background: color - } - }; - // TODO: automatically generate a nice highlight color + border:darkerColorHex, + highlight: { + background:lighterColorHex, + border:darkerColorHex + } + }; + } + else { + c = { + border:color, + border:color, + highlight: { + background:color, + border:color + } + }; + } } else { c = {}; diff --git a/src/graph/graphMixins/ManipulationMixin.js b/src/graph/graphMixins/ManipulationMixin.js index 9bc261bb..7e734f68 100644 --- a/src/graph/graphMixins/ManipulationMixin.js +++ b/src/graph/graphMixins/ManipulationMixin.js @@ -16,203 +16,94 @@ var manipulationMixin = { }, - /** - * main function, creates the main toolbar. Removes functions bound to the select event. Binds all the buttons of the toolbar. - * - * @private - */ - _createManipulatorBar : function() { - // remove bound functions - this.off('select', this.boundFunction); + _restoreOverloadedFunctions : function() { + for (var functionName in this.cachedFunctions) { + if (this.cachedFunctions.hasOwnProperty(functionName)) { + this[functionName] = this.cachedFunctions[functionName]; + } + } + }, - // reset global variables - this.blockConnectingEdgeSelection = false; - this.forceAppendSelection = false - while (this.manipulationDiv.hasChildNodes()) { - this.manipulationDiv.removeChild(this.manipulationDiv.firstChild); + _toggleEditMode : function() { + this.editMode = !this.editMode; + var toolbar = document.getElementById("graph-manipulationDiv") + if (this.editMode == true) { + toolbar.style.display="block"; } - // add the icons to the manipulator div - this.manipulationDiv.innerHTML = "" + - "Add Node" + - "
    " + - "Edit Selected" + - "
    " + - "Connect Node" + - "
    " + - "Delete selected"; - - // bind the icons - var addButton = document.getElementById("manipulate-addNode"); - addButton.onclick = this._createAddToolbar.bind(this); - var editButton = document.getElementById("manipulate-editNode"); - editButton.onclick = this._createEditToolbar.bind(this); - var connectButton = document.getElementById("manipulate-connectNode"); - connectButton.onclick = this._createConnectToolbar.bind(this); - var deleteButton = document.getElementById("manipulate-delete"); - deleteButton.onclick = this._createDeletionToolbar.bind(this); + else { + toolbar.style.display="none"; + } + this._createManipulatorBar() }, - /** - * Create the toolbar for adding Nodes + * main function, creates the main toolbar. Removes functions bound to the select event. Binds all the buttons of the toolbar. * * @private */ - _createAddToolbar : function() { - // clear the toolbar - this._clearManipulatorBar(); + _createManipulatorBar : function() { + // remove bound functions this.off('select', this.boundFunction); - // create the toolbar contents - this.manipulationDiv.innerHTML = "" + - "Back" + - "
    " + - "Click in an empty space to place a new node"; - - // bind the icon - var backButton = document.getElementById("manipulate-back"); - backButton.onclick = this._createManipulatorBar.bind(this); - - // we use the boundFunction so we can reference it when we unbind it from the "select" event. - this.boundFunction = this._addNode.bind(this); - this.on('select', this.boundFunction); - }, + // restore overloaded functions + this._restoreOverloadedFunctions(); + // resume calculation + this.freezeSimulation = false; - /** - * Create the toolbar to edit nodes or edges. - * TODO: edges not implemented yet, unsure what to edit. - * - * @private - */ - _createEditToolbar : function() { - // clear the toolbar + // reset global variables this.blockConnectingEdgeSelection = false; - this._clearManipulatorBar(); - this.off('select', this.boundFunction); - + this.forceAppendSelection = false - var message = ""; - if (this._selectionIsEmpty()) { - message = "Select a node or edge to edit."; - } - else { - if (this._getSelectedObjectCount() > 1) { - message = "Select a single node or edge to edit." - this._unselectAll(true); + if (this.editMode == true) { + while (this.manipulationDiv.hasChildNodes()) { + this.manipulationDiv.removeChild(this.manipulationDiv.firstChild); } - else { - if (this._clusterInSelection()) { - message = "You cannot edit a cluster." - this._unselectAll(true); - } - else { - if (this._getSelectedNodeCount() > 0) { // the selected item is a node - this._createEditNodeToolbar(); - } - else { // the selected item is an edge - this._createEditEdgeToolbar(); - } - } - } - } - - if (message != "") { - this.blockConnectingEdgeSelection = true; - // create the toolbar contents + // add the icons to the manipulator div this.manipulationDiv.innerHTML = "" + - "Back" + + "Add Node" + "
    " + - ""+message+""; + "Add Link"; + if (this._getSelectedNodeCount() == 1 && this.triggerFunctions.edit) { + this.manipulationDiv.innerHTML += "" + + "
    " + + "Edit Node"; + } + if (this._selectionIsEmpty() == false) { + this.manipulationDiv.innerHTML += "" + + "
    " + + "Delete selected"; + } - // bind the icon - var backButton = document.getElementById("manipulate-back"); - backButton.onclick = this._createManipulatorBar.bind(this); - // we use the boundFunction so we can reference it when we unbind it from the "select" event. - this.boundFunction = this._createEditToolbar.bind(this); + // bind the icons + var addNodeButton = document.getElementById("manipulate-addNode"); + addNodeButton.onclick = this._createAddNodeToolbar.bind(this); + var addEdgeButton = document.getElementById("manipulate-connectNode"); + addEdgeButton.onclick = this._createAddEdgeToolbar.bind(this); + if (this._getSelectedNodeCount() == 1 && this.triggerFunctions.edit) { + var editButton = document.getElementById("manipulate-editNode"); + editButton.onclick = this._editNode.bind(this); + } + if (this._selectionIsEmpty() == false) { + var deleteButton = document.getElementById("manipulate-delete"); + deleteButton.onclick = this._deleteSelected.bind(this); + } + this.boundFunction = this._createManipulatorBar.bind(this); this.on('select', this.boundFunction); } }, - /** - * Create the toolbar to edit the selected node. The label and the color can be changed. Other colors are derived from the chosen color. - * TODO: change shape or group? - * - * @private - */ - _createEditNodeToolbar : function() { - // clear the toolbar - this.blockConnectingEdgeSelection = false; - this._clearManipulatorBar(); - this.off('select', this.boundFunction); - - var editObject = this._getEditObject(); - - // create the toolbar contents - this.manipulationDiv.innerHTML = "" + - "Cancel" + - "
    " + - "label: " + - "
    " + - "color: " + - "
    " + - "" - - // bind the icon - var backButton = document.getElementById("manipulate-back"); - backButton.onclick = this._createManipulatorBar.bind(this); - var saveButton = document.getElementById("manipulator-obj-save"); - saveButton.onclick = this._saveNodeData.bind(this); - - // we use the boundFunction so we can reference it when we unbind it from the "select" event. - this.boundFunction = this._createManipulatorBar.bind(this); - this.on('select', this.boundFunction); - }, - - - /** - * save the changes in the node data - * - * @private - */ - _saveNodeData : function() { - var editObjectId = this._getEditObject().id; - var label = document.getElementById('manipulator-obj-label').value; - - var definedColor = document.getElementById('manipulator-obj-color').value; - var hsv = util.hexToHSV(definedColor); - - var lighterColorHSV = {h:hsv.h,s:hsv.s * 0.45,v:Math.min(1,hsv.v * 1.05)}; - var darkerColorHSV = {h:hsv.h,s:Math.min(1,hsv.v * 1.25),v:hsv.v*0.6}; - var darkerColorHex = util.HSVToHex(darkerColorHSV.h ,darkerColorHSV.h ,darkerColorHSV.v); - var lighterColorHex = util.HSVToHex(lighterColorHSV.h,lighterColorHSV.s,lighterColorHSV.v); - - var updatedSettings = {id:editObjectId, - label: label, - color: { - background:definedColor, - border:darkerColorHex, - highlight: { - background:lighterColorHex, - border:darkerColorHex - } - }}; - this.nodesData.update(updatedSettings); - this._createManipulatorBar(); - }, - /** - * creating the toolbar to edit edges. + * Create the toolbar for adding Nodes * * @private */ - _createEditEdgeToolbar : function() { + _createAddNodeToolbar : function() { // clear the toolbar - this.blockConnectingEdgeSelection = false; this._clearManipulatorBar(); this.off('select', this.boundFunction); @@ -220,14 +111,14 @@ var manipulationMixin = { this.manipulationDiv.innerHTML = "" + "Back" + "
    " + - "Currently only nodes can be edited."; + "Click in an empty space to place a new node"; // bind the icon var backButton = document.getElementById("manipulate-back"); backButton.onclick = this._createManipulatorBar.bind(this); // we use the boundFunction so we can reference it when we unbind it from the "select" event. - this.boundFunction = this._createManipulatorBar.bind(this); + this.boundFunction = this._addNode.bind(this); this.on('select', this.boundFunction); }, @@ -237,9 +128,12 @@ var manipulationMixin = { * * @private */ - _createConnectToolbar : function() { + _createAddEdgeToolbar : function() { // clear the toolbar this._clearManipulatorBar(); + this._unselectAll(true); + this.freezeSimulation = true; + this.off('select', this.boundFunction); this._unselectAll(); @@ -249,7 +143,7 @@ var manipulationMixin = { this.manipulationDiv.innerHTML = "" + "Back" + "
    " + - "Select the node you want to connect to other nodes."; + "Click on a node and drag the edge to another node."; // bind the icon var backButton = document.getElementById("manipulate-back"); @@ -258,43 +152,16 @@ var manipulationMixin = { // we use the boundFunction so we can reference it when we unbind it from the "select" event. this.boundFunction = this._handleConnect.bind(this); this.on('select', this.boundFunction); - }, + // temporarily overload functions + this.cachedFunctions["_handleTouch"] = this._handleTouch; + this.cachedFunctions["_handleOnRelease"] = this._handleOnRelease; + this._handleTouch = this._handleConnect; + this._handleOnRelease = this._finishConnect; - /** - * create the toolbar for deleting selected objects. User has to be sure. - * - * @private - */ - _createDeletionToolbar : function() { - // clear the toolbar - this._clearManipulatorBar(); - this.off('select', this.boundFunction); + // redraw to show the unselect + this._redraw(); - if (this._selectionIsEmpty()) { - this.manipulationDiv.innerHTML = "" + - "Cannot delete an empty selection."; - var graph = this; - window.setTimeout (function() {graph._createManipulatorBar()},1500); - } - else { - this.manipulationDiv.innerHTML = "" + - "Back" + - "
    " + - "Are you sure? This cannot be undone." + - "
    " + - "Yes."; - - // bind the buttons - var backButton = document.getElementById("manipulate-back"); - backButton.onclick = this._createManipulatorBar.bind(this); - var acceptDeleteButton = document.getElementById("manipulate-acceptDelete"); - acceptDeleteButton.onclick = this._deleteSelected.bind(this); - - // we use the boundFunction so we can reference it when we unbind it from the "select" event. - this.boundFunction = this._createManipulatorBar.bind(this); - this.on('select', this.boundFunction); - } }, @@ -304,162 +171,226 @@ var manipulationMixin = { * * @private */ - _handleConnect : function() { - this.forceAppendSelection = false; - if (this._clusterInSelection()) { - this._unselectClusters(true); - if (!this._selectionIsEmpty()) { - this._setManipulationMessage("You cannot connect a node to a cluster."); - this.forceAppendSelection = true; - } - else { - this._setManipulationMessage("You cannot connect anything to a cluster."); - } - } - else if (!this._selectionIsEmpty()) { - if (this._getSelectedNodeCount() == 2) { - this._connectNodes(); - this._restoreSourceNode(); - this._setManipulationMessage("Click on another node you want to connect this node to or go back."); - } - else { - this._setManipulationMessage("Click on the node you want to connect this node."); - this._setSourceNode(); - this.forceAppendSelection = true; + _handleConnect : function(pointer) { + if (this._getSelectedNodeCount() == 0) { + var node = this._getNodeAt(pointer); + if (node != null) { + if (node.clusterSize > 1) { + alert("Cannot create edges to a cluster.") + } + else { + this._selectObject(node,false); + // create a node the temporary line can look at + this.sectors['support']['nodes']['targetNode'] = new Node({id:'targetNode'},{},{},this.constants); + this.sectors['support']['nodes']['targetNode'].x = node.x; + this.sectors['support']['nodes']['targetNode'].y = node.y; + this.sectors['support']['nodes']['targetViaNode'] = new Node({id:'targetViaNode'},{},{},this.constants); + this.sectors['support']['nodes']['targetViaNode'].x = node.x; + this.sectors['support']['nodes']['targetViaNode'].y = node.y; + this.sectors['support']['nodes']['targetViaNode'].parentEdgeId = "connectionEdge"; + + // create a temporary edge + this.edges['connectionEdge'] = new Edge({id:"connectionEdge",from:node.id,to:this.sectors['support']['nodes']['targetNode'].id}, this, this.constants); + this.edges['connectionEdge'].from = node; + this.edges['connectionEdge'].connected = true; + this.edges['connectionEdge'].smooth = true; + this.edges['connectionEdge'].selected = true; + this.edges['connectionEdge'].to = this.sectors['support']['nodes']['targetNode']; + this.edges['connectionEdge'].via = this.sectors['support']['nodes']['targetViaNode']; + + this.cachedFunctions["_handleOnDrag"] = this._handleOnDrag; + this._handleOnDrag = function(event) { + var pointer = this._getPointer(event.gesture.touches[0]); + this.sectors['support']['nodes']['targetNode'].x = this._canvasToX(pointer.x); + this.sectors['support']['nodes']['targetNode'].y = this._canvasToY(pointer.y); + this.sectors['support']['nodes']['targetViaNode'].x = 0.5 * (this._canvasToX(pointer.x) + this.edges['connectionEdge'].from.x); + this.sectors['support']['nodes']['targetViaNode'].y = this._canvasToY(pointer.y); + }; + + this.moving = true; + this.start(); + } } } - else { - this._setManipulationMessage("Select the node you want to connect to other nodes."); - } }, + _finishConnect : function(pointer) { + if (this._getSelectedNodeCount() == 1) { - /** - * returns the object that is selected - * - * @returns {*} - * @private - */ - _getEditObject : function() { - for(var objectId in this.selectionObj) { - if(this.selectionObj.hasOwnProperty(objectId)) { - return this.selectionObj[objectId]; - } - } - return null; - }, + // restore the drag function + this._handleOnDrag = this.cachedFunctions["_handleOnDrag"]; + delete this.cachedFunctions["_handleOnDrag"]; + // remember the edge id + var connectFromId = this.edges['connectionEdge'].fromId; - /** - * stores the first selected node for the connecting process as the source node. This allows us to remember the direction - * - * @private - */ - _setSourceNode : function() { - for(var objectId in this.selectionObj) { - if(this.selectionObj.hasOwnProperty(objectId)) { - if (this.selectionObj[objectId] instanceof Node) { - this.manipulationSourceNode = this.selectionObj[objectId]; + // remove the temporary nodes and edge + delete this.edges['connectionEdge'] + delete this.sectors['support']['nodes']['targetNode']; + delete this.sectors['support']['nodes']['targetViaNode']; + + var node = this._getNodeAt(pointer); + if (node != null) { + if (node.clusterSize > 1) { + alert("Cannot create edges to a cluster.") + } + else { + this._createEdge(connectFromId,node.id); + this._createManipulatorBar(); } } + this._unselectAll(); } }, /** - * gets the node the source connects to. + * Adds a node on the specified location * - * @returns {*} - * @private + * @param {Object} pointer */ - _getTargetNode : function() { - for(var objectId in this.selectionObj) { - if(this.selectionObj.hasOwnProperty(objectId)) { - if (this.selectionObj[objectId] instanceof Node) { - if (this.manipulationSourceNode.id != this.selectionObj[objectId].id) { - return this.selectionObj[objectId]; - } + _addNode : function() { + if (this._selectionIsEmpty() && this.editMode == true) { + var positionObject = this._pointerToPositionObject(this.pointerPosition); + var defaultData = {id:util.randomUUID(),x:positionObject.left,y:positionObject.top,label:"new",fixed:false}; + if (this.triggerFunctions.add) { + if (this.triggerFunctions.add.length == 2) { + var me = this; + this.triggerFunctions.add(defaultData, function(finalizedData) { + me.createNodeOnClick = true; + me.nodesData.add(finalizedData); + me.createNodeOnClick = false; + me._createManipulatorBar(); + me.moving = true; + me.start(); + }); + } + else { + alert("The function for add does not support two arguments (data,callback)."); + this._createManipulatorBar(); + this.moving = true; + this.start(); } } + else { + console.log("didnt use funciton") + this.createNodeOnClick = true; + this.nodesData.add(defaultData); + this.createNodeOnClick = false; + this._createManipulatorBar(); + this.moving = true; + this.start(); + } } - return null; - }, - - - /** - * restore the selection back to only the sourcenode - * - * @private - */ - _restoreSourceNode : function() { - this._unselectAll(true); - this._selectObject(this.manipulationSourceNode); }, /** - * change the description message on the toolbar + * connect two nodes with a new edge. * - * @param message * @private */ - _setManipulationMessage : function(message) { - var messageSpan = document.getElementById('manipulatorLabel'); - messageSpan.innerHTML = message; - }, - - - /** - * Adds a node on the specified location - * - * @param {Object} pointer - */ - _addNode : function() { - if (this._selectionIsEmpty()) { - var positionObject = this._pointerToPositionObject(this.pointerPosition); - this.createNodeOnClick = true; - this.nodesData.add({id:util.randomUUID(),x:positionObject.left,y:positionObject.top,label:"new",fixed:false}); - this.createNodeOnClick = false; - this.moving = true; - this.start(); + _createEdge : function(sourceNodeId,targetNodeId) { + if (this.editMode == true) { + var defaultData = {from:sourceNodeId, to:targetNodeId}; + if (this.triggerFunctions.connect) { + if (this.triggerFunctions.connect.length == 2) { + var me = this; + this.triggerFunctions.connect(defaultData, function(finalizedData) { + me.edgesData.add(finalizedData) + me.moving = true; + me.start(); + }); + } + else { + alert("The function for connect does not support two arguments (data,callback)."); + this.moving = true; + this.start(); + } + } + else { + this.edgesData.add(defaultData) + this.moving = true; + this.start(); + } } }, /** - * connect two nodes with a new edge. + * Create the toolbar to edit the selected node. The label and the color can be changed. Other colors are derived from the chosen color. * * @private */ - _connectNodes : function() { - var targetNode = this._getTargetNode(); - var sourceNode = this.manipulationSourceNode; - this.edgesData.add({from:sourceNode.id, to:targetNode.id}) - this.moving = true; - this.start(); + _editNode : function() { + if (this.triggerFunctions.edit && this.editMode == true) { + var node = this._getSelectedNode(); + var data = {id:node.id, + label: node.label, + group: node.group, + shape: node.shape, + color: { + background:node.color.background, + border:node.color.border, + highlight: { + background:node.color.highlight.background, + border:node.color.highlight.border + } + }}; + if (this.triggerFunctions.edit.length == 2) { + var me = this; + this.triggerFunctions.edit(data, function (finalizedData) { + me.nodesData.update(finalizedData); + me._createManipulatorBar(); + me.moving = true; + me.start(); + }); + } + else { + alert("The function for edit does not support two arguments (data, callback).") + } + } + else { + alert("No edit function has been bound to this button.") + } }, /** * delete everything in the selection - * TODO : place the alert in the gui. - * * * @private */ _deleteSelected : function() { - if (!this._clusterInSelection()) { - var selectedNodes = this.getSelectedNodes(); - var selectedEdges = this.getSelectedEdges(); - this._removeEdges(selectedEdges); - this._removeNodes(selectedNodes); - this.moving = true; - this.start(); - } - else { - alert("Clusters cannot be deleted.") + if (!this._selectionIsEmpty() && this.editMode == true) { + if (!this._clusterInSelection()) { + var selectedNodes = this.getSelectedNodes(); + var selectedEdges = this.getSelectedEdges(); + if (this.triggerFunctions.delete) { + var me = this; + var data = {nodes: selectedNodes, edges: selectedEdges}; + if (this.triggerFunctions.delete.length = 2) { + this.triggerFunctions.delete(data, function (finalizedData) { + me.edgesData.remove(finalizedData.edges); + me.nodesData.remove(finalizedData.nodes); + me.moving = true; + me.start(); + }); + } + else { + alert("The function for edit does not support two arguments (data, callback).") + } + } + else { + this.edgesData.remove(selectedEdges); + this.nodesData.remove(selectedNodes); + this.moving = true; + this.start(); + } + } + else { + alert("Clusters cannot be deleted."); + } } } - - }; \ No newline at end of file diff --git a/src/graph/graphMixins/MixinLoader.js b/src/graph/graphMixins/MixinLoader.js index 062e65ad..325febf9 100644 --- a/src/graph/graphMixins/MixinLoader.js +++ b/src/graph/graphMixins/MixinLoader.js @@ -149,6 +149,13 @@ var graphMixinLoaders = { if (this.manipulationDiv === undefined) { this.manipulationDiv = document.createElement('div'); this.manipulationDiv.className = 'graph-manipulationDiv'; + this.manipulationDiv.id = 'graph-manipulationDiv'; + if (this.editMode == true) { + this.manipulationDiv.style.display = "block"; + } + else { + this.manipulationDiv.style.display = "none"; + } this.containerElement.insertBefore(this.manipulationDiv, this.frame); } // load the manipulation functions @@ -157,6 +164,14 @@ var graphMixinLoaders = { // create the manipulator toolbar this._createManipulatorBar(); } + else { + if (this.manipulationDiv !== undefined) { + this._createManipulatorBar(); + this.containerElement.removeChild(this.manipulationDiv); + this.manipulationDiv = undefined; + this._clearMixin(manipulationMixin); + } + } }, diff --git a/src/graph/graphMixins/SelectionMixin.js b/src/graph/graphMixins/SelectionMixin.js index 5ed2272a..01078805 100644 --- a/src/graph/graphMixins/SelectionMixin.js +++ b/src/graph/graphMixins/SelectionMixin.js @@ -263,6 +263,23 @@ var SelectionMixin = { return count; }, + /** + * return the number of selected nodes + * + * @returns {number} + * @private + */ + _getSelectedNode : function() { + for (var objectId in this.selectionObj) { + if (this.selectionObj.hasOwnProperty(objectId)) { + if (this.selectionObj[objectId] instanceof Node) { + return this.selectionObj[objectId]; + } + } + } + return null; + }, + /** * return the number of selected edges @@ -488,7 +505,7 @@ var SelectionMixin = { * * @private */ - _handleOnRelease : function() { + _handleOnRelease : function(pointer) { this.xIncrement = 0; this.yIncrement = 0; this.zoomIncrement = 0; diff --git a/src/graph/graphMixins/physics/repulsion.js b/src/graph/graphMixins/physics/repulsion.js index 8df7236f..c1bc805f 100644 --- a/src/graph/graphMixins/physics/repulsion.js +++ b/src/graph/graphMixins/physics/repulsion.js @@ -23,7 +23,9 @@ var repulsionMixin = { var b = 4/3; // repulsing forces between nodes - var minimumDistance = this.constants.nodes.distance; + var nodeDistance = this.constants.physics.repulsion.nodeDistance; + var minimumDistance = nodeDistance; + // we loop from i over all but the last entree in the array // j loops from i+1 to the last. This way we do not double count any of the indices, nor i == j for (i = 0; i < nodeIndices.length-1; i++) { @@ -36,7 +38,7 @@ var repulsionMixin = { dy = node2.y - node1.y; distance = Math.sqrt(dx * dx + dy * dy); - minimumDistance = (combinedClusterSize == 0) ? this.constants.nodes.distance : (this.constants.nodes.distance * (1 + combinedClusterSize * this.constants.clustering.distanceAmplification)); + minimumDistance = (combinedClusterSize == 0) ? nodeDistance : (nodeDistance * (1 + combinedClusterSize * this.constants.clustering.distanceAmplification)); var a = a_base / minimumDistance; if (distance < 2*minimumDistance) { angle = Math.atan2(dy, dx); diff --git a/src/util.js b/src/util.js index 6b49996c..c65682a3 100644 --- a/src/util.js +++ b/src/util.js @@ -826,3 +826,7 @@ util.hexToHSV = function hexToHSV(hex) { return util.RGBToHSV(rgb.r,rgb.g,rgb.b); } +util.isValidHex = function isValidHex(hex) { + var isOk = /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(hex); + return isOk; +} From 2c6928d2561daee49b5c314c44a17e563d7ddcd4 Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Mon, 17 Feb 2014 21:23:12 +0100 Subject: [PATCH 49/52] Tweaked physics system, added documentation for all new features (physics, manipulation, smooth) made all GUI elements CSS and HTML. --- Jakefile.js | 8 +- docs/graph.html | 327 ++++++++++-- examples/graph/02_random_nodes.html | 2 - examples/graph/20_navigation.html | 3 +- examples/graph/21_data_manipulation.html | 482 +++++++----------- src/graph/Edge.js | 8 +- src/graph/Graph.js | 331 +++++++----- src/graph/Node.js | 48 +- src/graph/css/graph-manipulation.css | 128 +++++ src/graph/css/graph-navigation.css | 62 +++ src/graph/graphMixins/ClusterMixin.js | 9 +- src/graph/graphMixins/ManipulationMixin.js | 83 ++- src/graph/graphMixins/MixinLoader.js | 61 ++- src/graph/graphMixins/NavigationMixin.js | 136 ++--- src/graph/graphMixins/SectorsMixin.js | 42 +- src/graph/graphMixins/SelectionMixin.js | 63 +-- src/graph/graphMixins/physics/PhysicsMixin.js | 50 +- src/graph/graphMixins/physics/barnesHut.js | 76 +-- src/graph/graphMixins/physics/repulsion.js | 16 +- src/graph/img/cross.png | Bin 0 -> 18303 bytes src/graph/img/cross2.png | Bin 0 -> 17768 bytes 21 files changed, 1121 insertions(+), 814 deletions(-) create mode 100644 src/graph/css/graph-manipulation.css create mode 100644 src/graph/css/graph-navigation.css create mode 100644 src/graph/img/cross.png create mode 100644 src/graph/img/cross2.png diff --git a/Jakefile.js b/Jakefile.js index 971f2a7e..a36a934c 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -83,8 +83,8 @@ task('build', {async: true}, function () { './src/graph/Groups.js', './src/graph/Images.js', './src/graph/graphMixins/physics/PhysicsMixin.js', - './src/graph/graphMixins/physics/barnesHut.js', - './src/graph/graphMixins/physics/repulsion.js', + './src/graph/graphMixins/physics/BarnesHut.js', + './src/graph/graphMixins/physics/Repulsion.js', './src/graph/graphMixins/ManipulationMixin.js', './src/graph/graphMixins/SectorsMixin.js', './src/graph/graphMixins/ClusterMixin.js', @@ -103,6 +103,10 @@ task('build', {async: true}, function () { wrench.copyDirSyncRecursive('./src/graph/img', DIST+ '/img', { forceDelete: true }); + // copy css + wrench.copyDirSyncRecursive('./src/graph/css', DIST+ '/css', { + forceDelete: true + }); var timeStart = Date.now(); // bundle the concatenated script and dependencies into one file diff --git a/docs/graph.html b/docs/graph.html index 8dfe2594..37636cf4 100644 --- a/docs/graph.html +++ b/docs/graph.html @@ -53,7 +53,9 @@
  • Nodes
  • Edges
  • Groups
  • -
  • Clustering
  • +
  • Physics
  • +
  • Data_manipulation
  • +
  • Clustering
  • Navigation controls
  • Keyboard navigation
  • @@ -529,13 +531,6 @@ var edges = [ type. - - length - number - no - The length of the edge in pixels. - - style string @@ -647,6 +642,25 @@ var options = { Description + + physics + Object + none + + Configuration of the physics system governing the simulation of the nodes and edges. + Barnes-Hut nBody simulation is used by default. See section Physics for an overview of the available options. + + + + + dataManipulation + Object + none + + Settings for manipulating the Dataset. See section Data manipulation for an overview of the available options. + + + clustering Object @@ -710,6 +724,13 @@ var options = { + + smoothCurves + Boolean + true + If true, edges are drawn as smooth curves. This is more computationally intensive since the edge now is a quadratic Bezier curve with control points on both nodes and an invisible node in the center of the edge. This support node is also handed by the physics simulation. + + selectable Boolean @@ -964,12 +985,6 @@ var options = { Only applicable when the line style is dash-line. - - length - Number - 100 - The default length of a edge. - style String @@ -1122,6 +1137,235 @@ var nodes = [ +

    Physics

    +

    + The physics system has been overhauled to increase performance. The original simulation method was based on particel physics with a repulsion field (potential) around each node, + and the edges were modelled as springs. The new system employed the Barnes-Hut gravitational simulation model. The edges are still modelled as springs. + To unify the physics system, the damping, repulsion distance and edge length have been combined in an physics option. To retain good behaviour, both the old repulsion model and the Barnes-Hut model have their own parameters. + If no options for the physics system are supplied, the Barnes-Hut method will be used with the default parameters. +

    +
    +// These variables must be defined in an options object named physics.
    +// If a variable is not supplied, the default value is used.
    +var options = {
    +    physics: {
    +        barnesHut: {
    +            enabled: true,
    +            gravitationalConstant: -2000,
    +            centralGravity: 0.1,
    +            springLength: 100,
    +            springConstant: 0.05,
    +            damping: 0.09
    +        },
    +        repulsion: {
    +            centralGravity: 0.1,
    +            springLength: 50,
    +            springConstant: 0.05,
    +            nodeDistance: 100,
    +            damping: 0.09
    +        },
    +    }
    +
    +
    barnesHut:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDefaultDescription
    enabledBooleantrueThis switches the Barnes-Hut simulation on or off. If it is turned off, the old repulsion model is used. Barnes-Hut is generally faster and yields better results.
    gravitationalConstantNumber-2000This is the gravitational constand used to calculate the gravity forces. More information is available here.
    centralGravityNumber0.1The central gravity is a force that pulls all nodes to the center. This ensures independent groups do not float apart.
    springLengthNumber100In the previous versions this was a property of the edges, called length. This is the length of the springs when they are at rest. During the simulation they will be streched by the gravitational fields. + To greatly reduce the edge length, the gravitationalConstant has to be reduced as well.
    springConstantNumber0.05This is the spring constant used to calculate the spring forces based on Hooke′s Law. More information is available here.
    dampingNumber0.09This is the damping constant. It is used to dissipate energy from the system to have it settle in an equilibrium. More information is available here.
    +
    repulsion:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDefaultDescription
    centralGravityNumber0.1The central gravity is a force that pulls all nodes to the center. This ensures independent groups do not float apart.
    springLengthNumber50In the previous versions this was a property of the edges, called length. This is the length of the springs when they are at rest. During the simulation they will be streched by the gravitational fields. + To greatly reduce the edge length, the gravitationalConstant has to be reduced as well.
    nodeDistanceNumber100This parameter is used to define the distance of influence of the repulsion field of the nodes. Below half this distance, the repulsion is maximal and beyond twice this distance the repulsion is zero.
    springConstantNumber0.05This is the spring constant used to calculate the spring forces based on Hooke′s Law. More information is available here.
    dampingNumber0.09This is the damping constant. It is used to dissipate energy from the system to have it settle in an equilibrium. More information is available here.
    + +

    Data manipulation

    +

    + By using the data manipulation feature of the graph you can dynamically create nodes, connect nodes with edges, edit nodes or delete nodes and edges. + The toolbar is fully HTML and CSS so the user can style this to their preference. To control the behaviour of the data manipulation, users can insert custom functions + into the data manipulation process. For example, an injected function can show an detailed pop-up when a user wants to add a node. In example 21, + two functions have been injected into the add and edit functionality. This is described in more detail in the next subsection. +

    +
    +// These variables must be defined in an options object named dataManipulation.
    +// If a variable is not supplied, the default value is used.
    +var options = {
    +    dataManipulation: {
    +      enabled: false,
    +      initiallyVisible: false
    +    }
    +}
    +// OR to just load the module with default values:
    +var options: {
    +    dataManipulation: true
    +}
    +
    + + + + + + + + + + + + + + + + + + + + +
    NameTypeDefaultDescription
    enabledBooleanfalseEnabling or disabling of the data manipulation toolbar. If it is initially hidden, an edit button appears in the top left corner.
    initiallyVisibleBooleanfalseInitially hide or show the data manipulation toolbar.
    + +

    Data manipulation: custom functionality

    +

    + Users can insert custom functions into the add node, edit node, connect nodes, and delete selected operations. This is done by supplying them in the options. + If the callback is NOT called, nothing happens. Example 21 has two working examples + for the add and edit functions. The data the user is supplied with in these functions has been described in the code below. + For the add data, you can add any and all options that are accepted for node creation as described above. The same goes for edit, however only the fields described + in the code below contain information on the selected node. The callback for connect accepts any options that are used for edge creation. Only the callback for delete selected + requires the same data structure that is supplied to the user. +

    +
    +// If a variable is not supplied, the default value is used.
    +var options: {
    +    dataManipulation: true,
    +    onAdd: function(data,callback) {
    +        // fixed must be false because we define a set x and y position.
    +        // If fixed is not false, the node cannot move.
    +        /** data = {id: random unique id,
    +        *           label: new,
    +        *           x: x position of click (canvas space),
    +        *           y: y position of click (canvas space),
    +        *           fixed: false
    +        *          };
    +        */
    +        var newData = {..}; // alter the data as you want.
    +                            // all fields normally accepted by a node can be used.
    +        callback(newData);  // call the callback to add a node.
    +    },
    +    onEdit: function(data,callback) {
    +        /** data = {id:...,
    +        *           label: ...,
    +        *           group: ...,
    +        *           shape: ...,
    +        *           color: {
    +        *             background:...,
    +        *             border:...,
    +        *             highlight: {
    +        *               background:...,
    +        *               border:...
    +        *             }
    +        *           }
    +        *          };
    +        */
    +        var newData = {..}; // alter the data as you want.
    +                            // all fields normally accepted by a node can be used.
    +        callback(newData);  // call the callback with the new data to edit the node.
    +    }
    +    onConnect: function(data,callback) {
    +        // data = {from: nodeId1, to: nodeId2};
    +        var newData = {..};      // check or alter data as you see fit.
    +        callback(newData);       // call the callback to connect the nodes.
    +    },
    +    onDelete: function(data,callback) {
    +        // data = {nodes: [selectedNodeIds], edges: [selectedEdgeIds]};
    +        var newData = {..}; // alter the data as you want.
    +                            // the same data structure is required.
    +        callback(newData);  // call the callback to delete the objects.
    +    }
    +};
    +
    +

    + Because the interface elements are CSS and HTML, the user will have to correct for size changes of the canvas. To facilitate this, a new event has been added called frameResize. + A function can be bound to this event. This function is supplied with the new widht and height of the canvas. The CSS can then be updated accordingly. + An code snippet from example 21 is shown below. +

    +
    +graph.on("frameResize", function(params) {console.log(params.width,params.height)});
    +
    +

    Clustering

    The graph now supports dynamic clustering of nodes. This allows a user to view a very large dataset (> 50.000 nodes) without @@ -1150,16 +1394,19 @@ var options = { reduceToNodes:300, chainThreshold: 0.4, clusterEdgeThreshold: 20, - sectorThreshold: 50, + sectorThreshold: 100, screenSizeThreshold: 0.2, fontSizeMultiplier: 4.0, - forceAmplification: 0.6, - distanceAmplification: 0.2, - edgeGrowth: 11, - nodeScaling: {width: 10, - height: 10, - radius: 10}, - activeAreaBoxSize: 100 + maxFontSize: 1000, + forceAmplification: 0.1, + distanceAmplification: 0.1, + edgeGrowth: 20, + nodeScaling: {width: 1, + height: 1, + radius: 1}, + maxNodeSizeIncrements: 600, + activeAreaBoxSize: 100, + clusterLevelDifference: 2 } } // OR to just load the module with default values: @@ -1233,6 +1480,12 @@ var options: { 4.0 This parameter denotes the increase in fontSize of the cluster when a single node is added to it. + + maxFontSize + Number + 1000 + This parameter denotes the largest allowed font size. If the font becomes too large, some browsers experience problems displaying this. + forceAmplification Number @@ -1251,7 +1504,7 @@ var options: { edgeGrowth Number - 11 + 20 This factor determines the elongation of edges connected to a cluster. @@ -1272,13 +1525,29 @@ var options: { 10 This factor determines how much the radius of a cluster increases in pixels per added node. - - activeAreaBoxSize + + maxNodeSizeIncrements + Number + 600 + This limits the size clusters can grow to. The default value, 600, implies that if a cluster contains more than 600 nodes, it will no longer grow. + + + activeAreaBoxSize + Number + 100 + Imagine a square with an edge length of activeAreaBoxSize pixels around your cursor. + If a cluster is in this box as you zoom in, the cluster can be opened in a seperate sector. + This is regardless of the zoom level. + + + clusterLevelDifference Number - 100 - Imagine a square with an edge length of activeAreaBoxSize pixels around your cursor. - If a cluster is in this box as you zoom in, the cluster can be opened in a seperate sector. - This is regardless of the zoom level. + 2 + At every clustering session, Graph will check if the difference between cluster levels is + acceptable. When a cluster is formed when zooming out, that is one cluster level. + If you zoom out further and it encompasses more nodes, that is another level. For example: + If the highest level of your graph at any given time is 3, nodes that have not clustered or + have clustered only once will join their neighbour with the lowest cluster level. diff --git a/examples/graph/02_random_nodes.html b/examples/graph/02_random_nodes.html index ee648bbc..ea1202aa 100755 --- a/examples/graph/02_random_nodes.html +++ b/examples/graph/02_random_nodes.html @@ -102,8 +102,6 @@ -calculation time: ms -render time: ms diff --git a/examples/graph/20_navigation.html b/examples/graph/20_navigation.html index 5bfaff77..8bc2006a 100644 --- a/examples/graph/20_navigation.html +++ b/examples/graph/20_navigation.html @@ -34,6 +34,7 @@ + - - + #operation { + font-size:28px; + } + #graph-popUp { + display:none; + position:absolute; + top:350px; + left:170px; + z-index:299; + width:250px; + height:120px; + background-color: #f9f9f9; + border-style:solid; + border-width:3px; + border-color: #5394ed; + padding:10px; + text-align: center; + } + + + + + + -

    Navigation controls and keyboad navigation

    +

    Editing the dataset

    - This example is the same as example 2, except for the navigation controls that has been activated. The navigation controls are described below.

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Icons:
    Keyboard shortcuts:
    Up arrow
    Down arrow
    Left arrow
    Right arrow
    =
    [
    Page up
    -
    ]
    Page down
    None
    Description:
    Move up
    Move down
    Move left
    Move right
    Zoom in
    Zoom out
    Zoom extends
    -
    - Apart from clicking the icons, you can also navigate using the keyboard. The buttons are in table above. - Zoom Extends changes the zoom and position of the camera to encompass all visible nodes. - - + In this example we have enabled the data manipulation setting. If the dataManipulation option is set to true, the edit button will appear. + If you prefer to have the toolbar visible initially, you can set the initiallyVisible option to true. The exact method is described in the docs. +

    + The data manipulation allows the user to add nodes, connect them, edit them and delete any selected items. In this example we have created trigger functions + for the add and edit operations. By settings these trigger functions the user can direct the way the data is manipulated. In this example we have created a simple + pop-up that allows us to edit some of the properties.

    - - - - - -
    - +
    + node
    + + + + + +
    id
    label
    + + +
    +

    + diff --git a/src/graph/Edge.js b/src/graph/Edge.js index ba5aa6da..eafcdfdb 100644 --- a/src/graph/Edge.js +++ b/src/graph/Edge.js @@ -231,7 +231,7 @@ Edge.prototype._drawLine = function(ctx) { ctx.lineWidth = this._getLineWidth(); var point; - if (this.from != this.to) { + if (this.from != this.to+9) { // draw line this._line(ctx); @@ -706,15 +706,15 @@ Edge.prototype.setScale = function(scale) { Edge.prototype.select = function() { this.selected = true; -} +}; Edge.prototype.unselect = function() { this.selected = false; -} +}; Edge.prototype.positionBezierNode = function() { if (this.via !== null) { this.via.x = 0.5 * (this.from.x + this.to.x); this.via.y = 0.5 * (this.from.y + this.to.y); } -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/graph/Graph.js b/src/graph/Graph.js index bbfff971..6c0ed49b 100644 --- a/src/graph/Graph.js +++ b/src/graph/Graph.js @@ -17,12 +17,17 @@ function Graph (container, data, options) { this.containerElement = container; this.width = '100%'; this.height = '100%'; - // to give everything a nice fluidity, we seperate the rendering and calculating of the forces - this.renderRefreshRate = 60; // hz (fps) + + // render and calculation settings + this.renderRefreshRate = 60; // hz (fps) this.renderTimestep = 1000 / this.renderRefreshRate; // ms -- saves calculation later on - this.stabilize = true; // stabilize before displaying the graph + this.renderTime = 0.5 * this.renderTimestep; // measured time it takes to render a frame + this.maxRenderSteps = 4; // max amount of physics ticks per render step. + + this.stabilize = true; // stabilize before displaying the graph this.selectable = true; - // these functions can be triggered when the dataset is edited + + // these functions are triggered when the dataset is edited this.triggerFunctions = {add:null,edit:null,connect:null,delete:null}; // set constant values @@ -61,8 +66,6 @@ function Graph (container, data, options) { fontColor: '#343434', fontSize: 14, // px fontFace: 'arial', - //distance: 100, //px - length: 100, // px dash: { length: 10, gap: 5, @@ -72,18 +75,21 @@ function Graph (container, data, options) { physics: { barnesHut: { enabled: true, - theta: 1 / 0.5, // inverted to save time during calculation - gravitationalConstant: -3000, - centralGravity: 0.9, - springLength: 40, - springConstant: 0.04 + theta: 1 / 0.6, // inverted to save time during calculation + gravitationalConstant: -2000, + centralGravity: 0.1, + springLength: 100, + springConstant: 0.05, + damping: 0.09 }, repulsion: { - centralGravity: 0.01, - springLength: 80, + centralGravity: 0.1, + springLength: 50, springConstant: 0.05, - nodeDistance: 100 + nodeDistance: 100, + damping: 0.09 }, + damping: null, centralGravity: null, springLength: null, springConstant: null @@ -98,8 +104,8 @@ function Graph (container, data, options) { sectorThreshold: 100, // (# nodes in cluster) | cluster size threshold. If larger, expanding in own sector. screenSizeThreshold: 0.2, // (% of canvas) | relative size threshold. If the width or height of a clusternode takes up this much of the screen, decluster node. fontSizeMultiplier: 4.0, // (px PNiC) | how much the cluster font size grows per node in cluster (in px). - forceAmplification: 0.1, // (multiplier PNiC) | factor of increase fo the repulsion force of a cluster (per node in cluster). maxFontSize: 1000, + forceAmplification: 0.1, // (multiplier PNiC) | factor of increase fo the repulsion force of a cluster (per node in cluster). distanceAmplification: 0.1, // (multiplier PNiC) | factor how much the repulsion distance of a cluster increases (per node in cluster). edgeGrowth: 20, // (px PNiC) | amount of clusterSize connected to the edge is multiplied with this and added to edgeLength. nodeScaling: {width: 1, // (px PNiC) | growth of the width per node in cluster. @@ -117,104 +123,101 @@ function Graph (container, data, options) { enabled: false, speed: {x: 10, y: 10, zoom: 0.02} }, - dataManipulationToolbar: { + dataManipulation: { enabled: false, initiallyVisible: false }, smoothCurves: true, - maxVelocity: 25, - minVelocity: 0.1, // px/s + maxVelocity: 10, + minVelocity: 0.1, // px/s maxIterations: 1000 // maximum number of iteration to stabilize }; - this.editMode = this.constants.dataManipulationToolbar.initiallyVisible; + this.editMode = this.constants.dataManipulation.initiallyVisible; // Node variables + var graph = this; this.groups = new Groups(); // object with groups this.images = new Images(); // object with images this.images.setOnloadCallback(function () { graph._redraw(); }); - // navigation variables + + // keyboard navigation variables this.xIncrement = 0; this.yIncrement = 0; this.zoomIncrement = 0; + // loading all the mixins: // load the force calculation functions, grouped under the physics system. this._loadPhysicsSystem(); - // create a frame and canvas this._create(); - // load the sector system. (mandatory, fully integrated with Graph) this._loadSectorSystem(); - // load the cluster system. (mandatory, even when not using the cluster system, there are function calls to it) this._loadClusterSystem(); - // load the selection system. (mandatory, required by Graph) this._loadSelectionSystem(); - // apply options this.setOptions(options); // other vars - var graph = this; this.freezeSimulation = false;// freeze the simulation this.cachedFunctions = {}; + // containers for nodes and edges this.calculationNodes = {}; this.calculationNodeIndices = []; this.nodeIndices = []; // array with all the indices of the nodes. Used to speed up forces calculation this.nodes = {}; // object with Node objects this.edges = {}; // object with Edge objects + // position and scale variables and objects this.canvasTopLeft = {"x": 0,"y": 0}; // coordinates of the top left of the canvas. they will be set during _redraw. this.canvasBottomRight = {"x": 0,"y": 0}; // coordinates of the bottom right of the canvas. they will be set during _redraw this.pointerPosition = {"x": 0,"y": 0}; // coordinates of the bottom right of the canvas. they will be set during _redraw - this.areaCenter = {}; // object with x and y elements used for determining the center of the zoom action this.scale = 1; // defining the global scale variable in the constructor this.previousScale = this.scale; // this is used to check if the zoom operation is zooming in or out + // datasets or dataviews this.nodesData = null; // A DataSet or DataView this.edgesData = null; // A DataSet or DataView // create event listeners used to subscribe on the DataSets of the nodes and edges - var me = this; this.nodesListeners = { 'add': function (event, params) { - me._addNodes(params.items); - me.start(); + graph._addNodes(params.items); + graph.start(); }, 'update': function (event, params) { - me._updateNodes(params.items); - me.start(); + graph._updateNodes(params.items); + graph.start(); }, 'remove': function (event, params) { - me._removeNodes(params.items); - me.start(); + graph._removeNodes(params.items); + graph.start(); } }; this.edgesListeners = { 'add': function (event, params) { - me._addEdges(params.items); - me.start(); + graph._addEdges(params.items); + graph.start(); }, 'update': function (event, params) { - me._updateEdges(params.items); - me.start(); + graph._updateEdges(params.items); + graph.start(); }, 'remove': function (event, params) { - me._removeEdges(params.items); - me.start(); + graph._removeEdges(params.items); + graph.start(); } }; - // properties of the data + // properties for the animation this.moving = false; // True if any of the nodes have an undefined position - this.timer = undefined; - + this.timer = undefined; // Scheduling function. Is definded in this.start(); // load data (the disable start variable will be the same as the enabled clustering) this.setData(data,this.constants.clustering.enabled); @@ -314,10 +317,10 @@ Graph.prototype.zoomToFit = function(initialZoom, doNotStart) { if (initialZoom == true) { if (this.constants.clustering.enabled == true && numberOfNodes >= this.constants.clustering.initialMaxNodes) { - zoomLevel = 38.8467 / (numberOfNodes - 14.50184) + 0.0116; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. + zoomLevel = 77.5271985 / (numberOfNodes + 187.266146) + 4.76710517e-05; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. } else { - zoomLevel = 42.54117319 / (numberOfNodes + 39.31966387) + 0.1944405; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. + zoomLevel = 30.5062972 / (numberOfNodes + 19.93597763) + 0.08413486; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. } } else { @@ -418,11 +421,22 @@ Graph.prototype.setOptions = function (options) { if (options.height !== undefined) {this.height = options.height;} if (options.stabilize !== undefined) {this.stabilize = options.stabilize;} if (options.selectable !== undefined) {this.selectable = options.selectable;} + if (options.smoothCurves !== undefined) {this.constants.smoothCurves = options.smoothCurves;} - if (options.triggerFunctions) { - for (prop in options.triggerFunctions) { - this.triggerFunctions[prop] = options.triggerFunctions[prop]; + if (options.onAdd) { + this.triggerFunctions.add = options.onAdd; } + + if (options.onEdit) { + this.triggerFunctions.edit = options.onEdit; + } + + if (options.onConnect) { + this.triggerFunctions.connect = options.onConnect; + } + + if (options.onDelete) { + this.triggerFunctions.delete = options.onDelete; } if (options.physics) { @@ -481,16 +495,16 @@ Graph.prototype.setOptions = function (options) { this.constants.keyboard.enabled = false; } - if (options.dataManipulationToolbar) { - this.constants.dataManipulationToolbar.enabled = true; - for (prop in options.dataManipulationToolbar) { - if (options.dataManipulationToolbar.hasOwnProperty(prop)) { - this.constants.dataManipulationToolbar[prop] = options.dataManipulationToolbar[prop]; + if (options.dataManipulation) { + this.constants.dataManipulation.enabled = true; + for (prop in options.dataManipulation) { + if (options.dataManipulation.hasOwnProperty(prop)) { + this.constants.dataManipulation[prop] = options.dataManipulation[prop]; } } } - else if (options.dataManipulationToolbar !== undefined) { - this.constants.dataManipulationToolbar.enabled = false; + else if (options.dataManipulation !== undefined) { + this.constants.dataManipulation.enabled = false; } // TODO: work out these options and document them @@ -547,14 +561,17 @@ Graph.prototype.setOptions = function (options) { } } + + // (Re)loading the mixins that can be enabled or disabled in the options. // load the force calculation functions, grouped under the physics system. this._loadPhysicsSystem(); - // load the navigation system. this._loadNavigationControls(); - // load the data manipulation system this._loadManipulationSystem(); + // configure the smooth curves + this._configureSmoothCurves(); + // bind keys. If disabled, this will not do anything; this._createKeyBinds(); @@ -562,7 +579,7 @@ Graph.prototype.setOptions = function (options) { this.setSize(this.width, this.height); this._setTranslation(this.frame.clientWidth / 2, this.frame.clientHeight / 2); this._setScale(1); - this.zoomToFit() + this.zoomToFit(); this._redraw(); }; @@ -575,7 +592,7 @@ Graph.prototype.setOptions = function (options) { * event specific properties. */ Graph.prototype.on = function on (event, callback) { - var available = ['select']; + var available = ['select','frameResize']; if (available.indexOf(event) == -1) { throw new Error('Unknown event "' + event + '". Choose from ' + available.join()); @@ -693,14 +710,13 @@ Graph.prototype._createKeyBinds = function() { this.mousetrap.bind("pagedown",this._zoomOut.bind(me),"keydown"); this.mousetrap.bind("pagedown",this._stopZoom.bind(me), "keyup"); } - this.mousetrap.bind("b",this._toggleBarnesHut.bind(me)); +// this.mousetrap.bind("b",this._toggleBarnesHut.bind(me)); - if (this.constants.dataManipulationToolbar.enabled == true) { + if (this.constants.dataManipulation.enabled == true) { this.mousetrap.bind("escape",this._createManipulatorBar.bind(me)); this.mousetrap.bind("del",this._deleteSelected.bind(me)); - this.mousetrap.bind("e",this._toggleEditMode.bind(me)); } -} +}; /** * Get the pointer location from a touch location @@ -737,6 +753,12 @@ Graph.prototype._onDragStart = function () { }; +/** + * This function is called by _onDragStart. + * It is separated out because we can then overload it for the datamanipulation system. + * + * @private + */ Graph.prototype._handleDragStart = function() { var drag = this.drag; var node = this._getNodeAt(drag.pointer); @@ -778,7 +800,7 @@ Graph.prototype._handleDragStart = function() { } } } -} +}; /** @@ -789,6 +811,13 @@ Graph.prototype._onDrag = function (event) { this._handleOnDrag(event) }; + +/** + * This function is called by _onDrag. + * It is separated out because we can then overload it for the datamanipulation system. + * + * @private + */ Graph.prototype._handleOnDrag = function(event) { if (this.drag.pinched) { return; @@ -817,7 +846,7 @@ Graph.prototype._handleOnDrag = function(event) { } }); - // start animation if not yet running + // start _animationStep if not yet running if (!this.moving) { this.moving = true; this.start(); @@ -834,7 +863,7 @@ Graph.prototype._handleOnDrag = function(event) { this._redraw(); this.moved = true; } -} +}; /** * handle drag start event @@ -938,8 +967,6 @@ Graph.prototype._zoom = function(scale, pointer) { this.areaCenter = {"x" : this._canvasToX(pointer.x), "y" : this._canvasToY(pointer.y)}; - // this.areaCenter = {"x" : pointer.x,"y" : pointer.y }; -// console.log(translation.x,translation.y,pointer.x,pointer.y,scale); this.pinch.mousewheelScale = scale; this._setScale(scale); this._setTranslation(tx, ty); @@ -949,6 +976,7 @@ Graph.prototype._zoom = function(scale, pointer) { return scale; }; + /** * Event handler for mouse wheel event, used to zoom the timeline * See http://adomas.org/javascript-mouse-wheel/ @@ -1098,6 +1126,7 @@ Graph.prototype._checkShowPopup = function (pointer) { } }; + /** * Check if the popup must be hided, which is the case when the mouse is no * longer hovering on the object @@ -1135,9 +1164,7 @@ Graph.prototype.setSize = function(width, height) { this.manipulationDiv.style.width = this.frame.canvas.clientWidth; } - if (this.constants.navigation.enabled == true) { - this._relocateNavigation(); - } + this._trigger('frameResize', {width:this.frame.canvas.width,height:this.frame.canvas.height}); }; /** @@ -1200,7 +1227,7 @@ Graph.prototype._addNodes = function(ids) { this.nodes[id] = node; // note: this may replace an existing node if ((node.xFixed == false || node.yFixed == false) && this.createNodeOnClick != true) { - var radius = this.constants.physics.springLength * 0.2*ids.length; + var radius = 10 * 0.1*ids.length; var angle = 2 * Math.PI * Math.random(); if (node.xFixed == false) {node.x = radius * Math.cos(angle);} if (node.yFixed == false) {node.y = radius * Math.sin(angle);} @@ -1211,7 +1238,7 @@ Graph.prototype._addNodes = function(ids) { } } this._updateNodeIndexList(); - this._setCalculationNodes() + this._updateCalculationNodes(); this._reconnectEdges(); this._updateValueRange(this.nodes); this.updateLabels(); @@ -1337,7 +1364,7 @@ Graph.prototype._addEdges = function (ids) { this.moving = true; this._updateValueRange(edges); this._createBezierNodes(); - this._setCalculationNodes(); + this._updateCalculationNodes(); }; /** @@ -1392,7 +1419,7 @@ Graph.prototype._removeEdges = function (ids) { this.moving = true; this._updateValueRange(edges); - this._setCalculationNodes(); + this._updateCalculationNodes(); }; /** @@ -1497,10 +1524,6 @@ Graph.prototype._redraw = function() { // restore original scaling and translation ctx.restore(); - - if (this.constants.navigation.enabled == true) { - this._doInNavigationSector("_drawNodes",ctx,true); - } }; /** @@ -1698,7 +1721,7 @@ Graph.prototype._isMoving = function(vmin) { * @private */ Graph.prototype._discreteStepNodes = function() { - var interval = 1.0; + var interval = 0.75; var nodes = this.nodes; var nodeId; @@ -1726,13 +1749,7 @@ Graph.prototype._discreteStepNodes = function() { }; - -/** - * Start animating nodes and edges - * - * @poram {Boolean} runCalculationStep - */ -Graph.prototype.start = function() { +Graph.prototype._physicsTick = function() { if (!this.freezeSimulation) { if (this.moving) { this._doInAllActiveSectors("_initializeForceCalculation"); @@ -1743,33 +1760,53 @@ Graph.prototype.start = function() { this._findCenter(this._getRange()) } } +}; - if (this.moving || this.xIncrement != 0 || this.yIncrement != 0 || this.zoomIncrement != 0) { - // start animation. only start calculationTimer if it is not already running - if (!this.timer) { - var graph = this; - this.timer = window.setTimeout(function () { - graph.timer = undefined; - - // keyboad movement - if (graph.xIncrement != 0 || graph.yIncrement != 0) { - var translation = graph._getTranslation(); - graph._setTranslation(translation.x+graph.xIncrement, translation.y+graph.yIncrement); - } - if (graph.zoomIncrement != 0) { - var center = { - x: graph.frame.canvas.clientWidth / 2, - y: graph.frame.canvas.clientHeight / 2 - }; - graph._zoom(graph.scale*(1 + graph.zoomIncrement), center); - } +/** + * This function runs one step of the animation. It calls an x amount of physics ticks and one render tick. + * It reschedules itself at the beginning of the function + * + * @private + */ +Graph.prototype._animationStep = function() { + // reset the timer so a new scheduled animation step can be set + this.timer = undefined; + + // handle the keyboad movement + this._handleNavigation(); + + // this schedules a new animation step + this.start(); - graph.start(); - graph.start(); - graph._redraw(); + // start the physics simulation + var calculationTime = Date.now(); + var maxSteps = 1; + this._physicsTick(); + var timeRequired = Date.now() - calculationTime; + while (timeRequired < (this.renderTimestep - this.renderTime) && maxSteps < this.maxRenderSteps) { + this._physicsTick(); + timeRequired = Date.now() - calculationTime; + maxSteps++; + + } + + // start the rendering process + var renderTime = Date.now(); + this._redraw(); + this.renderTime = Date.now() - renderTime; +}; - }, this.renderTimestep); + +/** + * Schedule a animation step with the refreshrate interval. + * + * @poram {Boolean} runCalculationStep + */ +Graph.prototype.start = function() { + if (this.moving || this.xIncrement != 0 || this.yIncrement != 0 || this.zoomIncrement != 0) { + if (!this.timer) { + this.timer = window.setTimeout(this._animationStep.bind(this), this.renderTimestep); // wait this.renderTimeStep milliseconds and perform the animation step function } } else { @@ -1777,24 +1814,29 @@ Graph.prototype.start = function() { } }; + /** - * Debug function, does one step of the graph + * Move the graph according to the keyboard presses. + * + * @private */ -Graph.prototype.singleStep = function() { - if (this.moving) { - this._initializeForceCalculation(); - this._discreteStepNodes(); - - var vmin = this.constants.minVelocity; - this.moving = this._isMoving(vmin); - this._redraw(); +Graph.prototype._handleNavigation = function() { + if (this.xIncrement != 0 || this.yIncrement != 0) { + var translation = this._getTranslation(); + this._setTranslation(translation.x+this.xIncrement, translation.y+this.yIncrement); + } + if (this.zoomIncrement != 0) { + var center = { + x: this.frame.canvas.clientWidth / 2, + y: this.frame.canvas.clientHeight / 2 + }; + this._zoom(this.scale*(1 + this.zoomIncrement), center); } }; - /** - * Freeze the animation + * Freeze the _animationStep */ Graph.prototype.toggleFreeze = function() { if (this.freezeSimulation == false) { @@ -1807,24 +1849,43 @@ Graph.prototype.toggleFreeze = function() { }; + +Graph.prototype._configureSmoothCurves = function() { + if (this.constants.smoothCurves == true) { + this._createBezierNodes(); + } + else { + // delete the support nodes + this.sectors['support']['nodes'] = {}; + for (var edgeId in this.edges) { + if (this.edges.hasOwnProperty(edgeId)) { + this.edges[edgeId].smooth = false; + this.edges[edgeId].via = null; + } + } + } + this._updateCalculationNodes(); + this.moving = true; + this.start(); +}; + Graph.prototype._createBezierNodes = function() { if (this.constants.smoothCurves == true) { for (var edgeId in this.edges) { if (this.edges.hasOwnProperty(edgeId)) { var edge = this.edges[edgeId]; - if (edge.smooth == true) { - if (edge.via == null) { - var nodeId = "edgeId:".concat(edge.id); - this.sectors['support']['nodes'][nodeId] = new Node( - {id:nodeId, - mass:1, - shape:'circle', - internalMultiplier:1, - damping: 1.2},{},{},this.constants); - edge.via = this.sectors['support']['nodes'][nodeId]; - edge.via.parentEdgeId = edge.id; - edge.positionBezierNode(); - } + if (edge.via == null) { + edge.smooth = true; + var nodeId = "edgeId:".concat(edge.id); + this.sectors['support']['nodes'][nodeId] = new Node( + {id:nodeId, + mass:1, + shape:'circle', + internalMultiplier:1 + },{},{},this.constants); + edge.via = this.sectors['support']['nodes'][nodeId]; + edge.via.parentEdgeId = edge.id; + edge.positionBezierNode(); } } } @@ -1838,7 +1899,7 @@ Graph.prototype._initializeMixinLoaders = function () { Graph.prototype[mixinFunction] = graphMixinLoaders[mixinFunction]; } } -} +}; diff --git a/src/graph/Node.js b/src/graph/Node.js index ba86acde..83c372fb 100644 --- a/src/graph/Node.js +++ b/src/graph/Node.js @@ -34,6 +34,7 @@ function Node(properties, imagelist, grouplist, constants) { this.fontSize = constants.nodes.fontSize; this.fontFace = constants.nodes.fontFace; this.fontColor = constants.nodes.fontColor; + this.fontDrawThreshold = 3; this.color = constants.nodes.color; @@ -54,11 +55,15 @@ function Node(properties, imagelist, grouplist, constants) { this.radiusMax = constants.nodes.radiusMax; this.imagelist = imagelist; - this.grouplist = grouplist; - this.dampingBase = 0.9; - this.damping = 0.9; // this is manipulated in the updateDamping function + // physics properties + this.fx = 0.0; // external force x + this.fy = 0.0; // external force y + this.vx = 0.0; // velocity x + this.vy = 0.0; // velocity y + this.minForce = constants.minForce; + this.damping = constants.physics.damping; this.mass = 1; // kg this.setProperties(properties, constants); @@ -73,15 +78,9 @@ function Node(properties, imagelist, grouplist, constants) { this.maxNodeSizeIncrements = constants.clustering.maxNodeSizeIncrements; this.growthIndicator = 0; - // mass, force, velocity - - this.fx = 0.0; // external force x - this.fy = 0.0; // external force y - this.vx = 0.0; // velocity x - this.vy = 0.0; // velocity y - this.minForce = constants.minForce; - + // variables to tell the node about the graph. this.graphScaleInv = 1; + this.graphScale = 1; this.canvasTopLeft = {"x": -300, "y": -300}; this.canvasBottomRight = {"x": 300, "y": 300}; this.parentEdgeId = null; @@ -445,15 +444,7 @@ Node.prototype.isFixed = function() { */ // TODO: replace this method with calculating the kinetic energy Node.prototype.isMoving = function(vmin) { - - if (Math.abs(this.vx) > vmin || Math.abs(this.vy) > vmin) { -// console.log(vmin,this.vx,this.vy); - return true; - } - else { - return false; - } - //return (Math.abs(this.vx) > vmin || Math.abs(this.vy) > vmin); + return (Math.abs(this.vx) > vmin || Math.abs(this.vy) > vmin); }; /** @@ -902,7 +893,7 @@ Node.prototype._drawText = function (ctx) { Node.prototype._label = function (ctx, text, x, y, align, baseline) { - if (text) { + if (text && this.fontSize * this.graphScale > this.fontDrawThreshold) { ctx.font = (this.selected ? "bold " : "") + this.fontSize + "px " + this.fontFace; ctx.fillStyle = this.fontColor || "black"; ctx.textAlign = align || "center"; @@ -956,7 +947,7 @@ Node.prototype.inArea = function() { else { return true; } -} +}; /** * checks if the core of the node is in the display area, this is used for opening clusters around zoom @@ -967,7 +958,7 @@ Node.prototype.inView = function() { this.x < this.canvasBottomRight.x && this.y >= this.canvasTopLeft.y && this.y < this.canvasBottomRight.y); -} +}; /** * This allows the zoom level of the graph to influence the rendering @@ -979,6 +970,7 @@ Node.prototype.inView = function() { */ Node.prototype.setScaleAndPos = function(scale,canvasTopLeft,canvasBottomRight) { this.graphScaleInv = 1.0/scale; + this.graphScale = scale; this.canvasTopLeft = canvasTopLeft; this.canvasBottomRight = canvasBottomRight; }; @@ -991,17 +983,9 @@ Node.prototype.setScaleAndPos = function(scale,canvasTopLeft,canvasBottomRight) */ Node.prototype.setScale = function(scale) { this.graphScaleInv = 1.0/scale; + this.graphScale = scale; }; -/** - * This function updates the damping parameter of the node based on its mass, - * heavier nodes have more damping. - * - * @param {Number} numberOfNodes - */ -Node.prototype.updateDamping = function() { - this.damping = Math.min(Math.max(1.2,this.dampingBase),this.dampingBase + 0.01*this.growthIndicator); -}; /** diff --git a/src/graph/css/graph-manipulation.css b/src/graph/css/graph-manipulation.css new file mode 100644 index 00000000..6d0b41ce --- /dev/null +++ b/src/graph/css/graph-manipulation.css @@ -0,0 +1,128 @@ +div.graph-manipulationDiv { + border-width:0px; + border-bottom: 1px; + border-style:solid; + border-color: #d6d9d8; + background: #ffffff; /* Old browsers */ + background: -moz-linear-gradient(top, #ffffff 0%, #fcfcfc 48%, #fafafa 50%, #fcfcfc 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(48%,#fcfcfc), color-stop(50%,#fafafa), color-stop(100%,#fcfcfc)); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, #ffffff 0%,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(top, #ffffff 0%,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%); /* Opera 11.10+ */ + background: -ms-linear-gradient(top, #ffffff 0%,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%); /* IE10+ */ + background: linear-gradient(to bottom, #ffffff 0%,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%); /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#fcfcfc',GradientType=0 ); /* IE6-9 */ + + width: 600px; + height:30px; + z-index:10; + position:absolute; +} + +div.graph-manipulation-editMode { + height:30px; + z-index:10; + position:absolute; + margin-top:20px; +} + +div.graph-manipulation-closeDiv { + height:30px; + width:30px; + z-index:11; + position:absolute; + margin-top:3px; + margin-left:590px; + background-position: 0px 0px; + background-repeat:no-repeat; + background-image: url("../../dist/img/cross.png"); + cursor: pointer; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +span.graph-manipulationUI { + font-family: verdana; + font-size: 12px; + -moz-border-radius: 15px; + border-radius: 15px; + display:inline-block; + background-position: 0px 0px; + background-repeat:no-repeat; + height:24px; + margin: -14px 0px 0px 10px; + vertical-align:middle; + cursor: pointer; + padding: 0px 8px 0px 8px; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +span.graph-manipulationUI:hover { + box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.20); +} + +span.graph-manipulationUI:active { + box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.50); +} + +span.graph-manipulationUI.back { + background-image: url("../../dist/img/backIcon.png"); +} + +span.graph-manipulationUI.none:hover { + box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.0); + cursor: default; +} +span.graph-manipulationUI.none:active { + box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.0); +} +span.graph-manipulationUI.none { + padding: 0px 0px 0px 0px; +} +span.graph-manipulationUI.notification{ + margin: 2px; + font-weight: bold; +} + +span.graph-manipulationUI.add { + background-image: url("../../dist/img/addNodeIcon.png"); +} + +span.graph-manipulationUI.edit { + background-image: url("../../dist/img/editIcon.png"); +} + +span.graph-manipulationUI.edit.editmode { + background-color: #fcfcfc; + border-style:solid; + border-width:1px; + border-color: #cccccc; +} + +span.graph-manipulationUI.connect { + background-image: url("../../dist/img/connectIcon.png"); +} + +span.graph-manipulationUI.delete { + background-image: url("../../dist/img/deleteIcon.png"); +} +/* top right bottom left */ +span.graph-manipulationLabel { + margin: 0px 0px 0px 23px; + line-height: 25px; +} +div.graph-seperatorLine { + display:inline-block; + width:1px; + height:20px; + background-color: #bdbdbd; + margin: 5px 7px 0px 15px; +} \ No newline at end of file diff --git a/src/graph/css/graph-navigation.css b/src/graph/css/graph-navigation.css new file mode 100644 index 00000000..f72c496a --- /dev/null +++ b/src/graph/css/graph-navigation.css @@ -0,0 +1,62 @@ +div.graph-navigation { + width:34px; + height:34px; + z-index:10; + -moz-border-radius: 17px; + border-radius: 17px; + position:absolute; + display:inline-block; + background-position: 2px 2px; + background-repeat:no-repeat; + cursor: pointer; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +div.graph-navigation:hover { + box-shadow: 0px 0px 3px 3px rgba(56, 207, 21, 0.30); +} + +div.graph-navigation:active { + box-shadow: 0px 0px 1px 3px rgba(56, 207, 21, 0.95); +} + +div.graph-navigation.up { + background-image: url("../../dist/img/upArrow.png"); + margin-top:520px; + margin-left:55px; +} +div.graph-navigation.down { + background-image: url("../../dist/img/downArrow.png"); + margin-top:560px; + margin-left:55px; +} +div.graph-navigation.left { + background-image: url("../../dist/img/leftArrow.png"); + margin-top:560px; + margin-left:15px; +} +div.graph-navigation.right { + background-image: url("../../dist/img/rightArrow.png"); + margin-top:560px; + margin-left:95px; +} +div.graph-navigation.zoomIn { + background-image: url("../../dist/img/plus.png"); + margin-top:560px; + margin-left:555px; +} +div.graph-navigation.zoomOut { + background-image: url("../../dist/img/minus.png"); + margin-top:560px; + margin-left:515px; +} +div.graph-navigation.zoomExtends { + background-image: url("../../dist/img/zoomExtends.png"); + margin-top:520px; + margin-left:555px; +} \ No newline at end of file diff --git a/src/graph/graphMixins/ClusterMixin.js b/src/graph/graphMixins/ClusterMixin.js index b84dd84f..0ca8eb5f 100644 --- a/src/graph/graphMixins/ClusterMixin.js +++ b/src/graph/graphMixins/ClusterMixin.js @@ -57,6 +57,7 @@ var ClusterMixin = { if (level > 0 && reposition == true) { this.repositionNodes(); } + this._updateCalculationNodes(); }, /** @@ -86,7 +87,7 @@ var ClusterMixin = { // update the index list, dynamic edges and labels this._updateNodeIndexList(); this._updateDynamicEdges(); - this._setCalculationNodes(); + this._updateCalculationNodes(); this.updateLabels(); } @@ -198,7 +199,7 @@ var ClusterMixin = { } } - this._setCalculationNodes(); + this._updateCalculationNodes(); }, /** @@ -283,7 +284,7 @@ var ClusterMixin = { for (var i = 0; i < this.nodeIndices.length; i++) { var node = this.nodes[this.nodeIndices[i]]; this._expandClusterNode(node,recursive,force); - this._setCalculationNodes(); + this._updateCalculationNodes(); } }, @@ -1044,7 +1045,7 @@ var ClusterMixin = { for (var i = 0; i < this.nodeIndices.length; i++) { var node = this.nodes[this.nodeIndices[i]]; if ((node.xFixed == false || node.yFixed == false) && this.createNodeOnClick != true) { - var radius = this.constants.physics.springLength * (1 + 0.1*node.mass); + var radius = this.constants.physics.springLength * node.mass; var angle = 2 * Math.PI * Math.random(); if (node.xFixed == false) {node.x = radius * Math.cos(angle);} if (node.yFixed == false) {node.y = radius * Math.sin(angle);} diff --git a/src/graph/graphMixins/ManipulationMixin.js b/src/graph/graphMixins/ManipulationMixin.js index 7e734f68..d1dfc0c1 100644 --- a/src/graph/graphMixins/ManipulationMixin.js +++ b/src/graph/graphMixins/ManipulationMixin.js @@ -15,7 +15,13 @@ var manipulationMixin = { } }, - + /** + * Manipulation UI temporarily overloads certain functions to extend or replace them. To be able to restore + * these functions to their original functionality, we saved them in this.cachedFunctions. + * This function restores these functions to their original function. + * + * @private + */ _restoreOverloadedFunctions : function() { for (var functionName in this.cachedFunctions) { if (this.cachedFunctions.hasOwnProperty(functionName)) { @@ -24,15 +30,27 @@ var manipulationMixin = { } }, - + /** + * Enable or disable edit-mode. + * + * @private + */ _toggleEditMode : function() { this.editMode = !this.editMode; - var toolbar = document.getElementById("graph-manipulationDiv") + var toolbar = document.getElementById("graph-manipulationDiv"); + var closeDiv = document.getElementById("graph-manipulation-closeDiv"); + var editModeDiv = document.getElementById("graph-manipulation-editMode"); if (this.editMode == true) { toolbar.style.display="block"; + closeDiv.style.display="block"; + editModeDiv.style.display="none"; + closeDiv.onclick = this._toggleEditMode.bind(this); } else { toolbar.style.display="none"; + closeDiv.style.display="none"; + editModeDiv.style.display="block"; + closeDiv.onclick = null; } this._createManipulatorBar() }, @@ -62,37 +80,51 @@ var manipulationMixin = { } // add the icons to the manipulator div this.manipulationDiv.innerHTML = "" + - "Add Node" + - "
    " + - "Add Link"; + "" + + "Add Node" + + "
    " + + "" + + "Add Link"; if (this._getSelectedNodeCount() == 1 && this.triggerFunctions.edit) { this.manipulationDiv.innerHTML += "" + - "
    " + - "Edit Node"; + "
    " + + "" + + "Edit Node"; } if (this._selectionIsEmpty() == false) { this.manipulationDiv.innerHTML += "" + - "
    " + - "Delete selected"; + "
    " + + "" + + "Delete selected"; } // bind the icons - var addNodeButton = document.getElementById("manipulate-addNode"); + var addNodeButton = document.getElementById("graph-manipulate-addNode"); addNodeButton.onclick = this._createAddNodeToolbar.bind(this); - var addEdgeButton = document.getElementById("manipulate-connectNode"); + var addEdgeButton = document.getElementById("graph-manipulate-connectNode"); addEdgeButton.onclick = this._createAddEdgeToolbar.bind(this); if (this._getSelectedNodeCount() == 1 && this.triggerFunctions.edit) { - var editButton = document.getElementById("manipulate-editNode"); + var editButton = document.getElementById("graph-manipulate-editNode"); editButton.onclick = this._editNode.bind(this); } if (this._selectionIsEmpty() == false) { - var deleteButton = document.getElementById("manipulate-delete"); + var deleteButton = document.getElementById("graph-manipulate-delete"); deleteButton.onclick = this._deleteSelected.bind(this); } + var closeDiv = document.getElementById("graph-manipulation-closeDiv"); + closeDiv.onclick = this._toggleEditMode.bind(this); + this.boundFunction = this._createManipulatorBar.bind(this); this.on('select', this.boundFunction); } + else { + this.editModeDiv.innerHTML = "" + + "" + + "Edit" + var editModeButton = document.getElementById("graph-manipulate-editModeButton"); + editModeButton.onclick = this._toggleEditMode.bind(this); + } }, @@ -109,12 +141,14 @@ var manipulationMixin = { // create the toolbar contents this.manipulationDiv.innerHTML = "" + - "Back" + - "
    " + - "Click in an empty space to place a new node"; + "" + + "Back" + + "
    " + + "" + + "Click in an empty space to place a new node"; // bind the icon - var backButton = document.getElementById("manipulate-back"); + var backButton = document.getElementById("graph-manipulate-back"); backButton.onclick = this._createManipulatorBar.bind(this); // we use the boundFunction so we can reference it when we unbind it from the "select" event. @@ -141,12 +175,14 @@ var manipulationMixin = { this.blockConnectingEdgeSelection = true; this.manipulationDiv.innerHTML = "" + - "Back" + - "
    " + - "Click on a node and drag the edge to another node."; + "" + + "Back" + + "
    " + + "" + + "Click on a node and drag the edge to another node to connect them."; // bind the icon - var backButton = document.getElementById("manipulate-back"); + var backButton = document.getElementById("graph-manipulate-back"); backButton.onclick = this._createManipulatorBar.bind(this); // we use the boundFunction so we can reference it when we unbind it from the "select" event. @@ -273,7 +309,6 @@ var manipulationMixin = { } } else { - console.log("didnt use funciton") this.createNodeOnClick = true; this.nodesData.add(defaultData); this.createNodeOnClick = false; @@ -373,6 +408,7 @@ var manipulationMixin = { this.triggerFunctions.delete(data, function (finalizedData) { me.edgesData.remove(finalizedData.edges); me.nodesData.remove(finalizedData.nodes); + this._unselectAll(); me.moving = true; me.start(); }); @@ -384,6 +420,7 @@ var manipulationMixin = { else { this.edgesData.remove(selectedEdges); this.nodesData.remove(selectedNodes); + this._unselectAll(); this.moving = true; this.start(); } diff --git a/src/graph/graphMixins/MixinLoader.js b/src/graph/graphMixins/MixinLoader.js index 325febf9..f025b08a 100644 --- a/src/graph/graphMixins/MixinLoader.js +++ b/src/graph/graphMixins/MixinLoader.js @@ -59,6 +59,7 @@ var graphMixinLoaders = { this.constants.physics.centralGravity = this.constants.physics.barnesHut.centralGravity; this.constants.physics.springLength = this.constants.physics.barnesHut.springLength; this.constants.physics.springConstant = this.constants.physics.barnesHut.springConstant; + this.constants.physics.damping = this.constants.physics.barnesHut.damping; this.constants.physics.springGrowthPerMass = this.constants.physics.barnesHut.springGrowthPerMass; this._loadMixin(barnesHutMixin); @@ -70,6 +71,7 @@ var graphMixinLoaders = { this.constants.physics.centralGravity = this.constants.physics.repulsion.centralGravity; this.constants.physics.springLength = this.constants.physics.repulsion.springLength; this.constants.physics.springConstant = this.constants.physics.repulsion.springConstant; + this.constants.physics.damping = this.constants.physics.repulsion.damping; this.constants.physics.springGrowthPerMass = this.constants.physics.repulsion.springGrowthPerMass; this._loadMixin(repulsionMixin); @@ -103,12 +105,7 @@ var graphMixinLoaders = { "nodeIndices":[], "formationScale": 1.0, "drawingNode": undefined }; - this.sectors["frozen"] = { }, - this.sectors["navigation"] = {"nodes":{}, - "edges":{}, - "nodeIndices":[], - "formationScale": 1.0, - "drawingNode": undefined }; + this.sectors["frozen"] = {}, this.sectors["support"] = {"nodes":{}, "edges":{}, "nodeIndices":[], @@ -143,8 +140,7 @@ var graphMixinLoaders = { this.blockConnectingEdgeSelection = false; this.forceAppendSelection = false - - if (this.constants.dataManipulationToolbar.enabled == true) { + if (this.constants.dataManipulation.enabled == true) { // load the manipulator HTML elements. All styling done in css. if (this.manipulationDiv === undefined) { this.manipulationDiv = document.createElement('div'); @@ -158,6 +154,28 @@ var graphMixinLoaders = { } this.containerElement.insertBefore(this.manipulationDiv, this.frame); } + + if (this.editModeDiv === undefined) { + this.editModeDiv = document.createElement('div'); + this.editModeDiv.className = 'graph-manipulation-editMode'; + this.editModeDiv.id = 'graph-manipulation-editMode'; + if (this.editMode == true) { + this.editModeDiv.style.display = "none"; + } + else { + this.editModeDiv.style.display = "block"; + } + this.containerElement.insertBefore(this.editModeDiv, this.frame); + } + + if (this.closeDiv === undefined) { + this.closeDiv = document.createElement('div'); + this.closeDiv.className = 'graph-manipulation-closeDiv'; + this.closeDiv.id = 'graph-manipulation-closeDiv'; + this.closeDiv.style.display = this.manipulationDiv.style.display; + this.containerElement.insertBefore(this.closeDiv, this.frame); + } + // load the manipulation functions this._loadMixin(manipulationMixin); @@ -166,9 +184,17 @@ var graphMixinLoaders = { } else { if (this.manipulationDiv !== undefined) { + // removes all the bindings and overloads this._createManipulatorBar(); + // remove the manipulation divs this.containerElement.removeChild(this.manipulationDiv); + this.containerElement.removeChild(this.editModeDiv); + this.containerElement.removeChild(this.closeDiv); + this.manipulationDiv = undefined; + this.editModeDiv = undefined; + this.closeDiv = undefined; + // remove the mixin functions this._clearMixin(manipulationMixin); } } @@ -183,24 +209,11 @@ var graphMixinLoaders = { _loadNavigationControls : function() { this._loadMixin(NavigationMixin); + // the clean function removes the button divs, this is done to remove the bindings. + this._cleanNavigation(); if (this.constants.navigation.enabled == true) { this._loadNavigationElements(); } - }, - - - /** - * this function exists to avoid errors when not loading the navigation system - */ - _relocateNavigation : function() { - // empty, is overloaded by navigation system - }, + } - - /** - * this function exists to avoid errors when not loading the navigation system - */ - _unHighlightAll : function() { - // empty, is overloaded by the navigation system - } } diff --git a/src/graph/graphMixins/NavigationMixin.js b/src/graph/graphMixins/NavigationMixin.js index 20540622..60897987 100644 --- a/src/graph/graphMixins/NavigationMixin.js +++ b/src/graph/graphMixins/NavigationMixin.js @@ -4,35 +4,15 @@ var NavigationMixin = { - /** - * This function moves the navigation controls if the canvas size has been changed. If the arugments - * verticaAlignTop and horizontalAlignLeft are false, the correction will be made - * - * @private - */ - _relocateNavigation : function() { - if (this.sectors !== undefined) { - var xOffset = this.navigationClientWidth - this.frame.canvas.clientWidth; - var yOffset = this.navigationClientHeight - this.frame.canvas.clientHeight; - this.navigationClientWidth = this.frame.canvas.clientWidth; - this.navigationClientHeight = this.frame.canvas.clientHeight; - var node = null; - - for (var nodeId in this.sectors["navigation"]["nodes"]) { - if (this.sectors["navigation"]["nodes"].hasOwnProperty(nodeId)) { - node = this.sectors["navigation"]["nodes"][nodeId]; - if (!node.horizontalAlignLeft) { - node.x -= xOffset; - } - if (!node.verticalAlignTop) { - node.y -= yOffset; - } - } - } + _cleanNavigation : function() { + // clean up previosu navigation items + var wrapper = document.getElementById('graph-navigation_wrapper'); + if (wrapper != null) { + this.containerElement.removeChild(wrapper); } + document.onmouseup = null; }, - /** * Creation of the navigation controls nodes. They are drawn over the rest of the nodes and are not affected by scale and translation * they have a triggerFunction which is called on click. If the position of the navigation controls is dependent @@ -42,83 +22,45 @@ var NavigationMixin = { * @private */ _loadNavigationElements : function() { - var DIR = this.constants.navigation.iconPath; - this.navigationClientWidth = this.frame.canvas.clientWidth; - this.navigationClientHeight = this.frame.canvas.clientHeight; - if (this.navigationClientWidth === undefined) { - this.navigationClientWidth = 0; - this.navigationClientHeight = 0; + this._cleanNavigation(); + + this.navigationDivs = {}; + var navigationDivs = ['up','down','left','right','zoomIn','zoomOut','zoomExtends']; + var navigationDivActions = ['_moveUp','_moveDown','_moveLeft','_moveRight','_zoomIn','_zoomOut','zoomToFit']; + + this.navigationDivs['wrapper'] = document.createElement('div'); + this.navigationDivs['wrapper'].id = "graph-navigation_wrapper"; + this.containerElement.insertBefore(this.navigationDivs['wrapper'],this.frame); + + for (var i = 0; i < navigationDivs.length; i++) { + this.navigationDivs[navigationDivs[i]] = document.createElement('div'); + this.navigationDivs[navigationDivs[i]].id = "graph-navigation_" + navigationDivs[i]; + this.navigationDivs[navigationDivs[i]].className = "graph-navigation " + navigationDivs[i]; + this.navigationDivs['wrapper'].appendChild(this.navigationDivs[navigationDivs[i]]); + this.navigationDivs[navigationDivs[i]].onmousedown = this[navigationDivActions[i]].bind(this); } - var offset = 15; - var intermediateOffset = 7; - var navigationNodes = [ - {id: 'navigation_up', shape: 'image', image: DIR + '/uparrow.png', triggerFunction: "_moveUp", - verticalAlignTop: false, x: 45 + offset + intermediateOffset, y: this.navigationClientHeight - 45 - offset - intermediateOffset}, - {id: 'navigation_down', shape: 'image', image: DIR + '/downarrow.png', triggerFunction: "_moveDown", - verticalAlignTop: false, x: 45 + offset + intermediateOffset, y: this.navigationClientHeight - 15 - offset}, - {id: 'navigation_left', shape: 'image', image: DIR + '/leftarrow.png', triggerFunction: "_moveLeft", - verticalAlignTop: false, x: 15 + offset, y: this.navigationClientHeight - 15 - offset}, - {id: 'navigation_right', shape: 'image', image: DIR + '/rightarrow.png',triggerFunction: "_moveRight", - verticalAlignTop: false, x: 75 + offset + 2 * intermediateOffset, y: this.navigationClientHeight - 15 - offset}, - - {id: 'navigation_plus', shape: 'image', image: DIR + '/plus.png', triggerFunction: "_zoomIn", - verticalAlignTop: false, horizontalAlignLeft: false, - x: this.navigationClientWidth - 45 - offset - intermediateOffset, y: this.navigationClientHeight - 15 - offset}, - {id: 'navigation_min', shape: 'image', image: DIR + '/minus.png', triggerFunction: "_zoomOut", - verticalAlignTop: false, horizontalAlignLeft: false, - x: this.navigationClientWidth - 15 - offset, y: this.navigationClientHeight - 15 - offset}, - {id: 'navigation_zoomExtends', shape: 'image', image: DIR + '/zoomExtends.png', triggerFunction: "zoomToFit", - verticalAlignTop: false, horizontalAlignLeft: false, - x: this.navigationClientWidth - 15 - offset, y: this.navigationClientHeight - 45 - offset - intermediateOffset} - ]; - - var nodeObj = null; - for (var i = 0; i < navigationNodes.length; i++) { - nodeObj = this.sectors["navigation"]['nodes']; - nodeObj[navigationNodes[i]['id']] = new Node(navigationNodes[i], this.images, this.groups, this.constants); - } - }, + document.onmouseup = this._stopMovement.bind(this); + }, /** - * By setting the clustersize to be larger than 1, we use the clustering drawing method - * to illustrate the buttons are presed. We call this highlighting. + * this stops all movement induced by the navigation buttons * - * @param {String} elementId * @private */ - _highlightNavigationElement : function(elementId) { - if (this.sectors["navigation"]["nodes"].hasOwnProperty(elementId)) { - this.sectors["navigation"]["nodes"][elementId].clusterSize = 2; - } + _stopMovement : function() { + this._xStopMoving(); + this._yStopMoving(); + this._stopZoom(); }, /** - * Reverting back to a normal button + * stops the actions performed by page up and down etc. * - * @param {String} elementId - * @private - */ - _unHighlightNavigationElement : function(elementId) { - if (this.sectors["navigation"]["nodes"].hasOwnProperty(elementId)) { - this.sectors["navigation"]["nodes"][elementId].clusterSize = 1; - } - }, - - /** - * un-highlight (for lack of a better term) all navigation controls elements + * @param event * @private */ - _unHighlightAll : function() { - for (var nodeId in this.sectors['navigation']['nodes']) { - if (this.sectors['navigation']['nodes'].hasOwnProperty(nodeId)) { - this._unHighlightNavigationElement(nodeId); - } - } - }, - - _preventDefault : function(event) { if (event !== undefined) { if (event.preventDefault) { @@ -139,7 +81,7 @@ var NavigationMixin = { * @private */ _moveUp : function(event) { - this._highlightNavigationElement("navigation_up"); + console.log("here") this.yIncrement = this.constants.keyboard.speed.y; this.start(); // if there is no node movement, the calculation wont be done this._preventDefault(event); @@ -151,7 +93,6 @@ var NavigationMixin = { * @private */ _moveDown : function(event) { - this._highlightNavigationElement("navigation_down"); this.yIncrement = -this.constants.keyboard.speed.y; this.start(); // if there is no node movement, the calculation wont be done this._preventDefault(event); @@ -163,7 +104,6 @@ var NavigationMixin = { * @private */ _moveLeft : function(event) { - this._highlightNavigationElement("navigation_left"); this.xIncrement = this.constants.keyboard.speed.x; this.start(); // if there is no node movement, the calculation wont be done this._preventDefault(event); @@ -175,7 +115,6 @@ var NavigationMixin = { * @private */ _moveRight : function(event) { - this._highlightNavigationElement("navigation_right"); this.xIncrement = -this.constants.keyboard.speed.y; this.start(); // if there is no node movement, the calculation wont be done this._preventDefault(event); @@ -187,7 +126,6 @@ var NavigationMixin = { * @private */ _zoomIn : function(event) { - this._highlightNavigationElement("navigation_plus"); this.zoomIncrement = this.constants.keyboard.speed.zoom; this.start(); // if there is no node movement, the calculation wont be done this._preventDefault(event); @@ -199,7 +137,6 @@ var NavigationMixin = { * @private */ _zoomOut : function() { - this._highlightNavigationElement("navigation_min"); this.zoomIncrement = -this.constants.keyboard.speed.zoom; this.start(); // if there is no node movement, the calculation wont be done this._preventDefault(event); @@ -211,9 +148,6 @@ var NavigationMixin = { * @private */ _stopZoom : function() { - this._unHighlightNavigationElement("navigation_plus"); - this._unHighlightNavigationElement("navigation_min"); - this.zoomIncrement = 0; }, @@ -223,9 +157,6 @@ var NavigationMixin = { * @private */ _yStopMoving : function() { - this._unHighlightNavigationElement("navigation_up"); - this._unHighlightNavigationElement("navigation_down"); - this.yIncrement = 0; }, @@ -235,9 +166,6 @@ var NavigationMixin = { * @private */ _xStopMoving : function() { - this._unHighlightNavigationElement("navigation_left"); - this._unHighlightNavigationElement("navigation_right"); - this.xIncrement = 0; } diff --git a/src/graph/graphMixins/SectorsMixin.js b/src/graph/graphMixins/SectorsMixin.js index 1661c28c..331586ef 100644 --- a/src/graph/graphMixins/SectorsMixin.js +++ b/src/graph/graphMixins/SectorsMixin.js @@ -84,19 +84,6 @@ var SectorMixin = { }, - /** - * This function sets the global references to nodes, edges and nodeIndices to - * those of the navigation controls sector. - * - * @private - */ - _switchToNavigationSector : function() { - this.nodeIndices = this.sectors["navigation"]["nodeIndices"]; - this.nodes = this.sectors["navigation"]["nodes"]; - this.edges = this.sectors["navigation"]["edges"]; - }, - - /** * This function sets the global references to nodes, edges and nodeIndices back to * those of the currently active sector. @@ -365,7 +352,7 @@ var SectorMixin = { this._updateNodeIndexList(); // we refresh the list with calulation nodes and calculation node indices. - this._setCalculationNodes(); + this._updateCalculationNodes(); } } }, @@ -477,33 +464,6 @@ var SectorMixin = { }, - /** - * This runs a function in the navigation controls sector. - * - * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors - * | we don't pass the function itself because then the "this" is the window object - * | instead of the Graph object - * @param {*} [argument] | Optional: arguments to pass to the runFunction - * @private - */ - _doInNavigationSector : function(runFunction,argument) { - this._switchToNavigationSector(); - if (argument === undefined) { - this[runFunction](); - } - else { - var args = Array.prototype.splice.call(arguments, 1); - if (args.length > 1) { - this[runFunction](args[0],args[1]); - } - else { - this[runFunction](argument); - } - } - this._loadLatestSector(); - }, - - /** * This runs a function in all sectors. This is used in the _redraw(). * diff --git a/src/graph/graphMixins/SelectionMixin.js b/src/graph/graphMixins/SelectionMixin.js index 01078805..01b59511 100644 --- a/src/graph/graphMixins/SelectionMixin.js +++ b/src/graph/graphMixins/SelectionMixin.js @@ -32,18 +32,6 @@ var SelectionMixin = { }, - /** - * retrieve all nodes in the navigation controls overlapping with given object - * @param {Object} object An object with parameters left, top, right, bottom - * @return {Number[]} An array with id's of the overlapping nodes - * @private - */ - _getAllNavigationNodesOverlappingWith : function (object) { - var overlappingNodes = []; - this._doInNavigationSector("_getNodesOverlappingWith",object,overlappingNodes); - return overlappingNodes; - }, - /** * Return a position object in canvasspace from a single point in screenspace * @@ -61,42 +49,6 @@ var SelectionMixin = { bottom: y}; }, - /** - * Return a position object in canvasspace from a single point in screenspace - * - * @param pointer - * @returns {{left: number, top: number, right: number, bottom: number}} - * @private - */ - _pointerToScreenPositionObject : function(pointer) { - var x = pointer.x; - var y = pointer.y; - - return {left: x, - top: y, - right: x, - bottom: y}; - }, - - - /** - * Get the top navigation controls node at the a specific point (like a click) - * - * @param {{x: Number, y: Number}} pointer - * @return {Node | null} node - * @private - */ - _getNavigationNodeAt : function (pointer) { - var screenPositionObject = this._pointerToScreenPositionObject(pointer); - var overlappingNodes = this._getAllNavigationNodesOverlappingWith(screenPositionObject); - if (overlappingNodes.length > 0) { - return this.sectors["navigation"]["nodes"][overlappingNodes[overlappingNodes.length - 1]]; - } - else { - return null; - } - }, - /** * Get the top node at the a specific point (like a click) @@ -426,15 +378,7 @@ var SelectionMixin = { * @private */ _handleTouch : function(pointer) { - if (this.constants.navigation.enabled == true) { - this.pointerPosition = pointer; - var node = this._getNavigationNodeAt(pointer); - if (node != null) { - if (this[node.triggerFunction] !== undefined) { - this[node.triggerFunction](); - } - } - } + }, @@ -506,10 +450,7 @@ var SelectionMixin = { * @private */ _handleOnRelease : function(pointer) { - this.xIncrement = 0; - this.yIncrement = 0; - this.zoomIncrement = 0; - this._unHighlightAll(); + }, diff --git a/src/graph/graphMixins/physics/PhysicsMixin.js b/src/graph/graphMixins/physics/PhysicsMixin.js index 4fb4284a..c5513761 100644 --- a/src/graph/graphMixins/physics/PhysicsMixin.js +++ b/src/graph/graphMixins/physics/PhysicsMixin.js @@ -72,7 +72,7 @@ var physicsMixin = { * * @private */ - _setCalculationNodes : function() { + _updateCalculationNodes : function() { if (this.constants.smoothCurves == true) { this.calculationNodes = {}; this.calculationNodeIndices = []; @@ -113,27 +113,28 @@ var physicsMixin = { * @private */ _calculateGravitationalForces : function() { - var dx, dy, angle, fx, fy, node, i; + var dx, dy, distance, node, i; var nodes = this.calculationNodes; var gravity = this.constants.physics.centralGravity; + var gravityForce = 0; for (i = 0; i < this.calculationNodeIndices.length; i++) { node = nodes[this.calculationNodeIndices[i]]; + node.damping = this.constants.physics.damping; // possibly add function to alter damping properties of clusters. // gravity does not apply when we are in a pocket sector if (this._sector() == "default") { dx = -node.x; dy = -node.y; + distance = Math.sqrt(dx*dx + dy*dy); + gravityForce = gravity / distance; - angle = Math.atan2(dy, dx); - fx = Math.cos(angle) * gravity; - fy = Math.sin(angle) * gravity; + node.fx = dx * gravityForce; + node.fy = dy * gravityForce; } else { - fx = 0; - fy = 0; + node.fx = 0; + node.fy = 0; } - node._setForce(fx, fy); - node.updateDamping(); } }, @@ -145,6 +146,7 @@ var physicsMixin = { */ _calculateSpringForces : function() { var edgeLength, edge, edgeId; + var dx, dy, fx, fy, springForce, length; var edges = this.edges; // forces caused by the edges, modelled as springs @@ -157,7 +159,20 @@ var physicsMixin = { edgeLength = edge.length; // this implies that the edges between big clusters are longer edgeLength += (edge.to.clusterSize + edge.from.clusterSize - 2) * this.constants.clustering.edgeGrowth; - this._calculateSpringForce(edge.from,edge.to,edgeLength); + + dx = (edge.from.x - edge.to.x); + dy = (edge.from.y - edge.to.y); + length = Math.sqrt(dx * dx + dy * dy); + + springForce = this.constants.physics.springConstant * (edgeLength - length) / length; + + fx = dx * springForce; + fy = dy * springForce; + + edge.from.fx += fx; + edge.from.fy += fy; + edge.to.fx -= fx; + edge.to.fy -= fy; } } } @@ -211,19 +226,20 @@ var physicsMixin = { * @private */ _calculateSpringForce : function(node1,node2,edgeLength) { - var dx, dy, angle, fx, fy, springForce, length; + var dx, dy, fx, fy, springForce, length; dx = (node1.x - node2.x); dy = (node1.y - node2.y); length = Math.sqrt(dx * dx + dy * dy); - angle = Math.atan2(dy, dx); - springForce = this.constants.physics.springConstant * (edgeLength - length); + springForce = this.constants.physics.springConstant * (edgeLength - length) / length; - fx = Math.cos(angle) * springForce; - fy = Math.sin(angle) * springForce; + fx = dx * springForce; + fy = dy * springForce; - node1._addForce(fx, fy); - node2._addForce(-fx, -fy); + node1.fx += fx; + node1.fy += fy; + node2.fx -= fx; + node2.fy -= fy; } } \ No newline at end of file diff --git a/src/graph/graphMixins/physics/barnesHut.js b/src/graph/graphMixins/physics/barnesHut.js index a7646213..9e658c8c 100644 --- a/src/graph/graphMixins/physics/barnesHut.js +++ b/src/graph/graphMixins/physics/barnesHut.js @@ -50,49 +50,47 @@ var barnesHutMixin = { dy = parentBranch.centerOfMass.y - node.y; distance = Math.sqrt(dx * dx + dy * dy); - if (distance > 0) { // distance is 0 if it looks to apply a force on itself. - // BarnesHut condition - if (distance * parentBranch.calcSize < this.constants.physics.barnesHut.theta) { - // Did not pass the condition, go into children if available - if (parentBranch.childrenCount == 4) { - this._getForceContribution(parentBranch.children.NW,node); - this._getForceContribution(parentBranch.children.NE,node); - this._getForceContribution(parentBranch.children.SW,node); - this._getForceContribution(parentBranch.children.SE,node); - } - else { // parentBranch must have only one node, if it was empty we wouldnt be here - if (parentBranch.children.data.id != node.id) { // if it is not self - this._getForceOnNode(parentBranch, node, dx ,dy, distance); + // BarnesHut condition + // original condition : s/d < theta = passed === d/s > 1/theta = passed + // calcSize = 1/s --> d * 1/s > 1/theta = passed + if (distance * parentBranch.calcSize > this.constants.physics.barnesHut.theta) { + // duplicate code to reduce function calls to speed up program + if (distance == 0) { + distance = 0.5*Math.random(); + dx = distance; + } + var gravityForce = this.constants.physics.barnesHut.gravitationalConstant * parentBranch.mass * node.mass / (distance * distance * distance); + var fx = dx * gravityForce; + var fy = dy * gravityForce; + node.fx += fx; + node.fy += fy; + } + else { + // Did not pass the condition, go into children if available + if (parentBranch.childrenCount == 4) { + this._getForceContribution(parentBranch.children.NW,node); + this._getForceContribution(parentBranch.children.NE,node); + this._getForceContribution(parentBranch.children.SW,node); + this._getForceContribution(parentBranch.children.SE,node); + } + else { // parentBranch must have only one node, if it was empty we wouldnt be here + if (parentBranch.children.data.id != node.id) { // if it is not self + // duplicate code to reduce function calls to speed up program + if (distance == 0) { + distance = 0.5*Math.random(); + dx = distance; } + var gravityForce = this.constants.physics.barnesHut.gravitationalConstant * parentBranch.mass * node.mass / (distance * distance * distance); + var fx = dx * gravityForce; + var fy = dy * gravityForce; + node.fx += fx; + node.fy += fy; } } - else { - this._getForceOnNode(parentBranch, node, dx ,dy, distance); - } } } }, - /** - * The gravitational force applied on the node by the mass of the branch. - * - * @param parentBranch - * @param node - * @param dx - * @param dy - * @param distance - * @private - */ - _getForceOnNode : function(parentBranch, node, dx ,dy, distance) { - // even if the parentBranch only has one node, its Center of Mass is at the right place (the node in this case). - var gravityForce = this.constants.physics.barnesHut.gravitationalConstant * parentBranch.mass * node.mass / (distance * distance); - var angle = Math.atan2(dy, dx); - var fx = Math.cos(angle) * gravityForce; - var fy = Math.sin(angle) * gravityForce; - node._addForce(fx, fy); - }, - - /** * This function constructs the barnesHut tree recursively. It creates the root, splits it and starts placing the nodes. * @@ -177,7 +175,7 @@ var barnesHutMixin = { // update the mass of the branch. this._updateBranchMass(parentBranch,node); } - //console.log(parentBranch.children.NW.range.maxX,parentBranch.children.NW.range.maxY, node.x,node.y); + if (parentBranch.children.NW.range.maxX > node.x) { // in NW or SW if (parentBranch.children.NW.range.maxY > node.y) { // in NW this._placeInRegion(parentBranch,node,"NW"); @@ -209,7 +207,9 @@ var barnesHutMixin = { // we move one node a pixel and we do not put it in the tree. if (parentBranch.children[region].children.data.x == node.x && parentBranch.children[region].children.data.y == node.y) { - node.x += 0.1; + node.x += Math.random(); + node.y += Math.random(); + this._placeInTree(parentBranch,node, true); } else { this._splitBranch(parentBranch.children[region]); diff --git a/src/graph/graphMixins/physics/repulsion.js b/src/graph/graphMixins/physics/repulsion.js index c1bc805f..dccfb9c4 100644 --- a/src/graph/graphMixins/physics/repulsion.js +++ b/src/graph/graphMixins/physics/repulsion.js @@ -41,8 +41,6 @@ var repulsionMixin = { minimumDistance = (combinedClusterSize == 0) ? nodeDistance : (nodeDistance * (1 + combinedClusterSize * this.constants.clustering.distanceAmplification)); var a = a_base / minimumDistance; if (distance < 2*minimumDistance) { - angle = Math.atan2(dy, dx); - if (distance < 0.5*minimumDistance) { repulsingForce = 1.0; } @@ -50,17 +48,17 @@ var repulsionMixin = { repulsingForce = a * distance + b; // linear approx of 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)) } - if (this.sectors['support']['nodes'].hasOwnProperty(node1.id)) { - } - // amplify the repulsion for clusters. repulsingForce *= (combinedClusterSize == 0) ? 1 : 1 + combinedClusterSize * this.constants.clustering.forceAmplification; + repulsingForce = repulsingForce/distance; - fx = Math.cos(angle) * repulsingForce; - fy = Math.sin(angle) * repulsingForce; + fx = dx * repulsingForce; + fy = dy * repulsingForce; - node1._addForce(-fx, -fy); - node2._addForce(fx, fy); + node1.fx -= fx; + node1.fy -= fy; + node2.fx += fx; + node2.fy += fy; } } } diff --git a/src/graph/img/cross.png b/src/graph/img/cross.png new file mode 100644 index 0000000000000000000000000000000000000000..9cbd189ab6ae99ed5794c30a12ddc0480987f29f GIT binary patch literal 18303 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 literal 0 HcmV?d00001 From 9d225542b9368859ac19794eddc427a784b201b3 Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Tue, 18 Feb 2014 16:37:50 +0100 Subject: [PATCH 50/52] finalized docs and zoom --- docs/graph.html | 3 ++- src/graph/Graph.js | 38 +++++++++++++++------------ src/graph/graphMixins/ClusterMixin.js | 2 +- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/docs/graph.html b/docs/graph.html index 37636cf4..8df62843 100644 --- a/docs/graph.html +++ b/docs/graph.html @@ -1305,7 +1305,8 @@ var options: { for the add and edit functions. The data the user is supplied with in these functions has been described in the code below. For the add data, you can add any and all options that are accepted for node creation as described above. The same goes for edit, however only the fields described in the code below contain information on the selected node. The callback for connect accepts any options that are used for edge creation. Only the callback for delete selected - requires the same data structure that is supplied to the user. + requires the same data structure that is supplied to the user.

    + If there is no injected function supplied for the edit operation, the button will not be shown in the toolbar.

     // If a variable is not supplied, the default value is used.
    diff --git a/src/graph/Graph.js b/src/graph/Graph.js
    index 6c0ed49b..fd402de6 100644
    --- a/src/graph/Graph.js
    +++ b/src/graph/Graph.js
    @@ -216,7 +216,7 @@ function Graph (container, data, options) {
       };
     
       // properties for the animation
    -  this.moving = false;    // True if any of the nodes have an undefined position
    +  this.moving = true;
       this.timer = undefined; // Scheduling function. Is definded in this.start();
     
       // load data (the disable start variable will be the same as the enabled clustering)
    @@ -305,7 +305,7 @@ Graph.prototype._centerGraph = function(range) {
      *
      * @param {Boolean} [initialZoom]  | zoom based on fitted formula or range, true = fitted, default = false;
      */
    -Graph.prototype.zoomToFit = function(initialZoom, doNotStart) {
    +Graph.prototype.zoomToFit = function(initialZoom, disableStart) {
       if (initialZoom === undefined) {
         initialZoom = false;
       }
    @@ -315,12 +315,23 @@ Graph.prototype.zoomToFit = function(initialZoom, doNotStart) {
       var zoomLevel;
     
       if (initialZoom == true) {
    -    if (this.constants.clustering.enabled == true &&
    +    if (this.constants.smoothCurves == true) {
    +      if (this.constants.clustering.enabled == true &&
             numberOfNodes >= this.constants.clustering.initialMaxNodes) {
    -      zoomLevel = 77.5271985 / (numberOfNodes + 187.266146) + 4.76710517e-05; // this is obtained from fitting a dataset from 5 points with scale levels that looked good.
    +        zoomLevel = 49.07548 / (numberOfNodes + 142.05338) + 9.1444e-04; // this is obtained from fitting a dataset from 5 points with scale levels that looked good.
    +      }
    +      else {
    +        zoomLevel = 12.662 / (numberOfNodes + 7.4147) + 0.0964822; // this is obtained from fitting a dataset from 5 points with scale levels that looked good.
    +      }
         }
         else {
    -      zoomLevel = 30.5062972 / (numberOfNodes + 19.93597763) + 0.08413486; // this is obtained from fitting a dataset from 5 points with scale levels that looked good.
    +      if (this.constants.clustering.enabled == true &&
    +          numberOfNodes >= this.constants.clustering.initialMaxNodes) {
    +        zoomLevel = 77.5271985 / (numberOfNodes + 187.266146) + 4.76710517e-05; // this is obtained from fitting a dataset from 5 points with scale levels that looked good.
    +      }
    +      else {
    +        zoomLevel = 30.5062972 / (numberOfNodes + 19.93597763) + 0.08413486; // this is obtained from fitting a dataset from 5 points with scale levels that looked good.
    +      }
         }
       }
       else {
    @@ -340,7 +351,7 @@ Graph.prototype.zoomToFit = function(initialZoom, doNotStart) {
       this.pinch.mousewheelScale = zoomLevel;
       this._setScale(zoomLevel);
       this._centerGraph(range);
    -  if (doNotStart == false || doNotStart === undefined) {
    +  if (disableStart == false || disableStart === undefined) {
         this.start();
       }
     };
    @@ -404,7 +415,6 @@ Graph.prototype.setData = function(data, disableStart) {
         if (this.stabilize) {
           this._doStabilize();
         }
    -    this.moving = true;
         this.start();
       }
     };
    @@ -579,7 +589,6 @@ Graph.prototype.setOptions = function (options) {
       this.setSize(this.width, this.height);
       this._setTranslation(this.frame.clientWidth / 2, this.frame.clientHeight / 2);
       this._setScale(1);
    -  this.zoomToFit();
       this._redraw();
     };
     
    @@ -1679,19 +1688,14 @@ Graph.prototype._drawEdges = function(ctx) {
      * @private
      */
     Graph.prototype._doStabilize = function() {
    -  //var start = new Date();
    -
       // find stable position
       var count = 0;
    -  var vmin = this.constants.minVelocity;
    -  var stable = false;
    -  while (!stable && count < this.constants.maxIterations) {
    -    this._initializeForceCalculation();
    -    this._discreteStepNodes();
    -    stable = !this._isMoving(vmin);
    +  while (this.moving && count < this.constants.maxIterations) {
    +    this._physicsTick();
         count++;
       }
    -  this.zoomToFit();
    +
    +  this.zoomToFit(false,true);
     };
     
     
    diff --git a/src/graph/graphMixins/ClusterMixin.js b/src/graph/graphMixins/ClusterMixin.js
    index 0ca8eb5f..e0de527a 100644
    --- a/src/graph/graphMixins/ClusterMixin.js
    +++ b/src/graph/graphMixins/ClusterMixin.js
    @@ -1045,7 +1045,7 @@ var ClusterMixin = {
         for (var i = 0; i < this.nodeIndices.length; i++) {
           var node = this.nodes[this.nodeIndices[i]];
           if ((node.xFixed == false || node.yFixed == false) && this.createNodeOnClick != true) {
    -        var radius = this.constants.physics.springLength * node.mass;
    +        var radius = this.constants.physics.springLength * Math.min(100,node.mass);
             var angle = 2 * Math.PI * Math.random();
             if (node.xFixed == false) {node.x = radius * Math.cos(angle);}
             if (node.yFixed == false) {node.y = radius * Math.sin(angle);}
    
    From ad39a54d7d82d443fc98ae1d9b24c4717d8999b8 Mon Sep 17 00:00:00 2001
    From: josdejong 
    Date: Tue, 18 Feb 2014 16:58:25 +0100
    Subject: [PATCH 51/52] Fixed filename case errors
    
    ---
     Jakefile.js | 4 ++--
     1 file changed, 2 insertions(+), 2 deletions(-)
    
    diff --git a/Jakefile.js b/Jakefile.js
    index a36a934c..1022f161 100644
    --- a/Jakefile.js
    +++ b/Jakefile.js
    @@ -83,8 +83,8 @@ task('build', {async: true}, function () {
           './src/graph/Groups.js',
           './src/graph/Images.js',
           './src/graph/graphMixins/physics/PhysicsMixin.js',
    -      './src/graph/graphMixins/physics/BarnesHut.js',
    -      './src/graph/graphMixins/physics/Repulsion.js',
    +      './src/graph/graphMixins/physics/barnesHut.js',
    +      './src/graph/graphMixins/physics/repulsion.js',
           './src/graph/graphMixins/ManipulationMixin.js',
           './src/graph/graphMixins/SectorsMixin.js',
           './src/graph/graphMixins/ClusterMixin.js',
    
    From d48fd1ed692af47f612e3d8ad936a6a6e1bcff2f Mon Sep 17 00:00:00 2001
    From: josdejong 
    Date: Tue, 18 Feb 2014 17:09:42 +0100
    Subject: [PATCH 52/52] Fixed filename case errors
    
    ---
     Jakefile.js                                      |   4 ++--
     examples/graph/20_navigation.html                |   8 ++++----
     .../physics/{barnesHut.js => BarnesHut.js}       |   0
     .../physics/{repulsion.js => Repulsion.js}       |   0
     .../downarrow.png => src/graph/img/downArrow.png | Bin
     src/graph/img/downarrow.png                      | Bin 4460 -> 0 bytes
     .../leftarrow.png => src/graph/img/leftArrow.png | Bin
     src/graph/img/leftarrow.png                      | Bin 4531 -> 0 bytes
     .../graph/img/rightArrow.png                     | Bin
     src/graph/img/rightarrow.png                     | Bin 4514 -> 0 bytes
     .../img/uparrow.png => src/graph/img/upArrow.png | Bin
     src/graph/img/uparrow.png                        | Bin 4461 -> 0 bytes
     12 files changed, 6 insertions(+), 6 deletions(-)
     rename src/graph/graphMixins/physics/{barnesHut.js => BarnesHut.js} (100%)
     rename src/graph/graphMixins/physics/{repulsion.js => Repulsion.js} (100%)
     rename dist/img/downarrow.png => src/graph/img/downArrow.png (100%)
     delete mode 100644 src/graph/img/downarrow.png
     rename dist/img/leftarrow.png => src/graph/img/leftArrow.png (100%)
     delete mode 100644 src/graph/img/leftarrow.png
     rename dist/img/rightarrow.png => src/graph/img/rightArrow.png (100%)
     delete mode 100644 src/graph/img/rightarrow.png
     rename dist/img/uparrow.png => src/graph/img/upArrow.png (100%)
     delete mode 100644 src/graph/img/uparrow.png
    
    diff --git a/Jakefile.js b/Jakefile.js
    index 1022f161..a36a934c 100644
    --- a/Jakefile.js
    +++ b/Jakefile.js
    @@ -83,8 +83,8 @@ task('build', {async: true}, function () {
           './src/graph/Groups.js',
           './src/graph/Images.js',
           './src/graph/graphMixins/physics/PhysicsMixin.js',
    -      './src/graph/graphMixins/physics/barnesHut.js',
    -      './src/graph/graphMixins/physics/repulsion.js',
    +      './src/graph/graphMixins/physics/BarnesHut.js',
    +      './src/graph/graphMixins/physics/Repulsion.js',
           './src/graph/graphMixins/ManipulationMixin.js',
           './src/graph/graphMixins/SectorsMixin.js',
           './src/graph/graphMixins/ClusterMixin.js',
    diff --git a/examples/graph/20_navigation.html b/examples/graph/20_navigation.html
    index 8bc2006a..742d85eb 100644
    --- a/examples/graph/20_navigation.html
    +++ b/examples/graph/20_navigation.html
    @@ -130,10 +130,10 @@
       
    -      
    -      
    -      
    -      
    +      
    +      
    +      
    +      
    diff --git a/src/graph/graphMixins/physics/barnesHut.js b/src/graph/graphMixins/physics/BarnesHut.js
    similarity index 100%
    rename from src/graph/graphMixins/physics/barnesHut.js
    rename to src/graph/graphMixins/physics/BarnesHut.js
    diff --git a/src/graph/graphMixins/physics/repulsion.js b/src/graph/graphMixins/physics/Repulsion.js
    similarity index 100%
    rename from src/graph/graphMixins/physics/repulsion.js
    rename to src/graph/graphMixins/physics/Repulsion.js
    diff --git a/dist/img/downarrow.png b/src/graph/img/downArrow.png
    similarity index 100%
    rename from dist/img/downarrow.png
    rename to src/graph/img/downArrow.png
    diff --git a/src/graph/img/downarrow.png b/src/graph/img/downarrow.png
    deleted file mode 100644
    index e77d5e6d4157b12a5b2fa08a9fc138f0ab9eb4e7..0000000000000000000000000000000000000000
    GIT binary patch
    literal 0
    HcmV?d00001
    
    literal 4460
    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�EM>-Bgb&Rym2{we-b7Oawc(c4k4MzLw~<#m(JZ
    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
    Re)#|Z002ovPDHLkV1iMdkGuc?
    
    diff --git a/dist/img/rightarrow.png b/src/graph/img/rightArrow.png
    similarity index 100%
    rename from dist/img/rightarrow.png
    rename to src/graph/img/rightArrow.png
    diff --git a/src/graph/img/rightarrow.png b/src/graph/img/rightarrow.png
    deleted file mode 100644
    index c3a209d8b0a58355305aae03b5520a1e070d8eab..0000000000000000000000000000000000000000
    GIT binary patch
    literal 0
    HcmV?d00001
    
    literal 4514
    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
    
    
    Icons:
  • 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

    - - - -
    - {{ content }} -
    -